summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/cliconfig/config.go1
-rw-r--r--cmd/podman/main_local.go22
-rw-r--r--cmd/podman/play_kube.go1
-rw-r--r--cmd/podmanV2/common/create.go2
-rw-r--r--cmd/podmanV2/common/default.go2
-rw-r--r--cmd/podmanV2/containers/attach.go60
-rw-r--r--cmd/podmanV2/containers/exec.go93
-rw-r--r--cmd/podmanV2/containers/start.go87
-rw-r--r--cmd/podmanV2/main.go1
-rw-r--r--cmd/podmanV2/pods/inspect.go64
-rw-r--r--cmd/podmanV2/system/version.go119
-rw-r--r--completions/bash/podman1
-rw-r--r--docs/source/markdown/podman-play-kube.1.md14
-rw-r--r--go.mod4
-rw-r--r--go.sum5
-rw-r--r--libpod/container_api.go24
-rw-r--r--libpod/container_exec.go4
-rw-r--r--libpod/container_top_linux.go2
-rw-r--r--libpod/define/config.go24
-rw-r--r--libpod/healthcheck.go2
-rw-r--r--libpod/oci.go4
-rw-r--r--libpod/oci_attach_linux.go8
-rw-r--r--libpod/oci_attach_unsupported.go4
-rw-r--r--pkg/adapter/containers.go2
-rw-r--r--pkg/adapter/pods.go18
-rw-r--r--pkg/adapter/terminal_linux.go5
-rw-r--r--pkg/adapter/terminal_unsupported.go2
-rw-r--r--pkg/api/handlers/libpod/pods.go5
-rw-r--r--pkg/bindings/pods/pods.go11
-rw-r--r--pkg/domain/entities/containers.go50
-rw-r--r--pkg/domain/entities/engine_container.go6
-rw-r--r--pkg/domain/entities/pods.go12
-rw-r--r--pkg/domain/infra/abi/containers.go180
-rw-r--r--pkg/domain/infra/abi/pods.go21
-rw-r--r--pkg/domain/infra/abi/terminal/sigproxy_linux.go47
-rw-r--r--pkg/domain/infra/abi/terminal/terminal.go103
-rw-r--r--pkg/domain/infra/abi/terminal/terminal_linux.go123
-rw-r--r--pkg/domain/infra/tunnel/containers.go12
-rw-r--r--pkg/domain/infra/tunnel/pods.go10
-rw-r--r--pkg/domain/infra/tunnel/system.go1
-rw-r--r--pkg/varlinkapi/attach.go8
-rw-r--r--vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go88
-rw-r--r--vendor/modules.txt4
43 files changed, 1167 insertions, 89 deletions
diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go
index 99f389799..6d98aaf0e 100644
--- a/cmd/podman/cliconfig/config.go
+++ b/cmd/podman/cliconfig/config.go
@@ -321,6 +321,7 @@ type KubePlayValues struct {
Authfile string
CertDir string
Creds string
+ Network string
Quiet bool
SignaturePolicy string
TlsVerify bool
diff --git a/cmd/podman/main_local.go b/cmd/podman/main_local.go
index 23b3f5ae7..a65e6acf8 100644
--- a/cmd/podman/main_local.go
+++ b/cmd/podman/main_local.go
@@ -11,7 +11,6 @@ import (
"os"
"runtime/pprof"
"strconv"
- "strings"
"syscall"
"github.com/containers/common/pkg/config"
@@ -192,7 +191,7 @@ func setupRootless(cmd *cobra.Command, args []string) error {
}
}
- if os.Geteuid() == 0 || cmd == _searchCommand || cmd == _versionCommand || cmd == _mountCommand || cmd == _migrateCommand || strings.HasPrefix(cmd.Use, "help") {
+ if !executeCommandInUserNS(cmd) {
return nil
}
@@ -243,6 +242,25 @@ func setupRootless(cmd *cobra.Command, args []string) error {
return nil
}
+// Most podman commands when run in rootless mode, need to be executed in the
+// users usernamespace. This function is updated with a list of commands that
+// should NOT be run within the user namespace.
+func executeCommandInUserNS(cmd *cobra.Command) bool {
+ if os.Geteuid() == 0 {
+ return false
+ }
+ switch cmd {
+ case _migrateCommand,
+ _mountCommand,
+ _renumberCommand,
+ _infoCommand,
+ _searchCommand,
+ _versionCommand:
+ return false
+ }
+ return true
+}
+
func setRLimits() error {
rlimits := new(syscall.Rlimit)
rlimits.Cur = 1048576
diff --git a/cmd/podman/play_kube.go b/cmd/podman/play_kube.go
index 2028d2ef4..a5669c595 100644
--- a/cmd/podman/play_kube.go
+++ b/cmd/podman/play_kube.go
@@ -51,6 +51,7 @@ func init() {
flags.StringVar(&playKubeCommand.SeccompProfileRoot, "seccomp-profile-root", defaultSeccompRoot, "Directory path for seccomp profiles")
markFlagHidden(flags, "signature-policy")
}
+ flags.StringVar(&playKubeCommand.Network, "network", "", "Connect pod to CNI network(s)")
}
func playKubeCmd(c *cliconfig.KubePlayValues) error {
diff --git a/cmd/podmanV2/common/create.go b/cmd/podmanV2/common/create.go
index 724ed2f42..f81d021c8 100644
--- a/cmd/podmanV2/common/create.go
+++ b/cmd/podmanV2/common/create.go
@@ -138,7 +138,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
)
createFlags.StringVar(
&cf.DetachKeys,
- "detach-keys", getDefaultDetachKeys(),
+ "detach-keys", GetDefaultDetachKeys(),
"Override the key sequence for detaching a container. Format is a single character `[a-Z]` or a comma separated sequence of `ctrl-<value>`, where `<value>` is one of: `a-cf`, `@`, `^`, `[`, `\\`, `]`, `^` or `_`",
)
createFlags.StringSliceVar(
diff --git a/cmd/podmanV2/common/default.go b/cmd/podmanV2/common/default.go
index fea161edf..b71fcb6f0 100644
--- a/cmd/podmanV2/common/default.go
+++ b/cmd/podmanV2/common/default.go
@@ -116,6 +116,6 @@ func getDefaultPidsDescription() string {
return "Tune container pids limit (set 0 for unlimited)"
}
-func getDefaultDetachKeys() string {
+func GetDefaultDetachKeys() string {
return defaultContainerConfig.Engine.DetachKeys
}
diff --git a/cmd/podmanV2/containers/attach.go b/cmd/podmanV2/containers/attach.go
new file mode 100644
index 000000000..d62dcff86
--- /dev/null
+++ b/cmd/podmanV2/containers/attach.go
@@ -0,0 +1,60 @@
+package containers
+
+import (
+ "os"
+
+ "github.com/containers/libpod/cmd/podmanV2/common"
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ attachDescription = "The podman attach command allows you to attach to a running container using the container's ID or name, either to view its ongoing output or to control it interactively."
+ attachCommand = &cobra.Command{
+ Use: "attach [flags] CONTAINER",
+ Short: "Attach to a running container",
+ Long: attachDescription,
+ RunE: attach,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) > 1 || (len(args) == 0 && !cmd.Flag("latest").Changed) {
+ return errors.Errorf("attach requires the name or id of one running container or the latest flag")
+ }
+ return nil
+ },
+ PreRunE: preRunE,
+ Example: `podman attach ctrID
+ podman attach 1234
+ podman attach --no-stdin foobar`,
+ }
+)
+
+var (
+ attachOpts entities.AttachOptions
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode},
+ Command: attachCommand,
+ })
+ flags := attachCommand.Flags()
+ flags.StringVar(&attachOpts.DetachKeys, "detach-keys", common.GetDefaultDetachKeys(), "Select the key sequence for detaching a container. Format is a single character `[a-Z]` or a comma separated sequence of `ctrl-<value>`, where `<value>` is one of: `a-z`, `@`, `^`, `[`, `\\`, `]`, `^` or `_`")
+ flags.BoolVar(&attachOpts.NoStdin, "no-stdin", false, "Do not attach STDIN. The default is false")
+ flags.BoolVar(&attachOpts.SigProxy, "sig-proxy", true, "Proxy received signals to the process")
+ flags.BoolVarP(&attachOpts.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
+ if registry.IsRemote() {
+ _ = flags.MarkHidden("latest")
+ }
+}
+
+func attach(cmd *cobra.Command, args []string) error {
+ attachOpts.Stdin = os.Stdin
+ if attachOpts.NoStdin {
+ attachOpts.Stdin = nil
+ }
+ attachOpts.Stdout = os.Stdout
+ attachOpts.Stderr = os.Stderr
+ return registry.ContainerEngine().ContainerAttach(registry.GetContext(), args[0], attachOpts)
+}
diff --git a/cmd/podmanV2/containers/exec.go b/cmd/podmanV2/containers/exec.go
new file mode 100644
index 000000000..4bff57dbb
--- /dev/null
+++ b/cmd/podmanV2/containers/exec.go
@@ -0,0 +1,93 @@
+package containers
+
+import (
+ "bufio"
+ "os"
+
+ "github.com/containers/libpod/cmd/podmanV2/common"
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+ envLib "github.com/containers/libpod/pkg/env"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ execDescription = `Execute the specified command inside a running container.
+`
+ execCommand = &cobra.Command{
+ Use: "exec [flags] CONTAINER [COMMAND [ARG...]]",
+ Short: "Run a process in a running container",
+ Long: execDescription,
+ PreRunE: preRunE,
+ RunE: exec,
+ Example: `podman exec -it ctrID ls
+ podman exec -it -w /tmp myCtr pwd
+ podman exec --user root ctrID ls`,
+ }
+)
+
+var (
+ envInput, envFile []string
+ execOpts entities.ExecOptions
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode},
+ Command: execCommand,
+ })
+ flags := execCommand.Flags()
+ flags.SetInterspersed(false)
+ flags.StringVar(&execOpts.DetachKeys, "detach-keys", common.GetDefaultDetachKeys(), "Select the key sequence for detaching a container. Format is a single character [a-Z] or ctrl-<value> where <value> is one of: a-z, @, ^, [, , or _")
+ flags.StringArrayVarP(&envInput, "env", "e", []string{}, "Set environment variables")
+ flags.StringSliceVar(&envFile, "env-file", []string{}, "Read in a file of environment variables")
+ flags.BoolVarP(&execOpts.Interactive, "interactive", "i", false, "Keep STDIN open even if not attached")
+ flags.BoolVarP(&execOpts.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
+ flags.BoolVar(&execOpts.Privileged, "privileged", false, "Give the process extended Linux capabilities inside the container. The default is false")
+ flags.BoolVarP(&execOpts.Tty, "tty", "t", false, "Allocate a pseudo-TTY. The default is false")
+ flags.StringVarP(&execOpts.User, "user", "u", "", "Sets the username or UID used and optionally the groupname or GID for the specified command")
+ flags.UintVar(&execOpts.PreserveFDs, "preserve-fds", 0, "Pass N additional file descriptors to the container")
+ flags.StringVarP(&execOpts.WorkDir, "workdir", "w", "", "Working directory inside the container")
+ if registry.IsRemote() {
+ _ = flags.MarkHidden("latest")
+ _ = flags.MarkHidden("preserve-fds")
+ }
+
+}
+func exec(cmd *cobra.Command, args []string) error {
+ var nameOrId string
+ execOpts.Cmd = args
+ if !execOpts.Latest {
+ execOpts.Cmd = args[1:]
+ nameOrId = args[0]
+ }
+ // Validate given environment variables
+ execOpts.Envs = make(map[string]string)
+ for _, f := range envFile {
+ fileEnv, err := envLib.ParseFile(f)
+ if err != nil {
+ return err
+ }
+ execOpts.Envs = envLib.Join(execOpts.Envs, fileEnv)
+ }
+
+ cliEnv, err := envLib.ParseSlice(envInput)
+ if err != nil {
+ return errors.Wrap(err, "error parsing environment variables")
+ }
+
+ execOpts.Envs = envLib.Join(execOpts.Envs, cliEnv)
+ execOpts.Streams.OutputStream = os.Stdout
+ execOpts.Streams.ErrorStream = os.Stderr
+ if execOpts.Interactive {
+ execOpts.Streams.InputStream = bufio.NewReader(os.Stdin)
+ execOpts.Streams.AttachInput = true
+ }
+ execOpts.Streams.AttachOutput = true
+ execOpts.Streams.AttachError = true
+
+ exitCode, err := registry.ContainerEngine().ContainerExec(registry.GetContext(), nameOrId, execOpts)
+ registry.SetExitCode(exitCode)
+ return err
+}
diff --git a/cmd/podmanV2/containers/start.go b/cmd/podmanV2/containers/start.go
new file mode 100644
index 000000000..0ae2f6d50
--- /dev/null
+++ b/cmd/podmanV2/containers/start.go
@@ -0,0 +1,87 @@
+package containers
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/containers/libpod/cmd/podmanV2/common"
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/cmd/podmanV2/utils"
+ "github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ startDescription = `Starts one or more containers. The container name or ID can be used.`
+ startCommand = &cobra.Command{
+ Use: "start [flags] CONTAINER [CONTAINER...]",
+ Short: "Start one or more containers",
+ Long: startDescription,
+ RunE: start,
+ PreRunE: preRunE,
+ Args: cobra.MinimumNArgs(1),
+ Example: `podman start --latest
+ podman start 860a4b231279 5421ab43b45
+ podman start --interactive --attach imageID`,
+ }
+)
+
+var (
+ startOptions entities.ContainerStartOptions
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode},
+ Command: startCommand,
+ })
+ flags := startCommand.Flags()
+ flags.BoolVarP(&startOptions.Attach, "attach", "a", false, "Attach container's STDOUT and STDERR")
+ flags.StringVar(&startOptions.DetachKeys, "detach-keys", common.GetDefaultDetachKeys(), "Select the key sequence for detaching a container. Format is a single character `[a-Z]` or a comma separated sequence of `ctrl-<value>`, where `<value>` is one of: `a-z`, `@`, `^`, `[`, `\\`, `]`, `^` or `_`")
+ flags.BoolVarP(&startOptions.Interactive, "interactive", "i", false, "Keep STDIN open even if not attached")
+ flags.BoolVarP(&startOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
+ flags.BoolVar(&startOptions.SigProxy, "sig-proxy", false, "Proxy received signals to the process (default true if attaching, false otherwise)")
+ if registry.IsRemote() {
+ _ = flags.MarkHidden("latest")
+ _ = flags.MarkHidden("sig-proxy")
+ }
+
+}
+
+func start(cmd *cobra.Command, args []string) error {
+ var errs utils.OutputErrors
+ if len(args) > 1 && startOptions.Attach {
+ return errors.Errorf("you cannot start and attach multiple containers at once")
+ }
+
+ sigProxy := startOptions.SigProxy || startOptions.Attach
+ if cmd.Flag("sig-proxy").Changed {
+ sigProxy = startOptions.SigProxy
+ }
+
+ if sigProxy && !startOptions.Attach {
+ return errors.Wrapf(define.ErrInvalidArg, "you cannot use sig-proxy without --attach")
+ }
+ if startOptions.Attach {
+ startOptions.Stdin = os.Stdin
+ startOptions.Stderr = os.Stderr
+ startOptions.Stdout = os.Stdout
+ }
+
+ responses, err := registry.ContainerEngine().ContainerStart(registry.GetContext(), args, startOptions)
+ if err != nil {
+ return err
+ }
+
+ for _, r := range responses {
+ if r.Err == nil {
+ fmt.Println(r.Id)
+ } else {
+ errs = append(errs, r.Err)
+ }
+ }
+ // TODO need to understand an implement exitcodes
+ return errs.PrintErrors()
+}
diff --git a/cmd/podmanV2/main.go b/cmd/podmanV2/main.go
index 6781a7f06..fe3cd9f16 100644
--- a/cmd/podmanV2/main.go
+++ b/cmd/podmanV2/main.go
@@ -12,6 +12,7 @@ import (
_ "github.com/containers/libpod/cmd/podmanV2/networks"
_ "github.com/containers/libpod/cmd/podmanV2/pods"
"github.com/containers/libpod/cmd/podmanV2/registry"
+ _ "github.com/containers/libpod/cmd/podmanV2/system"
_ "github.com/containers/libpod/cmd/podmanV2/volumes"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/domain/entities"
diff --git a/cmd/podmanV2/pods/inspect.go b/cmd/podmanV2/pods/inspect.go
new file mode 100644
index 000000000..9aab610f2
--- /dev/null
+++ b/cmd/podmanV2/pods/inspect.go
@@ -0,0 +1,64 @@
+package pods
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ inspectOptions = entities.PodInspectOptions{}
+)
+
+var (
+ inspectDescription = fmt.Sprintf(`Display the configuration for a pod by name or id
+
+ By default, this will render all results in a JSON array.`)
+
+ inspectCmd = &cobra.Command{
+ Use: "inspect [flags] POD [POD...]",
+ Short: "Displays a pod configuration",
+ Long: inspectDescription,
+ RunE: inspect,
+ Example: `podman pod inspect podID`,
+ }
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: inspectCmd,
+ Parent: podCmd,
+ })
+ flags := inspectCmd.Flags()
+ flags.BoolVarP(&inspectOptions.Latest, "latest", "l", false, "Act on the latest pod podman is aware of")
+ if registry.IsRemote() {
+ _ = flags.MarkHidden("latest")
+ }
+}
+
+func inspect(cmd *cobra.Command, args []string) error {
+
+ if len(args) < 1 && !inspectOptions.Latest {
+ return errors.Errorf("you must provide the name or id of a running pod")
+ }
+
+ if !inspectOptions.Latest {
+ inspectOptions.NameOrID = args[0]
+ }
+ responses, err := registry.ContainerEngine().PodInspect(context.Background(), inspectOptions)
+ if err != nil {
+ return err
+ }
+ b, err := jsoniter.MarshalIndent(responses, "", " ")
+ if err != nil {
+ return err
+ }
+ fmt.Println(string(b))
+ return nil
+}
diff --git a/cmd/podmanV2/system/version.go b/cmd/podmanV2/system/version.go
new file mode 100644
index 000000000..e8002056b
--- /dev/null
+++ b/cmd/podmanV2/system/version.go
@@ -0,0 +1,119 @@
+package system
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "strings"
+ "text/tabwriter"
+ "time"
+
+ "github.com/containers/buildah/pkg/formats"
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ versionCommand = &cobra.Command{
+ Use: "version",
+ Args: cobra.NoArgs,
+ Short: "Display the Podman Version Information",
+ RunE: version,
+ PersistentPreRunE: preRunE,
+ }
+ format string
+)
+
+type versionStruct struct {
+ Client define.Version
+ Server define.Version
+}
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: versionCommand,
+ })
+ flags := versionCommand.Flags()
+ flags.StringVarP(&format, "format", "f", "", "Change the output format to JSON or a Go template")
+}
+
+func version(cmd *cobra.Command, args []string) error {
+ var (
+ v versionStruct
+ err error
+ )
+ v.Client, err = define.GetVersion()
+ if err != nil {
+ return errors.Wrapf(err, "unable to determine version")
+ }
+ // TODO we need to discuss how to implement
+ // this more. current endpoints dont have a
+ // version endpoint. maybe we use info?
+ //if remote {
+ // v.Server, err = getRemoteVersion(c)
+ // if err != nil {
+ // return err
+ // }
+ //} else {
+ v.Server = v.Client
+ //}
+
+ versionOutputFormat := format
+ if versionOutputFormat != "" {
+ if strings.Join(strings.Fields(versionOutputFormat), "") == "{{json.}}" {
+ versionOutputFormat = formats.JSONString
+ }
+ var out formats.Writer
+ switch versionOutputFormat {
+ case formats.JSONString:
+ out = formats.JSONStruct{Output: v}
+ return out.Out()
+ default:
+ out = formats.StdoutTemplate{Output: v, Template: versionOutputFormat}
+ err := out.Out()
+ if err != nil {
+ // On Failure, assume user is using older version of podman version --format and check client
+ out = formats.StdoutTemplate{Output: v.Client, Template: versionOutputFormat}
+ if err1 := out.Out(); err1 != nil {
+ return err
+ }
+ }
+ }
+ return nil
+ }
+ w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
+ defer w.Flush()
+
+ if registry.IsRemote() {
+ if _, err := fmt.Fprintf(w, "Client:\n"); err != nil {
+ return err
+ }
+ formatVersion(w, v.Client)
+ if _, err := fmt.Fprintf(w, "\nServer:\n"); err != nil {
+ return err
+ }
+ formatVersion(w, v.Server)
+ } else {
+ formatVersion(w, v.Client)
+ }
+ return nil
+}
+
+func formatVersion(writer io.Writer, version define.Version) {
+ fmt.Fprintf(writer, "Version:\t%s\n", version.Version)
+ fmt.Fprintf(writer, "RemoteAPI Version:\t%d\n", version.RemoteAPIVersion)
+ fmt.Fprintf(writer, "Go Version:\t%s\n", version.GoVersion)
+ if version.GitCommit != "" {
+ fmt.Fprintf(writer, "Git Commit:\t%s\n", version.GitCommit)
+ }
+ // Prints out the build time in readable format
+ if version.Built != 0 {
+ fmt.Fprintf(writer, "Built:\t%s\n", time.Unix(version.Built, 0).Format(time.ANSIC))
+ }
+
+ fmt.Fprintf(writer, "OS/Arch:\t%s\n", version.OsArch)
+}
diff --git a/completions/bash/podman b/completions/bash/podman
index 77f881d53..6997db3b5 100644
--- a/completions/bash/podman
+++ b/completions/bash/podman
@@ -2681,6 +2681,7 @@ _podman_play_kube() {
--authfile
--cert-dir
--creds
+ --network
"
local boolean_options="
diff --git a/docs/source/markdown/podman-play-kube.1.md b/docs/source/markdown/podman-play-kube.1.md
index 2367ff7fe..dd9441800 100644
--- a/docs/source/markdown/podman-play-kube.1.md
+++ b/docs/source/markdown/podman-play-kube.1.md
@@ -36,6 +36,10 @@ The [username[:password]] to use to authenticate with the registry if required.
If one or both values are not supplied, a command line prompt will appear and the
value can be entered. The password is entered without echo.
+**--network**=*cni networks*
+
+A comma-separated list of the names of CNI networks the pod should join.
+
**--quiet**, **-q**
Suppress output information when pulling images
@@ -62,8 +66,16 @@ $ podman play kube demo.yml
52182811df2b1e73f36476003a66ec872101ea59034ac0d4d3a7b40903b955a6
```
+CNI network(s) can be specified as comma-separated list using ``--network``
+```
+$ podman play kube demo.yml --network cni1,cni2
+52182811df2b1e73f36476003a66ec872101ea59034ac0d4d3a7b40903b955a6
+```
+
+Please take into account that CNI networks must be created first using podman-network-create(1).
+
## SEE ALSO
-podman(1), podman-container(1), podman-pod(1), podman-generate-kube(1), podman-play(1)
+podman(1), podman-container(1), podman-pod(1), podman-generate-kube(1), podman-play(1), podman-network-create(1)
## HISTORY
December 2018, Originally compiled by Brent Baude (bbaude at redhat dot com)
diff --git a/go.mod b/go.mod
index 15ba92c38..36ec8b931 100644
--- a/go.mod
+++ b/go.mod
@@ -10,7 +10,7 @@ require (
github.com/containernetworking/cni v0.7.2-0.20200304161608-4fae32b84921
github.com/containernetworking/plugins v0.8.5
github.com/containers/buildah v1.14.6-0.20200402210551-e9a6703edee2
- github.com/containers/common v0.8.0
+ github.com/containers/common v0.8.1
github.com/containers/conmon v2.0.14+incompatible
github.com/containers/image/v5 v5.3.1
github.com/containers/psgo v1.4.0
@@ -42,7 +42,7 @@ require (
github.com/opencontainers/runc v1.0.0-rc9
github.com/opencontainers/runtime-spec v0.1.2-0.20190618234442-a950415649c7
github.com/opencontainers/runtime-tools v0.9.0
- github.com/opencontainers/selinux v1.4.0
+ github.com/opencontainers/selinux v1.5.0
github.com/opentracing/opentracing-go v1.1.0
github.com/pkg/errors v0.9.1
github.com/pmezard/go-difflib v1.0.0
diff --git a/go.sum b/go.sum
index 834dad07e..c90c410b7 100644
--- a/go.sum
+++ b/go.sum
@@ -71,6 +71,8 @@ github.com/containers/common v0.6.1/go.mod h1:m62kenckrWi5rZx32kaLje2Og0hpf6NsaT
github.com/containers/common v0.7.0/go.mod h1:UmhIdvSkhTR0hWR01AnuZGNufm80+A0s8isb05eTmz0=
github.com/containers/common v0.8.0 h1:C+wjkcmR4gooeKCXZpyjsHSFARm5AZRegflGz0x0MMw=
github.com/containers/common v0.8.0/go.mod h1:QJTx9+SvhHKP6e+p7Nxqc8oNnS5rSf0KVhxudIbDslU=
+github.com/containers/common v0.8.1 h1:1IUwAtZ4mC7GYRr4AC23cHf2oXCuoLzTUoSzIkSgnYw=
+github.com/containers/common v0.8.1/go.mod h1:VxDJbaA1k6N1TNv9Rt6bQEF4hyKVHNfOfGA5L91ADEs=
github.com/containers/common v1.0.0 h1:sZB48LzGP4bP1CmrkQIFUzdUVBysqRv3kWVk4+qbaVA=
github.com/containers/common v1.0.0/go.mod h1:m62kenckrWi5rZx32kaLje2Og0hpf6NsaTBn6+b+Oys=
github.com/containers/conmon v2.0.14+incompatible h1:knU1O1QxXy5YxtjMQVKEyCajROaehizK9FHaICl+P5Y=
@@ -353,6 +355,8 @@ github.com/opencontainers/selinux v1.3.1/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwy
github.com/opencontainers/selinux v1.3.2/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
github.com/opencontainers/selinux v1.4.0 h1:cpiX/2wWIju/6My60T6/z9CxNG7c8xTQyEmA9fChpUo=
github.com/opencontainers/selinux v1.4.0/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
+github.com/opencontainers/selinux v1.5.0 h1:giFN+hbiSqvKWPyagmNk9sABaH7VUZ/+XS7tInqDQ6c=
+github.com/opencontainers/selinux v1.5.0/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
github.com/openshift/api v0.0.0-20200106203948-7ab22a2c8316 h1:enQG2QUGwug4fR1yM6hL0Fjzx6Km/exZY6RbSPwMu3o=
github.com/openshift/api v0.0.0-20200106203948-7ab22a2c8316/go.mod h1:dv+J0b/HWai0QnMVb37/H0v36klkLBi2TNpPeWDxX10=
github.com/openshift/imagebuilder v1.1.3 h1:8TiphsD2wboU7tygtGZ5ZBfCP9FH2ZtvEAli67V2PJ4=
@@ -587,6 +591,7 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72 h1:bw9doJza/SFBEweII/rHQh338oozWyiFsBRHtrflcws=
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
diff --git a/libpod/container_api.go b/libpod/container_api.go
index 967180437..55c79fa74 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -3,7 +3,6 @@ package libpod
import (
"bufio"
"context"
- "io"
"io/ioutil"
"net"
"os"
@@ -96,7 +95,7 @@ func (c *Container) Start(ctx context.Context, recursive bool) (err error) {
// The channel will be closed automatically after the result of attach has been
// sent.
// If recursive is set, StartAndAttach will also start all containers this container depends on.
-func (c *Container) StartAndAttach(ctx context.Context, streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, recursive bool) (attachResChan <-chan error, err error) {
+func (c *Container) StartAndAttach(ctx context.Context, streams *define.AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, recursive bool) (attachResChan <-chan error, err error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
@@ -213,29 +212,10 @@ func (c *Container) Kill(signal uint) error {
return c.save()
}
-// AttachStreams contains streams that will be attached to the container
-type AttachStreams struct {
- // OutputStream will be attached to container's STDOUT
- OutputStream io.WriteCloser
- // ErrorStream will be attached to container's STDERR
- ErrorStream io.WriteCloser
- // InputStream will be attached to container's STDIN
- InputStream *bufio.Reader
- // AttachOutput is whether to attach to STDOUT
- // If false, stdout will not be attached
- AttachOutput bool
- // AttachError is whether to attach to STDERR
- // If false, stdout will not be attached
- AttachError bool
- // AttachInput is whether to attach to STDIN
- // If false, stdout will not be attached
- AttachInput bool
-}
-
// Attach attaches to a container.
// This function returns when the attach finishes. It does not hold the lock for
// the duration of its runtime, only using it at the beginning to verify state.
-func (c *Container) Attach(streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize) error {
+func (c *Container) Attach(streams *define.AttachStreams, keys string, resize <-chan remotecommand.TerminalSize) error {
if !c.batched {
c.lock.Lock()
if err := c.syncContainer(); err != nil {
diff --git a/libpod/container_exec.go b/libpod/container_exec.go
index 5469462f8..c1ce8b724 100644
--- a/libpod/container_exec.go
+++ b/libpod/container_exec.go
@@ -221,7 +221,7 @@ func (c *Container) ExecStart(sessionID string) error {
// ExecStartAndAttach starts and attaches to an exec session in a container.
// TODO: Should we include detach keys in the signature to allow override?
// TODO: How do we handle AttachStdin/AttachStdout/AttachStderr?
-func (c *Container) ExecStartAndAttach(sessionID string, streams *AttachStreams) error {
+func (c *Container) ExecStartAndAttach(sessionID string, streams *define.AttachStreams) error {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
@@ -544,7 +544,7 @@ func (c *Container) ExecResize(sessionID string, newSize remotecommand.TerminalS
// Exec emulates the old Libpod exec API, providing a single call to create,
// run, and remove an exec session. Returns exit code and error. Exit code is
// not guaranteed to be set sanely if error is not nil.
-func (c *Container) Exec(config *ExecConfig, streams *AttachStreams, resize <-chan remotecommand.TerminalSize) (int, error) {
+func (c *Container) Exec(config *ExecConfig, streams *define.AttachStreams, resize <-chan remotecommand.TerminalSize) (int, error) {
sessionID, err := c.ExecCreate(config)
if err != nil {
return -1, err
diff --git a/libpod/container_top_linux.go b/libpod/container_top_linux.go
index 2a35a2ae9..98a69966a 100644
--- a/libpod/container_top_linux.go
+++ b/libpod/container_top_linux.go
@@ -112,7 +112,7 @@ func (c *Container) execPS(args []string) ([]string, error) {
defer wErrPipe.Close()
defer rErrPipe.Close()
- streams := new(AttachStreams)
+ streams := new(define.AttachStreams)
streams.OutputStream = wPipe
streams.ErrorStream = wErrPipe
streams.AttachOutput = true
diff --git a/libpod/define/config.go b/libpod/define/config.go
index 7b967f17d..10e00062a 100644
--- a/libpod/define/config.go
+++ b/libpod/define/config.go
@@ -1,5 +1,10 @@
package define
+import (
+ "bufio"
+ "io"
+)
+
var (
// DefaultInfraImage to use for infra container
DefaultInfraImage = "k8s.gcr.io/pause:3.2"
@@ -33,3 +38,22 @@ const (
V2s2ManifestDir = "docker-dir"
V2s2Archive = "docker-archive"
)
+
+// AttachStreams contains streams that will be attached to the container
+type AttachStreams struct {
+ // OutputStream will be attached to container's STDOUT
+ OutputStream io.WriteCloser
+ // ErrorStream will be attached to container's STDERR
+ ErrorStream io.WriteCloser
+ // InputStream will be attached to container's STDIN
+ InputStream *bufio.Reader
+ // AttachOutput is whether to attach to STDOUT
+ // If false, stdout will not be attached
+ AttachOutput bool
+ // AttachError is whether to attach to STDERR
+ // If false, stdout will not be attached
+ AttachError bool
+ // AttachInput is whether to attach to STDIN
+ // If false, stdout will not be attached
+ AttachInput bool
+}
diff --git a/libpod/healthcheck.go b/libpod/healthcheck.go
index 08a613dfe..daddb6561 100644
--- a/libpod/healthcheck.go
+++ b/libpod/healthcheck.go
@@ -108,7 +108,7 @@ func (c *Container) runHealthCheck() (HealthCheckStatus, error) {
hcw := hcWriteCloser{
captureBuffer,
}
- streams := new(AttachStreams)
+ streams := new(define.AttachStreams)
streams.OutputStream = hcw
streams.ErrorStream = hcw
diff --git a/libpod/oci.go b/libpod/oci.go
index ef46cf5c3..e4fbcb62e 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -4,6 +4,8 @@ import (
"bufio"
"net"
+ "github.com/containers/libpod/libpod/define"
+
"k8s.io/client-go/tools/remotecommand"
)
@@ -141,7 +143,7 @@ type ExecOptions struct {
// the container was run as will be used.
User string
// Streams are the streams that will be attached to the container.
- Streams *AttachStreams
+ Streams *define.AttachStreams
// PreserveFDs is a number of additional file descriptors (in addition
// to 0, 1, 2) that will be passed to the executed process. The total FDs
// passed will be 3 + PreserveFDs.
diff --git a/libpod/oci_attach_linux.go b/libpod/oci_attach_linux.go
index fb0a54bff..ff158c2d1 100644
--- a/libpod/oci_attach_linux.go
+++ b/libpod/oci_attach_linux.go
@@ -31,7 +31,7 @@ const (
// Attach to the given container
// Does not check if state is appropriate
// started is only required if startContainer is true
-func (c *Container) attach(streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, startContainer bool, started chan bool) error {
+func (c *Container) attach(streams *define.AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, startContainer bool, started chan bool) error {
if !streams.AttachOutput && !streams.AttachError && !streams.AttachInput {
return errors.Wrapf(define.ErrInvalidArg, "must provide at least one stream to attach to")
}
@@ -94,7 +94,7 @@ func (c *Container) attach(streams *AttachStreams, keys string, resize <-chan re
// 4. attachToExec sends on startFd, signalling it has attached to the socket and child is ready to go
// 5. child receives on startFd, runs the runtime exec command
// attachToExec is responsible for closing startFd and attachFd
-func (c *Container) attachToExec(streams *AttachStreams, keys *string, sessionID string, startFd, attachFd *os.File) error {
+func (c *Container) attachToExec(streams *define.AttachStreams, keys *string, sessionID string, startFd, attachFd *os.File) error {
if !streams.AttachOutput && !streams.AttachError && !streams.AttachInput {
return errors.Wrapf(define.ErrInvalidArg, "must provide at least one stream to attach to")
}
@@ -189,7 +189,7 @@ func buildSocketPath(socketPath string) string {
return socketPath
}
-func setupStdioChannels(streams *AttachStreams, conn *net.UnixConn, detachKeys []byte) (chan error, chan error) {
+func setupStdioChannels(streams *define.AttachStreams, conn *net.UnixConn, detachKeys []byte) (chan error, chan error) {
receiveStdoutError := make(chan error)
go func() {
receiveStdoutError <- redirectResponseToOutputStreams(streams.OutputStream, streams.ErrorStream, streams.AttachOutput, streams.AttachError, conn)
@@ -257,7 +257,7 @@ func redirectResponseToOutputStreams(outputStream, errorStream io.Writer, writeO
return err
}
-func readStdio(streams *AttachStreams, receiveStdoutError, stdinDone chan error) error {
+func readStdio(streams *define.AttachStreams, receiveStdoutError, stdinDone chan error) error {
var err error
select {
case err = <-receiveStdoutError:
diff --git a/libpod/oci_attach_unsupported.go b/libpod/oci_attach_unsupported.go
index 987d2c973..3b0216e5d 100644
--- a/libpod/oci_attach_unsupported.go
+++ b/libpod/oci_attach_unsupported.go
@@ -9,10 +9,10 @@ import (
"k8s.io/client-go/tools/remotecommand"
)
-func (c *Container) attach(streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, startContainer bool, started chan bool) error {
+func (c *Container) attach(streams *define.AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, startContainer bool, started chan bool) error {
return define.ErrNotImplemented
}
-func (c *Container) attachToExec(streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, sessionID string, startFd *os.File, attachFd *os.File) error {
+func (c *Container) attachToExec(streams *define.AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, sessionID string, startFd *os.File, attachFd *os.File) error {
return define.ErrNotImplemented
}
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go
index b4ebeb944..ecadbd2f9 100644
--- a/pkg/adapter/containers.go
+++ b/pkg/adapter/containers.go
@@ -1004,7 +1004,7 @@ func (r *LocalRuntime) ExecContainer(ctx context.Context, cli *cliconfig.ExecVal
}
env = envLib.Join(env, cliEnv)
- streams := new(libpod.AttachStreams)
+ streams := new(define.AttachStreams)
streams.OutputStream = os.Stdout
streams.ErrorStream = os.Stderr
if cli.Interactive {
diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go
index 102eabd8b..7c2a84cc7 100644
--- a/pkg/adapter/pods.go
+++ b/pkg/adapter/pods.go
@@ -343,7 +343,7 @@ func (r *LocalRuntime) CreatePod(ctx context.Context, cli *cliconfig.PodCreateVa
logrus.Debugf("Pod will use host networking")
options = append(options, libpod.WithPodHostNetwork())
case "":
- return "", errors.Errorf("invalid value passed to --net: must provide a comma-separated list of CNI networks or host")
+ return "", errors.Errorf("invalid value passed to --network: must provide a comma-separated list of CNI networks or host")
default:
// We'll assume this is a comma-separated list of CNI
// networks.
@@ -595,6 +595,22 @@ func (r *LocalRuntime) PlayKubeYAML(ctx context.Context, c *cliconfig.KubePlayVa
podPorts := getPodPorts(podYAML.Spec.Containers)
podOptions = append(podOptions, libpod.WithInfraContainerPorts(podPorts))
+ if c.Flag("network").Changed {
+ netValue := c.String("network")
+ switch strings.ToLower(netValue) {
+ case "bridge", "host":
+ return nil, errors.Errorf("invalid value passed to --network: bridge or host networking must be configured in YAML")
+ case "":
+ return nil, errors.Errorf("invalid value passed to --network: must provide a comma-separated list of CNI networks")
+ default:
+ // We'll assume this is a comma-separated list of CNI
+ // networks.
+ networks := strings.Split(netValue, ",")
+ logrus.Debugf("Pod joining CNI networks: %v", networks)
+ podOptions = append(podOptions, libpod.WithPodNetworks(networks))
+ }
+ }
+
// Create the Pod
pod, err = r.NewPod(ctx, podOptions...)
if err != nil {
diff --git a/pkg/adapter/terminal_linux.go b/pkg/adapter/terminal_linux.go
index ef5a6f926..a56704be6 100644
--- a/pkg/adapter/terminal_linux.go
+++ b/pkg/adapter/terminal_linux.go
@@ -7,6 +7,7 @@ import (
"os"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh/terminal"
@@ -14,7 +15,7 @@ import (
)
// ExecAttachCtr execs and attaches to a container
-func ExecAttachCtr(ctx context.Context, ctr *libpod.Container, tty, privileged bool, env map[string]string, cmd []string, user, workDir string, streams *libpod.AttachStreams, preserveFDs uint, detachKeys string) (int, error) {
+func ExecAttachCtr(ctx context.Context, ctr *libpod.Container, tty, privileged bool, env map[string]string, cmd []string, user, workDir string, streams *define.AttachStreams, preserveFDs uint, detachKeys string) (int, error) {
resize := make(chan remotecommand.TerminalSize)
haveTerminal := terminal.IsTerminal(int(os.Stdin.Fd()))
@@ -69,7 +70,7 @@ func StartAttachCtr(ctx context.Context, ctr *libpod.Container, stdout, stderr,
defer cancel()
}
- streams := new(libpod.AttachStreams)
+ streams := new(define.AttachStreams)
streams.OutputStream = stdout
streams.ErrorStream = stderr
streams.InputStream = bufio.NewReader(stdin)
diff --git a/pkg/adapter/terminal_unsupported.go b/pkg/adapter/terminal_unsupported.go
index 3009f0a38..9067757a1 100644
--- a/pkg/adapter/terminal_unsupported.go
+++ b/pkg/adapter/terminal_unsupported.go
@@ -11,7 +11,7 @@ import (
)
// ExecAttachCtr execs and attaches to a container
-func ExecAttachCtr(ctx context.Context, ctr *libpod.Container, tty, privileged bool, env map[string]string, cmd []string, user, workDir string, streams *libpod.AttachStreams, preserveFDs uint, detachKeys string) (int, error) {
+func ExecAttachCtr(ctx context.Context, ctr *libpod.Container, tty, privileged bool, env map[string]string, cmd []string, user, workDir string, streams *define.AttachStreams, preserveFDs uint, detachKeys string) (int, error) {
return -1, define.ErrNotImplemented
}
diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go
index e834029b2..a890169a1 100644
--- a/pkg/api/handlers/libpod/pods.go
+++ b/pkg/api/handlers/libpod/pods.go
@@ -73,7 +73,10 @@ func PodInspect(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
return
}
- utils.WriteResponse(w, http.StatusOK, podData)
+ report := entities.PodInspectReport{
+ PodInspect: podData,
+ }
+ utils.WriteResponse(w, http.StatusOK, report)
}
func PodStop(w http.ResponseWriter, r *http.Request) {
diff --git a/pkg/bindings/pods/pods.go b/pkg/bindings/pods/pods.go
index ae87c00e9..83847614a 100644
--- a/pkg/bindings/pods/pods.go
+++ b/pkg/bindings/pods/pods.go
@@ -7,7 +7,6 @@ import (
"strconv"
"strings"
- "github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/api/handlers"
"github.com/containers/libpod/pkg/bindings"
"github.com/containers/libpod/pkg/domain/entities"
@@ -49,17 +48,19 @@ func Exists(ctx context.Context, nameOrID string) (bool, error) {
}
// Inspect returns low-level information about the given pod.
-func Inspect(ctx context.Context, nameOrID string) (*libpod.PodInspect, error) {
+func Inspect(ctx context.Context, nameOrID string) (*entities.PodInspectReport, error) {
+ var (
+ report entities.PodInspectReport
+ )
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- inspect := libpod.PodInspect{}
response, err := conn.DoRequest(nil, http.MethodGet, "/pods/%s/json", nil, nameOrID)
if err != nil {
- return &inspect, err
+ return nil, err
}
- return &inspect, response.Process(&inspect)
+ return &report, response.Process(&report)
}
// Kill sends a SIGTERM to all the containers in a pod. The optional signal parameter
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index 74b23cd71..6b4bb9ba2 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -2,6 +2,7 @@ package entities
import (
"io"
+ "os"
"time"
"github.com/containers/libpod/libpod/define"
@@ -157,3 +158,52 @@ type RestoreReport struct {
type ContainerCreateReport struct {
Id string
}
+
+// AttachOptions describes the cli and other values
+// needed to perform an attach
+type AttachOptions struct {
+ DetachKeys string
+ Latest bool
+ NoStdin bool
+ SigProxy bool
+ Stdin *os.File
+ Stdout *os.File
+ Stderr *os.File
+}
+
+// ExecOptions describes the cli values to exec into
+// a container
+type ExecOptions struct {
+ Cmd []string
+ DetachKeys string
+ Envs map[string]string
+ Interactive bool
+ Latest bool
+ PreserveFDs uint
+ Privileged bool
+ Streams define.AttachStreams
+ Tty bool
+ User string
+ WorkDir string
+}
+
+// ContainerStartOptions describes the val from the
+// CLI needed to start a container
+type ContainerStartOptions struct {
+ Attach bool
+ DetachKeys string
+ Interactive bool
+ Latest bool
+ SigProxy bool
+ Stdout *os.File
+ Stderr *os.File
+ Stdin *os.File
+}
+
+// ContainerStartReport describes the response from starting
+// containers from the cli
+type ContainerStartReport struct {
+ Id string
+ Err error
+ ExitCode int
+}
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 025da50f3..264780771 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -8,10 +8,12 @@ import (
)
type ContainerEngine interface {
+ ContainerAttach(ctx context.Context, nameOrId string, options AttachOptions) error
ContainerCommit(ctx context.Context, nameOrId string, options CommitOptions) (*CommitReport, error)
ContainerCheckpoint(ctx context.Context, namesOrIds []string, options CheckpointOptions) ([]*CheckpointReport, error)
ContainerRestore(ctx context.Context, namesOrIds []string, options RestoreOptions) ([]*RestoreReport, error)
ContainerCreate(ctx context.Context, s *specgen.SpecGenerator) (*ContainerCreateReport, error)
+ ContainerExec(ctx context.Context, nameOrId string, options ExecOptions) (int, error)
ContainerExists(ctx context.Context, nameOrId string) (*BoolReport, error)
ContainerInspect(ctx context.Context, namesOrIds []string, options InspectOptions) ([]*ContainerInspectReport, error)
ContainerExport(ctx context.Context, nameOrId string, options ContainerExportOptions) error
@@ -19,11 +21,13 @@ type ContainerEngine interface {
ContainerPause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error)
ContainerRestart(ctx context.Context, namesOrIds []string, options RestartOptions) ([]*RestartReport, error)
ContainerRm(ctx context.Context, namesOrIds []string, options RmOptions) ([]*RmReport, error)
+ ContainerStart(ctx context.Context, namesOrIds []string, options ContainerStartOptions) ([]*ContainerStartReport, error)
ContainerStop(ctx context.Context, namesOrIds []string, options StopOptions) ([]*StopReport, error)
ContainerTop(ctx context.Context, options TopOptions) (*StringSliceReport, error)
ContainerUnpause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error)
ContainerWait(ctx context.Context, namesOrIds []string, options WaitOptions) ([]WaitReport, error)
HealthCheckRun(ctx context.Context, nameOrId string, options HealthCheckOptions) (*define.HealthCheckResults, error)
+
PodCreate(ctx context.Context, opts PodCreateOptions) (*PodCreateReport, error)
PodExists(ctx context.Context, nameOrId string) (*BoolReport, error)
PodKill(ctx context.Context, namesOrIds []string, options PodKillOptions) ([]*PodKillReport, error)
@@ -35,6 +39,8 @@ type ContainerEngine interface {
PodStop(ctx context.Context, namesOrIds []string, options PodStopOptions) ([]*PodStopReport, error)
PodTop(ctx context.Context, options PodTopOptions) (*StringSliceReport, error)
PodUnpause(ctx context.Context, namesOrIds []string, options PodunpauseOptions) ([]*PodUnpauseReport, error)
+ PodInspect(ctx context.Context, options PodInspectOptions) (*PodInspectReport, error)
+
VolumeCreate(ctx context.Context, opts VolumeCreateOptions) (*IdOrNameResponse, error)
VolumeInspect(ctx context.Context, namesOrIds []string, opts VolumeInspectOptions) ([]*VolumeInspectReport, error)
VolumeList(ctx context.Context, opts VolumeListOptions) ([]*VolumeListReport, error)
diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go
index a0b2c6cec..cd2e79961 100644
--- a/pkg/domain/entities/pods.go
+++ b/pkg/domain/entities/pods.go
@@ -3,6 +3,7 @@ package entities
import (
"time"
+ "github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/specgen"
)
@@ -164,3 +165,14 @@ type PodPSOptions struct {
Quiet bool
Sort string
}
+
+type PodInspectOptions struct {
+ Latest bool
+
+ // Options for the API.
+ NameOrID string
+}
+
+type PodInspectReport struct {
+ *libpod.PodInspect
+}
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index d3d51db82..929c3f335 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -5,16 +5,18 @@ package abi
import (
"context"
"io/ioutil"
+ "strconv"
"strings"
"github.com/containers/buildah"
"github.com/containers/image/v5/manifest"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/libpod/events"
"github.com/containers/libpod/libpod/image"
- "github.com/containers/libpod/pkg/adapter/shortcuts"
"github.com/containers/libpod/pkg/checkpoint"
"github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/domain/infra/abi/terminal"
"github.com/containers/libpod/pkg/signal"
"github.com/containers/libpod/pkg/specgen"
"github.com/containers/libpod/pkg/specgen/generate"
@@ -64,7 +66,7 @@ func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []strin
var (
responses []entities.WaitReport
)
- ctrs, err := shortcuts.GetContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
+ ctrs, err := getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
if err != nil {
return nil, err
}
@@ -90,7 +92,7 @@ func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []stri
if options.All {
ctrs, err = ic.Libpod.GetAllContainers()
} else {
- ctrs, err = shortcuts.GetContainersByContext(false, false, namesOrIds, ic.Libpod)
+ ctrs, err = getContainersByContext(false, false, namesOrIds, ic.Libpod)
}
if err != nil {
return nil, err
@@ -111,7 +113,7 @@ func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []st
if options.All {
ctrs, err = ic.Libpod.GetAllContainers()
} else {
- ctrs, err = shortcuts.GetContainersByContext(false, false, namesOrIds, ic.Libpod)
+ ctrs, err = getContainersByContext(false, false, namesOrIds, ic.Libpod)
}
if err != nil {
return nil, err
@@ -135,7 +137,7 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
id := strings.Split(string(content), "\n")[0]
names = append(names, id)
}
- ctrs, err := shortcuts.GetContainersByContext(options.All, options.Latest, names, ic.Libpod)
+ ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
return nil, err
}
@@ -171,7 +173,7 @@ func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []strin
if err != nil {
return nil, err
}
- ctrs, err := shortcuts.GetContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
+ ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
if err != nil {
return nil, err
}
@@ -187,7 +189,7 @@ func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []st
var (
reports []*entities.RestartReport
)
- ctrs, err := shortcuts.GetContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
+ ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
if err != nil {
return nil, err
}
@@ -229,7 +231,7 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string,
names = append(names, id)
}
- ctrs, err := shortcuts.GetContainersByContext(options.All, options.Latest, names, ic.Libpod)
+ ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
// Failed to get containers. If force is specified, get the containers ID
// and evict them
@@ -277,7 +279,7 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string,
func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, error) {
var reports []*entities.ContainerInspectReport
- ctrs, err := shortcuts.GetContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
+ ctrs, err := getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
if err != nil {
return nil, err
}
@@ -455,3 +457,163 @@ func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecG
}
return &entities.ContainerCreateReport{Id: ctr.ID()}, nil
}
+
+func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrId string, options entities.AttachOptions) error {
+ ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrId}, ic.Libpod)
+ if err != nil {
+ return err
+ }
+ ctr := ctrs[0]
+ conState, err := ctr.State()
+ if err != nil {
+ return errors.Wrapf(err, "unable to determine state of %s", ctr.ID())
+ }
+ if conState != define.ContainerStateRunning {
+ return errors.Errorf("you can only attach to running containers")
+ }
+
+ // If the container is in a pod, also set to recursively start dependencies
+ if err := terminal.StartAttachCtr(ctx, ctr, options.Stdin, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, false, ctr.PodID() != ""); err != nil && errors.Cause(err) != define.ErrDetach {
+ return errors.Wrapf(err, "error attaching to container %s", ctr.ID())
+ }
+ return nil
+}
+
+func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrId string, options entities.ExecOptions) (int, error) {
+ ec := define.ExecErrorCodeGeneric
+ if options.PreserveFDs > 0 {
+ entries, err := ioutil.ReadDir("/proc/self/fd")
+ if err != nil {
+ return ec, errors.Wrapf(err, "unable to read /proc/self/fd")
+ }
+
+ m := make(map[int]bool)
+ for _, e := range entries {
+ i, err := strconv.Atoi(e.Name())
+ if err != nil {
+ return ec, errors.Wrapf(err, "cannot parse %s in /proc/self/fd", e.Name())
+ }
+ m[i] = true
+ }
+
+ for i := 3; i < 3+int(options.PreserveFDs); i++ {
+ if _, found := m[i]; !found {
+ return ec, errors.New("invalid --preserve-fds=N specified. Not enough FDs available")
+ }
+ }
+ }
+ ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrId}, ic.Libpod)
+ if err != nil {
+ return ec, err
+ }
+ ctr := ctrs[0]
+ ec, err = terminal.ExecAttachCtr(ctx, ctr, options.Tty, options.Privileged, options.Envs, options.Cmd, options.User, options.WorkDir, &options.Streams, options.PreserveFDs, options.DetachKeys)
+ return define.TranslateExecErrorToExitCode(ec, err), err
+}
+
+func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) {
+ var reports []*entities.ContainerStartReport
+ var exitCode = define.ExecErrorCodeGeneric
+ ctrs, err := getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
+ if err != nil {
+ return nil, err
+ }
+ // There can only be one container if attach was used
+ for _, ctr := range ctrs {
+ ctrState, err := ctr.State()
+ if err != nil {
+ return nil, err
+ }
+ ctrRunning := ctrState == define.ContainerStateRunning
+
+ if options.Attach {
+ err = terminal.StartAttachCtr(ctx, ctr, options.Stdout, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, !ctrRunning, ctr.PodID() != "")
+ if errors.Cause(err) == define.ErrDetach {
+ // User manually detached
+ // Exit cleanly immediately
+ reports = append(reports, &entities.ContainerStartReport{
+ Id: ctr.ID(),
+ Err: nil,
+ ExitCode: 0,
+ })
+ return reports, nil
+ }
+
+ if errors.Cause(err) == define.ErrWillDeadlock {
+ logrus.Debugf("Deadlock error: %v", err)
+ reports = append(reports, &entities.ContainerStartReport{
+ Id: ctr.ID(),
+ Err: err,
+ ExitCode: define.ExitCode(err),
+ })
+ return reports, errors.Errorf("attempting to start container %s would cause a deadlock; please run 'podman system renumber' to resolve", ctr.ID())
+ }
+
+ if ctrRunning {
+ reports = append(reports, &entities.ContainerStartReport{
+ Id: ctr.ID(),
+ Err: nil,
+ ExitCode: 0,
+ })
+ return reports, err
+ }
+
+ if err != nil {
+ reports = append(reports, &entities.ContainerStartReport{
+ Id: ctr.ID(),
+ Err: err,
+ ExitCode: exitCode,
+ })
+ return reports, errors.Wrapf(err, "unable to start container %s", ctr.ID())
+ }
+
+ if ecode, err := ctr.Wait(); err != nil {
+ if errors.Cause(err) == define.ErrNoSuchCtr {
+ // Check events
+ event, err := ic.Libpod.GetLastContainerEvent(ctr.ID(), events.Exited)
+ if err != nil {
+ logrus.Errorf("Cannot get exit code: %v", err)
+ exitCode = define.ExecErrorCodeNotFound
+ } else {
+ exitCode = event.ContainerExitCode
+ }
+ }
+ } else {
+ exitCode = int(ecode)
+ }
+ reports = append(reports, &entities.ContainerStartReport{
+ Id: ctr.ID(),
+ Err: err,
+ ExitCode: exitCode,
+ })
+ return reports, nil
+ } // end attach
+
+ // Start the container if it's not running already.
+ if !ctrRunning {
+ // Handle non-attach start
+ // If the container is in a pod, also set to recursively start dependencies
+ report := &entities.ContainerStartReport{
+ Id: ctr.ID(),
+ ExitCode: 125,
+ }
+ if err := ctr.Start(ctx, ctr.PodID() != ""); err != nil {
+ //if lastError != nil {
+ // fmt.Fprintln(os.Stderr, lastError)
+ //}
+ report.Err = err
+ if errors.Cause(err) == define.ErrWillDeadlock {
+ report.Err = errors.Wrapf(err, "please run 'podman system renumber' to resolve deadlocks")
+ reports = append(reports, report)
+ continue
+ }
+ report.Err = errors.Wrapf(err, "unable to start container %q", ctr.ID())
+ reports = append(reports, report)
+ continue
+ }
+ report.ExitCode = 0
+ reports = append(reports, report)
+ }
+ }
+ return reports, nil
+}
diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go
index 494a048ec..073cd8d5c 100644
--- a/pkg/domain/infra/abi/pods.go
+++ b/pkg/domain/infra/abi/pods.go
@@ -331,3 +331,24 @@ func (ic *ContainerEngine) PodPs(ctx context.Context, options entities.PodPSOpti
}
return reports, nil
}
+
+func (ic *ContainerEngine) PodInspect(ctx context.Context, options entities.PodInspectOptions) (*entities.PodInspectReport, error) {
+ var (
+ pod *libpod.Pod
+ err error
+ )
+ // Look up the pod.
+ if options.Latest {
+ pod, err = ic.Libpod.GetLatestPod()
+ } else {
+ pod, err = ic.Libpod.LookupPod(options.NameOrID)
+ }
+ if err != nil {
+ return nil, errors.Wrap(err, "unable to lookup requested container")
+ }
+ inspect, err := pod.Inspect()
+ if err != nil {
+ return nil, err
+ }
+ return &entities.PodInspectReport{PodInspect: inspect}, nil
+}
diff --git a/pkg/domain/infra/abi/terminal/sigproxy_linux.go b/pkg/domain/infra/abi/terminal/sigproxy_linux.go
new file mode 100644
index 000000000..d7f5853d8
--- /dev/null
+++ b/pkg/domain/infra/abi/terminal/sigproxy_linux.go
@@ -0,0 +1,47 @@
+// +build ABISupport
+
+package terminal
+
+import (
+ "os"
+ "syscall"
+
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/signal"
+ "github.com/sirupsen/logrus"
+)
+
+// ProxySignals ...
+func ProxySignals(ctr *libpod.Container) {
+ sigBuffer := make(chan os.Signal, 128)
+ signal.CatchAll(sigBuffer)
+
+ logrus.Debugf("Enabling signal proxying")
+
+ go func() {
+ for s := range sigBuffer {
+ // Ignore SIGCHLD and SIGPIPE - these are mostly likely
+ // intended for the podman command itself.
+ // SIGURG was added because of golang 1.14 and its preemptive changes
+ // causing more signals to "show up".
+ // https://github.com/containers/libpod/issues/5483
+ if s == syscall.SIGCHLD || s == syscall.SIGPIPE || s == syscall.SIGURG {
+ continue
+ }
+
+ if err := ctr.Kill(uint(s.(syscall.Signal))); err != nil {
+ // If the container dies, and we find out here,
+ // we need to forward that one signal to
+ // ourselves so that it is not lost, and then
+ // we terminate the proxy and let the defaults
+ // play out.
+ logrus.Errorf("Error forwarding signal %d to container %s: %v", s, ctr.ID(), err)
+ signal.StopCatch(sigBuffer)
+ if err := syscall.Kill(syscall.Getpid(), s.(syscall.Signal)); err != nil {
+ logrus.Errorf("failed to kill pid %d", syscall.Getpid())
+ }
+ return
+ }
+ }
+ }()
+}
diff --git a/pkg/domain/infra/abi/terminal/terminal.go b/pkg/domain/infra/abi/terminal/terminal.go
new file mode 100644
index 000000000..f187bdd6b
--- /dev/null
+++ b/pkg/domain/infra/abi/terminal/terminal.go
@@ -0,0 +1,103 @@
+// +build ABISupport
+
+package terminal
+
+import (
+ "context"
+ "os"
+ "os/signal"
+
+ lsignal "github.com/containers/libpod/pkg/signal"
+ "github.com/docker/docker/pkg/term"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "k8s.io/client-go/tools/remotecommand"
+)
+
+// RawTtyFormatter ...
+type RawTtyFormatter struct {
+}
+
+// getResize returns a TerminalSize command matching stdin's current
+// size on success, and nil on errors.
+func getResize() *remotecommand.TerminalSize {
+ winsize, err := term.GetWinsize(os.Stdin.Fd())
+ if err != nil {
+ logrus.Warnf("Could not get terminal size %v", err)
+ return nil
+ }
+ return &remotecommand.TerminalSize{
+ Width: winsize.Width,
+ Height: winsize.Height,
+ }
+}
+
+// Helper for prepareAttach - set up a goroutine to generate terminal resize events
+func resizeTty(ctx context.Context, resize chan remotecommand.TerminalSize) {
+ sigchan := make(chan os.Signal, 1)
+ signal.Notify(sigchan, lsignal.SIGWINCH)
+ go func() {
+ defer close(resize)
+ // Update the terminal size immediately without waiting
+ // for a SIGWINCH to get the correct initial size.
+ resizeEvent := getResize()
+ for {
+ if resizeEvent == nil {
+ select {
+ case <-ctx.Done():
+ return
+ case <-sigchan:
+ resizeEvent = getResize()
+ }
+ } else {
+ select {
+ case <-ctx.Done():
+ return
+ case <-sigchan:
+ resizeEvent = getResize()
+ case resize <- *resizeEvent:
+ resizeEvent = nil
+ }
+ }
+ }
+ }()
+}
+
+func restoreTerminal(state *term.State) error {
+ logrus.SetFormatter(&logrus.TextFormatter{})
+ return term.RestoreTerminal(os.Stdin.Fd(), state)
+}
+
+// Format ...
+func (f *RawTtyFormatter) Format(entry *logrus.Entry) ([]byte, error) {
+ textFormatter := logrus.TextFormatter{}
+ bytes, err := textFormatter.Format(entry)
+
+ if err == nil {
+ bytes = append(bytes, '\r')
+ }
+
+ return bytes, err
+}
+
+func handleTerminalAttach(ctx context.Context, resize chan remotecommand.TerminalSize) (context.CancelFunc, *term.State, error) {
+ logrus.Debugf("Handling terminal attach")
+
+ subCtx, cancel := context.WithCancel(ctx)
+
+ resizeTty(subCtx, resize)
+
+ oldTermState, err := term.SaveState(os.Stdin.Fd())
+ if err != nil {
+ // allow caller to not have to do any cleaning up if we error here
+ cancel()
+ return nil, nil, errors.Wrapf(err, "unable to save terminal state")
+ }
+
+ logrus.SetFormatter(&RawTtyFormatter{})
+ if _, err := term.SetRawTerminal(os.Stdin.Fd()); err != nil {
+ return cancel, nil, err
+ }
+
+ return cancel, oldTermState, nil
+}
diff --git a/pkg/domain/infra/abi/terminal/terminal_linux.go b/pkg/domain/infra/abi/terminal/terminal_linux.go
new file mode 100644
index 000000000..664205df1
--- /dev/null
+++ b/pkg/domain/infra/abi/terminal/terminal_linux.go
@@ -0,0 +1,123 @@
+// +build ABISupport
+
+package terminal
+
+import (
+ "bufio"
+ "context"
+ "fmt"
+ "os"
+
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "golang.org/x/crypto/ssh/terminal"
+ "k8s.io/client-go/tools/remotecommand"
+)
+
+// ExecAttachCtr execs and attaches to a container
+func ExecAttachCtr(ctx context.Context, ctr *libpod.Container, tty, privileged bool, env map[string]string, cmd []string, user, workDir string, streams *define.AttachStreams, preserveFDs uint, detachKeys string) (int, error) {
+ resize := make(chan remotecommand.TerminalSize)
+ haveTerminal := terminal.IsTerminal(int(os.Stdin.Fd()))
+
+ // Check if we are attached to a terminal. If we are, generate resize
+ // events, and set the terminal to raw mode
+ if haveTerminal && tty {
+ cancel, oldTermState, err := handleTerminalAttach(ctx, resize)
+ if err != nil {
+ return -1, err
+ }
+ defer cancel()
+ defer func() {
+ if err := restoreTerminal(oldTermState); err != nil {
+ logrus.Errorf("unable to restore terminal: %q", err)
+ }
+ }()
+ }
+
+ execConfig := new(libpod.ExecConfig)
+ execConfig.Command = cmd
+ execConfig.Terminal = tty
+ execConfig.Privileged = privileged
+ execConfig.Environment = env
+ execConfig.User = user
+ execConfig.WorkDir = workDir
+ execConfig.DetachKeys = &detachKeys
+ execConfig.PreserveFDs = preserveFDs
+
+ return ctr.Exec(execConfig, streams, resize)
+}
+
+// StartAttachCtr starts and (if required) attaches to a container
+// if you change the signature of this function from os.File to io.Writer, it will trigger a downstream
+// error. we may need to just lint disable this one.
+func StartAttachCtr(ctx context.Context, ctr *libpod.Container, stdout, stderr, stdin *os.File, detachKeys string, sigProxy bool, startContainer bool, recursive bool) error { //nolint-interfacer
+ resize := make(chan remotecommand.TerminalSize)
+
+ haveTerminal := terminal.IsTerminal(int(os.Stdin.Fd()))
+
+ // Check if we are attached to a terminal. If we are, generate resize
+ // events, and set the terminal to raw mode
+ if haveTerminal && ctr.Spec().Process.Terminal {
+ cancel, oldTermState, err := handleTerminalAttach(ctx, resize)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ if err := restoreTerminal(oldTermState); err != nil {
+ logrus.Errorf("unable to restore terminal: %q", err)
+ }
+ }()
+ defer cancel()
+ }
+
+ streams := new(define.AttachStreams)
+ streams.OutputStream = stdout
+ streams.ErrorStream = stderr
+ streams.InputStream = bufio.NewReader(stdin)
+ streams.AttachOutput = true
+ streams.AttachError = true
+ streams.AttachInput = true
+
+ if stdout == nil {
+ logrus.Debugf("Not attaching to stdout")
+ streams.AttachOutput = false
+ }
+ if stderr == nil {
+ logrus.Debugf("Not attaching to stderr")
+ streams.AttachError = false
+ }
+ if stdin == nil {
+ logrus.Debugf("Not attaching to stdin")
+ streams.AttachInput = false
+ }
+
+ if !startContainer {
+ if sigProxy {
+ ProxySignals(ctr)
+ }
+
+ return ctr.Attach(streams, detachKeys, resize)
+ }
+
+ attachChan, err := ctr.StartAndAttach(ctx, streams, detachKeys, resize, recursive)
+ if err != nil {
+ return err
+ }
+
+ if sigProxy {
+ ProxySignals(ctr)
+ }
+
+ if stdout == nil && stderr == nil {
+ fmt.Printf("%s\n", ctr.ID())
+ }
+
+ err = <-attachChan
+ if err != nil {
+ return errors.Wrapf(err, "error attaching to container %s", ctr.ID())
+ }
+
+ return nil
+}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index ae8994cba..4101068ba 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -305,3 +305,15 @@ func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecG
}
return &entities.ContainerCreateReport{Id: response.ID}, nil
}
+
+func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrId string, options entities.AttachOptions) error {
+ return errors.New("not implemented")
+}
+
+func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrId string, options entities.ExecOptions) (int, error) {
+ return 125, errors.New("not implemented")
+}
+
+func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) {
+ return nil, errors.New("not implemented")
+}
diff --git a/pkg/domain/infra/tunnel/pods.go b/pkg/domain/infra/tunnel/pods.go
index ad87a0a29..dad77284f 100644
--- a/pkg/domain/infra/tunnel/pods.go
+++ b/pkg/domain/infra/tunnel/pods.go
@@ -197,3 +197,13 @@ func (ic *ContainerEngine) PodTop(ctx context.Context, options entities.PodTopOp
func (ic *ContainerEngine) PodPs(ctx context.Context, options entities.PodPSOptions) ([]*entities.ListPodsReport, error) {
return pods.List(ic.ClientCxt, options.Filters)
}
+
+func (ic *ContainerEngine) PodInspect(ctx context.Context, options entities.PodInspectOptions) (*entities.PodInspectReport, error) {
+ switch {
+ case options.Latest:
+ return nil, errors.New("latest is not supported")
+ case options.NameOrID == "":
+ return nil, errors.New("NameOrID must be specified")
+ }
+ return pods.Inspect(ic.ClientCxt, options.NameOrID)
+}
diff --git a/pkg/domain/infra/tunnel/system.go b/pkg/domain/infra/tunnel/system.go
new file mode 100644
index 000000000..5bafef1fe
--- /dev/null
+++ b/pkg/domain/infra/tunnel/system.go
@@ -0,0 +1 @@
+package tunnel
diff --git a/pkg/varlinkapi/attach.go b/pkg/varlinkapi/attach.go
index 94f4d653e..34f351669 100644
--- a/pkg/varlinkapi/attach.go
+++ b/pkg/varlinkapi/attach.go
@@ -16,7 +16,7 @@ import (
"k8s.io/client-go/tools/remotecommand"
)
-func setupStreams(call iopodman.VarlinkCall) (*bufio.Reader, *bufio.Writer, *io.PipeReader, *io.PipeWriter, *libpod.AttachStreams) {
+func setupStreams(call iopodman.VarlinkCall) (*bufio.Reader, *bufio.Writer, *io.PipeReader, *io.PipeWriter, *define.AttachStreams) {
// These are the varlink sockets
reader := call.Call.Reader
@@ -30,7 +30,7 @@ func setupStreams(call iopodman.VarlinkCall) (*bufio.Reader, *bufio.Writer, *io.
// TODO if runc ever starts passing stderr, we can too
// stderrWriter := NewVirtWriteCloser(writer, ToStderr)
- streams := libpod.AttachStreams{
+ streams := define.AttachStreams{
OutputStream: stdoutWriter,
InputStream: bufio.NewReader(pr),
// Runc eats the error stream
@@ -117,7 +117,7 @@ func (i *LibpodAPI) Attach(call iopodman.VarlinkCall, name string, detachKeys st
return call.Writer.Flush()
}
-func attach(ctr *libpod.Container, streams *libpod.AttachStreams, detachKeys string, resize chan remotecommand.TerminalSize, errChan chan error) error {
+func attach(ctr *libpod.Container, streams *define.AttachStreams, detachKeys string, resize chan remotecommand.TerminalSize, errChan chan error) error {
go func() {
if err := ctr.Attach(streams, detachKeys, resize); err != nil {
errChan <- err
@@ -127,7 +127,7 @@ func attach(ctr *libpod.Container, streams *libpod.AttachStreams, detachKeys str
return attachError
}
-func startAndAttach(ctr *libpod.Container, streams *libpod.AttachStreams, detachKeys string, resize chan remotecommand.TerminalSize, errChan chan error) error {
+func startAndAttach(ctr *libpod.Container, streams *define.AttachStreams, detachKeys string, resize chan remotecommand.TerminalSize, errChan chan error) error {
var finalErr error
attachChan, err := ctr.StartAndAttach(getContext(), streams, detachKeys, resize, false)
if err != nil {
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
index 599bdb6e2..9c979e5e2 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
@@ -31,6 +31,7 @@ const (
// Disabled constant to indicate SELinux is disabled
Disabled = -1
+ contextFile = "/usr/share/containers/selinux/contexts"
selinuxDir = "/etc/selinux/"
selinuxConfig = selinuxDir + "config"
selinuxfsMount = "/sys/fs/selinux"
@@ -684,23 +685,26 @@ func ROFileLabel() string {
return roFileLabel
}
-/*
-ContainerLabels returns an allocated processLabel and fileLabel to be used for
-container labeling by the calling process.
-*/
-func ContainerLabels() (processLabel string, fileLabel string) {
+func openContextFile() (*os.File, error) {
+ if f, err := os.Open(contextFile); err == nil {
+ return f, nil
+ }
+ lxcPath := filepath.Join(getSELinuxPolicyRoot(), "/contexts/lxc_contexts")
+ return os.Open(lxcPath)
+}
+
+var labels = loadLabels()
+
+func loadLabels() map[string]string {
var (
val, key string
bufin *bufio.Reader
)
- if !GetEnabled() {
- return "", ""
- }
- lxcPath := fmt.Sprintf("%s/contexts/lxc_contexts", getSELinuxPolicyRoot())
- in, err := os.Open(lxcPath)
+ labels := make(map[string]string)
+ in, err := openContextFile()
if err != nil {
- return "", ""
+ return labels
}
defer in.Close()
@@ -712,7 +716,7 @@ func ContainerLabels() (processLabel string, fileLabel string) {
if err == io.EOF {
done = true
} else {
- goto exit
+ break
}
}
line = strings.TrimSpace(line)
@@ -726,26 +730,64 @@ func ContainerLabels() (processLabel string, fileLabel string) {
}
if groups := assignRegex.FindStringSubmatch(line); groups != nil {
key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
- if key == "process" {
- processLabel = strings.Trim(val, "\"")
- }
- if key == "file" {
- fileLabel = strings.Trim(val, "\"")
- }
- if key == "ro_file" {
- roFileLabel = strings.Trim(val, "\"")
- }
+ labels[key] = strings.Trim(val, "\"")
}
}
- if processLabel == "" || fileLabel == "" {
+ return labels
+}
+
+/*
+KVMContainerLabels returns the default processLabel and mountLabel to be used
+for kvm containers by the calling process.
+*/
+func KVMContainerLabels() (string, string) {
+ processLabel := labels["kvm_process"]
+ if processLabel == "" {
+ processLabel = labels["process"]
+ }
+
+ return addMcs(processLabel, labels["file"])
+}
+
+/*
+InitContainerLabels returns the default processLabel and file labels to be
+used for containers running an init system like systemd by the calling process.
+*/
+func InitContainerLabels() (string, string) {
+ processLabel := labels["init_process"]
+ if processLabel == "" {
+ processLabel = labels["process"]
+ }
+
+ return addMcs(processLabel, labels["file"])
+}
+
+/*
+ContainerLabels returns an allocated processLabel and fileLabel to be used for
+container labeling by the calling process.
+*/
+func ContainerLabels() (processLabel string, fileLabel string) {
+ if !GetEnabled() {
return "", ""
}
+ processLabel = labels["process"]
+ fileLabel = labels["file"]
+ roFileLabel = labels["ro_file"]
+
+ if processLabel == "" || fileLabel == "" {
+ return "", fileLabel
+ }
+
if roFileLabel == "" {
roFileLabel = fileLabel
}
-exit:
+
+ return addMcs(processLabel, fileLabel)
+}
+
+func addMcs(processLabel, fileLabel string) (string, string) {
scon, _ := NewContext(processLabel)
if scon["level"] != "" {
mcs := uniqMcs(1024)
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 2ec974c02..f4663b04d 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -82,7 +82,7 @@ github.com/containers/buildah/pkg/secrets
github.com/containers/buildah/pkg/supplemented
github.com/containers/buildah/pkg/umask
github.com/containers/buildah/util
-# github.com/containers/common v0.8.0
+# github.com/containers/common v0.8.1
github.com/containers/common/pkg/apparmor
github.com/containers/common/pkg/capabilities
github.com/containers/common/pkg/cgroupv2
@@ -411,7 +411,7 @@ github.com/opencontainers/runtime-tools/generate
github.com/opencontainers/runtime-tools/generate/seccomp
github.com/opencontainers/runtime-tools/specerror
github.com/opencontainers/runtime-tools/validate
-# github.com/opencontainers/selinux v1.4.0
+# github.com/opencontainers/selinux v1.5.0
github.com/opencontainers/selinux/go-selinux
github.com/opencontainers/selinux/go-selinux/label
github.com/opencontainers/selinux/pkg/pwalk