diff --git a/client/client_interfaces.go b/client/client_interfaces.go index 7276e147a1..086c87badb 100644 --- a/client/client_interfaces.go +++ b/client/client_interfaces.go @@ -7,9 +7,7 @@ import ( "github.com/moby/moby/api/types" "github.com/moby/moby/api/types/container" - "github.com/moby/moby/api/types/events" "github.com/moby/moby/api/types/network" - "github.com/moby/moby/api/types/registry" "github.com/moby/moby/api/types/system" ) @@ -176,9 +174,9 @@ type SwarmAPIClient interface { // SystemAPIClient defines API client methods for the system type SystemAPIClient interface { - Events(ctx context.Context, options EventsListOptions) (<-chan events.Message, <-chan error) - Info(ctx context.Context) (system.Info, error) - RegistryLogin(ctx context.Context, auth registry.AuthConfig) (registry.AuthenticateOKBody, error) + Events(ctx context.Context, options EventsListOptions) EventsResult + Info(ctx context.Context, options InfoOptions) (SystemInfoResult, error) + RegistryLogin(ctx context.Context, auth RegistryLoginOptions) (RegistryLoginResult, error) DiskUsage(ctx context.Context, options DiskUsageOptions) (system.DiskUsage, error) Ping(ctx context.Context, options PingOptions) (PingResult, error) } diff --git a/client/client_test.go b/client/client_test.go index 4f6aec4c07..db69f84eed 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -408,13 +408,13 @@ func TestNegotiateAPIVersionAutomatic(t *testing.T) { // First request should trigger negotiation pingVersion = "1.50" expected = "1.50" - _, _ = client.Info(ctx) + _, _ = client.Info(ctx, InfoOptions{}) assert.Check(t, is.Equal(client.ClientVersion(), expected)) // Once successfully negotiated, subsequent requests should not re-negotiate pingVersion = "1.49" expected = "1.50" - _, _ = client.Info(ctx) + _, _ = client.Info(ctx, InfoOptions{}) assert.Check(t, is.Equal(client.ClientVersion(), expected)) } diff --git a/client/login.go b/client/login.go index 9cb365338d..6974ec22ce 100644 --- a/client/login.go +++ b/client/login.go @@ -8,17 +8,38 @@ import ( "github.com/moby/moby/api/types/registry" ) +type RegistryLoginOptions struct { + Username string + Password string + ServerAddress string + IdentityToken string + RegistryToken string +} + +// RegistryLoginResult holds the result of a RegistryLogin query. +type RegistryLoginResult struct { + Auth registry.AuthenticateOKBody +} + // RegistryLogin authenticates the docker server with a given docker registry. // It returns unauthorizedError when the authentication fails. -func (cli *Client) RegistryLogin(ctx context.Context, auth registry.AuthConfig) (registry.AuthenticateOKBody, error) { +func (cli *Client) RegistryLogin(ctx context.Context, options RegistryLoginOptions) (RegistryLoginResult, error) { + auth := registry.AuthConfig{ + Username: options.Username, + Password: options.Password, + ServerAddress: options.ServerAddress, + IdentityToken: options.IdentityToken, + RegistryToken: options.RegistryToken, + } + resp, err := cli.post(ctx, "/auth", url.Values{}, auth, nil) defer ensureReaderClosed(resp) if err != nil { - return registry.AuthenticateOKBody{}, err + return RegistryLoginResult{}, err } var response registry.AuthenticateOKBody err = json.NewDecoder(resp.Body).Decode(&response) - return response, err + return RegistryLoginResult{Auth: response}, err } diff --git a/client/system_events.go b/client/system_events.go index 598c2e25d3..748e012086 100644 --- a/client/system_events.go +++ b/client/system_events.go @@ -19,11 +19,17 @@ type EventsListOptions struct { Filters Filters } +// EventsResult holds the result of an Events query. +type EventsResult struct { + Messages <-chan events.Message + Err <-chan error +} + // Events returns a stream of events in the daemon. It's up to the caller to close the stream // by cancelling the context. Once the stream has been completely read an [io.EOF] error is // sent over the error channel. If an error is sent, all processing is stopped. It's up // to the caller to reopen the stream in the event of an error by reinvoking this method. -func (cli *Client) Events(ctx context.Context, options EventsListOptions) (<-chan events.Message, <-chan error) { +func (cli *Client) Events(ctx context.Context, options EventsListOptions) EventsResult { messages := make(chan events.Message) errs := make(chan error, 1) @@ -76,7 +82,10 @@ func (cli *Client) Events(ctx context.Context, options EventsListOptions) (<-cha }() <-started - return messages, errs + return EventsResult{ + Messages: messages, + Err: errs, + } } func buildEventsQueryParams(options EventsListOptions) (url.Values, error) { diff --git a/client/system_events_test.go b/client/system_events_test.go index 8acd827728..068a2182e7 100644 --- a/client/system_events_test.go +++ b/client/system_events_test.go @@ -37,8 +37,8 @@ func TestEventsErrorInOptions(t *testing.T) { for _, tc := range errorCases { client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error"))) assert.NilError(t, err) - _, errs := client.Events(context.Background(), tc.options) - err = <-errs + events := client.Events(context.Background(), tc.options) + err = <-events.Err assert.Check(t, is.ErrorContains(err, tc.expectedError)) } } @@ -46,8 +46,8 @@ func TestEventsErrorInOptions(t *testing.T) { func TestEventsErrorFromServer(t *testing.T) { client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error"))) assert.NilError(t, err) - _, errs := client.Events(context.Background(), EventsListOptions{}) - err = <-errs + events := client.Events(context.Background(), EventsListOptions{}) + err = <-events.Err assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal)) } @@ -133,18 +133,18 @@ func TestEvents(t *testing.T) { })) assert.NilError(t, err) - messages, errs := client.Events(context.Background(), eventsCase.options) + events := client.Events(context.Background(), eventsCase.options) loop: for { select { - case err := <-errs: + case err := <-events.Err: if err != nil && !errors.Is(err, io.EOF) { t.Fatal(err) } break loop - case e := <-messages: + case e := <-events.Messages: _, ok := eventsCase.expectedEvents[e.Actor.ID] assert.Check(t, ok, "event received not expected with action %s & id %s", e.Action, e.Actor.ID) } diff --git a/client/system_info.go b/client/system_info.go index 865cd35eee..4c0a2238e1 100644 --- a/client/system_info.go +++ b/client/system_info.go @@ -9,18 +9,26 @@ import ( "github.com/moby/moby/api/types/system" ) +type InfoOptions struct { + // No options currently; placeholder for future use +} + +type SystemInfoResult struct { + Info system.Info +} + // Info returns information about the docker server. -func (cli *Client) Info(ctx context.Context) (system.Info, error) { - var info system.Info +func (cli *Client) Info(ctx context.Context, options InfoOptions) (SystemInfoResult, error) { resp, err := cli.get(ctx, "/info", url.Values{}, nil) defer ensureReaderClosed(resp) if err != nil { - return info, err + return SystemInfoResult{}, err } + var info system.Info if err := json.NewDecoder(resp.Body).Decode(&info); err != nil { - return info, fmt.Errorf("Error reading remote info: %v", err) + return SystemInfoResult{}, fmt.Errorf("Error reading remote info: %v", err) } - return info, nil + return SystemInfoResult{Info: info}, nil } diff --git a/client/system_info_test.go b/client/system_info_test.go index 0521907bb4..4680e1a6be 100644 --- a/client/system_info_test.go +++ b/client/system_info_test.go @@ -14,14 +14,14 @@ import ( func TestInfoServerError(t *testing.T) { client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error"))) assert.NilError(t, err) - _, err = client.Info(context.Background()) + _, err = client.Info(context.Background(), InfoOptions{}) assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal)) } func TestInfoInvalidResponseJSONError(t *testing.T) { client, err := NewClientWithOpts(WithMockClient(mockResponse(http.StatusOK, nil, "invalid json"))) assert.NilError(t, err) - _, err = client.Info(context.Background()) + _, err = client.Info(context.Background(), InfoOptions{}) assert.Check(t, is.ErrorContains(err, "invalid character")) } @@ -38,8 +38,9 @@ func TestInfo(t *testing.T) { })) assert.NilError(t, err) - info, err := client.Info(context.Background()) + result, err := client.Info(context.Background(), InfoOptions{}) assert.NilError(t, err) + info := result.Info assert.Check(t, is.Equal(info.ID, "daemonID")) assert.Check(t, is.Equal(info.Containers, 3)) @@ -68,8 +69,9 @@ func TestInfoWithDiscoveredDevices(t *testing.T) { })) assert.NilError(t, err) - info, err := client.Info(context.Background()) + result, err := client.Info(context.Background(), InfoOptions{}) assert.NilError(t, err) + info := result.Info assert.Check(t, is.Equal(info.ID, "daemonID")) assert.Check(t, is.Equal(info.Containers, 3)) diff --git a/integration-cli/docker_api_swarm_test.go b/integration-cli/docker_api_swarm_test.go index 8c8f15d871..05bea86af3 100644 --- a/integration-cli/docker_api_swarm_test.go +++ b/integration-cli/docker_api_swarm_test.go @@ -756,9 +756,9 @@ func checkClusterHealth(t *testing.T, cl []*daemon.Daemon, managerCount, workerC // check info in a poll.WaitOn(), because if the cluster doesn't have a leader, `info` will return an error checkInfo := func(t *testing.T) (any, string) { - client := d.NewClientT(t) - daemonInfo, err := client.Info(ctx) - info = daemonInfo.Swarm + apiClient := d.NewClientT(t) + result, err := apiClient.Info(ctx, client.InfoOptions{}) + info = result.Info.Swarm return err, "cluster not ready in time" } poll.WaitOn(t, pollCheck(t, checkInfo, checker.IsNil()), poll.WithTimeout(defaultReconciliationTimeout)) diff --git a/integration-cli/docker_cli_info_unix_test.go b/integration-cli/docker_cli_info_unix_test.go index 26ebb8f49a..7122b5e4cd 100644 --- a/integration-cli/docker_cli_info_unix_test.go +++ b/integration-cli/docker_cli_info_unix_test.go @@ -21,8 +21,9 @@ func (s *DockerCLIInfoSuite) TestInfoSecurityOptions(c *testing.T) { apiClient, err := client.NewClientWithOpts(client.FromEnv) assert.NilError(c, err) defer apiClient.Close() - info, err := apiClient.Info(testutil.GetContext(c)) + result, err := apiClient.Info(testutil.GetContext(c), client.InfoOptions{}) assert.NilError(c, err) + info := result.Info if Apparmor() { assert.Check(c, is.Contains(info.SecurityOptions, "name=apparmor")) diff --git a/integration-cli/docker_cli_plugins_logdriver_test.go b/integration-cli/docker_cli_plugins_logdriver_test.go index c36450169e..2911309e8e 100644 --- a/integration-cli/docker_cli_plugins_logdriver_test.go +++ b/integration-cli/docker_cli_plugins_logdriver_test.go @@ -54,8 +54,9 @@ func (s *DockerCLIPluginLogDriverSuite) TestPluginLogDriverInfoList(c *testing.T assert.NilError(c, err) defer apiClient.Close() - info, err := apiClient.Info(testutil.GetContext(c)) + result, err := apiClient.Info(testutil.GetContext(c), client.InfoOptions{}) assert.NilError(c, err) + info := result.Info drivers := strings.Join(info.Plugins.Log, " ") assert.Assert(c, is.Contains(drivers, "json-file")) diff --git a/integration-cli/docker_utils_test.go b/integration-cli/docker_utils_test.go index 7f88f2dc84..f3b1fab670 100644 --- a/integration-cli/docker_utils_test.go +++ b/integration-cli/docker_utils_test.go @@ -200,8 +200,9 @@ func daemonTime(t *testing.T) time.Time { assert.NilError(t, err) defer apiClient.Close() - info, err := apiClient.Info(testutil.GetContext(t)) + result, err := apiClient.Info(testutil.GetContext(t), client.InfoOptions{}) assert.NilError(t, err) + info := result.Info dt, err := time.Parse(time.RFC3339Nano, info.SystemTime) assert.Assert(t, err == nil, "invalid time format in GET /info response") @@ -286,11 +287,11 @@ func minimalBaseImage() string { } func getGoroutineNumber(ctx context.Context, apiClient client.APIClient) (int, error) { - info, err := apiClient.Info(ctx) + result, err := apiClient.Info(ctx, client.InfoOptions{}) if err != nil { return 0, err } - return info.NGoroutines, nil + return result.Info.NGoroutines, nil } func waitForStableGoroutineCount(ctx context.Context, t poll.TestingT, apiClient client.APIClient) int { diff --git a/integration/build/build_test.go b/integration/build/build_test.go index 1e4f274943..7539471588 100644 --- a/integration/build/build_test.go +++ b/integration/build/build_test.go @@ -740,10 +740,12 @@ func TestBuildEmitsImageCreateEvent(t *testing.T) { assert.NilError(t, err) buildLogs := out.String() - eventsChan, errs := apiClient.Events(ctx, client.EventsListOptions{ + result := apiClient.Events(ctx, client.EventsListOptions{ Since: since.Format(time.RFC3339Nano), Until: time.Now().Format(time.RFC3339Nano), }) + eventsChan := result.Messages + errs := result.Err var eventsReceived []string imageCreateEvts := 0 diff --git a/integration/container/cdi_test.go b/integration/container/cdi_test.go index 68dfa8460c..a9318d7f49 100644 --- a/integration/container/cdi_test.go +++ b/integration/container/cdi_test.go @@ -188,8 +188,9 @@ func TestCDIInfoDiscoveredDevices(t *testing.T) { defer d.Stop(t) c := d.NewClientT(t) - info, err := c.Info(ctx) + result, err := c.Info(ctx, client.InfoOptions{}) assert.NilError(t, err) + info := result.Info assert.Check(t, is.Len(info.CDISpecDirs, 1)) assert.Check(t, is.Equal(info.CDISpecDirs[0], cdiDir)) diff --git a/integration/container/create_test.go b/integration/container/create_test.go index 8a20516300..e96ab8e1b8 100644 --- a/integration/container/create_test.go +++ b/integration/container/create_test.go @@ -807,9 +807,10 @@ func TestContainerdContainerImageInfo(t *testing.T) { apiClient := testEnv.APIClient() defer apiClient.Close() - info, err := apiClient.Info(ctx) + result, err := apiClient.Info(ctx, client.InfoOptions{}) assert.NilError(t, err) + info := result.Info skip.If(t, info.Containerd == nil, "requires containerd") // Currently a containerd container is only created when the container is started. diff --git a/integration/container/mounts_linux_test.go b/integration/container/mounts_linux_test.go index e5e24e5674..8d43ed7d1a 100644 --- a/integration/container/mounts_linux_test.go +++ b/integration/container/mounts_linux_test.go @@ -98,10 +98,11 @@ func TestMountDaemonRoot(t *testing.T) { ctx := setupTest(t) apiClient := testEnv.APIClient() - info, err := apiClient.Info(ctx) + result, err := apiClient.Info(ctx, client.InfoOptions{}) if err != nil { t.Fatal(err) } + info := result.Info for _, test := range []struct { desc string diff --git a/integration/container/pause_test.go b/integration/container/pause_test.go index 2e7bab1e5e..d32d84c0a4 100644 --- a/integration/container/pause_test.go +++ b/integration/container/pause_test.go @@ -39,11 +39,13 @@ func TestPause(t *testing.T) { until := request.DaemonUnixTime(ctx, t, apiClient, testEnv) - messages, errs := apiClient.Events(ctx, client.EventsListOptions{ + result := apiClient.Events(ctx, client.EventsListOptions{ Since: since, Until: until, Filters: make(client.Filters).Add(string(events.ContainerEventType), cID), }) + messages := result.Messages + errs := result.Err assert.Check(t, is.DeepEqual([]events.Action{events.ActionPause, events.ActionUnPause}, getEventActions(t, messages, errs))) } diff --git a/integration/container/restart_test.go b/integration/container/restart_test.go index 07039a7d24..2b67e055c6 100644 --- a/integration/container/restart_test.go +++ b/integration/container/restart_test.go @@ -247,9 +247,11 @@ func TestContainerRestartWithCancelledRequest(t *testing.T) { }() // Start listening for events. - messages, errs := apiClient.Events(ctx, client.EventsListOptions{ + result := apiClient.Events(ctx, client.EventsListOptions{ Filters: make(client.Filters).Add("container", cID).Add("event", string(events.ActionRestart)), }) + messages := result.Messages + errs := result.Err // Make restart request, but cancel the request before the container // is (forcibly) killed. diff --git a/integration/container/stats_test.go b/integration/container/stats_test.go index 167ac0511a..da6e12e2ea 100644 --- a/integration/container/stats_test.go +++ b/integration/container/stats_test.go @@ -21,9 +21,10 @@ func TestStats(t *testing.T) { ctx := setupTest(t) apiClient := testEnv.APIClient() - info, err := apiClient.Info(ctx) + result, err := apiClient.Info(ctx, client.InfoOptions{}) assert.NilError(t, err) + info := result.Info cID := container.Run(ctx, t, apiClient) t.Run("no-stream", func(t *testing.T) { resp, err := apiClient.ContainerStats(ctx, cID, client.ContainerStatsOptions{ diff --git a/integration/internal/system/goroutines.go b/integration/internal/system/goroutines.go index 1b9c27fcec..a35e287080 100644 --- a/integration/internal/system/goroutines.go +++ b/integration/internal/system/goroutines.go @@ -70,9 +70,9 @@ func CheckGoroutineCount(ctx context.Context, apiClient client.SystemAPIClient, } func getGoroutineNumber(ctx context.Context, apiClient client.SystemAPIClient) (int, error) { - info, err := apiClient.Info(ctx) + result, err := apiClient.Info(ctx, client.InfoOptions{}) if err != nil { return 0, err } - return info.NGoroutines, nil + return result.Info.NGoroutines, nil } diff --git a/integration/networking/firewall_linux_test.go b/integration/networking/firewall_linux_test.go index 436b6d054e..0b117538bb 100644 --- a/integration/networking/firewall_linux_test.go +++ b/integration/networking/firewall_linux_test.go @@ -31,8 +31,9 @@ func TestInfoFirewallBackend(t *testing.T) { if !testEnv.IsRootless() && networking.FirewalldRunning() { expDriver += "+firewalld" } - info, err := c.Info(ctx) + result, err := c.Info(ctx, client.InfoOptions{}) assert.NilError(t, err) + info := result.Info assert.Assert(t, info.FirewallBackend != nil, "expected firewall backend in info response") t.Log("FirewallBackend: Driver:", info.FirewallBackend.Driver) for _, kv := range info.FirewallBackend.Info { @@ -43,8 +44,9 @@ func TestInfoFirewallBackend(t *testing.T) { // Check FirewallBackend is omitted for API <= 1.48. t.Run("api 1.48", func(t *testing.T) { c148 := request.NewAPIClient(t, client.WithVersion("1.48")) - info148, err := c148.Info(ctx) + result, err := c148.Info(ctx, client.InfoOptions{}) assert.NilError(t, err) + info148 := result.Info assert.Check(t, is.Nil(info148.FirewallBackend)) }) } diff --git a/integration/plugin/authz/authz_plugin_test.go b/integration/plugin/authz/authz_plugin_test.go index 26eaffafaf..8b7a38251f 100644 --- a/integration/plugin/authz/authz_plugin_test.go +++ b/integration/plugin/authz/authz_plugin_test.go @@ -276,9 +276,10 @@ func systemTime(ctx context.Context, t *testing.T, apiClient client.APIClient, t return time.Now() } - info, err := apiClient.Info(ctx) + result, err := apiClient.Info(ctx, client.InfoOptions{}) assert.NilError(t, err) + info := result.Info dt, err := time.Parse(time.RFC3339Nano, info.SystemTime) assert.NilError(t, err, "invalid time format in GET /info response") return dt @@ -289,9 +290,9 @@ func systemEventsSince(ctx context.Context, apiClient client.APIClient, since st Since: since, } ctx, cancel := context.WithCancel(ctx) - events, errs := apiClient.Events(ctx, eventOptions) + result := apiClient.Events(ctx, eventOptions) - return events, errs, cancel + return result.Messages, result.Err, cancel } func TestAuthZPluginErrorResponse(t *testing.T) { diff --git a/integration/system/event_test.go b/integration/system/event_test.go index 035ebb2e1a..fe317225f6 100644 --- a/integration/system/event_test.go +++ b/integration/system/event_test.go @@ -30,9 +30,11 @@ func TestEventsExecDie(t *testing.T) { }) assert.NilError(t, err) - msg, errs := apiClient.Events(ctx, client.EventsListOptions{ + result := apiClient.Events(ctx, client.EventsListOptions{ Filters: make(client.Filters).Add("container", cID).Add("event", string(events.ActionExecDie)), }) + msg := result.Messages + errs := result.Err _, err = apiClient.ExecStart(ctx, res.ID, client.ExecStartOptions{ Detach: true, @@ -107,11 +109,13 @@ func TestEventsVolumeCreate(t *testing.T) { Add("type", "volume"). Add("event", "create"). Add("volume", volName) - messages, errs := apiClient.Events(ctx, client.EventsListOptions{ + result := apiClient.Events(ctx, client.EventsListOptions{ Since: since, Until: request.DaemonUnixTime(ctx, t, apiClient, testEnv), Filters: filter, }) + messages := result.Messages + errs := result.Err volEvents, err := getEvents(messages, errs) assert.NilError(t, err) @@ -123,11 +127,13 @@ func TestEventsVolumeCreate(t *testing.T) { Target: "/tmp/foo", })) - messages, errs = apiClient.Events(ctx, client.EventsListOptions{ + result = apiClient.Events(ctx, client.EventsListOptions{ Since: since, Until: request.DaemonUnixTime(ctx, t, apiClient, testEnv), Filters: filter, }) + messages = result.Messages + errs = result.Err volEvents, err = getEvents(messages, errs) assert.NilError(t, err) diff --git a/integration/system/info_test.go b/integration/system/info_test.go index 65a81820f8..13e247ac28 100644 --- a/integration/system/info_test.go +++ b/integration/system/info_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/moby/moby/api/types/registry" + "github.com/moby/moby/client" "github.com/moby/moby/v2/internal/testutil" "github.com/moby/moby/v2/internal/testutil/daemon" "gotest.tools/v3/assert" @@ -17,9 +18,10 @@ func TestInfoAPI(t *testing.T) { ctx := setupTest(t) apiClient := testEnv.APIClient() - info, err := apiClient.Info(ctx) + result, err := apiClient.Info(ctx, client.InfoOptions{}) assert.NilError(t, err) + info := result.Info // TODO(thaJeztah): make sure we have other tests that run a local daemon and check other fields based on known state. assert.Check(t, info.ID != "") assert.Check(t, is.Equal(info.Containers, info.ContainersRunning+info.ContainersPaused+info.ContainersStopped)) @@ -51,9 +53,11 @@ func TestInfoAPIWarnings(t *testing.T) { d.Start(t, "-H=0.0.0.0:23756", "-H="+d.Sock()) defer d.Stop(t) - info, err := c.Info(ctx) + result, err := c.Info(ctx, client.InfoOptions{}) assert.NilError(t, err) + info := result.Info + stringsToCheck := []string{ "Access to the remote API is equivalent to root access", "http://0.0.0.0:23756", diff --git a/integration/system/login_test.go b/integration/system/login_test.go index 233502e1a0..ebc3209e2e 100644 --- a/integration/system/login_test.go +++ b/integration/system/login_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/moby/moby/api/types/registry" + "github.com/moby/moby/client" registrypkg "github.com/moby/moby/v2/daemon/pkg/registry" "github.com/moby/moby/v2/integration/internal/requirement" "gotest.tools/v3/assert" @@ -19,7 +19,7 @@ func TestLoginFailsWithBadCredentials(t *testing.T) { ctx := setupTest(t) apiClient := testEnv.APIClient() - _, err := apiClient.RegistryLogin(ctx, registry.AuthConfig{ + _, err := apiClient.RegistryLogin(ctx, client.RegistryLoginOptions{ Username: "no-user", Password: "no-password", }) diff --git a/internal/testutil/daemon/daemon.go b/internal/testutil/daemon/daemon.go index 0e0fdb2ba5..4c4c4dd39c 100644 --- a/internal/testutil/daemon/daemon.go +++ b/internal/testutil/daemon/daemon.go @@ -985,8 +985,9 @@ func (d *Daemon) queryRootDir() (string, error) { func (d *Daemon) Info(t testing.TB) system.Info { t.Helper() c := d.NewClientT(t) - info, err := c.Info(context.Background()) + result, err := c.Info(context.Background(), client.InfoOptions{}) assert.NilError(t, err) + info := result.Info assert.NilError(t, c.Close()) return info } diff --git a/internal/testutil/daemon/swarm.go b/internal/testutil/daemon/swarm.go index b848345e9f..4bb51535b1 100644 --- a/internal/testutil/daemon/swarm.go +++ b/internal/testutil/daemon/swarm.go @@ -162,8 +162,9 @@ func (d *Daemon) SwarmLeave(ctx context.Context, t testing.TB, force bool) error func (d *Daemon) SwarmInfo(ctx context.Context, t testing.TB) swarm.Info { t.Helper() cli := d.NewClientT(t) - info, err := cli.Info(ctx) + result, err := cli.Info(ctx, client.InfoOptions{}) assert.NilError(t, err, "get swarm info") + info := result.Info return info.Swarm } diff --git a/internal/testutil/environment/environment.go b/internal/testutil/environment/environment.go index c55b396dbe..98695269ad 100644 --- a/internal/testutil/environment/environment.go +++ b/internal/testutil/environment/environment.go @@ -46,10 +46,11 @@ func New(ctx context.Context) (*Execution, error) { // FromClient creates a new Execution environment from the passed in client func FromClient(ctx context.Context, c *client.Client) (*Execution, error) { - info, err := c.Info(ctx) + result, err := c.Info(ctx, client.InfoOptions{}) if err != nil { return nil, errors.Wrapf(err, "failed to get info from daemon") } + info := result.Info v, err := c.ServerVersion(context.Background()) if err != nil { return nil, errors.Wrapf(err, "failed to get version info from daemon") diff --git a/internal/testutil/request/request.go b/internal/testutil/request/request.go index dfd225905f..02a6c649da 100644 --- a/internal/testutil/request/request.go +++ b/internal/testutil/request/request.go @@ -33,14 +33,15 @@ func NewAPIClient(t testing.TB, ops ...client.Opt) client.APIClient { } // DaemonTime provides the current time on the daemon host -func DaemonTime(ctx context.Context, t testing.TB, client client.APIClient, testEnv *environment.Execution) time.Time { +func DaemonTime(ctx context.Context, t testing.TB, apiClient client.APIClient, testEnv *environment.Execution) time.Time { t.Helper() if testEnv.IsLocalDaemon() { return time.Now() } - info, err := client.Info(ctx) + result, err := apiClient.Info(ctx, client.InfoOptions{}) assert.NilError(t, err) + info := result.Info dt, err := time.Parse(time.RFC3339Nano, info.SystemTime) assert.NilError(t, err, "invalid time format in GET /info response") diff --git a/vendor/github.com/moby/moby/client/client_interfaces.go b/vendor/github.com/moby/moby/client/client_interfaces.go index 7276e147a1..086c87badb 100644 --- a/vendor/github.com/moby/moby/client/client_interfaces.go +++ b/vendor/github.com/moby/moby/client/client_interfaces.go @@ -7,9 +7,7 @@ import ( "github.com/moby/moby/api/types" "github.com/moby/moby/api/types/container" - "github.com/moby/moby/api/types/events" "github.com/moby/moby/api/types/network" - "github.com/moby/moby/api/types/registry" "github.com/moby/moby/api/types/system" ) @@ -176,9 +174,9 @@ type SwarmAPIClient interface { // SystemAPIClient defines API client methods for the system type SystemAPIClient interface { - Events(ctx context.Context, options EventsListOptions) (<-chan events.Message, <-chan error) - Info(ctx context.Context) (system.Info, error) - RegistryLogin(ctx context.Context, auth registry.AuthConfig) (registry.AuthenticateOKBody, error) + Events(ctx context.Context, options EventsListOptions) EventsResult + Info(ctx context.Context, options InfoOptions) (SystemInfoResult, error) + RegistryLogin(ctx context.Context, auth RegistryLoginOptions) (RegistryLoginResult, error) DiskUsage(ctx context.Context, options DiskUsageOptions) (system.DiskUsage, error) Ping(ctx context.Context, options PingOptions) (PingResult, error) } diff --git a/vendor/github.com/moby/moby/client/login.go b/vendor/github.com/moby/moby/client/login.go index 9cb365338d..6974ec22ce 100644 --- a/vendor/github.com/moby/moby/client/login.go +++ b/vendor/github.com/moby/moby/client/login.go @@ -8,17 +8,38 @@ import ( "github.com/moby/moby/api/types/registry" ) +type RegistryLoginOptions struct { + Username string + Password string + ServerAddress string + IdentityToken string + RegistryToken string +} + +// RegistryLoginResult holds the result of a RegistryLogin query. +type RegistryLoginResult struct { + Auth registry.AuthenticateOKBody +} + // RegistryLogin authenticates the docker server with a given docker registry. // It returns unauthorizedError when the authentication fails. -func (cli *Client) RegistryLogin(ctx context.Context, auth registry.AuthConfig) (registry.AuthenticateOKBody, error) { +func (cli *Client) RegistryLogin(ctx context.Context, options RegistryLoginOptions) (RegistryLoginResult, error) { + auth := registry.AuthConfig{ + Username: options.Username, + Password: options.Password, + ServerAddress: options.ServerAddress, + IdentityToken: options.IdentityToken, + RegistryToken: options.RegistryToken, + } + resp, err := cli.post(ctx, "/auth", url.Values{}, auth, nil) defer ensureReaderClosed(resp) if err != nil { - return registry.AuthenticateOKBody{}, err + return RegistryLoginResult{}, err } var response registry.AuthenticateOKBody err = json.NewDecoder(resp.Body).Decode(&response) - return response, err + return RegistryLoginResult{Auth: response}, err } diff --git a/vendor/github.com/moby/moby/client/system_events.go b/vendor/github.com/moby/moby/client/system_events.go index 598c2e25d3..748e012086 100644 --- a/vendor/github.com/moby/moby/client/system_events.go +++ b/vendor/github.com/moby/moby/client/system_events.go @@ -19,11 +19,17 @@ type EventsListOptions struct { Filters Filters } +// EventsResult holds the result of an Events query. +type EventsResult struct { + Messages <-chan events.Message + Err <-chan error +} + // Events returns a stream of events in the daemon. It's up to the caller to close the stream // by cancelling the context. Once the stream has been completely read an [io.EOF] error is // sent over the error channel. If an error is sent, all processing is stopped. It's up // to the caller to reopen the stream in the event of an error by reinvoking this method. -func (cli *Client) Events(ctx context.Context, options EventsListOptions) (<-chan events.Message, <-chan error) { +func (cli *Client) Events(ctx context.Context, options EventsListOptions) EventsResult { messages := make(chan events.Message) errs := make(chan error, 1) @@ -76,7 +82,10 @@ func (cli *Client) Events(ctx context.Context, options EventsListOptions) (<-cha }() <-started - return messages, errs + return EventsResult{ + Messages: messages, + Err: errs, + } } func buildEventsQueryParams(options EventsListOptions) (url.Values, error) { diff --git a/vendor/github.com/moby/moby/client/system_info.go b/vendor/github.com/moby/moby/client/system_info.go index 865cd35eee..4c0a2238e1 100644 --- a/vendor/github.com/moby/moby/client/system_info.go +++ b/vendor/github.com/moby/moby/client/system_info.go @@ -9,18 +9,26 @@ import ( "github.com/moby/moby/api/types/system" ) +type InfoOptions struct { + // No options currently; placeholder for future use +} + +type SystemInfoResult struct { + Info system.Info +} + // Info returns information about the docker server. -func (cli *Client) Info(ctx context.Context) (system.Info, error) { - var info system.Info +func (cli *Client) Info(ctx context.Context, options InfoOptions) (SystemInfoResult, error) { resp, err := cli.get(ctx, "/info", url.Values{}, nil) defer ensureReaderClosed(resp) if err != nil { - return info, err + return SystemInfoResult{}, err } + var info system.Info if err := json.NewDecoder(resp.Body).Decode(&info); err != nil { - return info, fmt.Errorf("Error reading remote info: %v", err) + return SystemInfoResult{}, fmt.Errorf("Error reading remote info: %v", err) } - return info, nil + return SystemInfoResult{Info: info}, nil }