From 612342198ce75f575b0ab785e724add50d21a4ed Mon Sep 17 00:00:00 2001 From: Austin Vazquez Date: Tue, 21 Oct 2025 09:31:50 -0500 Subject: [PATCH] client: refactor swarm api functions to wrap params/responses Co-authored-by: Claude Signed-off-by: Austin Vazquez --- client/client_interfaces.go | 14 +++--- client/swarm_get_unlock_key.go | 11 +++-- client/swarm_get_unlock_key_test.go | 4 +- client/swarm_init.go | 43 +++++++++++++++-- client/swarm_init_test.go | 7 ++- client/swarm_inspect.go | 15 ++++-- client/swarm_inspect_test.go | 4 +- client/swarm_join.go | 26 +++++++++- client/swarm_join_test.go | 5 +- client/swarm_leave.go | 14 ++++-- client/swarm_leave_test.go | 4 +- client/swarm_unlock.go | 15 +++++- client/swarm_unlock_test.go | 5 +- client/swarm_update.go | 23 ++++++--- client/swarm_update_flags.go | 8 ---- client/swarm_update_test.go | 4 +- integration-cli/docker_api_swarm_test.go | 20 ++++---- integration/system/ping_test.go | 5 +- internal/testutil/daemon/swarm.go | 48 +++++++++++++------ .../moby/moby/client/client_interfaces.go | 14 +++--- .../moby/moby/client/swarm_get_unlock_key.go | 11 +++-- .../github.com/moby/moby/client/swarm_init.go | 43 +++++++++++++++-- .../moby/moby/client/swarm_inspect.go | 15 ++++-- .../github.com/moby/moby/client/swarm_join.go | 26 +++++++++- .../moby/moby/client/swarm_leave.go | 14 ++++-- .../moby/moby/client/swarm_unlock.go | 15 +++++- .../moby/moby/client/swarm_update.go | 23 ++++++--- .../moby/moby/client/swarm_update_flags.go | 8 ---- 28 files changed, 318 insertions(+), 126 deletions(-) delete mode 100644 client/swarm_update_flags.go delete mode 100644 vendor/github.com/moby/moby/client/swarm_update_flags.go diff --git a/client/client_interfaces.go b/client/client_interfaces.go index fcb00553fc..f0b437eb43 100644 --- a/client/client_interfaces.go +++ b/client/client_interfaces.go @@ -174,13 +174,13 @@ type ServiceAPIClient interface { // SwarmAPIClient defines API client methods for the swarm type SwarmAPIClient interface { - SwarmInit(ctx context.Context, req swarm.InitRequest) (string, error) - SwarmJoin(ctx context.Context, req swarm.JoinRequest) error - SwarmGetUnlockKey(ctx context.Context) (swarm.UnlockKeyResponse, error) - SwarmUnlock(ctx context.Context, req swarm.UnlockRequest) error - SwarmLeave(ctx context.Context, force bool) error - SwarmInspect(ctx context.Context) (swarm.Swarm, error) - SwarmUpdate(ctx context.Context, version swarm.Version, swarm swarm.Spec, flags SwarmUpdateFlags) error + SwarmInit(ctx context.Context, options SwarmInitOptions) (SwarmInitResult, error) + SwarmJoin(ctx context.Context, options SwarmJoinOptions) (SwarmJoinResult, error) + SwarmGetUnlockKey(ctx context.Context) (SwarmGetUnlockKeyResult, error) + SwarmUnlock(ctx context.Context, options SwarmUnlockOptions) (SwarmUnlockResult, error) + SwarmLeave(ctx context.Context, options SwarmLeaveOptions) (SwarmLeaveResult, error) + SwarmInspect(ctx context.Context) (SwarmInspectResult, error) + SwarmUpdate(ctx context.Context, version swarm.Version, options SwarmUpdateOptions) (SwarmUpdateResult, error) } // SystemAPIClient defines API client methods for the system diff --git a/client/swarm_get_unlock_key.go b/client/swarm_get_unlock_key.go index 9a41f0ac31..03ecce4094 100644 --- a/client/swarm_get_unlock_key.go +++ b/client/swarm_get_unlock_key.go @@ -7,15 +7,20 @@ import ( "github.com/moby/moby/api/types/swarm" ) +// SwarmGetUnlockKeyResult contains the swarm unlock key. +type SwarmGetUnlockKeyResult struct { + Key string +} + // SwarmGetUnlockKey retrieves the swarm's unlock key. -func (cli *Client) SwarmGetUnlockKey(ctx context.Context) (swarm.UnlockKeyResponse, error) { +func (cli *Client) SwarmGetUnlockKey(ctx context.Context) (SwarmGetUnlockKeyResult, error) { resp, err := cli.get(ctx, "/swarm/unlockkey", nil, nil) defer ensureReaderClosed(resp) if err != nil { - return swarm.UnlockKeyResponse{}, err + return SwarmGetUnlockKeyResult{}, err } var response swarm.UnlockKeyResponse err = json.NewDecoder(resp.Body).Decode(&response) - return response, err + return SwarmGetUnlockKeyResult{Key: response.UnlockKey}, err } diff --git a/client/swarm_get_unlock_key_test.go b/client/swarm_get_unlock_key_test.go index 82c7a64a42..50c35336f6 100644 --- a/client/swarm_get_unlock_key_test.go +++ b/client/swarm_get_unlock_key_test.go @@ -49,7 +49,7 @@ func TestSwarmGetUnlockKey(t *testing.T) { })) assert.NilError(t, err) - resp, err := client.SwarmGetUnlockKey(context.Background()) + result, err := client.SwarmGetUnlockKey(context.Background()) assert.NilError(t, err) - assert.Check(t, is.Equal(unlockKey, resp.UnlockKey)) + assert.Check(t, is.Equal(unlockKey, result.Key)) } diff --git a/client/swarm_init.go b/client/swarm_init.go index a8d02a920f..caad560856 100644 --- a/client/swarm_init.go +++ b/client/swarm_init.go @@ -3,19 +3,52 @@ package client import ( "context" "encoding/json" + "net/netip" "github.com/moby/moby/api/types/swarm" ) +// SwarmInitOptions contains options for initializing a new swarm. +type SwarmInitOptions struct { + ListenAddr string + AdvertiseAddr string + DataPathAddr string + DataPathPort uint32 + ForceNewCluster bool + Spec swarm.Spec + AutoLockManagers bool + Availability swarm.NodeAvailability + DefaultAddrPool []netip.Prefix + SubnetSize uint32 +} + +// SwarmInitResult contains the result of a SwarmInit operation. +type SwarmInitResult struct { + NodeID string +} + // SwarmInit initializes the swarm. -func (cli *Client) SwarmInit(ctx context.Context, req swarm.InitRequest) (string, error) { +func (cli *Client) SwarmInit(ctx context.Context, options SwarmInitOptions) (SwarmInitResult, error) { + req := swarm.InitRequest{ + ListenAddr: options.ListenAddr, + AdvertiseAddr: options.AdvertiseAddr, + DataPathAddr: options.DataPathAddr, + DataPathPort: options.DataPathPort, + ForceNewCluster: options.ForceNewCluster, + Spec: options.Spec, + AutoLockManagers: options.AutoLockManagers, + Availability: options.Availability, + DefaultAddrPool: options.DefaultAddrPool, + SubnetSize: options.SubnetSize, + } + resp, err := cli.post(ctx, "/swarm/init", nil, req, nil) defer ensureReaderClosed(resp) if err != nil { - return "", err + return SwarmInitResult{}, err } - var response string - err = json.NewDecoder(resp.Body).Decode(&response) - return response, err + var nodeID string + err = json.NewDecoder(resp.Body).Decode(&nodeID) + return SwarmInitResult{NodeID: nodeID}, err } diff --git a/client/swarm_init_test.go b/client/swarm_init_test.go index d1aed94870..eff1cf34e5 100644 --- a/client/swarm_init_test.go +++ b/client/swarm_init_test.go @@ -8,7 +8,6 @@ import ( "testing" cerrdefs "github.com/containerd/errdefs" - "github.com/moby/moby/api/types/swarm" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" ) @@ -17,7 +16,7 @@ func TestSwarmInitError(t *testing.T) { client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error"))) assert.NilError(t, err) - _, err = client.SwarmInit(context.Background(), swarm.InitRequest{}) + _, err = client.SwarmInit(context.Background(), SwarmInitOptions{}) assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal)) } @@ -35,9 +34,9 @@ func TestSwarmInit(t *testing.T) { })) assert.NilError(t, err) - resp, err := client.SwarmInit(context.Background(), swarm.InitRequest{ + result, err := client.SwarmInit(context.Background(), SwarmInitOptions{ ListenAddr: "0.0.0.0:2377", }) assert.NilError(t, err) - assert.Check(t, is.Equal(resp, "body")) + assert.Check(t, is.Equal(result.NodeID, "body")) } diff --git a/client/swarm_inspect.go b/client/swarm_inspect.go index 56e0ec4250..bf9308180a 100644 --- a/client/swarm_inspect.go +++ b/client/swarm_inspect.go @@ -7,15 +7,20 @@ import ( "github.com/moby/moby/api/types/swarm" ) +// type SwarmInspectResult represents the result of a SwarmInspect operation. +type SwarmInspectResult struct { + Swarm swarm.Swarm +} + // SwarmInspect inspects the swarm. -func (cli *Client) SwarmInspect(ctx context.Context) (swarm.Swarm, error) { +func (cli *Client) SwarmInspect(ctx context.Context) (SwarmInspectResult, error) { resp, err := cli.get(ctx, "/swarm", nil, nil) defer ensureReaderClosed(resp) if err != nil { - return swarm.Swarm{}, err + return SwarmInspectResult{}, err } - var response swarm.Swarm - err = json.NewDecoder(resp.Body).Decode(&response) - return response, err + var s swarm.Swarm + err = json.NewDecoder(resp.Body).Decode(&s) + return SwarmInspectResult{Swarm: s}, err } diff --git a/client/swarm_inspect_test.go b/client/swarm_inspect_test.go index d5e51e9ed1..be44ef05ea 100644 --- a/client/swarm_inspect_test.go +++ b/client/swarm_inspect_test.go @@ -43,7 +43,7 @@ func TestSwarmInspect(t *testing.T) { })) assert.NilError(t, err) - swarmInspect, err := client.SwarmInspect(context.Background()) + inspect, err := client.SwarmInspect(context.Background()) assert.NilError(t, err) - assert.Check(t, is.Equal(swarmInspect.ID, "swarm_id")) + assert.Check(t, is.Equal(inspect.Swarm.ID, "swarm_id")) } diff --git a/client/swarm_join.go b/client/swarm_join.go index 7a9fa076d6..ee91864409 100644 --- a/client/swarm_join.go +++ b/client/swarm_join.go @@ -6,9 +6,31 @@ import ( "github.com/moby/moby/api/types/swarm" ) +// SwarmJoinOptions specifies options for joining a swarm. +type SwarmJoinOptions struct { + ListenAddr string + AdvertiseAddr string + DataPathAddr string + RemoteAddrs []string + JoinToken string // accept by secret + Availability swarm.NodeAvailability +} + +// SwarmJoinResult contains the result of joining a swarm. +type SwarmJoinResult struct{} + // SwarmJoin joins the swarm. -func (cli *Client) SwarmJoin(ctx context.Context, req swarm.JoinRequest) error { +func (cli *Client) SwarmJoin(ctx context.Context, options SwarmJoinOptions) (SwarmJoinResult, error) { + req := swarm.JoinRequest{ + ListenAddr: options.ListenAddr, + AdvertiseAddr: options.AdvertiseAddr, + DataPathAddr: options.DataPathAddr, + RemoteAddrs: options.RemoteAddrs, + JoinToken: options.JoinToken, + Availability: options.Availability, + } + resp, err := cli.post(ctx, "/swarm/join", nil, req, nil) defer ensureReaderClosed(resp) - return err + return SwarmJoinResult{}, err } diff --git a/client/swarm_join_test.go b/client/swarm_join_test.go index b378740d19..696482a186 100644 --- a/client/swarm_join_test.go +++ b/client/swarm_join_test.go @@ -8,7 +8,6 @@ import ( "testing" cerrdefs "github.com/containerd/errdefs" - "github.com/moby/moby/api/types/swarm" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" ) @@ -17,7 +16,7 @@ func TestSwarmJoinError(t *testing.T) { client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error"))) assert.NilError(t, err) - err = client.SwarmJoin(context.Background(), swarm.JoinRequest{}) + _, err = client.SwarmJoin(context.Background(), SwarmJoinOptions{}) assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal)) } @@ -35,7 +34,7 @@ func TestSwarmJoin(t *testing.T) { })) assert.NilError(t, err) - err = client.SwarmJoin(context.Background(), swarm.JoinRequest{ + _, err = client.SwarmJoin(context.Background(), SwarmJoinOptions{ ListenAddr: "0.0.0.0:2377", }) assert.NilError(t, err) diff --git a/client/swarm_leave.go b/client/swarm_leave.go index fb0fe3b5d5..a65a13de3f 100644 --- a/client/swarm_leave.go +++ b/client/swarm_leave.go @@ -5,13 +5,21 @@ import ( "net/url" ) +// SwarmLeaveOptions contains options for leaving a swarm. +type SwarmLeaveOptions struct { + Force bool +} + +// SwarmLeaveResult represents the result of a SwarmLeave operation. +type SwarmLeaveResult struct{} + // SwarmLeave leaves the swarm. -func (cli *Client) SwarmLeave(ctx context.Context, force bool) error { +func (cli *Client) SwarmLeave(ctx context.Context, options SwarmLeaveOptions) (SwarmLeaveResult, error) { query := url.Values{} - if force { + if options.Force { query.Set("force", "1") } resp, err := cli.post(ctx, "/swarm/leave", query, nil, nil) defer ensureReaderClosed(resp) - return err + return SwarmLeaveResult{}, err } diff --git a/client/swarm_leave_test.go b/client/swarm_leave_test.go index 6ba9e534a4..71c1b26c1f 100644 --- a/client/swarm_leave_test.go +++ b/client/swarm_leave_test.go @@ -17,7 +17,7 @@ func TestSwarmLeaveError(t *testing.T) { client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error"))) assert.NilError(t, err) - err = client.SwarmLeave(context.Background(), false) + _, err = client.SwarmLeave(context.Background(), SwarmLeaveOptions{}) assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal)) } @@ -53,7 +53,7 @@ func TestSwarmLeave(t *testing.T) { })) assert.NilError(t, err) - err = client.SwarmLeave(context.Background(), leaveCase.force) + _, err = client.SwarmLeave(context.Background(), SwarmLeaveOptions{Force: leaveCase.force}) assert.NilError(t, err) } } diff --git a/client/swarm_unlock.go b/client/swarm_unlock.go index 5eb3d59399..92335afb54 100644 --- a/client/swarm_unlock.go +++ b/client/swarm_unlock.go @@ -6,9 +6,20 @@ import ( "github.com/moby/moby/api/types/swarm" ) +// SwarmUnlockOptions specifies options for unlocking a swarm. +type SwarmUnlockOptions struct { + Key string +} + +// SwarmUnlockResult represents the result of unlocking a swarm. +type SwarmUnlockResult struct{} + // SwarmUnlock unlocks locked swarm. -func (cli *Client) SwarmUnlock(ctx context.Context, req swarm.UnlockRequest) error { +func (cli *Client) SwarmUnlock(ctx context.Context, options SwarmUnlockOptions) (SwarmUnlockResult, error) { + req := &swarm.UnlockRequest{ + UnlockKey: options.Key, + } resp, err := cli.post(ctx, "/swarm/unlock", nil, req, nil) defer ensureReaderClosed(resp) - return err + return SwarmUnlockResult{}, err } diff --git a/client/swarm_unlock_test.go b/client/swarm_unlock_test.go index 96123bb086..caf723fb7e 100644 --- a/client/swarm_unlock_test.go +++ b/client/swarm_unlock_test.go @@ -8,7 +8,6 @@ import ( "testing" cerrdefs "github.com/containerd/errdefs" - "github.com/moby/moby/api/types/swarm" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" ) @@ -17,7 +16,7 @@ func TestSwarmUnlockError(t *testing.T) { client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error"))) assert.NilError(t, err) - err = client.SwarmUnlock(context.Background(), swarm.UnlockRequest{UnlockKey: "SWMKEY-1-y6guTZNTwpQeTL5RhUfOsdBdXoQjiB2GADHSRJvbXeU"}) + _, err = client.SwarmUnlock(context.Background(), SwarmUnlockOptions{Key: "SWMKEY-1-y6guTZNTwpQeTL5RhUfOsdBdXoQjiB2GADHSRJvbXeU"}) assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal)) } @@ -35,6 +34,6 @@ func TestSwarmUnlock(t *testing.T) { })) assert.NilError(t, err) - err = client.SwarmUnlock(context.Background(), swarm.UnlockRequest{UnlockKey: "SWMKEY-1-y6guTZNTwpQeTL5RhUfOsdBdXoQjiB2GADHSRJvbXeU"}) + _, err = client.SwarmUnlock(context.Background(), SwarmUnlockOptions{Key: "SWMKEY-1-y6guTZNTwpQeTL5RhUfOsdBdXoQjiB2GADHSRJvbXeU"}) assert.NilError(t, err) } diff --git a/client/swarm_update.go b/client/swarm_update.go index b6a077eae1..8f62876a56 100644 --- a/client/swarm_update.go +++ b/client/swarm_update.go @@ -8,14 +8,25 @@ import ( "github.com/moby/moby/api/types/swarm" ) +// SwarmUpdateOptions contains options for updating a swarm. +type SwarmUpdateOptions struct { + Swarm swarm.Spec + RotateWorkerToken bool + RotateManagerToken bool + RotateManagerUnlockKey bool +} + +// SwarmUpdateResult represents the result of a SwarmUpdate operation. +type SwarmUpdateResult struct{} + // SwarmUpdate updates the swarm. -func (cli *Client) SwarmUpdate(ctx context.Context, version swarm.Version, swarm swarm.Spec, flags SwarmUpdateFlags) error { +func (cli *Client) SwarmUpdate(ctx context.Context, version swarm.Version, options SwarmUpdateOptions) (SwarmUpdateResult, error) { query := url.Values{} query.Set("version", version.String()) - query.Set("rotateWorkerToken", strconv.FormatBool(flags.RotateWorkerToken)) - query.Set("rotateManagerToken", strconv.FormatBool(flags.RotateManagerToken)) - query.Set("rotateManagerUnlockKey", strconv.FormatBool(flags.RotateManagerUnlockKey)) - resp, err := cli.post(ctx, "/swarm/update", query, swarm, nil) + query.Set("rotateWorkerToken", strconv.FormatBool(options.RotateWorkerToken)) + query.Set("rotateManagerToken", strconv.FormatBool(options.RotateManagerToken)) + query.Set("rotateManagerUnlockKey", strconv.FormatBool(options.RotateManagerUnlockKey)) + resp, err := cli.post(ctx, "/swarm/update", query, options.Swarm, nil) defer ensureReaderClosed(resp) - return err + return SwarmUpdateResult{}, err } diff --git a/client/swarm_update_flags.go b/client/swarm_update_flags.go deleted file mode 100644 index 536f865035..0000000000 --- a/client/swarm_update_flags.go +++ /dev/null @@ -1,8 +0,0 @@ -package client - -// SwarmUpdateFlags contains flags for SwarmUpdate. -type SwarmUpdateFlags struct { - RotateWorkerToken bool - RotateManagerToken bool - RotateManagerUnlockKey bool -} diff --git a/client/swarm_update_test.go b/client/swarm_update_test.go index b499417703..3fad797899 100644 --- a/client/swarm_update_test.go +++ b/client/swarm_update_test.go @@ -17,7 +17,7 @@ func TestSwarmUpdateError(t *testing.T) { client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error"))) assert.NilError(t, err) - err = client.SwarmUpdate(context.Background(), swarm.Version{}, swarm.Spec{}, SwarmUpdateFlags{}) + _, err = client.SwarmUpdate(context.Background(), swarm.Version{}, SwarmUpdateOptions{}) assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal)) } @@ -35,6 +35,6 @@ func TestSwarmUpdate(t *testing.T) { })) assert.NilError(t, err) - err = client.SwarmUpdate(context.Background(), swarm.Version{}, swarm.Spec{}, SwarmUpdateFlags{}) + _, err = client.SwarmUpdate(context.Background(), swarm.Version{}, SwarmUpdateOptions{}) assert.NilError(t, err) } diff --git a/integration-cli/docker_api_swarm_test.go b/integration-cli/docker_api_swarm_test.go index b892bf2e36..45971b6853 100644 --- a/integration-cli/docker_api_swarm_test.go +++ b/integration-cli/docker_api_swarm_test.go @@ -91,7 +91,7 @@ func (s *DockerSwarmSuite) TestAPISwarmJoinToken(c *testing.T) { d2 := s.AddDaemon(ctx, c, false, false) c2 := d2.NewClientT(c) - err := c2.SwarmJoin(testutil.GetContext(c), swarm.JoinRequest{ + _, err := c2.SwarmJoin(testutil.GetContext(c), client.SwarmJoinOptions{ ListenAddr: d2.SwarmListenAddr(), RemoteAddrs: []string{d1.SwarmListenAddr()}, }) @@ -99,7 +99,7 @@ func (s *DockerSwarmSuite) TestAPISwarmJoinToken(c *testing.T) { info := d2.SwarmInfo(ctx, c) assert.Equal(c, info.LocalNodeState, swarm.LocalNodeStateInactive) - err = c2.SwarmJoin(testutil.GetContext(c), swarm.JoinRequest{ + _, err = c2.SwarmJoin(testutil.GetContext(c), client.SwarmJoinOptions{ ListenAddr: d2.SwarmListenAddr(), JoinToken: "foobaz", RemoteAddrs: []string{d1.SwarmListenAddr()}, @@ -124,7 +124,7 @@ func (s *DockerSwarmSuite) TestAPISwarmJoinToken(c *testing.T) { // change tokens d1.RotateTokens(c) - err = c2.SwarmJoin(testutil.GetContext(c), swarm.JoinRequest{ + _, err = c2.SwarmJoin(testutil.GetContext(c), client.SwarmJoinOptions{ ListenAddr: d2.SwarmListenAddr(), JoinToken: workerToken, RemoteAddrs: []string{d1.SwarmListenAddr()}, @@ -145,7 +145,7 @@ func (s *DockerSwarmSuite) TestAPISwarmJoinToken(c *testing.T) { // change spec, don't change tokens d1.UpdateSwarm(c, func(s *swarm.Spec) {}) - err = c2.SwarmJoin(testutil.GetContext(c), swarm.JoinRequest{ + _, err = c2.SwarmJoin(testutil.GetContext(c), client.SwarmJoinOptions{ ListenAddr: d2.SwarmListenAddr(), RemoteAddrs: []string{d1.SwarmListenAddr()}, }) @@ -192,7 +192,7 @@ func (s *DockerSwarmSuite) TestAPISwarmCAHash(c *testing.T) { splitToken[2] = "1kxftv4ofnc6mt30lmgipg6ngf9luhwqopfk1tz6bdmnkubg0e" replacementToken := strings.Join(splitToken, "-") c2 := d2.NewClientT(c) - err := c2.SwarmJoin(testutil.GetContext(c), swarm.JoinRequest{ + _, err := c2.SwarmJoin(testutil.GetContext(c), client.SwarmJoinOptions{ ListenAddr: d2.SwarmListenAddr(), JoinToken: replacementToken, RemoteAddrs: []string{d1.SwarmListenAddr()}, @@ -463,7 +463,7 @@ func (s *DockerSwarmSuite) TestAPISwarmLeaveOnPendingJoin(c *testing.T) { id = strings.TrimSpace(id) c2 := d2.NewClientT(c) - err = c2.SwarmJoin(testutil.GetContext(c), swarm.JoinRequest{ + _, err = c2.SwarmJoin(testutil.GetContext(c), client.SwarmJoinOptions{ ListenAddr: d2.SwarmListenAddr(), RemoteAddrs: []string{"123.123.123.123:1234"}, }) @@ -487,8 +487,8 @@ func (s *DockerSwarmSuite) TestAPISwarmRestoreOnPendingJoin(c *testing.T) { ctx := testutil.GetContext(c) d := s.AddDaemon(ctx, c, false, false) - client := d.NewClientT(c) - err := client.SwarmJoin(testutil.GetContext(c), swarm.JoinRequest{ + cli := d.NewClientT(c) + _, err := cli.SwarmJoin(testutil.GetContext(c), client.SwarmJoinOptions{ ListenAddr: d.SwarmListenAddr(), RemoteAddrs: []string{"123.123.123.123:1234"}, }) @@ -909,8 +909,8 @@ func (s *DockerSwarmSuite) TestAPISwarmErrorHandling(c *testing.T) { assert.NilError(c, err) defer ln.Close() d := s.AddDaemon(ctx, c, false, false) - client := d.NewClientT(c) - _, err = client.SwarmInit(testutil.GetContext(c), swarm.InitRequest{ + cli := d.NewClientT(c) + _, err = cli.SwarmInit(testutil.GetContext(c), client.SwarmInitOptions{ ListenAddr: d.SwarmListenAddr(), }) assert.ErrorContains(c, err, "address already in use") diff --git a/integration/system/ping_test.go b/integration/system/ping_test.go index d022915c60..5e47761012 100644 --- a/integration/system/ping_test.go +++ b/integration/system/ping_test.go @@ -9,6 +9,7 @@ import ( "github.com/moby/moby/api/types/build" "github.com/moby/moby/api/types/swarm" + "github.com/moby/moby/client" "github.com/moby/moby/v2/internal/testutil" "github.com/moby/moby/v2/internal/testutil/daemon" "github.com/moby/moby/v2/internal/testutil/request" @@ -73,7 +74,7 @@ func TestPingSwarmHeader(t *testing.T) { assert.Equal(t, p.SwarmStatus.ControlAvailable, false) }) - _, err := apiClient.SwarmInit(ctx, swarm.InitRequest{ListenAddr: "127.0.0.1", AdvertiseAddr: "127.0.0.1:2377"}) + _, err := apiClient.SwarmInit(ctx, client.SwarmInitOptions{ListenAddr: "127.0.0.1", AdvertiseAddr: "127.0.0.1:2377"}) assert.NilError(t, err) t.Run("after swarm init", func(t *testing.T) { @@ -84,7 +85,7 @@ func TestPingSwarmHeader(t *testing.T) { assert.Equal(t, p.SwarmStatus.ControlAvailable, true) }) - err = apiClient.SwarmLeave(ctx, true) + _, err = apiClient.SwarmLeave(ctx, client.SwarmLeaveOptions{Force: true}) assert.NilError(t, err) t.Run("after swarm leave", func(t *testing.T) { diff --git a/internal/testutil/daemon/swarm.go b/internal/testutil/daemon/swarm.go index d08036e3d7..bba6a6efe8 100644 --- a/internal/testutil/daemon/swarm.go +++ b/internal/testutil/daemon/swarm.go @@ -101,7 +101,18 @@ func (d *Daemon) SwarmInitWithError(ctx context.Context, t testing.TB, req swarm } cli := d.NewClientT(t) defer cli.Close() - _, err := cli.SwarmInit(ctx, req) + _, err := cli.SwarmInit(ctx, client.SwarmInitOptions{ + ListenAddr: req.ListenAddr, + AdvertiseAddr: req.AdvertiseAddr, + DataPathAddr: req.DataPathAddr, + DataPathPort: req.DataPathPort, + ForceNewCluster: req.ForceNewCluster, + Spec: req.Spec, + AutoLockManagers: req.AutoLockManagers, + Availability: req.Availability, + DefaultAddrPool: req.DefaultAddrPool, + SubnetSize: req.SubnetSize, + }) if err == nil { d.CachedInfo = d.Info(t) } @@ -123,7 +134,14 @@ func (d *Daemon) SwarmJoin(ctx context.Context, t testing.TB, req swarm.JoinRequ } cli := d.NewClientT(t) defer cli.Close() - err := cli.SwarmJoin(ctx, req) + _, err := cli.SwarmJoin(ctx, client.SwarmJoinOptions{ + ListenAddr: req.ListenAddr, + AdvertiseAddr: req.AdvertiseAddr, + DataPathAddr: req.DataPathAddr, + RemoteAddrs: req.RemoteAddrs, + JoinToken: req.JoinToken, + Availability: req.Availability, + }) assert.NilError(t, err, "[%s] joining swarm", d.id) d.CachedInfo = d.Info(t) } @@ -136,7 +154,8 @@ func (d *Daemon) SwarmJoin(ctx context.Context, t testing.TB, req swarm.JoinRequ func (d *Daemon) SwarmLeave(ctx context.Context, t testing.TB, force bool) error { cli := d.NewClientT(t) defer cli.Close() - return cli.SwarmLeave(ctx, force) + _, err := cli.SwarmLeave(ctx, client.SwarmLeaveOptions{Force: force}) + return err } // SwarmInfo returns the swarm information of the daemon @@ -157,7 +176,7 @@ func (d *Daemon) SwarmUnlock(t testing.TB, req swarm.UnlockRequest) error { cli := d.NewClientT(t) defer cli.Close() - err := cli.SwarmUnlock(context.Background(), req) + _, err := cli.SwarmUnlock(context.Background(), client.SwarmUnlockOptions{Key: req.UnlockKey}) if err != nil { err = errors.Wrap(err, "unlocking swarm") } @@ -170,9 +189,9 @@ func (d *Daemon) GetSwarm(t testing.TB) swarm.Swarm { cli := d.NewClientT(t) defer cli.Close() - sw, err := cli.SwarmInspect(context.Background()) + result, err := cli.SwarmInspect(context.Background()) assert.NilError(t, err) - return sw + return result.Swarm } // UpdateSwarm updates the current swarm object with the specified spec constructors @@ -186,7 +205,9 @@ func (d *Daemon) UpdateSwarm(t testing.TB, f ...SpecConstructor) { fn(&sw.Spec) } - err := cli.SwarmUpdate(context.Background(), sw.Version, sw.Spec, client.SwarmUpdateFlags{}) + _, err := cli.SwarmUpdate(context.Background(), sw.Version, client.SwarmUpdateOptions{ + Swarm: sw.Spec, + }) assert.NilError(t, err) } @@ -196,15 +217,14 @@ func (d *Daemon) RotateTokens(t testing.TB) { cli := d.NewClientT(t) defer cli.Close() - sw, err := cli.SwarmInspect(context.Background()) + result, err := cli.SwarmInspect(context.Background()) assert.NilError(t, err) - flags := client.SwarmUpdateFlags{ + _, err = cli.SwarmUpdate(context.Background(), result.Swarm.Version, client.SwarmUpdateOptions{ + Swarm: result.Swarm.Spec, RotateManagerToken: true, RotateWorkerToken: true, - } - - err = cli.SwarmUpdate(context.Background(), sw.Version, sw.Spec, flags) + }) assert.NilError(t, err) } @@ -214,9 +234,9 @@ func (d *Daemon) JoinTokens(t testing.TB) swarm.JoinTokens { cli := d.NewClientT(t) defer cli.Close() - sw, err := cli.SwarmInspect(context.Background()) + result, err := cli.SwarmInspect(context.Background()) assert.NilError(t, err) - return sw.JoinTokens + return result.Swarm.JoinTokens } func (d *Daemon) startArgs() []string { diff --git a/vendor/github.com/moby/moby/client/client_interfaces.go b/vendor/github.com/moby/moby/client/client_interfaces.go index fcb00553fc..f0b437eb43 100644 --- a/vendor/github.com/moby/moby/client/client_interfaces.go +++ b/vendor/github.com/moby/moby/client/client_interfaces.go @@ -174,13 +174,13 @@ type ServiceAPIClient interface { // SwarmAPIClient defines API client methods for the swarm type SwarmAPIClient interface { - SwarmInit(ctx context.Context, req swarm.InitRequest) (string, error) - SwarmJoin(ctx context.Context, req swarm.JoinRequest) error - SwarmGetUnlockKey(ctx context.Context) (swarm.UnlockKeyResponse, error) - SwarmUnlock(ctx context.Context, req swarm.UnlockRequest) error - SwarmLeave(ctx context.Context, force bool) error - SwarmInspect(ctx context.Context) (swarm.Swarm, error) - SwarmUpdate(ctx context.Context, version swarm.Version, swarm swarm.Spec, flags SwarmUpdateFlags) error + SwarmInit(ctx context.Context, options SwarmInitOptions) (SwarmInitResult, error) + SwarmJoin(ctx context.Context, options SwarmJoinOptions) (SwarmJoinResult, error) + SwarmGetUnlockKey(ctx context.Context) (SwarmGetUnlockKeyResult, error) + SwarmUnlock(ctx context.Context, options SwarmUnlockOptions) (SwarmUnlockResult, error) + SwarmLeave(ctx context.Context, options SwarmLeaveOptions) (SwarmLeaveResult, error) + SwarmInspect(ctx context.Context) (SwarmInspectResult, error) + SwarmUpdate(ctx context.Context, version swarm.Version, options SwarmUpdateOptions) (SwarmUpdateResult, error) } // SystemAPIClient defines API client methods for the system diff --git a/vendor/github.com/moby/moby/client/swarm_get_unlock_key.go b/vendor/github.com/moby/moby/client/swarm_get_unlock_key.go index 9a41f0ac31..03ecce4094 100644 --- a/vendor/github.com/moby/moby/client/swarm_get_unlock_key.go +++ b/vendor/github.com/moby/moby/client/swarm_get_unlock_key.go @@ -7,15 +7,20 @@ import ( "github.com/moby/moby/api/types/swarm" ) +// SwarmGetUnlockKeyResult contains the swarm unlock key. +type SwarmGetUnlockKeyResult struct { + Key string +} + // SwarmGetUnlockKey retrieves the swarm's unlock key. -func (cli *Client) SwarmGetUnlockKey(ctx context.Context) (swarm.UnlockKeyResponse, error) { +func (cli *Client) SwarmGetUnlockKey(ctx context.Context) (SwarmGetUnlockKeyResult, error) { resp, err := cli.get(ctx, "/swarm/unlockkey", nil, nil) defer ensureReaderClosed(resp) if err != nil { - return swarm.UnlockKeyResponse{}, err + return SwarmGetUnlockKeyResult{}, err } var response swarm.UnlockKeyResponse err = json.NewDecoder(resp.Body).Decode(&response) - return response, err + return SwarmGetUnlockKeyResult{Key: response.UnlockKey}, err } diff --git a/vendor/github.com/moby/moby/client/swarm_init.go b/vendor/github.com/moby/moby/client/swarm_init.go index a8d02a920f..caad560856 100644 --- a/vendor/github.com/moby/moby/client/swarm_init.go +++ b/vendor/github.com/moby/moby/client/swarm_init.go @@ -3,19 +3,52 @@ package client import ( "context" "encoding/json" + "net/netip" "github.com/moby/moby/api/types/swarm" ) +// SwarmInitOptions contains options for initializing a new swarm. +type SwarmInitOptions struct { + ListenAddr string + AdvertiseAddr string + DataPathAddr string + DataPathPort uint32 + ForceNewCluster bool + Spec swarm.Spec + AutoLockManagers bool + Availability swarm.NodeAvailability + DefaultAddrPool []netip.Prefix + SubnetSize uint32 +} + +// SwarmInitResult contains the result of a SwarmInit operation. +type SwarmInitResult struct { + NodeID string +} + // SwarmInit initializes the swarm. -func (cli *Client) SwarmInit(ctx context.Context, req swarm.InitRequest) (string, error) { +func (cli *Client) SwarmInit(ctx context.Context, options SwarmInitOptions) (SwarmInitResult, error) { + req := swarm.InitRequest{ + ListenAddr: options.ListenAddr, + AdvertiseAddr: options.AdvertiseAddr, + DataPathAddr: options.DataPathAddr, + DataPathPort: options.DataPathPort, + ForceNewCluster: options.ForceNewCluster, + Spec: options.Spec, + AutoLockManagers: options.AutoLockManagers, + Availability: options.Availability, + DefaultAddrPool: options.DefaultAddrPool, + SubnetSize: options.SubnetSize, + } + resp, err := cli.post(ctx, "/swarm/init", nil, req, nil) defer ensureReaderClosed(resp) if err != nil { - return "", err + return SwarmInitResult{}, err } - var response string - err = json.NewDecoder(resp.Body).Decode(&response) - return response, err + var nodeID string + err = json.NewDecoder(resp.Body).Decode(&nodeID) + return SwarmInitResult{NodeID: nodeID}, err } diff --git a/vendor/github.com/moby/moby/client/swarm_inspect.go b/vendor/github.com/moby/moby/client/swarm_inspect.go index 56e0ec4250..bf9308180a 100644 --- a/vendor/github.com/moby/moby/client/swarm_inspect.go +++ b/vendor/github.com/moby/moby/client/swarm_inspect.go @@ -7,15 +7,20 @@ import ( "github.com/moby/moby/api/types/swarm" ) +// type SwarmInspectResult represents the result of a SwarmInspect operation. +type SwarmInspectResult struct { + Swarm swarm.Swarm +} + // SwarmInspect inspects the swarm. -func (cli *Client) SwarmInspect(ctx context.Context) (swarm.Swarm, error) { +func (cli *Client) SwarmInspect(ctx context.Context) (SwarmInspectResult, error) { resp, err := cli.get(ctx, "/swarm", nil, nil) defer ensureReaderClosed(resp) if err != nil { - return swarm.Swarm{}, err + return SwarmInspectResult{}, err } - var response swarm.Swarm - err = json.NewDecoder(resp.Body).Decode(&response) - return response, err + var s swarm.Swarm + err = json.NewDecoder(resp.Body).Decode(&s) + return SwarmInspectResult{Swarm: s}, err } diff --git a/vendor/github.com/moby/moby/client/swarm_join.go b/vendor/github.com/moby/moby/client/swarm_join.go index 7a9fa076d6..ee91864409 100644 --- a/vendor/github.com/moby/moby/client/swarm_join.go +++ b/vendor/github.com/moby/moby/client/swarm_join.go @@ -6,9 +6,31 @@ import ( "github.com/moby/moby/api/types/swarm" ) +// SwarmJoinOptions specifies options for joining a swarm. +type SwarmJoinOptions struct { + ListenAddr string + AdvertiseAddr string + DataPathAddr string + RemoteAddrs []string + JoinToken string // accept by secret + Availability swarm.NodeAvailability +} + +// SwarmJoinResult contains the result of joining a swarm. +type SwarmJoinResult struct{} + // SwarmJoin joins the swarm. -func (cli *Client) SwarmJoin(ctx context.Context, req swarm.JoinRequest) error { +func (cli *Client) SwarmJoin(ctx context.Context, options SwarmJoinOptions) (SwarmJoinResult, error) { + req := swarm.JoinRequest{ + ListenAddr: options.ListenAddr, + AdvertiseAddr: options.AdvertiseAddr, + DataPathAddr: options.DataPathAddr, + RemoteAddrs: options.RemoteAddrs, + JoinToken: options.JoinToken, + Availability: options.Availability, + } + resp, err := cli.post(ctx, "/swarm/join", nil, req, nil) defer ensureReaderClosed(resp) - return err + return SwarmJoinResult{}, err } diff --git a/vendor/github.com/moby/moby/client/swarm_leave.go b/vendor/github.com/moby/moby/client/swarm_leave.go index fb0fe3b5d5..a65a13de3f 100644 --- a/vendor/github.com/moby/moby/client/swarm_leave.go +++ b/vendor/github.com/moby/moby/client/swarm_leave.go @@ -5,13 +5,21 @@ import ( "net/url" ) +// SwarmLeaveOptions contains options for leaving a swarm. +type SwarmLeaveOptions struct { + Force bool +} + +// SwarmLeaveResult represents the result of a SwarmLeave operation. +type SwarmLeaveResult struct{} + // SwarmLeave leaves the swarm. -func (cli *Client) SwarmLeave(ctx context.Context, force bool) error { +func (cli *Client) SwarmLeave(ctx context.Context, options SwarmLeaveOptions) (SwarmLeaveResult, error) { query := url.Values{} - if force { + if options.Force { query.Set("force", "1") } resp, err := cli.post(ctx, "/swarm/leave", query, nil, nil) defer ensureReaderClosed(resp) - return err + return SwarmLeaveResult{}, err } diff --git a/vendor/github.com/moby/moby/client/swarm_unlock.go b/vendor/github.com/moby/moby/client/swarm_unlock.go index 5eb3d59399..92335afb54 100644 --- a/vendor/github.com/moby/moby/client/swarm_unlock.go +++ b/vendor/github.com/moby/moby/client/swarm_unlock.go @@ -6,9 +6,20 @@ import ( "github.com/moby/moby/api/types/swarm" ) +// SwarmUnlockOptions specifies options for unlocking a swarm. +type SwarmUnlockOptions struct { + Key string +} + +// SwarmUnlockResult represents the result of unlocking a swarm. +type SwarmUnlockResult struct{} + // SwarmUnlock unlocks locked swarm. -func (cli *Client) SwarmUnlock(ctx context.Context, req swarm.UnlockRequest) error { +func (cli *Client) SwarmUnlock(ctx context.Context, options SwarmUnlockOptions) (SwarmUnlockResult, error) { + req := &swarm.UnlockRequest{ + UnlockKey: options.Key, + } resp, err := cli.post(ctx, "/swarm/unlock", nil, req, nil) defer ensureReaderClosed(resp) - return err + return SwarmUnlockResult{}, err } diff --git a/vendor/github.com/moby/moby/client/swarm_update.go b/vendor/github.com/moby/moby/client/swarm_update.go index b6a077eae1..8f62876a56 100644 --- a/vendor/github.com/moby/moby/client/swarm_update.go +++ b/vendor/github.com/moby/moby/client/swarm_update.go @@ -8,14 +8,25 @@ import ( "github.com/moby/moby/api/types/swarm" ) +// SwarmUpdateOptions contains options for updating a swarm. +type SwarmUpdateOptions struct { + Swarm swarm.Spec + RotateWorkerToken bool + RotateManagerToken bool + RotateManagerUnlockKey bool +} + +// SwarmUpdateResult represents the result of a SwarmUpdate operation. +type SwarmUpdateResult struct{} + // SwarmUpdate updates the swarm. -func (cli *Client) SwarmUpdate(ctx context.Context, version swarm.Version, swarm swarm.Spec, flags SwarmUpdateFlags) error { +func (cli *Client) SwarmUpdate(ctx context.Context, version swarm.Version, options SwarmUpdateOptions) (SwarmUpdateResult, error) { query := url.Values{} query.Set("version", version.String()) - query.Set("rotateWorkerToken", strconv.FormatBool(flags.RotateWorkerToken)) - query.Set("rotateManagerToken", strconv.FormatBool(flags.RotateManagerToken)) - query.Set("rotateManagerUnlockKey", strconv.FormatBool(flags.RotateManagerUnlockKey)) - resp, err := cli.post(ctx, "/swarm/update", query, swarm, nil) + query.Set("rotateWorkerToken", strconv.FormatBool(options.RotateWorkerToken)) + query.Set("rotateManagerToken", strconv.FormatBool(options.RotateManagerToken)) + query.Set("rotateManagerUnlockKey", strconv.FormatBool(options.RotateManagerUnlockKey)) + resp, err := cli.post(ctx, "/swarm/update", query, options.Swarm, nil) defer ensureReaderClosed(resp) - return err + return SwarmUpdateResult{}, err } diff --git a/vendor/github.com/moby/moby/client/swarm_update_flags.go b/vendor/github.com/moby/moby/client/swarm_update_flags.go deleted file mode 100644 index 536f865035..0000000000 --- a/vendor/github.com/moby/moby/client/swarm_update_flags.go +++ /dev/null @@ -1,8 +0,0 @@ -package client - -// SwarmUpdateFlags contains flags for SwarmUpdate. -type SwarmUpdateFlags struct { - RotateWorkerToken bool - RotateManagerToken bool - RotateManagerUnlockKey bool -}