mirror of https://github.com/docker/cli.git
container: validate --pull option on create and run
Before this change, specifying the `--pull` flag without a value, could result in the flag after it, or the positional argument to be used as value. This patch makes sure that the value is an expected value; docker create --pull --rm hello-world docker: invalid pull option: '--rm': must be one of "always", "missing" or "never". docker run --pull --rm hello-world docker: invalid pull option: '--rm': must be one of "always", "missing" or "never". docker run --pull hello-world docker: invalid pull option: 'hello-world': must be one of "always", "missing" or "never". Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
44f3b87f0e
commit
190dac77bd
|
@ -79,6 +79,10 @@ func NewCreateCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCreate(dockerCli command.Cli, flags *pflag.FlagSet, options *createOptions, copts *containerOptions) error {
|
func runCreate(dockerCli command.Cli, flags *pflag.FlagSet, options *createOptions, copts *containerOptions) error {
|
||||||
|
if err := validatePullOpt(options.pull); err != nil {
|
||||||
|
reportError(dockerCli.Err(), "create", err.Error(), true)
|
||||||
|
return cli.StatusError{StatusCode: 125}
|
||||||
|
}
|
||||||
proxyConfig := dockerCli.ConfigFile().ParseProxyConfig(dockerCli.Client().DaemonHost(), opts.ConvertKVStringsToMapWithNil(copts.env.GetAll()))
|
proxyConfig := dockerCli.ConfigFile().ParseProxyConfig(dockerCli.Client().DaemonHost(), opts.ConvertKVStringsToMapWithNil(copts.env.GetAll()))
|
||||||
newEnv := []string{}
|
newEnv := []string{}
|
||||||
for k, v := range proxyConfig {
|
for k, v := range proxyConfig {
|
||||||
|
@ -323,3 +327,19 @@ var localhostIPRegexp = regexp.MustCompile(ipLocalhost)
|
||||||
func isLocalhost(ip string) bool {
|
func isLocalhost(ip string) bool {
|
||||||
return localhostIPRegexp.MatchString(ip)
|
return localhostIPRegexp.MatchString(ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validatePullOpt(val string) error {
|
||||||
|
switch val {
|
||||||
|
case PullImageAlways, PullImageMissing, PullImageNever, "":
|
||||||
|
// valid option, but nothing to do yet
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return fmt.Errorf(
|
||||||
|
"invalid pull option: '%s': must be one of %q, %q or %q",
|
||||||
|
val,
|
||||||
|
PullImageAlways,
|
||||||
|
PullImageMissing,
|
||||||
|
PullImageNever,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package container
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
@ -10,6 +11,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/config/configfile"
|
"github.com/docker/cli/cli/config/configfile"
|
||||||
"github.com/docker/cli/internal/test"
|
"github.com/docker/cli/internal/test"
|
||||||
"github.com/docker/cli/internal/test/notary"
|
"github.com/docker/cli/internal/test/notary"
|
||||||
|
@ -18,6 +20,7 @@ import (
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
is "gotest.tools/v3/assert/cmp"
|
is "gotest.tools/v3/assert/cmp"
|
||||||
"gotest.tools/v3/fs"
|
"gotest.tools/v3/fs"
|
||||||
|
@ -153,6 +156,40 @@ func TestCreateContainerImagePullPolicy(t *testing.T) {
|
||||||
assert.Check(t, is.Equal(c.ExpectedPulls, pullCounter))
|
assert.Check(t, is.Equal(c.ExpectedPulls, pullCounter))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreateContainerImagePullPolicyInvalid(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
PullPolicy string
|
||||||
|
ExpectedErrMsg string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
PullPolicy: "busybox:latest",
|
||||||
|
ExpectedErrMsg: `invalid pull option: 'busybox:latest': must be one of "always", "missing" or "never"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
PullPolicy: "--network=foo",
|
||||||
|
ExpectedErrMsg: `invalid pull option: '--network=foo': must be one of "always", "missing" or "never"`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range cases {
|
||||||
|
tc := tc
|
||||||
|
t.Run(tc.PullPolicy, func(t *testing.T) {
|
||||||
|
dockerCli := test.NewFakeCli(&fakeClient{})
|
||||||
|
err := runCreate(
|
||||||
|
dockerCli,
|
||||||
|
&pflag.FlagSet{},
|
||||||
|
&createOptions{pull: tc.PullPolicy},
|
||||||
|
&containerOptions{},
|
||||||
|
)
|
||||||
|
|
||||||
|
statusErr := cli.StatusError{}
|
||||||
|
assert.Check(t, errors.As(err, &statusErr))
|
||||||
|
assert.Equal(t, statusErr.StatusCode, 125)
|
||||||
|
assert.Check(t, is.Contains(dockerCli.ErrBuffer().String(), tc.ExpectedErrMsg))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestNewCreateCommandWithContentTrustErrors(t *testing.T) {
|
func TestNewCreateCommandWithContentTrustErrors(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
|
|
|
@ -91,6 +91,10 @@ func NewRunCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
func runRun(dockerCli command.Cli, flags *pflag.FlagSet, ropts *runOptions, copts *containerOptions) error {
|
func runRun(dockerCli command.Cli, flags *pflag.FlagSet, ropts *runOptions, copts *containerOptions) error {
|
||||||
|
if err := validatePullOpt(ropts.pull); err != nil {
|
||||||
|
reportError(dockerCli.Err(), "run", err.Error(), true)
|
||||||
|
return cli.StatusError{StatusCode: 125}
|
||||||
|
}
|
||||||
proxyConfig := dockerCli.ConfigFile().ParseProxyConfig(dockerCli.Client().DaemonHost(), opts.ConvertKVStringsToMapWithNil(copts.env.GetAll()))
|
proxyConfig := dockerCli.ConfigFile().ParseProxyConfig(dockerCli.Client().DaemonHost(), opts.ConvertKVStringsToMapWithNil(copts.env.GetAll()))
|
||||||
newEnv := []string{}
|
newEnv := []string{}
|
||||||
for k, v := range proxyConfig {
|
for k, v := range proxyConfig {
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
package container
|
package container
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/internal/test"
|
"github.com/docker/cli/internal/test"
|
||||||
"github.com/docker/cli/internal/test/notary"
|
"github.com/docker/cli/internal/test/notary"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
is "gotest.tools/v3/assert/cmp"
|
is "gotest.tools/v3/assert/cmp"
|
||||||
)
|
)
|
||||||
|
@ -74,3 +77,36 @@ func TestRunCommandWithContentTrustErrors(t *testing.T) {
|
||||||
assert.Assert(t, is.Contains(cli.ErrBuffer().String(), tc.expectedError))
|
assert.Assert(t, is.Contains(cli.ErrBuffer().String(), tc.expectedError))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRunContainerImagePullPolicyInvalid(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
PullPolicy string
|
||||||
|
ExpectedErrMsg string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
PullPolicy: "busybox:latest",
|
||||||
|
ExpectedErrMsg: `invalid pull option: 'busybox:latest': must be one of "always", "missing" or "never"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
PullPolicy: "--network=foo",
|
||||||
|
ExpectedErrMsg: `invalid pull option: '--network=foo': must be one of "always", "missing" or "never"`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range cases {
|
||||||
|
tc := tc
|
||||||
|
t.Run(tc.PullPolicy, func(t *testing.T) {
|
||||||
|
dockerCli := test.NewFakeCli(&fakeClient{})
|
||||||
|
err := runRun(
|
||||||
|
dockerCli,
|
||||||
|
&pflag.FlagSet{},
|
||||||
|
&runOptions{createOptions: createOptions{pull: tc.PullPolicy}},
|
||||||
|
&containerOptions{},
|
||||||
|
)
|
||||||
|
|
||||||
|
statusErr := cli.StatusError{}
|
||||||
|
assert.Check(t, errors.As(err, &statusErr))
|
||||||
|
assert.Equal(t, statusErr.StatusCode, 125)
|
||||||
|
assert.Check(t, is.Contains(dockerCli.ErrBuffer().String(), tc.ExpectedErrMsg))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue