From 4791595b5cb3b2350c66b0d1ba91a6a171652409 Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Wed, 8 Dec 2021 15:31:49 +0100 Subject: network connect allow ip, ipv6 and mac address Network connect now supports setting a static ipv4, ipv6 and mac address for the container network. The options are added to the cli and api. Fixes #9883 Signed-off-by: Paul Holzinger --- pkg/api/handlers/compat/networks.go | 52 ++++++++++++++++++++++++++++++++++--- pkg/api/handlers/libpod/networks.go | 2 +- 2 files changed, 50 insertions(+), 4 deletions(-) (limited to 'pkg/api/handlers') diff --git a/pkg/api/handlers/compat/networks.go b/pkg/api/handlers/compat/networks.go index 8aab29658..db3af7d0b 100644 --- a/pkg/api/handlers/compat/networks.go +++ b/pkg/api/handlers/compat/networks.go @@ -299,20 +299,66 @@ func Connect(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) var ( - aliases []string netConnect types.NetworkConnect ) if err := json.NewDecoder(r.Body).Decode(&netConnect); err != nil { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()")) return } + + netOpts := nettypes.PerNetworkOptions{} + name := utils.GetName(r) if netConnect.EndpointConfig != nil { if netConnect.EndpointConfig.Aliases != nil { - aliases = netConnect.EndpointConfig.Aliases + netOpts.Aliases = netConnect.EndpointConfig.Aliases + } + + // if IP address is provided + if len(netConnect.EndpointConfig.IPAddress) > 0 { + staticIP := net.ParseIP(netConnect.EndpointConfig.IPAddress) + if staticIP == nil { + utils.Error(w, "failed to parse the ip address", http.StatusInternalServerError, + errors.Errorf("failed to parse the ip address %q", netConnect.EndpointConfig.IPAddress)) + return + } + netOpts.StaticIPs = append(netOpts.StaticIPs, staticIP) + } + + if netConnect.EndpointConfig.IPAMConfig != nil { + // if IPAMConfig.IPv4Address is provided + if len(netConnect.EndpointConfig.IPAMConfig.IPv4Address) > 0 { + staticIP := net.ParseIP(netConnect.EndpointConfig.IPAMConfig.IPv4Address) + if staticIP == nil { + utils.Error(w, "failed to parse the ipv4 address", http.StatusInternalServerError, + errors.Errorf("failed to parse the ipv4 address %q", netConnect.EndpointConfig.IPAMConfig.IPv4Address)) + return + } + netOpts.StaticIPs = append(netOpts.StaticIPs, staticIP) + } + // if IPAMConfig.IPv6Address is provided + if len(netConnect.EndpointConfig.IPAMConfig.IPv6Address) > 0 { + staticIP := net.ParseIP(netConnect.EndpointConfig.IPAMConfig.IPv6Address) + if staticIP == nil { + utils.Error(w, "failed to parse the ipv6 address", http.StatusInternalServerError, + errors.Errorf("failed to parse the ipv6 address %q", netConnect.EndpointConfig.IPAMConfig.IPv6Address)) + return + } + netOpts.StaticIPs = append(netOpts.StaticIPs, staticIP) + } + } + // If MAC address is provided + if len(netConnect.EndpointConfig.MacAddress) > 0 { + staticMac, err := net.ParseMAC(netConnect.EndpointConfig.MacAddress) + if err != nil { + utils.Error(w, "failed to parse the mac address", http.StatusInternalServerError, + errors.Errorf("failed to parse the mac address %q", netConnect.EndpointConfig.IPAMConfig.IPv6Address)) + return + } + netOpts.StaticMAC = nettypes.HardwareAddr(staticMac) } } - err := runtime.ConnectContainerToNetwork(netConnect.Container, name, aliases) + err := runtime.ConnectContainerToNetwork(netConnect.Container, name, netOpts) if err != nil { if errors.Cause(err) == define.ErrNoSuchCtr { utils.ContainerNotFound(w, netConnect.Container, err) diff --git a/pkg/api/handlers/libpod/networks.go b/pkg/api/handlers/libpod/networks.go index 1f7f2e26c..a28c3c57c 100644 --- a/pkg/api/handlers/libpod/networks.go +++ b/pkg/api/handlers/libpod/networks.go @@ -125,7 +125,7 @@ func Connect(w http.ResponseWriter, r *http.Request) { return } name := utils.GetName(r) - err := runtime.ConnectContainerToNetwork(netConnect.Container, name, netConnect.Aliases) + err := runtime.ConnectContainerToNetwork(netConnect.Container, name, netConnect.PerNetworkOptions) if err != nil { if errors.Cause(err) == define.ErrNoSuchCtr { utils.ContainerNotFound(w, netConnect.Container, err) -- cgit v1.2.3-54-g00ecf From 46938bbf889de590b00c9be8ea5b4fb86f363519 Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Wed, 8 Dec 2021 18:19:43 +0100 Subject: fix incorrect swagger doc for network dis/connect The swagger api docs used the extra Body struct as part of the request which is wrong. We just want the plain type. Signed-off-by: Paul Holzinger --- pkg/api/handlers/compat/swagger.go | 10 ++++------ pkg/api/handlers/libpod/swagger.go | 6 ++++++ pkg/api/server/register_networks.go | 6 +++--- 3 files changed, 13 insertions(+), 9 deletions(-) (limited to 'pkg/api/handlers') diff --git a/pkg/api/handlers/compat/swagger.go b/pkg/api/handlers/compat/swagger.go index cfbdd1154..32167d6b5 100644 --- a/pkg/api/handlers/compat/swagger.go +++ b/pkg/api/handlers/compat/swagger.go @@ -55,15 +55,13 @@ type swagCompatNetworkCreateResponse struct { } // Network disconnect -// swagger:model NetworkConnectRequest +// swagger:model NetworkCompatConnectRequest type swagCompatNetworkConnectRequest struct { - // in:body - Body struct{ types.NetworkConnect } + types.NetworkConnect } // Network disconnect -// swagger:model NetworkDisconnectRequest +// swagger:model NetworkCompatDisconnectRequest type swagCompatNetworkDisconnectRequest struct { - // in:body - Body struct{ types.NetworkDisconnect } + types.NetworkDisconnect } diff --git a/pkg/api/handlers/libpod/swagger.go b/pkg/api/handlers/libpod/swagger.go index 7ccfdd0f3..8d7058b1e 100644 --- a/pkg/api/handlers/libpod/swagger.go +++ b/pkg/api/handlers/libpod/swagger.go @@ -133,6 +133,12 @@ type swagNetworkPruneResponse struct { Body []entities.NetworkPruneReport } +// Network connect +// swagger:model NetworkConnectRequest +type swagNetworkConnectRequest struct { + entities.NetworkConnectOptions +} + func ServeSwagger(w http.ResponseWriter, r *http.Request) { path := DefaultPodmanSwaggerSpec if p, found := os.LookupEnv("PODMAN_SWAGGER_SPEC"); found { diff --git a/pkg/api/server/register_networks.go b/pkg/api/server/register_networks.go index 641bce333..344486299 100644 --- a/pkg/api/server/register_networks.go +++ b/pkg/api/server/register_networks.go @@ -131,7 +131,7 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // name: create // description: attributes for connecting a container to a network // schema: - // $ref: "#/definitions/NetworkConnectRequest" + // $ref: "#/definitions/NetworkCompatConnectRequest" // responses: // 200: // description: OK @@ -159,7 +159,7 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // name: create // description: attributes for disconnecting a container from a network // schema: - // $ref: "#/definitions/NetworkDisconnectRequest" + // $ref: "#/definitions/NetworkCompatDisconnectRequest" // responses: // 200: // description: OK @@ -368,7 +368,7 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // name: create // description: attributes for disconnecting a container from a network // schema: - // $ref: "#/definitions/NetworkDisconnectRequest" + // $ref: "#/definitions/NetworkCompatDisconnectRequest" // responses: // 200: // description: OK -- cgit v1.2.3-54-g00ecf From 3e9af2029f1f92fbc069f81ba9ca90c090617e9c Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Mon, 13 Dec 2021 15:56:20 +0100 Subject: play kube add support for multiple networks Allow the same --network options for play kube as for podman run/create. Signed-off-by: Paul Holzinger --- cmd/podman/play/kube.go | 2 +- docs/source/markdown/podman-play-kube.1.md | 18 ++++++-- pkg/api/handlers/libpod/play.go | 4 +- pkg/api/server/register_play.go | 6 ++- pkg/bindings/play/types.go | 4 +- pkg/bindings/play/types_kube_options.go | 6 +-- pkg/domain/entities/play.go | 4 +- pkg/domain/infra/abi/play.go | 69 ++++++++++++++++++------------ pkg/domain/infra/tunnel/play.go | 2 +- test/e2e/play_kube_test.go | 35 +++++++++++++++ test/system/700-play.bats | 2 - 11 files changed, 105 insertions(+), 47 deletions(-) (limited to 'pkg/api/handlers') diff --git a/cmd/podman/play/kube.go b/cmd/podman/play/kube.go index 11b5d7d34..ae4066a6f 100644 --- a/cmd/podman/play/kube.go +++ b/cmd/podman/play/kube.go @@ -69,7 +69,7 @@ func init() { _ = kubeCmd.RegisterFlagCompletionFunc(staticMACFlagName, completion.AutocompleteNone) networkFlagName := "network" - flags.StringVar(&kubeOptions.Network, networkFlagName, "", "Connect pod to CNI network(s)") + flags.StringArrayVar(&kubeOptions.Networks, networkFlagName, nil, "Connect pod to network(s) or network mode") _ = kubeCmd.RegisterFlagCompletionFunc(networkFlagName, common.AutocompleteNetworkFlag) staticIPFlagName := "ip" diff --git a/docs/source/markdown/podman-play-kube.1.md b/docs/source/markdown/podman-play-kube.1.md index 075fbbe81..81ab65176 100644 --- a/docs/source/markdown/podman-play-kube.1.md +++ b/docs/source/markdown/podman-play-kube.1.md @@ -142,6 +142,7 @@ removed. Any volumes created are left intact. #### **--ip**=*IP address* Assign a static ip address to the pod. This option can be specified several times when play kube creates more than one pod. +Note: When joining multiple networks you should use the **--network name:ip=\** syntax. #### **--log-driver**=driver @@ -167,15 +168,24 @@ This option is currently supported only by the **journald** log driver. #### **--mac-address**=*MAC address* Assign a static mac address to the pod. This option can be specified several times when play kube creates more than one pod. +Note: When joining multiple networks you should use the **--network name:mac=\** syntax. #### **--network**=*mode*, **--net** -Change the network mode of the pod. The host and bridge network mode should be configured in the yaml file. +Change the network mode of the pod. The host network mode should be configured in the YAML file. Valid _mode_ values are: +- **bridge[:OPTIONS,...]**: Create a network stack on the default bridge. This is the default for rootfull containers. It is possible to specify these additional options: + - **alias=name**: Add network-scoped alias for the container. + - **ip=IPv4**: Specify a static ipv4 address for this container. + - **ip=IPv6**: Specify a static ipv6 address for this container. + - **mac=MAC**: Specify a static mac address address for this container. + - **interface_name**: Specify a name for the created network interface inside the container. + + For example to set a static ipv4 address and a static mac address, use `--network bridge:ip=10.88.0.10,mac=44:33:22:11:00:99`. +- \[:OPTIONS,...]: Connect to a user-defined network; this is the network name or ID from a network created by **[podman network create](podman-network-create.1.md)**. Using the network name implies the bridge network mode. It is possible to specify the same options described under the bridge mode above. You can use the **--network** option multiple times to specify additional networks. - **none**: Create a network namespace for the container but do not configure network interfaces for it, thus the container has no network connectivity. - **container:**_id_: Reuse another container's network stack. -- **network**: Connect to a user-defined network, multiple networks should be comma-separated. - **ns:**_path_: Path to a network namespace to join. - **private**: Create a new namespace for the container. This will use the **bridge** mode for rootfull containers and **slirp4netns** for rootless ones. - **slirp4netns[:OPTIONS,...]**: use **slirp4netns**(1) to create a user network stack. This is the default for rootless containers. It is possible to specify these additional options: @@ -253,9 +263,9 @@ $ podman play kube demo.yml --configmap configmap-foo.yml --configmap configmap- 52182811df2b1e73f36476003a66ec872101ea59034ac0d4d3a7b40903b955a6 ``` -CNI network(s) can be specified as comma-separated list using ``--network`` +Create a pod connected to two networks (called net1 and net2) with a static ip ``` -$ podman play kube demo.yml --network cni1,cni2 +$ podman play kube demo.yml --network net1:ip=10.89.1.5 --network net2:ip=10.89.10.10 52182811df2b1e73f36476003a66ec872101ea59034ac0d4d3a7b40903b955a6 ``` diff --git a/pkg/api/handlers/libpod/play.go b/pkg/api/handlers/libpod/play.go index f943fc240..312aa32de 100644 --- a/pkg/api/handlers/libpod/play.go +++ b/pkg/api/handlers/libpod/play.go @@ -23,7 +23,7 @@ func PlayKube(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder) query := struct { - Network string `schema:"network"` + Network []string `schema:"network"` TLSVerify bool `schema:"tlsVerify"` LogDriver string `schema:"logDriver"` LogOptions []string `schema:"logOptions"` @@ -103,7 +103,7 @@ func PlayKube(w http.ResponseWriter, r *http.Request) { Authfile: authfile, Username: username, Password: password, - Network: query.Network, + Networks: query.Network, NoHosts: query.NoHosts, Quiet: true, LogDriver: query.LogDriver, diff --git a/pkg/api/server/register_play.go b/pkg/api/server/register_play.go index 915d0d02e..5ace01929 100644 --- a/pkg/api/server/register_play.go +++ b/pkg/api/server/register_play.go @@ -18,8 +18,10 @@ func (s *APIServer) registerPlayHandlers(r *mux.Router) error { // parameters: // - in: query // name: network - // type: string - // description: Connect the pod to this network. + // type: array + // description: USe the network mode or specify an array of networks. + // items: + // type: string // - in: query // name: tlsVerify // type: boolean diff --git a/pkg/bindings/play/types.go b/pkg/bindings/play/types.go index 011f7f9ca..ca639e46b 100644 --- a/pkg/bindings/play/types.go +++ b/pkg/bindings/play/types.go @@ -15,8 +15,8 @@ type KubeOptions struct { Username *string // Password for authenticating against the registry. Password *string - // Network - name of the CNI network to connect to. - Network *string + // Network - name of the networks to connect to. + Network *[]string // NoHosts - do not generate /etc/hosts file in pod's containers NoHosts *bool // Quiet - suppress output when pulling images. diff --git a/pkg/bindings/play/types_kube_options.go b/pkg/bindings/play/types_kube_options.go index 344771e0c..593f026a3 100644 --- a/pkg/bindings/play/types_kube_options.go +++ b/pkg/bindings/play/types_kube_options.go @@ -79,15 +79,15 @@ func (o *KubeOptions) GetPassword() string { } // WithNetwork set field Network to given value -func (o *KubeOptions) WithNetwork(value string) *KubeOptions { +func (o *KubeOptions) WithNetwork(value []string) *KubeOptions { o.Network = &value return o } // GetNetwork returns value of field Network -func (o *KubeOptions) GetNetwork() string { +func (o *KubeOptions) GetNetwork() []string { if o.Network == nil { - var z string + var z []string return z } return *o.Network diff --git a/pkg/domain/entities/play.go b/pkg/domain/entities/play.go index ad35dfe25..39234caf8 100644 --- a/pkg/domain/entities/play.go +++ b/pkg/domain/entities/play.go @@ -26,8 +26,8 @@ type PlayKubeOptions struct { Username string // Password for authenticating against the registry. Password string - // Network - name of the CNI network to connect to. - Network string + // Networks - name of the network to connect to. + Networks []string // Quiet - suppress output when pulling images. Quiet bool // SignaturePolicy - path to a signature-policy file. diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index 409ba938a..6b3b04a0b 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -17,6 +17,7 @@ import ( "github.com/containers/image/v5/types" "github.com/containers/podman/v3/libpod" "github.com/containers/podman/v3/libpod/define" + nettypes "github.com/containers/podman/v3/libpod/network/types" "github.com/containers/podman/v3/pkg/autoupdate" "github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/specgen" @@ -195,39 +196,51 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY return nil, err } - if options.Network != "" { - ns, networks, netOpts, err := specgen.ParseNetworkFlag([]string{options.Network}) - if err != nil { - return nil, err - } + ns, networks, netOpts, err := specgen.ParseNetworkFlag(options.Networks) + if err != nil { + return nil, err + } - if (ns.IsBridge() && len(networks) == 0) || ns.IsHost() { - return nil, errors.Errorf("invalid value passed to --network: bridge or host networking must be configured in YAML") - } + if (ns.IsBridge() && len(networks) == 0) || ns.IsHost() { + return nil, errors.Errorf("invalid value passed to --network: bridge or host networking must be configured in YAML") + } - podOpt.Net.Network = ns - if len(networks) > 0 { - podOpt.Net.Networks = networks + podOpt.Net.Network = ns + podOpt.Net.Networks = networks + podOpt.Net.NetworkOptions = netOpts + + // FIXME This is very hard to support properly with a good ux + if len(options.StaticIPs) > *ipIndex { + if !podOpt.Net.Network.IsBridge() { + errors.Wrap(define.ErrInvalidArg, "static ip addresses can only be set when the network mode is bridge") + } + if len(podOpt.Net.Networks) != 1 { + return nil, errors.Wrap(define.ErrInvalidArg, "cannot set static ip addresses for more than network, use netname:ip= syntax to specify ips for more than network") } - if len(netOpts) > 0 { - podOpt.Net.NetworkOptions = netOpts + for name, netOpts := range podOpt.Net.Networks { + netOpts.StaticIPs = append(netOpts.StaticIPs, options.StaticIPs[*ipIndex]) + podOpt.Net.Networks[name] = netOpts } + } else if len(options.StaticIPs) > 0 { + // only warn if the user has set at least one ip + logrus.Warn("No more static ips left using a random one") } - - // FIXME This is very hard to support properly - // if len(options.StaticIPs) > *ipIndex { - // podOpt.Net.StaticIP = &options.StaticIPs[*ipIndex] - // } else if len(options.StaticIPs) > 0 { - // // only warn if the user has set at least one ip - // logrus.Warn("No more static ips left using a random one") - // } - // if len(options.StaticMACs) > *ipIndex { - // podOpt.Net.StaticMAC = &options.StaticMACs[*ipIndex] - // } else if len(options.StaticIPs) > 0 { - // // only warn if the user has set at least one mac - // logrus.Warn("No more static macs left using a random one") - // } - // *ipIndex++ + if len(options.StaticMACs) > *ipIndex { + if !podOpt.Net.Network.IsBridge() { + errors.Wrap(define.ErrInvalidArg, "static mac address can only be set when the network mode is bridge") + } + if len(podOpt.Net.Networks) != 1 { + return nil, errors.Wrap(define.ErrInvalidArg, "cannot set static mac address for more than network, use netname:mac= syntax to specify mac for more than network") + } + for name, netOpts := range podOpt.Net.Networks { + netOpts.StaticMAC = nettypes.HardwareAddr(options.StaticMACs[*ipIndex]) + podOpt.Net.Networks[name] = netOpts + } + } else if len(options.StaticIPs) > 0 { + // only warn if the user has set at least one mac + logrus.Warn("No more static macs left using a random one") + } + *ipIndex++ p := specgen.NewPodSpecGenerator() if err != nil { diff --git a/pkg/domain/infra/tunnel/play.go b/pkg/domain/infra/tunnel/play.go index 75952ce2c..103be0cf1 100644 --- a/pkg/domain/infra/tunnel/play.go +++ b/pkg/domain/infra/tunnel/play.go @@ -11,7 +11,7 @@ import ( func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, opts entities.PlayKubeOptions) (*entities.PlayKubeReport, error) { options := new(play.KubeOptions).WithAuthfile(opts.Authfile).WithUsername(opts.Username).WithPassword(opts.Password) options.WithCertDir(opts.CertDir).WithQuiet(opts.Quiet).WithSignaturePolicy(opts.SignaturePolicy).WithConfigMaps(opts.ConfigMaps) - options.WithLogDriver(opts.LogDriver).WithNetwork(opts.Network).WithSeccompProfileRoot(opts.SeccompProfileRoot) + options.WithLogDriver(opts.LogDriver).WithNetwork(opts.Networks).WithSeccompProfileRoot(opts.SeccompProfileRoot) options.WithStaticIPs(opts.StaticIPs).WithStaticMACs(opts.StaticMACs) if len(opts.LogOptions) > 0 { options.WithLogOptions(opts.LogOptions) diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index 36010704f..f79710ee6 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -2136,6 +2136,41 @@ spec: } }) + It("podman play kube with multiple networks", func() { + ctr := getCtr(withImage(ALPINE)) + pod := getPod(withCtr(ctr)) + err := generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + net1 := "net1" + stringid.GenerateNonCryptoID() + net2 := "net2" + stringid.GenerateNonCryptoID() + + net := podmanTest.Podman([]string{"network", "create", "--subnet", "10.0.11.0/24", net1}) + net.WaitWithDefaultTimeout() + defer podmanTest.removeCNINetwork(net1) + Expect(net).Should(Exit(0)) + + net = podmanTest.Podman([]string{"network", "create", "--subnet", "10.0.12.0/24", net2}) + net.WaitWithDefaultTimeout() + defer podmanTest.removeCNINetwork(net2) + Expect(net).Should(Exit(0)) + + ip1 := "10.0.11.5" + ip2 := "10.0.12.10" + + kube := podmanTest.Podman([]string{"play", "kube", "--network", net1 + ":ip=" + ip1, "--network", net2 + ":ip=" + ip2, kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(0)) + + inspect := podmanTest.Podman([]string{"exec", getCtrNameInPod(pod), "ip", "addr"}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) + Expect(inspect.OutputToString()).To(ContainSubstring(ip1)) + Expect(inspect.OutputToString()).To(ContainSubstring(ip2)) + Expect(inspect.OutputToString()).To(ContainSubstring("eth0")) + Expect(inspect.OutputToString()).To(ContainSubstring("eth1")) + }) + It("podman play kube test with network portbindings", func() { ip := "127.0.0.100" port := "5000" diff --git a/test/system/700-play.bats b/test/system/700-play.bats index b77d41920..88c7cad87 100644 --- a/test/system/700-play.bats +++ b/test/system/700-play.bats @@ -104,8 +104,6 @@ RELABEL="system_u:object_r:container_file_t:s0" TESTDIR=$PODMAN_TMPDIR/testdir mkdir -p $TESTDIR echo "$testYaml" | sed "s|TESTDIR|${TESTDIR}|g" > $PODMAN_TMPDIR/test.yaml - run_podman 125 play kube --network bridge $PODMAN_TMPDIR/test.yaml - is "$output" ".*invalid value passed to --network: bridge or host networking must be configured in YAML" "podman plan-network should fail with --network host" run_podman 125 play kube --network host $PODMAN_TMPDIR/test.yaml is "$output" ".*invalid value passed to --network: bridge or host networking must be configured in YAML" "podman plan-network should fail with --network host" run_podman play kube --network slirp4netns:port_handler=slirp4netns $PODMAN_TMPDIR/test.yaml -- cgit v1.2.3-54-g00ecf