Merge pull request #2602 from BrianWieder/1681-docker-exec-env-file

Added env-file flag to docker exec
This commit is contained in:
Silvin Lubecki 2020-06-30 11:29:25 +02:00 committed by GitHub
commit 1c6dd42dab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 85 additions and 17 deletions

View File

@ -27,10 +27,14 @@ type execOptions struct {
workdir string
container string
command []string
envFile opts.ListOpts
}
func newExecOptions() execOptions {
return execOptions{env: opts.NewListOpts(opts.ValidateEnv)}
return execOptions{
env: opts.NewListOpts(opts.ValidateEnv),
envFile: opts.NewListOpts(nil),
}
}
// NewExecCommand creates a new cobra.Command for `docker exec`
@ -59,6 +63,8 @@ func NewExecCommand(dockerCli command.Cli) *cobra.Command {
flags.BoolVarP(&options.privileged, "privileged", "", false, "Give extended privileges to the command")
flags.VarP(&options.env, "env", "e", "Set environment variables")
flags.SetAnnotation("env", "version", []string{"1.25"})
flags.Var(&options.envFile, "env-file", "Read in a file of environment variables")
flags.SetAnnotation("env-file", "version", []string{"1.25"})
flags.StringVarP(&options.workdir, "workdir", "w", "", "Working directory inside the container")
flags.SetAnnotation("workdir", "version", []string{"1.35"})
@ -66,7 +72,11 @@ func NewExecCommand(dockerCli command.Cli) *cobra.Command {
}
func runExec(dockerCli command.Cli, options execOptions) error {
execConfig := parseExec(options, dockerCli.ConfigFile())
execConfig, err := parseExec(options, dockerCli.ConfigFile())
if err != nil {
return err
}
ctx := context.Background()
client := dockerCli.Client()
@ -185,30 +195,35 @@ func getExecExitStatus(ctx context.Context, client apiclient.ContainerAPIClient,
// parseExec parses the specified args for the specified command and generates
// an ExecConfig from it.
func parseExec(opts execOptions, configFile *configfile.ConfigFile) *types.ExecConfig {
func parseExec(execOpts execOptions, configFile *configfile.ConfigFile) (*types.ExecConfig, error) {
execConfig := &types.ExecConfig{
User: opts.user,
Privileged: opts.privileged,
Tty: opts.tty,
Cmd: opts.command,
Detach: opts.detach,
Env: opts.env.GetAll(),
WorkingDir: opts.workdir,
User: execOpts.user,
Privileged: execOpts.privileged,
Tty: execOpts.tty,
Cmd: execOpts.command,
Detach: execOpts.detach,
WorkingDir: execOpts.workdir,
}
// collect all the environment variables for the container
var err error
if execConfig.Env, err = opts.ReadKVEnvStrings(execOpts.envFile.GetAll(), execOpts.env.GetAll()); err != nil {
return nil, err
}
// If -d is not set, attach to everything by default
if !opts.detach {
if !execOpts.detach {
execConfig.AttachStdout = true
execConfig.AttachStderr = true
if opts.interactive {
if execOpts.interactive {
execConfig.AttachStdin = true
}
}
if opts.detachKeys != "" {
execConfig.DetachKeys = opts.detachKeys
if execOpts.detachKeys != "" {
execConfig.DetachKeys = execOpts.detachKeys
} else {
execConfig.DetachKeys = configFile.DetachKeys
}
return execConfig
return execConfig, nil
}

View File

@ -3,6 +3,7 @@ package container
import (
"context"
"io/ioutil"
"os"
"testing"
"github.com/docker/cli/cli"
@ -13,10 +14,12 @@ import (
"github.com/pkg/errors"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/fs"
)
func withDefaultOpts(options execOptions) execOptions {
options.env = opts.NewListOpts(opts.ValidateEnv)
options.envFile = opts.NewListOpts(nil)
if len(options.command) == 0 {
options.command = []string{"command"}
}
@ -24,6 +27,13 @@ func withDefaultOpts(options execOptions) execOptions {
}
func TestParseExec(t *testing.T) {
content := `ONE=1
TWO=2
`
tmpFile := fs.NewFile(t, t.Name(), fs.WithContent(content))
defer tmpFile.Remove()
testcases := []struct {
options execOptions
configFile configfile.ConfigFile
@ -102,14 +112,51 @@ func TestParseExec(t *testing.T) {
Detach: true,
},
},
{
expected: types.ExecConfig{
Cmd: []string{"command"},
AttachStdout: true,
AttachStderr: true,
Env: []string{"ONE=1", "TWO=2"},
},
options: func() execOptions {
o := withDefaultOpts(execOptions{})
o.envFile.Set(tmpFile.Path())
return o
}(),
},
{
expected: types.ExecConfig{
Cmd: []string{"command"},
AttachStdout: true,
AttachStderr: true,
Env: []string{"ONE=1", "TWO=2", "ONE=override"},
},
options: func() execOptions {
o := withDefaultOpts(execOptions{})
o.envFile.Set(tmpFile.Path())
o.env.Set("ONE=override")
return o
}(),
},
}
for _, testcase := range testcases {
execConfig := parseExec(testcase.options, &testcase.configFile)
execConfig, err := parseExec(testcase.options, &testcase.configFile)
assert.NilError(t, err)
assert.Check(t, is.DeepEqual(testcase.expected, *execConfig))
}
}
func TestParseExecNoSuchFile(t *testing.T) {
execOpts := withDefaultOpts(execOptions{})
execOpts.envFile.Set("no-such-env-file")
execConfig, err := parseExec(execOpts, &configfile.ConfigFile{})
assert.ErrorContains(t, err, "no-such-env-file")
assert.Check(t, os.IsNotExist(err))
assert.Check(t, execConfig == nil)
}
func TestRunExec(t *testing.T) {
var testcases = []struct {
doc string

View File

@ -1604,6 +1604,10 @@ _docker_container_exec() {
__docker_nospace
return
;;
--env-file)
_filedir
return
;;
--user|-u)
__docker_complete_user_group
return
@ -1615,7 +1619,7 @@ _docker_container_exec() {
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--detach -d --detach-keys --env -e --help --interactive -i --privileged -t --tty -u --user --workdir -w" -- "$cur" ) )
COMPREPLY=( $( compgen -W "--detach -d --detach-keys --env -e --env-file --help --interactive -i --privileged -t --tty -u --user --workdir -w" -- "$cur" ) )
;;
*)
__docker_complete_containers_running

View File

@ -750,6 +750,7 @@ __docker_container_subcommand() {
$opts_attach_exec_run_start \
"($help -d --detach)"{-d,--detach}"[Detached mode: leave the container running in the background]" \
"($help)*"{-e=,--env=}"[Set environment variables]:environment variable: " \
"($help)*--env-file=[Read environment variables from a file]:environment file:_files" \
"($help -i --interactive)"{-i,--interactive}"[Keep stdin open even if not attached]" \
"($help)--privileged[Give extended Linux capabilities to the command]" \
"($help -t --tty)"{-t,--tty}"[Allocate a pseudo-tty]" \

View File

@ -15,6 +15,7 @@ Options:
-d, --detach Detached mode: run command in the background
--detach-keys Override the key sequence for detaching a container
-e, --env=[] Set environment variables
--env-file Read in a file of environment variables
--help Print usage
-i, --interactive Keep STDIN open even if not attached
--privileged Give extended privileges to the command