Merge pull request #16732 from flouthoc/network-update

network: add support for `podman network update` and `--network-dns-server`
This commit is contained in:
OpenShift Merge Robot
2023-01-12 12:18:14 -05:00
committed by GitHub
16 changed files with 320 additions and 16 deletions

View File

@ -80,6 +80,9 @@ func networkCreateFlags(cmd *cobra.Command) {
flags.BoolVar(&networkCreateOptions.DisableDNS, "disable-dns", false, "disable dns plugin")
flags.BoolVar(&networkCreateOptions.IgnoreIfExists, "ignore", false, "Don't fail if network already exists")
dnsserverFlagName := "dns"
flags.StringArrayVar(&networkCreateOptions.NetworkDNSServers, dnsserverFlagName, nil, "DNS servers this network will use")
_ = cmd.RegisterFlagCompletionFunc(dnsserverFlagName, completion.AutocompleteNone)
}
func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
@ -107,13 +110,14 @@ func networkCreate(cmd *cobra.Command, args []string) error {
}
network := types.Network{
Name: name,
Driver: networkCreateOptions.Driver,
Options: networkCreateOptions.Options,
Labels: networkCreateOptions.Labels,
IPv6Enabled: networkCreateOptions.IPv6,
DNSEnabled: !networkCreateOptions.DisableDNS,
Internal: networkCreateOptions.Internal,
Name: name,
Driver: networkCreateOptions.Driver,
Options: networkCreateOptions.Options,
Labels: networkCreateOptions.Labels,
IPv6Enabled: networkCreateOptions.IPv6,
DNSEnabled: !networkCreateOptions.DisableDNS,
NetworkDNSServers: networkCreateOptions.NetworkDNSServers,
Internal: networkCreateOptions.Internal,
}
if cmd.Flags().Changed(ipamDriverFlagName) {

View File

@ -0,0 +1,57 @@
package network
import (
"fmt"
"github.com/containers/common/pkg/completion"
"github.com/containers/podman/v4/cmd/podman/common"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/spf13/cobra"
)
var (
networkUpdateDescription = `Update an existing podman network`
networkUpdateCommand = &cobra.Command{
Use: "update [options] NETWORK",
Short: "update an existing podman network",
Long: networkUpdateDescription,
RunE: networkUpdate,
Args: cobra.ExactArgs(1),
ValidArgsFunction: common.AutocompleteNetworks,
Example: `podman network update podman1`,
}
)
var (
networkUpdateOptions entities.NetworkUpdateOptions
)
func networkUpdateFlags(cmd *cobra.Command) {
flags := cmd.Flags()
addDNSServerFlagName := "dns-add"
flags.StringArrayVar(&networkUpdateOptions.AddDNSServers, addDNSServerFlagName, nil, "add network level nameservers")
removeDNSServerFlagName := "dns-drop"
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 {
name := args[0]
err := registry.ContainerEngine().NetworkUpdate(registry.Context(), name, networkUpdateOptions)
if err != nil {
return err
}
fmt.Println(name)
return nil
}

View File

@ -24,6 +24,10 @@ release because it is used as a special network mode in **podman run/create --ne
Disables the DNS plugin for this network which if enabled, can perform container to container name
resolution.
#### **--dns**=*ip*
Set network-scoped DNS resolver/nameserver for containers in this network. If not set, the host servers from `/etc/resolv.conf` will be used. It can be overwritten on the container level with the `podman run/create --dns` option. This option can be specified multiple times to set more than one IP.
#### **--driver**, **-d**
Driver to manage the network. Currently `bridge`, `macvlan` and `ipvlan` are supported. Defaults to `bridge`.

View File

@ -0,0 +1,36 @@
% podman-network-update 1
## NAME
podman\-network\-update - Update an existing Podman network
## SYNOPSIS
**podman network update** [*options*] *network*
## DESCRIPTION
Allow changes to existing container networks. At present, only changes to the DNS servers in use by a network is supported.
NOTE: Only supported with the netavark network backend.
## OPTIONS
#### **--dns-add**
Accepts array of DNS resolvers and add it to the existing list of resolvers configured for a network.
#### **--dns-drop**
Accepts array of DNS resolvers and removes them from the existing list of resolvers configured for a network.
## EXAMPLE
Update a network
```
$ podman network update network1 --dns-add 8.8.8.8,1.1.1.1
```
Update a network and add/remove dns servers
```
$ podman network update network1 --dns-drop 8.8.8.8 --dns-add 3.3.3.3
```
## SEE ALSO
**[podman(1)](podman.1.md)**, **[podman-network(1)](podman-network.1.md)**, **[podman-network-inspect(1)](podman-network-inspect.1.md)**, **[podman-network-ls(1)](podman-network-ls.1.md)**

View File

@ -32,6 +32,7 @@ so networks have to be created again after a backend change.
| prune | [podman-network-prune(1)](podman-network-prune.1.md) | Remove all unused networks |
| reload | [podman-network-reload(1)](podman-network-reload.1.md) | Reload network configuration for containers |
| rm | [podman-network-rm(1)](podman-network-rm.1.md) | Remove one or more networks |
| update | [podman-network-upate(1)](podman-network-update.1.md) | Update an existing Podman network |
## SEE ALSO
**[podman(1)](podman.1.md)**, **[containers.conf(5)](https://github.com/containers/common/blob/main/docs/containers.conf.5.md)**

View File

@ -53,6 +53,26 @@ func CreateNetwork(w http.ResponseWriter, r *http.Request) {
utils.WriteResponse(w, http.StatusOK, report)
}
func UpdateNetwork(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
ic := abi.ContainerEngine{Libpod: runtime}
networkUpdateOptions := entities.NetworkUpdateOptions{}
if err := json.NewDecoder(r.Body).Decode(&networkUpdateOptions); err != nil {
utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to decode request JSON payload: %w", err))
return
}
name := utils.GetName(r)
err := ic.NetworkUpdate(r.Context(), name, networkUpdateOptions)
if err != nil {
utils.Error(w, http.StatusInternalServerError, err)
}
utils.WriteResponse(w, http.StatusNoContent, nil)
}
func ListNetworks(w http.ResponseWriter, r *http.Request) {
if v, err := utils.SupportedVersion(r, ">=4.0.0"); err != nil {
utils.BadRequest(w, "version", v.String(), err)

View File

@ -44,3 +44,7 @@ type networkDisconnectRequest types.NetworkDisconnect
// Network connect
// swagger:model
type networkConnectRequestLibpod entities.NetworkConnectOptions
// Network update
// swagger:model
type networkUpdateRequestLibpod entities.NetworkUpdateOptions

View File

@ -234,6 +234,33 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error {
// 500:
// $ref: "#/responses/internalError"
r.HandleFunc(VersionedPath("/libpod/networks/{name}"), s.APIHandler(libpod.RemoveNetwork)).Methods(http.MethodDelete)
// swagger:operation POST /libpod/networks/{name}/update libpod NetworkUpdateLibpod
// ---
// tags:
// - networks
// summary: Update exisiting podman network
// description: Update exisiting podman network
// produces:
// - application/json
// parameters:
// - in: path
// name: name
// type: string
// required: true
// description: the name or ID of the network
// - in: body
// name: update
// description: attributes for updating a netavark network
// schema:
// $ref: "#/definitions/networkUpdateRequestLibpod"
// responses:
// 200:
// description: OK
// 400:
// $ref: "#/responses/badParamError"
// 500:
// $ref: "#/responses/internalError"
r.HandleFunc(VersionedPath("/libpod/networks/{name}/update"), s.APIHandler(libpod.UpdateNetwork)).Methods(http.MethodPost)
// swagger:operation GET /libpod/networks/{name}/exists libpod NetworkExistsLibpod
// ---
// tags:

View File

@ -50,6 +50,25 @@ func CreateWithOptions(ctx context.Context, network *types.Network, extraCreateO
return report, response.Process(&report)
}
// Updates an existing netavark network config
func Update(ctx context.Context, netNameOrID string, options *UpdateOptions) error {
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
networkConfig, err := jsoniter.MarshalToString(options)
if err != nil {
return err
}
reader := strings.NewReader(networkConfig)
response, err := conn.DoRequest(ctx, reader, http.MethodPost, "/networks/%s/update", nil, nil, netNameOrID)
if err != nil {
return err
}
defer response.Body.Close()
return response.Process(nil)
}
// Inspect returns information about a network configuration
func Inspect(ctx context.Context, nameOrID string, _ *InspectOptions) (types.Network, error) {
var net types.Network

View File

@ -58,6 +58,14 @@ type ListOptions struct {
Filters map[string][]string
}
// NetworkUpdateOptions describes options to update a network
//
//go:generate go run ../generator/generator.go UpdateOptions
type UpdateOptions struct {
AddDNSServers []string `json:"adddnsservers"`
RemoveDNSServers []string `json:"removednsservers"`
}
// DisconnectOptions are optional options for disconnecting
// containers from a network
//

View File

@ -0,0 +1,48 @@
// Code generated by go generate; DO NOT EDIT.
package network
import (
"net/url"
"github.com/containers/podman/v4/pkg/bindings/internal/util"
)
// Changed returns true if named field has been set
func (o *UpdateOptions) Changed(fieldName string) bool {
return util.Changed(o, fieldName)
}
// ToParams formats struct fields to be passed to API service
func (o *UpdateOptions) ToParams() (url.Values, error) {
return util.ToParams(o)
}
// WithAddDNSServers set field AddDNSServers to given value
func (o *UpdateOptions) WithAddDNSServers(value []string) *UpdateOptions {
o.AddDNSServers = value
return o
}
// GetAddDNSServers returns value of field AddDNSServers
func (o *UpdateOptions) GetAddDNSServers() []string {
if o.AddDNSServers == nil {
var z []string
return z
}
return o.AddDNSServers
}
// WithRemoveDNSServers set field RemoveDNSServers to given value
func (o *UpdateOptions) WithRemoveDNSServers(value []string) *UpdateOptions {
o.RemoveDNSServers = value
return o
}
// GetRemoveDNSServers returns value of field RemoveDNSServers
func (o *UpdateOptions) GetRemoveDNSServers() []string {
if o.RemoveDNSServers == nil {
var z []string
return z
}
return o.RemoveDNSServers
}

View File

@ -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, createOptions *types.NetworkCreateOptions) (*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)

View File

@ -41,21 +41,28 @@ type NetworkRmReport struct {
// NetworkCreateOptions describes options to create a network
type NetworkCreateOptions struct {
DisableDNS bool
Driver string
Gateways []net.IP
Internal bool
Labels map[string]string
MacVLAN string
Ranges []string
Subnets []string
IPv6 bool
DisableDNS bool
Driver string
Gateways []net.IP
Internal bool
Labels map[string]string
MacVLAN string
NetworkDNSServers []string
Ranges []string
Subnets []string
IPv6 bool
// Mapping of driver options and values.
Options map[string]string
// IgnoreIfExists if true, do not fail if the network already exists
IgnoreIfExists bool
}
// NetworkUpdateOptions describes options to update a network
type NetworkUpdateOptions struct {
AddDNSServers []string `json:"adddnsservers"`
RemoveDNSServers []string `json:"removednsservers"`
}
// NetworkCreateReport describes a created network for the cli
type NetworkCreateReport struct {
Name string

View File

@ -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

View File

@ -12,6 +12,11 @@ import (
"github.com/containers/podman/v4/pkg/errorhandling"
)
func (ic *ContainerEngine) NetworkUpdate(ctx context.Context, netName string, opts entities.NetworkUpdateOptions) error {
options := new(network.UpdateOptions).WithAddDNSServers(opts.AddDNSServers).WithRemoveDNSServers(opts.RemoveDNSServers)
return network.Update(ic.ClientCtx, netName, options)
}
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)

View File

@ -1,6 +1,7 @@
package integration
import (
"encoding/json"
"fmt"
"net"
"os"
@ -8,6 +9,7 @@ import (
"syscall"
"github.com/containernetworking/plugins/pkg/ns"
"github.com/containers/common/libnetwork/types"
. "github.com/containers/podman/v4/test/utils"
"github.com/containers/storage/pkg/stringid"
. "github.com/onsi/ginkgo"
@ -41,6 +43,56 @@ var _ = Describe("Podman run networking", func() {
})
It("podman verify network scoped DNS server and also verify updating network dns server", func() {
// TODO: Unskip after https://github.com/containers/podman/pull/16525
Skip("TODO: unskip after https://github.com/containers/podman/pull/16525")
// Following test is only functional with netavark and aardvark
SkipIfCNI(podmanTest)
net := createNetworkName("IntTest")
session := podmanTest.Podman([]string{"network", "create", net, "--dns", "1.1.1.1"})
session.WaitWithDefaultTimeout()
defer podmanTest.removeNetwork(net)
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"network", "inspect", net})
session.WaitWithDefaultTimeout()
defer podmanTest.removeNetwork(net)
var results []types.Network
err := json.Unmarshal([]byte(session.OutputToString()), &results)
Expect(err).ToNot(HaveOccurred())
Expect(results).To(HaveLen(1))
result := results[0]
Expect(result.Subnets).To(HaveLen(1))
aardvarkDNSGateway := result.Subnets[0].Gateway.String()
Expect(session.OutputToString()).To(ContainSubstring("1.1.1.1"))
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"run", "-d", "--name", "con1", "--network", net, "busybox", "top"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"exec", "-i", "con1", "nslookup", "google.com", aardvarkDNSGateway})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.OutputToString()).To(ContainSubstring("Non-authoritative answer: Name: google.com Address:"))
// Update to a bad DNS Server
session = podmanTest.Podman([]string{"network", "update", net, "--dns-add", "7.7.7.7"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
// Remove good DNS server
session = podmanTest.Podman([]string{"network", "update", net, "--dns-drop=1.1.1.1"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"exec", "-i", "con1", "nslookup", "google.com", aardvarkDNSGateway})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(1))
Expect(session.OutputToString()).To(ContainSubstring(";; connection timed out; no servers could be reached"))
})
It("podman run network connection with default bridge", func() {
session := podmanTest.RunContainerWithNetworkTest("")
session.WaitWithDefaultTimeout()