aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Heon <matthew.heon@pm.me>2020-05-18 17:27:27 -0400
committerMatthew Heon <matthew.heon@pm.me>2020-05-20 16:11:05 -0400
commit05a034118fcb5057593cb1492f1c9be59f7a88d8 (patch)
treed85e6737ba5117d893985788bb79007247e74578
parent43413887c0d8a20095e454d1046df46a42810e75 (diff)
downloadpodman-05a034118fcb5057593cb1492f1c9be59f7a88d8.tar.gz
podman-05a034118fcb5057593cb1492f1c9be59f7a88d8.tar.bz2
podman-05a034118fcb5057593cb1492f1c9be59f7a88d8.zip
Add CLI frontend for detached exec
Add a new ContainerEngine method for creating a detached exec session, and wire in the frontend code to do this. As part of this, move Streams out of ExecOptions to the function signature in an effort to share the struct between both methods. Fixes #5884 Signed-off-by: Matthew Heon <matthew.heon@pm.me>
-rw-r--r--cmd/podman/containers/exec.go35
-rw-r--r--pkg/domain/entities/containers.go1
-rw-r--r--pkg/domain/entities/engine_container.go3
-rw-r--r--pkg/domain/infra/abi/containers.go56
-rw-r--r--pkg/domain/infra/abi/terminal/terminal_linux.go14
-rw-r--r--pkg/domain/infra/tunnel/containers.go6
6 files changed, 88 insertions, 27 deletions
diff --git a/cmd/podman/containers/exec.go b/cmd/podman/containers/exec.go
index 0992b3862..7554d6a93 100644
--- a/cmd/podman/containers/exec.go
+++ b/cmd/podman/containers/exec.go
@@ -2,9 +2,11 @@ package containers
import (
"bufio"
+ "fmt"
"os"
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/domain/entities"
envLib "github.com/containers/libpod/pkg/env"
"github.com/pkg/errors"
@@ -41,10 +43,12 @@ var (
var (
envInput, envFile []string
execOpts entities.ExecOptions
+ execDetach bool
)
func execFlags(flags *pflag.FlagSet) {
flags.SetInterspersed(false)
+ flags.BoolVarP(&execDetach, "detach", "d", false, "Run the exec session in detached mode (backgrounded)")
flags.StringVar(&execOpts.DetachKeys, "detach-keys", containerConfig.DetachKeys(), "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")
@@ -106,16 +110,27 @@ func exec(cmd *cobra.Command, args []string) error {
}
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
+
+ if !execDetach {
+ streams := define.AttachStreams{}
+ streams.OutputStream = os.Stdout
+ streams.ErrorStream = os.Stderr
+ if execOpts.Interactive {
+ streams.InputStream = bufio.NewReader(os.Stdin)
+ streams.AttachInput = true
+ }
+ streams.AttachOutput = true
+ streams.AttachError = true
+
+ exitCode, err := registry.ContainerEngine().ContainerExec(registry.GetContext(), nameOrId, execOpts, streams)
+ registry.SetExitCode(exitCode)
+ return err
}
- execOpts.Streams.AttachOutput = true
- execOpts.Streams.AttachError = true
- exitCode, err := registry.ContainerEngine().ContainerExec(registry.GetContext(), nameOrId, execOpts)
- registry.SetExitCode(exitCode)
- return err
+ id, err := registry.ContainerEngine().ContainerExecDetached(registry.GetContext(), nameOrId, execOpts)
+ if err != nil {
+ return err
+ }
+ fmt.Println(id)
+ return nil
}
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index 3cc4b6db1..f362f88a6 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -242,7 +242,6 @@ type ExecOptions struct {
Latest bool
PreserveFDs uint
Privileged bool
- Streams define.AttachStreams
Tty bool
User string
WorkDir string
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index e77f0758b..3d5161745 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -19,7 +19,8 @@ type ContainerEngine interface {
ContainerCp(ctx context.Context, source, dest string, options ContainerCpOptions) (*ContainerCpReport, error)
ContainerCreate(ctx context.Context, s *specgen.SpecGenerator) (*ContainerCreateReport, error)
ContainerDiff(ctx context.Context, nameOrId string, options DiffOptions) (*DiffReport, error)
- ContainerExec(ctx context.Context, nameOrId string, options ExecOptions) (int, error)
+ ContainerExec(ctx context.Context, nameOrId string, options ExecOptions, streams define.AttachStreams) (int, error)
+ ContainerExecDetached(ctx context.Context, nameOrID string, options ExecOptions) (string, error)
ContainerExists(ctx context.Context, nameOrId string) (*BoolReport, error)
ContainerExport(ctx context.Context, nameOrId string, options ContainerExportOptions) error
ContainerInit(ctx context.Context, namesOrIds []string, options ContainerInitOptions) ([]*ContainerInitReport, error)
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 035efe575..18282bb79 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -536,7 +536,22 @@ func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrId string,
return nil
}
-func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrId string, options entities.ExecOptions) (int, error) {
+func makeExecConfig(options entities.ExecOptions) *libpod.ExecConfig {
+ execConfig := new(libpod.ExecConfig)
+ execConfig.Command = options.Cmd
+ execConfig.Terminal = options.Tty
+ execConfig.Privileged = options.Privileged
+ execConfig.Environment = options.Envs
+ execConfig.User = options.User
+ execConfig.WorkDir = options.WorkDir
+ execConfig.DetachKeys = &options.DetachKeys
+ execConfig.PreserveFDs = options.PreserveFDs
+ execConfig.AttachStdin = options.Interactive
+
+ return execConfig
+}
+
+func checkExecPreserveFDs(options entities.ExecOptions) (int, error) {
ec := define.ExecErrorCodeGeneric
if options.PreserveFDs > 0 {
entries, err := ioutil.ReadDir("/proc/self/fd")
@@ -559,15 +574,52 @@ func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrId string, o
}
}
}
+ return ec, nil
+}
+
+func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrId string, options entities.ExecOptions, streams define.AttachStreams) (int, error) {
+ ec, err := checkExecPreserveFDs(options)
+ if err != nil {
+ return ec, err
+ }
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)
+
+ execConfig := makeExecConfig(options)
+
+ ec, err = terminal.ExecAttachCtr(ctx, ctr, execConfig, &streams)
return define.TranslateExecErrorToExitCode(ec, err), err
}
+func (ic *ContainerEngine) ContainerExecDetached(ctx context.Context, nameOrId string, options entities.ExecOptions) (string, error) {
+ _, err := checkExecPreserveFDs(options)
+ if err != nil {
+ return "", err
+ }
+ ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrId}, ic.Libpod)
+ if err != nil {
+ return "", err
+ }
+ ctr := ctrs[0]
+
+ execConfig := makeExecConfig(options)
+
+ // Create and start the exec session
+ id, err := ctr.ExecCreate(execConfig)
+ if err != nil {
+ return "", err
+ }
+
+ // TODO: we should try and retrieve exit code if this fails.
+ if err := ctr.ExecStart(id); err != nil {
+ return "", err
+ }
+ return id, nil
+}
+
func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) {
var reports []*entities.ContainerStartReport
var exitCode = define.ExecErrorCodeGeneric
diff --git a/pkg/domain/infra/abi/terminal/terminal_linux.go b/pkg/domain/infra/abi/terminal/terminal_linux.go
index 15701342f..8d9cdde03 100644
--- a/pkg/domain/infra/abi/terminal/terminal_linux.go
+++ b/pkg/domain/infra/abi/terminal/terminal_linux.go
@@ -15,13 +15,13 @@ 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 *define.AttachStreams, preserveFDs uint, detachKeys string) (int, error) {
+func ExecAttachCtr(ctx context.Context, ctr *libpod.Container, execConfig *libpod.ExecConfig, streams *define.AttachStreams) (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 {
+ if haveTerminal && execConfig.Terminal {
cancel, oldTermState, err := handleTerminalAttach(ctx, resize)
if err != nil {
return -1, err
@@ -34,16 +34,6 @@ func ExecAttachCtr(ctx context.Context, ctr *libpod.Container, tty, privileged b
}()
}
- 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)
}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index cebd332e3..b460e3e91 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -329,10 +329,14 @@ func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrId string,
return containers.Attach(ic.ClientCxt, nameOrId, &options.DetachKeys, nil, bindings.PTrue, options.Stdin, options.Stdout, options.Stderr)
}
-func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrId string, options entities.ExecOptions) (int, error) {
+func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrId string, options entities.ExecOptions, streams define.AttachStreams) (int, error) {
return 125, errors.New("not implemented")
}
+func (ic *ContainerEngine) ContainerExecDetached(ctx context.Context, nameOrID string, options entities.ExecOptions) (string, error) {
+ return "", errors.New("not implemented")
+}
+
func startAndAttach(ic *ContainerEngine, name string, detachKeys *string, input, output, errput *os.File) error { //nolint
attachErr := make(chan error)
go func() {