Remove containerizedengine package dependency from docker/cli/command…

… this removes a whole lot of dependencies from people depending on docker/cli…

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
This commit is contained in:
Vincent Demeester 2018-09-11 14:46:30 +02:00
parent 8ec21567a7
commit 2d344b2f61
No known key found for this signature in database
GPG Key ID: 083CC6FD6EB699A3
29 changed files with 283 additions and 262 deletions

View File

@ -19,8 +19,8 @@ import (
manifeststore "github.com/docker/cli/cli/manifest/store" manifeststore "github.com/docker/cli/cli/manifest/store"
registryclient "github.com/docker/cli/cli/registry/client" registryclient "github.com/docker/cli/cli/registry/client"
"github.com/docker/cli/cli/trust" "github.com/docker/cli/cli/trust"
"github.com/docker/cli/internal/containerizedengine"
dopts "github.com/docker/cli/opts" dopts "github.com/docker/cli/opts"
clitypes "github.com/docker/cli/types"
"github.com/docker/docker/api" "github.com/docker/docker/api"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
registrytypes "github.com/docker/docker/api/types/registry" registrytypes "github.com/docker/docker/api/types/registry"
@ -55,20 +55,21 @@ type Cli interface {
ManifestStore() manifeststore.Store ManifestStore() manifeststore.Store
RegistryClient(bool) registryclient.RegistryClient RegistryClient(bool) registryclient.RegistryClient
ContentTrustEnabled() bool ContentTrustEnabled() bool
NewContainerizedEngineClient(sockPath string) (containerizedengine.Client, error) NewContainerizedEngineClient(sockPath string) (clitypes.ContainerizedClient, error)
} }
// DockerCli is an instance the docker command line client. // DockerCli is an instance the docker command line client.
// Instances of the client can be returned from NewDockerCli. // Instances of the client can be returned from NewDockerCli.
type DockerCli struct { type DockerCli struct {
configFile *configfile.ConfigFile configFile *configfile.ConfigFile
in *InStream in *InStream
out *OutStream out *OutStream
err io.Writer err io.Writer
client client.APIClient client client.APIClient
serverInfo ServerInfo serverInfo ServerInfo
clientInfo ClientInfo clientInfo ClientInfo
contentTrust bool contentTrust bool
newContainerizeClient func(string) (clitypes.ContainerizedClient, error)
} }
// DefaultVersion returns api.defaultVersion or DOCKER_API_VERSION if specified. // 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 // NewContainerizedEngineClient returns a containerized engine client
func (cli *DockerCli) NewContainerizedEngineClient(sockPath string) (containerizedengine.Client, error) { func (cli *DockerCli) NewContainerizedEngineClient(sockPath string) (clitypes.ContainerizedClient, error) {
return containerizedengine.NewClient(sockPath) return cli.newContainerizeClient(sockPath)
} }
// ServerInfo stores details about the supported features and platform of the // 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. // 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 { 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} return &DockerCli{in: NewInStream(in), out: NewOutStream(out), err: err, contentTrust: isTrusted, newContainerizeClient: containerizedFn}
} }
// NewAPIClientFromFlags creates a new APIClient from command line flags // NewAPIClientFromFlags creates a new APIClient from command line flags

View File

@ -6,8 +6,8 @@ import (
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/formatter" "github.com/docker/cli/cli/command/formatter"
"github.com/docker/cli/internal/containerizedengine"
"github.com/docker/cli/internal/licenseutils" "github.com/docker/cli/internal/licenseutils"
clitypes "github.com/docker/cli/types"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/licensing/model" "github.com/docker/licensing/model"
"github.com/pkg/errors" "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.licenseFile, "license", "", "License File")
flags.StringVar(&options.version, "version", "", "Specify engine version (default is to use currently running version)") 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.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.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.displayOnly, "display-only", false, "only display the available licenses and exit")
flags.BoolVar(&options.quiet, "quiet", false, "Only display available licenses by ID") 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 return err
} }
opts := containerizedengine.EngineInitOptions{ opts := clitypes.EngineInitOptions{
RegistryPrefix: options.registryPrefix, RegistryPrefix: options.registryPrefix,
EngineImage: options.image, EngineImage: options.image,
EngineVersion: options.version, EngineVersion: options.version,

View File

@ -4,13 +4,13 @@ import (
"fmt" "fmt"
"testing" "testing"
"github.com/docker/cli/internal/containerizedengine" "github.com/docker/cli/types"
"gotest.tools/assert" "gotest.tools/assert"
) )
func TestActivateNoContainerd(t *testing.T) { func TestActivateNoContainerd(t *testing.T) {
testCli.SetContainerizedEngineClient( testCli.SetContainerizedEngineClient(
func(string) (containerizedengine.Client, error) { func(string) (types.ContainerizedClient, error) {
return nil, fmt.Errorf("some error") return nil, fmt.Errorf("some error")
}, },
) )
@ -24,7 +24,7 @@ func TestActivateNoContainerd(t *testing.T) {
func TestActivateBadLicense(t *testing.T) { func TestActivateBadLicense(t *testing.T) {
testCli.SetContainerizedEngineClient( testCli.SetContainerizedEngineClient(
func(string) (containerizedengine.Client, error) { func(string) (types.ContainerizedClient, error) {
return &fakeContainerizedEngineClient{}, nil return &fakeContainerizedEngineClient{}, nil
}, },
) )

View File

@ -7,7 +7,7 @@ import (
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/formatter" "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/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -72,7 +72,7 @@ func runCheck(dockerCli command.Cli, options checkOptions) error {
return err return err
} }
availUpdates := []containerizedengine.Update{ availUpdates := []clitypes.Update{
{Type: "current", Version: currentVersion}, {Type: "current", Version: currentVersion},
} }
if len(versions.Patches) > 0 { if len(versions.Patches) > 0 {
@ -115,14 +115,14 @@ func runCheck(dockerCli command.Cli, options checkOptions) error {
func processVersions(currentVersion, verType string, func processVersions(currentVersion, verType string,
includePrerelease bool, includePrerelease bool,
versions []containerizedengine.DockerVersion) []containerizedengine.Update { versions []clitypes.DockerVersion) []clitypes.Update {
availUpdates := []containerizedengine.Update{} availUpdates := []clitypes.Update{}
for _, ver := range versions { for _, ver := range versions {
if !includePrerelease && ver.Prerelease() != "" { if !includePrerelease && ver.Prerelease() != "" {
continue continue
} }
if ver.Tag != currentVersion { if ver.Tag != currentVersion {
availUpdates = append(availUpdates, containerizedengine.Update{ availUpdates = append(availUpdates, clitypes.Update{
Type: verType, Type: verType,
Version: ver.Tag, Version: ver.Tag,
Notes: fmt.Sprintf("%s/%s", releaseNotePrefix, ver.Tag), Notes: fmt.Sprintf("%s/%s", releaseNotePrefix, ver.Tag),

View File

@ -6,8 +6,8 @@ import (
"testing" "testing"
registryclient "github.com/docker/cli/cli/registry/client" registryclient "github.com/docker/cli/cli/registry/client"
"github.com/docker/cli/internal/containerizedengine"
"github.com/docker/cli/internal/test" "github.com/docker/cli/internal/test"
clitypes "github.com/docker/cli/types"
"github.com/docker/docker/client" "github.com/docker/docker/client"
ver "github.com/hashicorp/go-version" ver "github.com/hashicorp/go-version"
"gotest.tools/assert" "gotest.tools/assert"
@ -20,7 +20,7 @@ var (
func TestCheckForUpdatesNoContainerd(t *testing.T) { func TestCheckForUpdatesNoContainerd(t *testing.T) {
testCli.SetContainerizedEngineClient( testCli.SetContainerizedEngineClient(
func(string) (containerizedengine.Client, error) { func(string) (clitypes.ContainerizedClient, error) {
return nil, fmt.Errorf("some error") return nil, fmt.Errorf("some error")
}, },
) )
@ -33,11 +33,11 @@ func TestCheckForUpdatesNoContainerd(t *testing.T) {
func TestCheckForUpdatesNoCurrentVersion(t *testing.T) { func TestCheckForUpdatesNoCurrentVersion(t *testing.T) {
retErr := fmt.Errorf("some failure") retErr := fmt.Errorf("some failure")
getCurrentEngineVersionFunc := func(ctx context.Context) (containerizedengine.EngineInitOptions, error) { getCurrentEngineVersionFunc := func(ctx context.Context) (clitypes.EngineInitOptions, error) {
return containerizedengine.EngineInitOptions{}, retErr return clitypes.EngineInitOptions{}, retErr
} }
testCli.SetContainerizedEngineClient( testCli.SetContainerizedEngineClient(
func(string) (containerizedengine.Client, error) { func(string) (clitypes.ContainerizedClient, error) {
return &fakeContainerizedEngineClient{ return &fakeContainerizedEngineClient{
getCurrentEngineVersionFunc: getCurrentEngineVersionFunc, getCurrentEngineVersionFunc: getCurrentEngineVersionFunc,
}, nil }, nil
@ -54,11 +54,11 @@ func TestCheckForUpdatesGetEngineVersionsFail(t *testing.T) {
retErr := fmt.Errorf("some failure") retErr := fmt.Errorf("some failure")
getEngineVersionsFunc := func(ctx context.Context, getEngineVersionsFunc := func(ctx context.Context,
registryClient registryclient.RegistryClient, registryClient registryclient.RegistryClient,
currentVersion, imageName string) (containerizedengine.AvailableVersions, error) { currentVersion, imageName string) (clitypes.AvailableVersions, error) {
return containerizedengine.AvailableVersions{}, retErr return clitypes.AvailableVersions{}, retErr
} }
testCli.SetContainerizedEngineClient( testCli.SetContainerizedEngineClient(
func(string) (containerizedengine.Client, error) { func(string) (clitypes.ContainerizedClient, error) {
return &fakeContainerizedEngineClient{ return &fakeContainerizedEngineClient{
getEngineVersionsFunc: getEngineVersionsFunc, getEngineVersionsFunc: getEngineVersionsFunc,
}, nil }, nil
@ -72,23 +72,23 @@ func TestCheckForUpdatesGetEngineVersionsFail(t *testing.T) {
} }
func TestCheckForUpdatesGetEngineVersionsHappy(t *testing.T) { func TestCheckForUpdatesGetEngineVersionsHappy(t *testing.T) {
getCurrentEngineVersionFunc := func(ctx context.Context) (containerizedengine.EngineInitOptions, error) { getCurrentEngineVersionFunc := func(ctx context.Context) (clitypes.EngineInitOptions, error) {
return containerizedengine.EngineInitOptions{ return clitypes.EngineInitOptions{
EngineImage: "current engine", EngineImage: "current engine",
EngineVersion: "1.1.0", EngineVersion: "1.1.0",
}, nil }, nil
} }
getEngineVersionsFunc := func(ctx context.Context, getEngineVersionsFunc := func(ctx context.Context,
registryClient registryclient.RegistryClient, registryClient registryclient.RegistryClient,
currentVersion, imageName string) (containerizedengine.AvailableVersions, error) { currentVersion, imageName string) (clitypes.AvailableVersions, error) {
return containerizedengine.AvailableVersions{ return clitypes.AvailableVersions{
Downgrades: parseVersions(t, "1.0.1", "1.0.2", "1.0.3-beta1"), 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"), 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"), Upgrades: parseVersions(t, "1.2.0", "2.0.0", "2.1.0-beta1"),
}, nil }, nil
} }
testCli.SetContainerizedEngineClient( testCli.SetContainerizedEngineClient(
func(string) (containerizedengine.Client, error) { func(string) (clitypes.ContainerizedClient, error) {
return &fakeContainerizedEngineClient{ return &fakeContainerizedEngineClient{
getEngineVersionsFunc: getEngineVersionsFunc, getEngineVersionsFunc: getEngineVersionsFunc,
getCurrentEngineVersionFunc: getCurrentEngineVersionFunc, getCurrentEngineVersionFunc: getCurrentEngineVersionFunc,
@ -128,14 +128,14 @@ func TestCheckForUpdatesGetEngineVersionsHappy(t *testing.T) {
golden.Assert(t, testCli.OutBuffer().String(), "check-patches-only.golden") 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) v, err := ver.NewVersion(tag)
assert.NilError(t, err) 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 { func parseVersions(t *testing.T, tags ...string) []clitypes.DockerVersion {
ret := make([]containerizedengine.DockerVersion, len(tags)) ret := make([]clitypes.DockerVersion, len(tags))
for i, tag := range tags { for i, tag := range tags {
ret[i] = makeVersion(t, tag) ret[i] = makeVersion(t, tag)
} }

View File

@ -5,7 +5,7 @@ import (
"github.com/containerd/containerd" "github.com/containerd/containerd"
registryclient "github.com/docker/cli/cli/registry/client" 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" "github.com/docker/docker/api/types"
) )
@ -13,28 +13,28 @@ type (
fakeContainerizedEngineClient struct { fakeContainerizedEngineClient struct {
closeFunc func() error closeFunc func() error
activateEngineFunc func(ctx context.Context, activateEngineFunc func(ctx context.Context,
opts containerizedengine.EngineInitOptions, opts clitypes.EngineInitOptions,
out containerizedengine.OutStream, out clitypes.OutStream,
authConfig *types.AuthConfig, authConfig *types.AuthConfig,
healthfn func(context.Context) error) error healthfn func(context.Context) error) error
initEngineFunc func(ctx context.Context, initEngineFunc func(ctx context.Context,
opts containerizedengine.EngineInitOptions, opts clitypes.EngineInitOptions,
out containerizedengine.OutStream, out clitypes.OutStream,
authConfig *types.AuthConfig, authConfig *types.AuthConfig,
healthfn func(context.Context) error) error healthfn func(context.Context) error) error
doUpdateFunc func(ctx context.Context, doUpdateFunc func(ctx context.Context,
opts containerizedengine.EngineInitOptions, opts clitypes.EngineInitOptions,
out containerizedengine.OutStream, out clitypes.OutStream,
authConfig *types.AuthConfig, authConfig *types.AuthConfig,
healthfn func(context.Context) error) error healthfn func(context.Context) error) error
getEngineVersionsFunc func(ctx context.Context, getEngineVersionsFunc func(ctx context.Context,
registryClient registryclient.RegistryClient, registryClient registryclient.RegistryClient,
currentVersion, currentVersion,
imageName string) (containerizedengine.AvailableVersions, error) imageName string) (clitypes.AvailableVersions, error)
getEngineFunc func(ctx context.Context) (containerd.Container, error) getEngineFunc func(ctx context.Context) (containerd.Container, error)
removeEngineFunc func(ctx context.Context, engine containerd.Container) error removeEngineFunc func(ctx context.Context) error
getCurrentEngineVersionFunc func(ctx context.Context) (containerizedengine.EngineInitOptions, 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, func (w *fakeContainerizedEngineClient) ActivateEngine(ctx context.Context,
opts containerizedengine.EngineInitOptions, opts clitypes.EngineInitOptions,
out containerizedengine.OutStream, out clitypes.OutStream,
authConfig *types.AuthConfig, authConfig *types.AuthConfig,
healthfn func(context.Context) error) error { healthfn func(context.Context) error) error {
if w.activateEngineFunc != nil { if w.activateEngineFunc != nil {
@ -56,8 +56,8 @@ func (w *fakeContainerizedEngineClient) ActivateEngine(ctx context.Context,
return nil return nil
} }
func (w *fakeContainerizedEngineClient) InitEngine(ctx context.Context, func (w *fakeContainerizedEngineClient) InitEngine(ctx context.Context,
opts containerizedengine.EngineInitOptions, opts clitypes.EngineInitOptions,
out containerizedengine.OutStream, out clitypes.OutStream,
authConfig *types.AuthConfig, authConfig *types.AuthConfig,
healthfn func(context.Context) error) error { healthfn func(context.Context) error) error {
if w.initEngineFunc != nil { if w.initEngineFunc != nil {
@ -66,8 +66,8 @@ func (w *fakeContainerizedEngineClient) InitEngine(ctx context.Context,
return nil return nil
} }
func (w *fakeContainerizedEngineClient) DoUpdate(ctx context.Context, func (w *fakeContainerizedEngineClient) DoUpdate(ctx context.Context,
opts containerizedengine.EngineInitOptions, opts clitypes.EngineInitOptions,
out containerizedengine.OutStream, out clitypes.OutStream,
authConfig *types.AuthConfig, authConfig *types.AuthConfig,
healthfn func(context.Context) error) error { healthfn func(context.Context) error) error {
if w.doUpdateFunc != nil { if w.doUpdateFunc != nil {
@ -77,12 +77,12 @@ func (w *fakeContainerizedEngineClient) DoUpdate(ctx context.Context,
} }
func (w *fakeContainerizedEngineClient) GetEngineVersions(ctx context.Context, func (w *fakeContainerizedEngineClient) GetEngineVersions(ctx context.Context,
registryClient registryclient.RegistryClient, registryClient registryclient.RegistryClient,
currentVersion, imageName string) (containerizedengine.AvailableVersions, error) { currentVersion, imageName string) (clitypes.AvailableVersions, error) {
if w.getEngineVersionsFunc != nil { if w.getEngineVersionsFunc != nil {
return w.getEngineVersionsFunc(ctx, registryClient, currentVersion, imageName) 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) { 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 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 { if w.removeEngineFunc != nil {
return w.removeEngineFunc(ctx, engine) return w.removeEngineFunc(ctx)
} }
return nil 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 { if w.getCurrentEngineVersionFunc != nil {
return w.getCurrentEngineVersionFunc(ctx) return w.getCurrentEngineVersionFunc(ctx)
} }
return containerizedengine.EngineInitOptions{}, nil return clitypes.EngineInitOptions{}, nil
} }

View File

@ -5,13 +5,13 @@ import (
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/internal/containerizedengine" clitypes "github.com/docker/cli/types"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
type extendedEngineInitOptions struct { type extendedEngineInitOptions struct {
containerizedengine.EngineInitOptions clitypes.EngineInitOptions
sockPath string sockPath string
} }
@ -34,7 +34,7 @@ file on the host and may be pre-created before running the 'init' command.
} }
flags := cmd.Flags() flags := cmd.Flags()
flags.StringVar(&options.EngineVersion, "version", cli.Version, "Specify engine version") 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.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.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") flags.StringVar(&options.sockPath, "containerd", "", "override default location of containerd endpoint")

View File

@ -4,13 +4,13 @@ import (
"fmt" "fmt"
"testing" "testing"
"github.com/docker/cli/internal/containerizedengine" clitypes "github.com/docker/cli/types"
"gotest.tools/assert" "gotest.tools/assert"
) )
func TestInitNoContainerd(t *testing.T) { func TestInitNoContainerd(t *testing.T) {
testCli.SetContainerizedEngineClient( testCli.SetContainerizedEngineClient(
func(string) (containerizedengine.Client, error) { func(string) (clitypes.ContainerizedClient, error) {
return nil, fmt.Errorf("some error") return nil, fmt.Errorf("some error")
}, },
) )
@ -23,7 +23,7 @@ func TestInitNoContainerd(t *testing.T) {
func TestInitHappy(t *testing.T) { func TestInitHappy(t *testing.T) {
testCli.SetContainerizedEngineClient( testCli.SetContainerizedEngineClient(
func(string) (containerizedengine.Client, error) { func(string) (clitypes.ContainerizedClient, error) {
return &fakeContainerizedEngineClient{}, nil return &fakeContainerizedEngineClient{}, nil
}, },
) )

View File

@ -45,10 +45,5 @@ func runRm(dockerCli command.Cli, options rmOptions) error {
} }
defer client.Close() defer client.Close()
engine, err := client.GetEngine(ctx) return client.RemoveEngine(ctx)
if err != nil {
return err
}
return client.RemoveEngine(ctx, engine)
} }

View File

@ -4,13 +4,13 @@ import (
"fmt" "fmt"
"testing" "testing"
"github.com/docker/cli/internal/containerizedengine" clitypes "github.com/docker/cli/types"
"gotest.tools/assert" "gotest.tools/assert"
) )
func TestRmNoContainerd(t *testing.T) { func TestRmNoContainerd(t *testing.T) {
testCli.SetContainerizedEngineClient( testCli.SetContainerizedEngineClient(
func(string) (containerizedengine.Client, error) { func(string) (clitypes.ContainerizedClient, error) {
return nil, fmt.Errorf("some error") return nil, fmt.Errorf("some error")
}, },
) )
@ -23,7 +23,7 @@ func TestRmNoContainerd(t *testing.T) {
func TestRmHappy(t *testing.T) { func TestRmHappy(t *testing.T) {
testCli.SetContainerizedEngineClient( testCli.SetContainerizedEngineClient(
func(string) (containerizedengine.Client, error) { func(string) (clitypes.ContainerizedClient, error) {
return &fakeContainerizedEngineClient{}, nil return &fakeContainerizedEngineClient{}, nil
}, },
) )

View File

@ -4,13 +4,13 @@ import (
"fmt" "fmt"
"testing" "testing"
"github.com/docker/cli/internal/containerizedengine" clitypes "github.com/docker/cli/types"
"gotest.tools/assert" "gotest.tools/assert"
) )
func TestUpdateNoContainerd(t *testing.T) { func TestUpdateNoContainerd(t *testing.T) {
testCli.SetContainerizedEngineClient( testCli.SetContainerizedEngineClient(
func(string) (containerizedengine.Client, error) { func(string) (clitypes.ContainerizedClient, error) {
return nil, fmt.Errorf("some error") return nil, fmt.Errorf("some error")
}, },
) )
@ -23,7 +23,7 @@ func TestUpdateNoContainerd(t *testing.T) {
func TestUpdateHappy(t *testing.T) { func TestUpdateHappy(t *testing.T) {
testCli.SetContainerizedEngineClient( testCli.SetContainerizedEngineClient(
func(string) (containerizedengine.Client, error) { func(string) (clitypes.ContainerizedClient, error) {
return &fakeContainerizedEngineClient{}, nil return &fakeContainerizedEngineClient{}, nil
}, },
) )

View File

@ -1,7 +1,7 @@
package formatter package formatter
import ( import (
"github.com/docker/cli/internal/containerizedengine" clitypes "github.com/docker/cli/types"
) )
const ( const (
@ -31,7 +31,7 @@ func NewUpdatesFormat(source string, quiet bool) Format {
} }
// UpdatesWrite writes the context // 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 { render := func(format func(subContext subContext) error) error {
for _, update := range availableUpdates { for _, update := range availableUpdates {
updatesCtx := &updateContext{trunc: ctx.Trunc, u: update} updatesCtx := &updateContext{trunc: ctx.Trunc, u: update}
@ -53,7 +53,7 @@ func UpdatesWrite(ctx Context, availableUpdates []containerizedengine.Update) er
type updateContext struct { type updateContext struct {
HeaderContext HeaderContext
trunc bool trunc bool
u containerizedengine.Update u clitypes.Update
} }
func (c *updateContext) MarshalJSON() ([]byte, error) { func (c *updateContext) MarshalJSON() ([]byte, error) {

View File

@ -6,7 +6,7 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/docker/cli/internal/containerizedengine" clitypes "github.com/docker/cli/types"
"gotest.tools/assert" "gotest.tools/assert"
is "gotest.tools/assert/cmp" is "gotest.tools/assert/cmp"
) )
@ -84,7 +84,7 @@ version2
} }
for _, testcase := range cases { for _, testcase := range cases {
updates := []containerizedengine.Update{ updates := []clitypes.Update{
{Type: "updateType1", Version: "version1", Notes: "description 1"}, {Type: "updateType1", Version: "version1", Notes: "description 1"},
{Type: "updateType2", Version: "version2", Notes: "description 2"}, {Type: "updateType2", Version: "version2", Notes: "description 2"},
} }
@ -100,7 +100,7 @@ version2
} }
func TestUpdateContextWriteJSON(t *testing.T) { func TestUpdateContextWriteJSON(t *testing.T) {
updates := []containerizedengine.Update{ updates := []clitypes.Update{
{Type: "updateType1", Version: "version1", Notes: "note1"}, {Type: "updateType1", Version: "version1", Notes: "note1"},
{Type: "updateType2", Version: "version2", Notes: "note2"}, {Type: "updateType2", Version: "version2", Notes: "note2"},
} }
@ -124,7 +124,7 @@ func TestUpdateContextWriteJSON(t *testing.T) {
} }
func TestUpdateContextWriteJSONField(t *testing.T) { func TestUpdateContextWriteJSONField(t *testing.T) {
updates := []containerizedengine.Update{ updates := []clitypes.Update{
{Type: "updateType1", Version: "version1"}, {Type: "updateType1", Version: "version1"},
{Type: "updateType2", Version: "version2"}, {Type: "updateType2", Version: "version2"},
} }

View File

@ -13,6 +13,7 @@ import (
cliconfig "github.com/docker/cli/cli/config" cliconfig "github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/debug" "github.com/docker/cli/cli/debug"
cliflags "github.com/docker/cli/cli/flags" cliflags "github.com/docker/cli/cli/flags"
"github.com/docker/cli/internal/containerizedengine"
"github.com/docker/docker/api/types/versions" "github.com/docker/docker/api/types/versions"
"github.com/docker/docker/client" "github.com/docker/docker/client"
"github.com/docker/docker/pkg/term" "github.com/docker/docker/pkg/term"
@ -168,7 +169,7 @@ func main() {
stdin, stdout, stderr := term.StdStreams() stdin, stdout, stderr := term.StdStreams()
logrus.SetOutput(stderr) logrus.SetOutput(stderr)
dockerCli := command.NewDockerCli(stdin, stdout, stderr, contentTrustEnabled()) dockerCli := command.NewDockerCli(stdin, stdout, stderr, contentTrustEnabled(), containerizedengine.NewClient)
cmd := newDockerCommand(dockerCli) cmd := newDockerCommand(dockerCli)
if err := cmd.Execute(); err != nil { if err := cmd.Execute(); err != nil {

View File

@ -26,7 +26,7 @@ func TestClientDebugEnabled(t *testing.T) {
func TestExitStatusForInvalidSubcommandWithHelpFlag(t *testing.T) { func TestExitStatusForInvalidSubcommandWithHelpFlag(t *testing.T) {
discard := ioutil.Discard 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"}) cmd.SetArgs([]string{"help", "invalid"})
err := cmd.Execute() err := cmd.Execute()
assert.Error(t, err, "unknown help topic: invalid") assert.Error(t, err, "unknown help topic: invalid")

View File

@ -19,7 +19,7 @@ const descriptionSourcePath = "docs/reference/commandline/"
func generateCliYaml(opts *options) error { func generateCliYaml(opts *options) error {
stdin, stdout, stderr := term.StdStreams() 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"} cmd := &cobra.Command{Use: "docker"}
commands.AddCommands(cmd, dockerCli) commands.AddCommands(cmd, dockerCli)
source := filepath.Join(opts.source, descriptionSourcePath) source := filepath.Join(opts.source, descriptionSourcePath)

View File

@ -5,9 +5,16 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/containerd/containerd"
"github.com/docker/cli/internal/containerizedengine" "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 // CleanupEngine ensures the local engine has been removed between testcases
func CleanupEngine(t *testing.T) error { func CleanupEngine(t *testing.T) error {
t.Log("doing engine cleanup") t.Log("doing engine cleanup")
@ -19,7 +26,7 @@ func CleanupEngine(t *testing.T) error {
} }
// See if the engine exists first // See if the engine exists first
engine, err := client.GetEngine(ctx) _, err = client.(containerizedclient).GetEngine(ctx)
if err != nil { if err != nil {
if strings.Contains(err.Error(), "not present") { if strings.Contains(err.Error(), "not present") {
t.Log("engine was not detected, no cleanup to perform") t.Log("engine was not detected, no cleanup to perform")
@ -31,7 +38,7 @@ func CleanupEngine(t *testing.T) error {
return err return err
} }
// TODO Consider nuking the docker dir too so there's no cached content between test cases // 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 { if err != nil {
t.Logf("Failed to remove engine: %s", err) t.Logf("Failed to remove engine: %s", err)
} }

View File

@ -1,7 +1,6 @@
package containerizedengine package containerizedengine
import ( import (
"bytes"
"context" "context"
"syscall" "syscall"
@ -69,10 +68,6 @@ type (
loadProcessFunc func(context.Context, string, cio.Attach) (containerd.Process, error) loadProcessFunc func(context.Context, string, cio.Attach) (containerd.Process, error)
metricsFunc func(context.Context) (*containerdtypes.Metric, error) metricsFunc func(context.Context) (*containerdtypes.Metric, error)
} }
testOutStream struct {
bytes.Buffer
}
) )
func (w *fakeContainerdClient) Containers(ctx context.Context, filters ...string) ([]containerd.Container, error) { 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 return nil, nil
} }
func (o *testOutStream) FD() uintptr {
return 0
}
func (o *testOutStream) IsTerminal() bool {
return false
}

View File

@ -7,6 +7,7 @@ import (
"github.com/containerd/containerd" "github.com/containerd/containerd"
"github.com/containerd/containerd/images" "github.com/containerd/containerd/images"
"github.com/containerd/containerd/remotes/docker" "github.com/containerd/containerd/remotes/docker"
clitypes "github.com/docker/cli/types"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/jsonmessage" "github.com/docker/docker/pkg/jsonmessage"
ocispec "github.com/opencontainers/image-spec/specs-go/v1" ocispec "github.com/opencontainers/image-spec/specs-go/v1"
@ -15,7 +16,7 @@ import (
// NewClient returns a new containerizedengine client // NewClient returns a new containerizedengine client
// This client can be used to manage the lifecycle of // This client can be used to manage the lifecycle of
// dockerd running as a container on containerd. // dockerd running as a container on containerd.
func NewClient(sockPath string) (Client, error) { func NewClient(sockPath string) (clitypes.ContainerizedClient, error) {
if sockPath == "" { if sockPath == "" {
sockPath = containerdSockPath sockPath = containerdSockPath
} }
@ -23,17 +24,17 @@ func NewClient(sockPath string) (Client, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return baseClient{ return &baseClient{
cclient: cclient, cclient: cclient,
}, nil }, nil
} }
// Close will close the underlying clients // Close will close the underlying clients
func (c baseClient) Close() error { func (c *baseClient) Close() error {
return c.cclient.Close() 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) { authConfig *types.AuthConfig) (containerd.Image, error) {
resolver := docker.NewResolver(docker.ResolverOptions{ resolver := docker.NewResolver(docker.ResolverOptions{

View File

@ -1,11 +1,13 @@
package containerizedengine package containerizedengine
import ( import (
"bytes"
"context" "context"
"fmt" "fmt"
"testing" "testing"
"github.com/containerd/containerd" "github.com/containerd/containerd"
"github.com/docker/cli/cli/command"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"gotest.tools/assert" "gotest.tools/assert"
) )
@ -22,7 +24,7 @@ func TestPullWithAuthPullFail(t *testing.T) {
} }
imageName := "testnamegoeshere" 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") assert.ErrorContains(t, err, "pull failure")
} }
@ -38,6 +40,6 @@ func TestPullWithAuthPullPass(t *testing.T) {
} }
imageName := "testnamegoeshere" 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) assert.NilError(t, err)
} }

View File

@ -12,12 +12,15 @@ import (
"github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/runtime/restart" "github.com/containerd/containerd/runtime/restart"
"github.com/docker/cli/internal/pkg/containerized" "github.com/docker/cli/internal/pkg/containerized"
clitypes "github.com/docker/cli/types"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
var _ clitypes.ContainerizedClient = &baseClient{}
// InitEngine is the main entrypoint for `docker engine init` // 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 { authConfig *types.AuthConfig, healthfn func(context.Context) error) error {
ctx = namespaces.WithNamespace(ctx, engineNamespace) 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) // 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) ctx = namespaces.WithNamespace(ctx, engineNamespace)
containers, err := c.cclient.Containers(ctx, "id=="+engineContainerName) containers, err := c.cclient.Containers(ctx, "id=="+engineContainerName)
if err != nil { 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 // 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) ctx := namespaces.WithNamespace(context.Background(), engineNamespace)
image, err := engine.Image(ctx) image, err := engine.Image(ctx)
if err != nil { if err != nil {
@ -94,7 +97,7 @@ var (
) )
// waitForEngine will wait for the engine to start // 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) ticker := time.NewTicker(engineWaitInterval)
defer ticker.Stop() defer ticker.Stop()
defer func() { 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 var ret error
for { for {
select { select {
@ -137,7 +140,15 @@ func (c baseClient) waitForEngineContainer(ctx context.Context, ticker *time.Tic
} }
// RemoveEngine gracefully unwinds the current engine // 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) ctx = namespaces.WithNamespace(ctx, engineNamespace)
// Make sure the container isn't being restarted while we unwind it // 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 // 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) ctx = namespaces.WithNamespace(ctx, engineNamespace)
image, err := c.cclient.GetImage(ctx, imageName) image, err := c.cclient.GetImage(ctx, imageName)
if err != nil { if err != nil {

View File

@ -1,6 +1,7 @@
package containerizedengine package containerizedengine
import ( import (
"bytes"
"context" "context"
"fmt" "fmt"
"strings" "strings"
@ -12,6 +13,8 @@ import (
"github.com/containerd/containerd/cio" "github.com/containerd/containerd/cio"
"github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/oci" "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/docker/docker/api/types"
"github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-spec/specs-go"
"gotest.tools/assert" "gotest.tools/assert"
@ -26,11 +29,11 @@ func healthfnError(ctx context.Context) error {
func TestInitGetEngineFail(t *testing.T) { func TestInitGetEngineFail(t *testing.T) {
ctx := context.Background() ctx := context.Background()
opts := EngineInitOptions{ opts := clitypes.EngineInitOptions{
EngineVersion: "engineversiongoeshere", EngineVersion: "engineversiongoeshere",
RegistryPrefix: "registryprefixgoeshere", RegistryPrefix: "registryprefixgoeshere",
ConfigFile: "/tmp/configfilegoeshere", ConfigFile: "/tmp/configfilegoeshere",
EngineImage: CommunityEngineImage, EngineImage: clitypes.CommunityEngineImage,
} }
container := &fakeContainer{} container := &fakeContainer{}
client := baseClient{ 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) assert.Assert(t, err == ErrEngineAlreadyPresent)
} }
func TestInitCheckImageFail(t *testing.T) { func TestInitCheckImageFail(t *testing.T) {
ctx := context.Background() ctx := context.Background()
opts := EngineInitOptions{ opts := clitypes.EngineInitOptions{
EngineVersion: "engineversiongoeshere", EngineVersion: "engineversiongoeshere",
RegistryPrefix: "registryprefixgoeshere", RegistryPrefix: "registryprefixgoeshere",
ConfigFile: "/tmp/configfilegoeshere", ConfigFile: "/tmp/configfilegoeshere",
EngineImage: CommunityEngineImage, EngineImage: clitypes.CommunityEngineImage,
} }
client := baseClient{ client := baseClient{
cclient: &fakeContainerdClient{ 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, "unable to check for image")
assert.ErrorContains(t, err, "something went wrong") assert.ErrorContains(t, err, "something went wrong")
} }
func TestInitPullFail(t *testing.T) { func TestInitPullFail(t *testing.T) {
ctx := context.Background() ctx := context.Background()
opts := EngineInitOptions{ opts := clitypes.EngineInitOptions{
EngineVersion: "engineversiongoeshere", EngineVersion: "engineversiongoeshere",
RegistryPrefix: "registryprefixgoeshere", RegistryPrefix: "registryprefixgoeshere",
ConfigFile: "/tmp/configfilegoeshere", ConfigFile: "/tmp/configfilegoeshere",
EngineImage: CommunityEngineImage, EngineImage: clitypes.CommunityEngineImage,
} }
client := baseClient{ client := baseClient{
cclient: &fakeContainerdClient{ 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, "unable to pull image")
assert.ErrorContains(t, err, "pull failure") assert.ErrorContains(t, err, "pull failure")
} }
func TestInitStartFail(t *testing.T) { func TestInitStartFail(t *testing.T) {
ctx := context.Background() ctx := context.Background()
opts := EngineInitOptions{ opts := clitypes.EngineInitOptions{
EngineVersion: "engineversiongoeshere", EngineVersion: "engineversiongoeshere",
RegistryPrefix: "registryprefixgoeshere", RegistryPrefix: "registryprefixgoeshere",
ConfigFile: "/tmp/configfilegoeshere", ConfigFile: "/tmp/configfilegoeshere",
EngineImage: CommunityEngineImage, EngineImage: clitypes.CommunityEngineImage,
} }
client := baseClient{ client := baseClient{
cclient: &fakeContainerdClient{ 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") 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") 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") 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) 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, "failed to remove existing engine")
assert.ErrorContains(t, err, "delete failure") 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") 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") 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") 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") 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) 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) assert.Assert(t, err == ErrEngineShutdownTimeout)
} }

View File

@ -3,24 +3,14 @@ package containerizedengine
import ( import (
"context" "context"
"errors" "errors"
"io"
"github.com/containerd/containerd" "github.com/containerd/containerd"
"github.com/containerd/containerd/containers" "github.com/containerd/containerd/containers"
"github.com/containerd/containerd/content" "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" specs "github.com/opencontainers/runtime-spec/specs-go"
) )
const ( 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" containerdSockPath = "/run/containerd/containerd.sock"
engineContainerName = "dockerd" engineContainerName = "dockerd"
engineNamespace = "docker" 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 { type baseClient struct {
cclient containerdClient 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 // containerdClient abstracts the containerd client to aid in testability
type containerdClient interface { type containerdClient interface {
Containers(ctx context.Context, filters ...string) ([]containerd.Container, error) Containers(ctx context.Context, filters ...string) ([]containerd.Container, error)
@ -128,32 +83,3 @@ type containerdClient interface {
ContentStore() content.Store ContentStore() content.Store
ContainerService() containers.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
}

View File

@ -9,16 +9,17 @@ import (
"github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/namespaces"
"github.com/docker/cli/internal/pkg/containerized" "github.com/docker/cli/internal/pkg/containerized"
clitypes "github.com/docker/cli/types"
"github.com/docker/distribution/reference" "github.com/docker/distribution/reference"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
// GetCurrentEngineVersion determines the current type of engine (image) and version // 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) ctx = namespaces.WithNamespace(ctx, engineNamespace)
ret := EngineInitOptions{} ret := clitypes.EngineInitOptions{}
currentEngine := CommunityEngineImage currentEngine := clitypes.CommunityEngineImage
engine, err := c.GetEngine(ctx) engine, err := c.GetEngine(ctx)
if err != nil { if err != nil {
if err == ErrEngineNotPresent { 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) return ret, errors.Wrapf(err, "failed to parse image name: %s", imageName)
} }
if strings.Contains(distributionRef.Name(), EnterpriseEngineImage) { if strings.Contains(distributionRef.Name(), clitypes.EnterpriseEngineImage) {
currentEngine = EnterpriseEngineImage currentEngine = clitypes.EnterpriseEngineImage
} }
taggedRef, ok := distributionRef.(reference.NamedTagged) taggedRef, ok := distributionRef.(reference.NamedTagged)
if !ok { 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 // 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 { authConfig *types.AuthConfig, healthfn func(context.Context) error) error {
// set the proxy scope to "ee" for activate flows // set the proxy scope to "ee" for activate flows
opts.scope = "ee" opts.Scope = "ee"
ctx = namespaces.WithNamespace(ctx, engineNamespace) ctx = namespaces.WithNamespace(ctx, engineNamespace)
@ -64,7 +65,7 @@ func (c baseClient) ActivateEngine(ctx context.Context, opts EngineInitOptions,
return err return err
} }
opts.EngineVersion = currentOpts.EngineVersion 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 // This is a "no-op" activation so the only change would be the license - don't update the engine itself
return nil return nil
} }
@ -73,7 +74,7 @@ func (c baseClient) ActivateEngine(ctx context.Context, opts EngineInitOptions,
} }
// DoUpdate performs the underlying engine update // 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 { authConfig *types.AuthConfig, healthfn func(context.Context) error) error {
ctx = namespaces.WithNamespace(ctx, engineNamespace) ctx = namespaces.WithNamespace(ctx, engineNamespace)
@ -117,13 +118,13 @@ func (c baseClient) DoUpdate(ctx context.Context, opts EngineInitOptions, out Ou
defer cancel() defer cancel()
return c.waitForEngine(ctx, out, healthfn) return c.waitForEngine(ctx, out, healthfn)
}) })
if err == nil && opts.scope != "" { if err == nil && opts.Scope != "" {
var labels map[string]string var labels map[string]string
labels, err = engine.Labels(ctx) labels, err = engine.Labels(ctx)
if err != nil { if err != nil {
return err return err
} }
labels[proxyLabel] = opts.scope labels[proxyLabel] = opts.Scope
_, err = engine.SetLabels(ctx, labels) _, err = engine.SetLabels(ctx, labels)
} }
return err return err

View File

@ -1,6 +1,7 @@
package containerizedengine package containerizedengine
import ( import (
"bytes"
"context" "context"
"fmt" "fmt"
"testing" "testing"
@ -8,6 +9,8 @@ import (
"github.com/containerd/containerd" "github.com/containerd/containerd"
"github.com/containerd/containerd/cio" "github.com/containerd/containerd/cio"
"github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/errdefs"
"github.com/docker/cli/cli/command"
clitypes "github.com/docker/cli/types"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"gotest.tools/assert" "gotest.tools/assert"
) )
@ -16,7 +19,7 @@ func TestGetCurrentEngineVersionHappy(t *testing.T) {
ctx := context.Background() ctx := context.Background()
image := &fakeImage{ image := &fakeImage{
nameFunc: func() string { nameFunc: func() string {
return "acme.com/dockermirror/" + CommunityEngineImage + ":engineversion" return "acme.com/dockermirror/" + clitypes.CommunityEngineImage + ":engineversion"
}, },
} }
container := &fakeContainer{ container := &fakeContainer{
@ -34,7 +37,7 @@ func TestGetCurrentEngineVersionHappy(t *testing.T) {
opts, err := client.GetCurrentEngineVersion(ctx) opts, err := client.GetCurrentEngineVersion(ctx)
assert.NilError(t, err) 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.RegistryPrefix, "acme.com/dockermirror")
assert.Equal(t, opts.EngineVersion, "engineversion") assert.Equal(t, opts.EngineVersion, "engineversion")
} }
@ -43,7 +46,7 @@ func TestGetCurrentEngineVersionEnterpriseHappy(t *testing.T) {
ctx := context.Background() ctx := context.Background()
image := &fakeImage{ image := &fakeImage{
nameFunc: func() string { nameFunc: func() string {
return "docker.io/docker/" + EnterpriseEngineImage + ":engineversion" return "docker.io/docker/" + clitypes.EnterpriseEngineImage + ":engineversion"
}, },
} }
container := &fakeContainer{ container := &fakeContainer{
@ -61,7 +64,7 @@ func TestGetCurrentEngineVersionEnterpriseHappy(t *testing.T) {
opts, err := client.GetCurrentEngineVersion(ctx) opts, err := client.GetCurrentEngineVersion(ctx)
assert.NilError(t, err) 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.EngineVersion, "engineversion")
assert.Equal(t, opts.RegistryPrefix, "docker.io/docker") assert.Equal(t, opts.RegistryPrefix, "docker.io/docker")
} }
@ -147,14 +150,14 @@ func TestActivateNoEngine(t *testing.T) {
}, },
}, },
} }
opts := EngineInitOptions{ opts := clitypes.EngineInitOptions{
EngineVersion: "engineversiongoeshere", EngineVersion: "engineversiongoeshere",
RegistryPrefix: "registryprefixgoeshere", RegistryPrefix: "registryprefixgoeshere",
ConfigFile: "/tmp/configfilegoeshere", 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") assert.ErrorContains(t, err, "unable to find")
} }
@ -163,7 +166,7 @@ func TestActivateNoChange(t *testing.T) {
registryPrefix := "registryprefixgoeshere" registryPrefix := "registryprefixgoeshere"
image := &fakeImage{ image := &fakeImage{
nameFunc: func() string { nameFunc: func() string {
return registryPrefix + "/" + EnterpriseEngineImage + ":engineversion" return registryPrefix + "/" + clitypes.EnterpriseEngineImage + ":engineversion"
}, },
} }
container := &fakeContainer{ container := &fakeContainer{
@ -184,14 +187,14 @@ func TestActivateNoChange(t *testing.T) {
}, },
}, },
} }
opts := EngineInitOptions{ opts := clitypes.EngineInitOptions{
EngineVersion: "engineversiongoeshere", EngineVersion: "engineversiongoeshere",
RegistryPrefix: "registryprefixgoeshere", RegistryPrefix: "registryprefixgoeshere",
ConfigFile: "/tmp/configfilegoeshere", 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) assert.NilError(t, err)
} }
@ -219,34 +222,34 @@ func TestActivateDoUpdateFail(t *testing.T) {
}, },
}, },
} }
opts := EngineInitOptions{ opts := clitypes.EngineInitOptions{
EngineVersion: "engineversiongoeshere", EngineVersion: "engineversiongoeshere",
RegistryPrefix: "registryprefixgoeshere", RegistryPrefix: "registryprefixgoeshere",
ConfigFile: "/tmp/configfilegoeshere", 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, "check for image")
assert.ErrorContains(t, err, "something went wrong") assert.ErrorContains(t, err, "something went wrong")
} }
func TestDoUpdateNoVersion(t *testing.T) { func TestDoUpdateNoVersion(t *testing.T) {
ctx := context.Background() ctx := context.Background()
opts := EngineInitOptions{ opts := clitypes.EngineInitOptions{
EngineVersion: "", EngineVersion: "",
RegistryPrefix: "registryprefixgoeshere", RegistryPrefix: "registryprefixgoeshere",
ConfigFile: "/tmp/configfilegoeshere", ConfigFile: "/tmp/configfilegoeshere",
EngineImage: EnterpriseEngineImage, EngineImage: clitypes.EnterpriseEngineImage,
} }
client := baseClient{} 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") assert.ErrorContains(t, err, "please pick the version you")
} }
func TestDoUpdateImageMiscError(t *testing.T) { func TestDoUpdateImageMiscError(t *testing.T) {
ctx := context.Background() ctx := context.Background()
opts := EngineInitOptions{ opts := clitypes.EngineInitOptions{
EngineVersion: "engineversiongoeshere", EngineVersion: "engineversiongoeshere",
RegistryPrefix: "registryprefixgoeshere", RegistryPrefix: "registryprefixgoeshere",
ConfigFile: "/tmp/configfilegoeshere", 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, "check for image")
assert.ErrorContains(t, err, "something went wrong") assert.ErrorContains(t, err, "something went wrong")
} }
func TestDoUpdatePullFail(t *testing.T) { func TestDoUpdatePullFail(t *testing.T) {
ctx := context.Background() ctx := context.Background()
opts := EngineInitOptions{ opts := clitypes.EngineInitOptions{
EngineVersion: "engineversiongoeshere", EngineVersion: "engineversiongoeshere",
RegistryPrefix: "registryprefixgoeshere", RegistryPrefix: "registryprefixgoeshere",
ConfigFile: "/tmp/configfilegoeshere", 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, "unable to pull")
assert.ErrorContains(t, err, "pull failure") assert.ErrorContains(t, err, "pull failure")
} }
func TestDoUpdateEngineMissing(t *testing.T) { func TestDoUpdateEngineMissing(t *testing.T) {
ctx := context.Background() ctx := context.Background()
opts := EngineInitOptions{ opts := clitypes.EngineInitOptions{
EngineVersion: "engineversiongoeshere", EngineVersion: "engineversiongoeshere",
RegistryPrefix: "registryprefixgoeshere", RegistryPrefix: "registryprefixgoeshere",
ConfigFile: "/tmp/configfilegoeshere", 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") assert.ErrorContains(t, err, "unable to find existing engine")
} }

View File

@ -5,6 +5,7 @@ import (
"sort" "sort"
registryclient "github.com/docker/cli/cli/registry/client" registryclient "github.com/docker/cli/cli/registry/client"
clitypes "github.com/docker/cli/types"
"github.com/docker/distribution/reference" "github.com/docker/distribution/reference"
ver "github.com/hashicorp/go-version" ver "github.com/hashicorp/go-version"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -12,29 +13,29 @@ import (
) )
// GetEngineVersions reports the versions of the engine that are available // 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) imageRef, err := reference.ParseNormalizedNamed(imageName)
if err != nil { if err != nil {
return AvailableVersions{}, err return clitypes.AvailableVersions{}, err
} }
tags, err := registryClient.GetTags(ctx, imageRef) tags, err := registryClient.GetTags(ctx, imageRef)
if err != nil { if err != nil {
return AvailableVersions{}, err return clitypes.AvailableVersions{}, err
} }
return parseTags(tags, currentVersion) return parseTags(tags, currentVersion)
} }
func parseTags(tags []string, currentVersion string) (AvailableVersions, error) { func parseTags(tags []string, currentVersion string) (clitypes.AvailableVersions, error) {
var ret AvailableVersions var ret clitypes.AvailableVersions
currentVer, err := ver.NewVersion(currentVersion) currentVer, err := ver.NewVersion(currentVersion)
if err != nil { if err != nil {
return ret, errors.Wrapf(err, "failed to parse existing version %s", currentVersion) return ret, errors.Wrapf(err, "failed to parse existing version %s", currentVersion)
} }
downgrades := []DockerVersion{} downgrades := []clitypes.DockerVersion{}
patches := []DockerVersion{} patches := []clitypes.DockerVersion{}
upgrades := []DockerVersion{} upgrades := []clitypes.DockerVersion{}
currentSegments := currentVer.Segments() currentSegments := currentVer.Segments()
for _, tag := range tags { for _, tag := range tags {
tmp, err := ver.NewVersion(tag) 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) logrus.Debugf("Unable to parse %s: %s", tag, err)
continue continue
} }
testVersion := DockerVersion{Version: *tmp, Tag: tag} testVersion := clitypes.DockerVersion{Version: *tmp, Tag: tag}
if testVersion.LessThan(currentVer) { if testVersion.LessThan(currentVer) {
downgrades = append(downgrades, testVersion) downgrades = append(downgrades, testVersion)
continue continue

View File

@ -12,7 +12,7 @@ import (
manifeststore "github.com/docker/cli/cli/manifest/store" manifeststore "github.com/docker/cli/cli/manifest/store"
registryclient "github.com/docker/cli/cli/registry/client" registryclient "github.com/docker/cli/cli/registry/client"
"github.com/docker/cli/cli/trust" "github.com/docker/cli/cli/trust"
"github.com/docker/cli/internal/containerizedengine" clitypes "github.com/docker/cli/types"
"github.com/docker/docker/client" "github.com/docker/docker/client"
notaryclient "github.com/theupdateframework/notary/client" notaryclient "github.com/theupdateframework/notary/client"
) )
@ -20,7 +20,7 @@ import (
// NotaryClientFuncType defines a function that returns a fake notary client // NotaryClientFuncType defines a function that returns a fake notary client
type NotaryClientFuncType func(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (notaryclient.Repository, error) type NotaryClientFuncType func(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (notaryclient.Repository, error)
type clientInfoFuncType func() command.ClientInfo type clientInfoFuncType func() command.ClientInfo
type containerizedEngineFuncType func(string) (containerizedengine.Client, error) type containerizedEngineFuncType func(string) (clitypes.ContainerizedClient, error)
// FakeCli emulates the default DockerCli // FakeCli emulates the default DockerCli
type FakeCli struct { type FakeCli struct {
@ -172,7 +172,7 @@ func EnableContentTrust(c *FakeCli) {
} }
// NewContainerizedEngineClient returns a containerized engine client // 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 { if c.containerizedEngineClientFunc != nil {
return c.containerizedEngineClientFunc(sockPath) return c.containerizedEngineClientFunc(sockPath)
} }

View File

@ -25,7 +25,7 @@ func generateManPages(opts *options) error {
} }
stdin, stdout, stderr := term.StdStreams() 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"} cmd := &cobra.Command{Use: "docker"}
commands.AddCommands(cmd, dockerCli) commands.AddCommands(cmd, dockerCli)
source := filepath.Join(opts.source, descriptionSourcePath) source := filepath.Join(opts.source, descriptionSourcePath)

81
types/types.go Normal file
View File

@ -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
}