Merge pull request #6571 from thaJeztah/bump_modules
vendor: github.com/moby/moby/api, moby/moby/client master
This commit is contained in:
@ -8,6 +8,7 @@ import (
|
||||
"github.com/docker/cli/cli-plugins/metadata"
|
||||
"github.com/docker/cli/cli-plugins/plugin"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/moby/moby/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -25,7 +26,7 @@ func main() {
|
||||
Short: "Print the API version of the server",
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
apiClient := dockerCLI.Client()
|
||||
ping, err := apiClient.Ping(context.Background())
|
||||
ping, err := apiClient.Ping(context.Background(), client.PingOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -25,7 +25,6 @@ import (
|
||||
"github.com/docker/cli/cli/version"
|
||||
dopts "github.com/docker/cli/opts"
|
||||
"github.com/moby/moby/api/types/build"
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -378,7 +377,7 @@ func (cli *DockerCli) initializeFromClient() {
|
||||
ctx, cancel := context.WithTimeout(cli.baseCtx, cli.getInitTimeout())
|
||||
defer cancel()
|
||||
|
||||
ping, err := cli.client.Ping(ctx)
|
||||
ping, err := cli.client.Ping(ctx, client.PingOptions{})
|
||||
if err != nil {
|
||||
// Default to true if we fail to connect to daemon
|
||||
cli.serverInfo = ServerInfo{HasExperimental: true}
|
||||
@ -564,7 +563,7 @@ type ServerInfo struct {
|
||||
// in the ping response, or if an error occurred, in which case the client
|
||||
// should use other ways to get the current swarm status, such as the /swarm
|
||||
// endpoint.
|
||||
SwarmStatus *swarm.Status
|
||||
SwarmStatus *client.SwarmStatus
|
||||
}
|
||||
|
||||
// NewDockerCli returns a DockerCli instance with all operators applied on it.
|
||||
|
||||
@ -20,7 +20,6 @@ import (
|
||||
"github.com/docker/cli/cli/config/configfile"
|
||||
"github.com/docker/cli/cli/context/store"
|
||||
"github.com/docker/cli/cli/flags"
|
||||
"github.com/moby/moby/api/types"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
@ -80,7 +79,7 @@ func TestNewAPIClientFromFlagsWithCustomHeaders(t *testing.T) {
|
||||
"My-Header": "Custom-Value",
|
||||
"User-Agent": UserAgent(),
|
||||
}
|
||||
_, err = apiClient.Ping(context.Background())
|
||||
_, err = apiClient.Ping(context.TODO(), client.PingOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.DeepEqual(t, received, expectedHeaders)
|
||||
}
|
||||
@ -115,7 +114,7 @@ func TestNewAPIClientFromFlagsWithCustomHeadersFromEnv(t *testing.T) {
|
||||
"Four": []string{"four-value-override"},
|
||||
"User-Agent": []string{UserAgent()},
|
||||
}
|
||||
_, err = apiClient.Ping(context.Background())
|
||||
_, err = apiClient.Ping(context.TODO(), client.PingOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.DeepEqual(t, received, expectedHeaders)
|
||||
}
|
||||
@ -135,12 +134,12 @@ func TestNewAPIClientFromFlagsWithAPIVersionFromEnv(t *testing.T) {
|
||||
|
||||
type fakeClient struct {
|
||||
client.Client
|
||||
pingFunc func() (types.Ping, error)
|
||||
pingFunc func() (client.PingResult, error)
|
||||
version string
|
||||
negotiated bool
|
||||
}
|
||||
|
||||
func (c *fakeClient) Ping(_ context.Context) (types.Ping, error) {
|
||||
func (c *fakeClient) Ping(_ context.Context, _ client.PingOptions) (client.PingResult, error) {
|
||||
return c.pingFunc()
|
||||
}
|
||||
|
||||
@ -148,7 +147,7 @@ func (c *fakeClient) ClientVersion() string {
|
||||
return c.version
|
||||
}
|
||||
|
||||
func (c *fakeClient) NegotiateAPIVersionPing(types.Ping) {
|
||||
func (c *fakeClient) NegotiateAPIVersionPing(client.PingResult) {
|
||||
c.negotiated = true
|
||||
}
|
||||
|
||||
@ -157,29 +156,29 @@ func TestInitializeFromClient(t *testing.T) {
|
||||
|
||||
testcases := []struct {
|
||||
doc string
|
||||
pingFunc func() (types.Ping, error)
|
||||
pingFunc func() (client.PingResult, error)
|
||||
expectedServer ServerInfo
|
||||
negotiated bool
|
||||
}{
|
||||
{
|
||||
doc: "successful ping",
|
||||
pingFunc: func() (types.Ping, error) {
|
||||
return types.Ping{Experimental: true, OSType: "linux", APIVersion: "v1.44"}, nil
|
||||
pingFunc: func() (client.PingResult, error) {
|
||||
return client.PingResult{Experimental: true, OSType: "linux", APIVersion: "v1.44"}, nil
|
||||
},
|
||||
expectedServer: ServerInfo{HasExperimental: true, OSType: "linux"},
|
||||
negotiated: true,
|
||||
},
|
||||
{
|
||||
doc: "failed ping, no API version",
|
||||
pingFunc: func() (types.Ping, error) {
|
||||
return types.Ping{}, errors.New("failed")
|
||||
pingFunc: func() (client.PingResult, error) {
|
||||
return client.PingResult{}, errors.New("failed")
|
||||
},
|
||||
expectedServer: ServerInfo{HasExperimental: true},
|
||||
},
|
||||
{
|
||||
doc: "failed ping, with API version",
|
||||
pingFunc: func() (types.Ping, error) {
|
||||
return types.Ping{APIVersion: "v1.44"}, errors.New("failed")
|
||||
pingFunc: func() (client.PingResult, error) {
|
||||
return client.PingResult{APIVersion: "v1.44"}, errors.New("failed")
|
||||
},
|
||||
expectedServer: ServerInfo{HasExperimental: true},
|
||||
negotiated: true,
|
||||
@ -211,7 +210,7 @@ func TestInitializeFromClientHangs(t *testing.T) {
|
||||
assert.NilError(t, err)
|
||||
|
||||
receiveReqCh := make(chan bool)
|
||||
timeoutCtx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
timeoutCtx, cancel := context.WithTimeout(context.TODO(), time.Second)
|
||||
defer cancel()
|
||||
|
||||
// Simulate a server that hangs on connections.
|
||||
@ -385,7 +384,7 @@ func TestNewDockerCliWithCustomUserAgent(t *testing.T) {
|
||||
cli.options = opts
|
||||
cli.configFile = &configfile.ConfigFile{}
|
||||
|
||||
_, err = cli.Client().Ping(context.Background())
|
||||
_, err = cli.Client().Ping(context.TODO(), client.PingOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.DeepEqual(t, received, "fake-agent/0.0.1")
|
||||
}
|
||||
|
||||
@ -27,12 +27,12 @@ func ImageNames(dockerCLI APIClientProvider, limit int) cobra.CompletionFunc {
|
||||
if limit > 0 && len(args) >= limit {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
list, err := dockerCLI.Client().ImageList(cmd.Context(), client.ImageListOptions{})
|
||||
res, err := dockerCLI.Client().ImageList(cmd.Context(), client.ImageListOptions{})
|
||||
if err != nil {
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
var names []string
|
||||
for _, img := range list {
|
||||
for _, img := range res.Items {
|
||||
names = append(names, img.RepoTags...)
|
||||
}
|
||||
return names, cobra.ShellCompDirectiveNoFileComp
|
||||
@ -47,13 +47,13 @@ func ImageNamesWithBase(dockerCLI APIClientProvider, limit int) cobra.Completion
|
||||
if limit > 0 && len(args) >= limit {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
list, err := dockerCLI.Client().ImageList(cmd.Context(), client.ImageListOptions{})
|
||||
res, err := dockerCLI.Client().ImageList(cmd.Context(), client.ImageListOptions{})
|
||||
if err != nil {
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
var names []string
|
||||
baseNameCounts := make(map[string]int)
|
||||
for _, img := range list {
|
||||
for _, img := range res.Items {
|
||||
names = append(names, img.RepoTags...)
|
||||
for _, tag := range img.RepoTags {
|
||||
ref, err := reference.ParseNormalizedNamed(tag)
|
||||
@ -110,12 +110,12 @@ func ContainerNames(dockerCLI APIClientProvider, all bool, filters ...func(conta
|
||||
// VolumeNames offers completion for volumes
|
||||
func VolumeNames(dockerCLI APIClientProvider) cobra.CompletionFunc {
|
||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
list, err := dockerCLI.Client().VolumeList(cmd.Context(), client.VolumeListOptions{})
|
||||
res, err := dockerCLI.Client().VolumeList(cmd.Context(), client.VolumeListOptions{})
|
||||
if err != nil {
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
var names []string
|
||||
for _, vol := range list.Volumes {
|
||||
for _, vol := range res.Items.Volumes {
|
||||
names = append(names, vol.Name)
|
||||
}
|
||||
return names, cobra.ShellCompDirectiveNoFileComp
|
||||
@ -125,12 +125,12 @@ func VolumeNames(dockerCLI APIClientProvider) cobra.CompletionFunc {
|
||||
// NetworkNames offers completion for networks
|
||||
func NetworkNames(dockerCLI APIClientProvider) cobra.CompletionFunc {
|
||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
list, err := dockerCLI.Client().NetworkList(cmd.Context(), client.NetworkListOptions{})
|
||||
res, err := dockerCLI.Client().NetworkList(cmd.Context(), client.NetworkListOptions{})
|
||||
if err != nil {
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
var names []string
|
||||
for _, nw := range list {
|
||||
for _, nw := range res.Items {
|
||||
names = append(names, nw.Name)
|
||||
}
|
||||
return names, cobra.ShellCompDirectiveNoFileComp
|
||||
|
||||
@ -28,38 +28,38 @@ func (c fakeCLI) Client() client.APIClient {
|
||||
|
||||
type fakeClient struct {
|
||||
client.Client
|
||||
containerListFunc func(options client.ContainerListOptions) ([]container.Summary, error)
|
||||
imageListFunc func(options client.ImageListOptions) ([]image.Summary, error)
|
||||
networkListFunc func(ctx context.Context, options client.NetworkListOptions) ([]network.Summary, error)
|
||||
volumeListFunc func(filter client.Filters) (volume.ListResponse, error)
|
||||
containerListFunc func(context.Context, client.ContainerListOptions) ([]container.Summary, error)
|
||||
imageListFunc func(context.Context, client.ImageListOptions) (client.ImageListResult, error)
|
||||
networkListFunc func(context.Context, client.NetworkListOptions) (client.NetworkListResult, error)
|
||||
volumeListFunc func(context.Context, client.VolumeListOptions) (client.VolumeListResult, error)
|
||||
}
|
||||
|
||||
func (c *fakeClient) ContainerList(_ context.Context, options client.ContainerListOptions) ([]container.Summary, error) {
|
||||
func (c *fakeClient) ContainerList(ctx context.Context, options client.ContainerListOptions) ([]container.Summary, error) {
|
||||
if c.containerListFunc != nil {
|
||||
return c.containerListFunc(options)
|
||||
return c.containerListFunc(ctx, options)
|
||||
}
|
||||
return []container.Summary{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) ImageList(_ context.Context, options client.ImageListOptions) ([]image.Summary, error) {
|
||||
func (c *fakeClient) ImageList(ctx context.Context, options client.ImageListOptions) (client.ImageListResult, error) {
|
||||
if c.imageListFunc != nil {
|
||||
return c.imageListFunc(options)
|
||||
return c.imageListFunc(ctx, options)
|
||||
}
|
||||
return []image.Summary{}, nil
|
||||
return client.ImageListResult{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) NetworkList(ctx context.Context, options client.NetworkListOptions) ([]network.Summary, error) {
|
||||
func (c *fakeClient) NetworkList(ctx context.Context, options client.NetworkListOptions) (client.NetworkListResult, error) {
|
||||
if c.networkListFunc != nil {
|
||||
return c.networkListFunc(ctx, options)
|
||||
}
|
||||
return []network.Summary{}, nil
|
||||
return client.NetworkListResult{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) VolumeList(_ context.Context, options client.VolumeListOptions) (volume.ListResponse, error) {
|
||||
func (c *fakeClient) VolumeList(ctx context.Context, options client.VolumeListOptions) (client.VolumeListResult, error) {
|
||||
if c.volumeListFunc != nil {
|
||||
return c.volumeListFunc(options.Filters)
|
||||
return c.volumeListFunc(ctx, options)
|
||||
}
|
||||
return volume.ListResponse{}, nil
|
||||
return client.VolumeListResult{}, nil
|
||||
}
|
||||
|
||||
func TestCompleteContainerNames(t *testing.T) {
|
||||
@ -153,7 +153,7 @@ func TestCompleteContainerNames(t *testing.T) {
|
||||
t.Setenv("DOCKER_COMPLETION_SHOW_CONTAINER_IDS", "yes")
|
||||
}
|
||||
comp := ContainerNames(fakeCLI{&fakeClient{
|
||||
containerListFunc: func(opts client.ContainerListOptions) ([]container.Summary, error) {
|
||||
containerListFunc: func(_ context.Context, opts client.ContainerListOptions) ([]container.Summary, error) {
|
||||
assert.Check(t, is.DeepEqual(opts, tc.expOpts))
|
||||
if tc.expDirective == cobra.ShellCompDirectiveError {
|
||||
return nil, errors.New("some error occurred")
|
||||
@ -226,11 +226,11 @@ func TestCompleteImageNames(t *testing.T) {
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.doc, func(t *testing.T) {
|
||||
comp := ImageNames(fakeCLI{&fakeClient{
|
||||
imageListFunc: func(options client.ImageListOptions) ([]image.Summary, error) {
|
||||
imageListFunc: func(context.Context, client.ImageListOptions) (client.ImageListResult, error) {
|
||||
if tc.expDirective == cobra.ShellCompDirectiveError {
|
||||
return nil, errors.New("some error occurred")
|
||||
return client.ImageListResult{}, errors.New("some error occurred")
|
||||
}
|
||||
return tc.images, nil
|
||||
return client.ImageListResult{Items: tc.images}, nil
|
||||
},
|
||||
}}, -1)
|
||||
|
||||
@ -286,11 +286,11 @@ func TestCompleteNetworkNames(t *testing.T) {
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.doc, func(t *testing.T) {
|
||||
comp := NetworkNames(fakeCLI{&fakeClient{
|
||||
networkListFunc: func(ctx context.Context, options client.NetworkListOptions) ([]network.Summary, error) {
|
||||
networkListFunc: func(context.Context, client.NetworkListOptions) (client.NetworkListResult, error) {
|
||||
if tc.expDirective == cobra.ShellCompDirectiveError {
|
||||
return nil, errors.New("some error occurred")
|
||||
return client.NetworkListResult{}, errors.New("some error occurred")
|
||||
}
|
||||
return tc.networks, nil
|
||||
return client.NetworkListResult{Items: tc.networks}, nil
|
||||
},
|
||||
}})
|
||||
|
||||
@ -337,11 +337,11 @@ func TestCompleteVolumeNames(t *testing.T) {
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.doc, func(t *testing.T) {
|
||||
comp := VolumeNames(fakeCLI{&fakeClient{
|
||||
volumeListFunc: func(filter client.Filters) (volume.ListResponse, error) {
|
||||
volumeListFunc: func(context.Context, client.VolumeListOptions) (client.VolumeListResult, error) {
|
||||
if tc.expDirective == cobra.ShellCompDirectiveError {
|
||||
return volume.ListResponse{}, errors.New("some error occurred")
|
||||
return client.VolumeListResult{}, errors.New("some error occurred")
|
||||
}
|
||||
return volume.ListResponse{Volumes: tc.volumes}, nil
|
||||
return client.VolumeListResult{Items: volume.ListResponse{Volumes: tc.volumes}}, nil
|
||||
},
|
||||
}})
|
||||
|
||||
|
||||
@ -3,42 +3,41 @@ package config
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/client"
|
||||
)
|
||||
|
||||
type fakeClient struct {
|
||||
client.Client
|
||||
configCreateFunc func(context.Context, swarm.ConfigSpec) (swarm.ConfigCreateResponse, error)
|
||||
configInspectFunc func(context.Context, string) (swarm.Config, []byte, error)
|
||||
configListFunc func(context.Context, client.ConfigListOptions) ([]swarm.Config, error)
|
||||
configRemoveFunc func(string) error
|
||||
configCreateFunc func(context.Context, client.ConfigCreateOptions) (client.ConfigCreateResult, error)
|
||||
configInspectFunc func(context.Context, string, client.ConfigInspectOptions) (client.ConfigInspectResult, error)
|
||||
configListFunc func(context.Context, client.ConfigListOptions) (client.ConfigListResult, error)
|
||||
configRemoveFunc func(context.Context, string, client.ConfigRemoveOptions) (client.ConfigRemoveResult, error)
|
||||
}
|
||||
|
||||
func (c *fakeClient) ConfigCreate(ctx context.Context, spec swarm.ConfigSpec) (swarm.ConfigCreateResponse, error) {
|
||||
func (c *fakeClient) ConfigCreate(ctx context.Context, options client.ConfigCreateOptions) (client.ConfigCreateResult, error) {
|
||||
if c.configCreateFunc != nil {
|
||||
return c.configCreateFunc(ctx, spec)
|
||||
return c.configCreateFunc(ctx, options)
|
||||
}
|
||||
return swarm.ConfigCreateResponse{}, nil
|
||||
return client.ConfigCreateResult{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) ConfigInspectWithRaw(ctx context.Context, id string) (swarm.Config, []byte, error) {
|
||||
func (c *fakeClient) ConfigInspect(ctx context.Context, id string, options client.ConfigInspectOptions) (client.ConfigInspectResult, error) {
|
||||
if c.configInspectFunc != nil {
|
||||
return c.configInspectFunc(ctx, id)
|
||||
return c.configInspectFunc(ctx, id, options)
|
||||
}
|
||||
return swarm.Config{}, nil, nil
|
||||
return client.ConfigInspectResult{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) ConfigList(ctx context.Context, options client.ConfigListOptions) ([]swarm.Config, error) {
|
||||
func (c *fakeClient) ConfigList(ctx context.Context, options client.ConfigListOptions) (client.ConfigListResult, error) {
|
||||
if c.configListFunc != nil {
|
||||
return c.configListFunc(ctx, options)
|
||||
}
|
||||
return []swarm.Config{}, nil
|
||||
return client.ConfigListResult{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) ConfigRemove(_ context.Context, name string) error {
|
||||
func (c *fakeClient) ConfigRemove(ctx context.Context, name string, options client.ConfigRemoveOptions) (client.ConfigRemoveResult, error) {
|
||||
if c.configRemoveFunc != nil {
|
||||
return c.configRemoveFunc(name)
|
||||
return c.configRemoveFunc(ctx, name, options)
|
||||
}
|
||||
return nil
|
||||
return client.ConfigRemoveResult{}, nil
|
||||
}
|
||||
|
||||
@ -38,12 +38,12 @@ func newConfigCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
// completeNames offers completion for swarm configs
|
||||
func completeNames(dockerCLI completion.APIClientProvider) cobra.CompletionFunc {
|
||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
list, err := dockerCLI.Client().ConfigList(cmd.Context(), client.ConfigListOptions{})
|
||||
res, err := dockerCLI.Client().ConfigList(cmd.Context(), client.ConfigListOptions{})
|
||||
if err != nil {
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
var names []string
|
||||
for _, config := range list {
|
||||
for _, config := range res.Items {
|
||||
names = append(names, config.ID)
|
||||
}
|
||||
return names, cobra.ShellCompDirectiveNoFileComp
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/opts"
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/client"
|
||||
"github.com/moby/sys/sequential"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -84,7 +85,9 @@ func runCreate(ctx context.Context, dockerCLI command.Cli, options createOptions
|
||||
Name: options.templateDriver,
|
||||
}
|
||||
}
|
||||
r, err := apiClient.ConfigCreate(ctx, spec)
|
||||
r, err := apiClient.ConfigCreate(ctx, client.ConfigCreateOptions{
|
||||
Spec: spec,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ import (
|
||||
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
"gotest.tools/v3/golden"
|
||||
@ -23,7 +24,7 @@ const configDataFile = "config-create-with-name.golden"
|
||||
func TestConfigCreateErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
configCreateFunc func(context.Context, swarm.ConfigSpec) (swarm.ConfigCreateResponse, error)
|
||||
configCreateFunc func(context.Context, client.ConfigCreateOptions) (client.ConfigCreateResult, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
@ -36,8 +37,8 @@ func TestConfigCreateErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
args: []string{"name", filepath.Join("testdata", configDataFile)},
|
||||
configCreateFunc: func(_ context.Context, configSpec swarm.ConfigSpec) (swarm.ConfigCreateResponse, error) {
|
||||
return swarm.ConfigCreateResponse{}, errors.New("error creating config")
|
||||
configCreateFunc: func(_ context.Context, options client.ConfigCreateOptions) (client.ConfigCreateResult, error) {
|
||||
return client.ConfigCreateResult{}, errors.New("error creating config")
|
||||
},
|
||||
expectedError: "error creating config",
|
||||
},
|
||||
@ -61,15 +62,15 @@ func TestConfigCreateWithName(t *testing.T) {
|
||||
const name = "config-with-name"
|
||||
var actual []byte
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
configCreateFunc: func(_ context.Context, spec swarm.ConfigSpec) (swarm.ConfigCreateResponse, error) {
|
||||
if spec.Name != name {
|
||||
return swarm.ConfigCreateResponse{}, fmt.Errorf("expected name %q, got %q", name, spec.Name)
|
||||
configCreateFunc: func(_ context.Context, options client.ConfigCreateOptions) (client.ConfigCreateResult, error) {
|
||||
if options.Spec.Name != name {
|
||||
return client.ConfigCreateResult{}, fmt.Errorf("expected name %q, got %q", name, options.Spec.Name)
|
||||
}
|
||||
|
||||
actual = spec.Data
|
||||
actual = options.Spec.Data
|
||||
|
||||
return swarm.ConfigCreateResponse{
|
||||
ID: "ID-" + spec.Name,
|
||||
return client.ConfigCreateResult{
|
||||
ID: "ID-" + options.Spec.Name,
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
@ -100,13 +101,13 @@ func TestConfigCreateWithLabels(t *testing.T) {
|
||||
}
|
||||
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
configCreateFunc: func(_ context.Context, spec swarm.ConfigSpec) (swarm.ConfigCreateResponse, error) {
|
||||
if !reflect.DeepEqual(spec, expected) {
|
||||
return swarm.ConfigCreateResponse{}, fmt.Errorf("expected %+v, got %+v", expected, spec)
|
||||
configCreateFunc: func(_ context.Context, options client.ConfigCreateOptions) (client.ConfigCreateResult, error) {
|
||||
if !reflect.DeepEqual(options.Spec, expected) {
|
||||
return client.ConfigCreateResult{}, fmt.Errorf("expected %+v, got %+v", expected, options.Spec)
|
||||
}
|
||||
|
||||
return swarm.ConfigCreateResponse{
|
||||
ID: "ID-" + spec.Name,
|
||||
return client.ConfigCreateResult{
|
||||
ID: "ID-" + options.Spec.Name,
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
@ -126,17 +127,17 @@ func TestConfigCreateWithTemplatingDriver(t *testing.T) {
|
||||
const name = "config-with-template-driver"
|
||||
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
configCreateFunc: func(_ context.Context, spec swarm.ConfigSpec) (swarm.ConfigCreateResponse, error) {
|
||||
if spec.Name != name {
|
||||
return swarm.ConfigCreateResponse{}, fmt.Errorf("expected name %q, got %q", name, spec.Name)
|
||||
configCreateFunc: func(_ context.Context, options client.ConfigCreateOptions) (client.ConfigCreateResult, error) {
|
||||
if options.Spec.Name != name {
|
||||
return client.ConfigCreateResult{}, fmt.Errorf("expected name %q, got %q", name, options.Spec.Name)
|
||||
}
|
||||
|
||||
if spec.Templating.Name != expectedDriver.Name {
|
||||
return swarm.ConfigCreateResponse{}, fmt.Errorf("expected driver %v, got %v", expectedDriver, spec.Labels)
|
||||
if options.Spec.Templating.Name != expectedDriver.Name {
|
||||
return client.ConfigCreateResult{}, fmt.Errorf("expected driver %v, got %v", expectedDriver, options.Spec.Labels)
|
||||
}
|
||||
|
||||
return swarm.ConfigCreateResponse{
|
||||
ID: "ID-" + spec.Name,
|
||||
return client.ConfigCreateResult{
|
||||
ID: "ID-" + options.Spec.Name,
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
"github.com/docker/cli/cli/command/inspect"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/client"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -44,7 +45,7 @@ func newFormat(source string, quiet bool) formatter.Format {
|
||||
}
|
||||
|
||||
// formatWrite writes the context
|
||||
func formatWrite(fmtCtx formatter.Context, configs []swarm.Config) error {
|
||||
func formatWrite(fmtCtx formatter.Context, configs client.ConfigListResult) error {
|
||||
cCtx := &configContext{
|
||||
HeaderContext: formatter.HeaderContext{
|
||||
Header: formatter.SubHeaderContext{
|
||||
@ -57,7 +58,7 @@ func formatWrite(fmtCtx formatter.Context, configs []swarm.Config) error {
|
||||
},
|
||||
}
|
||||
return fmtCtx.Write(cCtx, func(format func(subContext formatter.SubContext) error) error {
|
||||
for _, config := range configs {
|
||||
for _, config := range configs.Items {
|
||||
configCtx := &configContext{c: config}
|
||||
if err := format(configCtx); err != nil {
|
||||
return err
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/docker/cli/cli/command/formatter"
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
@ -48,23 +49,25 @@ id_rsa
|
||||
},
|
||||
}
|
||||
|
||||
configs := []swarm.Config{
|
||||
{
|
||||
ID: "1",
|
||||
Meta: swarm.Meta{CreatedAt: time.Now(), UpdatedAt: time.Now()},
|
||||
Spec: swarm.ConfigSpec{Annotations: swarm.Annotations{Name: "passwords"}},
|
||||
},
|
||||
{
|
||||
ID: "2",
|
||||
Meta: swarm.Meta{CreatedAt: time.Now(), UpdatedAt: time.Now()},
|
||||
Spec: swarm.ConfigSpec{Annotations: swarm.Annotations{Name: "id_rsa"}},
|
||||
res := client.ConfigListResult{
|
||||
Items: []swarm.Config{
|
||||
{
|
||||
ID: "1",
|
||||
Meta: swarm.Meta{CreatedAt: time.Now(), UpdatedAt: time.Now()},
|
||||
Spec: swarm.ConfigSpec{Annotations: swarm.Annotations{Name: "passwords"}},
|
||||
},
|
||||
{
|
||||
ID: "2",
|
||||
Meta: swarm.Meta{CreatedAt: time.Now(), UpdatedAt: time.Now()},
|
||||
Spec: swarm.ConfigSpec{Annotations: swarm.Annotations{Name: "id_rsa"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||
var out bytes.Buffer
|
||||
tc.context.Output = &out
|
||||
if err := formatWrite(tc.context, configs); err != nil {
|
||||
if err := formatWrite(tc.context, res); err != nil {
|
||||
assert.ErrorContains(t, err, tc.expected)
|
||||
} else {
|
||||
assert.Equal(t, out.String(), tc.expected)
|
||||
|
||||
@ -12,6 +12,7 @@ import (
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/command/formatter"
|
||||
flagsHelper "github.com/docker/cli/cli/flags"
|
||||
"github.com/moby/moby/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -50,7 +51,8 @@ func runInspect(ctx context.Context, dockerCLI command.Cli, opts inspectOptions)
|
||||
}
|
||||
|
||||
getRef := func(id string) (any, []byte, error) {
|
||||
return apiClient.ConfigInspectWithRaw(ctx, id)
|
||||
res, err := apiClient.ConfigInspect(ctx, id, client.ConfigInspectOptions{})
|
||||
return res.Config, res.Raw, err
|
||||
}
|
||||
|
||||
// check if the user is trying to apply a template to the pretty format, which
|
||||
|
||||
@ -10,7 +10,7 @@ import (
|
||||
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/docker/cli/internal/test/builders"
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
"gotest.tools/v3/golden"
|
||||
)
|
||||
@ -19,7 +19,7 @@ func TestConfigInspectErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
flags map[string]string
|
||||
configInspectFunc func(_ context.Context, configID string) (swarm.Config, []byte, error)
|
||||
configInspectFunc func(_ context.Context, configID string, _ client.ConfigInspectOptions) (client.ConfigInspectResult, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
@ -27,8 +27,8 @@ func TestConfigInspectErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
args: []string{"foo"},
|
||||
configInspectFunc: func(_ context.Context, configID string) (swarm.Config, []byte, error) {
|
||||
return swarm.Config{}, nil, errors.New("error while inspecting the config")
|
||||
configInspectFunc: func(context.Context, string, client.ConfigInspectOptions) (client.ConfigInspectResult, error) {
|
||||
return client.ConfigInspectResult{}, errors.New("error while inspecting the config")
|
||||
},
|
||||
expectedError: "error while inspecting the config",
|
||||
},
|
||||
@ -41,11 +41,13 @@ func TestConfigInspectErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
args: []string{"foo", "bar"},
|
||||
configInspectFunc: func(_ context.Context, configID string) (swarm.Config, []byte, error) {
|
||||
configInspectFunc: func(_ context.Context, configID string, _ client.ConfigInspectOptions) (client.ConfigInspectResult, error) {
|
||||
if configID == "foo" {
|
||||
return *builders.Config(builders.ConfigName("foo")), nil, nil
|
||||
return client.ConfigInspectResult{
|
||||
Config: *builders.Config(builders.ConfigName("foo")),
|
||||
}, nil
|
||||
}
|
||||
return swarm.Config{}, nil, errors.New("error while inspecting the config")
|
||||
return client.ConfigInspectResult{}, errors.New("error while inspecting the config")
|
||||
},
|
||||
expectedError: "error while inspecting the config",
|
||||
},
|
||||
@ -70,25 +72,34 @@ func TestConfigInspectWithoutFormat(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
configInspectFunc func(_ context.Context, configID string) (swarm.Config, []byte, error)
|
||||
configInspectFunc func(_ context.Context, configID string, _ client.ConfigInspectOptions) (client.ConfigInspectResult, error)
|
||||
}{
|
||||
{
|
||||
name: "single-config",
|
||||
args: []string{"foo"},
|
||||
configInspectFunc: func(_ context.Context, name string) (swarm.Config, []byte, error) {
|
||||
configInspectFunc: func(_ context.Context, name string, _ client.ConfigInspectOptions) (client.ConfigInspectResult, error) {
|
||||
if name != "foo" {
|
||||
return swarm.Config{}, nil, fmt.Errorf("invalid name, expected %s, got %s", "foo", name)
|
||||
return client.ConfigInspectResult{}, fmt.Errorf("invalid name, expected %s, got %s", "foo", name)
|
||||
}
|
||||
return *builders.Config(builders.ConfigID("ID-foo"), builders.ConfigName("foo")), nil, nil
|
||||
return client.ConfigInspectResult{
|
||||
Config: *builders.Config(
|
||||
builders.ConfigID("ID-foo"),
|
||||
builders.ConfigName("foo"),
|
||||
),
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple-configs-with-labels",
|
||||
args: []string{"foo", "bar"},
|
||||
configInspectFunc: func(_ context.Context, name string) (swarm.Config, []byte, error) {
|
||||
return *builders.Config(builders.ConfigID("ID-"+name), builders.ConfigName(name), builders.ConfigLabels(map[string]string{
|
||||
"label1": "label-foo",
|
||||
})), nil, nil
|
||||
configInspectFunc: func(_ context.Context, name string, _ client.ConfigInspectOptions) (client.ConfigInspectResult, error) {
|
||||
return client.ConfigInspectResult{
|
||||
Config: *builders.Config(
|
||||
builders.ConfigID("ID-"+name),
|
||||
builders.ConfigName(name),
|
||||
builders.ConfigLabels(map[string]string{"label1": "label-foo"}),
|
||||
),
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -102,16 +113,19 @@ func TestConfigInspectWithoutFormat(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConfigInspectWithFormat(t *testing.T) {
|
||||
configInspectFunc := func(_ context.Context, name string) (swarm.Config, []byte, error) {
|
||||
return *builders.Config(builders.ConfigName("foo"), builders.ConfigLabels(map[string]string{
|
||||
"label1": "label-foo",
|
||||
})), nil, nil
|
||||
configInspectFunc := func(_ context.Context, name string, _ client.ConfigInspectOptions) (client.ConfigInspectResult, error) {
|
||||
return client.ConfigInspectResult{
|
||||
Config: *builders.Config(
|
||||
builders.ConfigName("foo"),
|
||||
builders.ConfigLabels(map[string]string{"label1": "label-foo"}),
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
testCases := []struct {
|
||||
name string
|
||||
format string
|
||||
args []string
|
||||
configInspectFunc func(_ context.Context, name string) (swarm.Config, []byte, error)
|
||||
configInspectFunc func(_ context.Context, name string, _ client.ConfigInspectOptions) (client.ConfigInspectResult, error)
|
||||
}{
|
||||
{
|
||||
name: "simple-template",
|
||||
@ -141,21 +155,23 @@ func TestConfigInspectWithFormat(t *testing.T) {
|
||||
func TestConfigInspectPretty(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
configInspectFunc func(context.Context, string) (swarm.Config, []byte, error)
|
||||
configInspectFunc func(context.Context, string, client.ConfigInspectOptions) (client.ConfigInspectResult, error)
|
||||
}{
|
||||
{
|
||||
name: "simple",
|
||||
configInspectFunc: func(_ context.Context, id string) (swarm.Config, []byte, error) {
|
||||
return *builders.Config(
|
||||
builders.ConfigLabels(map[string]string{
|
||||
"lbl1": "value1",
|
||||
}),
|
||||
builders.ConfigID("configID"),
|
||||
builders.ConfigName("configName"),
|
||||
builders.ConfigCreatedAt(time.Time{}),
|
||||
builders.ConfigUpdatedAt(time.Time{}),
|
||||
builders.ConfigData([]byte("payload here")),
|
||||
), []byte{}, nil
|
||||
configInspectFunc: func(_ context.Context, id string, _ client.ConfigInspectOptions) (client.ConfigInspectResult, error) {
|
||||
return client.ConfigInspectResult{
|
||||
Config: *builders.Config(
|
||||
builders.ConfigLabels(map[string]string{
|
||||
"lbl1": "value1",
|
||||
}),
|
||||
builders.ConfigID("configID"),
|
||||
builders.ConfigName("configName"),
|
||||
builders.ConfigCreatedAt(time.Time{}),
|
||||
builders.ConfigUpdatedAt(time.Time{}),
|
||||
builders.ConfigData([]byte("payload here")),
|
||||
),
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -48,7 +48,7 @@ func newConfigListCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
func runList(ctx context.Context, dockerCLI command.Cli, options listOptions) error {
|
||||
apiClient := dockerCLI.Client()
|
||||
|
||||
configs, err := apiClient.ConfigList(ctx, client.ConfigListOptions{Filters: options.filter.Value()})
|
||||
res, err := apiClient.ConfigList(ctx, client.ConfigListOptions{Filters: options.filter.Value()})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -62,13 +62,13 @@ func runList(ctx context.Context, dockerCLI command.Cli, options listOptions) er
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(configs, func(i, j int) bool {
|
||||
return sortorder.NaturalLess(configs[i].Spec.Name, configs[j].Spec.Name)
|
||||
sort.Slice(res.Items, func(i, j int) bool {
|
||||
return sortorder.NaturalLess(res.Items[i].Spec.Name, res.Items[j].Spec.Name)
|
||||
})
|
||||
|
||||
configCtx := formatter.Context{
|
||||
Output: dockerCLI.Out(),
|
||||
Format: newFormat(format, options.quiet),
|
||||
}
|
||||
return formatWrite(configCtx, configs)
|
||||
return formatWrite(configCtx, res)
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ import (
|
||||
func TestConfigListErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
configListFunc func(context.Context, client.ConfigListOptions) ([]swarm.Config, error)
|
||||
configListFunc func(context.Context, client.ConfigListOptions) (client.ConfigListResult, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
@ -27,8 +27,8 @@ func TestConfigListErrors(t *testing.T) {
|
||||
expectedError: "accepts no argument",
|
||||
},
|
||||
{
|
||||
configListFunc: func(_ context.Context, options client.ConfigListOptions) ([]swarm.Config, error) {
|
||||
return []swarm.Config{}, errors.New("error listing configs")
|
||||
configListFunc: func(_ context.Context, options client.ConfigListOptions) (client.ConfigListResult, error) {
|
||||
return client.ConfigListResult{}, errors.New("error listing configs")
|
||||
},
|
||||
expectedError: "error listing configs",
|
||||
},
|
||||
@ -48,26 +48,28 @@ func TestConfigListErrors(t *testing.T) {
|
||||
|
||||
func TestConfigList(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
configListFunc: func(_ context.Context, options client.ConfigListOptions) ([]swarm.Config, error) {
|
||||
return []swarm.Config{
|
||||
*builders.Config(builders.ConfigID("ID-1-foo"),
|
||||
builders.ConfigName("1-foo"),
|
||||
builders.ConfigVersion(swarm.Version{Index: 10}),
|
||||
builders.ConfigCreatedAt(time.Now().Add(-2*time.Hour)),
|
||||
builders.ConfigUpdatedAt(time.Now().Add(-1*time.Hour)),
|
||||
),
|
||||
*builders.Config(builders.ConfigID("ID-10-foo"),
|
||||
builders.ConfigName("10-foo"),
|
||||
builders.ConfigVersion(swarm.Version{Index: 11}),
|
||||
builders.ConfigCreatedAt(time.Now().Add(-2*time.Hour)),
|
||||
builders.ConfigUpdatedAt(time.Now().Add(-1*time.Hour)),
|
||||
),
|
||||
*builders.Config(builders.ConfigID("ID-2-foo"),
|
||||
builders.ConfigName("2-foo"),
|
||||
builders.ConfigVersion(swarm.Version{Index: 11}),
|
||||
builders.ConfigCreatedAt(time.Now().Add(-2*time.Hour)),
|
||||
builders.ConfigUpdatedAt(time.Now().Add(-1*time.Hour)),
|
||||
),
|
||||
configListFunc: func(_ context.Context, options client.ConfigListOptions) (client.ConfigListResult, error) {
|
||||
return client.ConfigListResult{
|
||||
Items: []swarm.Config{
|
||||
*builders.Config(builders.ConfigID("ID-1-foo"),
|
||||
builders.ConfigName("1-foo"),
|
||||
builders.ConfigVersion(swarm.Version{Index: 10}),
|
||||
builders.ConfigCreatedAt(time.Now().Add(-2*time.Hour)),
|
||||
builders.ConfigUpdatedAt(time.Now().Add(-1*time.Hour)),
|
||||
),
|
||||
*builders.Config(builders.ConfigID("ID-10-foo"),
|
||||
builders.ConfigName("10-foo"),
|
||||
builders.ConfigVersion(swarm.Version{Index: 11}),
|
||||
builders.ConfigCreatedAt(time.Now().Add(-2*time.Hour)),
|
||||
builders.ConfigUpdatedAt(time.Now().Add(-1*time.Hour)),
|
||||
),
|
||||
*builders.Config(builders.ConfigID("ID-2-foo"),
|
||||
builders.ConfigName("2-foo"),
|
||||
builders.ConfigVersion(swarm.Version{Index: 11}),
|
||||
builders.ConfigCreatedAt(time.Now().Add(-2*time.Hour)),
|
||||
builders.ConfigUpdatedAt(time.Now().Add(-1*time.Hour)),
|
||||
),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
@ -78,12 +80,14 @@ func TestConfigList(t *testing.T) {
|
||||
|
||||
func TestConfigListWithQuietOption(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
configListFunc: func(_ context.Context, options client.ConfigListOptions) ([]swarm.Config, error) {
|
||||
return []swarm.Config{
|
||||
*builders.Config(builders.ConfigID("ID-foo"), builders.ConfigName("foo")),
|
||||
*builders.Config(builders.ConfigID("ID-bar"), builders.ConfigName("bar"), builders.ConfigLabels(map[string]string{
|
||||
"label": "label-bar",
|
||||
})),
|
||||
configListFunc: func(_ context.Context, options client.ConfigListOptions) (client.ConfigListResult, error) {
|
||||
return client.ConfigListResult{
|
||||
Items: []swarm.Config{
|
||||
*builders.Config(builders.ConfigID("ID-foo"), builders.ConfigName("foo")),
|
||||
*builders.Config(builders.ConfigID("ID-bar"), builders.ConfigName("bar"), builders.ConfigLabels(map[string]string{
|
||||
"label": "label-bar",
|
||||
})),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
@ -95,12 +99,14 @@ func TestConfigListWithQuietOption(t *testing.T) {
|
||||
|
||||
func TestConfigListWithConfigFormat(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
configListFunc: func(_ context.Context, options client.ConfigListOptions) ([]swarm.Config, error) {
|
||||
return []swarm.Config{
|
||||
*builders.Config(builders.ConfigID("ID-foo"), builders.ConfigName("foo")),
|
||||
*builders.Config(builders.ConfigID("ID-bar"), builders.ConfigName("bar"), builders.ConfigLabels(map[string]string{
|
||||
"label": "label-bar",
|
||||
})),
|
||||
configListFunc: func(_ context.Context, options client.ConfigListOptions) (client.ConfigListResult, error) {
|
||||
return client.ConfigListResult{
|
||||
Items: []swarm.Config{
|
||||
*builders.Config(builders.ConfigID("ID-foo"), builders.ConfigName("foo")),
|
||||
*builders.Config(builders.ConfigID("ID-bar"), builders.ConfigName("bar"), builders.ConfigLabels(map[string]string{
|
||||
"label": "label-bar",
|
||||
})),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
@ -114,12 +120,14 @@ func TestConfigListWithConfigFormat(t *testing.T) {
|
||||
|
||||
func TestConfigListWithFormat(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
configListFunc: func(_ context.Context, options client.ConfigListOptions) ([]swarm.Config, error) {
|
||||
return []swarm.Config{
|
||||
*builders.Config(builders.ConfigID("ID-foo"), builders.ConfigName("foo")),
|
||||
*builders.Config(builders.ConfigID("ID-bar"), builders.ConfigName("bar"), builders.ConfigLabels(map[string]string{
|
||||
"label": "label-bar",
|
||||
})),
|
||||
configListFunc: func(_ context.Context, options client.ConfigListOptions) (client.ConfigListResult, error) {
|
||||
return client.ConfigListResult{
|
||||
Items: []swarm.Config{
|
||||
*builders.Config(builders.ConfigID("ID-foo"), builders.ConfigName("foo")),
|
||||
*builders.Config(builders.ConfigID("ID-bar"), builders.ConfigName("bar"), builders.ConfigLabels(map[string]string{
|
||||
"label": "label-bar",
|
||||
})),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
@ -131,22 +139,24 @@ func TestConfigListWithFormat(t *testing.T) {
|
||||
|
||||
func TestConfigListWithFilter(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
configListFunc: func(_ context.Context, options client.ConfigListOptions) ([]swarm.Config, error) {
|
||||
configListFunc: func(_ context.Context, options client.ConfigListOptions) (client.ConfigListResult, error) {
|
||||
assert.Check(t, options.Filters["name"]["foo"])
|
||||
assert.Check(t, options.Filters["label"]["lbl1=Label-bar"])
|
||||
return []swarm.Config{
|
||||
*builders.Config(builders.ConfigID("ID-foo"),
|
||||
builders.ConfigName("foo"),
|
||||
builders.ConfigVersion(swarm.Version{Index: 10}),
|
||||
builders.ConfigCreatedAt(time.Now().Add(-2*time.Hour)),
|
||||
builders.ConfigUpdatedAt(time.Now().Add(-1*time.Hour)),
|
||||
),
|
||||
*builders.Config(builders.ConfigID("ID-bar"),
|
||||
builders.ConfigName("bar"),
|
||||
builders.ConfigVersion(swarm.Version{Index: 11}),
|
||||
builders.ConfigCreatedAt(time.Now().Add(-2*time.Hour)),
|
||||
builders.ConfigUpdatedAt(time.Now().Add(-1*time.Hour)),
|
||||
),
|
||||
return client.ConfigListResult{
|
||||
Items: []swarm.Config{
|
||||
*builders.Config(builders.ConfigID("ID-foo"),
|
||||
builders.ConfigName("foo"),
|
||||
builders.ConfigVersion(swarm.Version{Index: 10}),
|
||||
builders.ConfigCreatedAt(time.Now().Add(-2*time.Hour)),
|
||||
builders.ConfigUpdatedAt(time.Now().Add(-1*time.Hour)),
|
||||
),
|
||||
*builders.Config(builders.ConfigID("ID-bar"),
|
||||
builders.ConfigName("bar"),
|
||||
builders.ConfigVersion(swarm.Version{Index: 11}),
|
||||
builders.ConfigCreatedAt(time.Now().Add(-2*time.Hour)),
|
||||
builders.ConfigUpdatedAt(time.Now().Add(-1*time.Hour)),
|
||||
),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/moby/moby/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -30,7 +31,7 @@ func runRemove(ctx context.Context, dockerCLI command.Cli, names []string) error
|
||||
|
||||
var errs []error
|
||||
for _, name := range names {
|
||||
if err := apiClient.ConfigRemove(ctx, name); err != nil {
|
||||
if _, err := apiClient.ConfigRemove(ctx, name, client.ConfigRemoveOptions{}); err != nil {
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
@ -14,7 +16,7 @@ import (
|
||||
func TestConfigRemoveErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
configRemoveFunc func(string) error
|
||||
configRemoveFunc func(context.Context, string, client.ConfigRemoveOptions) (client.ConfigRemoveResult, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
@ -23,8 +25,8 @@ func TestConfigRemoveErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
args: []string{"foo"},
|
||||
configRemoveFunc: func(name string) error {
|
||||
return errors.New("error removing config")
|
||||
configRemoveFunc: func(ctx context.Context, name string, options client.ConfigRemoveOptions) (client.ConfigRemoveResult, error) {
|
||||
return client.ConfigRemoveResult{}, errors.New("error removing config")
|
||||
},
|
||||
expectedError: "error removing config",
|
||||
},
|
||||
@ -46,9 +48,9 @@ func TestConfigRemoveWithName(t *testing.T) {
|
||||
names := []string{"foo", "bar"}
|
||||
var removedConfigs []string
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
configRemoveFunc: func(name string) error {
|
||||
configRemoveFunc: func(_ context.Context, name string, _ client.ConfigRemoveOptions) (client.ConfigRemoveResult, error) {
|
||||
removedConfigs = append(removedConfigs, name)
|
||||
return nil
|
||||
return client.ConfigRemoveResult{}, nil
|
||||
},
|
||||
})
|
||||
cmd := newConfigRemoveCommand(cli)
|
||||
@ -63,12 +65,12 @@ func TestConfigRemoveContinueAfterError(t *testing.T) {
|
||||
var removedConfigs []string
|
||||
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
configRemoveFunc: func(name string) error {
|
||||
configRemoveFunc: func(_ context.Context, name string, _ client.ConfigRemoveOptions) (client.ConfigRemoveResult, error) {
|
||||
removedConfigs = append(removedConfigs, name)
|
||||
if name == "foo" {
|
||||
return errors.New("error removing config: " + name)
|
||||
return client.ConfigRemoveResult{}, errors.New("error removing config: " + name)
|
||||
}
|
||||
return nil
|
||||
return client.ConfigRemoveResult{}, nil
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@ -177,7 +177,7 @@ func resizeTTY(ctx context.Context, dockerCli command.Cli, containerID string) {
|
||||
// terminal, the only way to get the shell prompt to display for attaches 2+ is to artificially
|
||||
// resize it, then go back to normal. Without this, every attach after the first will
|
||||
// require the user to manually resize or hit enter.
|
||||
resizeTtyTo(ctx, dockerCli.Client(), containerID, height+1, width+1, false)
|
||||
resizeTTYTo(ctx, dockerCli.Client(), containerID, height+1, width+1, false)
|
||||
|
||||
// After the above resizing occurs, the call to MonitorTtySize below will handle resetting back
|
||||
// to the actual size.
|
||||
|
||||
@ -14,15 +14,15 @@ import (
|
||||
type fakeClient struct {
|
||||
client.Client
|
||||
inspectFunc func(string) (container.InspectResponse, error)
|
||||
execInspectFunc func(execID string) (client.ExecInspect, error)
|
||||
execCreateFunc func(containerID string, options client.ExecCreateOptions) (container.ExecCreateResponse, error)
|
||||
execInspectFunc func(execID string) (client.ExecInspectResult, error)
|
||||
execCreateFunc func(containerID string, options client.ExecCreateOptions) (client.ExecCreateResult, error)
|
||||
createContainerFunc func(config *container.Config,
|
||||
hostConfig *container.HostConfig,
|
||||
networkingConfig *network.NetworkingConfig,
|
||||
platform *ocispec.Platform,
|
||||
containerName string) (container.CreateResponse, error)
|
||||
containerStartFunc func(containerID string, options client.ContainerStartOptions) error
|
||||
imageCreateFunc func(ctx context.Context, parentReference string, options client.ImageCreateOptions) (io.ReadCloser, error)
|
||||
imageCreateFunc func(ctx context.Context, parentReference string, options client.ImageCreateOptions) (client.ImageCreateResult, error)
|
||||
infoFunc func() (system.Info, error)
|
||||
containerStatPathFunc func(containerID, path string) (container.PathStat, error)
|
||||
containerCopyFromFunc func(containerID, srcPath string) (io.ReadCloser, container.PathStat, error)
|
||||
@ -30,7 +30,7 @@ type fakeClient struct {
|
||||
waitFunc func(string) (<-chan container.WaitResponse, <-chan error)
|
||||
containerListFunc func(client.ContainerListOptions) ([]container.Summary, error)
|
||||
containerExportFunc func(string) (io.ReadCloser, error)
|
||||
containerExecResizeFunc func(id string, options client.ContainerResizeOptions) error
|
||||
containerExecResizeFunc func(id string, options client.ExecResizeOptions) (client.ExecResizeResult, error)
|
||||
containerRemoveFunc func(ctx context.Context, containerID string, options client.ContainerRemoveOptions) error
|
||||
containerRestartFunc func(ctx context.Context, containerID string, options client.ContainerStopOptions) error
|
||||
containerStopFunc func(ctx context.Context, containerID string, options client.ContainerStopOptions) error
|
||||
@ -58,22 +58,22 @@ func (f *fakeClient) ContainerInspect(_ context.Context, containerID string) (co
|
||||
return container.InspectResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) ContainerExecCreate(_ context.Context, containerID string, config client.ExecCreateOptions) (container.ExecCreateResponse, error) {
|
||||
func (f *fakeClient) ExecCreate(_ context.Context, containerID string, config client.ExecCreateOptions) (client.ExecCreateResult, error) {
|
||||
if f.execCreateFunc != nil {
|
||||
return f.execCreateFunc(containerID, config)
|
||||
}
|
||||
return container.ExecCreateResponse{}, nil
|
||||
return client.ExecCreateResult{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) ContainerExecInspect(_ context.Context, execID string) (client.ExecInspect, error) {
|
||||
func (f *fakeClient) ExecInspect(_ context.Context, execID string, _ client.ExecInspectOptions) (client.ExecInspectResult, error) {
|
||||
if f.execInspectFunc != nil {
|
||||
return f.execInspectFunc(execID)
|
||||
}
|
||||
return client.ExecInspect{}, nil
|
||||
return client.ExecInspectResult{}, nil
|
||||
}
|
||||
|
||||
func (*fakeClient) ContainerExecStart(context.Context, string, client.ExecStartOptions) error {
|
||||
return nil
|
||||
func (*fakeClient) ExecStart(context.Context, string, client.ExecStartOptions) (client.ExecStartResult, error) {
|
||||
return client.ExecStartResult{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) ContainerCreate(
|
||||
@ -97,11 +97,11 @@ func (f *fakeClient) ContainerRemove(ctx context.Context, containerID string, op
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) ImageCreate(ctx context.Context, parentReference string, options client.ImageCreateOptions) (io.ReadCloser, error) {
|
||||
func (f *fakeClient) ImageCreate(ctx context.Context, parentReference string, options client.ImageCreateOptions) (client.ImageCreateResult, error) {
|
||||
if f.imageCreateFunc != nil {
|
||||
return f.imageCreateFunc(ctx, parentReference, options)
|
||||
}
|
||||
return nil, nil
|
||||
return client.ImageCreateResult{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) Info(_ context.Context) (system.Info, error) {
|
||||
@ -157,11 +157,11 @@ func (f *fakeClient) ContainerExport(_ context.Context, containerID string) (io.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) ContainerExecResize(_ context.Context, id string, options client.ContainerResizeOptions) error {
|
||||
func (f *fakeClient) ExecResize(_ context.Context, id string, options client.ExecResizeOptions) (client.ExecResizeResult, error) {
|
||||
if f.containerExecResizeFunc != nil {
|
||||
return f.containerExecResizeFunc(id, options)
|
||||
}
|
||||
return nil
|
||||
return client.ExecResizeResult{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) ContainerKill(ctx context.Context, containerID, signal string) error {
|
||||
|
||||
@ -135,7 +135,7 @@ func pullImage(ctx context.Context, dockerCli command.Cli, img string, options *
|
||||
return err
|
||||
}
|
||||
|
||||
responseBody, err := dockerCli.Client().ImageCreate(ctx, img, client.ImageCreateOptions{
|
||||
resp, err := dockerCli.Client().ImageCreate(ctx, img, client.ImageCreateOptions{
|
||||
RegistryAuth: encodedAuth,
|
||||
Platform: options.platform,
|
||||
})
|
||||
@ -143,14 +143,14 @@ func pullImage(ctx context.Context, dockerCli command.Cli, img string, options *
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = responseBody.Close()
|
||||
_ = resp.Body.Close()
|
||||
}()
|
||||
|
||||
out := dockerCli.Err()
|
||||
if options.quiet {
|
||||
out = streams.NewOut(io.Discard)
|
||||
}
|
||||
return jsonstream.Display(ctx, responseBody, out)
|
||||
return jsonstream.Display(ctx, resp.Body, out)
|
||||
}
|
||||
|
||||
type cidFile struct {
|
||||
|
||||
@ -132,9 +132,9 @@ func TestCreateContainerImagePullPolicy(t *testing.T) {
|
||||
return container.CreateResponse{ID: containerID}, nil
|
||||
}
|
||||
},
|
||||
imageCreateFunc: func(ctx context.Context, parentReference string, options client.ImageCreateOptions) (io.ReadCloser, error) {
|
||||
imageCreateFunc: func(ctx context.Context, parentReference string, options client.ImageCreateOptions) (client.ImageCreateResult, error) {
|
||||
defer func() { pullCounter++ }()
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
return client.ImageCreateResult{Body: io.NopCloser(strings.NewReader(""))}, nil
|
||||
},
|
||||
infoFunc: func() (system.Info, error) {
|
||||
return system.Info{IndexServerAddress: "https://indexserver.example.com"}, nil
|
||||
|
||||
@ -72,11 +72,11 @@ func newExecCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
flags.StringVarP(&options.User, "user", "u", "", `Username or UID (format: "<name|uid>[:<group|gid>]")`)
|
||||
flags.BoolVar(&options.Privileged, "privileged", false, "Give extended privileges to the command")
|
||||
flags.VarP(&options.Env, "env", "e", "Set environment variables")
|
||||
flags.SetAnnotation("env", "version", []string{"1.25"})
|
||||
_ = flags.SetAnnotation("env", "version", []string{"1.25"})
|
||||
flags.Var(&options.EnvFile, "env-file", "Read in a file of environment variables")
|
||||
flags.SetAnnotation("env-file", "version", []string{"1.25"})
|
||||
_ = flags.SetAnnotation("env-file", "version", []string{"1.25"})
|
||||
flags.StringVarP(&options.Workdir, "workdir", "w", "", "Working directory inside the container")
|
||||
flags.SetAnnotation("workdir", "version", []string{"1.35"})
|
||||
_ = flags.SetAnnotation("workdir", "version", []string{"1.35"})
|
||||
|
||||
_ = cmd.RegisterFlagCompletionFunc("env", completion.EnvVarNames())
|
||||
_ = cmd.RegisterFlagCompletionFunc("env-file", completion.FileNames())
|
||||
@ -108,7 +108,7 @@ func RunExec(ctx context.Context, dockerCLI command.Cli, containerIDorName strin
|
||||
|
||||
fillConsoleSize(execOptions, dockerCLI)
|
||||
|
||||
response, err := apiClient.ContainerExecCreate(ctx, containerIDorName, *execOptions)
|
||||
response, err := apiClient.ExecCreate(ctx, containerIDorName, *execOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -119,11 +119,12 @@ func RunExec(ctx context.Context, dockerCLI command.Cli, containerIDorName strin
|
||||
}
|
||||
|
||||
if options.Detach {
|
||||
return apiClient.ContainerExecStart(ctx, execID, client.ExecStartOptions{
|
||||
_, err := apiClient.ExecStart(ctx, execID, client.ExecStartOptions{
|
||||
Detach: options.Detach,
|
||||
Tty: execOptions.Tty,
|
||||
ConsoleSize: execOptions.ConsoleSize,
|
||||
})
|
||||
return err
|
||||
}
|
||||
return interactiveExec(ctx, dockerCLI, execOptions, execID)
|
||||
}
|
||||
@ -158,7 +159,7 @@ func interactiveExec(ctx context.Context, dockerCli command.Cli, execOptions *cl
|
||||
fillConsoleSize(execOptions, dockerCli)
|
||||
|
||||
apiClient := dockerCli.Client()
|
||||
resp, err := apiClient.ContainerExecAttach(ctx, execID, client.ExecAttachOptions{
|
||||
resp, err := apiClient.ExecAttach(ctx, execID, client.ExecAttachOptions{
|
||||
Tty: execOptions.Tty,
|
||||
ConsoleSize: execOptions.ConsoleSize,
|
||||
})
|
||||
@ -177,7 +178,7 @@ func interactiveExec(ctx context.Context, dockerCli command.Cli, execOptions *cl
|
||||
inputStream: in,
|
||||
outputStream: out,
|
||||
errorStream: stderr,
|
||||
resp: resp,
|
||||
resp: resp.HijackedResponse,
|
||||
tty: execOptions.Tty,
|
||||
detachKeys: execOptions.DetachKeys,
|
||||
}
|
||||
@ -201,7 +202,7 @@ func interactiveExec(ctx context.Context, dockerCli command.Cli, execOptions *cl
|
||||
}
|
||||
|
||||
func getExecExitStatus(ctx context.Context, apiClient client.ContainerAPIClient, execID string) error {
|
||||
resp, err := apiClient.ContainerExecInspect(ctx, execID)
|
||||
resp, err := apiClient.ExecInspect(ctx, execID, client.ExecInspectOptions{})
|
||||
if err != nil {
|
||||
// If we can't connect, then the daemon probably died.
|
||||
if !client.IsErrConnectionFailed(err) {
|
||||
|
||||
@ -207,8 +207,8 @@ func TestRunExec(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func execCreateWithID(_ string, _ client.ExecCreateOptions) (container.ExecCreateResponse, error) {
|
||||
return container.ExecCreateResponse{ID: "execid"}, nil
|
||||
func execCreateWithID(_ string, _ client.ExecCreateOptions) (client.ExecCreateResult, error) {
|
||||
return client.ExecCreateResult{ExecCreateResponse: container.ExecCreateResponse{ID: "execid"}}, nil
|
||||
}
|
||||
|
||||
func TestGetExecExitStatus(t *testing.T) {
|
||||
@ -236,9 +236,11 @@ func TestGetExecExitStatus(t *testing.T) {
|
||||
|
||||
for _, testcase := range testcases {
|
||||
apiClient := &fakeClient{
|
||||
execInspectFunc: func(id string) (client.ExecInspect, error) {
|
||||
execInspectFunc: func(id string) (client.ExecInspectResult, error) {
|
||||
assert.Check(t, is.Equal(execID, id))
|
||||
return client.ExecInspect{ExitCode: testcase.exitCode}, testcase.inspectError
|
||||
return client.ExecInspectResult{
|
||||
ExecInspect: client.ExecInspect{ExitCode: testcase.exitCode},
|
||||
}, testcase.inspectError
|
||||
},
|
||||
}
|
||||
err := getExecExitStatus(context.Background(), apiClient, execID)
|
||||
|
||||
@ -235,7 +235,7 @@ func TestRunPullTermination(t *testing.T) {
|
||||
containerAttachFunc: func(ctx context.Context, containerID string, options client.ContainerAttachOptions) (client.HijackedResponse, error) {
|
||||
return client.HijackedResponse{}, errors.New("shouldn't try to attach to a container")
|
||||
},
|
||||
imageCreateFunc: func(ctx context.Context, parentReference string, options client.ImageCreateOptions) (io.ReadCloser, error) {
|
||||
imageCreateFunc: func(ctx context.Context, parentReference string, options client.ImageCreateOptions) (client.ImageCreateResult, error) {
|
||||
server, respReader := net.Pipe()
|
||||
t.Cleanup(func() {
|
||||
_ = server.Close()
|
||||
@ -260,7 +260,7 @@ func TestRunPullTermination(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
attachCh <- struct{}{}
|
||||
return respReader, nil
|
||||
return client.ImageCreateResult{Body: respReader}, nil
|
||||
},
|
||||
Version: client.MaxAPIVersion,
|
||||
})
|
||||
|
||||
@ -14,22 +14,23 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// resizeTtyTo resizes tty to specific height and width
|
||||
func resizeTtyTo(ctx context.Context, apiClient client.ContainerAPIClient, id string, height, width uint, isExec bool) error {
|
||||
// resizeTTYTo resizes TTY to specific height and width.
|
||||
func resizeTTYTo(ctx context.Context, apiClient client.ContainerAPIClient, id string, height, width uint, isExec bool) error {
|
||||
if height == 0 && width == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
options := client.ContainerResizeOptions{
|
||||
Height: height,
|
||||
Width: width,
|
||||
}
|
||||
|
||||
var err error
|
||||
if isExec {
|
||||
err = apiClient.ContainerExecResize(ctx, id, options)
|
||||
_, err = apiClient.ExecResize(ctx, id, client.ExecResizeOptions{
|
||||
Height: height,
|
||||
Width: width,
|
||||
})
|
||||
} else {
|
||||
err = apiClient.ContainerResize(ctx, id, options)
|
||||
err = apiClient.ContainerResize(ctx, id, client.ContainerResizeOptions{
|
||||
Height: height,
|
||||
Width: width,
|
||||
})
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@ -41,26 +42,26 @@ func resizeTtyTo(ctx context.Context, apiClient client.ContainerAPIClient, id st
|
||||
// resizeTty is to resize the tty with cli out's tty size
|
||||
func resizeTty(ctx context.Context, cli command.Cli, id string, isExec bool) error {
|
||||
height, width := cli.Out().GetTtySize()
|
||||
return resizeTtyTo(ctx, cli.Client(), id, height, width, isExec)
|
||||
return resizeTTYTo(ctx, cli.Client(), id, height, width, isExec)
|
||||
}
|
||||
|
||||
// initTtySize is to init the tty's size to the same as the window, if there is an error, it will retry 10 times.
|
||||
// initTtySize is to init the TTYs size to the same as the window, if there is an error, it will retry 10 times.
|
||||
func initTtySize(ctx context.Context, cli command.Cli, id string, isExec bool, resizeTtyFunc func(ctx context.Context, cli command.Cli, id string, isExec bool) error) {
|
||||
rttyFunc := resizeTtyFunc
|
||||
if rttyFunc == nil {
|
||||
rttyFunc = resizeTty
|
||||
rTTYfunc := resizeTtyFunc
|
||||
if rTTYfunc == nil {
|
||||
rTTYfunc = resizeTty
|
||||
}
|
||||
if err := rttyFunc(ctx, cli, id, isExec); err != nil {
|
||||
if err := rTTYfunc(ctx, cli, id, isExec); err != nil {
|
||||
go func() {
|
||||
var err error
|
||||
for retry := 0; retry < 10; retry++ {
|
||||
time.Sleep(time.Duration(retry+1) * 10 * time.Millisecond)
|
||||
if err = rttyFunc(ctx, cli, id, isExec); err == nil {
|
||||
if err = rTTYfunc(ctx, cli, id, isExec); err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Fprintln(cli.Err(), "failed to resize tty, using default size")
|
||||
_, _ = fmt.Fprintln(cli.Err(), "failed to resize tty, using default size")
|
||||
}
|
||||
}()
|
||||
}
|
||||
@ -77,7 +78,7 @@ func MonitorTtySize(ctx context.Context, cli command.Cli, id string, isExec bool
|
||||
h, w := cli.Out().GetTtySize()
|
||||
|
||||
if prevW != w || prevH != h {
|
||||
resizeTty(ctx, cli, id, isExec)
|
||||
_ = resizeTty(ctx, cli, id, isExec)
|
||||
}
|
||||
prevH = h
|
||||
prevW = w
|
||||
@ -88,7 +89,7 @@ func MonitorTtySize(ctx context.Context, cli command.Cli, id string, isExec bool
|
||||
gosignal.Notify(sigchan, signal.SIGWINCH)
|
||||
go func() {
|
||||
for range sigchan {
|
||||
resizeTty(ctx, cli, id, isExec)
|
||||
_ = resizeTty(ctx, cli, id, isExec)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
@ -15,12 +15,12 @@ import (
|
||||
|
||||
func TestInitTtySizeErrors(t *testing.T) {
|
||||
expectedError := "failed to resize tty, using default size\n"
|
||||
fakeContainerExecResizeFunc := func(id string, options client.ContainerResizeOptions) error {
|
||||
return errors.New("Error response from daemon: no such exec")
|
||||
fakeContainerExecResizeFunc := func(id string, options client.ExecResizeOptions) (client.ExecResizeResult, error) {
|
||||
return client.ExecResizeResult{}, errors.New("error response from daemon: no such exec")
|
||||
}
|
||||
fakeResizeTtyFunc := func(ctx context.Context, cli command.Cli, id string, isExec bool) error {
|
||||
height, width := uint(1024), uint(768)
|
||||
return resizeTtyTo(ctx, cli.Client(), id, height, width, isExec)
|
||||
return resizeTTYTo(ctx, cli.Client(), id, height, width, isExec)
|
||||
}
|
||||
ctx := context.Background()
|
||||
cli := test.NewFakeCli(&fakeClient{containerExecResizeFunc: fakeContainerExecResizeFunc})
|
||||
|
||||
@ -3,26 +3,25 @@ package idresolver
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/client"
|
||||
)
|
||||
|
||||
type fakeClient struct {
|
||||
client.Client
|
||||
nodeInspectFunc func(string) (swarm.Node, []byte, error)
|
||||
serviceInspectFunc func(string) (swarm.Service, []byte, error)
|
||||
nodeInspectFunc func(string) (client.NodeInspectResult, error)
|
||||
serviceInspectFunc func(string) (client.ServiceInspectResult, error)
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NodeInspectWithRaw(_ context.Context, nodeID string) (swarm.Node, []byte, error) {
|
||||
func (cli *fakeClient) NodeInspect(_ context.Context, nodeID string, _ client.NodeInspectOptions) (client.NodeInspectResult, error) {
|
||||
if cli.nodeInspectFunc != nil {
|
||||
return cli.nodeInspectFunc(nodeID)
|
||||
}
|
||||
return swarm.Node{}, []byte{}, nil
|
||||
return client.NodeInspectResult{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ServiceInspectWithRaw(_ context.Context, serviceID string, _ client.ServiceInspectOptions) (swarm.Service, []byte, error) {
|
||||
func (cli *fakeClient) ServiceInspect(_ context.Context, serviceID string, _ client.ServiceInspectOptions) (client.ServiceInspectResult, error) {
|
||||
if cli.serviceInspectFunc != nil {
|
||||
return cli.serviceInspectFunc(serviceID)
|
||||
}
|
||||
return swarm.Service{}, []byte{}, nil
|
||||
return client.ServiceInspectResult{}, nil
|
||||
}
|
||||
|
||||
@ -30,25 +30,25 @@ func New(apiClient client.APIClient, noResolve bool) *IDResolver {
|
||||
func (r *IDResolver) get(ctx context.Context, t any, id string) (string, error) {
|
||||
switch t.(type) {
|
||||
case swarm.Node:
|
||||
node, _, err := r.client.NodeInspectWithRaw(ctx, id)
|
||||
res, err := r.client.NodeInspect(ctx, id, client.NodeInspectOptions{})
|
||||
if err != nil {
|
||||
// TODO(thaJeztah): should error-handling be more specific, or is it ok to ignore any error?
|
||||
return id, nil //nolint:nilerr // ignore nil-error being returned, as this is a best-effort.
|
||||
}
|
||||
if node.Spec.Annotations.Name != "" {
|
||||
return node.Spec.Annotations.Name, nil
|
||||
if res.Node.Spec.Annotations.Name != "" {
|
||||
return res.Node.Spec.Annotations.Name, nil
|
||||
}
|
||||
if node.Description.Hostname != "" {
|
||||
return node.Description.Hostname, nil
|
||||
if res.Node.Description.Hostname != "" {
|
||||
return res.Node.Description.Hostname, nil
|
||||
}
|
||||
return id, nil
|
||||
case swarm.Service:
|
||||
service, _, err := r.client.ServiceInspectWithRaw(ctx, id, client.ServiceInspectOptions{})
|
||||
res, err := r.client.ServiceInspect(ctx, id, client.ServiceInspectOptions{})
|
||||
if err != nil {
|
||||
// TODO(thaJeztah): should error-handling be more specific, or is it ok to ignore any error?
|
||||
return id, nil //nolint:nilerr // ignore nil-error being returned, as this is a best-effort.
|
||||
}
|
||||
return service.Spec.Annotations.Name, nil
|
||||
return res.Service.Spec.Annotations.Name, nil
|
||||
default:
|
||||
return "", errors.New("unsupported type")
|
||||
}
|
||||
|
||||
@ -7,14 +7,15 @@ import (
|
||||
|
||||
"github.com/docker/cli/internal/test/builders"
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestResolveError(t *testing.T) {
|
||||
apiClient := &fakeClient{
|
||||
nodeInspectFunc: func(nodeID string) (swarm.Node, []byte, error) {
|
||||
return swarm.Node{}, []byte{}, errors.New("error inspecting node")
|
||||
nodeInspectFunc: func(nodeID string) (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{}, errors.New("error inspecting node")
|
||||
},
|
||||
}
|
||||
|
||||
@ -27,13 +28,13 @@ func TestResolveError(t *testing.T) {
|
||||
func TestResolveWithNoResolveOption(t *testing.T) {
|
||||
resolved := false
|
||||
apiClient := &fakeClient{
|
||||
nodeInspectFunc: func(nodeID string) (swarm.Node, []byte, error) {
|
||||
nodeInspectFunc: func(nodeID string) (client.NodeInspectResult, error) {
|
||||
resolved = true
|
||||
return swarm.Node{}, []byte{}, nil
|
||||
return client.NodeInspectResult{}, nil
|
||||
},
|
||||
serviceInspectFunc: func(serviceID string) (swarm.Service, []byte, error) {
|
||||
serviceInspectFunc: func(serviceID string) (client.ServiceInspectResult, error) {
|
||||
resolved = true
|
||||
return swarm.Service{}, []byte{}, nil
|
||||
return client.ServiceInspectResult{}, nil
|
||||
},
|
||||
}
|
||||
|
||||
@ -48,9 +49,11 @@ func TestResolveWithNoResolveOption(t *testing.T) {
|
||||
func TestResolveWithCache(t *testing.T) {
|
||||
inspectCounter := 0
|
||||
apiClient := &fakeClient{
|
||||
nodeInspectFunc: func(nodeID string) (swarm.Node, []byte, error) {
|
||||
nodeInspectFunc: func(string) (client.NodeInspectResult, error) {
|
||||
inspectCounter++
|
||||
return *builders.Node(builders.NodeName("node-foo")), []byte{}, nil
|
||||
return client.NodeInspectResult{
|
||||
Node: *builders.Node(builders.NodeName("node-foo")),
|
||||
}, nil
|
||||
},
|
||||
}
|
||||
|
||||
@ -69,27 +72,31 @@ func TestResolveWithCache(t *testing.T) {
|
||||
func TestResolveNode(t *testing.T) {
|
||||
testCases := []struct {
|
||||
nodeID string
|
||||
nodeInspectFunc func(string) (swarm.Node, []byte, error)
|
||||
nodeInspectFunc func(string) (client.NodeInspectResult, error)
|
||||
expectedID string
|
||||
}{
|
||||
{
|
||||
nodeID: "nodeID",
|
||||
nodeInspectFunc: func(string) (swarm.Node, []byte, error) {
|
||||
return swarm.Node{}, []byte{}, errors.New("error inspecting node")
|
||||
nodeInspectFunc: func(string) (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{}, errors.New("error inspecting node")
|
||||
},
|
||||
expectedID: "nodeID",
|
||||
},
|
||||
{
|
||||
nodeID: "nodeID",
|
||||
nodeInspectFunc: func(string) (swarm.Node, []byte, error) {
|
||||
return *builders.Node(builders.NodeName("node-foo")), []byte{}, nil
|
||||
nodeInspectFunc: func(string) (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{
|
||||
Node: *builders.Node(builders.NodeName("node-foo")),
|
||||
}, nil
|
||||
},
|
||||
expectedID: "node-foo",
|
||||
},
|
||||
{
|
||||
nodeID: "nodeID",
|
||||
nodeInspectFunc: func(string) (swarm.Node, []byte, error) {
|
||||
return *builders.Node(builders.NodeName(""), builders.Hostname("node-hostname")), []byte{}, nil
|
||||
nodeInspectFunc: func(string) (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{
|
||||
Node: *builders.Node(builders.NodeName(""), builders.Hostname("node-hostname")),
|
||||
}, nil
|
||||
},
|
||||
expectedID: "node-hostname",
|
||||
},
|
||||
@ -111,20 +118,22 @@ func TestResolveNode(t *testing.T) {
|
||||
func TestResolveService(t *testing.T) {
|
||||
testCases := []struct {
|
||||
serviceID string
|
||||
serviceInspectFunc func(string) (swarm.Service, []byte, error)
|
||||
serviceInspectFunc func(string) (client.ServiceInspectResult, error)
|
||||
expectedID string
|
||||
}{
|
||||
{
|
||||
serviceID: "serviceID",
|
||||
serviceInspectFunc: func(string) (swarm.Service, []byte, error) {
|
||||
return swarm.Service{}, []byte{}, errors.New("error inspecting service")
|
||||
serviceInspectFunc: func(string) (client.ServiceInspectResult, error) {
|
||||
return client.ServiceInspectResult{}, errors.New("error inspecting service")
|
||||
},
|
||||
expectedID: "serviceID",
|
||||
},
|
||||
{
|
||||
serviceID: "serviceID",
|
||||
serviceInspectFunc: func(string) (swarm.Service, []byte, error) {
|
||||
return *builders.Service(builders.ServiceName("service-foo")), []byte{}, nil
|
||||
serviceInspectFunc: func(string) (client.ServiceInspectResult, error) {
|
||||
return client.ServiceInspectResult{
|
||||
Service: *builders.Service(builders.ServiceName("service-foo")),
|
||||
}, nil
|
||||
},
|
||||
expectedID: "service-foo",
|
||||
},
|
||||
|
||||
@ -25,7 +25,7 @@ func TestRunBuildDockerfileFromStdinWithCompress(t *testing.T) {
|
||||
t.Setenv("DOCKER_BUILDKIT", "0")
|
||||
buffer := new(bytes.Buffer)
|
||||
fakeBuild := newFakeBuild()
|
||||
fakeImageBuild := func(ctx context.Context, buildContext io.Reader, options client.ImageBuildOptions) (client.ImageBuildResponse, error) {
|
||||
fakeImageBuild := func(ctx context.Context, buildContext io.Reader, options client.ImageBuildOptions) (client.ImageBuildResult, error) {
|
||||
tee := io.TeeReader(buildContext, buffer)
|
||||
gzipReader, err := gzip.NewReader(tee)
|
||||
assert.NilError(t, err)
|
||||
@ -181,11 +181,11 @@ func newFakeBuild() *fakeBuild {
|
||||
return &fakeBuild{}
|
||||
}
|
||||
|
||||
func (f *fakeBuild) build(_ context.Context, buildContext io.Reader, options client.ImageBuildOptions) (client.ImageBuildResponse, error) {
|
||||
func (f *fakeBuild) build(_ context.Context, buildContext io.Reader, options client.ImageBuildOptions) (client.ImageBuildResult, error) {
|
||||
f.context = tar.NewReader(buildContext)
|
||||
f.options = options
|
||||
body := new(bytes.Buffer)
|
||||
return client.ImageBuildResponse{Body: io.NopCloser(body)}, nil
|
||||
return client.ImageBuildResult{Body: io.NopCloser(body)}, nil
|
||||
}
|
||||
|
||||
func (f *fakeBuild) headers(t *testing.T) []*tar.Header {
|
||||
|
||||
@ -13,49 +13,48 @@ import (
|
||||
|
||||
type fakeClient struct {
|
||||
client.Client
|
||||
imageTagFunc func(string, string) error
|
||||
imageSaveFunc func(images []string, options ...client.ImageSaveOption) (io.ReadCloser, error)
|
||||
imageRemoveFunc func(image string, options client.ImageRemoveOptions) ([]image.DeleteResponse, error)
|
||||
imagePushFunc func(ref string, options client.ImagePushOptions) (io.ReadCloser, error)
|
||||
imageTagFunc func(options client.ImageTagOptions) (client.ImageTagResult, error)
|
||||
imageSaveFunc func(images []string, options ...client.ImageSaveOption) (client.ImageSaveResult, error)
|
||||
imageRemoveFunc func(image string, options client.ImageRemoveOptions) (client.ImageRemoveResult, error)
|
||||
imagePushFunc func(ref string, options client.ImagePushOptions) (client.ImagePushResponse, error)
|
||||
infoFunc func() (system.Info, error)
|
||||
imagePullFunc func(ref string, options client.ImagePullOptions) (client.ImagePullResponse, error)
|
||||
imagesPruneFunc func(options client.ImagePruneOptions) (client.ImagePruneResult, error)
|
||||
imageLoadFunc func(input io.Reader, options ...client.ImageLoadOption) (client.LoadResponse, error)
|
||||
imageListFunc func(options client.ImageListOptions) ([]image.Summary, error)
|
||||
imageInspectFunc func(img string) (image.InspectResponse, error)
|
||||
imageImportFunc func(source client.ImageImportSource, ref string, options client.ImageImportOptions) (io.ReadCloser, error)
|
||||
imageHistoryFunc func(img string, options ...client.ImageHistoryOption) ([]image.HistoryResponseItem, error)
|
||||
imageBuildFunc func(context.Context, io.Reader, client.ImageBuildOptions) (client.ImageBuildResponse, error)
|
||||
imageLoadFunc func(input io.Reader, options ...client.ImageLoadOption) (client.ImageLoadResult, error)
|
||||
imageListFunc func(options client.ImageListOptions) (client.ImageListResult, error)
|
||||
imageInspectFunc func(img string) (client.ImageInspectResult, error)
|
||||
imageImportFunc func(source client.ImageImportSource, ref string, options client.ImageImportOptions) (client.ImageImportResult, error)
|
||||
imageHistoryFunc func(img string, options ...client.ImageHistoryOption) (client.ImageHistoryResult, error)
|
||||
imageBuildFunc func(context.Context, io.Reader, client.ImageBuildOptions) (client.ImageBuildResult, error)
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ImageTag(_ context.Context, img, ref string) error {
|
||||
func (cli *fakeClient) ImageTag(_ context.Context, options client.ImageTagOptions) (client.ImageTagResult, error) {
|
||||
if cli.imageTagFunc != nil {
|
||||
return cli.imageTagFunc(img, ref)
|
||||
return cli.imageTagFunc(options)
|
||||
}
|
||||
return nil
|
||||
return client.ImageTagResult{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ImageSave(_ context.Context, images []string, options ...client.ImageSaveOption) (io.ReadCloser, error) {
|
||||
func (cli *fakeClient) ImageSave(_ context.Context, images []string, options ...client.ImageSaveOption) (client.ImageSaveResult, error) {
|
||||
if cli.imageSaveFunc != nil {
|
||||
return cli.imageSaveFunc(images, options...)
|
||||
}
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
return client.ImageSaveResult{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ImageRemove(_ context.Context, img string,
|
||||
options client.ImageRemoveOptions,
|
||||
) ([]image.DeleteResponse, error) {
|
||||
func (cli *fakeClient) ImageRemove(_ context.Context, img string, options client.ImageRemoveOptions) (client.ImageRemoveResult, error) {
|
||||
if cli.imageRemoveFunc != nil {
|
||||
return cli.imageRemoveFunc(img, options)
|
||||
}
|
||||
return []image.DeleteResponse{}, nil
|
||||
return client.ImageRemoveResult{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ImagePush(_ context.Context, ref string, options client.ImagePushOptions) (io.ReadCloser, error) {
|
||||
func (cli *fakeClient) ImagePush(_ context.Context, ref string, options client.ImagePushOptions) (client.ImagePushResponse, error) {
|
||||
if cli.imagePushFunc != nil {
|
||||
return cli.imagePushFunc(ref, options)
|
||||
}
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
// FIXME(thaJeztah): how to mock this?
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) Info(_ context.Context) (system.Info, error) {
|
||||
@ -69,7 +68,8 @@ func (cli *fakeClient) ImagePull(_ context.Context, ref string, options client.I
|
||||
if cli.imagePullFunc != nil {
|
||||
return cli.imagePullFunc(ref, options)
|
||||
}
|
||||
return client.ImagePullResponse{}, nil
|
||||
// FIXME(thaJeztah): how to mock this?
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ImagesPrune(_ context.Context, opts client.ImagePruneOptions) (client.ImagePruneResult, error) {
|
||||
@ -79,46 +79,46 @@ func (cli *fakeClient) ImagesPrune(_ context.Context, opts client.ImagePruneOpti
|
||||
return client.ImagePruneResult{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ImageLoad(_ context.Context, input io.Reader, options ...client.ImageLoadOption) (client.LoadResponse, error) {
|
||||
func (cli *fakeClient) ImageLoad(_ context.Context, input io.Reader, options ...client.ImageLoadOption) (client.ImageLoadResult, error) {
|
||||
if cli.imageLoadFunc != nil {
|
||||
return cli.imageLoadFunc(input, options...)
|
||||
}
|
||||
return client.LoadResponse{}, nil
|
||||
return client.ImageLoadResult{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ImageList(_ context.Context, options client.ImageListOptions) ([]image.Summary, error) {
|
||||
func (cli *fakeClient) ImageList(_ context.Context, options client.ImageListOptions) (client.ImageListResult, error) {
|
||||
if cli.imageListFunc != nil {
|
||||
return cli.imageListFunc(options)
|
||||
}
|
||||
return []image.Summary{}, nil
|
||||
return client.ImageListResult{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ImageInspect(_ context.Context, img string, _ ...client.ImageInspectOption) (image.InspectResponse, error) {
|
||||
func (cli *fakeClient) ImageInspect(_ context.Context, img string, _ ...client.ImageInspectOption) (client.ImageInspectResult, error) {
|
||||
if cli.imageInspectFunc != nil {
|
||||
return cli.imageInspectFunc(img)
|
||||
}
|
||||
return image.InspectResponse{}, nil
|
||||
return client.ImageInspectResult{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ImageImport(_ context.Context, source client.ImageImportSource, ref string,
|
||||
options client.ImageImportOptions,
|
||||
) (io.ReadCloser, error) {
|
||||
func (cli *fakeClient) ImageImport(_ context.Context, source client.ImageImportSource, ref string, options client.ImageImportOptions) (client.ImageImportResult, error) {
|
||||
if cli.imageImportFunc != nil {
|
||||
return cli.imageImportFunc(source, ref, options)
|
||||
}
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
return client.ImageImportResult{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ImageHistory(_ context.Context, img string, options ...client.ImageHistoryOption) ([]image.HistoryResponseItem, error) {
|
||||
func (cli *fakeClient) ImageHistory(_ context.Context, img string, options ...client.ImageHistoryOption) (client.ImageHistoryResult, error) {
|
||||
if cli.imageHistoryFunc != nil {
|
||||
return cli.imageHistoryFunc(img, options...)
|
||||
}
|
||||
return []image.HistoryResponseItem{{ID: img, Created: time.Now().Unix()}}, nil
|
||||
return client.ImageHistoryResult{
|
||||
Items: []image.HistoryResponseItem{{ID: img, Created: time.Now().Unix()}},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ImageBuild(ctx context.Context, buildContext io.Reader, options client.ImageBuildOptions) (client.ImageBuildResponse, error) {
|
||||
func (cli *fakeClient) ImageBuild(ctx context.Context, buildContext io.Reader, options client.ImageBuildOptions) (client.ImageBuildResult, error) {
|
||||
if cli.imageBuildFunc != nil {
|
||||
return cli.imageBuildFunc(ctx, buildContext, options)
|
||||
}
|
||||
return client.ImageBuildResponse{Body: io.NopCloser(strings.NewReader(""))}, nil
|
||||
return client.ImageBuildResult{Body: io.NopCloser(strings.NewReader(""))}, nil
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import (
|
||||
"github.com/docker/cli/cli/command/formatter"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/moby/moby/api/types/image"
|
||||
"github.com/moby/moby/client"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -36,7 +37,7 @@ func newHistoryFormat(source string, quiet bool, human bool) formatter.Format {
|
||||
}
|
||||
|
||||
// historyWrite writes the context
|
||||
func historyWrite(fmtCtx formatter.Context, human bool, histories []image.HistoryResponseItem) error {
|
||||
func historyWrite(fmtCtx formatter.Context, human bool, history client.ImageHistoryResult) error {
|
||||
historyCtx := &historyContext{
|
||||
HeaderContext: formatter.HeaderContext{
|
||||
Header: formatter.SubHeaderContext{
|
||||
@ -50,10 +51,10 @@ func historyWrite(fmtCtx formatter.Context, human bool, histories []image.Histor
|
||||
},
|
||||
}
|
||||
return fmtCtx.Write(historyCtx, func(format func(subContext formatter.SubContext) error) error {
|
||||
for _, history := range histories {
|
||||
for _, h := range history.Items {
|
||||
if err := format(&historyContext{
|
||||
trunc: fmtCtx.Trunc,
|
||||
h: history,
|
||||
h: h,
|
||||
human: human,
|
||||
}); err != nil {
|
||||
return err
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"github.com/docker/cli/cli/command/formatter"
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/moby/moby/api/types/image"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
@ -106,8 +107,8 @@ func TestHistoryContext_CreatedSince(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHistoryContext_CreatedBy(t *testing.T) {
|
||||
const withTabs = `/bin/sh -c apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 && echo "deb http://nginx.org/packages/mainline/debian/ jessie nginx" >> /etc/apt/sources.list && apt-get update && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates nginx=${NGINX_VERSION} nginx-module-xslt nginx-module-geoip nginx-module-image-filter nginx-module-perl nginx-module-njs gettext-base && rm -rf /var/lib/apt/lists/*` //nolint:revive // ignore line-length-limit
|
||||
const expected = `/bin/sh -c apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 && echo "deb http://nginx.org/packages/mainline/debian/ jessie nginx" >> /etc/apt/sources.list && apt-get update && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates nginx=${NGINX_VERSION} nginx-module-xslt nginx-module-geoip nginx-module-image-filter nginx-module-perl nginx-module-njs gettext-base && rm -rf /var/lib/apt/lists/*` //nolint:revive // ignore line-length-limit
|
||||
const withTabs = `/bin/sh -c apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 && echo "deb https://nginx.org/packages/mainline/debian/ jessie nginx" >> /etc/apt/sources.list && apt-get update && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates nginx=${NGINX_VERSION} nginx-module-xslt nginx-module-geoip nginx-module-image-filter nginx-module-perl nginx-module-njs gettext-base && rm -rf /var/lib/apt/lists/*` //nolint:revive // ignore line-length-limit
|
||||
const expected = `/bin/sh -c apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 && echo "deb https://nginx.org/packages/mainline/debian/ jessie nginx" >> /etc/apt/sources.list && apt-get update && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates nginx=${NGINX_VERSION} nginx-module-xslt nginx-module-geoip nginx-module-image-filter nginx-module-perl nginx-module-njs gettext-base && rm -rf /var/lib/apt/lists/*` //nolint:revive // ignore line-length-limit
|
||||
|
||||
var ctx historyContext
|
||||
cases := []historyCase{
|
||||
@ -196,20 +197,22 @@ func TestHistoryContext_Table(t *testing.T) {
|
||||
out := bytes.NewBufferString("")
|
||||
unixTime := time.Now().AddDate(0, 0, -1).Unix()
|
||||
oldDate := time.Now().AddDate(-17, 0, 0).Unix()
|
||||
histories := []image.HistoryResponseItem{
|
||||
{
|
||||
ID: "imageID1",
|
||||
Created: unixTime,
|
||||
CreatedBy: "/bin/bash ls && npm i && npm run test && karma -c karma.conf.js start && npm start && more commands here && the list goes on",
|
||||
Size: int64(182964289),
|
||||
Comment: "Hi",
|
||||
Tags: []string{"image:tag2"},
|
||||
histories := client.ImageHistoryResult{
|
||||
Items: []image.HistoryResponseItem{
|
||||
{
|
||||
ID: "imageID1",
|
||||
Created: unixTime,
|
||||
CreatedBy: "/bin/bash ls && npm i && npm run test && karma -c karma.conf.js start && npm start && more commands here && the list goes on",
|
||||
Size: int64(182964289),
|
||||
Comment: "Hi",
|
||||
Tags: []string{"image:tag2"},
|
||||
},
|
||||
{ID: "imageID2", Created: unixTime, CreatedBy: "/bin/bash echo", Size: int64(182964289), Comment: "Hi", Tags: []string{"image:tag2"}},
|
||||
{ID: "imageID3", Created: unixTime, CreatedBy: "/bin/bash ls", Size: int64(182964289), Comment: "Hi", Tags: []string{"image:tag2"}},
|
||||
{ID: "imageID4", Created: unixTime, CreatedBy: "/bin/bash grep", Size: int64(182964289), Comment: "Hi", Tags: []string{"image:tag2"}},
|
||||
{ID: "imageID5", Created: 0, CreatedBy: "/bin/bash echo", Size: int64(182964289), Comment: "Hi", Tags: []string{"image:tag2"}},
|
||||
{ID: "imageID6", Created: oldDate, CreatedBy: "/bin/bash echo", Size: int64(182964289), Comment: "Hi", Tags: []string{"image:tag2"}},
|
||||
},
|
||||
{ID: "imageID2", Created: unixTime, CreatedBy: "/bin/bash echo", Size: int64(182964289), Comment: "Hi", Tags: []string{"image:tag2"}},
|
||||
{ID: "imageID3", Created: unixTime, CreatedBy: "/bin/bash ls", Size: int64(182964289), Comment: "Hi", Tags: []string{"image:tag2"}},
|
||||
{ID: "imageID4", Created: unixTime, CreatedBy: "/bin/bash grep", Size: int64(182964289), Comment: "Hi", Tags: []string{"image:tag2"}},
|
||||
{ID: "imageID5", Created: 0, CreatedBy: "/bin/bash echo", Size: int64(182964289), Comment: "Hi", Tags: []string{"image:tag2"}},
|
||||
{ID: "imageID6", Created: oldDate, CreatedBy: "/bin/bash echo", Size: int64(182964289), Comment: "Hi", Tags: []string{"image:tag2"}},
|
||||
}
|
||||
|
||||
//nolint:dupword // ignore "Duplicate words (CREATED) found"
|
||||
|
||||
@ -19,7 +19,7 @@ func TestNewHistoryCommandErrors(t *testing.T) {
|
||||
name string
|
||||
args []string
|
||||
expectedError string
|
||||
imageHistoryFunc func(img string, options ...client.ImageHistoryOption) ([]image.HistoryResponseItem, error)
|
||||
imageHistoryFunc func(img string, options ...client.ImageHistoryOption) (client.ImageHistoryResult, error)
|
||||
}{
|
||||
{
|
||||
name: "wrong-args",
|
||||
@ -30,8 +30,8 @@ func TestNewHistoryCommandErrors(t *testing.T) {
|
||||
name: "client-error",
|
||||
args: []string{"image:tag"},
|
||||
expectedError: "something went wrong",
|
||||
imageHistoryFunc: func(string, ...client.ImageHistoryOption) ([]image.HistoryResponseItem, error) {
|
||||
return []image.HistoryResponseItem{{}}, errors.New("something went wrong")
|
||||
imageHistoryFunc: func(string, ...client.ImageHistoryOption) (client.ImageHistoryResult, error) {
|
||||
return client.ImageHistoryResult{}, errors.New("something went wrong")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -55,17 +55,19 @@ func TestNewHistoryCommandSuccess(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
imageHistoryFunc func(img string, options ...client.ImageHistoryOption) ([]image.HistoryResponseItem, error)
|
||||
imageHistoryFunc func(img string, options ...client.ImageHistoryOption) (client.ImageHistoryResult, error)
|
||||
}{
|
||||
{
|
||||
name: "simple",
|
||||
args: []string{"image:tag"},
|
||||
imageHistoryFunc: func(string, ...client.ImageHistoryOption) ([]image.HistoryResponseItem, error) {
|
||||
return []image.HistoryResponseItem{{
|
||||
ID: "1234567890123456789",
|
||||
Created: time.Now().Unix(),
|
||||
Comment: "none",
|
||||
}}, nil
|
||||
imageHistoryFunc: func(string, ...client.ImageHistoryOption) (client.ImageHistoryResult, error) {
|
||||
return client.ImageHistoryResult{
|
||||
Items: []image.HistoryResponseItem{{
|
||||
ID: "1234567890123456789",
|
||||
Created: time.Now().Unix(),
|
||||
Comment: "none",
|
||||
}},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -75,36 +77,42 @@ func TestNewHistoryCommandSuccess(t *testing.T) {
|
||||
{
|
||||
name: "non-human",
|
||||
args: []string{"--human=false", "image:tag"},
|
||||
imageHistoryFunc: func(string, ...client.ImageHistoryOption) ([]image.HistoryResponseItem, error) {
|
||||
return []image.HistoryResponseItem{{
|
||||
ID: "abcdef",
|
||||
Created: time.Date(2017, 1, 1, 12, 0, 3, 0, time.UTC).Unix(),
|
||||
CreatedBy: "rose",
|
||||
Comment: "new history item!",
|
||||
}}, nil
|
||||
imageHistoryFunc: func(string, ...client.ImageHistoryOption) (client.ImageHistoryResult, error) {
|
||||
return client.ImageHistoryResult{
|
||||
Items: []image.HistoryResponseItem{{
|
||||
ID: "abcdef",
|
||||
Created: time.Date(2017, 1, 1, 12, 0, 3, 0, time.UTC).Unix(),
|
||||
CreatedBy: "rose",
|
||||
Comment: "new history item!",
|
||||
}},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "quiet-no-trunc",
|
||||
args: []string{"--quiet", "--no-trunc", "image:tag"},
|
||||
imageHistoryFunc: func(string, ...client.ImageHistoryOption) ([]image.HistoryResponseItem, error) {
|
||||
return []image.HistoryResponseItem{{
|
||||
ID: "1234567890123456789",
|
||||
Created: time.Now().Unix(),
|
||||
}}, nil
|
||||
imageHistoryFunc: func(string, ...client.ImageHistoryOption) (client.ImageHistoryResult, error) {
|
||||
return client.ImageHistoryResult{
|
||||
Items: []image.HistoryResponseItem{{
|
||||
ID: "1234567890123456789",
|
||||
Created: time.Now().Unix(),
|
||||
}},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "platform",
|
||||
args: []string{"--platform", "linux/amd64", "image:tag"},
|
||||
imageHistoryFunc: func(img string, options ...client.ImageHistoryOption) ([]image.HistoryResponseItem, error) {
|
||||
imageHistoryFunc: func(img string, options ...client.ImageHistoryOption) (client.ImageHistoryResult, error) {
|
||||
// FIXME(thaJeztah): need to find appropriate way to test the result of "ImageHistoryWithPlatform" being applied
|
||||
assert.Check(t, len(options) > 0) // can be 1 or two depending on whether a terminal is attached :/
|
||||
// assert.Check(t, is.Contains(options, client.ImageHistoryWithPlatform(ocispec.Platform{OS: "linux", Architecture: "amd64"})))
|
||||
return []image.HistoryResponseItem{{
|
||||
ID: "1234567890123456789",
|
||||
Created: time.Now().Unix(),
|
||||
}}, nil
|
||||
return client.ImageHistoryResult{
|
||||
Items: []image.HistoryResponseItem{{
|
||||
ID: "1234567890123456789",
|
||||
Created: time.Now().Unix(),
|
||||
}},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -3,7 +3,6 @@ package image
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/cli/internal/test"
|
||||
@ -17,7 +16,7 @@ func TestNewImportCommandErrors(t *testing.T) {
|
||||
name string
|
||||
args []string
|
||||
expectedError string
|
||||
imageImportFunc func(source client.ImageImportSource, ref string, options client.ImageImportOptions) (io.ReadCloser, error)
|
||||
imageImportFunc func(source client.ImageImportSource, ref string, options client.ImageImportOptions) (client.ImageImportResult, error)
|
||||
}{
|
||||
{
|
||||
name: "wrong-args",
|
||||
@ -28,8 +27,8 @@ func TestNewImportCommandErrors(t *testing.T) {
|
||||
name: "import-failed",
|
||||
args: []string{"testdata/import-command-success.input.txt"},
|
||||
expectedError: "something went wrong",
|
||||
imageImportFunc: func(source client.ImageImportSource, ref string, options client.ImageImportOptions) (io.ReadCloser, error) {
|
||||
return nil, errors.New("something went wrong")
|
||||
imageImportFunc: func(source client.ImageImportSource, ref string, options client.ImageImportOptions) (client.ImageImportResult, error) {
|
||||
return client.ImageImportResult{}, errors.New("something went wrong")
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -51,10 +50,11 @@ func TestNewImportCommandInvalidFile(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewImportCommandSuccess(t *testing.T) {
|
||||
t.Skip("FIXME(thaJeztah): how to mock this?")
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
imageImportFunc func(source client.ImageImportSource, ref string, options client.ImageImportOptions) (io.ReadCloser, error)
|
||||
imageImportFunc func(source client.ImageImportSource, ref string, options client.ImageImportOptions) (client.ImageImportResult, error)
|
||||
}{
|
||||
{
|
||||
name: "simple",
|
||||
@ -67,33 +67,33 @@ func TestNewImportCommandSuccess(t *testing.T) {
|
||||
{
|
||||
name: "double",
|
||||
args: []string{"-", "image:local"},
|
||||
imageImportFunc: func(source client.ImageImportSource, ref string, options client.ImageImportOptions) (io.ReadCloser, error) {
|
||||
imageImportFunc: func(source client.ImageImportSource, ref string, options client.ImageImportOptions) (client.ImageImportResult, error) {
|
||||
assert.Check(t, is.Equal("image:local", ref))
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
return client.ImageImportResult{}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "message",
|
||||
args: []string{"--message", "test message", "-"},
|
||||
imageImportFunc: func(source client.ImageImportSource, ref string, options client.ImageImportOptions) (io.ReadCloser, error) {
|
||||
imageImportFunc: func(source client.ImageImportSource, ref string, options client.ImageImportOptions) (client.ImageImportResult, error) {
|
||||
assert.Check(t, is.Equal("test message", options.Message))
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
return client.ImageImportResult{}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change",
|
||||
args: []string{"--change", "ENV DEBUG=true", "-"},
|
||||
imageImportFunc: func(source client.ImageImportSource, ref string, options client.ImageImportOptions) (io.ReadCloser, error) {
|
||||
imageImportFunc: func(source client.ImageImportSource, ref string, options client.ImageImportOptions) (client.ImageImportResult, error) {
|
||||
assert.Check(t, is.Equal("ENV DEBUG=true", options.Changes[0]))
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
return client.ImageImportResult{}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change legacy syntax",
|
||||
args: []string{"--change", "ENV DEBUG true", "-"},
|
||||
imageImportFunc: func(source client.ImageImportSource, ref string, options client.ImageImportOptions) (io.ReadCloser, error) {
|
||||
imageImportFunc: func(source client.ImageImportSource, ref string, options client.ImageImportOptions) (client.ImageImportResult, error) {
|
||||
assert.Check(t, is.Equal("ENV DEBUG true", options.Changes[0]))
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
return client.ImageImportResult{}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/moby/moby/api/types/image"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
"gotest.tools/v3/golden"
|
||||
@ -41,39 +42,41 @@ func TestNewInspectCommandSuccess(t *testing.T) {
|
||||
name string
|
||||
args []string
|
||||
imageCount int
|
||||
imageInspectFunc func(img string) (image.InspectResponse, error)
|
||||
imageInspectFunc func(img string) (client.ImageInspectResult, error)
|
||||
}{
|
||||
{
|
||||
name: "simple",
|
||||
args: []string{"image"},
|
||||
imageCount: 1,
|
||||
imageInspectFunc: func(img string) (image.InspectResponse, error) {
|
||||
imageInspectFunc: func(img string) (client.ImageInspectResult, error) {
|
||||
imageInspectInvocationCount++
|
||||
assert.Check(t, is.Equal("image", img))
|
||||
return image.InspectResponse{}, nil
|
||||
return client.ImageInspectResult{}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "format",
|
||||
imageCount: 1,
|
||||
args: []string{"--format='{{.ID}}'", "image"},
|
||||
imageInspectFunc: func(img string) (image.InspectResponse, error) {
|
||||
imageInspectFunc: func(img string) (client.ImageInspectResult, error) {
|
||||
imageInspectInvocationCount++
|
||||
return image.InspectResponse{ID: img}, nil
|
||||
return client.ImageInspectResult{
|
||||
InspectResponse: image.InspectResponse{ID: img},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "simple-many",
|
||||
args: []string{"image1", "image2"},
|
||||
imageCount: 2,
|
||||
imageInspectFunc: func(img string) (image.InspectResponse, error) {
|
||||
imageInspectFunc: func(img string) (client.ImageInspectResult, error) {
|
||||
imageInspectInvocationCount++
|
||||
if imageInspectInvocationCount == 1 {
|
||||
assert.Check(t, is.Equal("image1", img))
|
||||
} else {
|
||||
assert.Check(t, is.Equal("image2", img))
|
||||
}
|
||||
return image.InspectResponse{}, nil
|
||||
return client.ImageInspectResult{}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -130,10 +130,10 @@ func runImages(ctx context.Context, dockerCLI command.Cli, options imagesOptions
|
||||
},
|
||||
Digest: options.showDigests,
|
||||
}
|
||||
if err := formatter.ImageWrite(imageCtx, images); err != nil {
|
||||
if err := formatter.ImageWrite(imageCtx, images.Items); err != nil {
|
||||
return err
|
||||
}
|
||||
if options.matchName != "" && len(images) == 0 && options.calledAs == "images" {
|
||||
if options.matchName != "" && len(images.Items) == 0 && options.calledAs == "images" {
|
||||
printAmbiguousHint(dockerCLI.Err(), options.matchName)
|
||||
}
|
||||
return nil
|
||||
|
||||
@ -8,7 +8,6 @@ import (
|
||||
|
||||
"github.com/docker/cli/cli/config/configfile"
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/moby/moby/api/types/image"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
"gotest.tools/v3/golden"
|
||||
@ -19,7 +18,7 @@ func TestNewImagesCommandErrors(t *testing.T) {
|
||||
name string
|
||||
args []string
|
||||
expectedError string
|
||||
imageListFunc func(options client.ImageListOptions) ([]image.Summary, error)
|
||||
imageListFunc func(options client.ImageListOptions) (client.ImageListResult, error)
|
||||
}{
|
||||
{
|
||||
name: "wrong-args",
|
||||
@ -29,8 +28,8 @@ func TestNewImagesCommandErrors(t *testing.T) {
|
||||
{
|
||||
name: "failed-list",
|
||||
expectedError: "something went wrong",
|
||||
imageListFunc: func(options client.ImageListOptions) ([]image.Summary, error) {
|
||||
return []image.Summary{}, errors.New("something went wrong")
|
||||
imageListFunc: func(options client.ImageListOptions) (client.ImageListResult, error) {
|
||||
return client.ImageListResult{}, errors.New("something went wrong")
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -50,7 +49,7 @@ func TestNewImagesCommandSuccess(t *testing.T) {
|
||||
name string
|
||||
args []string
|
||||
imageFormat string
|
||||
imageListFunc func(options client.ImageListOptions) ([]image.Summary, error)
|
||||
imageListFunc func(options client.ImageListOptions) (client.ImageListResult, error)
|
||||
}{
|
||||
{
|
||||
name: "simple",
|
||||
@ -67,17 +66,17 @@ func TestNewImagesCommandSuccess(t *testing.T) {
|
||||
{
|
||||
name: "match-name",
|
||||
args: []string{"image"},
|
||||
imageListFunc: func(options client.ImageListOptions) ([]image.Summary, error) {
|
||||
imageListFunc: func(options client.ImageListOptions) (client.ImageListResult, error) {
|
||||
assert.Check(t, options.Filters["reference"]["image"])
|
||||
return []image.Summary{}, nil
|
||||
return client.ImageListResult{}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "filters",
|
||||
args: []string{"--filter", "name=value"},
|
||||
imageListFunc: func(options client.ImageListOptions) ([]image.Summary, error) {
|
||||
imageListFunc: func(options client.ImageListOptions) (client.ImageListResult, error) {
|
||||
assert.Check(t, options.Filters["name"]["value"])
|
||||
return []image.Summary{}, nil
|
||||
return client.ImageListResult{}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -91,16 +91,16 @@ func runLoad(ctx context.Context, dockerCli command.Cli, opts loadOptions) error
|
||||
options = append(options, client.ImageLoadWithPlatforms(platformList...))
|
||||
}
|
||||
|
||||
response, err := dockerCli.Client().ImageLoad(ctx, input, options...)
|
||||
res, err := dockerCli.Client().ImageLoad(ctx, input, options...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
defer res.Close()
|
||||
|
||||
if response.Body != nil && response.JSON {
|
||||
return jsonstream.Display(ctx, response.Body, dockerCli.Out())
|
||||
if res.JSON {
|
||||
return jsonstream.Display(ctx, res, dockerCli.Out())
|
||||
}
|
||||
|
||||
_, err = io.Copy(dockerCli.Out(), response.Body)
|
||||
_, err = io.Copy(dockerCli.Out(), res)
|
||||
return err
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/cli/internal/test"
|
||||
@ -19,7 +18,7 @@ func TestNewLoadCommandErrors(t *testing.T) {
|
||||
args []string
|
||||
isTerminalIn bool
|
||||
expectedError string
|
||||
imageLoadFunc func(input io.Reader, options ...client.ImageLoadOption) (client.LoadResponse, error)
|
||||
imageLoadFunc func(input io.Reader, options ...client.ImageLoadOption) (client.ImageLoadResult, error)
|
||||
}{
|
||||
{
|
||||
name: "wrong-args",
|
||||
@ -36,16 +35,16 @@ func TestNewLoadCommandErrors(t *testing.T) {
|
||||
name: "pull-error",
|
||||
args: []string{},
|
||||
expectedError: "something went wrong",
|
||||
imageLoadFunc: func(io.Reader, ...client.ImageLoadOption) (client.LoadResponse, error) {
|
||||
return client.LoadResponse{}, errors.New("something went wrong")
|
||||
imageLoadFunc: func(input io.Reader, options ...client.ImageLoadOption) (client.ImageLoadResult, error) {
|
||||
return client.ImageLoadResult{}, errors.New("something went wrong")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid platform",
|
||||
args: []string{"--platform", "<invalid>"},
|
||||
expectedError: `invalid platform`,
|
||||
imageLoadFunc: func(io.Reader, ...client.ImageLoadOption) (client.LoadResponse, error) {
|
||||
return client.LoadResponse{}, nil
|
||||
imageLoadFunc: func(input io.Reader, options ...client.ImageLoadOption) (client.ImageLoadResult, error) {
|
||||
return client.ImageLoadResult{}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -73,59 +72,73 @@ func TestNewLoadCommandInvalidInput(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewLoadCommandSuccess(t *testing.T) {
|
||||
t.Skip("FIXME(thaJeztah): how to mock this?")
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
imageLoadFunc func(input io.Reader, options ...client.ImageLoadOption) (client.LoadResponse, error)
|
||||
imageLoadFunc func(input io.Reader, options ...client.ImageLoadOption) (client.ImageLoadResult, error)
|
||||
}{
|
||||
{
|
||||
name: "simple",
|
||||
args: []string{},
|
||||
imageLoadFunc: func(io.Reader, ...client.ImageLoadOption) (client.LoadResponse, error) {
|
||||
return client.LoadResponse{Body: io.NopCloser(strings.NewReader("Success"))}, nil
|
||||
imageLoadFunc: func(input io.Reader, options ...client.ImageLoadOption) (client.ImageLoadResult, error) {
|
||||
// FIXME(thaJeztah): how to mock this?
|
||||
// return client.ImageLoadResult{Body: io.NopCloser(strings.NewReader("Success"))}, nil
|
||||
return client.ImageLoadResult{}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "json",
|
||||
args: []string{},
|
||||
imageLoadFunc: func(io.Reader, ...client.ImageLoadOption) (client.LoadResponse, error) {
|
||||
return client.LoadResponse{
|
||||
Body: io.NopCloser(strings.NewReader(`{"ID": "1"}`)),
|
||||
JSON: true,
|
||||
}, nil
|
||||
imageLoadFunc: func(input io.Reader, options ...client.ImageLoadOption) (client.ImageLoadResult, error) {
|
||||
// FIXME(thaJeztah): how to mock this?
|
||||
// return client.ImageLoadResult{Body: io.NopCloser(strings.NewReader("Success"))}, nil
|
||||
// return client.ImageLoadResult{
|
||||
// Body: io.NopCloser(strings.NewReader(`{"ID": "1"}`)),
|
||||
// JSON: true,
|
||||
// }, nil
|
||||
return client.ImageLoadResult{}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "input-file",
|
||||
args: []string{"--input", "testdata/load-command-success.input.txt"},
|
||||
imageLoadFunc: func(input io.Reader, options ...client.ImageLoadOption) (client.LoadResponse, error) {
|
||||
return client.LoadResponse{Body: io.NopCloser(strings.NewReader("Success"))}, nil
|
||||
imageLoadFunc: func(input io.Reader, options ...client.ImageLoadOption) (client.ImageLoadResult, error) {
|
||||
// FIXME(thaJeztah): how to mock this?
|
||||
// return client.ImageLoadResult{Body: io.NopCloser(strings.NewReader("Success"))}, nil
|
||||
return client.ImageLoadResult{}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with-single-platform",
|
||||
args: []string{"--platform", "linux/amd64"},
|
||||
imageLoadFunc: func(input io.Reader, options ...client.ImageLoadOption) (client.LoadResponse, error) {
|
||||
imageLoadFunc: func(input io.Reader, options ...client.ImageLoadOption) (client.ImageLoadResult, error) {
|
||||
// FIXME(thaJeztah): need to find appropriate way to test the result of "ImageHistoryWithPlatform" being applied
|
||||
assert.Check(t, len(options) > 0) // can be 1 or two depending on whether a terminal is attached :/
|
||||
// assert.Check(t, is.Contains(options, client.ImageHistoryWithPlatform(ocispec.Platform{OS: "linux", Architecture: "amd64"})))
|
||||
return client.LoadResponse{Body: io.NopCloser(strings.NewReader("Success"))}, nil
|
||||
// FIXME(thaJeztah): how to mock this?
|
||||
// return client.ImageLoadResult{Body: io.NopCloser(strings.NewReader("Success"))}, nil
|
||||
return client.ImageLoadResult{}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with-comma-separated-platforms",
|
||||
args: []string{"--platform", "linux/amd64,linux/arm64/v8,linux/riscv64"},
|
||||
imageLoadFunc: func(input io.Reader, options ...client.ImageLoadOption) (client.LoadResponse, error) {
|
||||
imageLoadFunc: func(input io.Reader, options ...client.ImageLoadOption) (client.ImageLoadResult, error) {
|
||||
assert.Check(t, len(options) > 0) // can be 1 or two depending on whether a terminal is attached :/
|
||||
return client.LoadResponse{Body: io.NopCloser(strings.NewReader("Success"))}, nil
|
||||
// FIXME(thaJeztah): how to mock this?
|
||||
// return client.ImageLoadResult{Body: io.NopCloser(strings.NewReader("Success"))}, nil
|
||||
return client.ImageLoadResult{}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with-multiple-platform-options",
|
||||
args: []string{"--platform", "linux/amd64", "--platform", "linux/arm64/v8", "--platform", "linux/riscv64"},
|
||||
imageLoadFunc: func(input io.Reader, options ...client.ImageLoadOption) (client.LoadResponse, error) {
|
||||
imageLoadFunc: func(input io.Reader, options ...client.ImageLoadOption) (client.ImageLoadResult, error) {
|
||||
assert.Check(t, len(options) > 0) // can be 1 or two depending on whether a terminal is attached :/
|
||||
return client.LoadResponse{Body: io.NopCloser(strings.NewReader("Success"))}, nil
|
||||
// FIXME(thaJeztah): how to mock this?
|
||||
// return client.ImageLoadResult{Body: io.NopCloser(strings.NewReader("Success"))}, nil
|
||||
return client.ImageLoadResult{}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -49,6 +49,7 @@ func TestNewPullCommandErrors(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewPullCommandSuccess(t *testing.T) {
|
||||
t.Skip("FIXME(thaJeztah): how to mock this?")
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
@ -75,7 +76,8 @@ func TestNewPullCommandSuccess(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
imagePullFunc: func(ref string, options client.ImagePullOptions) (client.ImagePullResponse, error) {
|
||||
assert.Check(t, is.Equal(tc.expectedTag, ref), tc.name)
|
||||
return client.ImagePullResponse{}, nil
|
||||
// FIXME(thaJeztah): how to mock this?
|
||||
return nil, nil
|
||||
},
|
||||
})
|
||||
cmd := newPullCommand(cli)
|
||||
@ -120,7 +122,8 @@ func TestNewPullCommandWithContentTrustErrors(t *testing.T) {
|
||||
t.Setenv("DOCKER_CONTENT_TRUST", "true")
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
imagePullFunc: func(ref string, options client.ImagePullOptions) (client.ImagePullResponse, error) {
|
||||
return client.ImagePullResponse{}, errors.New("shouldn't try to pull image")
|
||||
// FIXME(thaJeztah): how to mock this?
|
||||
return nil, errors.New("shouldn't try to pull image")
|
||||
},
|
||||
})
|
||||
cli.SetNotaryClient(tc.notaryFunc)
|
||||
|
||||
@ -3,7 +3,6 @@ package image
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/cli/internal/test"
|
||||
@ -16,7 +15,7 @@ func TestNewPushCommandErrors(t *testing.T) {
|
||||
name string
|
||||
args []string
|
||||
expectedError string
|
||||
imagePushFunc func(ref string, options client.ImagePushOptions) (io.ReadCloser, error)
|
||||
imagePushFunc func(ref string, options client.ImagePushOptions) (client.ImagePushResponse, error)
|
||||
}{
|
||||
{
|
||||
name: "wrong-args",
|
||||
@ -31,9 +30,9 @@ func TestNewPushCommandErrors(t *testing.T) {
|
||||
{
|
||||
name: "push-failed",
|
||||
args: []string{"image:repo"},
|
||||
expectedError: "Failed to push",
|
||||
imagePushFunc: func(ref string, options client.ImagePushOptions) (io.ReadCloser, error) {
|
||||
return io.NopCloser(strings.NewReader("")), errors.New("Failed to push")
|
||||
expectedError: "failed to push",
|
||||
imagePushFunc: func(ref string, options client.ImagePushOptions) (client.ImagePushResponse, error) {
|
||||
return nil, errors.New("failed to push")
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -50,6 +49,7 @@ func TestNewPushCommandErrors(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewPushCommandSuccess(t *testing.T) {
|
||||
t.Skip("FIXME(thaJeztah): how to mock this?")
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
@ -66,11 +66,13 @@ func TestNewPushCommandSuccess(t *testing.T) {
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
imagePushFunc: func(ref string, options client.ImagePushOptions) (io.ReadCloser, error) {
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
imagePushFunc: func(ref string, options client.ImagePushOptions) (client.ImagePushResponse, error) {
|
||||
// FIXME(thaJeztah): how to mock this?
|
||||
return nil, nil
|
||||
},
|
||||
})
|
||||
cmd := newPushCommand(cli)
|
||||
|
||||
@ -79,14 +79,14 @@ func runRemove(ctx context.Context, dockerCLI command.Cli, opts removeOptions, i
|
||||
fatalErr := false
|
||||
var errs []error
|
||||
for _, img := range images {
|
||||
dels, err := apiClient.ImageRemove(ctx, img, options)
|
||||
res, err := apiClient.ImageRemove(ctx, img, options)
|
||||
if err != nil {
|
||||
if !errdefs.IsNotFound(err) {
|
||||
fatalErr = true
|
||||
}
|
||||
errs = append(errs, err)
|
||||
} else {
|
||||
for _, del := range dels {
|
||||
for _, del := range res.Deleted {
|
||||
if del.Deleted != "" {
|
||||
_, _ = fmt.Fprintln(dockerCLI.Out(), "Deleted:", del.Deleted)
|
||||
} else {
|
||||
|
||||
@ -36,7 +36,7 @@ func TestNewRemoveCommandErrors(t *testing.T) {
|
||||
name string
|
||||
args []string
|
||||
expectedError string
|
||||
imageRemoveFunc func(img string, options client.ImageRemoveOptions) ([]image.DeleteResponse, error)
|
||||
imageRemoveFunc func(img string, options client.ImageRemoveOptions) (client.ImageRemoveResult, error)
|
||||
}{
|
||||
{
|
||||
name: "wrong args",
|
||||
@ -46,19 +46,19 @@ func TestNewRemoveCommandErrors(t *testing.T) {
|
||||
name: "ImageRemove fail with force option",
|
||||
args: []string{"-f", "image1"},
|
||||
expectedError: "error removing image",
|
||||
imageRemoveFunc: func(img string, options client.ImageRemoveOptions) ([]image.DeleteResponse, error) {
|
||||
imageRemoveFunc: func(img string, options client.ImageRemoveOptions) (client.ImageRemoveResult, error) {
|
||||
assert.Check(t, is.Equal("image1", img))
|
||||
return []image.DeleteResponse{}, errors.New("error removing image")
|
||||
return client.ImageRemoveResult{}, errors.New("error removing image")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ImageRemove fail",
|
||||
args: []string{"arg1"},
|
||||
expectedError: "error removing image",
|
||||
imageRemoveFunc: func(img string, options client.ImageRemoveOptions) ([]image.DeleteResponse, error) {
|
||||
imageRemoveFunc: func(img string, options client.ImageRemoveOptions) (client.ImageRemoveResult, error) {
|
||||
assert.Check(t, !options.Force)
|
||||
assert.Check(t, options.PruneChildren)
|
||||
return []image.DeleteResponse{}, errors.New("error removing image")
|
||||
return client.ImageRemoveResult{}, errors.New("error removing image")
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -79,24 +79,26 @@ func TestNewRemoveCommandSuccess(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
imageRemoveFunc func(img string, options client.ImageRemoveOptions) ([]image.DeleteResponse, error)
|
||||
imageRemoveFunc func(img string, options client.ImageRemoveOptions) (client.ImageRemoveResult, error)
|
||||
expectedStderr string
|
||||
}{
|
||||
{
|
||||
name: "Image Deleted",
|
||||
args: []string{"image1"},
|
||||
imageRemoveFunc: func(img string, options client.ImageRemoveOptions) ([]image.DeleteResponse, error) {
|
||||
imageRemoveFunc: func(img string, options client.ImageRemoveOptions) (client.ImageRemoveResult, error) {
|
||||
assert.Check(t, is.Equal("image1", img))
|
||||
return []image.DeleteResponse{{Deleted: img}}, nil
|
||||
return client.ImageRemoveResult{
|
||||
Deleted: []image.DeleteResponse{{Deleted: img}},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Image not found with force option",
|
||||
args: []string{"-f", "image1"},
|
||||
imageRemoveFunc: func(img string, options client.ImageRemoveOptions) ([]image.DeleteResponse, error) {
|
||||
imageRemoveFunc: func(img string, options client.ImageRemoveOptions) (client.ImageRemoveResult, error) {
|
||||
assert.Check(t, is.Equal("image1", img))
|
||||
assert.Check(t, is.Equal(true, options.Force))
|
||||
return []image.DeleteResponse{}, notFound{"image1"}
|
||||
return client.ImageRemoveResult{}, notFound{"image1"}
|
||||
},
|
||||
expectedStderr: "Error: No such image: image1\n",
|
||||
},
|
||||
@ -104,19 +106,25 @@ func TestNewRemoveCommandSuccess(t *testing.T) {
|
||||
{
|
||||
name: "Image Untagged",
|
||||
args: []string{"image1"},
|
||||
imageRemoveFunc: func(img string, options client.ImageRemoveOptions) ([]image.DeleteResponse, error) {
|
||||
imageRemoveFunc: func(img string, options client.ImageRemoveOptions) (client.ImageRemoveResult, error) {
|
||||
assert.Check(t, is.Equal("image1", img))
|
||||
return []image.DeleteResponse{{Untagged: img}}, nil
|
||||
return client.ImageRemoveResult{
|
||||
Deleted: []image.DeleteResponse{{Untagged: img}},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Image Deleted and Untagged",
|
||||
args: []string{"image1", "image2"},
|
||||
imageRemoveFunc: func(img string, options client.ImageRemoveOptions) ([]image.DeleteResponse, error) {
|
||||
imageRemoveFunc: func(img string, options client.ImageRemoveOptions) (client.ImageRemoveResult, error) {
|
||||
if img == "image1" {
|
||||
return []image.DeleteResponse{{Untagged: img}}, nil
|
||||
return client.ImageRemoveResult{
|
||||
Deleted: []image.DeleteResponse{{Untagged: img}},
|
||||
}, nil
|
||||
}
|
||||
return []image.DeleteResponse{{Deleted: img}}, nil
|
||||
return client.ImageRemoveResult{
|
||||
Deleted: []image.DeleteResponse{{Deleted: img}},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ func TestNewSaveCommandErrors(t *testing.T) {
|
||||
args []string
|
||||
isTerminal bool
|
||||
expectedError string
|
||||
imageSaveFunc func(images []string, options ...client.ImageSaveOption) (io.ReadCloser, error)
|
||||
imageSaveFunc func(images []string, options ...client.ImageSaveOption) (client.ImageSaveResult, error)
|
||||
}{
|
||||
{
|
||||
name: "wrong args",
|
||||
@ -37,14 +37,14 @@ func TestNewSaveCommandErrors(t *testing.T) {
|
||||
args: []string{"arg1"},
|
||||
isTerminal: false,
|
||||
expectedError: "error saving image",
|
||||
imageSaveFunc: func([]string, ...client.ImageSaveOption) (io.ReadCloser, error) {
|
||||
return io.NopCloser(strings.NewReader("")), errors.New("error saving image")
|
||||
imageSaveFunc: func(images []string, options ...client.ImageSaveOption) (client.ImageSaveResult, error) {
|
||||
return client.ImageSaveResult{}, errors.New("error saving image")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "output directory does not exist",
|
||||
args: []string{"-o", "fakedir/out.tar", "arg1"},
|
||||
expectedError: `failed to save image: invalid output path: stat fakedir: no such file or directory`,
|
||||
args: []string{"-o", "fake-dir/out.tar", "arg1"},
|
||||
expectedError: `failed to save image: invalid output path: stat fake-dir: no such file or directory`,
|
||||
},
|
||||
{
|
||||
name: "output file is irregular",
|
||||
@ -74,16 +74,16 @@ func TestNewSaveCommandSuccess(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
isTerminal bool
|
||||
imageSaveFunc func(images []string, options ...client.ImageSaveOption) (io.ReadCloser, error)
|
||||
imageSaveFunc func(images []string, options ...client.ImageSaveOption) (client.ImageSaveResult, error)
|
||||
deferredFunc func()
|
||||
}{
|
||||
{
|
||||
args: []string{"-o", "save_tmp_file", "arg1"},
|
||||
isTerminal: true,
|
||||
imageSaveFunc: func(images []string, _ ...client.ImageSaveOption) (io.ReadCloser, error) {
|
||||
imageSaveFunc: func(images []string, options ...client.ImageSaveOption) (client.ImageSaveResult, error) {
|
||||
assert.Assert(t, is.Len(images, 1))
|
||||
assert.Check(t, is.Equal("arg1", images[0]))
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
return client.ImageSaveResult{}, nil
|
||||
},
|
||||
deferredFunc: func() {
|
||||
_ = os.Remove("save_tmp_file")
|
||||
@ -92,43 +92,43 @@ func TestNewSaveCommandSuccess(t *testing.T) {
|
||||
{
|
||||
args: []string{"arg1", "arg2"},
|
||||
isTerminal: false,
|
||||
imageSaveFunc: func(images []string, _ ...client.ImageSaveOption) (io.ReadCloser, error) {
|
||||
imageSaveFunc: func(images []string, options ...client.ImageSaveOption) (client.ImageSaveResult, error) {
|
||||
assert.Assert(t, is.Len(images, 2))
|
||||
assert.Check(t, is.Equal("arg1", images[0]))
|
||||
assert.Check(t, is.Equal("arg2", images[1]))
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
return client.ImageSaveResult{}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
args: []string{"--platform", "linux/amd64", "arg1"},
|
||||
isTerminal: false,
|
||||
imageSaveFunc: func(images []string, options ...client.ImageSaveOption) (io.ReadCloser, error) {
|
||||
imageSaveFunc: func(images []string, options ...client.ImageSaveOption) (client.ImageSaveResult, error) {
|
||||
assert.Assert(t, is.Len(images, 1))
|
||||
assert.Check(t, is.Equal("arg1", images[0]))
|
||||
// FIXME(thaJeztah): need to find appropriate way to test the result of "ImageHistoryWithPlatform" being applied
|
||||
assert.Check(t, len(options) > 0) // can be 1 or two depending on whether a terminal is attached :/
|
||||
// assert.Check(t, is.Contains(options, client.ImageHistoryWithPlatform(ocispec.Platform{OS: "linux", Architecture: "amd64"})))
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
return client.ImageSaveResult{}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
args: []string{"--platform", "linux/amd64,linux/arm64/v8,linux/riscv64", "arg1"},
|
||||
isTerminal: false,
|
||||
imageSaveFunc: func(images []string, options ...client.ImageSaveOption) (io.ReadCloser, error) {
|
||||
imageSaveFunc: func(images []string, options ...client.ImageSaveOption) (client.ImageSaveResult, error) {
|
||||
assert.Assert(t, is.Len(images, 1))
|
||||
assert.Check(t, is.Equal("arg1", images[0]))
|
||||
assert.Check(t, len(options) > 0) // can be 1 or 2 depending on whether a terminal is attached :/
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
return client.ImageSaveResult{}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
args: []string{"--platform", "linux/amd64", "--platform", "linux/arm64/v8", "--platform", "linux/riscv64", "arg1"},
|
||||
isTerminal: false,
|
||||
imageSaveFunc: func(images []string, options ...client.ImageSaveOption) (io.ReadCloser, error) {
|
||||
imageSaveFunc: func(images []string, options ...client.ImageSaveOption) (client.ImageSaveResult, error) {
|
||||
assert.Assert(t, is.Len(images, 1))
|
||||
assert.Check(t, is.Equal("arg1", images[0]))
|
||||
assert.Check(t, len(options) > 0) // can be 1 or 2 depending on whether a terminal is attached :/
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
return client.ImageSaveResult{}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -1,31 +1,25 @@
|
||||
package image
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/command/completion"
|
||||
"github.com/moby/moby/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type tagOptions struct {
|
||||
image string
|
||||
name string
|
||||
}
|
||||
|
||||
// newTagCommand creates a new "docker image tag" command.
|
||||
func newTagCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
var opts tagOptions
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]",
|
||||
Short: "Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE",
|
||||
Args: cli.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
opts.image = args[0]
|
||||
opts.name = args[1]
|
||||
return runTag(cmd.Context(), dockerCLI, opts)
|
||||
_, err := dockerCLI.Client().ImageTag(cmd.Context(), client.ImageTagOptions{
|
||||
Source: args[0],
|
||||
Target: args[1],
|
||||
})
|
||||
return err
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
"aliases": "docker image tag, docker tag",
|
||||
@ -39,7 +33,3 @@ func newTagCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runTag(ctx context.Context, dockerCli command.Cli, opts tagOptions) error {
|
||||
return dockerCli.Client().ImageTag(ctx, opts.image, opts.name)
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
@ -28,10 +29,10 @@ func TestCliNewTagCommandErrors(t *testing.T) {
|
||||
func TestCliNewTagCommand(t *testing.T) {
|
||||
cmd := newTagCommand(
|
||||
test.NewFakeCli(&fakeClient{
|
||||
imageTagFunc: func(image string, ref string) error {
|
||||
assert.Check(t, is.Equal("image1", image))
|
||||
assert.Check(t, is.Equal("image2", ref))
|
||||
return nil
|
||||
imageTagFunc: func(options client.ImageTagOptions) (client.ImageTagResult, error) {
|
||||
assert.Check(t, is.Equal("image1", options.Source))
|
||||
assert.Check(t, is.Equal("image2", options.Target))
|
||||
return client.ImageTagResult{}, nil
|
||||
},
|
||||
}))
|
||||
cmd.SetArgs([]string{"image1", "image2"})
|
||||
|
||||
@ -36,7 +36,7 @@ type treeView struct {
|
||||
}
|
||||
|
||||
func runTree(ctx context.Context, dockerCLI command.Cli, opts treeOptions) error {
|
||||
images, err := dockerCLI.Client().ImageList(ctx, client.ImageListOptions{
|
||||
res, err := dockerCLI.Client().ImageList(ctx, client.ImageListOptions{
|
||||
All: opts.all,
|
||||
Filters: opts.filters,
|
||||
Manifests: true,
|
||||
@ -45,15 +45,15 @@ func runTree(ctx context.Context, dockerCLI command.Cli, opts treeOptions) error
|
||||
return err
|
||||
}
|
||||
if !opts.all {
|
||||
images = slices.DeleteFunc(images, isDangling)
|
||||
res.Items = slices.DeleteFunc(res.Items, isDangling)
|
||||
}
|
||||
|
||||
view := treeView{
|
||||
images: make([]topImage, 0, len(images)),
|
||||
images: make([]topImage, 0, len(res.Items)),
|
||||
}
|
||||
attested := make(map[digest.Digest]bool)
|
||||
|
||||
for _, img := range images {
|
||||
for _, img := range res.Items {
|
||||
details := imageDetails{
|
||||
ID: img.ID,
|
||||
DiskUsage: units.HumanSizeWithPrecision(float64(img.Size), 3),
|
||||
|
||||
@ -13,6 +13,7 @@ import (
|
||||
"github.com/docker/cli/cli/trust"
|
||||
"github.com/docker/cli/internal/registry"
|
||||
registrytypes "github.com/moby/moby/api/types/registry"
|
||||
"github.com/moby/moby/client"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/sirupsen/logrus"
|
||||
notaryclient "github.com/theupdateframework/notary/client"
|
||||
@ -95,7 +96,11 @@ func trustedPull(ctx context.Context, cli command.Cli, imgRefAndAuth trust.Image
|
||||
familiarRef := reference.FamiliarString(tagged)
|
||||
trustedFamiliarRef := reference.FamiliarString(trustedRef)
|
||||
_, _ = fmt.Fprintf(cli.Err(), "Tagging %s as %s\n", trustedFamiliarRef, familiarRef)
|
||||
if err := cli.Client().ImageTag(ctx, trustedFamiliarRef, familiarRef); err != nil {
|
||||
_, err = cli.Client().ImageTag(ctx, client.ImageTagOptions{
|
||||
Source: trustedFamiliarRef,
|
||||
Target: familiarRef,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,9 +13,9 @@ type fakeClient struct {
|
||||
networkConnectFunc func(ctx context.Context, networkID, container string, config *network.EndpointSettings) error
|
||||
networkDisconnectFunc func(ctx context.Context, networkID, container string, force bool) error
|
||||
networkRemoveFunc func(ctx context.Context, networkID string) error
|
||||
networkListFunc func(ctx context.Context, options client.NetworkListOptions) ([]network.Summary, error)
|
||||
networkListFunc func(ctx context.Context, options client.NetworkListOptions) (client.NetworkListResult, error)
|
||||
networkPruneFunc func(ctx context.Context, options client.NetworkPruneOptions) (client.NetworkPruneResult, error)
|
||||
networkInspectFunc func(ctx context.Context, networkID string, options client.NetworkInspectOptions) (network.Inspect, []byte, error)
|
||||
networkInspectFunc func(ctx context.Context, networkID string, options client.NetworkInspectOptions) (client.NetworkInspectResult, error)
|
||||
}
|
||||
|
||||
func (c *fakeClient) NetworkCreate(ctx context.Context, name string, options client.NetworkCreateOptions) (network.CreateResponse, error) {
|
||||
@ -39,11 +39,11 @@ func (c *fakeClient) NetworkDisconnect(ctx context.Context, networkID, container
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) NetworkList(ctx context.Context, options client.NetworkListOptions) ([]network.Summary, error) {
|
||||
func (c *fakeClient) NetworkList(ctx context.Context, options client.NetworkListOptions) (client.NetworkListResult, error) {
|
||||
if c.networkListFunc != nil {
|
||||
return c.networkListFunc(ctx, options)
|
||||
}
|
||||
return []network.Summary{}, nil
|
||||
return client.NetworkListResult{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) NetworkRemove(ctx context.Context, networkID string) error {
|
||||
@ -53,11 +53,11 @@ func (c *fakeClient) NetworkRemove(ctx context.Context, networkID string) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) NetworkInspectWithRaw(ctx context.Context, networkID string, opts client.NetworkInspectOptions) (network.Inspect, []byte, error) {
|
||||
func (c *fakeClient) NetworkInspect(ctx context.Context, networkID string, opts client.NetworkInspectOptions) (client.NetworkInspectResult, error) {
|
||||
if c.networkInspectFunc != nil {
|
||||
return c.networkInspectFunc(ctx, networkID, opts)
|
||||
}
|
||||
return network.Inspect{}, nil, nil
|
||||
return client.NetworkInspectResult{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) NetworksPrune(ctx context.Context, opts client.NetworkPruneOptions) (client.NetworkPruneResult, error) {
|
||||
|
||||
@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/docker/cli/cli/command/formatter"
|
||||
"github.com/moby/moby/api/types/network"
|
||||
"github.com/moby/moby/client"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -35,7 +36,7 @@ func newFormat(source string, quiet bool) formatter.Format {
|
||||
}
|
||||
|
||||
// formatWrite writes the context.
|
||||
func formatWrite(fmtCtx formatter.Context, networks []network.Summary) error {
|
||||
func formatWrite(fmtCtx formatter.Context, networks client.NetworkListResult) error {
|
||||
networkCtx := networkContext{
|
||||
HeaderContext: formatter.HeaderContext{
|
||||
Header: formatter.SubHeaderContext{
|
||||
@ -52,7 +53,7 @@ func formatWrite(fmtCtx formatter.Context, networks []network.Summary) error {
|
||||
},
|
||||
}
|
||||
return fmtCtx.Write(&networkCtx, func(format func(subContext formatter.SubContext) error) error {
|
||||
for _, nw := range networks {
|
||||
for _, nw := range networks.Items {
|
||||
if err := format(&networkContext{
|
||||
trunc: fmtCtx.Trunc,
|
||||
n: nw,
|
||||
|
||||
@ -14,6 +14,7 @@ import (
|
||||
"github.com/docker/cli/cli/command/formatter"
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/moby/moby/api/types/network"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
@ -182,7 +183,9 @@ foobar_bar 2017-01-01 00:00:00 +0000 UTC
|
||||
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||
var out bytes.Buffer
|
||||
tc.context.Output = &out
|
||||
err := formatWrite(tc.context, networks)
|
||||
err := formatWrite(tc.context, client.NetworkListResult{
|
||||
Items: networks,
|
||||
})
|
||||
if err != nil {
|
||||
assert.Error(t, err, tc.expected)
|
||||
} else {
|
||||
@ -213,7 +216,9 @@ func TestNetworkContextWriteJSON(t *testing.T) {
|
||||
}
|
||||
|
||||
out := bytes.NewBufferString("")
|
||||
err := formatWrite(formatter.Context{Format: "{{json .}}", Output: out}, networks)
|
||||
err := formatWrite(formatter.Context{Format: "{{json .}}", Output: out}, client.NetworkListResult{
|
||||
Items: networks,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -242,7 +247,9 @@ func TestNetworkContextWriteJSONField(t *testing.T) {
|
||||
},
|
||||
}
|
||||
out := bytes.NewBufferString("")
|
||||
err := formatWrite(formatter.Context{Format: "{{json .ID}}", Output: out}, networks)
|
||||
err := formatWrite(formatter.Context{Format: "{{json .ID}}", Output: out}, client.NetworkListResult{
|
||||
Items: networks,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@ -45,6 +45,10 @@ func newInspectCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
|
||||
func runInspect(ctx context.Context, apiClient client.NetworkAPIClient, output io.Writer, opts inspectOptions) error {
|
||||
return inspect.Inspect(output, opts.names, opts.format, func(name string) (any, []byte, error) {
|
||||
return apiClient.NetworkInspectWithRaw(ctx, name, client.NetworkInspectOptions{Verbose: opts.verbose})
|
||||
res, err := apiClient.NetworkInspect(ctx, name, client.NetworkInspectOptions{Verbose: opts.verbose})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return res.Network, res.Raw, nil
|
||||
})
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ func newListCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
|
||||
func runList(ctx context.Context, dockerCLI command.Cli, options listOptions) error {
|
||||
apiClient := dockerCLI.Client()
|
||||
networkResources, err := apiClient.NetworkList(ctx, client.NetworkListOptions{Filters: options.filter.Value()})
|
||||
res, err := apiClient.NetworkList(ctx, client.NetworkListOptions{Filters: options.filter.Value()})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -61,8 +61,8 @@ func runList(ctx context.Context, dockerCLI command.Cli, options listOptions) er
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(networkResources, func(i, j int) bool {
|
||||
return sortorder.NaturalLess(networkResources[i].Name, networkResources[j].Name)
|
||||
sort.Slice(res.Items, func(i, j int) bool {
|
||||
return sortorder.NaturalLess(res.Items[i].Name, res.Items[j].Name)
|
||||
})
|
||||
|
||||
networksCtx := formatter.Context{
|
||||
@ -70,5 +70,5 @@ func runList(ctx context.Context, dockerCLI command.Cli, options listOptions) er
|
||||
Format: newFormat(format, options.quiet),
|
||||
Trunc: !options.noTrunc,
|
||||
}
|
||||
return formatWrite(networksCtx, networkResources)
|
||||
return formatWrite(networksCtx, res)
|
||||
}
|
||||
|
||||
@ -17,12 +17,12 @@ import (
|
||||
|
||||
func TestNetworkListErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
networkListFunc func(ctx context.Context, options client.NetworkListOptions) ([]network.Summary, error)
|
||||
networkListFunc func(ctx context.Context, options client.NetworkListOptions) (client.NetworkListResult, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
networkListFunc: func(ctx context.Context, options client.NetworkListOptions) ([]network.Summary, error) {
|
||||
return []network.Summary{}, errors.New("error creating network")
|
||||
networkListFunc: func(ctx context.Context, options client.NetworkListOptions) (client.NetworkListResult, error) {
|
||||
return client.NetworkListResult{}, errors.New("error creating network")
|
||||
},
|
||||
expectedError: "error creating network",
|
||||
},
|
||||
@ -43,7 +43,7 @@ func TestNetworkListErrors(t *testing.T) {
|
||||
func TestNetworkList(t *testing.T) {
|
||||
testCases := []struct {
|
||||
doc string
|
||||
networkListFunc func(ctx context.Context, options client.NetworkListOptions) ([]network.Summary, error)
|
||||
networkListFunc func(ctx context.Context, options client.NetworkListOptions) (client.NetworkListResult, error)
|
||||
flags map[string]string
|
||||
golden string
|
||||
}{
|
||||
@ -53,16 +53,22 @@ func TestNetworkList(t *testing.T) {
|
||||
"filter": "image.name=ubuntu",
|
||||
},
|
||||
golden: "network-list.golden",
|
||||
networkListFunc: func(ctx context.Context, options client.NetworkListOptions) ([]network.Summary, error) {
|
||||
networkListFunc: func(ctx context.Context, options client.NetworkListOptions) (client.NetworkListResult, error) {
|
||||
expectedOpts := client.NetworkListOptions{
|
||||
Filters: make(client.Filters).Add("image.name", "ubuntu"),
|
||||
}
|
||||
assert.Check(t, is.DeepEqual(expectedOpts, options))
|
||||
|
||||
return []network.Summary{*builders.NetworkResource(builders.NetworkResourceID("123454321"),
|
||||
builders.NetworkResourceName("network_1"),
|
||||
builders.NetworkResourceDriver("09.7.01"),
|
||||
builders.NetworkResourceScope("global"))}, nil
|
||||
return client.NetworkListResult{
|
||||
Items: []network.Summary{
|
||||
*builders.NetworkResource(
|
||||
builders.NetworkResourceID("123454321"),
|
||||
builders.NetworkResourceName("network_1"),
|
||||
builders.NetworkResourceDriver("09.7.01"),
|
||||
builders.NetworkResourceScope("global"),
|
||||
),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -71,11 +77,13 @@ func TestNetworkList(t *testing.T) {
|
||||
"format": "{{ .Name }}",
|
||||
},
|
||||
golden: "network-list-sort.golden",
|
||||
networkListFunc: func(ctx context.Context, options client.NetworkListOptions) ([]network.Summary, error) {
|
||||
return []network.Summary{
|
||||
*builders.NetworkResource(builders.NetworkResourceName("network-2-foo")),
|
||||
*builders.NetworkResource(builders.NetworkResourceName("network-1-foo")),
|
||||
*builders.NetworkResource(builders.NetworkResourceName("network-10-foo")),
|
||||
networkListFunc: func(ctx context.Context, options client.NetworkListOptions) (client.NetworkListResult, error) {
|
||||
return client.NetworkListResult{
|
||||
Items: []network.Summary{
|
||||
*builders.NetworkResource(builders.NetworkResourceName("network-2-foo")),
|
||||
*builders.NetworkResource(builders.NetworkResourceName("network-1-foo")),
|
||||
*builders.NetworkResource(builders.NetworkResourceName("network-10-foo")),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
|
||||
@ -49,8 +49,8 @@ func runRemove(ctx context.Context, dockerCLI command.Cli, networks []string, op
|
||||
status := 0
|
||||
|
||||
for _, name := range networks {
|
||||
nw, _, err := apiClient.NetworkInspectWithRaw(ctx, name, client.NetworkInspectOptions{})
|
||||
if err == nil && nw.Ingress {
|
||||
res, err := apiClient.NetworkInspect(ctx, name, client.NetworkInspectOptions{})
|
||||
if err == nil && res.Network.Ingress {
|
||||
r, err := prompt.Confirm(ctx, dockerCLI.In(), dockerCLI.Out(), ingressWarning)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@ -111,14 +111,16 @@ func TestNetworkRemovePromptTermination(t *testing.T) {
|
||||
networkRemoveFunc: func(ctx context.Context, networkID string) error {
|
||||
return errors.New("fakeClient networkRemoveFunc should not be called")
|
||||
},
|
||||
networkInspectFunc: func(ctx context.Context, networkID string, options client.NetworkInspectOptions) (network.Inspect, []byte, error) {
|
||||
return network.Inspect{
|
||||
Network: network.Network{
|
||||
ID: "existing-network",
|
||||
Name: "existing-network",
|
||||
Ingress: true,
|
||||
networkInspectFunc: func(ctx context.Context, networkID string, options client.NetworkInspectOptions) (client.NetworkInspectResult, error) {
|
||||
return client.NetworkInspectResult{
|
||||
Network: network.Inspect{
|
||||
Network: network.Network{
|
||||
ID: "existing-network",
|
||||
Name: "existing-network",
|
||||
Ingress: true,
|
||||
},
|
||||
},
|
||||
}, nil, nil
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
cmd := newRemoveCommand(cli)
|
||||
|
||||
@ -3,7 +3,6 @@ package node
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/api/types/system"
|
||||
"github.com/moby/moby/client"
|
||||
)
|
||||
@ -11,41 +10,41 @@ import (
|
||||
type fakeClient struct {
|
||||
client.Client
|
||||
infoFunc func() (system.Info, error)
|
||||
nodeInspectFunc func() (swarm.Node, []byte, error)
|
||||
nodeListFunc func() ([]swarm.Node, error)
|
||||
nodeRemoveFunc func() error
|
||||
nodeUpdateFunc func(nodeID string, version swarm.Version, node swarm.NodeSpec) error
|
||||
taskInspectFunc func(taskID string) (swarm.Task, []byte, error)
|
||||
taskListFunc func(options client.TaskListOptions) ([]swarm.Task, error)
|
||||
serviceInspectFunc func(ctx context.Context, serviceID string, opts client.ServiceInspectOptions) (swarm.Service, []byte, error)
|
||||
nodeInspectFunc func() (client.NodeInspectResult, error)
|
||||
nodeListFunc func() (client.NodeListResult, error)
|
||||
nodeRemoveFunc func() (client.NodeRemoveResult, error)
|
||||
nodeUpdateFunc func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error)
|
||||
taskInspectFunc func(taskID string) (client.TaskInspectResult, error)
|
||||
taskListFunc func(options client.TaskListOptions) (client.TaskListResult, error)
|
||||
serviceInspectFunc func(ctx context.Context, serviceID string, opts client.ServiceInspectOptions) (client.ServiceInspectResult, error)
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NodeInspectWithRaw(context.Context, string) (swarm.Node, []byte, error) {
|
||||
func (cli *fakeClient) NodeInspect(context.Context, string, client.NodeInspectOptions) (client.NodeInspectResult, error) {
|
||||
if cli.nodeInspectFunc != nil {
|
||||
return cli.nodeInspectFunc()
|
||||
}
|
||||
return swarm.Node{}, []byte{}, nil
|
||||
return client.NodeInspectResult{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NodeList(context.Context, client.NodeListOptions) ([]swarm.Node, error) {
|
||||
func (cli *fakeClient) NodeList(context.Context, client.NodeListOptions) (client.NodeListResult, error) {
|
||||
if cli.nodeListFunc != nil {
|
||||
return cli.nodeListFunc()
|
||||
}
|
||||
return []swarm.Node{}, nil
|
||||
return client.NodeListResult{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NodeRemove(context.Context, string, client.NodeRemoveOptions) error {
|
||||
func (cli *fakeClient) NodeRemove(context.Context, string, client.NodeRemoveOptions) (client.NodeRemoveResult, error) {
|
||||
if cli.nodeRemoveFunc != nil {
|
||||
return cli.nodeRemoveFunc()
|
||||
}
|
||||
return nil
|
||||
return client.NodeRemoveResult{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NodeUpdate(_ context.Context, nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
func (cli *fakeClient) NodeUpdate(_ context.Context, nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error) {
|
||||
if cli.nodeUpdateFunc != nil {
|
||||
return cli.nodeUpdateFunc(nodeID, version, node)
|
||||
return cli.nodeUpdateFunc(nodeID, options)
|
||||
}
|
||||
return nil
|
||||
return client.NodeUpdateResult{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) Info(context.Context) (system.Info, error) {
|
||||
@ -55,23 +54,23 @@ func (cli *fakeClient) Info(context.Context) (system.Info, error) {
|
||||
return system.Info{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) TaskInspectWithRaw(_ context.Context, taskID string) (swarm.Task, []byte, error) {
|
||||
func (cli *fakeClient) TaskInspect(_ context.Context, taskID string, _ client.TaskInspectOptions) (client.TaskInspectResult, error) {
|
||||
if cli.taskInspectFunc != nil {
|
||||
return cli.taskInspectFunc(taskID)
|
||||
}
|
||||
return swarm.Task{}, []byte{}, nil
|
||||
return client.TaskInspectResult{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) TaskList(_ context.Context, options client.TaskListOptions) ([]swarm.Task, error) {
|
||||
func (cli *fakeClient) TaskList(_ context.Context, options client.TaskListOptions) (client.TaskListResult, error) {
|
||||
if cli.taskListFunc != nil {
|
||||
return cli.taskListFunc(options)
|
||||
}
|
||||
return []swarm.Task{}, nil
|
||||
return client.TaskListResult{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ServiceInspectWithRaw(ctx context.Context, serviceID string, opts client.ServiceInspectOptions) (swarm.Service, []byte, error) {
|
||||
func (cli *fakeClient) ServiceInspect(ctx context.Context, serviceID string, opts client.ServiceInspectOptions) (client.ServiceInspectResult, error) {
|
||||
if cli.serviceInspectFunc != nil {
|
||||
return cli.serviceInspectFunc(ctx, serviceID, opts)
|
||||
}
|
||||
return swarm.Service{}, []byte{}, nil
|
||||
return client.ServiceInspectResult{}, nil
|
||||
}
|
||||
|
||||
@ -17,13 +17,13 @@ func completeNodeNames(dockerCLI completion.APIClientProvider) cobra.CompletionF
|
||||
// https://github.com/docker/cli/blob/f9ced58158d5e0b358052432244b483774a1983d/contrib/completion/bash/docker#L41-L43
|
||||
showIDs := os.Getenv("DOCKER_COMPLETION_SHOW_NODE_IDS") == "yes"
|
||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
list, err := dockerCLI.Client().NodeList(cmd.Context(), client.NodeListOptions{})
|
||||
res, err := dockerCLI.Client().NodeList(cmd.Context(), client.NodeListOptions{})
|
||||
if err != nil {
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
|
||||
names := make([]string, 0, len(list)+1)
|
||||
for _, node := range list {
|
||||
names := make([]string, 0, len(res.Items)+1)
|
||||
for _, node := range res.Items {
|
||||
if showIDs {
|
||||
names = append(names, node.Description.Hostname, node.ID)
|
||||
} else {
|
||||
|
||||
@ -8,14 +8,15 @@ import (
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/docker/cli/internal/test/builders"
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestNodeDemoteErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
nodeInspectFunc func() (swarm.Node, []byte, error)
|
||||
nodeUpdateFunc func(nodeID string, version swarm.Version, node swarm.NodeSpec) error
|
||||
nodeInspectFunc func() (client.NodeInspectResult, error)
|
||||
nodeUpdateFunc func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
@ -23,15 +24,15 @@ func TestNodeDemoteErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return swarm.Node{}, []byte{}, errors.New("error inspecting the node")
|
||||
nodeInspectFunc: func() (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{}, errors.New("error inspecting the node")
|
||||
},
|
||||
expectedError: "error inspecting the node",
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
return errors.New("error updating the node")
|
||||
nodeUpdateFunc: func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error) {
|
||||
return client.NodeUpdateResult{}, errors.New("error updating the node")
|
||||
},
|
||||
expectedError: "error updating the node",
|
||||
},
|
||||
@ -52,14 +53,16 @@ func TestNodeDemoteErrors(t *testing.T) {
|
||||
func TestNodeDemoteNoChange(t *testing.T) {
|
||||
cmd := newDemoteCommand(
|
||||
test.NewFakeCli(&fakeClient{
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *builders.Node(), []byte{}, nil
|
||||
nodeInspectFunc: func() (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{
|
||||
Node: *builders.Node(),
|
||||
}, nil
|
||||
},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
if node.Role != swarm.NodeRoleWorker {
|
||||
return errors.New("expected role worker, got " + string(node.Role))
|
||||
nodeUpdateFunc: func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error) {
|
||||
if options.Node.Role != swarm.NodeRoleWorker {
|
||||
return client.NodeUpdateResult{}, errors.New("expected role worker, got " + string(options.Node.Role))
|
||||
}
|
||||
return nil
|
||||
return client.NodeUpdateResult{}, nil
|
||||
},
|
||||
}))
|
||||
cmd.SetArgs([]string{"nodeID"})
|
||||
@ -69,14 +72,16 @@ func TestNodeDemoteNoChange(t *testing.T) {
|
||||
func TestNodeDemoteMultipleNode(t *testing.T) {
|
||||
cmd := newDemoteCommand(
|
||||
test.NewFakeCli(&fakeClient{
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *builders.Node(builders.Manager()), []byte{}, nil
|
||||
nodeInspectFunc: func() (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{
|
||||
Node: *builders.Node(builders.Manager()),
|
||||
}, nil
|
||||
},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
if node.Role != swarm.NodeRoleWorker {
|
||||
return errors.New("expected role worker, got " + string(node.Role))
|
||||
nodeUpdateFunc: func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error) {
|
||||
if options.Node.Role != swarm.NodeRoleWorker {
|
||||
return client.NodeUpdateResult{}, errors.New("expected role worker, got " + string(options.Node.Role))
|
||||
}
|
||||
return nil
|
||||
return client.NodeUpdateResult{}, nil
|
||||
},
|
||||
}))
|
||||
cmd.SetArgs([]string{"nodeID1", "nodeID2"})
|
||||
|
||||
@ -11,6 +11,7 @@ import (
|
||||
"github.com/docker/go-units"
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/api/types/system"
|
||||
"github.com/moby/moby/client"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -99,7 +100,7 @@ func newFormat(source string, quiet bool) formatter.Format {
|
||||
}
|
||||
|
||||
// formatWrite writes the context.
|
||||
func formatWrite(fmtCtx formatter.Context, nodes []swarm.Node, info system.Info) error {
|
||||
func formatWrite(fmtCtx formatter.Context, nodes client.NodeListResult, info system.Info) error {
|
||||
nodeCtx := &nodeContext{
|
||||
HeaderContext: formatter.HeaderContext{
|
||||
Header: formatter.SubHeaderContext{
|
||||
@ -115,7 +116,7 @@ func formatWrite(fmtCtx formatter.Context, nodes []swarm.Node, info system.Info)
|
||||
},
|
||||
}
|
||||
return fmtCtx.Write(nodeCtx, func(format func(subContext formatter.SubContext) error) error {
|
||||
for _, node := range nodes {
|
||||
for _, node := range nodes.Items {
|
||||
if err := format(&nodeContext{
|
||||
n: node,
|
||||
info: info,
|
||||
|
||||
@ -14,6 +14,7 @@ import (
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/api/types/system"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
@ -166,38 +167,40 @@ foobar_boo Unknown
|
||||
},
|
||||
}
|
||||
|
||||
nodes := []swarm.Node{
|
||||
{
|
||||
ID: "nodeID1",
|
||||
Description: swarm.NodeDescription{
|
||||
Hostname: "foobar_baz",
|
||||
TLSInfo: swarm.TLSInfo{TrustRoot: "no"},
|
||||
Engine: swarm.EngineDescription{EngineVersion: "18.03.0-ce"},
|
||||
nodes := client.NodeListResult{
|
||||
Items: []swarm.Node{
|
||||
{
|
||||
ID: "nodeID1",
|
||||
Description: swarm.NodeDescription{
|
||||
Hostname: "foobar_baz",
|
||||
TLSInfo: swarm.TLSInfo{TrustRoot: "no"},
|
||||
Engine: swarm.EngineDescription{EngineVersion: "18.03.0-ce"},
|
||||
},
|
||||
Status: swarm.NodeStatus{State: swarm.NodeState("foo")},
|
||||
Spec: swarm.NodeSpec{Availability: swarm.NodeAvailability("drain")},
|
||||
ManagerStatus: &swarm.ManagerStatus{Leader: true},
|
||||
},
|
||||
Status: swarm.NodeStatus{State: swarm.NodeState("foo")},
|
||||
Spec: swarm.NodeSpec{Availability: swarm.NodeAvailability("drain")},
|
||||
ManagerStatus: &swarm.ManagerStatus{Leader: true},
|
||||
},
|
||||
{
|
||||
ID: "nodeID2",
|
||||
Description: swarm.NodeDescription{
|
||||
Hostname: "foobar_bar",
|
||||
TLSInfo: swarm.TLSInfo{TrustRoot: "hi"},
|
||||
Engine: swarm.EngineDescription{EngineVersion: "1.2.3"},
|
||||
{
|
||||
ID: "nodeID2",
|
||||
Description: swarm.NodeDescription{
|
||||
Hostname: "foobar_bar",
|
||||
TLSInfo: swarm.TLSInfo{TrustRoot: "hi"},
|
||||
Engine: swarm.EngineDescription{EngineVersion: "1.2.3"},
|
||||
},
|
||||
Status: swarm.NodeStatus{State: swarm.NodeState("bar")},
|
||||
Spec: swarm.NodeSpec{Availability: swarm.NodeAvailability("active")},
|
||||
ManagerStatus: &swarm.ManagerStatus{
|
||||
Leader: false,
|
||||
Reachability: swarm.Reachability("Reachable"),
|
||||
},
|
||||
},
|
||||
Status: swarm.NodeStatus{State: swarm.NodeState("bar")},
|
||||
Spec: swarm.NodeSpec{Availability: swarm.NodeAvailability("active")},
|
||||
ManagerStatus: &swarm.ManagerStatus{
|
||||
Leader: false,
|
||||
Reachability: swarm.Reachability("Reachable"),
|
||||
{
|
||||
ID: "nodeID3",
|
||||
Description: swarm.NodeDescription{Hostname: "foobar_boo"},
|
||||
Status: swarm.NodeStatus{State: swarm.NodeState("boo")},
|
||||
Spec: swarm.NodeSpec{Availability: swarm.NodeAvailability("active")},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "nodeID3",
|
||||
Description: swarm.NodeDescription{Hostname: "foobar_boo"},
|
||||
Status: swarm.NodeStatus{State: swarm.NodeState("boo")},
|
||||
Spec: swarm.NodeSpec{Availability: swarm.NodeAvailability("active")},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
@ -246,10 +249,12 @@ func TestNodeContextWriteJSON(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, testcase := range cases {
|
||||
nodes := []swarm.Node{
|
||||
{ID: "nodeID1", Description: swarm.NodeDescription{Hostname: "foobar_baz", TLSInfo: swarm.TLSInfo{TrustRoot: "hi"}, Engine: swarm.EngineDescription{EngineVersion: "1.2.3"}}},
|
||||
{ID: "nodeID2", Description: swarm.NodeDescription{Hostname: "foobar_bar", TLSInfo: swarm.TLSInfo{TrustRoot: "no"}}},
|
||||
{ID: "nodeID3", Description: swarm.NodeDescription{Hostname: "foobar_boo", Engine: swarm.EngineDescription{EngineVersion: "18.03.0-ce"}}},
|
||||
nodes := client.NodeListResult{
|
||||
Items: []swarm.Node{
|
||||
{ID: "nodeID1", Description: swarm.NodeDescription{Hostname: "foobar_baz", TLSInfo: swarm.TLSInfo{TrustRoot: "hi"}, Engine: swarm.EngineDescription{EngineVersion: "1.2.3"}}},
|
||||
{ID: "nodeID2", Description: swarm.NodeDescription{Hostname: "foobar_bar", TLSInfo: swarm.TLSInfo{TrustRoot: "no"}}},
|
||||
{ID: "nodeID3", Description: swarm.NodeDescription{Hostname: "foobar_boo", Engine: swarm.EngineDescription{EngineVersion: "18.03.0-ce"}}},
|
||||
},
|
||||
}
|
||||
out := bytes.NewBufferString("")
|
||||
err := formatWrite(formatter.Context{Format: "{{json .}}", Output: out}, nodes, testcase.info)
|
||||
@ -267,9 +272,11 @@ func TestNodeContextWriteJSON(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNodeContextWriteJSONField(t *testing.T) {
|
||||
nodes := []swarm.Node{
|
||||
{ID: "nodeID1", Description: swarm.NodeDescription{Hostname: "foobar_baz"}},
|
||||
{ID: "nodeID2", Description: swarm.NodeDescription{Hostname: "foobar_bar"}},
|
||||
nodes := client.NodeListResult{
|
||||
Items: []swarm.Node{
|
||||
{ID: "nodeID1", Description: swarm.NodeDescription{Hostname: "foobar_baz"}},
|
||||
{ID: "nodeID2", Description: swarm.NodeDescription{Hostname: "foobar_bar"}},
|
||||
},
|
||||
}
|
||||
out := bytes.NewBufferString("")
|
||||
err := formatWrite(formatter.Context{Format: "{{json .ID}}", Output: out}, nodes, system.Info{})
|
||||
@ -281,7 +288,7 @@ func TestNodeContextWriteJSONField(t *testing.T) {
|
||||
var s string
|
||||
err := json.Unmarshal([]byte(line), &s)
|
||||
assert.NilError(t, err, msg)
|
||||
assert.Check(t, is.Equal(nodes[i].ID, s), msg)
|
||||
assert.Check(t, is.Equal(nodes.Items[i].ID, s), msg)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ import (
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/command/formatter"
|
||||
flagsHelper "github.com/docker/cli/cli/flags"
|
||||
"github.com/moby/moby/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -54,8 +55,8 @@ func runInspect(ctx context.Context, dockerCLI command.Cli, opts inspectOptions)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
node, _, err := apiClient.NodeInspectWithRaw(ctx, nodeRef)
|
||||
return node, nil, err
|
||||
res, err := apiClient.NodeInspect(ctx, nodeRef, client.NodeInspectOptions{})
|
||||
return res.Node, res.Raw, err
|
||||
}
|
||||
|
||||
// check if the user is trying to apply a template to the pretty format, which
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"github.com/docker/cli/internal/test/builders"
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/api/types/system"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
"gotest.tools/v3/golden"
|
||||
)
|
||||
@ -18,7 +19,7 @@ func TestNodeInspectErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
flags map[string]string
|
||||
nodeInspectFunc func() (swarm.Node, []byte, error)
|
||||
nodeInspectFunc func() (client.NodeInspectResult, error)
|
||||
infoFunc func() (system.Info, error)
|
||||
expectedError string
|
||||
}{
|
||||
@ -34,8 +35,8 @@ func TestNodeInspectErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return swarm.Node{}, []byte{}, errors.New("error inspecting the node")
|
||||
nodeInspectFunc: func() (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{}, errors.New("error inspecting the node")
|
||||
},
|
||||
infoFunc: func() (system.Info, error) {
|
||||
return system.Info{}, errors.New("error asking for node info")
|
||||
@ -44,8 +45,8 @@ func TestNodeInspectErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
args: []string{"self"},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return swarm.Node{}, []byte{}, errors.New("error inspecting the node")
|
||||
nodeInspectFunc: func() (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{}, errors.New("error inspecting the node")
|
||||
},
|
||||
infoFunc: func() (system.Info, error) {
|
||||
return system.Info{Swarm: swarm.Info{NodeID: "abc"}}, nil
|
||||
@ -82,26 +83,30 @@ func TestNodeInspectErrors(t *testing.T) {
|
||||
func TestNodeInspectPretty(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
nodeInspectFunc func() (swarm.Node, []byte, error)
|
||||
nodeInspectFunc func() (client.NodeInspectResult, error)
|
||||
}{
|
||||
{
|
||||
name: "simple",
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *builders.Node(builders.NodeLabels(map[string]string{
|
||||
"lbl1": "value1",
|
||||
})), []byte{}, nil
|
||||
nodeInspectFunc: func() (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{
|
||||
Node: *builders.Node(builders.NodeLabels(map[string]string{"lbl1": "value1"})),
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "manager",
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *builders.Node(builders.Manager()), []byte{}, nil
|
||||
nodeInspectFunc: func() (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{
|
||||
Node: *builders.Node(builders.Manager()),
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "manager-leader",
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *builders.Node(builders.Manager(builders.Leader())), []byte{}, nil
|
||||
nodeInspectFunc: func() (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{
|
||||
Node: *builders.Node(builders.Manager(builders.Leader())),
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ func newListCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
func runList(ctx context.Context, dockerCLI command.Cli, options listOptions) error {
|
||||
apiClient := dockerCLI.Client()
|
||||
|
||||
nodes, err := apiClient.NodeList(ctx, client.NodeListOptions{
|
||||
res, err := apiClient.NodeList(ctx, client.NodeListOptions{
|
||||
Filters: options.filter.Value(),
|
||||
})
|
||||
if err != nil {
|
||||
@ -54,7 +54,7 @@ func runList(ctx context.Context, dockerCLI command.Cli, options listOptions) er
|
||||
}
|
||||
|
||||
var info system.Info
|
||||
if len(nodes) > 0 && !options.quiet {
|
||||
if len(res.Items) > 0 && !options.quiet {
|
||||
// only non-empty nodes and not quiet, should we call /info api
|
||||
info, err = apiClient.Info(ctx)
|
||||
if err != nil {
|
||||
@ -74,8 +74,8 @@ func runList(ctx context.Context, dockerCLI command.Cli, options listOptions) er
|
||||
Output: dockerCLI.Out(),
|
||||
Format: newFormat(format, options.quiet),
|
||||
}
|
||||
sort.Slice(nodes, func(i, j int) bool {
|
||||
return sortorder.NaturalLess(nodes[i].Description.Hostname, nodes[j].Description.Hostname)
|
||||
sort.Slice(res.Items, func(i, j int) bool {
|
||||
return sortorder.NaturalLess(res.Items[i].Description.Hostname, res.Items[j].Description.Hostname)
|
||||
})
|
||||
return formatWrite(nodesCtx, nodes, info)
|
||||
return formatWrite(nodesCtx, res, info)
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"github.com/docker/cli/internal/test/builders"
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/api/types/system"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
"gotest.tools/v3/golden"
|
||||
@ -17,21 +18,21 @@ import (
|
||||
|
||||
func TestNodeListErrorOnAPIFailure(t *testing.T) {
|
||||
testCases := []struct {
|
||||
nodeListFunc func() ([]swarm.Node, error)
|
||||
nodeListFunc func() (client.NodeListResult, error)
|
||||
infoFunc func() (system.Info, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
nodeListFunc: func() ([]swarm.Node, error) {
|
||||
return []swarm.Node{}, errors.New("error listing nodes")
|
||||
nodeListFunc: func() (client.NodeListResult, error) {
|
||||
return client.NodeListResult{}, errors.New("error listing nodes")
|
||||
},
|
||||
expectedError: "error listing nodes",
|
||||
},
|
||||
{
|
||||
nodeListFunc: func() ([]swarm.Node, error) {
|
||||
return []swarm.Node{
|
||||
{
|
||||
ID: "nodeID",
|
||||
nodeListFunc: func() (client.NodeListResult, error) {
|
||||
return client.NodeListResult{
|
||||
Items: []swarm.Node{
|
||||
{ID: "nodeID"},
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
@ -55,11 +56,13 @@ func TestNodeListErrorOnAPIFailure(t *testing.T) {
|
||||
|
||||
func TestNodeList(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
nodeListFunc: func() ([]swarm.Node, error) {
|
||||
return []swarm.Node{
|
||||
*builders.Node(builders.NodeID("nodeID1"), builders.Hostname("node-2-foo"), builders.Manager(builders.Leader()), builders.EngineVersion(".")),
|
||||
*builders.Node(builders.NodeID("nodeID2"), builders.Hostname("node-10-foo"), builders.Manager(), builders.EngineVersion("18.03.0-ce")),
|
||||
*builders.Node(builders.NodeID("nodeID3"), builders.Hostname("node-1-foo")),
|
||||
nodeListFunc: func() (client.NodeListResult, error) {
|
||||
return client.NodeListResult{
|
||||
Items: []swarm.Node{
|
||||
*builders.Node(builders.NodeID("nodeID1"), builders.Hostname("node-2-foo"), builders.Manager(builders.Leader()), builders.EngineVersion(".")),
|
||||
*builders.Node(builders.NodeID("nodeID2"), builders.Hostname("node-10-foo"), builders.Manager(), builders.EngineVersion("18.03.0-ce")),
|
||||
*builders.Node(builders.NodeID("nodeID3"), builders.Hostname("node-1-foo")),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
infoFunc: func() (system.Info, error) {
|
||||
@ -78,9 +81,11 @@ func TestNodeList(t *testing.T) {
|
||||
|
||||
func TestNodeListQuietShouldOnlyPrintIDs(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
nodeListFunc: func() ([]swarm.Node, error) {
|
||||
return []swarm.Node{
|
||||
*builders.Node(builders.NodeID("nodeID1")),
|
||||
nodeListFunc: func() (client.NodeListResult, error) {
|
||||
return client.NodeListResult{
|
||||
Items: []swarm.Node{
|
||||
*builders.Node(builders.NodeID("nodeID1")),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
@ -92,11 +97,13 @@ func TestNodeListQuietShouldOnlyPrintIDs(t *testing.T) {
|
||||
|
||||
func TestNodeListDefaultFormatFromConfig(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
nodeListFunc: func() ([]swarm.Node, error) {
|
||||
return []swarm.Node{
|
||||
*builders.Node(builders.NodeID("nodeID1"), builders.Hostname("nodeHostname1"), builders.Manager(builders.Leader())),
|
||||
*builders.Node(builders.NodeID("nodeID2"), builders.Hostname("nodeHostname2"), builders.Manager()),
|
||||
*builders.Node(builders.NodeID("nodeID3"), builders.Hostname("nodeHostname3")),
|
||||
nodeListFunc: func() (client.NodeListResult, error) {
|
||||
return client.NodeListResult{
|
||||
Items: []swarm.Node{
|
||||
*builders.Node(builders.NodeID("nodeID1"), builders.Hostname("nodeHostname1"), builders.Manager(builders.Leader())),
|
||||
*builders.Node(builders.NodeID("nodeID2"), builders.Hostname("nodeHostname2"), builders.Manager()),
|
||||
*builders.Node(builders.NodeID("nodeID3"), builders.Hostname("nodeHostname3")),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
infoFunc: func() (system.Info, error) {
|
||||
@ -117,10 +124,12 @@ func TestNodeListDefaultFormatFromConfig(t *testing.T) {
|
||||
|
||||
func TestNodeListFormat(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
nodeListFunc: func() ([]swarm.Node, error) {
|
||||
return []swarm.Node{
|
||||
*builders.Node(builders.NodeID("nodeID1"), builders.Hostname("nodeHostname1"), builders.Manager(builders.Leader())),
|
||||
*builders.Node(builders.NodeID("nodeID2"), builders.Hostname("nodeHostname2"), builders.Manager()),
|
||||
nodeListFunc: func() (client.NodeListResult, error) {
|
||||
return client.NodeListResult{
|
||||
Items: []swarm.Node{
|
||||
*builders.Node(builders.NodeID("nodeID1"), builders.Hostname("nodeHostname1"), builders.Manager(builders.Leader())),
|
||||
*builders.Node(builders.NodeID("nodeID2"), builders.Hostname("nodeHostname2"), builders.Manager()),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
infoFunc: func() (system.Info, error) {
|
||||
|
||||
@ -8,14 +8,15 @@ import (
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/docker/cli/internal/test/builders"
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestNodePromoteErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
nodeInspectFunc func() (swarm.Node, []byte, error)
|
||||
nodeUpdateFunc func(nodeID string, version swarm.Version, node swarm.NodeSpec) error
|
||||
nodeInspectFunc func() (client.NodeInspectResult, error)
|
||||
nodeUpdateFunc func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
@ -23,15 +24,15 @@ func TestNodePromoteErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return swarm.Node{}, []byte{}, errors.New("error inspecting the node")
|
||||
nodeInspectFunc: func() (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{}, errors.New("error inspecting the node")
|
||||
},
|
||||
expectedError: "error inspecting the node",
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
return errors.New("error updating the node")
|
||||
nodeUpdateFunc: func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error) {
|
||||
return client.NodeUpdateResult{}, errors.New("error updating the node")
|
||||
},
|
||||
expectedError: "error updating the node",
|
||||
},
|
||||
@ -52,14 +53,16 @@ func TestNodePromoteErrors(t *testing.T) {
|
||||
func TestNodePromoteNoChange(t *testing.T) {
|
||||
cmd := newPromoteCommand(
|
||||
test.NewFakeCli(&fakeClient{
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *builders.Node(builders.Manager()), []byte{}, nil
|
||||
nodeInspectFunc: func() (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{
|
||||
Node: *builders.Node(builders.Manager()),
|
||||
}, nil
|
||||
},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
if node.Role != swarm.NodeRoleManager {
|
||||
return errors.New("expected role manager, got" + string(node.Role))
|
||||
nodeUpdateFunc: func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error) {
|
||||
if options.Node.Role != swarm.NodeRoleManager {
|
||||
return client.NodeUpdateResult{}, errors.New("expected role manager, got" + string(options.Node.Role))
|
||||
}
|
||||
return nil
|
||||
return client.NodeUpdateResult{}, nil
|
||||
},
|
||||
}))
|
||||
cmd.SetArgs([]string{"nodeID"})
|
||||
@ -69,14 +72,16 @@ func TestNodePromoteNoChange(t *testing.T) {
|
||||
func TestNodePromoteMultipleNode(t *testing.T) {
|
||||
cmd := newPromoteCommand(
|
||||
test.NewFakeCli(&fakeClient{
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *builders.Node(), []byte{}, nil
|
||||
nodeInspectFunc: func() (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{
|
||||
Node: *builders.Node(),
|
||||
}, nil
|
||||
},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
if node.Role != swarm.NodeRoleManager {
|
||||
return errors.New("expected role manager, got" + string(node.Role))
|
||||
nodeUpdateFunc: func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error) {
|
||||
if options.Node.Role != swarm.NodeRoleManager {
|
||||
return client.NodeUpdateResult{}, errors.New("expected role manager, got" + string(options.Node.Role))
|
||||
}
|
||||
return nil
|
||||
return client.NodeUpdateResult{}, nil
|
||||
},
|
||||
}))
|
||||
cmd.SetArgs([]string{"nodeID1", "nodeID2"})
|
||||
|
||||
@ -9,7 +9,6 @@ import (
|
||||
"github.com/docker/cli/cli/command/idresolver"
|
||||
"github.com/docker/cli/cli/command/task"
|
||||
"github.com/docker/cli/opts"
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -57,7 +56,7 @@ func runPs(ctx context.Context, dockerCLI command.Cli, options psOptions) error
|
||||
|
||||
var (
|
||||
errs []error
|
||||
tasks []swarm.Task
|
||||
tasks = client.TaskListResult{}
|
||||
)
|
||||
|
||||
for _, nodeID := range options.nodeIDs {
|
||||
@ -67,14 +66,14 @@ func runPs(ctx context.Context, dockerCLI command.Cli, options psOptions) error
|
||||
continue
|
||||
}
|
||||
|
||||
node, _, err := apiClient.NodeInspectWithRaw(ctx, nodeRef)
|
||||
res, err := apiClient.NodeInspect(ctx, nodeRef, client.NodeInspectOptions{})
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
|
||||
filter := options.filter.Value()
|
||||
filter.Add("node", node.ID)
|
||||
filter.Add("node", res.Node.ID)
|
||||
|
||||
nodeTasks, err := apiClient.TaskList(ctx, client.TaskListOptions{Filters: filter})
|
||||
if err != nil {
|
||||
@ -82,7 +81,7 @@ func runPs(ctx context.Context, dockerCLI command.Cli, options psOptions) error
|
||||
continue
|
||||
}
|
||||
|
||||
tasks = append(tasks, nodeTasks...)
|
||||
tasks.Items = append(tasks.Items, nodeTasks.Items...)
|
||||
}
|
||||
|
||||
format := options.format
|
||||
@ -90,7 +89,7 @@ func runPs(ctx context.Context, dockerCLI command.Cli, options psOptions) error
|
||||
format = task.DefaultFormat(dockerCLI.ConfigFile(), options.quiet)
|
||||
}
|
||||
|
||||
if len(errs) == 0 || len(tasks) != 0 {
|
||||
if len(errs) == 0 || len(tasks.Items) != 0 {
|
||||
if err := task.Print(ctx, dockerCLI, tasks, idresolver.New(apiClient, options.noResolve), !options.noTrunc, options.quiet, format); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
@ -22,9 +22,9 @@ func TestNodePsErrors(t *testing.T) {
|
||||
args []string
|
||||
flags map[string]string
|
||||
infoFunc func() (system.Info, error)
|
||||
nodeInspectFunc func() (swarm.Node, []byte, error)
|
||||
taskListFunc func(options client.TaskListOptions) ([]swarm.Task, error)
|
||||
taskInspectFunc func(taskID string) (swarm.Task, []byte, error)
|
||||
nodeInspectFunc func() (client.NodeInspectResult, error)
|
||||
taskListFunc func(options client.TaskListOptions) (client.TaskListResult, error)
|
||||
taskInspectFunc func(taskID string) (client.TaskInspectResult, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
@ -35,15 +35,15 @@ func TestNodePsErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return swarm.Node{}, []byte{}, errors.New("error inspecting the node")
|
||||
nodeInspectFunc: func() (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{}, errors.New("error inspecting the node")
|
||||
},
|
||||
expectedError: "error inspecting the node",
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
taskListFunc: func(options client.TaskListOptions) ([]swarm.Task, error) {
|
||||
return []swarm.Task{}, errors.New("error returning the task list")
|
||||
taskListFunc: func(options client.TaskListOptions) (client.TaskListResult, error) {
|
||||
return client.TaskListResult{}, errors.New("error returning the task list")
|
||||
},
|
||||
expectedError: "error returning the task list",
|
||||
},
|
||||
@ -72,64 +72,76 @@ func TestNodePs(t *testing.T) {
|
||||
args []string
|
||||
flags map[string]string
|
||||
infoFunc func() (system.Info, error)
|
||||
nodeInspectFunc func() (swarm.Node, []byte, error)
|
||||
taskListFunc func(options client.TaskListOptions) ([]swarm.Task, error)
|
||||
taskInspectFunc func(taskID string) (swarm.Task, []byte, error)
|
||||
serviceInspectFunc func(ctx context.Context, serviceID string, opts client.ServiceInspectOptions) (swarm.Service, []byte, error)
|
||||
nodeInspectFunc func() (client.NodeInspectResult, error)
|
||||
taskListFunc func(options client.TaskListOptions) (client.TaskListResult, error)
|
||||
taskInspectFunc func(taskID string) (client.TaskInspectResult, error)
|
||||
serviceInspectFunc func(ctx context.Context, serviceID string, opts client.ServiceInspectOptions) (client.ServiceInspectResult, error)
|
||||
}{
|
||||
{
|
||||
name: "simple",
|
||||
args: []string{"nodeID"},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *builders.Node(), []byte{}, nil
|
||||
},
|
||||
taskListFunc: func(options client.TaskListOptions) ([]swarm.Task, error) {
|
||||
return []swarm.Task{
|
||||
*builders.Task(builders.WithStatus(builders.Timestamp(time.Now().Add(-2*time.Hour)), builders.PortStatus([]swarm.PortConfig{
|
||||
{
|
||||
TargetPort: 80,
|
||||
PublishedPort: 80,
|
||||
Protocol: "tcp",
|
||||
},
|
||||
}))),
|
||||
nodeInspectFunc: func() (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{
|
||||
Node: *builders.Node(),
|
||||
}, nil
|
||||
},
|
||||
serviceInspectFunc: func(ctx context.Context, serviceID string, opts client.ServiceInspectOptions) (swarm.Service, []byte, error) {
|
||||
return swarm.Service{
|
||||
ID: serviceID,
|
||||
Spec: swarm.ServiceSpec{
|
||||
Annotations: swarm.Annotations{
|
||||
Name: serviceID,
|
||||
taskListFunc: func(options client.TaskListOptions) (client.TaskListResult, error) {
|
||||
return client.TaskListResult{
|
||||
Items: []swarm.Task{
|
||||
*builders.Task(builders.WithStatus(builders.Timestamp(time.Now().Add(-2*time.Hour)), builders.PortStatus([]swarm.PortConfig{
|
||||
{
|
||||
TargetPort: 80,
|
||||
PublishedPort: 80,
|
||||
Protocol: "tcp",
|
||||
},
|
||||
}))),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
serviceInspectFunc: func(ctx context.Context, serviceID string, opts client.ServiceInspectOptions) (client.ServiceInspectResult, error) {
|
||||
return client.ServiceInspectResult{
|
||||
Service: swarm.Service{
|
||||
ID: serviceID,
|
||||
Spec: swarm.ServiceSpec{
|
||||
Annotations: swarm.Annotations{
|
||||
Name: serviceID,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, []byte{}, nil
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with-errors",
|
||||
args: []string{"nodeID"},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *builders.Node(), []byte{}, nil
|
||||
},
|
||||
taskListFunc: func(options client.TaskListOptions) ([]swarm.Task, error) {
|
||||
return []swarm.Task{
|
||||
*builders.Task(builders.TaskID("taskID1"), builders.TaskServiceID("failure"),
|
||||
builders.WithStatus(builders.Timestamp(time.Now().Add(-2*time.Hour)), builders.StatusErr("a task error"))),
|
||||
*builders.Task(builders.TaskID("taskID2"), builders.TaskServiceID("failure"),
|
||||
builders.WithStatus(builders.Timestamp(time.Now().Add(-3*time.Hour)), builders.StatusErr("a task error"))),
|
||||
*builders.Task(builders.TaskID("taskID3"), builders.TaskServiceID("failure"),
|
||||
builders.WithStatus(builders.Timestamp(time.Now().Add(-4*time.Hour)), builders.StatusErr("a task error"))),
|
||||
nodeInspectFunc: func() (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{
|
||||
Node: *builders.Node(),
|
||||
}, nil
|
||||
},
|
||||
serviceInspectFunc: func(ctx context.Context, serviceID string, opts client.ServiceInspectOptions) (swarm.Service, []byte, error) {
|
||||
return swarm.Service{
|
||||
ID: serviceID,
|
||||
Spec: swarm.ServiceSpec{
|
||||
Annotations: swarm.Annotations{
|
||||
Name: serviceID,
|
||||
taskListFunc: func(options client.TaskListOptions) (client.TaskListResult, error) {
|
||||
return client.TaskListResult{
|
||||
Items: []swarm.Task{
|
||||
*builders.Task(builders.TaskID("taskID1"), builders.TaskServiceID("failure"),
|
||||
builders.WithStatus(builders.Timestamp(time.Now().Add(-2*time.Hour)), builders.StatusErr("a task error"))),
|
||||
*builders.Task(builders.TaskID("taskID2"), builders.TaskServiceID("failure"),
|
||||
builders.WithStatus(builders.Timestamp(time.Now().Add(-3*time.Hour)), builders.StatusErr("a task error"))),
|
||||
*builders.Task(builders.TaskID("taskID3"), builders.TaskServiceID("failure"),
|
||||
builders.WithStatus(builders.Timestamp(time.Now().Add(-4*time.Hour)), builders.StatusErr("a task error"))),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
serviceInspectFunc: func(ctx context.Context, serviceID string, opts client.ServiceInspectOptions) (client.ServiceInspectResult, error) {
|
||||
return client.ServiceInspectResult{
|
||||
Service: swarm.Service{
|
||||
ID: serviceID,
|
||||
Spec: swarm.ServiceSpec{
|
||||
Annotations: swarm.Annotations{
|
||||
Name: serviceID,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, []byte{}, nil
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ func runRemove(ctx context.Context, dockerCLI command.Cli, nodeIDs []string, opt
|
||||
|
||||
var errs []error
|
||||
for _, id := range nodeIDs {
|
||||
if err := apiClient.NodeRemove(ctx, id, client.NodeRemoveOptions{Force: opts.force}); err != nil {
|
||||
if _, err := apiClient.NodeRemove(ctx, id, client.NodeRemoveOptions{Force: opts.force}); err != nil {
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -6,13 +6,14 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestNodeRemoveErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
nodeRemoveFunc func() error
|
||||
nodeRemoveFunc func() (client.NodeRemoveResult, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
@ -20,8 +21,8 @@ func TestNodeRemoveErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
nodeRemoveFunc: func() error {
|
||||
return errors.New("error removing the node")
|
||||
nodeRemoveFunc: func() (client.NodeRemoveResult, error) {
|
||||
return client.NodeRemoveResult{}, errors.New("error removing the node")
|
||||
},
|
||||
expectedError: "error removing the node",
|
||||
},
|
||||
|
||||
@ -52,19 +52,22 @@ func runUpdate(ctx context.Context, dockerCLI command.Cli, flags *pflag.FlagSet,
|
||||
|
||||
func updateNodes(ctx context.Context, apiClient client.NodeAPIClient, nodes []string, mergeNode func(node *swarm.Node) error, success func(nodeID string)) error {
|
||||
for _, nodeID := range nodes {
|
||||
node, _, err := apiClient.NodeInspectWithRaw(ctx, nodeID)
|
||||
res, err := apiClient.NodeInspect(ctx, nodeID, client.NodeInspectOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = mergeNode(&node)
|
||||
err = mergeNode(&res.Node)
|
||||
if err != nil {
|
||||
if errors.Is(err, errNoRoleChange) {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
err = apiClient.NodeUpdate(ctx, node.ID, node.Version, node.Spec)
|
||||
_, err = apiClient.NodeUpdate(ctx, res.Node.ID, client.NodeUpdateOptions{
|
||||
Version: res.Node.Version,
|
||||
Node: res.Node.Spec,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/docker/cli/internal/test/builders"
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
@ -16,8 +17,8 @@ func TestNodeUpdateErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
flags map[string]string
|
||||
nodeInspectFunc func() (swarm.Node, []byte, error)
|
||||
nodeUpdateFunc func(nodeID string, version swarm.Version, node swarm.NodeSpec) error
|
||||
nodeInspectFunc func() (client.NodeInspectResult, error)
|
||||
nodeUpdateFunc func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
@ -29,29 +30,31 @@ func TestNodeUpdateErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return swarm.Node{}, []byte{}, errors.New("error inspecting the node")
|
||||
nodeInspectFunc: func() (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{}, errors.New("error inspecting the node")
|
||||
},
|
||||
expectedError: "error inspecting the node",
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
return errors.New("error updating the node")
|
||||
nodeUpdateFunc: func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error) {
|
||||
return client.NodeUpdateResult{}, errors.New("error updating the node")
|
||||
},
|
||||
expectedError: "error updating the node",
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *builders.Node(builders.NodeLabels(map[string]string{
|
||||
"key": "value",
|
||||
})), []byte{}, nil
|
||||
nodeInspectFunc: func() (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{
|
||||
Node: *builders.Node(builders.NodeLabels(map[string]string{
|
||||
"key": "value",
|
||||
})),
|
||||
}, nil
|
||||
},
|
||||
flags: map[string]string{
|
||||
"label-rm": "notpresent",
|
||||
"label-rm": "not-present",
|
||||
},
|
||||
expectedError: "key notpresent doesn't exist in node's labels",
|
||||
expectedError: "key not-present doesn't exist in node's labels",
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
@ -74,22 +77,24 @@ func TestNodeUpdate(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
flags map[string]string
|
||||
nodeInspectFunc func() (swarm.Node, []byte, error)
|
||||
nodeUpdateFunc func(nodeID string, version swarm.Version, node swarm.NodeSpec) error
|
||||
nodeInspectFunc func() (client.NodeInspectResult, error)
|
||||
nodeUpdateFunc func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error)
|
||||
}{
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
flags: map[string]string{
|
||||
"role": "manager",
|
||||
},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *builders.Node(), []byte{}, nil
|
||||
nodeInspectFunc: func() (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{
|
||||
Node: *builders.Node(),
|
||||
}, nil
|
||||
},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
if node.Role != swarm.NodeRoleManager {
|
||||
return errors.New("expected role manager, got " + string(node.Role))
|
||||
nodeUpdateFunc: func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error) {
|
||||
if options.Node.Role != swarm.NodeRoleManager {
|
||||
return client.NodeUpdateResult{}, errors.New("expected role manager, got " + string(options.Node.Role))
|
||||
}
|
||||
return nil
|
||||
return client.NodeUpdateResult{}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -97,14 +102,16 @@ func TestNodeUpdate(t *testing.T) {
|
||||
flags: map[string]string{
|
||||
"availability": "drain",
|
||||
},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *builders.Node(), []byte{}, nil
|
||||
nodeInspectFunc: func() (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{
|
||||
Node: *builders.Node(),
|
||||
}, nil
|
||||
},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
if node.Availability != swarm.NodeAvailabilityDrain {
|
||||
return errors.New("expected drain availability, got " + string(node.Availability))
|
||||
nodeUpdateFunc: func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error) {
|
||||
if options.Node.Availability != swarm.NodeAvailabilityDrain {
|
||||
return client.NodeUpdateResult{}, errors.New("expected drain availability, got " + string(options.Node.Availability))
|
||||
}
|
||||
return nil
|
||||
return client.NodeUpdateResult{}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -112,14 +119,16 @@ func TestNodeUpdate(t *testing.T) {
|
||||
flags: map[string]string{
|
||||
"label-add": "lbl",
|
||||
},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *builders.Node(), []byte{}, nil
|
||||
nodeInspectFunc: func() (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{
|
||||
Node: *builders.Node(),
|
||||
}, nil
|
||||
},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
if _, present := node.Annotations.Labels["lbl"]; !present {
|
||||
return fmt.Errorf("expected 'lbl' label, got %v", node.Annotations.Labels)
|
||||
nodeUpdateFunc: func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error) {
|
||||
if _, present := options.Node.Annotations.Labels["lbl"]; !present {
|
||||
return client.NodeUpdateResult{}, fmt.Errorf("expected 'lbl' label, got %v", options.Node.Annotations.Labels)
|
||||
}
|
||||
return nil
|
||||
return client.NodeUpdateResult{}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -127,14 +136,16 @@ func TestNodeUpdate(t *testing.T) {
|
||||
flags: map[string]string{
|
||||
"label-add": "key=value",
|
||||
},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *builders.Node(), []byte{}, nil
|
||||
nodeInspectFunc: func() (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{
|
||||
Node: *builders.Node(),
|
||||
}, nil
|
||||
},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
if value, present := node.Annotations.Labels["key"]; !present || value != "value" {
|
||||
return fmt.Errorf("expected 'key' label to be 'value', got %v", node.Annotations.Labels)
|
||||
nodeUpdateFunc: func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error) {
|
||||
if value, present := options.Node.Annotations.Labels["key"]; !present || value != "value" {
|
||||
return client.NodeUpdateResult{}, fmt.Errorf("expected 'key' label to be 'value', got %v", options.Node.Annotations.Labels)
|
||||
}
|
||||
return nil
|
||||
return client.NodeUpdateResult{}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -142,16 +153,18 @@ func TestNodeUpdate(t *testing.T) {
|
||||
flags: map[string]string{
|
||||
"label-rm": "key",
|
||||
},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *builders.Node(builders.NodeLabels(map[string]string{
|
||||
"key": "value",
|
||||
})), []byte{}, nil
|
||||
nodeInspectFunc: func() (client.NodeInspectResult, error) {
|
||||
return client.NodeInspectResult{
|
||||
Node: *builders.Node(builders.NodeLabels(map[string]string{
|
||||
"key": "value",
|
||||
})),
|
||||
}, nil
|
||||
},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
if len(node.Annotations.Labels) > 0 {
|
||||
return fmt.Errorf("expected no labels, got %v", node.Annotations.Labels)
|
||||
nodeUpdateFunc: func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error) {
|
||||
if len(options.Node.Annotations.Labels) > 0 {
|
||||
return client.NodeUpdateResult{}, fmt.Errorf("expected no labels, got %v", options.Node.Annotations.Labels)
|
||||
}
|
||||
return nil
|
||||
return client.NodeUpdateResult{}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -4,81 +4,79 @@ import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/moby/moby/api/types/plugin"
|
||||
"github.com/moby/moby/api/types/system"
|
||||
"github.com/moby/moby/client"
|
||||
)
|
||||
|
||||
type fakeClient struct {
|
||||
client.Client
|
||||
pluginCreateFunc func(createContext io.Reader, options client.PluginCreateOptions) error
|
||||
pluginDisableFunc func(name string, options client.PluginDisableOptions) error
|
||||
pluginEnableFunc func(name string, options client.PluginEnableOptions) error
|
||||
pluginRemoveFunc func(name string, options client.PluginRemoveOptions) error
|
||||
pluginInstallFunc func(name string, options client.PluginInstallOptions) (io.ReadCloser, error)
|
||||
pluginListFunc func(options client.PluginListOptions) (plugin.ListResponse, error)
|
||||
pluginInspectFunc func(name string) (*plugin.Plugin, []byte, error)
|
||||
pluginUpgradeFunc func(name string, options client.PluginInstallOptions) (io.ReadCloser, error)
|
||||
pluginCreateFunc func(createContext io.Reader, options client.PluginCreateOptions) (client.PluginCreateResult, error)
|
||||
pluginDisableFunc func(name string, options client.PluginDisableOptions) (client.PluginDisableResult, error)
|
||||
pluginEnableFunc func(name string, options client.PluginEnableOptions) (client.PluginEnableResult, error)
|
||||
pluginRemoveFunc func(name string, options client.PluginRemoveOptions) (client.PluginRemoveResult, error)
|
||||
pluginInstallFunc func(name string, options client.PluginInstallOptions) (client.PluginInstallResult, error)
|
||||
pluginListFunc func(options client.PluginListOptions) (client.PluginListResult, error)
|
||||
pluginInspectFunc func(name string) (client.PluginInspectResult, error)
|
||||
pluginUpgradeFunc func(name string, options client.PluginUpgradeOptions) (client.PluginUpgradeResult, error)
|
||||
}
|
||||
|
||||
func (c *fakeClient) PluginCreate(_ context.Context, createContext io.Reader, options client.PluginCreateOptions) error {
|
||||
func (c *fakeClient) PluginCreate(_ context.Context, createContext io.Reader, options client.PluginCreateOptions) (client.PluginCreateResult, error) {
|
||||
if c.pluginCreateFunc != nil {
|
||||
return c.pluginCreateFunc(createContext, options)
|
||||
}
|
||||
return nil
|
||||
return client.PluginCreateResult{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) PluginEnable(_ context.Context, name string, options client.PluginEnableOptions) error {
|
||||
func (c *fakeClient) PluginEnable(_ context.Context, name string, options client.PluginEnableOptions) (client.PluginEnableResult, error) {
|
||||
if c.pluginEnableFunc != nil {
|
||||
return c.pluginEnableFunc(name, options)
|
||||
}
|
||||
return nil
|
||||
return client.PluginEnableResult{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) PluginDisable(_ context.Context, name string, options client.PluginDisableOptions) error {
|
||||
func (c *fakeClient) PluginDisable(_ context.Context, name string, options client.PluginDisableOptions) (client.PluginDisableResult, error) {
|
||||
if c.pluginDisableFunc != nil {
|
||||
return c.pluginDisableFunc(name, options)
|
||||
}
|
||||
return nil
|
||||
return client.PluginDisableResult{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) PluginRemove(_ context.Context, name string, options client.PluginRemoveOptions) error {
|
||||
func (c *fakeClient) PluginRemove(_ context.Context, name string, options client.PluginRemoveOptions) (client.PluginRemoveResult, error) {
|
||||
if c.pluginRemoveFunc != nil {
|
||||
return c.pluginRemoveFunc(name, options)
|
||||
}
|
||||
return nil
|
||||
return client.PluginRemoveResult{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) PluginInstall(_ context.Context, name string, options client.PluginInstallOptions) (io.ReadCloser, error) {
|
||||
func (c *fakeClient) PluginInstall(_ context.Context, name string, options client.PluginInstallOptions) (client.PluginInstallResult, error) {
|
||||
if c.pluginInstallFunc != nil {
|
||||
return c.pluginInstallFunc(name, options)
|
||||
}
|
||||
return nil, nil
|
||||
return client.PluginInstallResult{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) PluginList(_ context.Context, options client.PluginListOptions) (plugin.ListResponse, error) {
|
||||
func (c *fakeClient) PluginList(_ context.Context, options client.PluginListOptions) (client.PluginListResult, error) {
|
||||
if c.pluginListFunc != nil {
|
||||
return c.pluginListFunc(options)
|
||||
}
|
||||
|
||||
return plugin.ListResponse{}, nil
|
||||
return client.PluginListResult{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) PluginInspectWithRaw(_ context.Context, name string) (*plugin.Plugin, []byte, error) {
|
||||
func (c *fakeClient) PluginInspect(_ context.Context, name string, _ client.PluginInspectOptions) (client.PluginInspectResult, error) {
|
||||
if c.pluginInspectFunc != nil {
|
||||
return c.pluginInspectFunc(name)
|
||||
}
|
||||
|
||||
return nil, nil, nil
|
||||
return client.PluginInspectResult{}, nil
|
||||
}
|
||||
|
||||
func (*fakeClient) Info(context.Context) (system.Info, error) {
|
||||
return system.Info{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) PluginUpgrade(_ context.Context, name string, options client.PluginInstallOptions) (io.ReadCloser, error) {
|
||||
func (c *fakeClient) PluginUpgrade(_ context.Context, name string, options client.PluginUpgradeOptions) (client.PluginUpgradeResult, error) {
|
||||
if c.pluginUpgradeFunc != nil {
|
||||
return c.pluginUpgradeFunc(name, options)
|
||||
}
|
||||
// FIXME(thaJeztah): how to mock this?
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@ -32,14 +32,14 @@ func completeNames(dockerCLI completion.APIClientProvider, state pluginState) co
|
||||
// no filter
|
||||
}
|
||||
|
||||
list, err := dockerCLI.Client().PluginList(cmd.Context(), client.PluginListOptions{
|
||||
res, err := dockerCLI.Client().PluginList(cmd.Context(), client.PluginListOptions{
|
||||
Filters: f,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
var names []string
|
||||
for _, v := range list {
|
||||
for _, v := range res.Items {
|
||||
names = append(names, v.Name)
|
||||
}
|
||||
return names, cobra.ShellCompDirectiveNoFileComp
|
||||
|
||||
@ -114,7 +114,7 @@ func runCreate(ctx context.Context, dockerCli command.Cli, options pluginCreateO
|
||||
return err
|
||||
}
|
||||
|
||||
err = dockerCli.Client().PluginCreate(ctx, createCtx, client.PluginCreateOptions{RepoName: options.repoName})
|
||||
_, err = dockerCli.Client().PluginCreate(ctx, createCtx, client.PluginCreateOptions{RepoName: options.repoName})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -96,8 +96,8 @@ func TestCreateErrorFromDaemon(t *testing.T) {
|
||||
defer tmpDir.Remove()
|
||||
|
||||
cmd := newCreateCommand(test.NewFakeCli(&fakeClient{
|
||||
pluginCreateFunc: func(createContext io.Reader, createOptions client.PluginCreateOptions) error {
|
||||
return errors.New("error creating plugin")
|
||||
pluginCreateFunc: func(createContext io.Reader, createOptions client.PluginCreateOptions) (client.PluginCreateResult, error) {
|
||||
return client.PluginCreateResult{}, errors.New("error creating plugin")
|
||||
},
|
||||
}))
|
||||
cmd.SetArgs([]string{"plugin-foo", tmpDir.Path()})
|
||||
@ -113,8 +113,8 @@ func TestCreatePlugin(t *testing.T) {
|
||||
defer tmpDir.Remove()
|
||||
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
pluginCreateFunc: func(createContext io.Reader, createOptions client.PluginCreateOptions) error {
|
||||
return nil
|
||||
pluginCreateFunc: func(createContext io.Reader, createOptions client.PluginCreateOptions) (client.PluginCreateResult, error) {
|
||||
return client.PluginCreateResult{}, nil
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ func newDisableCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
Args: cli.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
name := args[0]
|
||||
if err := dockerCLI.Client().PluginDisable(cmd.Context(), name, opts); err != nil {
|
||||
if _, err := dockerCLI.Client().PluginDisable(cmd.Context(), name, opts); err != nil {
|
||||
return err
|
||||
}
|
||||
_, _ = fmt.Fprintln(dockerCLI.Out(), name)
|
||||
|
||||
@ -15,7 +15,7 @@ func TestPluginDisableErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
expectedError string
|
||||
pluginDisableFunc func(name string, disableOptions client.PluginDisableOptions) error
|
||||
pluginDisableFunc func(name string, disableOptions client.PluginDisableOptions) (client.PluginDisableResult, error)
|
||||
}{
|
||||
{
|
||||
args: []string{},
|
||||
@ -28,8 +28,8 @@ func TestPluginDisableErrors(t *testing.T) {
|
||||
{
|
||||
args: []string{"plugin-foo"},
|
||||
expectedError: "error disabling plugin",
|
||||
pluginDisableFunc: func(name string, disableOptions client.PluginDisableOptions) error {
|
||||
return errors.New("error disabling plugin")
|
||||
pluginDisableFunc: func(name string, disableOptions client.PluginDisableOptions) (client.PluginDisableResult, error) {
|
||||
return client.PluginDisableResult{}, errors.New("error disabling plugin")
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -48,8 +48,8 @@ func TestPluginDisableErrors(t *testing.T) {
|
||||
|
||||
func TestPluginDisable(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
pluginDisableFunc: func(name string, disableOptions client.PluginDisableOptions) error {
|
||||
return nil
|
||||
pluginDisableFunc: func(name string, disableOptions client.PluginDisableOptions) (client.PluginDisableResult, error) {
|
||||
return client.PluginDisableResult{}, nil
|
||||
},
|
||||
})
|
||||
cmd := newDisableCommand(cli)
|
||||
|
||||
@ -38,5 +38,6 @@ func runEnable(ctx context.Context, dockerCli command.Cli, name string, opts cli
|
||||
if opts.Timeout < 0 {
|
||||
return fmt.Errorf("negative timeout %d is invalid", opts.Timeout)
|
||||
}
|
||||
return dockerCli.Client().PluginEnable(ctx, name, opts)
|
||||
_, err := dockerCli.Client().PluginEnable(ctx, name, opts)
|
||||
return err
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ func TestPluginEnableErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
flags map[string]string
|
||||
pluginEnableFunc func(name string, options client.PluginEnableOptions) error
|
||||
pluginEnableFunc func(name string, options client.PluginEnableOptions) (client.PluginEnableResult, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
@ -28,8 +28,8 @@ func TestPluginEnableErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
args: []string{"plugin-foo"},
|
||||
pluginEnableFunc: func(name string, options client.PluginEnableOptions) error {
|
||||
return errors.New("failed to enable plugin")
|
||||
pluginEnableFunc: func(name string, options client.PluginEnableOptions) (client.PluginEnableResult, error) {
|
||||
return client.PluginEnableResult{}, errors.New("failed to enable plugin")
|
||||
},
|
||||
expectedError: "failed to enable plugin",
|
||||
},
|
||||
@ -58,8 +58,8 @@ func TestPluginEnableErrors(t *testing.T) {
|
||||
|
||||
func TestPluginEnable(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
pluginEnableFunc: func(name string, options client.PluginEnableOptions) error {
|
||||
return nil
|
||||
pluginEnableFunc: func(name string, options client.PluginEnableOptions) (client.PluginEnableResult, error) {
|
||||
return client.PluginEnableResult{}, nil
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/docker/cli/cli/command/formatter"
|
||||
"github.com/moby/moby/api/types/plugin"
|
||||
"github.com/moby/moby/client"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -38,7 +39,7 @@ func newFormat(source string, quiet bool) formatter.Format {
|
||||
}
|
||||
|
||||
// formatWrite writes the context
|
||||
func formatWrite(fmtCtx formatter.Context, plugins []*plugin.Plugin) error {
|
||||
func formatWrite(fmtCtx formatter.Context, plugins client.PluginListResult) error {
|
||||
pluginCtx := &pluginContext{
|
||||
HeaderContext: formatter.HeaderContext{
|
||||
Header: formatter.SubHeaderContext{
|
||||
@ -51,7 +52,7 @@ func formatWrite(fmtCtx formatter.Context, plugins []*plugin.Plugin) error {
|
||||
},
|
||||
}
|
||||
return fmtCtx.Write(pluginCtx, func(format func(subContext formatter.SubContext) error) error {
|
||||
for _, p := range plugins {
|
||||
for _, p := range plugins.Items {
|
||||
if err := format(&pluginContext{
|
||||
trunc: fmtCtx.Trunc,
|
||||
p: *p,
|
||||
|
||||
@ -12,6 +12,7 @@ import (
|
||||
"github.com/docker/cli/cli/command/formatter"
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/moby/moby/api/types/plugin"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
@ -146,9 +147,11 @@ foobar_bar
|
||||
},
|
||||
}
|
||||
|
||||
plugins := []*plugin.Plugin{
|
||||
{ID: "pluginID1", Name: "foobar_baz", Config: plugin.Config{Description: "description 1"}, Enabled: true},
|
||||
{ID: "pluginID2", Name: "foobar_bar", Config: plugin.Config{Description: "description 2"}, Enabled: false},
|
||||
plugins := client.PluginListResult{
|
||||
Items: []*plugin.Plugin{
|
||||
{ID: "pluginID1", Name: "foobar_baz", Config: plugin.Config{Description: "description 1"}, Enabled: true},
|
||||
{ID: "pluginID2", Name: "foobar_bar", Config: plugin.Config{Description: "description 2"}, Enabled: false},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
@ -167,9 +170,11 @@ foobar_bar
|
||||
}
|
||||
|
||||
func TestPluginContextWriteJSON(t *testing.T) {
|
||||
plugins := []*plugin.Plugin{
|
||||
{ID: "pluginID1", Name: "foobar_baz"},
|
||||
{ID: "pluginID2", Name: "foobar_bar"},
|
||||
plugins := client.PluginListResult{
|
||||
Items: []*plugin.Plugin{
|
||||
{ID: "pluginID1", Name: "foobar_baz"},
|
||||
{ID: "pluginID2", Name: "foobar_bar"},
|
||||
},
|
||||
}
|
||||
expectedJSONs := []map[string]any{
|
||||
{"Description": "", "Enabled": false, "ID": "pluginID1", "Name": "foobar_baz", "PluginReference": ""},
|
||||
@ -191,9 +196,11 @@ func TestPluginContextWriteJSON(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPluginContextWriteJSONField(t *testing.T) {
|
||||
plugins := []*plugin.Plugin{
|
||||
{ID: "pluginID1", Name: "foobar_baz"},
|
||||
{ID: "pluginID2", Name: "foobar_bar"},
|
||||
plugins := client.PluginListResult{
|
||||
Items: []*plugin.Plugin{
|
||||
{ID: "pluginID1", Name: "foobar_baz"},
|
||||
{ID: "pluginID2", Name: "foobar_bar"},
|
||||
},
|
||||
}
|
||||
out := bytes.NewBufferString("")
|
||||
err := formatWrite(formatter.Context{Format: "{{json .ID}}", Output: out}, plugins)
|
||||
@ -205,6 +212,6 @@ func TestPluginContextWriteJSONField(t *testing.T) {
|
||||
if err := json.Unmarshal([]byte(line), &s); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Check(t, is.Equal(plugins[i].ID, s))
|
||||
assert.Check(t, is.Equal(plugins.Items[i].ID, s))
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/command/inspect"
|
||||
flagsHelper "github.com/docker/cli/cli/flags"
|
||||
"github.com/moby/moby/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -41,6 +42,7 @@ func newInspectCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
func runInspect(ctx context.Context, dockerCLI command.Cli, opts inspectOptions) error {
|
||||
apiClient := dockerCLI.Client()
|
||||
return inspect.Inspect(dockerCLI.Out(), opts.pluginNames, opts.format, func(ref string) (any, []byte, error) {
|
||||
return apiClient.PluginInspectWithRaw(ctx, ref)
|
||||
res, err := apiClient.PluginInspect(ctx, ref, client.PluginInspectOptions{})
|
||||
return res.Plugin, res.Raw, err
|
||||
})
|
||||
}
|
||||
|
||||
@ -8,28 +8,30 @@ import (
|
||||
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/moby/moby/api/types/plugin"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
"gotest.tools/v3/golden"
|
||||
)
|
||||
|
||||
var pluginFoo = &plugin.Plugin{
|
||||
ID: "id-foo",
|
||||
Name: "name-foo",
|
||||
Config: plugin.Config{
|
||||
Description: "plugin foo description",
|
||||
DockerVersion: "17.12.1-ce",
|
||||
Documentation: "plugin foo documentation",
|
||||
Entrypoint: []string{"/foo"},
|
||||
Interface: plugin.Interface{
|
||||
Socket: "plugin-foo.sock",
|
||||
},
|
||||
Linux: plugin.LinuxConfig{
|
||||
Capabilities: []string{"CAP_SYS_ADMIN"},
|
||||
},
|
||||
WorkDir: "workdir-foo",
|
||||
Rootfs: &plugin.RootFS{
|
||||
DiffIds: []string{"sha256:deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"},
|
||||
Type: "layers",
|
||||
var pluginFoo = client.PluginInspectResult{
|
||||
Plugin: plugin.Plugin{
|
||||
ID: "id-foo",
|
||||
Name: "name-foo",
|
||||
Config: plugin.Config{
|
||||
Description: "plugin foo description",
|
||||
Documentation: "plugin foo documentation",
|
||||
Entrypoint: []string{"/foo"},
|
||||
Interface: plugin.Interface{
|
||||
Socket: "plugin-foo.sock",
|
||||
},
|
||||
Linux: plugin.LinuxConfig{
|
||||
Capabilities: []string{"CAP_SYS_ADMIN"},
|
||||
},
|
||||
WorkDir: "workdir-foo",
|
||||
Rootfs: &plugin.RootFS{
|
||||
DiffIds: []string{"sha256:deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"},
|
||||
Type: "layers",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -40,7 +42,7 @@ func TestInspectErrors(t *testing.T) {
|
||||
args []string
|
||||
flags map[string]string
|
||||
expectedError string
|
||||
inspectFunc func(name string) (*plugin.Plugin, []byte, error)
|
||||
inspectFunc func(name string) (client.PluginInspectResult, error)
|
||||
}{
|
||||
{
|
||||
description: "too few arguments",
|
||||
@ -51,8 +53,8 @@ func TestInspectErrors(t *testing.T) {
|
||||
description: "error inspecting plugin",
|
||||
args: []string{"foo"},
|
||||
expectedError: "error inspecting plugin",
|
||||
inspectFunc: func(name string) (*plugin.Plugin, []byte, error) {
|
||||
return nil, nil, errors.New("error inspecting plugin")
|
||||
inspectFunc: func(string) (client.PluginInspectResult, error) {
|
||||
return client.PluginInspectResult{}, errors.New("error inspecting plugin")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -62,6 +64,9 @@ func TestInspectErrors(t *testing.T) {
|
||||
"format": "{{invalid format}}",
|
||||
},
|
||||
expectedError: "template parsing error",
|
||||
inspectFunc: func(string) (client.PluginInspectResult, error) {
|
||||
return client.PluginInspectResult{}, errors.New("this function should not be called in this test")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -86,7 +91,7 @@ func TestInspect(t *testing.T) {
|
||||
args []string
|
||||
flags map[string]string
|
||||
golden string
|
||||
inspectFunc func(name string) (*plugin.Plugin, []byte, error)
|
||||
inspectFunc func(name string) (client.PluginInspectResult, error)
|
||||
}{
|
||||
{
|
||||
description: "inspect single plugin with format",
|
||||
@ -95,19 +100,21 @@ func TestInspect(t *testing.T) {
|
||||
"format": "{{ .Name }}",
|
||||
},
|
||||
golden: "plugin-inspect-single-with-format.golden",
|
||||
inspectFunc: func(name string) (*plugin.Plugin, []byte, error) {
|
||||
return &plugin.Plugin{
|
||||
ID: "id-foo",
|
||||
Name: "name-foo",
|
||||
}, []byte{}, nil
|
||||
inspectFunc: func(name string) (client.PluginInspectResult, error) {
|
||||
return client.PluginInspectResult{
|
||||
Plugin: plugin.Plugin{
|
||||
ID: "id-foo",
|
||||
Name: "name-foo",
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "inspect single plugin without format",
|
||||
args: []string{"foo"},
|
||||
golden: "plugin-inspect-single-without-format.golden",
|
||||
inspectFunc: func(name string) (*plugin.Plugin, []byte, error) {
|
||||
return pluginFoo, nil, nil
|
||||
inspectFunc: func(name string) (client.PluginInspectResult, error) {
|
||||
return pluginFoo, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -117,20 +124,24 @@ func TestInspect(t *testing.T) {
|
||||
"format": "{{ .Name }}",
|
||||
},
|
||||
golden: "plugin-inspect-multiple-with-format.golden",
|
||||
inspectFunc: func(name string) (*plugin.Plugin, []byte, error) {
|
||||
inspectFunc: func(name string) (client.PluginInspectResult, error) {
|
||||
switch name {
|
||||
case "foo":
|
||||
return &plugin.Plugin{
|
||||
ID: "id-foo",
|
||||
Name: "name-foo",
|
||||
}, []byte{}, nil
|
||||
return client.PluginInspectResult{
|
||||
Plugin: plugin.Plugin{
|
||||
ID: "id-foo",
|
||||
Name: "name-foo",
|
||||
},
|
||||
}, nil
|
||||
case "bar":
|
||||
return &plugin.Plugin{
|
||||
ID: "id-bar",
|
||||
Name: "name-bar",
|
||||
}, []byte{}, nil
|
||||
return client.PluginInspectResult{
|
||||
Plugin: plugin.Plugin{
|
||||
ID: "id-bar",
|
||||
Name: "name-bar",
|
||||
},
|
||||
}, nil
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("unexpected plugin name: %s", name)
|
||||
return client.PluginInspectResult{}, fmt.Errorf("unexpected plugin name: %s", name)
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@ -17,7 +17,7 @@ func TestInstallErrors(t *testing.T) {
|
||||
description string
|
||||
args []string
|
||||
expectedError string
|
||||
installFunc func(name string, options client.PluginInstallOptions) (io.ReadCloser, error)
|
||||
installFunc func(name string, options client.PluginInstallOptions) (client.PluginInstallResult, error)
|
||||
}{
|
||||
{
|
||||
description: "insufficient number of arguments",
|
||||
@ -38,8 +38,8 @@ func TestInstallErrors(t *testing.T) {
|
||||
description: "installation error",
|
||||
args: []string{"foo"},
|
||||
expectedError: "error installing plugin",
|
||||
installFunc: func(name string, options client.PluginInstallOptions) (io.ReadCloser, error) {
|
||||
return nil, errors.New("error installing plugin")
|
||||
installFunc: func(name string, options client.PluginInstallOptions) (client.PluginInstallResult, error) {
|
||||
return client.PluginInstallResult{}, errors.New("error installing plugin")
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -61,23 +61,23 @@ func TestInstall(t *testing.T) {
|
||||
description string
|
||||
args []string
|
||||
expectedOutput string
|
||||
installFunc func(name string, options client.PluginInstallOptions) (io.ReadCloser, error)
|
||||
installFunc func(name string, options client.PluginInstallOptions) (client.PluginInstallResult, error)
|
||||
}{
|
||||
{
|
||||
description: "install with no additional flags",
|
||||
args: []string{"foo"},
|
||||
expectedOutput: "Installed plugin foo\n",
|
||||
installFunc: func(name string, options client.PluginInstallOptions) (io.ReadCloser, error) {
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
installFunc: func(name string, options client.PluginInstallOptions) (client.PluginInstallResult, error) {
|
||||
return client.PluginInstallResult{ReadCloser: io.NopCloser(strings.NewReader(""))}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "install with disable flag",
|
||||
args: []string{"--disable", "foo"},
|
||||
expectedOutput: "Installed plugin foo\n",
|
||||
installFunc: func(name string, options client.PluginInstallOptions) (io.ReadCloser, error) {
|
||||
installFunc: func(name string, options client.PluginInstallOptions) (client.PluginInstallResult, error) {
|
||||
assert.Check(t, options.Disabled)
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
return client.PluginInstallResult{ReadCloser: io.NopCloser(strings.NewReader(""))}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -54,8 +54,8 @@ func runList(ctx context.Context, dockerCli command.Cli, options listOptions) er
|
||||
return err
|
||||
}
|
||||
|
||||
sort.Slice(resp, func(i, j int) bool {
|
||||
return sortorder.NaturalLess(resp[i].Name, resp[j].Name)
|
||||
sort.Slice(resp.Items, func(i, j int) bool {
|
||||
return sortorder.NaturalLess(resp.Items[i].Name, resp.Items[j].Name)
|
||||
})
|
||||
|
||||
format := options.format
|
||||
|
||||
@ -19,7 +19,7 @@ func TestListErrors(t *testing.T) {
|
||||
args []string
|
||||
flags map[string]string
|
||||
expectedError string
|
||||
listFunc func(client.PluginListOptions) (plugin.ListResponse, error)
|
||||
listFunc func(client.PluginListOptions) (client.PluginListResult, error)
|
||||
}{
|
||||
{
|
||||
description: "too many arguments",
|
||||
@ -30,8 +30,8 @@ func TestListErrors(t *testing.T) {
|
||||
description: "error listing plugins",
|
||||
args: []string{},
|
||||
expectedError: "error listing plugins",
|
||||
listFunc: func(client.PluginListOptions) (plugin.ListResponse, error) {
|
||||
return plugin.ListResponse{}, errors.New("error listing plugins")
|
||||
listFunc: func(client.PluginListOptions) (client.PluginListResult, error) {
|
||||
return client.PluginListResult{}, errors.New("error listing plugins")
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -60,14 +60,16 @@ func TestListErrors(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
singlePluginListFunc := func(client.PluginListOptions) (plugin.ListResponse, error) {
|
||||
return plugin.ListResponse{
|
||||
{
|
||||
ID: "id-foo",
|
||||
Name: "name-foo",
|
||||
Enabled: true,
|
||||
Config: plugin.Config{
|
||||
Description: "desc-bar",
|
||||
singlePluginListFunc := func(client.PluginListOptions) (client.PluginListResult, error) {
|
||||
return client.PluginListResult{
|
||||
Items: plugin.ListResponse{
|
||||
{
|
||||
ID: "id-foo",
|
||||
Name: "name-foo",
|
||||
Enabled: true,
|
||||
Config: plugin.Config{
|
||||
Description: "desc-bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
@ -78,7 +80,7 @@ func TestList(t *testing.T) {
|
||||
args []string
|
||||
flags map[string]string
|
||||
golden string
|
||||
listFunc func(client.PluginListOptions) (plugin.ListResponse, error)
|
||||
listFunc func(client.PluginListOptions) (client.PluginListResult, error)
|
||||
}{
|
||||
{
|
||||
description: "list with no additional flags",
|
||||
@ -93,7 +95,7 @@ func TestList(t *testing.T) {
|
||||
"filter": "foo=bar",
|
||||
},
|
||||
golden: "plugin-list-without-format.golden",
|
||||
listFunc: func(opts client.PluginListOptions) (plugin.ListResponse, error) {
|
||||
listFunc: func(opts client.PluginListOptions) (client.PluginListResult, error) {
|
||||
assert.Check(t, opts.Filters["foo"]["bar"])
|
||||
return singlePluginListFunc(opts)
|
||||
},
|
||||
@ -115,16 +117,16 @@ func TestList(t *testing.T) {
|
||||
"format": "{{ .ID }}",
|
||||
},
|
||||
golden: "plugin-list-with-no-trunc-option.golden",
|
||||
listFunc: func(client.PluginListOptions) (plugin.ListResponse, error) {
|
||||
return plugin.ListResponse{
|
||||
{
|
||||
listFunc: func(opts client.PluginListOptions) (client.PluginListResult, error) {
|
||||
return client.PluginListResult{
|
||||
Items: []*plugin.Plugin{{
|
||||
ID: "xyg4z2hiSLO5yTnBJfg4OYia9gKA6Qjd",
|
||||
Name: "name-foo",
|
||||
Enabled: true,
|
||||
Config: plugin.Config{
|
||||
Description: "desc-bar",
|
||||
},
|
||||
},
|
||||
}},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
@ -144,19 +146,21 @@ func TestList(t *testing.T) {
|
||||
"format": "{{ .Name }}",
|
||||
},
|
||||
golden: "plugin-list-sort.golden",
|
||||
listFunc: func(client.PluginListOptions) (plugin.ListResponse, error) {
|
||||
return plugin.ListResponse{
|
||||
{
|
||||
ID: "id-1",
|
||||
Name: "plugin-1-foo",
|
||||
},
|
||||
{
|
||||
ID: "id-2",
|
||||
Name: "plugin-10-foo",
|
||||
},
|
||||
{
|
||||
ID: "id-3",
|
||||
Name: "plugin-2-foo",
|
||||
listFunc: func(client.PluginListOptions) (client.PluginListResult, error) {
|
||||
return client.PluginListResult{
|
||||
Items: []*plugin.Plugin{
|
||||
{
|
||||
ID: "id-1",
|
||||
Name: "plugin-1-foo",
|
||||
},
|
||||
{
|
||||
ID: "id-2",
|
||||
Name: "plugin-10-foo",
|
||||
},
|
||||
{
|
||||
ID: "id-3",
|
||||
Name: "plugin-2-foo",
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
|
||||
@ -8,6 +8,7 @@ import (
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/internal/jsonstream"
|
||||
"github.com/moby/moby/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -45,7 +46,9 @@ func runPush(ctx context.Context, dockerCli command.Cli, name string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
responseBody, err := dockerCli.Client().PluginPush(ctx, reference.FamiliarString(named), encodedAuth)
|
||||
responseBody, err := dockerCli.Client().PluginPush(ctx, reference.FamiliarString(named), client.PluginPushOptions{
|
||||
RegistryAuth: encodedAuth,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ func runRemove(ctx context.Context, dockerCLI command.Cli, opts *rmOptions) erro
|
||||
|
||||
var errs []error
|
||||
for _, name := range opts.plugins {
|
||||
if err := apiClient.PluginRemove(ctx, name, client.PluginRemoveOptions{Force: opts.force}); err != nil {
|
||||
if _, err := apiClient.PluginRemove(ctx, name, client.PluginRemoveOptions{Force: opts.force}); err != nil {
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@ import (
|
||||
func TestRemoveErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
pluginRemoveFunc func(name string, options client.PluginRemoveOptions) error
|
||||
pluginRemoveFunc func(name string, options client.PluginRemoveOptions) (client.PluginRemoveResult, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
@ -23,8 +23,8 @@ func TestRemoveErrors(t *testing.T) {
|
||||
},
|
||||
{
|
||||
args: []string{"plugin-foo"},
|
||||
pluginRemoveFunc: func(name string, options client.PluginRemoveOptions) error {
|
||||
return errors.New("error removing plugin")
|
||||
pluginRemoveFunc: func(name string, options client.PluginRemoveOptions) (client.PluginRemoveResult, error) {
|
||||
return client.PluginRemoveResult{}, errors.New("error removing plugin")
|
||||
},
|
||||
expectedError: "error removing plugin",
|
||||
},
|
||||
@ -43,11 +43,7 @@ func TestRemoveErrors(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRemove(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
pluginRemoveFunc: func(name string, options client.PluginRemoveOptions) error {
|
||||
return nil
|
||||
},
|
||||
})
|
||||
cli := test.NewFakeCli(&fakeClient{})
|
||||
cmd := newRemoveCommand(cli)
|
||||
cmd.SetArgs([]string{"plugin-foo"})
|
||||
assert.NilError(t, cmd.Execute())
|
||||
@ -57,9 +53,9 @@ func TestRemove(t *testing.T) {
|
||||
func TestRemoveWithForceOption(t *testing.T) {
|
||||
force := false
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
pluginRemoveFunc: func(name string, options client.PluginRemoveOptions) error {
|
||||
pluginRemoveFunc: func(name string, options client.PluginRemoveOptions) (client.PluginRemoveResult, error) {
|
||||
force = options.Force
|
||||
return nil
|
||||
return client.PluginRemoveResult{}, nil
|
||||
},
|
||||
})
|
||||
cmd := newRemoveCommand(cli)
|
||||
|
||||
@ -3,6 +3,7 @@ package plugin
|
||||
import (
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/moby/moby/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -12,7 +13,10 @@ func newSetCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
Short: "Change settings for a plugin",
|
||||
Args: cli.RequiresMinArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return dockerCLI.Client().PluginSet(cmd.Context(), args[0], args[1:])
|
||||
_, err := dockerCLI.Client().PluginSet(cmd.Context(), args[0], client.PluginSetOptions{
|
||||
Args: args[1:],
|
||||
})
|
||||
return err
|
||||
},
|
||||
ValidArgsFunction: completeNames(dockerCLI, stateAny), // TODO(thaJeztah): should only complete for the first arg
|
||||
DisableFlagsInUseLine: true,
|
||||
|
||||
@ -8,7 +8,6 @@
|
||||
"Value": null
|
||||
},
|
||||
"Description": "plugin foo description",
|
||||
"DockerVersion": "17.12.1-ce",
|
||||
"Documentation": "plugin foo documentation",
|
||||
"Entrypoint": [
|
||||
"/foo"
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/internal/jsonstream"
|
||||
"github.com/docker/cli/internal/prompt"
|
||||
"github.com/moby/moby/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -40,18 +41,18 @@ func newUpgradeCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
}
|
||||
|
||||
func runUpgrade(ctx context.Context, dockerCLI command.Cli, opts pluginOptions) error {
|
||||
p, _, err := dockerCLI.Client().PluginInspectWithRaw(ctx, opts.localName)
|
||||
res, err := dockerCLI.Client().PluginInspect(ctx, opts.localName, client.PluginInspectOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error reading plugin data: %w", err)
|
||||
}
|
||||
|
||||
if p.Enabled {
|
||||
if res.Plugin.Enabled {
|
||||
return errors.New("the plugin must be disabled before upgrading")
|
||||
}
|
||||
|
||||
opts.localName = p.Name
|
||||
opts.localName = res.Plugin.Name
|
||||
if opts.remote == "" {
|
||||
opts.remote = p.PluginReference
|
||||
opts.remote = res.Plugin.PluginReference
|
||||
}
|
||||
remote, err := reference.ParseNormalizedNamed(opts.remote)
|
||||
if err != nil {
|
||||
@ -59,13 +60,13 @@ func runUpgrade(ctx context.Context, dockerCLI command.Cli, opts pluginOptions)
|
||||
}
|
||||
remote = reference.TagNameOnly(remote)
|
||||
|
||||
old, err := reference.ParseNormalizedNamed(p.PluginReference)
|
||||
old, err := reference.ParseNormalizedNamed(res.Plugin.PluginReference)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing current image reference: %w", err)
|
||||
}
|
||||
old = reference.TagNameOnly(old)
|
||||
|
||||
_, _ = fmt.Fprintf(dockerCLI.Out(), "Upgrading plugin %s from %s to %s\n", p.Name, reference.FamiliarString(old), reference.FamiliarString(remote))
|
||||
_, _ = fmt.Fprintf(dockerCLI.Out(), "Upgrading plugin %s from %s to %s\n", res.Plugin.Name, reference.FamiliarString(old), reference.FamiliarString(remote))
|
||||
if !opts.skipRemoteCheck && remote.String() != old.String() {
|
||||
r, err := prompt.Confirm(ctx, dockerCLI.In(), dockerCLI.Out(), "Plugin images do not match, are you sure?")
|
||||
if err != nil {
|
||||
@ -81,7 +82,7 @@ func runUpgrade(ctx context.Context, dockerCLI command.Cli, opts pluginOptions)
|
||||
return err
|
||||
}
|
||||
|
||||
responseBody, err := dockerCLI.Client().PluginUpgrade(ctx, opts.localName, options)
|
||||
responseBody, err := dockerCLI.Client().PluginUpgrade(ctx, opts.localName, client.PluginUpgradeOptions(options))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -17,16 +17,18 @@ func TestUpgradePromptTermination(t *testing.T) {
|
||||
t.Cleanup(cancel)
|
||||
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
pluginUpgradeFunc: func(name string, options client.PluginInstallOptions) (io.ReadCloser, error) {
|
||||
pluginUpgradeFunc: func(name string, options client.PluginUpgradeOptions) (client.PluginUpgradeResult, error) {
|
||||
return nil, errors.New("should not be called")
|
||||
},
|
||||
pluginInspectFunc: func(name string) (*plugin.Plugin, []byte, error) {
|
||||
return &plugin.Plugin{
|
||||
ID: "5724e2c8652da337ab2eedd19fc6fc0ec908e4bd907c7421bf6a8dfc70c4c078",
|
||||
Name: "foo/bar",
|
||||
Enabled: false,
|
||||
PluginReference: "localhost:5000/foo/bar:v0.1.0",
|
||||
}, []byte{}, nil
|
||||
pluginInspectFunc: func(name string) (client.PluginInspectResult, error) {
|
||||
return client.PluginInspectResult{
|
||||
Plugin: plugin.Plugin{
|
||||
ID: "5724e2c8652da337ab2eedd19fc6fc0ec908e4bd907c7421bf6a8dfc70c4c078",
|
||||
Name: "foo/bar",
|
||||
Enabled: false,
|
||||
PluginReference: "localhost:5000/foo/bar:v0.1.0",
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
cmd := newUpgradeCommand(cli)
|
||||
|
||||
@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/docker/cli/cli/command/formatter"
|
||||
registrytypes "github.com/moby/moby/api/types/registry"
|
||||
"github.com/moby/moby/client"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -26,7 +27,7 @@ func newFormat(source string) formatter.Format {
|
||||
}
|
||||
|
||||
// formatWrite writes the context.
|
||||
func formatWrite(fmtCtx formatter.Context, results []registrytypes.SearchResult) error {
|
||||
func formatWrite(fmtCtx formatter.Context, results client.ImageSearchResult) error {
|
||||
searchCtx := &searchContext{
|
||||
HeaderContext: formatter.HeaderContext{
|
||||
Header: formatter.SubHeaderContext{
|
||||
@ -38,7 +39,7 @@ func formatWrite(fmtCtx formatter.Context, results []registrytypes.SearchResult)
|
||||
},
|
||||
}
|
||||
return fmtCtx.Write(searchCtx, func(format func(subContext formatter.SubContext) error) error {
|
||||
for _, result := range results {
|
||||
for _, result := range results.Items {
|
||||
if err := format(&searchContext{
|
||||
trunc: fmtCtx.Trunc,
|
||||
s: result,
|
||||
|
||||
@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/docker/cli/cli/command/formatter"
|
||||
registrytypes "github.com/moby/moby/api/types/registry"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
"gotest.tools/v3/golden"
|
||||
@ -184,9 +185,11 @@ result2 5
|
||||
},
|
||||
}
|
||||
|
||||
results := []registrytypes.SearchResult{
|
||||
{Name: "result1", Description: "Official build", StarCount: 5000, IsOfficial: true},
|
||||
{Name: "result2", Description: "Not official", StarCount: 5},
|
||||
results := client.ImageSearchResult{
|
||||
Items: []registrytypes.SearchResult{
|
||||
{Name: "result1", Description: "Official build", StarCount: 5000, IsOfficial: true},
|
||||
{Name: "result2", Description: "Not official", StarCount: 5},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
|
||||
@ -3,42 +3,41 @@ package secret
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/client"
|
||||
)
|
||||
|
||||
type fakeClient struct {
|
||||
client.Client
|
||||
secretCreateFunc func(context.Context, swarm.SecretSpec) (swarm.SecretCreateResponse, error)
|
||||
secretInspectFunc func(context.Context, string) (swarm.Secret, []byte, error)
|
||||
secretListFunc func(context.Context, client.SecretListOptions) ([]swarm.Secret, error)
|
||||
secretRemoveFunc func(context.Context, string) error
|
||||
secretCreateFunc func(context.Context, client.SecretCreateOptions) (client.SecretCreateResult, error)
|
||||
secretInspectFunc func(context.Context, string, client.SecretInspectOptions) (client.SecretInspectResult, error)
|
||||
secretListFunc func(context.Context, client.SecretListOptions) (client.SecretListResult, error)
|
||||
secretRemoveFunc func(context.Context, string, client.SecretRemoveOptions) (client.SecretRemoveResult, error)
|
||||
}
|
||||
|
||||
func (c *fakeClient) SecretCreate(ctx context.Context, spec swarm.SecretSpec) (swarm.SecretCreateResponse, error) {
|
||||
func (c *fakeClient) SecretCreate(ctx context.Context, options client.SecretCreateOptions) (client.SecretCreateResult, error) {
|
||||
if c.secretCreateFunc != nil {
|
||||
return c.secretCreateFunc(ctx, spec)
|
||||
return c.secretCreateFunc(ctx, options)
|
||||
}
|
||||
return swarm.SecretCreateResponse{}, nil
|
||||
return client.SecretCreateResult{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) SecretInspectWithRaw(ctx context.Context, id string) (swarm.Secret, []byte, error) {
|
||||
func (c *fakeClient) SecretInspect(ctx context.Context, id string, options client.SecretInspectOptions) (client.SecretInspectResult, error) {
|
||||
if c.secretInspectFunc != nil {
|
||||
return c.secretInspectFunc(ctx, id)
|
||||
return c.secretInspectFunc(ctx, id, options)
|
||||
}
|
||||
return swarm.Secret{}, nil, nil
|
||||
return client.SecretInspectResult{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) SecretList(ctx context.Context, options client.SecretListOptions) ([]swarm.Secret, error) {
|
||||
func (c *fakeClient) SecretList(ctx context.Context, options client.SecretListOptions) (client.SecretListResult, error) {
|
||||
if c.secretListFunc != nil {
|
||||
return c.secretListFunc(ctx, options)
|
||||
}
|
||||
return []swarm.Secret{}, nil
|
||||
return client.SecretListResult{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) SecretRemove(ctx context.Context, name string) error {
|
||||
func (c *fakeClient) SecretRemove(ctx context.Context, name string, options client.SecretRemoveOptions) (client.SecretRemoveResult, error) {
|
||||
if c.secretRemoveFunc != nil {
|
||||
return c.secretRemoveFunc(ctx, name)
|
||||
return c.secretRemoveFunc(ctx, name, options)
|
||||
}
|
||||
return nil
|
||||
return client.SecretRemoveResult{}, nil
|
||||
}
|
||||
|
||||
@ -38,12 +38,12 @@ func newSecretCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
// completeNames offers completion for swarm secrets
|
||||
func completeNames(dockerCLI completion.APIClientProvider) cobra.CompletionFunc {
|
||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
list, err := dockerCLI.Client().SecretList(cmd.Context(), client.SecretListOptions{})
|
||||
res, err := dockerCLI.Client().SecretList(cmd.Context(), client.SecretListOptions{})
|
||||
if err != nil {
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
}
|
||||
var names []string
|
||||
for _, secret := range list {
|
||||
for _, secret := range res.Items {
|
||||
names = append(names, secret.Spec.Name)
|
||||
}
|
||||
return names, cobra.ShellCompDirectiveNoFileComp
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/opts"
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/client"
|
||||
"github.com/moby/sys/sequential"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -100,7 +101,9 @@ func runSecretCreate(ctx context.Context, dockerCLI command.Cli, options createO
|
||||
Name: options.templateDriver,
|
||||
}
|
||||
}
|
||||
r, err := apiClient.SecretCreate(ctx, spec)
|
||||
r, err := apiClient.SecretCreate(ctx, client.SecretCreateOptions{
|
||||
Spec: spec,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user