From 2d344b2f6129c83601e039aa31c8477aab927d94 Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Tue, 11 Sep 2018 14:46:30 +0200 Subject: [PATCH] =?UTF-8?q?Remove=20containerizedengine=20package=20depend?= =?UTF-8?q?ency=20from=20docker/cli/command=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … this removes a whole lot of dependencies from people depending on docker/cli… Signed-off-by: Vincent Demeester --- cli/command/cli.go | 29 +++---- cli/command/engine/activate.go | 6 +- cli/command/engine/activate_test.go | 6 +- cli/command/engine/check.go | 10 +-- cli/command/engine/check_test.go | 34 ++++---- cli/command/engine/client_test.go | 44 +++++----- cli/command/engine/init.go | 6 +- cli/command/engine/init_test.go | 6 +- cli/command/engine/rm.go | 7 +- cli/command/engine/rm_test.go | 6 +- cli/command/engine/update_test.go | 6 +- cli/command/formatter/updates.go | 6 +- cli/command/formatter/updates_test.go | 8 +- cmd/docker/docker.go | 3 +- cmd/docker/docker_test.go | 2 +- docs/yaml/generate.go | 2 +- e2eengine/utils.go | 11 ++- internal/containerizedengine/client_test.go | 12 --- internal/containerizedengine/containerd.go | 9 ++- .../containerizedengine/containerd_test.go | 6 +- internal/containerizedengine/engine.go | 25 ++++-- internal/containerizedengine/engine_test.go | 47 ++++++----- internal/containerizedengine/types.go | 74 ----------------- internal/containerizedengine/update.go | 23 +++--- internal/containerizedengine/update_test.go | 49 +++++------ internal/containerizedengine/versions.go | 19 ++--- internal/test/cli.go | 6 +- man/generate.go | 2 +- types/types.go | 81 +++++++++++++++++++ 29 files changed, 283 insertions(+), 262 deletions(-) create mode 100644 types/types.go diff --git a/cli/command/cli.go b/cli/command/cli.go index 693ddc6a1b..242b5f0358 100644 --- a/cli/command/cli.go +++ b/cli/command/cli.go @@ -19,8 +19,8 @@ import ( manifeststore "github.com/docker/cli/cli/manifest/store" registryclient "github.com/docker/cli/cli/registry/client" "github.com/docker/cli/cli/trust" - "github.com/docker/cli/internal/containerizedengine" dopts "github.com/docker/cli/opts" + clitypes "github.com/docker/cli/types" "github.com/docker/docker/api" "github.com/docker/docker/api/types" registrytypes "github.com/docker/docker/api/types/registry" @@ -55,20 +55,21 @@ type Cli interface { ManifestStore() manifeststore.Store RegistryClient(bool) registryclient.RegistryClient ContentTrustEnabled() bool - NewContainerizedEngineClient(sockPath string) (containerizedengine.Client, error) + NewContainerizedEngineClient(sockPath string) (clitypes.ContainerizedClient, error) } // DockerCli is an instance the docker command line client. // Instances of the client can be returned from NewDockerCli. type DockerCli struct { - configFile *configfile.ConfigFile - in *InStream - out *OutStream - err io.Writer - client client.APIClient - serverInfo ServerInfo - clientInfo ClientInfo - contentTrust bool + configFile *configfile.ConfigFile + in *InStream + out *OutStream + err io.Writer + client client.APIClient + serverInfo ServerInfo + clientInfo ClientInfo + contentTrust bool + newContainerizeClient func(string) (clitypes.ContainerizedClient, error) } // DefaultVersion returns api.defaultVersion or DOCKER_API_VERSION if specified. @@ -233,8 +234,8 @@ func (cli *DockerCli) NotaryClient(imgRefAndAuth trust.ImageRefAndAuth, actions } // NewContainerizedEngineClient returns a containerized engine client -func (cli *DockerCli) NewContainerizedEngineClient(sockPath string) (containerizedengine.Client, error) { - return containerizedengine.NewClient(sockPath) +func (cli *DockerCli) NewContainerizedEngineClient(sockPath string) (clitypes.ContainerizedClient, error) { + return cli.newContainerizeClient(sockPath) } // ServerInfo stores details about the supported features and platform of the @@ -252,8 +253,8 @@ type ClientInfo struct { } // NewDockerCli returns a DockerCli instance with IO output and error streams set by in, out and err. -func NewDockerCli(in io.ReadCloser, out, err io.Writer, isTrusted bool) *DockerCli { - return &DockerCli{in: NewInStream(in), out: NewOutStream(out), err: err, contentTrust: isTrusted} +func NewDockerCli(in io.ReadCloser, out, err io.Writer, isTrusted bool, containerizedFn func(string) (clitypes.ContainerizedClient, error)) *DockerCli { + return &DockerCli{in: NewInStream(in), out: NewOutStream(out), err: err, contentTrust: isTrusted, newContainerizeClient: containerizedFn} } // NewAPIClientFromFlags creates a new APIClient from command line flags diff --git a/cli/command/engine/activate.go b/cli/command/engine/activate.go index 7655307c40..270daff720 100644 --- a/cli/command/engine/activate.go +++ b/cli/command/engine/activate.go @@ -6,8 +6,8 @@ import ( "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command/formatter" - "github.com/docker/cli/internal/containerizedengine" "github.com/docker/cli/internal/licenseutils" + clitypes "github.com/docker/cli/types" "github.com/docker/docker/api/types" "github.com/docker/licensing/model" "github.com/pkg/errors" @@ -57,7 +57,7 @@ https://hub.docker.com/ then specify the file with the '--license' flag. flags.StringVar(&options.licenseFile, "license", "", "License File") flags.StringVar(&options.version, "version", "", "Specify engine version (default is to use currently running version)") flags.StringVar(&options.registryPrefix, "registry-prefix", "docker.io/docker", "Override the default location where engine images are pulled") - flags.StringVar(&options.image, "engine-image", containerizedengine.EnterpriseEngineImage, "Specify engine image") + flags.StringVar(&options.image, "engine-image", clitypes.EnterpriseEngineImage, "Specify engine image") flags.StringVar(&options.format, "format", "", "Pretty-print licenses using a Go template") flags.BoolVar(&options.displayOnly, "display-only", false, "only display the available licenses and exit") flags.BoolVar(&options.quiet, "quiet", false, "Only display available licenses by ID") @@ -98,7 +98,7 @@ func runActivate(cli command.Cli, options activateOptions) error { return err } - opts := containerizedengine.EngineInitOptions{ + opts := clitypes.EngineInitOptions{ RegistryPrefix: options.registryPrefix, EngineImage: options.image, EngineVersion: options.version, diff --git a/cli/command/engine/activate_test.go b/cli/command/engine/activate_test.go index deb6486363..6936161eef 100644 --- a/cli/command/engine/activate_test.go +++ b/cli/command/engine/activate_test.go @@ -4,13 +4,13 @@ import ( "fmt" "testing" - "github.com/docker/cli/internal/containerizedengine" + "github.com/docker/cli/types" "gotest.tools/assert" ) func TestActivateNoContainerd(t *testing.T) { testCli.SetContainerizedEngineClient( - func(string) (containerizedengine.Client, error) { + func(string) (types.ContainerizedClient, error) { return nil, fmt.Errorf("some error") }, ) @@ -24,7 +24,7 @@ func TestActivateNoContainerd(t *testing.T) { func TestActivateBadLicense(t *testing.T) { testCli.SetContainerizedEngineClient( - func(string) (containerizedengine.Client, error) { + func(string) (types.ContainerizedClient, error) { return &fakeContainerizedEngineClient{}, nil }, ) diff --git a/cli/command/engine/check.go b/cli/command/engine/check.go index 6df1c62446..0ba19cc0e6 100644 --- a/cli/command/engine/check.go +++ b/cli/command/engine/check.go @@ -7,7 +7,7 @@ import ( "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command/formatter" - "github.com/docker/cli/internal/containerizedengine" + clitypes "github.com/docker/cli/types" "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -72,7 +72,7 @@ func runCheck(dockerCli command.Cli, options checkOptions) error { return err } - availUpdates := []containerizedengine.Update{ + availUpdates := []clitypes.Update{ {Type: "current", Version: currentVersion}, } if len(versions.Patches) > 0 { @@ -115,14 +115,14 @@ func runCheck(dockerCli command.Cli, options checkOptions) error { func processVersions(currentVersion, verType string, includePrerelease bool, - versions []containerizedengine.DockerVersion) []containerizedengine.Update { - availUpdates := []containerizedengine.Update{} + versions []clitypes.DockerVersion) []clitypes.Update { + availUpdates := []clitypes.Update{} for _, ver := range versions { if !includePrerelease && ver.Prerelease() != "" { continue } if ver.Tag != currentVersion { - availUpdates = append(availUpdates, containerizedengine.Update{ + availUpdates = append(availUpdates, clitypes.Update{ Type: verType, Version: ver.Tag, Notes: fmt.Sprintf("%s/%s", releaseNotePrefix, ver.Tag), diff --git a/cli/command/engine/check_test.go b/cli/command/engine/check_test.go index 622e8dd76d..14c6eddb27 100644 --- a/cli/command/engine/check_test.go +++ b/cli/command/engine/check_test.go @@ -6,8 +6,8 @@ import ( "testing" registryclient "github.com/docker/cli/cli/registry/client" - "github.com/docker/cli/internal/containerizedengine" "github.com/docker/cli/internal/test" + clitypes "github.com/docker/cli/types" "github.com/docker/docker/client" ver "github.com/hashicorp/go-version" "gotest.tools/assert" @@ -20,7 +20,7 @@ var ( func TestCheckForUpdatesNoContainerd(t *testing.T) { testCli.SetContainerizedEngineClient( - func(string) (containerizedengine.Client, error) { + func(string) (clitypes.ContainerizedClient, error) { return nil, fmt.Errorf("some error") }, ) @@ -33,11 +33,11 @@ func TestCheckForUpdatesNoContainerd(t *testing.T) { func TestCheckForUpdatesNoCurrentVersion(t *testing.T) { retErr := fmt.Errorf("some failure") - getCurrentEngineVersionFunc := func(ctx context.Context) (containerizedengine.EngineInitOptions, error) { - return containerizedengine.EngineInitOptions{}, retErr + getCurrentEngineVersionFunc := func(ctx context.Context) (clitypes.EngineInitOptions, error) { + return clitypes.EngineInitOptions{}, retErr } testCli.SetContainerizedEngineClient( - func(string) (containerizedengine.Client, error) { + func(string) (clitypes.ContainerizedClient, error) { return &fakeContainerizedEngineClient{ getCurrentEngineVersionFunc: getCurrentEngineVersionFunc, }, nil @@ -54,11 +54,11 @@ func TestCheckForUpdatesGetEngineVersionsFail(t *testing.T) { retErr := fmt.Errorf("some failure") getEngineVersionsFunc := func(ctx context.Context, registryClient registryclient.RegistryClient, - currentVersion, imageName string) (containerizedengine.AvailableVersions, error) { - return containerizedengine.AvailableVersions{}, retErr + currentVersion, imageName string) (clitypes.AvailableVersions, error) { + return clitypes.AvailableVersions{}, retErr } testCli.SetContainerizedEngineClient( - func(string) (containerizedengine.Client, error) { + func(string) (clitypes.ContainerizedClient, error) { return &fakeContainerizedEngineClient{ getEngineVersionsFunc: getEngineVersionsFunc, }, nil @@ -72,23 +72,23 @@ func TestCheckForUpdatesGetEngineVersionsFail(t *testing.T) { } func TestCheckForUpdatesGetEngineVersionsHappy(t *testing.T) { - getCurrentEngineVersionFunc := func(ctx context.Context) (containerizedengine.EngineInitOptions, error) { - return containerizedengine.EngineInitOptions{ + getCurrentEngineVersionFunc := func(ctx context.Context) (clitypes.EngineInitOptions, error) { + return clitypes.EngineInitOptions{ EngineImage: "current engine", EngineVersion: "1.1.0", }, nil } getEngineVersionsFunc := func(ctx context.Context, registryClient registryclient.RegistryClient, - currentVersion, imageName string) (containerizedengine.AvailableVersions, error) { - return containerizedengine.AvailableVersions{ + currentVersion, imageName string) (clitypes.AvailableVersions, error) { + return clitypes.AvailableVersions{ Downgrades: parseVersions(t, "1.0.1", "1.0.2", "1.0.3-beta1"), Patches: parseVersions(t, "1.1.1", "1.1.2", "1.1.3-beta1"), Upgrades: parseVersions(t, "1.2.0", "2.0.0", "2.1.0-beta1"), }, nil } testCli.SetContainerizedEngineClient( - func(string) (containerizedengine.Client, error) { + func(string) (clitypes.ContainerizedClient, error) { return &fakeContainerizedEngineClient{ getEngineVersionsFunc: getEngineVersionsFunc, getCurrentEngineVersionFunc: getCurrentEngineVersionFunc, @@ -128,14 +128,14 @@ func TestCheckForUpdatesGetEngineVersionsHappy(t *testing.T) { golden.Assert(t, testCli.OutBuffer().String(), "check-patches-only.golden") } -func makeVersion(t *testing.T, tag string) containerizedengine.DockerVersion { +func makeVersion(t *testing.T, tag string) clitypes.DockerVersion { v, err := ver.NewVersion(tag) assert.NilError(t, err) - return containerizedengine.DockerVersion{Version: *v, Tag: tag} + return clitypes.DockerVersion{Version: *v, Tag: tag} } -func parseVersions(t *testing.T, tags ...string) []containerizedengine.DockerVersion { - ret := make([]containerizedengine.DockerVersion, len(tags)) +func parseVersions(t *testing.T, tags ...string) []clitypes.DockerVersion { + ret := make([]clitypes.DockerVersion, len(tags)) for i, tag := range tags { ret[i] = makeVersion(t, tag) } diff --git a/cli/command/engine/client_test.go b/cli/command/engine/client_test.go index 19a9d5c1b5..5f2f6587e1 100644 --- a/cli/command/engine/client_test.go +++ b/cli/command/engine/client_test.go @@ -5,7 +5,7 @@ import ( "github.com/containerd/containerd" registryclient "github.com/docker/cli/cli/registry/client" - "github.com/docker/cli/internal/containerizedengine" + clitypes "github.com/docker/cli/types" "github.com/docker/docker/api/types" ) @@ -13,28 +13,28 @@ type ( fakeContainerizedEngineClient struct { closeFunc func() error activateEngineFunc func(ctx context.Context, - opts containerizedengine.EngineInitOptions, - out containerizedengine.OutStream, + opts clitypes.EngineInitOptions, + out clitypes.OutStream, authConfig *types.AuthConfig, healthfn func(context.Context) error) error initEngineFunc func(ctx context.Context, - opts containerizedengine.EngineInitOptions, - out containerizedengine.OutStream, + opts clitypes.EngineInitOptions, + out clitypes.OutStream, authConfig *types.AuthConfig, healthfn func(context.Context) error) error doUpdateFunc func(ctx context.Context, - opts containerizedengine.EngineInitOptions, - out containerizedengine.OutStream, + opts clitypes.EngineInitOptions, + out clitypes.OutStream, authConfig *types.AuthConfig, healthfn func(context.Context) error) error getEngineVersionsFunc func(ctx context.Context, registryClient registryclient.RegistryClient, currentVersion, - imageName string) (containerizedengine.AvailableVersions, error) + imageName string) (clitypes.AvailableVersions, error) getEngineFunc func(ctx context.Context) (containerd.Container, error) - removeEngineFunc func(ctx context.Context, engine containerd.Container) error - getCurrentEngineVersionFunc func(ctx context.Context) (containerizedengine.EngineInitOptions, error) + removeEngineFunc func(ctx context.Context) error + getCurrentEngineVersionFunc func(ctx context.Context) (clitypes.EngineInitOptions, error) } ) @@ -46,8 +46,8 @@ func (w *fakeContainerizedEngineClient) Close() error { } func (w *fakeContainerizedEngineClient) ActivateEngine(ctx context.Context, - opts containerizedengine.EngineInitOptions, - out containerizedengine.OutStream, + opts clitypes.EngineInitOptions, + out clitypes.OutStream, authConfig *types.AuthConfig, healthfn func(context.Context) error) error { if w.activateEngineFunc != nil { @@ -56,8 +56,8 @@ func (w *fakeContainerizedEngineClient) ActivateEngine(ctx context.Context, return nil } func (w *fakeContainerizedEngineClient) InitEngine(ctx context.Context, - opts containerizedengine.EngineInitOptions, - out containerizedengine.OutStream, + opts clitypes.EngineInitOptions, + out clitypes.OutStream, authConfig *types.AuthConfig, healthfn func(context.Context) error) error { if w.initEngineFunc != nil { @@ -66,8 +66,8 @@ func (w *fakeContainerizedEngineClient) InitEngine(ctx context.Context, return nil } func (w *fakeContainerizedEngineClient) DoUpdate(ctx context.Context, - opts containerizedengine.EngineInitOptions, - out containerizedengine.OutStream, + opts clitypes.EngineInitOptions, + out clitypes.OutStream, authConfig *types.AuthConfig, healthfn func(context.Context) error) error { if w.doUpdateFunc != nil { @@ -77,12 +77,12 @@ func (w *fakeContainerizedEngineClient) DoUpdate(ctx context.Context, } func (w *fakeContainerizedEngineClient) GetEngineVersions(ctx context.Context, registryClient registryclient.RegistryClient, - currentVersion, imageName string) (containerizedengine.AvailableVersions, error) { + currentVersion, imageName string) (clitypes.AvailableVersions, error) { if w.getEngineVersionsFunc != nil { return w.getEngineVersionsFunc(ctx, registryClient, currentVersion, imageName) } - return containerizedengine.AvailableVersions{}, nil + return clitypes.AvailableVersions{}, nil } func (w *fakeContainerizedEngineClient) GetEngine(ctx context.Context) (containerd.Container, error) { @@ -91,15 +91,15 @@ func (w *fakeContainerizedEngineClient) GetEngine(ctx context.Context) (containe } return nil, nil } -func (w *fakeContainerizedEngineClient) RemoveEngine(ctx context.Context, engine containerd.Container) error { +func (w *fakeContainerizedEngineClient) RemoveEngine(ctx context.Context) error { if w.removeEngineFunc != nil { - return w.removeEngineFunc(ctx, engine) + return w.removeEngineFunc(ctx) } return nil } -func (w *fakeContainerizedEngineClient) GetCurrentEngineVersion(ctx context.Context) (containerizedengine.EngineInitOptions, error) { +func (w *fakeContainerizedEngineClient) GetCurrentEngineVersion(ctx context.Context) (clitypes.EngineInitOptions, error) { if w.getCurrentEngineVersionFunc != nil { return w.getCurrentEngineVersionFunc(ctx) } - return containerizedengine.EngineInitOptions{}, nil + return clitypes.EngineInitOptions{}, nil } diff --git a/cli/command/engine/init.go b/cli/command/engine/init.go index b8a9054682..9d1ff3e34e 100644 --- a/cli/command/engine/init.go +++ b/cli/command/engine/init.go @@ -5,13 +5,13 @@ import ( "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" - "github.com/docker/cli/internal/containerizedengine" + clitypes "github.com/docker/cli/types" "github.com/pkg/errors" "github.com/spf13/cobra" ) type extendedEngineInitOptions struct { - containerizedengine.EngineInitOptions + clitypes.EngineInitOptions sockPath string } @@ -34,7 +34,7 @@ file on the host and may be pre-created before running the 'init' command. } flags := cmd.Flags() flags.StringVar(&options.EngineVersion, "version", cli.Version, "Specify engine version") - flags.StringVar(&options.EngineImage, "engine-image", containerizedengine.CommunityEngineImage, "Specify engine image") + flags.StringVar(&options.EngineImage, "engine-image", clitypes.CommunityEngineImage, "Specify engine image") flags.StringVar(&options.RegistryPrefix, "registry-prefix", "docker.io/docker", "Override the default location where engine images are pulled") flags.StringVar(&options.ConfigFile, "config-file", "/etc/docker/daemon.json", "Specify the location of the daemon configuration file on the host") flags.StringVar(&options.sockPath, "containerd", "", "override default location of containerd endpoint") diff --git a/cli/command/engine/init_test.go b/cli/command/engine/init_test.go index 9e73bc8a02..5d6c91b1f4 100644 --- a/cli/command/engine/init_test.go +++ b/cli/command/engine/init_test.go @@ -4,13 +4,13 @@ import ( "fmt" "testing" - "github.com/docker/cli/internal/containerizedengine" + clitypes "github.com/docker/cli/types" "gotest.tools/assert" ) func TestInitNoContainerd(t *testing.T) { testCli.SetContainerizedEngineClient( - func(string) (containerizedengine.Client, error) { + func(string) (clitypes.ContainerizedClient, error) { return nil, fmt.Errorf("some error") }, ) @@ -23,7 +23,7 @@ func TestInitNoContainerd(t *testing.T) { func TestInitHappy(t *testing.T) { testCli.SetContainerizedEngineClient( - func(string) (containerizedengine.Client, error) { + func(string) (clitypes.ContainerizedClient, error) { return &fakeContainerizedEngineClient{}, nil }, ) diff --git a/cli/command/engine/rm.go b/cli/command/engine/rm.go index 13668be0b9..c27e9d2136 100644 --- a/cli/command/engine/rm.go +++ b/cli/command/engine/rm.go @@ -45,10 +45,5 @@ func runRm(dockerCli command.Cli, options rmOptions) error { } defer client.Close() - engine, err := client.GetEngine(ctx) - if err != nil { - return err - } - - return client.RemoveEngine(ctx, engine) + return client.RemoveEngine(ctx) } diff --git a/cli/command/engine/rm_test.go b/cli/command/engine/rm_test.go index c8a90318dd..25d3d290f4 100644 --- a/cli/command/engine/rm_test.go +++ b/cli/command/engine/rm_test.go @@ -4,13 +4,13 @@ import ( "fmt" "testing" - "github.com/docker/cli/internal/containerizedengine" + clitypes "github.com/docker/cli/types" "gotest.tools/assert" ) func TestRmNoContainerd(t *testing.T) { testCli.SetContainerizedEngineClient( - func(string) (containerizedengine.Client, error) { + func(string) (clitypes.ContainerizedClient, error) { return nil, fmt.Errorf("some error") }, ) @@ -23,7 +23,7 @@ func TestRmNoContainerd(t *testing.T) { func TestRmHappy(t *testing.T) { testCli.SetContainerizedEngineClient( - func(string) (containerizedengine.Client, error) { + func(string) (clitypes.ContainerizedClient, error) { return &fakeContainerizedEngineClient{}, nil }, ) diff --git a/cli/command/engine/update_test.go b/cli/command/engine/update_test.go index 0aa56644b9..a609113296 100644 --- a/cli/command/engine/update_test.go +++ b/cli/command/engine/update_test.go @@ -4,13 +4,13 @@ import ( "fmt" "testing" - "github.com/docker/cli/internal/containerizedengine" + clitypes "github.com/docker/cli/types" "gotest.tools/assert" ) func TestUpdateNoContainerd(t *testing.T) { testCli.SetContainerizedEngineClient( - func(string) (containerizedengine.Client, error) { + func(string) (clitypes.ContainerizedClient, error) { return nil, fmt.Errorf("some error") }, ) @@ -23,7 +23,7 @@ func TestUpdateNoContainerd(t *testing.T) { func TestUpdateHappy(t *testing.T) { testCli.SetContainerizedEngineClient( - func(string) (containerizedengine.Client, error) { + func(string) (clitypes.ContainerizedClient, error) { return &fakeContainerizedEngineClient{}, nil }, ) diff --git a/cli/command/formatter/updates.go b/cli/command/formatter/updates.go index 8aa220bfdc..e67e035b35 100644 --- a/cli/command/formatter/updates.go +++ b/cli/command/formatter/updates.go @@ -1,7 +1,7 @@ package formatter import ( - "github.com/docker/cli/internal/containerizedengine" + clitypes "github.com/docker/cli/types" ) const ( @@ -31,7 +31,7 @@ func NewUpdatesFormat(source string, quiet bool) Format { } // UpdatesWrite writes the context -func UpdatesWrite(ctx Context, availableUpdates []containerizedengine.Update) error { +func UpdatesWrite(ctx Context, availableUpdates []clitypes.Update) error { render := func(format func(subContext subContext) error) error { for _, update := range availableUpdates { updatesCtx := &updateContext{trunc: ctx.Trunc, u: update} @@ -53,7 +53,7 @@ func UpdatesWrite(ctx Context, availableUpdates []containerizedengine.Update) er type updateContext struct { HeaderContext trunc bool - u containerizedengine.Update + u clitypes.Update } func (c *updateContext) MarshalJSON() ([]byte, error) { diff --git a/cli/command/formatter/updates_test.go b/cli/command/formatter/updates_test.go index 1fe93ef95b..a7343f3344 100644 --- a/cli/command/formatter/updates_test.go +++ b/cli/command/formatter/updates_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/docker/cli/internal/containerizedengine" + clitypes "github.com/docker/cli/types" "gotest.tools/assert" is "gotest.tools/assert/cmp" ) @@ -84,7 +84,7 @@ version2 } for _, testcase := range cases { - updates := []containerizedengine.Update{ + updates := []clitypes.Update{ {Type: "updateType1", Version: "version1", Notes: "description 1"}, {Type: "updateType2", Version: "version2", Notes: "description 2"}, } @@ -100,7 +100,7 @@ version2 } func TestUpdateContextWriteJSON(t *testing.T) { - updates := []containerizedengine.Update{ + updates := []clitypes.Update{ {Type: "updateType1", Version: "version1", Notes: "note1"}, {Type: "updateType2", Version: "version2", Notes: "note2"}, } @@ -124,7 +124,7 @@ func TestUpdateContextWriteJSON(t *testing.T) { } func TestUpdateContextWriteJSONField(t *testing.T) { - updates := []containerizedengine.Update{ + updates := []clitypes.Update{ {Type: "updateType1", Version: "version1"}, {Type: "updateType2", Version: "version2"}, } diff --git a/cmd/docker/docker.go b/cmd/docker/docker.go index badc1bcc6c..a2bcd2a2cd 100644 --- a/cmd/docker/docker.go +++ b/cmd/docker/docker.go @@ -13,6 +13,7 @@ import ( cliconfig "github.com/docker/cli/cli/config" "github.com/docker/cli/cli/debug" cliflags "github.com/docker/cli/cli/flags" + "github.com/docker/cli/internal/containerizedengine" "github.com/docker/docker/api/types/versions" "github.com/docker/docker/client" "github.com/docker/docker/pkg/term" @@ -168,7 +169,7 @@ func main() { stdin, stdout, stderr := term.StdStreams() logrus.SetOutput(stderr) - dockerCli := command.NewDockerCli(stdin, stdout, stderr, contentTrustEnabled()) + dockerCli := command.NewDockerCli(stdin, stdout, stderr, contentTrustEnabled(), containerizedengine.NewClient) cmd := newDockerCommand(dockerCli) if err := cmd.Execute(); err != nil { diff --git a/cmd/docker/docker_test.go b/cmd/docker/docker_test.go index 92a9466853..7f7336b63e 100644 --- a/cmd/docker/docker_test.go +++ b/cmd/docker/docker_test.go @@ -26,7 +26,7 @@ func TestClientDebugEnabled(t *testing.T) { func TestExitStatusForInvalidSubcommandWithHelpFlag(t *testing.T) { discard := ioutil.Discard - cmd := newDockerCommand(command.NewDockerCli(os.Stdin, discard, discard, false)) + cmd := newDockerCommand(command.NewDockerCli(os.Stdin, discard, discard, false, nil)) cmd.SetArgs([]string{"help", "invalid"}) err := cmd.Execute() assert.Error(t, err, "unknown help topic: invalid") diff --git a/docs/yaml/generate.go b/docs/yaml/generate.go index 3603c97c4a..c37ad64498 100644 --- a/docs/yaml/generate.go +++ b/docs/yaml/generate.go @@ -19,7 +19,7 @@ const descriptionSourcePath = "docs/reference/commandline/" func generateCliYaml(opts *options) error { stdin, stdout, stderr := term.StdStreams() - dockerCli := command.NewDockerCli(stdin, stdout, stderr, false) + dockerCli := command.NewDockerCli(stdin, stdout, stderr, false, nil) cmd := &cobra.Command{Use: "docker"} commands.AddCommands(cmd, dockerCli) source := filepath.Join(opts.source, descriptionSourcePath) diff --git a/e2eengine/utils.go b/e2eengine/utils.go index 1dcd6f6ac0..3f109f73db 100644 --- a/e2eengine/utils.go +++ b/e2eengine/utils.go @@ -5,9 +5,16 @@ import ( "strings" "testing" + "github.com/containerd/containerd" "github.com/docker/cli/internal/containerizedengine" + "github.com/docker/cli/types" ) +type containerizedclient interface { + types.ContainerizedClient + GetEngine(context.Context) (containerd.Container, error) +} + // CleanupEngine ensures the local engine has been removed between testcases func CleanupEngine(t *testing.T) error { t.Log("doing engine cleanup") @@ -19,7 +26,7 @@ func CleanupEngine(t *testing.T) error { } // See if the engine exists first - engine, err := client.GetEngine(ctx) + _, err = client.(containerizedclient).GetEngine(ctx) if err != nil { if strings.Contains(err.Error(), "not present") { t.Log("engine was not detected, no cleanup to perform") @@ -31,7 +38,7 @@ func CleanupEngine(t *testing.T) error { return err } // TODO Consider nuking the docker dir too so there's no cached content between test cases - err = client.RemoveEngine(ctx, engine) + err = client.RemoveEngine(ctx) if err != nil { t.Logf("Failed to remove engine: %s", err) } diff --git a/internal/containerizedengine/client_test.go b/internal/containerizedengine/client_test.go index 9c2b4aa8b2..cc5c5770b2 100644 --- a/internal/containerizedengine/client_test.go +++ b/internal/containerizedengine/client_test.go @@ -1,7 +1,6 @@ package containerizedengine import ( - "bytes" "context" "syscall" @@ -69,10 +68,6 @@ type ( loadProcessFunc func(context.Context, string, cio.Attach) (containerd.Process, error) metricsFunc func(context.Context) (*containerdtypes.Metric, error) } - - testOutStream struct { - bytes.Buffer - } ) func (w *fakeContainerdClient) Containers(ctx context.Context, filters ...string) ([]containerd.Container, error) { @@ -339,10 +334,3 @@ func (t *fakeTask) Metrics(ctx context.Context) (*containerdtypes.Metric, error) } return nil, nil } - -func (o *testOutStream) FD() uintptr { - return 0 -} -func (o *testOutStream) IsTerminal() bool { - return false -} diff --git a/internal/containerizedengine/containerd.go b/internal/containerizedengine/containerd.go index be63eb2d9c..537b3ac98a 100644 --- a/internal/containerizedengine/containerd.go +++ b/internal/containerizedengine/containerd.go @@ -7,6 +7,7 @@ import ( "github.com/containerd/containerd" "github.com/containerd/containerd/images" "github.com/containerd/containerd/remotes/docker" + clitypes "github.com/docker/cli/types" "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/jsonmessage" ocispec "github.com/opencontainers/image-spec/specs-go/v1" @@ -15,7 +16,7 @@ import ( // NewClient returns a new containerizedengine client // This client can be used to manage the lifecycle of // dockerd running as a container on containerd. -func NewClient(sockPath string) (Client, error) { +func NewClient(sockPath string) (clitypes.ContainerizedClient, error) { if sockPath == "" { sockPath = containerdSockPath } @@ -23,17 +24,17 @@ func NewClient(sockPath string) (Client, error) { if err != nil { return nil, err } - return baseClient{ + return &baseClient{ cclient: cclient, }, nil } // Close will close the underlying clients -func (c baseClient) Close() error { +func (c *baseClient) Close() error { return c.cclient.Close() } -func (c baseClient) pullWithAuth(ctx context.Context, imageName string, out OutStream, +func (c *baseClient) pullWithAuth(ctx context.Context, imageName string, out clitypes.OutStream, authConfig *types.AuthConfig) (containerd.Image, error) { resolver := docker.NewResolver(docker.ResolverOptions{ diff --git a/internal/containerizedengine/containerd_test.go b/internal/containerizedengine/containerd_test.go index 1b48c77bc1..cca86be55b 100644 --- a/internal/containerizedengine/containerd_test.go +++ b/internal/containerizedengine/containerd_test.go @@ -1,11 +1,13 @@ package containerizedengine import ( + "bytes" "context" "fmt" "testing" "github.com/containerd/containerd" + "github.com/docker/cli/cli/command" "github.com/docker/docker/api/types" "gotest.tools/assert" ) @@ -22,7 +24,7 @@ func TestPullWithAuthPullFail(t *testing.T) { } imageName := "testnamegoeshere" - _, err := client.pullWithAuth(ctx, imageName, &testOutStream{}, &types.AuthConfig{}) + _, err := client.pullWithAuth(ctx, imageName, command.NewOutStream(&bytes.Buffer{}), &types.AuthConfig{}) assert.ErrorContains(t, err, "pull failure") } @@ -38,6 +40,6 @@ func TestPullWithAuthPullPass(t *testing.T) { } imageName := "testnamegoeshere" - _, err := client.pullWithAuth(ctx, imageName, &testOutStream{}, &types.AuthConfig{}) + _, err := client.pullWithAuth(ctx, imageName, command.NewOutStream(&bytes.Buffer{}), &types.AuthConfig{}) assert.NilError(t, err) } diff --git a/internal/containerizedengine/engine.go b/internal/containerizedengine/engine.go index fb8d8d8474..8356fc3fc5 100644 --- a/internal/containerizedengine/engine.go +++ b/internal/containerizedengine/engine.go @@ -12,12 +12,15 @@ import ( "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/runtime/restart" "github.com/docker/cli/internal/pkg/containerized" + clitypes "github.com/docker/cli/types" "github.com/docker/docker/api/types" "github.com/pkg/errors" ) +var _ clitypes.ContainerizedClient = &baseClient{} + // InitEngine is the main entrypoint for `docker engine init` -func (c baseClient) InitEngine(ctx context.Context, opts EngineInitOptions, out OutStream, +func (c *baseClient) InitEngine(ctx context.Context, opts clitypes.EngineInitOptions, out clitypes.OutStream, authConfig *types.AuthConfig, healthfn func(context.Context) error) error { ctx = namespaces.WithNamespace(ctx, engineNamespace) @@ -66,7 +69,7 @@ func (c baseClient) InitEngine(ctx context.Context, opts EngineInitOptions, out } // GetEngine will return the containerd container running the engine (or error) -func (c baseClient) GetEngine(ctx context.Context) (containerd.Container, error) { +func (c *baseClient) GetEngine(ctx context.Context) (containerd.Container, error) { ctx = namespaces.WithNamespace(ctx, engineNamespace) containers, err := c.cclient.Containers(ctx, "id=="+engineContainerName) if err != nil { @@ -79,7 +82,7 @@ func (c baseClient) GetEngine(ctx context.Context) (containerd.Container, error) } // getEngineImage will return the current image used by the engine -func (c baseClient) getEngineImage(engine containerd.Container) (string, error) { +func (c *baseClient) getEngineImage(engine containerd.Container) (string, error) { ctx := namespaces.WithNamespace(context.Background(), engineNamespace) image, err := engine.Image(ctx) if err != nil { @@ -94,7 +97,7 @@ var ( ) // waitForEngine will wait for the engine to start -func (c baseClient) waitForEngine(ctx context.Context, out io.Writer, healthfn func(context.Context) error) error { +func (c *baseClient) waitForEngine(ctx context.Context, out io.Writer, healthfn func(context.Context) error) error { ticker := time.NewTicker(engineWaitInterval) defer ticker.Stop() defer func() { @@ -120,7 +123,7 @@ func (c baseClient) waitForEngine(ctx context.Context, out io.Writer, healthfn f } } -func (c baseClient) waitForEngineContainer(ctx context.Context, ticker *time.Ticker) error { +func (c *baseClient) waitForEngineContainer(ctx context.Context, ticker *time.Ticker) error { var ret error for { select { @@ -137,7 +140,15 @@ func (c baseClient) waitForEngineContainer(ctx context.Context, ticker *time.Tic } // RemoveEngine gracefully unwinds the current engine -func (c baseClient) RemoveEngine(ctx context.Context, engine containerd.Container) error { +func (c *baseClient) RemoveEngine(ctx context.Context) error { + engine, err := c.GetEngine(ctx) + if err != nil { + return err + } + return c.removeEngine(ctx, engine) +} + +func (c *baseClient) removeEngine(ctx context.Context, engine containerd.Container) error { ctx = namespaces.WithNamespace(ctx, engineNamespace) // Make sure the container isn't being restarted while we unwind it @@ -190,7 +201,7 @@ func (c baseClient) RemoveEngine(ctx context.Context, engine containerd.Containe } // startEngineOnContainerd creates a new docker engine running on containerd -func (c baseClient) startEngineOnContainerd(ctx context.Context, imageName, configFile string) error { +func (c *baseClient) startEngineOnContainerd(ctx context.Context, imageName, configFile string) error { ctx = namespaces.WithNamespace(ctx, engineNamespace) image, err := c.cclient.GetImage(ctx, imageName) if err != nil { diff --git a/internal/containerizedengine/engine_test.go b/internal/containerizedengine/engine_test.go index 0e7d4da23d..21ab83d68a 100644 --- a/internal/containerizedengine/engine_test.go +++ b/internal/containerizedengine/engine_test.go @@ -1,6 +1,7 @@ package containerizedengine import ( + "bytes" "context" "fmt" "strings" @@ -12,6 +13,8 @@ import ( "github.com/containerd/containerd/cio" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/oci" + "github.com/docker/cli/cli/command" + clitypes "github.com/docker/cli/types" "github.com/docker/docker/api/types" "github.com/opencontainers/runtime-spec/specs-go" "gotest.tools/assert" @@ -26,11 +29,11 @@ func healthfnError(ctx context.Context) error { func TestInitGetEngineFail(t *testing.T) { ctx := context.Background() - opts := EngineInitOptions{ + opts := clitypes.EngineInitOptions{ EngineVersion: "engineversiongoeshere", RegistryPrefix: "registryprefixgoeshere", ConfigFile: "/tmp/configfilegoeshere", - EngineImage: CommunityEngineImage, + EngineImage: clitypes.CommunityEngineImage, } container := &fakeContainer{} client := baseClient{ @@ -41,17 +44,17 @@ func TestInitGetEngineFail(t *testing.T) { }, } - err := client.InitEngine(ctx, opts, &testOutStream{}, &types.AuthConfig{}, healthfnHappy) + err := client.InitEngine(ctx, opts, command.NewOutStream(&bytes.Buffer{}), &types.AuthConfig{}, healthfnHappy) assert.Assert(t, err == ErrEngineAlreadyPresent) } func TestInitCheckImageFail(t *testing.T) { ctx := context.Background() - opts := EngineInitOptions{ + opts := clitypes.EngineInitOptions{ EngineVersion: "engineversiongoeshere", RegistryPrefix: "registryprefixgoeshere", ConfigFile: "/tmp/configfilegoeshere", - EngineImage: CommunityEngineImage, + EngineImage: clitypes.CommunityEngineImage, } client := baseClient{ cclient: &fakeContainerdClient{ @@ -65,18 +68,18 @@ func TestInitCheckImageFail(t *testing.T) { }, } - err := client.InitEngine(ctx, opts, &testOutStream{}, &types.AuthConfig{}, healthfnHappy) + err := client.InitEngine(ctx, opts, command.NewOutStream(&bytes.Buffer{}), &types.AuthConfig{}, healthfnHappy) assert.ErrorContains(t, err, "unable to check for image") assert.ErrorContains(t, err, "something went wrong") } func TestInitPullFail(t *testing.T) { ctx := context.Background() - opts := EngineInitOptions{ + opts := clitypes.EngineInitOptions{ EngineVersion: "engineversiongoeshere", RegistryPrefix: "registryprefixgoeshere", ConfigFile: "/tmp/configfilegoeshere", - EngineImage: CommunityEngineImage, + EngineImage: clitypes.CommunityEngineImage, } client := baseClient{ cclient: &fakeContainerdClient{ @@ -93,18 +96,18 @@ func TestInitPullFail(t *testing.T) { }, } - err := client.InitEngine(ctx, opts, &testOutStream{}, &types.AuthConfig{}, healthfnHappy) + err := client.InitEngine(ctx, opts, command.NewOutStream(&bytes.Buffer{}), &types.AuthConfig{}, healthfnHappy) assert.ErrorContains(t, err, "unable to pull image") assert.ErrorContains(t, err, "pull failure") } func TestInitStartFail(t *testing.T) { ctx := context.Background() - opts := EngineInitOptions{ + opts := clitypes.EngineInitOptions{ EngineVersion: "engineversiongoeshere", RegistryPrefix: "registryprefixgoeshere", ConfigFile: "/tmp/configfilegoeshere", - EngineImage: CommunityEngineImage, + EngineImage: clitypes.CommunityEngineImage, } client := baseClient{ cclient: &fakeContainerdClient{ @@ -121,7 +124,7 @@ func TestInitStartFail(t *testing.T) { }, } - err := client.InitEngine(ctx, opts, &testOutStream{}, &types.AuthConfig{}, healthfnHappy) + err := client.InitEngine(ctx, opts, command.NewOutStream(&bytes.Buffer{}), &types.AuthConfig{}, healthfnHappy) assert.ErrorContains(t, err, "failed to create docker daemon") } @@ -211,7 +214,7 @@ func TestWaitForEngineNeverShowsUp(t *testing.T) { }, } - err := client.waitForEngine(ctx, &testOutStream{}, healthfnError) + err := client.waitForEngine(ctx, command.NewOutStream(&bytes.Buffer{}), healthfnError) assert.ErrorContains(t, err, "timeout waiting") } @@ -228,7 +231,7 @@ func TestWaitForEnginePingFail(t *testing.T) { }, } - err := client.waitForEngine(ctx, &testOutStream{}, healthfnError) + err := client.waitForEngine(ctx, command.NewOutStream(&bytes.Buffer{}), healthfnError) assert.ErrorContains(t, err, "ping fail") } @@ -245,7 +248,7 @@ func TestWaitForEngineHealthy(t *testing.T) { }, } - err := client.waitForEngine(ctx, &testOutStream{}, healthfnHappy) + err := client.waitForEngine(ctx, command.NewOutStream(&bytes.Buffer{}), healthfnHappy) assert.NilError(t, err) } @@ -261,7 +264,7 @@ func TestRemoveEngineBadTaskBadDelete(t *testing.T) { }, } - err := client.RemoveEngine(ctx, container) + err := client.removeEngine(ctx, container) assert.ErrorContains(t, err, "failed to remove existing engine") assert.ErrorContains(t, err, "delete failure") } @@ -280,7 +283,7 @@ func TestRemoveEngineTaskNoStatus(t *testing.T) { }, } - err := client.RemoveEngine(ctx, container) + err := client.removeEngine(ctx, container) assert.ErrorContains(t, err, "task status failure") } @@ -301,7 +304,7 @@ func TestRemoveEngineTaskNotRunningDeleteFail(t *testing.T) { }, } - err := client.RemoveEngine(ctx, container) + err := client.removeEngine(ctx, container) assert.ErrorContains(t, err, "task delete failure") } @@ -322,7 +325,7 @@ func TestRemoveEngineTaskRunningKillFail(t *testing.T) { }, } - err := client.RemoveEngine(ctx, container) + err := client.removeEngine(ctx, container) assert.ErrorContains(t, err, "task kill failure") } @@ -343,7 +346,7 @@ func TestRemoveEngineTaskRunningWaitFail(t *testing.T) { }, } - err := client.RemoveEngine(ctx, container) + err := client.removeEngine(ctx, container) assert.ErrorContains(t, err, "task wait failure") } @@ -366,7 +369,7 @@ func TestRemoveEngineTaskRunningHappyPath(t *testing.T) { }, } - err := client.RemoveEngine(ctx, container) + err := client.removeEngine(ctx, container) assert.NilError(t, err) } @@ -390,7 +393,7 @@ func TestRemoveEngineTaskKillTimeout(t *testing.T) { }, } - err := client.RemoveEngine(ctx, container) + err := client.removeEngine(ctx, container) assert.Assert(t, err == ErrEngineShutdownTimeout) } diff --git a/internal/containerizedengine/types.go b/internal/containerizedengine/types.go index b3acbd28d1..d86a9c3338 100644 --- a/internal/containerizedengine/types.go +++ b/internal/containerizedengine/types.go @@ -3,24 +3,14 @@ package containerizedengine import ( "context" "errors" - "io" "github.com/containerd/containerd" "github.com/containerd/containerd/containers" "github.com/containerd/containerd/content" - registryclient "github.com/docker/cli/cli/registry/client" - "github.com/docker/docker/api/types" - ver "github.com/hashicorp/go-version" specs "github.com/opencontainers/runtime-spec/specs-go" ) const ( - // CommunityEngineImage is the repo name for the community engine - CommunityEngineImage = "engine-community" - - // EnterpriseEngineImage is the repo name for the enterprise engine - EnterpriseEngineImage = "engine-enterprise" - containerdSockPath = "/run/containerd/containerd.sock" engineContainerName = "dockerd" engineNamespace = "docker" @@ -79,45 +69,10 @@ var ( } ) -// Client can be used to manage the lifecycle of -// dockerd running as a container on containerd. -type Client interface { - Close() error - ActivateEngine(ctx context.Context, - opts EngineInitOptions, - out OutStream, - authConfig *types.AuthConfig, - healthfn func(context.Context) error) error - InitEngine(ctx context.Context, - opts EngineInitOptions, - out OutStream, - authConfig *types.AuthConfig, - healthfn func(context.Context) error) error - DoUpdate(ctx context.Context, - opts EngineInitOptions, - out OutStream, - authConfig *types.AuthConfig, - healthfn func(context.Context) error) error - GetEngineVersions(ctx context.Context, registryClient registryclient.RegistryClient, currentVersion, imageName string) (AvailableVersions, error) - - GetEngine(ctx context.Context) (containerd.Container, error) - RemoveEngine(ctx context.Context, engine containerd.Container) error - GetCurrentEngineVersion(ctx context.Context) (EngineInitOptions, error) -} type baseClient struct { cclient containerdClient } -// EngineInitOptions contains the configuration settings -// use during initialization of a containerized docker engine -type EngineInitOptions struct { - RegistryPrefix string - EngineImage string - EngineVersion string - ConfigFile string - scope string -} - // containerdClient abstracts the containerd client to aid in testability type containerdClient interface { Containers(ctx context.Context, filters ...string) ([]containerd.Container, error) @@ -128,32 +83,3 @@ type containerdClient interface { ContentStore() content.Store ContainerService() containers.Store } - -// AvailableVersions groups the available versions which were discovered -type AvailableVersions struct { - Downgrades []DockerVersion - Patches []DockerVersion - Upgrades []DockerVersion -} - -// DockerVersion wraps a semantic version to retain the original tag -// since the docker date based versions don't strictly follow semantic -// versioning (leading zeros, etc.) -type DockerVersion struct { - ver.Version - Tag string -} - -// Update stores available updates for rendering in a table -type Update struct { - Type string - Version string - Notes string -} - -// OutStream is an output stream used to write normal program output. -type OutStream interface { - io.Writer - FD() uintptr - IsTerminal() bool -} diff --git a/internal/containerizedengine/update.go b/internal/containerizedengine/update.go index 5432d8dd4d..0150688372 100644 --- a/internal/containerizedengine/update.go +++ b/internal/containerizedengine/update.go @@ -9,16 +9,17 @@ import ( "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/namespaces" "github.com/docker/cli/internal/pkg/containerized" + clitypes "github.com/docker/cli/types" "github.com/docker/distribution/reference" "github.com/docker/docker/api/types" "github.com/pkg/errors" ) // GetCurrentEngineVersion determines the current type of engine (image) and version -func (c baseClient) GetCurrentEngineVersion(ctx context.Context) (EngineInitOptions, error) { +func (c *baseClient) GetCurrentEngineVersion(ctx context.Context) (clitypes.EngineInitOptions, error) { ctx = namespaces.WithNamespace(ctx, engineNamespace) - ret := EngineInitOptions{} - currentEngine := CommunityEngineImage + ret := clitypes.EngineInitOptions{} + currentEngine := clitypes.CommunityEngineImage engine, err := c.GetEngine(ctx) if err != nil { if err == ErrEngineNotPresent { @@ -35,8 +36,8 @@ func (c baseClient) GetCurrentEngineVersion(ctx context.Context) (EngineInitOpti return ret, errors.Wrapf(err, "failed to parse image name: %s", imageName) } - if strings.Contains(distributionRef.Name(), EnterpriseEngineImage) { - currentEngine = EnterpriseEngineImage + if strings.Contains(distributionRef.Name(), clitypes.EnterpriseEngineImage) { + currentEngine = clitypes.EnterpriseEngineImage } taggedRef, ok := distributionRef.(reference.NamedTagged) if !ok { @@ -49,11 +50,11 @@ func (c baseClient) GetCurrentEngineVersion(ctx context.Context) (EngineInitOpti } // ActivateEngine will switch the image from the CE to EE image -func (c baseClient) ActivateEngine(ctx context.Context, opts EngineInitOptions, out OutStream, +func (c *baseClient) ActivateEngine(ctx context.Context, opts clitypes.EngineInitOptions, out clitypes.OutStream, authConfig *types.AuthConfig, healthfn func(context.Context) error) error { // set the proxy scope to "ee" for activate flows - opts.scope = "ee" + opts.Scope = "ee" ctx = namespaces.WithNamespace(ctx, engineNamespace) @@ -64,7 +65,7 @@ func (c baseClient) ActivateEngine(ctx context.Context, opts EngineInitOptions, return err } opts.EngineVersion = currentOpts.EngineVersion - if currentOpts.EngineImage == EnterpriseEngineImage { + if currentOpts.EngineImage == clitypes.EnterpriseEngineImage { // This is a "no-op" activation so the only change would be the license - don't update the engine itself return nil } @@ -73,7 +74,7 @@ func (c baseClient) ActivateEngine(ctx context.Context, opts EngineInitOptions, } // DoUpdate performs the underlying engine update -func (c baseClient) DoUpdate(ctx context.Context, opts EngineInitOptions, out OutStream, +func (c *baseClient) DoUpdate(ctx context.Context, opts clitypes.EngineInitOptions, out clitypes.OutStream, authConfig *types.AuthConfig, healthfn func(context.Context) error) error { ctx = namespaces.WithNamespace(ctx, engineNamespace) @@ -117,13 +118,13 @@ func (c baseClient) DoUpdate(ctx context.Context, opts EngineInitOptions, out Ou defer cancel() return c.waitForEngine(ctx, out, healthfn) }) - if err == nil && opts.scope != "" { + if err == nil && opts.Scope != "" { var labels map[string]string labels, err = engine.Labels(ctx) if err != nil { return err } - labels[proxyLabel] = opts.scope + labels[proxyLabel] = opts.Scope _, err = engine.SetLabels(ctx, labels) } return err diff --git a/internal/containerizedengine/update_test.go b/internal/containerizedengine/update_test.go index de9e010941..cb1e06dd68 100644 --- a/internal/containerizedengine/update_test.go +++ b/internal/containerizedengine/update_test.go @@ -1,6 +1,7 @@ package containerizedengine import ( + "bytes" "context" "fmt" "testing" @@ -8,6 +9,8 @@ import ( "github.com/containerd/containerd" "github.com/containerd/containerd/cio" "github.com/containerd/containerd/errdefs" + "github.com/docker/cli/cli/command" + clitypes "github.com/docker/cli/types" "github.com/docker/docker/api/types" "gotest.tools/assert" ) @@ -16,7 +19,7 @@ func TestGetCurrentEngineVersionHappy(t *testing.T) { ctx := context.Background() image := &fakeImage{ nameFunc: func() string { - return "acme.com/dockermirror/" + CommunityEngineImage + ":engineversion" + return "acme.com/dockermirror/" + clitypes.CommunityEngineImage + ":engineversion" }, } container := &fakeContainer{ @@ -34,7 +37,7 @@ func TestGetCurrentEngineVersionHappy(t *testing.T) { opts, err := client.GetCurrentEngineVersion(ctx) assert.NilError(t, err) - assert.Equal(t, opts.EngineImage, CommunityEngineImage) + assert.Equal(t, opts.EngineImage, clitypes.CommunityEngineImage) assert.Equal(t, opts.RegistryPrefix, "acme.com/dockermirror") assert.Equal(t, opts.EngineVersion, "engineversion") } @@ -43,7 +46,7 @@ func TestGetCurrentEngineVersionEnterpriseHappy(t *testing.T) { ctx := context.Background() image := &fakeImage{ nameFunc: func() string { - return "docker.io/docker/" + EnterpriseEngineImage + ":engineversion" + return "docker.io/docker/" + clitypes.EnterpriseEngineImage + ":engineversion" }, } container := &fakeContainer{ @@ -61,7 +64,7 @@ func TestGetCurrentEngineVersionEnterpriseHappy(t *testing.T) { opts, err := client.GetCurrentEngineVersion(ctx) assert.NilError(t, err) - assert.Equal(t, opts.EngineImage, EnterpriseEngineImage) + assert.Equal(t, opts.EngineImage, clitypes.EnterpriseEngineImage) assert.Equal(t, opts.EngineVersion, "engineversion") assert.Equal(t, opts.RegistryPrefix, "docker.io/docker") } @@ -147,14 +150,14 @@ func TestActivateNoEngine(t *testing.T) { }, }, } - opts := EngineInitOptions{ + opts := clitypes.EngineInitOptions{ EngineVersion: "engineversiongoeshere", RegistryPrefix: "registryprefixgoeshere", ConfigFile: "/tmp/configfilegoeshere", - EngineImage: EnterpriseEngineImage, + EngineImage: clitypes.EnterpriseEngineImage, } - err := client.ActivateEngine(ctx, opts, &testOutStream{}, &types.AuthConfig{}, healthfnHappy) + err := client.ActivateEngine(ctx, opts, command.NewOutStream(&bytes.Buffer{}), &types.AuthConfig{}, healthfnHappy) assert.ErrorContains(t, err, "unable to find") } @@ -163,7 +166,7 @@ func TestActivateNoChange(t *testing.T) { registryPrefix := "registryprefixgoeshere" image := &fakeImage{ nameFunc: func() string { - return registryPrefix + "/" + EnterpriseEngineImage + ":engineversion" + return registryPrefix + "/" + clitypes.EnterpriseEngineImage + ":engineversion" }, } container := &fakeContainer{ @@ -184,14 +187,14 @@ func TestActivateNoChange(t *testing.T) { }, }, } - opts := EngineInitOptions{ + opts := clitypes.EngineInitOptions{ EngineVersion: "engineversiongoeshere", RegistryPrefix: "registryprefixgoeshere", ConfigFile: "/tmp/configfilegoeshere", - EngineImage: EnterpriseEngineImage, + EngineImage: clitypes.EnterpriseEngineImage, } - err := client.ActivateEngine(ctx, opts, &testOutStream{}, &types.AuthConfig{}, healthfnHappy) + err := client.ActivateEngine(ctx, opts, command.NewOutStream(&bytes.Buffer{}), &types.AuthConfig{}, healthfnHappy) assert.NilError(t, err) } @@ -219,34 +222,34 @@ func TestActivateDoUpdateFail(t *testing.T) { }, }, } - opts := EngineInitOptions{ + opts := clitypes.EngineInitOptions{ EngineVersion: "engineversiongoeshere", RegistryPrefix: "registryprefixgoeshere", ConfigFile: "/tmp/configfilegoeshere", - EngineImage: EnterpriseEngineImage, + EngineImage: clitypes.EnterpriseEngineImage, } - err := client.ActivateEngine(ctx, opts, &testOutStream{}, &types.AuthConfig{}, healthfnHappy) + err := client.ActivateEngine(ctx, opts, command.NewOutStream(&bytes.Buffer{}), &types.AuthConfig{}, healthfnHappy) assert.ErrorContains(t, err, "check for image") assert.ErrorContains(t, err, "something went wrong") } func TestDoUpdateNoVersion(t *testing.T) { ctx := context.Background() - opts := EngineInitOptions{ + opts := clitypes.EngineInitOptions{ EngineVersion: "", RegistryPrefix: "registryprefixgoeshere", ConfigFile: "/tmp/configfilegoeshere", - EngineImage: EnterpriseEngineImage, + EngineImage: clitypes.EnterpriseEngineImage, } client := baseClient{} - err := client.DoUpdate(ctx, opts, &testOutStream{}, &types.AuthConfig{}, healthfnHappy) + err := client.DoUpdate(ctx, opts, command.NewOutStream(&bytes.Buffer{}), &types.AuthConfig{}, healthfnHappy) assert.ErrorContains(t, err, "please pick the version you") } func TestDoUpdateImageMiscError(t *testing.T) { ctx := context.Background() - opts := EngineInitOptions{ + opts := clitypes.EngineInitOptions{ EngineVersion: "engineversiongoeshere", RegistryPrefix: "registryprefixgoeshere", ConfigFile: "/tmp/configfilegoeshere", @@ -260,14 +263,14 @@ func TestDoUpdateImageMiscError(t *testing.T) { }, }, } - err := client.DoUpdate(ctx, opts, &testOutStream{}, &types.AuthConfig{}, healthfnHappy) + err := client.DoUpdate(ctx, opts, command.NewOutStream(&bytes.Buffer{}), &types.AuthConfig{}, healthfnHappy) assert.ErrorContains(t, err, "check for image") assert.ErrorContains(t, err, "something went wrong") } func TestDoUpdatePullFail(t *testing.T) { ctx := context.Background() - opts := EngineInitOptions{ + opts := clitypes.EngineInitOptions{ EngineVersion: "engineversiongoeshere", RegistryPrefix: "registryprefixgoeshere", ConfigFile: "/tmp/configfilegoeshere", @@ -284,14 +287,14 @@ func TestDoUpdatePullFail(t *testing.T) { }, }, } - err := client.DoUpdate(ctx, opts, &testOutStream{}, &types.AuthConfig{}, healthfnHappy) + err := client.DoUpdate(ctx, opts, command.NewOutStream(&bytes.Buffer{}), &types.AuthConfig{}, healthfnHappy) assert.ErrorContains(t, err, "unable to pull") assert.ErrorContains(t, err, "pull failure") } func TestDoUpdateEngineMissing(t *testing.T) { ctx := context.Background() - opts := EngineInitOptions{ + opts := clitypes.EngineInitOptions{ EngineVersion: "engineversiongoeshere", RegistryPrefix: "registryprefixgoeshere", ConfigFile: "/tmp/configfilegoeshere", @@ -313,6 +316,6 @@ func TestDoUpdateEngineMissing(t *testing.T) { }, }, } - err := client.DoUpdate(ctx, opts, &testOutStream{}, &types.AuthConfig{}, healthfnHappy) + err := client.DoUpdate(ctx, opts, command.NewOutStream(&bytes.Buffer{}), &types.AuthConfig{}, healthfnHappy) assert.ErrorContains(t, err, "unable to find existing engine") } diff --git a/internal/containerizedengine/versions.go b/internal/containerizedengine/versions.go index ddff58df5c..63ac4a2dc2 100644 --- a/internal/containerizedengine/versions.go +++ b/internal/containerizedengine/versions.go @@ -5,6 +5,7 @@ import ( "sort" registryclient "github.com/docker/cli/cli/registry/client" + clitypes "github.com/docker/cli/types" "github.com/docker/distribution/reference" ver "github.com/hashicorp/go-version" "github.com/pkg/errors" @@ -12,29 +13,29 @@ import ( ) // GetEngineVersions reports the versions of the engine that are available -func (c baseClient) GetEngineVersions(ctx context.Context, registryClient registryclient.RegistryClient, currentVersion, imageName string) (AvailableVersions, error) { +func (c *baseClient) GetEngineVersions(ctx context.Context, registryClient registryclient.RegistryClient, currentVersion, imageName string) (clitypes.AvailableVersions, error) { imageRef, err := reference.ParseNormalizedNamed(imageName) if err != nil { - return AvailableVersions{}, err + return clitypes.AvailableVersions{}, err } tags, err := registryClient.GetTags(ctx, imageRef) if err != nil { - return AvailableVersions{}, err + return clitypes.AvailableVersions{}, err } return parseTags(tags, currentVersion) } -func parseTags(tags []string, currentVersion string) (AvailableVersions, error) { - var ret AvailableVersions +func parseTags(tags []string, currentVersion string) (clitypes.AvailableVersions, error) { + var ret clitypes.AvailableVersions currentVer, err := ver.NewVersion(currentVersion) if err != nil { return ret, errors.Wrapf(err, "failed to parse existing version %s", currentVersion) } - downgrades := []DockerVersion{} - patches := []DockerVersion{} - upgrades := []DockerVersion{} + downgrades := []clitypes.DockerVersion{} + patches := []clitypes.DockerVersion{} + upgrades := []clitypes.DockerVersion{} currentSegments := currentVer.Segments() for _, tag := range tags { tmp, err := ver.NewVersion(tag) @@ -42,7 +43,7 @@ func parseTags(tags []string, currentVersion string) (AvailableVersions, error) logrus.Debugf("Unable to parse %s: %s", tag, err) continue } - testVersion := DockerVersion{Version: *tmp, Tag: tag} + testVersion := clitypes.DockerVersion{Version: *tmp, Tag: tag} if testVersion.LessThan(currentVer) { downgrades = append(downgrades, testVersion) continue diff --git a/internal/test/cli.go b/internal/test/cli.go index 40ede8a7d4..a7445881f8 100644 --- a/internal/test/cli.go +++ b/internal/test/cli.go @@ -12,7 +12,7 @@ import ( manifeststore "github.com/docker/cli/cli/manifest/store" registryclient "github.com/docker/cli/cli/registry/client" "github.com/docker/cli/cli/trust" - "github.com/docker/cli/internal/containerizedengine" + clitypes "github.com/docker/cli/types" "github.com/docker/docker/client" notaryclient "github.com/theupdateframework/notary/client" ) @@ -20,7 +20,7 @@ import ( // NotaryClientFuncType defines a function that returns a fake notary client type NotaryClientFuncType func(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (notaryclient.Repository, error) type clientInfoFuncType func() command.ClientInfo -type containerizedEngineFuncType func(string) (containerizedengine.Client, error) +type containerizedEngineFuncType func(string) (clitypes.ContainerizedClient, error) // FakeCli emulates the default DockerCli type FakeCli struct { @@ -172,7 +172,7 @@ func EnableContentTrust(c *FakeCli) { } // NewContainerizedEngineClient returns a containerized engine client -func (c *FakeCli) NewContainerizedEngineClient(sockPath string) (containerizedengine.Client, error) { +func (c *FakeCli) NewContainerizedEngineClient(sockPath string) (clitypes.ContainerizedClient, error) { if c.containerizedEngineClientFunc != nil { return c.containerizedEngineClientFunc(sockPath) } diff --git a/man/generate.go b/man/generate.go index 4197558a22..2d940e31fd 100644 --- a/man/generate.go +++ b/man/generate.go @@ -25,7 +25,7 @@ func generateManPages(opts *options) error { } stdin, stdout, stderr := term.StdStreams() - dockerCli := command.NewDockerCli(stdin, stdout, stderr, false) + dockerCli := command.NewDockerCli(stdin, stdout, stderr, false, nil) cmd := &cobra.Command{Use: "docker"} commands.AddCommands(cmd, dockerCli) source := filepath.Join(opts.source, descriptionSourcePath) diff --git a/types/types.go b/types/types.go new file mode 100644 index 0000000000..0a376e0579 --- /dev/null +++ b/types/types.go @@ -0,0 +1,81 @@ +package types + +import ( + "context" + "io" + + registryclient "github.com/docker/cli/cli/registry/client" + "github.com/docker/docker/api/types" + ver "github.com/hashicorp/go-version" +) + +const ( + // CommunityEngineImage is the repo name for the community engine + CommunityEngineImage = "engine-community" + + // EnterpriseEngineImage is the repo name for the enterprise engine + EnterpriseEngineImage = "engine-enterprise" +) + +// ContainerizedClient can be used to manage the lifecycle of +// dockerd running as a container on containerd. +type ContainerizedClient interface { + Close() error + ActivateEngine(ctx context.Context, + opts EngineInitOptions, + out OutStream, + authConfig *types.AuthConfig, + healthfn func(context.Context) error) error + InitEngine(ctx context.Context, + opts EngineInitOptions, + out OutStream, + authConfig *types.AuthConfig, + healthfn func(context.Context) error) error + DoUpdate(ctx context.Context, + opts EngineInitOptions, + out OutStream, + authConfig *types.AuthConfig, + healthfn func(context.Context) error) error + GetEngineVersions(ctx context.Context, registryClient registryclient.RegistryClient, currentVersion, imageName string) (AvailableVersions, error) + GetCurrentEngineVersion(ctx context.Context) (EngineInitOptions, error) + RemoveEngine(ctx context.Context) error +} + +// EngineInitOptions contains the configuration settings +// use during initialization of a containerized docker engine +type EngineInitOptions struct { + RegistryPrefix string + EngineImage string + EngineVersion string + ConfigFile string + Scope string +} + +// AvailableVersions groups the available versions which were discovered +type AvailableVersions struct { + Downgrades []DockerVersion + Patches []DockerVersion + Upgrades []DockerVersion +} + +// DockerVersion wraps a semantic version to retain the original tag +// since the docker date based versions don't strictly follow semantic +// versioning (leading zeros, etc.) +type DockerVersion struct { + ver.Version + Tag string +} + +// Update stores available updates for rendering in a table +type Update struct { + Type string + Version string + Notes string +} + +// OutStream is an output stream used to write normal program output. +type OutStream interface { + io.Writer + FD() uintptr + IsTerminal() bool +}