Merge pull request #5225 from thaJeztah/network_cleanups

cli/command/network: some cleanup and pass smaller interfaces
This commit is contained in:
Paweł Gronowski 2024-07-04 12:05:46 +02:00 committed by GitHub
commit 6abed4e3c4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 68 additions and 65 deletions

View File

@ -25,7 +25,7 @@ type connectOptions struct {
driverOpts []string driverOpts []string
} }
func newConnectCommand(dockerCli command.Cli) *cobra.Command { func newConnectCommand(dockerCLI command.Cli) *cobra.Command {
options := connectOptions{ options := connectOptions{
links: opts.NewListOpts(opts.ValidateLink), links: opts.NewListOpts(opts.ValidateLink),
} }
@ -37,14 +37,14 @@ func newConnectCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
options.network = args[0] options.network = args[0]
options.container = args[1] options.container = args[1]
return runConnect(cmd.Context(), dockerCli.Client(), options) return runConnect(cmd.Context(), dockerCLI.Client(), options)
}, },
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) == 0 { if len(args) == 0 {
return completion.NetworkNames(dockerCli)(cmd, args, toComplete) return completion.NetworkNames(dockerCLI)(cmd, args, toComplete)
} }
nw := args[0] nw := args[0]
return completion.ContainerNames(dockerCli, true, not(isConnected(nw)))(cmd, args, toComplete) return completion.ContainerNames(dockerCLI, true, not(isConnected(nw)))(cmd, args, toComplete)
}, },
} }

View File

@ -3,6 +3,7 @@ package network
import ( import (
"context" "context"
"fmt" "fmt"
"io"
"net" "net"
"strings" "strings"
@ -11,6 +12,7 @@ import (
"github.com/docker/cli/cli/command/completion" "github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/opts" "github.com/docker/cli/opts"
"github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/network"
"github.com/docker/docker/client"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -27,22 +29,27 @@ type createOptions struct {
ingress bool ingress bool
configOnly bool configOnly bool
configFrom string configFrom string
ipam ipamOptions
ipamDriver string
ipamSubnet []string
ipamIPRange []string
ipamGateway []string
ipamAux opts.MapOpts
ipamOpt opts.MapOpts
} }
func newCreateCommand(dockerCli command.Cli) *cobra.Command { type ipamOptions struct {
driver string
subnets []string
ipRanges []string
gateways []string
auxAddresses opts.MapOpts
driverOpts opts.MapOpts
}
func newCreateCommand(dockerCLI command.Cli) *cobra.Command {
var ipv6 bool var ipv6 bool
options := createOptions{ options := createOptions{
driverOpts: *opts.NewMapOpts(nil, nil), driverOpts: *opts.NewMapOpts(nil, nil),
labels: opts.NewListOpts(opts.ValidateLabel), labels: opts.NewListOpts(opts.ValidateLabel),
ipamAux: *opts.NewMapOpts(nil, nil), ipam: ipamOptions{
ipamOpt: *opts.NewMapOpts(nil, nil), auxAddresses: *opts.NewMapOpts(nil, nil),
driverOpts: *opts.NewMapOpts(nil, nil),
},
} }
cmd := &cobra.Command{ cmd := &cobra.Command{
@ -56,7 +63,7 @@ func newCreateCommand(dockerCli command.Cli) *cobra.Command {
options.ipv6 = &ipv6 options.ipv6 = &ipv6
} }
return runCreate(cmd.Context(), dockerCli, options) return runCreate(cmd.Context(), dockerCLI.Client(), dockerCLI.Out(), options)
}, },
ValidArgsFunction: completion.NoComplete, ValidArgsFunction: completion.NoComplete,
} }
@ -78,21 +85,19 @@ func newCreateCommand(dockerCli command.Cli) *cobra.Command {
flags.StringVar(&options.configFrom, "config-from", "", "The network from which to copy the configuration") flags.StringVar(&options.configFrom, "config-from", "", "The network from which to copy the configuration")
flags.SetAnnotation("config-from", "version", []string{"1.30"}) flags.SetAnnotation("config-from", "version", []string{"1.30"})
flags.StringVar(&options.ipamDriver, "ipam-driver", "default", "IP Address Management Driver") flags.StringVar(&options.ipam.driver, "ipam-driver", "default", "IP Address Management Driver")
flags.StringSliceVar(&options.ipamSubnet, "subnet", []string{}, "Subnet in CIDR format that represents a network segment") flags.StringSliceVar(&options.ipam.subnets, "subnet", []string{}, "Subnet in CIDR format that represents a network segment")
flags.StringSliceVar(&options.ipamIPRange, "ip-range", []string{}, "Allocate container ip from a sub-range") flags.StringSliceVar(&options.ipam.ipRanges, "ip-range", []string{}, "Allocate container ip from a sub-range")
flags.StringSliceVar(&options.ipamGateway, "gateway", []string{}, "IPv4 or IPv6 Gateway for the master subnet") flags.StringSliceVar(&options.ipam.gateways, "gateway", []string{}, "IPv4 or IPv6 Gateway for the master subnet")
flags.Var(&options.ipamAux, "aux-address", "Auxiliary IPv4 or IPv6 addresses used by Network driver") flags.Var(&options.ipam.auxAddresses, "aux-address", "Auxiliary IPv4 or IPv6 addresses used by Network driver")
flags.Var(&options.ipamOpt, "ipam-opt", "Set IPAM driver specific options") flags.Var(&options.ipam.driverOpts, "ipam-opt", "Set IPAM driver specific options")
return cmd return cmd
} }
func runCreate(ctx context.Context, dockerCli command.Cli, options createOptions) error { func runCreate(ctx context.Context, apiClient client.NetworkAPIClient, output io.Writer, options createOptions) error {
client := dockerCli.Client() ipamCfg, err := createIPAMConfig(options.ipam)
ipamCfg, err := consolidateIpam(options.ipamSubnet, options.ipamIPRange, options.ipamGateway, options.ipamAux.GetAll())
if err != nil { if err != nil {
return err return err
} }
@ -103,14 +108,10 @@ func runCreate(ctx context.Context, dockerCli command.Cli, options createOptions
Network: options.configFrom, Network: options.configFrom,
} }
} }
resp, err := client.NetworkCreate(ctx, options.name, network.CreateOptions{ resp, err := apiClient.NetworkCreate(ctx, options.name, network.CreateOptions{
Driver: options.driver, Driver: options.driver,
Options: options.driverOpts.GetAll(), Options: options.driverOpts.GetAll(),
IPAM: &network.IPAM{ IPAM: ipamCfg,
Driver: options.ipamDriver,
Config: ipamCfg,
Options: options.ipamOpt.GetAll(),
},
Internal: options.internal, Internal: options.internal,
EnableIPv6: options.ipv6, EnableIPv6: options.ipv6,
Attachable: options.attachable, Attachable: options.attachable,
@ -123,25 +124,25 @@ func runCreate(ctx context.Context, dockerCli command.Cli, options createOptions
if err != nil { if err != nil {
return err return err
} }
fmt.Fprintf(dockerCli.Out(), "%s\n", resp.ID) _, _ = fmt.Fprintf(output, "%s\n", resp.ID)
return nil return nil
} }
// Consolidates the ipam configuration as a group from different related configurations // Consolidates the ipam configuration as a group from different related configurations
// user can configure network with multiple non-overlapping subnets and hence it is // user can configure network with multiple non-overlapping subnets and hence it is
// possible to correlate the various related parameters and consolidate them. // possible to correlate the various related parameters and consolidate them.
// consolidateIpam consolidates subnets, ip-ranges, gateways and auxiliary addresses into // createIPAMConfig consolidates subnets, ip-ranges, gateways and auxiliary addresses into
// structured ipam data. // structured ipam data.
// //
//nolint:gocyclo //nolint:gocyclo
func consolidateIpam(subnets, ranges, gateways []string, auxaddrs map[string]string) ([]network.IPAMConfig, error) { func createIPAMConfig(options ipamOptions) (*network.IPAM, error) {
if len(subnets) < len(ranges) || len(subnets) < len(gateways) { if len(options.subnets) < len(options.ipRanges) || len(options.subnets) < len(options.gateways) {
return nil, errors.Errorf("every ip-range or gateway must have a corresponding subnet") return nil, errors.Errorf("every ip-range or gateway must have a corresponding subnet")
} }
iData := map[string]*network.IPAMConfig{} iData := map[string]*network.IPAMConfig{}
// Populate non-overlapping subnets into consolidation map // Populate non-overlapping subnets into consolidation map
for _, s := range subnets { for _, s := range options.subnets {
for k := range iData { for k := range iData {
ok1, err := subnetMatches(s, k) ok1, err := subnetMatches(s, k)
if err != nil { if err != nil {
@ -159,9 +160,9 @@ func consolidateIpam(subnets, ranges, gateways []string, auxaddrs map[string]str
} }
// Validate and add valid ip ranges // Validate and add valid ip ranges
for _, r := range ranges { for _, r := range options.ipRanges {
match := false match := false
for _, s := range subnets { for _, s := range options.subnets {
ok, err := subnetMatches(s, r) ok, err := subnetMatches(s, r)
if err != nil { if err != nil {
return nil, err return nil, err
@ -182,9 +183,9 @@ func consolidateIpam(subnets, ranges, gateways []string, auxaddrs map[string]str
} }
// Validate and add valid gateways // Validate and add valid gateways
for _, g := range gateways { for _, g := range options.gateways {
match := false match := false
for _, s := range subnets { for _, s := range options.subnets {
ok, err := subnetMatches(s, g) ok, err := subnetMatches(s, g)
if err != nil { if err != nil {
return nil, err return nil, err
@ -205,9 +206,9 @@ func consolidateIpam(subnets, ranges, gateways []string, auxaddrs map[string]str
} }
// Validate and add aux-addresses // Validate and add aux-addresses
for key, aa := range auxaddrs { for key, aa := range options.auxAddresses.GetAll() {
match := false match := false
for _, s := range subnets { for _, s := range options.subnets {
ok, err := subnetMatches(s, aa) ok, err := subnetMatches(s, aa)
if err != nil { if err != nil {
return nil, err return nil, err
@ -223,11 +224,16 @@ func consolidateIpam(subnets, ranges, gateways []string, auxaddrs map[string]str
} }
} }
idl := []network.IPAMConfig{} idl := make([]network.IPAMConfig, 0, len(iData))
for _, v := range iData { for _, v := range iData {
idl = append(idl, *v) idl = append(idl, *v)
} }
return idl, nil
return &network.IPAM{
Driver: options.driver,
Config: idl,
Options: options.driverOpts.GetAll(),
}, nil
} }
func subnetMatches(subnet, data string) (bool, error) { func subnetMatches(subnet, data string) (bool, error) {

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion" "github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -26,7 +27,7 @@ func newDisconnectCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
opts.network = args[0] opts.network = args[0]
opts.container = args[1] opts.container = args[1]
return runDisconnect(cmd.Context(), dockerCli, opts) return runDisconnect(cmd.Context(), dockerCli.Client(), opts)
}, },
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) == 0 { if len(args) == 0 {
@ -43,10 +44,8 @@ func newDisconnectCommand(dockerCli command.Cli) *cobra.Command {
return cmd return cmd
} }
func runDisconnect(ctx context.Context, dockerCli command.Cli, opts disconnectOptions) error { func runDisconnect(ctx context.Context, apiClient client.NetworkAPIClient, opts disconnectOptions) error {
client := dockerCli.Client() return apiClient.NetworkDisconnect(ctx, opts.network, opts.container, opts.force)
return client.NetworkDisconnect(ctx, opts.network, opts.container, opts.force)
} }
func isConnected(network string) func(types.Container) bool { func isConnected(network string) func(types.Container) bool {

View File

@ -5,6 +5,7 @@ package network
import ( import (
"context" "context"
"io"
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
@ -12,6 +13,7 @@ import (
"github.com/docker/cli/cli/command/inspect" "github.com/docker/cli/cli/command/inspect"
flagsHelper "github.com/docker/cli/cli/flags" flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/network"
"github.com/docker/docker/client"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -21,7 +23,7 @@ type inspectOptions struct {
verbose bool verbose bool
} }
func newInspectCommand(dockerCli command.Cli) *cobra.Command { func newInspectCommand(dockerCLI command.Cli) *cobra.Command {
var opts inspectOptions var opts inspectOptions
cmd := &cobra.Command{ cmd := &cobra.Command{
@ -30,9 +32,9 @@ func newInspectCommand(dockerCli command.Cli) *cobra.Command {
Args: cli.RequiresMinArgs(1), Args: cli.RequiresMinArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
opts.names = args opts.names = args
return runInspect(cmd.Context(), dockerCli, opts) return runInspect(cmd.Context(), dockerCLI.Client(), dockerCLI.Out(), opts)
}, },
ValidArgsFunction: completion.NetworkNames(dockerCli), ValidArgsFunction: completion.NetworkNames(dockerCLI),
} }
cmd.Flags().StringVarP(&opts.format, "format", "f", "", flagsHelper.InspectFormatHelp) cmd.Flags().StringVarP(&opts.format, "format", "f", "", flagsHelper.InspectFormatHelp)
@ -41,12 +43,8 @@ func newInspectCommand(dockerCli command.Cli) *cobra.Command {
return cmd return cmd
} }
func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions) error { func runInspect(ctx context.Context, apiClient client.NetworkAPIClient, output io.Writer, opts inspectOptions) error {
client := dockerCli.Client() return inspect.Inspect(output, opts.names, opts.format, func(name string) (any, []byte, error) {
return apiClient.NetworkInspectWithRaw(ctx, name, network.InspectOptions{Verbose: opts.verbose})
getNetFunc := func(name string) (any, []byte, error) { })
return client.NetworkInspectWithRaw(ctx, name, network.InspectOptions{Verbose: opts.verbose})
}
return inspect.Inspect(dockerCli.Out(), opts.names, opts.format, getNetFunc)
} }

View File

@ -31,7 +31,7 @@ func NewPruneCommand(dockerCli command.Cli) *cobra.Command {
return err return err
} }
if output != "" { if output != "" {
fmt.Fprintln(dockerCli.Out(), output) _, _ = fmt.Fprintln(dockerCli.Out(), output)
} }
return nil return nil
}, },

View File

@ -60,11 +60,11 @@ func runRemove(ctx context.Context, dockerCli command.Cli, networks []string, op
if opts.force && errdefs.IsNotFound(err) { if opts.force && errdefs.IsNotFound(err) {
continue continue
} }
fmt.Fprintf(dockerCli.Err(), "%s\n", err) _, _ = fmt.Fprintf(dockerCli.Err(), "%s\n", err)
status = 1 status = 1
continue continue
} }
fmt.Fprintf(dockerCli.Out(), "%s\n", name) _, _ = fmt.Fprintf(dockerCli.Out(), "%s\n", name)
} }
if status != 0 { if status != 0 {