Skip to content

Commit

Permalink
Merge pull request moby#49388 from thaJeztah/client_unify_interfaces
Browse files Browse the repository at this point in the history
client: deprecate CommonAPIClient interface, add HijackDialer, SwarmManagementAPIClient interfaces
  • Loading branch information
thaJeztah authored Feb 4, 2025
2 parents 2277b35 + 2997c0d commit 63ea5dc
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 35 deletions.
2 changes: 1 addition & 1 deletion client/buildkit/buildkit.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
// Example:
//
// bkclient.New(ctx, "", ClientOpts(c)...)
func ClientOpts(c client.CommonAPIClient) []bkclient.ClientOpt {
func ClientOpts(c client.HijackDialer) []bkclient.ClientOpt {
return []bkclient.ClientOpt{
bkclient.WithSessionDialer(func(ctx context.Context, proto string, meta map[string][]string) (net.Conn, error) {
return c.DialHijack(ctx, "/session", proto, meta)
Expand Down
10 changes: 5 additions & 5 deletions client/interface_experimental.go → client/checkpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import (
"github.com/docker/docker/api/types/checkpoint"
)

type apiClientExperimental interface {
CheckpointAPIClient
}

// CheckpointAPIClient defines API client methods for the checkpoints
// CheckpointAPIClient defines API client methods for the checkpoints.
//
// Experimental: checkpoint and restore is still an experimental feature,
// and only available if the daemon is running with experimental features
// enabled.
type CheckpointAPIClient interface {
CheckpointCreate(ctx context.Context, container string, options checkpoint.CreateOptions) error
CheckpointDelete(ctx context.Context, container string, options checkpoint.DeleteOptions) error
Expand Down
7 changes: 7 additions & 0 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ const DummyHost = "api.moby.localhost"
// recent version before negotiation was introduced.
const fallbackAPIVersion = "1.24"

// Ensure that Client always implements APIClient.
var _ APIClient = &Client{}

// Client is the API client that performs all operations
// against a docker server.
type Client struct {
Expand Down Expand Up @@ -449,6 +452,10 @@ func (cli *Client) dialerFromTransport() func(context.Context, string, string) (
//
// ["docker dial-stdio"]: https://github.com/docker/cli/pull/1014
func (cli *Client) Dialer() func(context.Context) (net.Conn, error) {
return cli.dialer()
}

func (cli *Client) dialer() func(context.Context) (net.Conn, error) {
return func(ctx context.Context) (net.Conn, error) {
if dialFn := cli.dialerFromTransport(); dialFn != nil {
return dialFn(ctx, cli.proto, cli.addr)
Expand Down
34 changes: 28 additions & 6 deletions client/interface.go → client/client_interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,23 @@ import (
)

// CommonAPIClient is the common methods between stable and experimental versions of APIClient.
type CommonAPIClient interface {
//
// Deprecated: use [APIClient] instead. This type will be an alias for [APIClient] in the next release, and removed after.
type CommonAPIClient = stableAPIClient

// APIClient is an interface that clients that talk with a docker server must implement.
type APIClient interface {
stableAPIClient
CheckpointAPIClient // CheckpointAPIClient is still experimental.
}

type stableAPIClient interface {
ConfigAPIClient
ContainerAPIClient
DistributionAPIClient
ImageAPIClient
NodeAPIClient
NetworkAPIClient
PluginAPIClient
ServiceAPIClient
SwarmAPIClient
SecretAPIClient
SystemAPIClient
VolumeAPIClient
ClientVersion() string
Expand All @@ -39,9 +45,25 @@ type CommonAPIClient interface {
ServerVersion(ctx context.Context) (types.Version, error)
NegotiateAPIVersion(ctx context.Context)
NegotiateAPIVersionPing(types.Ping)
DialHijack(ctx context.Context, url, proto string, meta map[string][]string) (net.Conn, error)
HijackDialer
Dialer() func(context.Context) (net.Conn, error)
Close() error
SwarmManagementAPIClient
}

// SwarmManagementAPIClient defines all methods for managing Swarm-specific
// objects.
type SwarmManagementAPIClient interface {
SwarmAPIClient
NodeAPIClient
ServiceAPIClient
SecretAPIClient
ConfigAPIClient
}

// HijackDialer defines methods for a hijack dialer.
type HijackDialer interface {
DialHijack(ctx context.Context, url, proto string, meta map[string][]string) (net.Conn, error)
}

// ContainerAPIClient defines API client methods for the containers
Expand Down
22 changes: 10 additions & 12 deletions client/hijack.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,17 @@ func (cli *Client) postHijacked(ctx context.Context, path string, query url.Valu
if err != nil {
return types.HijackedResponse{}, err
}
conn, mediaType, err := cli.setupHijackConn(req, "tcp")
conn, mediaType, err := setupHijackConn(cli.dialer(), req, "tcp")
if err != nil {
return types.HijackedResponse{}, err
}

return types.NewHijackedResponse(conn, mediaType), err
if versions.LessThan(cli.ClientVersion(), "1.42") {
// Prior to 1.42, Content-Type is always set to raw-stream and not relevant
mediaType = ""
}

return types.NewHijackedResponse(conn, mediaType), nil
}

// DialHijack returns a hijacked connection with negotiated protocol proto.
Expand All @@ -41,16 +46,15 @@ func (cli *Client) DialHijack(ctx context.Context, url, proto string, meta map[s
}
req = cli.addHeaders(req, meta)

conn, _, err := cli.setupHijackConn(req, proto)
conn, _, err := setupHijackConn(cli.Dialer(), req, proto)
return conn, err
}

func (cli *Client) setupHijackConn(req *http.Request, proto string) (_ net.Conn, _ string, retErr error) {
func setupHijackConn(dialer func(context.Context) (net.Conn, error), req *http.Request, proto string) (_ net.Conn, _ string, retErr error) {
ctx := req.Context()
req.Header.Set("Connection", "Upgrade")
req.Header.Set("Upgrade", proto)

dialer := cli.Dialer()
conn, err := dialer(ctx)
if err != nil {
return nil, "", errors.Wrap(err, "cannot connect to the Docker daemon. Is 'docker daemon' running on this host?")
Expand Down Expand Up @@ -96,13 +100,7 @@ func (cli *Client) setupHijackConn(req *http.Request, proto string) (_ net.Conn,
hc.r.Reset(nil)
}

var mediaType string
if versions.GreaterThanOrEqualTo(cli.ClientVersion(), "1.42") {
// Prior to 1.42, Content-Type is always set to raw-stream and not relevant
mediaType = resp.Header.Get("Content-Type")
}

return conn, mediaType, nil
return conn, resp.Header.Get("Content-Type"), nil
}

// hijackedConn wraps a net.Conn and is returned by setupHijackConn in the case
Expand Down
10 changes: 0 additions & 10 deletions client/interface_stable.go

This file was deleted.

2 changes: 1 addition & 1 deletion integration/internal/swarm/states.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func RunningTasksCount(ctx context.Context, client client.ServiceAPIClient, serv
// JobComplete is a poll function for determining that a ReplicatedJob is
// completed additionally, while polling, it verifies that the job never
// exceeds MaxConcurrent running tasks
func JobComplete(ctx context.Context, client client.CommonAPIClient, service swarmtypes.Service) func(log poll.LogT) poll.Result {
func JobComplete(ctx context.Context, client client.ServiceAPIClient, service swarmtypes.Service) func(log poll.LogT) poll.Result {
filter := filters.NewArgs(filters.Arg("service", service.ID))

var jobIteration swarmtypes.Version
Expand Down

0 comments on commit 63ea5dc

Please sign in to comment.