From 7c657d433627cf6d8123132ea7328faf28e0cdec Mon Sep 17 00:00:00 2001 From: Aditya R Date: Sun, 4 Dec 2022 21:27:49 +0530 Subject: [PATCH] network: add support for podman network update and --network-dns-server * Add support for `podman network update <>` ```console network update Description: update networks for containers and pods Usage: podman network update [options] [NAME] Examples: podman network update podman1 Options: --add-dns-servers stringArray add network level nameservers --remove-dns-servers stringArray remove network level nameservers ``` * Add support for `--network-dns-server` to `podman network create` Extends podman to support recently added features in `netavark` and `aardvark-dns` * https://github.com/containers/netavark/pull/497 * https://github.com/containers/aardvark-dns/pull/252 * https://github.com/containers/netavark/pull/503 [NO NEW TESTS NEEDED] [NO TESTS NEEDED] Signed-off-by: Aditya R --- cmd/podman/networks/create.go | 5 ++ cmd/podman/networks/update.go | 63 ++++++++++++++++ go.mod | 2 + go.sum | 4 +- pkg/domain/entities/engine_container.go | 1 + pkg/domain/entities/network.go | 7 ++ pkg/domain/infra/abi/network.go | 11 +++ pkg/domain/infra/tunnel/network.go | 5 ++ .../common/libnetwork/cni/config.go | 4 + .../common/libnetwork/netavark/config.go | 74 ++++++++++++++++--- .../common/libnetwork/netavark/run.go | 11 +++ .../common/libnetwork/types/network.go | 10 +++ vendor/modules.txt | 3 +- 13 files changed, 188 insertions(+), 12 deletions(-) create mode 100644 cmd/podman/networks/update.go diff --git a/cmd/podman/networks/create.go b/cmd/podman/networks/create.go index 8b0ebeb2b506..9252ed056545 100644 --- a/cmd/podman/networks/create.go +++ b/cmd/podman/networks/create.go @@ -78,6 +78,10 @@ func networkCreateFlags(cmd *cobra.Command) { _ = cmd.RegisterFlagCompletionFunc(subnetFlagName, completion.AutocompleteNone) flags.BoolVar(&networkCreateOptions.DisableDNS, "disable-dns", false, "disable dns plugin") + + dnsserverFlagName := "network-dns-servers" + flags.StringArrayVar(&networkCreateOptions.NetworkDNSServers, dnsserverFlagName, nil, "network level nameservers") + _ = cmd.RegisterFlagCompletionFunc(dnsserverFlagName, completion.AutocompleteNone) } func init() { registry.Commands = append(registry.Commands, registry.CliCommand{ @@ -111,6 +115,7 @@ func networkCreate(cmd *cobra.Command, args []string) error { Labels: networkCreateOptions.Labels, IPv6Enabled: networkCreateOptions.IPv6, DNSEnabled: !networkCreateOptions.DisableDNS, + NetworkDNSServers: networkCreateOptions.NetworkDNSServers, Internal: networkCreateOptions.Internal, } diff --git a/cmd/podman/networks/update.go b/cmd/podman/networks/update.go new file mode 100644 index 000000000000..d80eafcbe256 --- /dev/null +++ b/cmd/podman/networks/update.go @@ -0,0 +1,63 @@ +package network + +import ( + "fmt" + + //"github.com/containers/common/libnetwork/types" + "github.com/containers/common/pkg/completion" + //"github.com/containers/podman/v4/cmd/podman/common" + //"github.com/containers/podman/v4/cmd/podman/parse" + "github.com/containers/podman/v4/cmd/podman/registry" + "github.com/containers/podman/v4/pkg/domain/entities" + "github.com/spf13/cobra" +) + +var ( + networkUpdateDescription = `update networks for containers and pods` + networkUpdateCommand = &cobra.Command{ + Use: "update [options] [NAME]", + Short: "network update", + Long: networkUpdateDescription, + RunE: networkUpdate, + Args: cobra.MaximumNArgs(1), + ValidArgsFunction: completion.AutocompleteNone, + Example: `podman network update podman1`, + } +) + +var ( + networkUpdateOptions entities.NetworkUpdateOptions +) + +func networkUpdateFlags(cmd *cobra.Command) { + flags := cmd.Flags() + + addDNSServerFlagName := "add-dns-servers" + flags.StringArrayVar(&networkUpdateOptions.AddDNSServers, addDNSServerFlagName, nil, "add network level nameservers") + removeDNSServerFlagName := "remove-dns-servers" + flags.StringArrayVar(&networkUpdateOptions.RemoveDNSServers, removeDNSServerFlagName, nil, "remove network level nameservers") + _ = cmd.RegisterFlagCompletionFunc(addDNSServerFlagName, completion.AutocompleteNone) + _ = cmd.RegisterFlagCompletionFunc(removeDNSServerFlagName, completion.AutocompleteNone) +} +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Command: networkUpdateCommand, + Parent: networkCmd, + }) + networkUpdateFlags(networkUpdateCommand) +} + +func networkUpdate(cmd *cobra.Command, args []string) error { + var ( + name string + ) + if len(args) > 0 { + name = args[0] + } + + err := registry.ContainerEngine().NetworkUpdate(registry.Context(), name, networkUpdateOptions) + if err != nil { + return err + } + return nil +} diff --git a/go.mod b/go.mod index 23461545454a..84ad9d9ad2a0 100644 --- a/go.mod +++ b/go.mod @@ -144,3 +144,5 @@ require ( ) replace github.com/opencontainers/runc => github.com/opencontainers/runc v1.1.1-0.20220617142545-8b9452f75cbc + +replace github.com/containers/common => github.com/flouthoc/common v0.39.1-0.20221203075808-f714653a2929 diff --git a/go.sum b/go.sum index 208ce4f29c9e..b452c670faaa 100644 --- a/go.sum +++ b/go.sum @@ -264,8 +264,6 @@ github.com/containernetworking/plugins v1.1.1 h1:+AGfFigZ5TiQH00vhR8qPeSatj53eNG github.com/containernetworking/plugins v1.1.1/go.mod h1:Sr5TH/eBsGLXK/h71HeLfX19sZPp3ry5uHSkI4LPxV8= github.com/containers/buildah v1.28.1-0.20221130132810-cf661299d14f h1:Nzbda2tG7/aimoKnDxysqFgS1Q/gSsbcn88lFPj9LwY= github.com/containers/buildah v1.28.1-0.20221130132810-cf661299d14f/go.mod h1:0HcSoS6BHXWzMKqtxY1L0gupebEX33oPC+X62lPi6+c= -github.com/containers/common v0.50.2-0.20221128124429-24d78208a290 h1:ds8YJg3Z91jOcqVR31aFFMH+BOobolXBeGktas58VgY= -github.com/containers/common v0.50.2-0.20221128124429-24d78208a290/go.mod h1:rzuZglPq/5sz6n29nhyDPCXh44CZymkCR2sacEZb7zw= github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg= github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I= github.com/containers/image/v5 v5.23.1-0.20221130170538-333c50e3eac8 h1:GLTTwKYkNGDhG3HagLuPvhieu1JEjDs9RsCDr8oJr9s= @@ -382,6 +380,8 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/flouthoc/common v0.39.1-0.20221203075808-f714653a2929 h1:Bj+2daLee3+4ux14y7+F4psuaPSQKkA+nA4C15uY6uM= +github.com/flouthoc/common v0.39.1-0.20221203075808-f714653a2929/go.mod h1:rzuZglPq/5sz6n29nhyDPCXh44CZymkCR2sacEZb7zw= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go index 44c4f2e4b3fc..3b95f0e9a2e4 100644 --- a/pkg/domain/entities/engine_container.go +++ b/pkg/domain/entities/engine_container.go @@ -64,6 +64,7 @@ type ContainerEngine interface { //nolint:interfacebloat KubeApply(ctx context.Context, body io.Reader, opts ApplyOptions) error NetworkConnect(ctx context.Context, networkname string, options NetworkConnectOptions) error NetworkCreate(ctx context.Context, network types.Network) (*types.Network, error) + NetworkUpdate(ctx context.Context, networkname string, options NetworkUpdateOptions) error NetworkDisconnect(ctx context.Context, networkname string, options NetworkDisconnectOptions) error NetworkExists(ctx context.Context, networkname string) (*BoolReport, error) NetworkInspect(ctx context.Context, namesOrIds []string, options InspectOptions) ([]types.Network, []error, error) diff --git a/pkg/domain/entities/network.go b/pkg/domain/entities/network.go index 9e59953c6776..2d788566c137 100644 --- a/pkg/domain/entities/network.go +++ b/pkg/domain/entities/network.go @@ -42,6 +42,7 @@ type NetworkRmReport struct { // NetworkCreateOptions describes options to create a network type NetworkCreateOptions struct { DisableDNS bool + NetworkDNSServers []string Driver string Gateways []net.IP Internal bool @@ -54,6 +55,12 @@ type NetworkCreateOptions struct { Options map[string]string } +// NetworkUpdateOptions describes options to update a network +type NetworkUpdateOptions struct { + AddDNSServers []string + RemoveDNSServers []string +} + // NetworkCreateReport describes a created network for the cli type NetworkCreateReport struct { Name string diff --git a/pkg/domain/infra/abi/network.go b/pkg/domain/infra/abi/network.go index 82fa1fab3203..70ad40de4d86 100644 --- a/pkg/domain/infra/abi/network.go +++ b/pkg/domain/infra/abi/network.go @@ -13,6 +13,17 @@ import ( "github.com/containers/podman/v4/pkg/domain/entities" ) +func (ic *ContainerEngine) NetworkUpdate(ctx context.Context, netName string, options entities.NetworkUpdateOptions) error { + var networkUpdateOptions types.NetworkUpdateOptions + networkUpdateOptions.AddDNSServers = options.AddDNSServers + networkUpdateOptions.RemoveDNSServers = options.RemoveDNSServers + err := ic.Libpod.Network().NetworkUpdate(netName, networkUpdateOptions) + if err != nil { + return err + } + return nil +} + func (ic *ContainerEngine) NetworkList(ctx context.Context, options entities.NetworkListOptions) ([]types.Network, error) { // dangling filter is not provided by netutil var wantDangling bool diff --git a/pkg/domain/infra/tunnel/network.go b/pkg/domain/infra/tunnel/network.go index 6e27b8e56da6..e9936a15b2c4 100644 --- a/pkg/domain/infra/tunnel/network.go +++ b/pkg/domain/infra/tunnel/network.go @@ -12,6 +12,11 @@ import ( "github.com/containers/podman/v4/pkg/errorhandling" ) +func (ic *ContainerEngine) NetworkUpdate(ctx context.Context, netName string, options entities.NetworkUpdateOptions) error { + // TODO: yet to be implemented for podman-remote + return nil +} + func (ic *ContainerEngine) NetworkList(ctx context.Context, opts entities.NetworkListOptions) ([]types.Network, error) { options := new(network.ListOptions).WithFilters(opts.Filters) return network.List(ic.ClientCtx, options) diff --git a/vendor/github.com/containers/common/libnetwork/cni/config.go b/vendor/github.com/containers/common/libnetwork/cni/config.go index 8e9418ad56b1..fb34f2f1a7e9 100644 --- a/vendor/github.com/containers/common/libnetwork/cni/config.go +++ b/vendor/github.com/containers/common/libnetwork/cni/config.go @@ -15,6 +15,10 @@ import ( "github.com/sirupsen/logrus" ) +func (n *cniNetwork) NetworkUpdate(name string, options types.NetworkUpdateOptions) error { + return fmt.Errorf("NetworkUpdate is not supported for backend CNI: %w", types.ErrInvalidArg) +} + // NetworkCreate will take a partial filled Network and fill the // missing fields. It creates the Network and returns the full Network. func (n *cniNetwork) NetworkCreate(net types.Network) (types.Network, error) { diff --git a/vendor/github.com/containers/common/libnetwork/netavark/config.go b/vendor/github.com/containers/common/libnetwork/netavark/config.go index 292981657eb4..af9e8cbd9c6c 100644 --- a/vendor/github.com/containers/common/libnetwork/netavark/config.go +++ b/vendor/github.com/containers/common/libnetwork/netavark/config.go @@ -10,6 +10,7 @@ import ( "net" "os" "path/filepath" + "reflect" "strconv" "time" @@ -19,6 +20,69 @@ import ( "github.com/containers/storage/pkg/stringid" ) +func sliceRemoveDuplicates(strList []string) []string { + list := make([]string, 0, len(strList)) + for _, item := range strList { + if !util.StringInSlice(item, list) { + list = append(list, item) + } + } + return list +} + +func (n *netavarkNetwork) commitNetwork(network *types.Network) error { + confPath := filepath.Join(n.networkConfigDir, network.Name+".json") + f, err := os.Create(confPath) + if err != nil { + return err + } + defer f.Close() + enc := json.NewEncoder(f) + enc.SetIndent("", " ") + err = enc.Encode(network) + if err != nil { + return err + } + return nil +} + +func (n *netavarkNetwork) NetworkUpdate(name string, options types.NetworkUpdateOptions) error { + n.lock.Lock() + defer n.lock.Unlock() + err := n.loadNetworks() + if err != nil { + return err + } + network, err := n.getNetwork(name) + if err != nil { + return err + } + networkDNSServersBefore := network.NetworkDNSServers + networkDNSServersAfter := []string{} + for _, server := range networkDNSServersBefore { + if util.StringInSlice(server, options.RemoveDNSServers) { + continue + } + networkDNSServersAfter = append(networkDNSServersAfter, server) + } + networkDNSServersAfter = append(networkDNSServersAfter, options.AddDNSServers...) + networkDNSServersAfter = sliceRemoveDuplicates(networkDNSServersAfter) + network.NetworkDNSServers = networkDNSServersAfter + if reflect.DeepEqual(networkDNSServersBefore, networkDNSServersAfter) { + return nil + } + err = n.commitNetwork(network) + if err != nil { + return err + } + + err = n.execUpdate(network.Name, network.NetworkDNSServers) + if err != nil { + return err + } + return nil +} + // NetworkCreate will take a partial filled Network and fill the // missing fields. It creates the Network and returns the full Network. func (n *netavarkNetwork) NetworkCreate(net types.Network) (types.Network, error) { @@ -158,15 +222,7 @@ func (n *netavarkNetwork) networkCreate(newNetwork *types.Network, defaultNet bo newNetwork.Created = time.Now() if !defaultNet { - confPath := filepath.Join(n.networkConfigDir, newNetwork.Name+".json") - f, err := os.Create(confPath) - if err != nil { - return nil, err - } - defer f.Close() - enc := json.NewEncoder(f) - enc.SetIndent("", " ") - err = enc.Encode(newNetwork) + err = n.commitNetwork(newNetwork) if err != nil { return nil, err } diff --git a/vendor/github.com/containers/common/libnetwork/netavark/run.go b/vendor/github.com/containers/common/libnetwork/netavark/run.go index b364f42d3f20..92807ec86b54 100644 --- a/vendor/github.com/containers/common/libnetwork/netavark/run.go +++ b/vendor/github.com/containers/common/libnetwork/netavark/run.go @@ -7,6 +7,7 @@ import ( "encoding/json" "fmt" "strconv" + "strings" "github.com/containers/common/libnetwork/internal/util" "github.com/containers/common/libnetwork/types" @@ -18,6 +19,16 @@ type netavarkOptions struct { Networks map[string]*types.Network `json:"network_info"` } +func (n *netavarkNetwork) execUpdate(networkName string, networkDNSServers []string) error { + err := n.loadNetworks() + if err != nil { + return err + } + + retErr := n.execNetavark([]string{"update", networkName, "--network-dns-servers", strings.Join(networkDNSServers, ",")}, nil, nil) + return retErr +} + // Setup will setup the container network namespace. It returns // a map of StatusBlocks, the key is the network name. func (n *netavarkNetwork) Setup(namespacePath string, options types.SetupOptions) (map[string]types.StatusBlock, error) { diff --git a/vendor/github.com/containers/common/libnetwork/types/network.go b/vendor/github.com/containers/common/libnetwork/types/network.go index d0e6d1796b7d..b36c687c64c2 100644 --- a/vendor/github.com/containers/common/libnetwork/types/network.go +++ b/vendor/github.com/containers/common/libnetwork/types/network.go @@ -10,6 +10,8 @@ type ContainerNetwork interface { // NetworkCreate will take a partial filled Network and fill the // missing fields. It creates the Network and returns the full Network. NetworkCreate(Network) (Network, error) + // NetworkUpdate will take network name and ID and updates network DNS Servers. + NetworkUpdate(nameOrID string, options NetworkUpdateOptions) error // NetworkRemove will remove the Network with the given name or ID. NetworkRemove(nameOrID string) error // NetworkList will return all known Networks. Optionally you can @@ -70,6 +72,14 @@ type Network struct { IPAMOptions map[string]string `json:"ipam_options,omitempty"` } +// NetworkOptions for a given container. +type NetworkUpdateOptions struct { + // List of custom DNS server for podman's DNS resolver. + // Priority order will be kept as defined by user in the configuration. + AddDNSServers []string `json:"add_dns_servers,omitempty"` + RemoveDNSServers []string `json:"remove_dns_servers,omitempty"` +} + // IPNet is used as custom net.IPNet type to add Marshal/Unmarshal methods. type IPNet struct { net.IPNet diff --git a/vendor/modules.txt b/vendor/modules.txt index 27fb3253ca0b..63887b073b8e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -118,7 +118,7 @@ github.com/containers/buildah/pkg/rusage github.com/containers/buildah/pkg/sshagent github.com/containers/buildah/pkg/util github.com/containers/buildah/util -# github.com/containers/common v0.50.2-0.20221128124429-24d78208a290 +# github.com/containers/common v0.50.2-0.20221128124429-24d78208a290 => github.com/flouthoc/common v0.39.1-0.20221203075808-f714653a2929 ## explicit; go 1.17 github.com/containers/common/libimage github.com/containers/common/libimage/define @@ -971,3 +971,4 @@ gopkg.in/yaml.v3 ## explicit; go 1.12 sigs.k8s.io/yaml # github.com/opencontainers/runc => github.com/opencontainers/runc v1.1.1-0.20220617142545-8b9452f75cbc +# github.com/containers/common => github.com/flouthoc/common v0.39.1-0.20221203075808-f714653a2929