diff --git a/cli/command/container/opts.go b/cli/command/container/opts.go index fb58567ee119..509662095cfb 100644 --- a/cli/command/container/opts.go +++ b/cli/command/container/opts.go @@ -858,7 +858,9 @@ func parseNetworkAttachmentOpt(ep opts.NetworkAttachmentOpts) (*networktypes.End } } - epConfig := &networktypes.EndpointSettings{} + epConfig := &networktypes.EndpointSettings{ + GwPriority: ep.GwPriority, + } epConfig.Aliases = append(epConfig.Aliases, ep.Aliases...) if len(ep.DriverOpts) > 0 { epConfig.DriverOpts = make(map[string]string) diff --git a/cli/command/network/connect.go b/cli/command/network/connect.go index 0d9e87125975..9ffd25c85e9d 100644 --- a/cli/command/network/connect.go +++ b/cli/command/network/connect.go @@ -23,6 +23,7 @@ type connectOptions struct { aliases []string linklocalips []string driverOpts []string + gwPriority int } func newConnectCommand(dockerCLI command.Cli) *cobra.Command { @@ -55,6 +56,7 @@ func newConnectCommand(dockerCLI command.Cli) *cobra.Command { flags.StringSliceVar(&options.aliases, "alias", []string{}, "Add network-scoped alias for the container") flags.StringSliceVar(&options.linklocalips, "link-local-ip", []string{}, "Add a link-local address for the container") flags.StringSliceVar(&options.driverOpts, "driver-opt", []string{}, "driver options for the network") + flags.IntVar(&options.gwPriority, "gw-priority", 0, "Highest gw-priority provides the default gateway. Accepts positive and negative values.") return cmd } @@ -73,6 +75,7 @@ func runConnect(ctx context.Context, apiClient client.NetworkAPIClient, options Links: options.links.GetAll(), Aliases: options.aliases, DriverOpts: driverOpts, + GwPriority: options.gwPriority, }) } diff --git a/cli/command/network/connect_test.go b/cli/command/network/connect_test.go index c44fe3fc5f60..f51ef869edbe 100644 --- a/cli/command/network/connect_test.go +++ b/cli/command/network/connect_test.go @@ -56,6 +56,7 @@ func TestNetworkConnectWithFlags(t *testing.T) { "driveropt1": "optval1,optval2", "driveropt2": "optval4", }, + GwPriority: 100, } cli := test.NewFakeCli(&fakeClient{ networkConnectFunc: func(ctx context.Context, networkID, container string, config *network.EndpointSettings) error { @@ -76,6 +77,7 @@ func TestNetworkConnectWithFlags(t *testing.T) { {"ip6", "fdef:f401:8da0:1234::5678"}, {"link", "otherctr"}, {"link-local-ip", "169.254.42.42"}, + {"gw-priority", "100"}, } { err := cmd.Flags().Set(opt.name, opt.value) assert.Check(t, err) diff --git a/docs/reference/commandline/container_run.md b/docs/reference/commandline/container_run.md index 98e86e907d8e..d8e1b3f52e4d 100644 --- a/docs/reference/commandline/container_run.md +++ b/docs/reference/commandline/container_run.md @@ -749,15 +749,16 @@ To specify options when connecting to more than one network, use the extended sy for the `--network` flag. Comma-separated options that can be specified in the extended `--network` syntax are: -| Option | Top-level Equivalent | Description | -|-----------------|---------------------------------------|-------------------------------------------------| -| `name` | | The name of the network (mandatory) | -| `alias` | `--network-alias` | Add network-scoped alias for the container | -| `ip` | `--ip` | IPv4 address (e.g., 172.30.100.104) | -| `ip6` | `--ip6` | IPv6 address (e.g., 2001:db8::33) | -| `mac-address` | `--mac-address` | Container MAC address (e.g., 92:d0:c6:0a:29:33) | -| `link-local-ip` | `--link-local-ip` | Container IPv4/IPv6 link-local addresses | -| `driver-opt` | `docker network connect --driver-opt` | Network driver options | +| Option | Top-level Equivalent | Description | +|-----------------|---------------------------------------|-----------------------------------------------------------------------------------------| +| `name` | | The name of the network (mandatory) | +| `alias` | `--network-alias` | Add network-scoped alias for the container | +| `ip` | `--ip` | IPv4 address (e.g., 172.30.100.104) | +| `ip6` | `--ip6` | IPv6 address (e.g., 2001:db8::33) | +| `mac-address` | `--mac-address` | Container MAC address (e.g., 92:d0:c6:0a:29:33) | +| `link-local-ip` | `--link-local-ip` | Container IPv4/IPv6 link-local addresses | +| `driver-opt` | `docker network connect --driver-opt` | Network driver options | +| `gw-priority` | | Highest gw-priority provides the default gateway. Accepts positive and negative values. | ```console $ docker network create --subnet 192.0.2.0/24 my-net1 diff --git a/docs/reference/commandline/network_connect.md b/docs/reference/commandline/network_connect.md index 08924b936ec7..3a6514fab719 100644 --- a/docs/reference/commandline/network_connect.md +++ b/docs/reference/commandline/network_connect.md @@ -5,14 +5,15 @@ Connect a container to a network ### Options -| Name | Type | Default | Description | -|:--------------------|:--------------|:--------|:-------------------------------------------| -| [`--alias`](#alias) | `stringSlice` | | Add network-scoped alias for the container | -| `--driver-opt` | `stringSlice` | | driver options for the network | -| [`--ip`](#ip) | `string` | | IPv4 address (e.g., `172.30.100.104`) | -| `--ip6` | `string` | | IPv6 address (e.g., `2001:db8::33`) | -| [`--link`](#link) | `list` | | Add link to another container | -| `--link-local-ip` | `stringSlice` | | Add a link-local address for the container | +| Name | Type | Default | Description | +|:--------------------|:--------------|:--------|:----------------------------------------------------------------------------------------| +| [`--alias`](#alias) | `stringSlice` | | Add network-scoped alias for the container | +| `--driver-opt` | `stringSlice` | | driver options for the network | +| `--gw-priority` | `int` | `0` | Highest gw-priority provides the default gateway. Accepts positive and negative values. | +| [`--ip`](#ip) | `string` | | IPv4 address (e.g., `172.30.100.104`) | +| `--ip6` | `string` | | IPv6 address (e.g., `2001:db8::33`) | +| [`--link`](#link) | `list` | | Add link to another container | +| `--link-local-ip` | `stringSlice` | | Add a link-local address for the container | diff --git a/opts/network.go b/opts/network.go index 413aec7b52e6..2ce5dff1f81b 100644 --- a/opts/network.go +++ b/opts/network.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "regexp" + "strconv" "strings" ) @@ -16,6 +17,7 @@ const ( networkOptMacAddress = "mac-address" networkOptLinkLocalIP = "link-local-ip" driverOpt = "driver-opt" + gwPriorityOpt = "gw-priority" ) // NetworkAttachmentOpts represents the network options for endpoint creation @@ -28,6 +30,7 @@ type NetworkAttachmentOpts struct { IPv6Address string LinkLocalIPs []string MacAddress string + GwPriority int } // NetworkOpt represents a network config in swarm mode. @@ -83,6 +86,11 @@ func (n *NetworkOpt) Set(value string) error { //nolint:gocyclo netOpt.DriverOpts = make(map[string]string) } netOpt.DriverOpts[key] = val + case gwPriorityOpt: + netOpt.GwPriority, err = strconv.Atoi(val) + if err != nil { + return fmt.Errorf("invalid gw-priority: %w", err) + } default: return errors.New("invalid field key " + key) } diff --git a/opts/network_test.go b/opts/network_test.go index 722062bd7d5c..71f38e98ac16 100644 --- a/opts/network_test.go +++ b/opts/network_test.go @@ -112,6 +112,16 @@ func TestNetworkOptAdvancedSyntax(t *testing.T) { }, }, }, + { + value: "name=docknet1,gw-priority=10", + expected: []NetworkAttachmentOpts{ + { + Target: "docknet1", + Aliases: []string{}, + GwPriority: 10, + }, + }, + }, } for _, tc := range testCases { t.Run(tc.value, func(t *testing.T) { diff --git a/vendor.mod b/vendor.mod index 8cb6b1988d01..3bdaa2cbb4be 100644 --- a/vendor.mod +++ b/vendor.mod @@ -13,7 +13,7 @@ require ( github.com/distribution/reference v0.6.0 github.com/docker/cli-docs-tool v0.8.0 github.com/docker/distribution v2.8.3+incompatible - github.com/docker/docker v27.0.2-0.20241120142749-e5c2b5e10d68+incompatible // master (v-next) + github.com/docker/docker v27.0.2-0.20241202115249-87fbd9cd3b37+incompatible // master (v-next) github.com/docker/docker-credential-helpers v0.8.2 github.com/docker/go-connections v0.5.0 github.com/docker/go-units v0.5.0 diff --git a/vendor.sum b/vendor.sum index f0b3eabf1482..d10d4faecf9a 100644 --- a/vendor.sum +++ b/vendor.sum @@ -51,8 +51,8 @@ github.com/docker/cli-docs-tool v0.8.0/go.mod h1:8TQQ3E7mOXoYUs811LiPdUnAhXrcVsB github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v27.0.2-0.20241120142749-e5c2b5e10d68+incompatible h1:ZWh4HhdUCagAd3S+gsFPOobHbc562obYFSrz3irGSsU= -github.com/docker/docker v27.0.2-0.20241120142749-e5c2b5e10d68+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v27.0.2-0.20241202115249-87fbd9cd3b37+incompatible h1:Ct0/s+pkUCDPBsQmLVHnBEas8OlTRxNvDXdSa6Y2PfE= +github.com/docker/docker v27.0.2-0.20241202115249-87fbd9cd3b37+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo= github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0= diff --git a/vendor/github.com/docker/docker/api/swagger.yaml b/vendor/github.com/docker/docker/api/swagger.yaml index a237f374aaef..b9f805a52f73 100644 --- a/vendor/github.com/docker/docker/api/swagger.yaml +++ b/vendor/github.com/docker/docker/api/swagger.yaml @@ -2927,6 +2927,16 @@ definitions: example: com.example.some-label: "some-value" com.example.some-other-label: "some-other-value" + GwPriority: + description: | + This property determines which endpoint will provide the default + gateway for a container. The endpoint with the highest priority will + be used. If multiple endpoints have the same priority, endpoints are + lexicographically sorted based on their network name, and the one + that sorts first is picked. + type: "number" + example: + - 10 # Operational data NetworkID: @@ -10910,6 +10920,7 @@ paths: IPv4Address: "172.24.56.89" IPv6Address: "2001:db8::5689" MacAddress: "02:42:ac:12:05:02" + Priority: 100 tags: ["Network"] /networks/{id}/disconnect: diff --git a/vendor/github.com/docker/docker/api/types/network/endpoint.go b/vendor/github.com/docker/docker/api/types/network/endpoint.go index 0fbb40b351c3..d724ea02a261 100644 --- a/vendor/github.com/docker/docker/api/types/network/endpoint.go +++ b/vendor/github.com/docker/docker/api/types/network/endpoint.go @@ -19,6 +19,7 @@ type EndpointSettings struct { // generated address). MacAddress string DriverOpts map[string]string + GwPriority int // Operational data NetworkID string EndpointID string diff --git a/vendor/github.com/docker/docker/registry/service.go b/vendor/github.com/docker/docker/registry/service.go index 6881c1105769..73f422150dc0 100644 --- a/vendor/github.com/docker/docker/registry/service.go +++ b/vendor/github.com/docker/docker/registry/service.go @@ -103,7 +103,6 @@ func (s *Service) ResolveRepository(name reference.Named) (*RepositoryInfo, erro type APIEndpoint struct { Mirror bool URL *url.URL - Version APIVersion // Deprecated: v1 registries are deprecated, and endpoints are always v2. AllowNondistributableArtifacts bool Official bool TrimHostname bool diff --git a/vendor/github.com/docker/docker/registry/service_v2.go b/vendor/github.com/docker/docker/registry/service_v2.go index 5d09e11c9c5c..42b1730a257f 100644 --- a/vendor/github.com/docker/docker/registry/service_v2.go +++ b/vendor/github.com/docker/docker/registry/service_v2.go @@ -25,7 +25,6 @@ func (s *Service) lookupV2Endpoints(hostname string) (endpoints []APIEndpoint, e } endpoints = append(endpoints, APIEndpoint{ URL: mirrorURL, - Version: APIVersion2, //nolint:staticcheck // ignore SA1019 (Version is deprecated) to allow potential consumers to transition. Mirror: true, TrimHostname: true, TLSConfig: mirrorTLSConfig, @@ -33,7 +32,6 @@ func (s *Service) lookupV2Endpoints(hostname string) (endpoints []APIEndpoint, e } endpoints = append(endpoints, APIEndpoint{ URL: DefaultV2Registry, - Version: APIVersion2, //nolint:staticcheck // ignore SA1019 (Version is deprecated) to allow potential consumers to transition. Official: true, TrimHostname: true, TLSConfig: tlsconfig.ServerDefault(), @@ -55,7 +53,6 @@ func (s *Service) lookupV2Endpoints(hostname string) (endpoints []APIEndpoint, e Scheme: "https", Host: hostname, }, - Version: APIVersion2, //nolint:staticcheck // ignore SA1019 (Version is deprecated) to allow potential consumers to transition. AllowNondistributableArtifacts: ana, TrimHostname: true, TLSConfig: tlsConfig, @@ -68,7 +65,6 @@ func (s *Service) lookupV2Endpoints(hostname string) (endpoints []APIEndpoint, e Scheme: "http", Host: hostname, }, - Version: APIVersion2, //nolint:staticcheck // ignore SA1019 (Version is deprecated) to allow potential consumers to transition. AllowNondistributableArtifacts: ana, TrimHostname: true, // used to check if supposed to be secure via InsecureSkipVerify diff --git a/vendor/github.com/docker/docker/registry/types.go b/vendor/github.com/docker/docker/registry/types.go index 54aa0bd19dfc..02d7f4f383b7 100644 --- a/vendor/github.com/docker/docker/registry/types.go +++ b/vendor/github.com/docker/docker/registry/types.go @@ -5,27 +5,6 @@ import ( "github.com/docker/docker/api/types/registry" ) -// APIVersion is an integral representation of an API version (presently -// either 1 or 2) -// -// Deprecated: v1 registries are deprecated, and endpoints are always v2. -type APIVersion int - -func (av APIVersion) String() string { - return apiVersions[av] -} - -// API Version identifiers. -const ( - APIVersion1 APIVersion = 1 // Deprecated: v1 registries are deprecated, and endpoints are always v2. - APIVersion2 APIVersion = 2 // Deprecated: v1 registries are deprecated, and endpoints are always v2. -) - -var apiVersions = map[APIVersion]string{ - APIVersion1: "v1", - APIVersion2: "v2", -} - // RepositoryInfo describes a repository type RepositoryInfo struct { Name reference.Named @@ -37,5 +16,7 @@ type RepositoryInfo struct { Official bool // Class represents the class of the repository, such as "plugin" // or "image". + // + // Deprecated: this field is no longer used, and will be removed in the next release. Class string } diff --git a/vendor/modules.txt b/vendor/modules.txt index 5856c811c015..11654fe8816f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -55,7 +55,7 @@ github.com/docker/distribution/registry/client/transport github.com/docker/distribution/registry/storage/cache github.com/docker/distribution/registry/storage/cache/memory github.com/docker/distribution/uuid -# github.com/docker/docker v27.0.2-0.20241120142749-e5c2b5e10d68+incompatible +# github.com/docker/docker v27.0.2-0.20241202115249-87fbd9cd3b37+incompatible ## explicit github.com/docker/docker/api github.com/docker/docker/api/types