From 85e8fbf7f33717ef6a0d6cf9e2143b52c874c2de Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Mon, 16 Aug 2021 16:11:26 +0200 Subject: Wire network interface into libpod Make use of the new network interface in libpod. This commit contains several breaking changes: - podman network create only outputs the new network name and not file path. - podman network ls shows the network driver instead of the cni version and plugins. - podman network inspect outputs the new network struct and not the cni conflist. - The bindings and libpod api endpoints have been changed to use the new network structure. The container network status is stored in a new field in the state. The status should be received with the new `c.getNetworkStatus`. This will migrate the old status to the new format. Therefore old containers should contine to work correctly in all cases even when network connect/ disconnect is used. New features: - podman network reload keeps the ip and mac for more than one network. - podman container restore keeps the ip and mac for more than one network. - The network create compat endpoint can now use more than one ipam config. The man pages and the swagger doc are updated to reflect the latest changes. Signed-off-by: Paul Holzinger --- test/apiv2/35-networks.at | 70 +++++++------ test/e2e/inspect_test.go | 4 +- test/e2e/network_create_test.go | 218 +++++++++++----------------------------- test/e2e/network_test.go | 75 +++++++------- test/system/500-networking.bats | 73 +++++++++----- 5 files changed, 190 insertions(+), 250 deletions(-) (limited to 'test') diff --git a/test/apiv2/35-networks.at b/test/apiv2/35-networks.at index 7a36b605f..a4cb5a480 100644 --- a/test/apiv2/35-networks.at +++ b/test/apiv2/35-networks.at @@ -6,42 +6,52 @@ t GET networks/non-existing-network 404 \ .cause='network not found' -t POST libpod/networks/create?name=network1 200 \ - .Filename~.*/network1\\.conflist - -# --data '{"Subnet":{"IP":"10.10.254.0","Mask":[255,255,255,0]},"Labels":{"abc":"val"}}' -t POST libpod/networks/create?name=network2 \ - Subnet='{"IP":"10.10.254.0","Mask":[255,255,255,0]}' \ - Labels='{"abc":"val"}' \ +t POST libpod/networks/create name='"network1"' 200 \ + .name=network1 + .created~[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}.* \ + +# --data '{"name":"network2","subnets":[{"subnet":"10.10.254.0/24"}],"Labels":{"abc":"val"}}' +t POST libpod/networks/create name='"network2"' \ + subnets='[{"subnet":"10.10.254.0/24"}]' \ + labels='{"abc":"val"}' \ 200 \ - .Filename~.*/network2\\.conflist - -# --data '{"Subnet":{"IP":"10.10.133.0","Mask":[255,255,255,0]},"Labels":{"xyz":"val"}}' -t POST libpod/networks/create?name=network3 \ - Subnet='{"IP":"10.10.133.0","Mask":[255,255,255,0]}' \ - Labels='{"xyz":"val"}' \ + .name=network2 \ + .subnets[0].subnet=10.10.254.0/24 \ + .subnets[0].gateway=10.10.254.1 \ + .labels.abc=val + +# --data '{"name":"network3","subnets":[{"subnet":"10.10.133.0/24"}],"Labels":{"xyz":"val"}}' +t POST libpod/networks/create name="network3" \ + subnets='[{"subnet":"10.10.133.0/24"}]' \ + labels='{"xyz":"val"}' \ 200 \ - .Filename~.*/network3\\.conflist - -# --data '{"Subnet":{"IP":"10.10.134.0","Mask":[255,255,255,0]},"Labels":{"zaq":"val"}}' -t POST libpod/networks/create?name=network4 \ - Subnet='{"IP":"10.10.134.0","Mask":[255,255,255,0]}' \ - Labels='{"zaq":"val"}' \ + .name=network3 \ + .subnets[0].subnet=10.10.133.0/24 \ + .subnets[0].gateway=10.10.133.1 \ + .labels.xyz=val + +# --data '{"name":"network4","subnets":[{"subnet":"10.10.134.0/24"}],"Labels":{"zaq":"val"}}' +t POST libpod/networks/create name="network4" \ + subnets='[{"subnet":"10.10.134.0/24"}]' \ + labels='{"zaq":"val"}' \ 200 \ - .Filename~.*/network4\\.conflist + .name=network4 \ + .subnets[0].subnet=10.10.134.0/24 \ + .subnets[0].gateway=10.10.134.1 \ + .labels.zaq=val # test for empty mask -t POST libpod/networks/create Subnet='{"IP":"10.10.1.0","Mask":[]}' 500 \ - .cause~'.*cannot be empty' +t POST libpod/networks/create subnets='[{"subnet":"10.10.134.0"}]' 500 \ + .cause~'.*invalid CIDR address: 10.10.134.0' # test for invalid mask -t POST libpod/networks/create Subnet='{"IP":"10.10.1.0","Mask":[0,255,255,0]}' 500 \ - .cause~'.*mask is invalid' +t POST libpod/networks/create subnets='[{"subnet":"10.10.134.0/65"}]' 500 \ + .cause~'.*invalid CIDR address: 10.10.134.0/65' # network list t GET libpod/networks/json 200 t GET libpod/networks/json?filters='{"name":["network1"]}' 200 \ length=1 \ - .[0].Name=network1 + .[0].name=network1 t GET networks 200 #inspect network @@ -121,7 +131,8 @@ t DELETE libpod/networks/network2 200 \ .[0].Err=null # test until filter - libpod api -podman network create network5 --label xyz +t POST libpod/networks/create name='"network5"' labels='{"xyz":""}' 200 \ + .name=network5 # with date way back in the past, network should not be deleted t POST libpod/networks/prune?filters='{"until":["500000"]}' 200 @@ -132,7 +143,8 @@ t POST libpod/networks/prune?filters='{"until":["5000000000"]}' 200 t GET libpod/networks/json?filters='{"label":["xyz"]}' 200 length=0 # test until filter - compat api -podman network create network6 --label zaq +t POST networks/create Name='"network6"' Labels='{"zaq":""}' 201 \ + .Id~[0-9a-f]\\{64\\} # with date way back in the past, network should not be deleted t POST networks/prune?filters='{"until":["500000"]}' 200 @@ -143,7 +155,9 @@ t POST networks/prune?filters='{"until":["5000000000"]}' 200 t GET networks?filters='{"label":["zaq"]}' 200 length=0 # test macvlan network response -podman network create --driver macvlan macvlan1 +t POST libpod/networks/create name='"macvlan1"' driver="macvlan" 200 \ + .name=macvlan1 \ + .driver=macvlan # libpod api inspect the macvlan network t GET libpod/networks/macvlan1/json 200 .name="macvlan1" diff --git a/test/e2e/inspect_test.go b/test/e2e/inspect_test.go index 59615d009..12165d92d 100644 --- a/test/e2e/inspect_test.go +++ b/test/e2e/inspect_test.go @@ -374,10 +374,10 @@ var _ = Describe("Podman inspect", func() { name, path := generateNetworkConfig(podmanTest) defer removeConf(path) - session := podmanTest.Podman([]string{"inspect", name, "--format", "{{.cniVersion}}"}) + session := podmanTest.Podman([]string{"inspect", name, "--format", "{{.Driver}}"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - Expect(session.LineInOutputContains("0.3.0")).To(BeTrue()) + Expect(session.OutputToString()).To(ContainSubstring("bridge")) }) It("podman inspect a volume", func() { diff --git a/test/e2e/network_create_test.go b/test/e2e/network_create_test.go index fb4a144fa..585f52b8a 100644 --- a/test/e2e/network_create_test.go +++ b/test/e2e/network_create_test.go @@ -2,61 +2,17 @@ package integration import ( "encoding/json" - "io/ioutil" "net" "os" - "strings" - cniversion "github.com/containernetworking/cni/pkg/version" - "github.com/containers/podman/v3/libpod/network" + "github.com/containers/podman/v3/libpod/network/types" . "github.com/containers/podman/v3/test/utils" "github.com/containers/storage/pkg/stringid" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/gexec" - "github.com/pkg/errors" ) -var ErrPluginNotFound = errors.New("plugin not found") - -func findPluginByName(plugins interface{}, pluginType string) (interface{}, error) { - for _, p := range plugins.([]interface{}) { - r := p.(map[string]interface{}) - if pluginType == r["type"] { - return p, nil - } - } - return nil, errors.Wrap(ErrPluginNotFound, pluginType) -} - -func genericPluginsToBridge(plugins interface{}, pluginType string) (network.HostLocalBridge, error) { - var bridge network.HostLocalBridge - generic, err := findPluginByName(plugins, pluginType) - if err != nil { - return bridge, err - } - b, err := json.Marshal(generic) - if err != nil { - return bridge, err - } - err = json.Unmarshal(b, &bridge) - return bridge, err -} - -func genericPluginsToPortMap(plugins interface{}, pluginType string) (network.PortMapConfig, error) { - var portMap network.PortMapConfig - generic, err := findPluginByName(plugins, "portmap") - if err != nil { - return portMap, err - } - b, err := json.Marshal(generic) - if err != nil { - return portMap, err - } - err = json.Unmarshal(b, &portMap) - return portMap, err -} - func removeNetworkDevice(name string) { session := SystemExec("ip", []string{"link", "delete", name}) session.WaitWithDefaultTimeout() @@ -85,59 +41,7 @@ var _ = Describe("Podman network create", func() { processTestResult(f) }) - It("podman network create with no input", func() { - var result network.NcList - - nc := podmanTest.Podman([]string{"network", "create"}) - nc.WaitWithDefaultTimeout() - Expect(nc).Should(Exit(0)) - - fileContent, err := ioutil.ReadFile(nc.OutputToString()) - Expect(err).To(BeNil()) - err = json.Unmarshal(fileContent, &result) - Expect(err).To(BeNil()) - defer podmanTest.removeCNINetwork(result["name"].(string)) - Expect(result["cniVersion"]).To(Equal(cniversion.Current())) - Expect(strings.HasPrefix(result["name"].(string), "cni-podman")).To(BeTrue()) - - bridgePlugin, err := genericPluginsToBridge(result["plugins"], "bridge") - Expect(err).To(BeNil()) - portMapPlugin, err := genericPluginsToPortMap(result["plugins"], "portmap") - Expect(err).To(BeNil()) - - Expect(bridgePlugin.IPAM.Routes[0].Dest).To(Equal("0.0.0.0/0")) - Expect(bridgePlugin.IsGW).To(BeTrue()) - Expect(bridgePlugin.IPMasq).To(BeTrue()) - Expect(bridgePlugin.IPAM.Ranges[0][0].Gateway).ToNot(BeEmpty()) - Expect(portMapPlugin.Capabilities["portMappings"]).To(BeTrue()) - - }) - - It("podman network create with name", func() { - var ( - results []network.NcList - ) - - netName := "inspectnet-" + stringid.GenerateNonCryptoID() - nc := podmanTest.Podman([]string{"network", "create", netName}) - nc.WaitWithDefaultTimeout() - defer podmanTest.removeCNINetwork(netName) - Expect(nc).Should(Exit(0)) - - inspect := podmanTest.Podman([]string{"network", "inspect", netName}) - inspect.WaitWithDefaultTimeout() - - err := json.Unmarshal([]byte(inspect.OutputToString()), &results) - Expect(err).To(BeNil()) - result := results[0] - Expect(result["name"]).To(Equal(netName)) - - }) - It("podman network create with name and subnet", func() { - var ( - results []network.NcList - ) netName := "subnet-" + stringid.GenerateNonCryptoID() nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.12.0/24", netName}) nc.WaitWithDefaultTimeout() @@ -147,25 +51,25 @@ var _ = Describe("Podman network create", func() { // Inspect the network configuration inspect := podmanTest.Podman([]string{"network", "inspect", netName}) inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) // JSON the network configuration into something usable + var results []types.Network err := json.Unmarshal([]byte(inspect.OutputToString()), &results) Expect(err).To(BeNil()) + Expect(results).To(HaveLen(1)) result := results[0] - Expect(result["name"]).To(Equal(netName)) - - // JSON the bridge info - bridgePlugin, err := genericPluginsToBridge(result["plugins"], "bridge") - Expect(err).To(BeNil()) - // check that gateway is added to config - Expect(bridgePlugin.IPAM.Ranges[0][0].Gateway).To(Equal("10.11.12.1")) + Expect(result.Name).To(Equal(netName)) + Expect(result.Subnets).To(HaveLen(1)) + Expect(result.Subnets[0].Gateway.String()).To(Equal("10.11.12.1")) // Once a container executes a new network, the nic will be created. We should clean those up // best we can - defer removeNetworkDevice(bridgePlugin.BrName) + defer removeNetworkDevice(result.NetworkInterface) try := podmanTest.Podman([]string{"run", "-it", "--rm", "--network", netName, ALPINE, "sh", "-c", "ip addr show eth0 | awk ' /inet / {print $2}'"}) try.WaitWithDefaultTimeout() + Expect(try).To(Exit(0)) _, subnet, err := net.ParseCIDR("10.11.12.0/24") Expect(err).To(BeNil()) @@ -178,9 +82,6 @@ var _ = Describe("Podman network create", func() { It("podman network create with name and IPv6 subnet", func() { SkipIfRootless("FIXME It needs the ip6tables modules loaded") - var ( - results []network.NcList - ) netName := "ipv6-" + stringid.GenerateNonCryptoID() nc := podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:1:2:3:4::/64", netName}) nc.WaitWithDefaultTimeout() @@ -190,24 +91,26 @@ var _ = Describe("Podman network create", func() { // Inspect the network configuration inspect := podmanTest.Podman([]string{"network", "inspect", netName}) inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) // JSON the network configuration into something usable + var results []types.Network err := json.Unmarshal([]byte(inspect.OutputToString()), &results) Expect(err).To(BeNil()) + Expect(results).To(HaveLen(1)) result := results[0] - Expect(result["name"]).To(Equal(netName)) - - // JSON the bridge info - bridgePlugin, err := genericPluginsToBridge(result["plugins"], "bridge") - Expect(err).To(BeNil()) - Expect(bridgePlugin.IPAM.Routes[0].Dest).To(Equal("::/0")) + Expect(result.Name).To(Equal(netName)) + Expect(result.Subnets).To(HaveLen(1)) + Expect(result.Subnets[0].Gateway.String()).To(Equal("fd00:1:2:3::1")) + Expect(result.Subnets[0].Subnet.String()).To(Equal("fd00:1:2:3::/64")) // Once a container executes a new network, the nic will be created. We should clean those up // best we can - defer removeNetworkDevice(bridgePlugin.BrName) + defer removeNetworkDevice(result.NetworkInterface) try := podmanTest.Podman([]string{"run", "-it", "--rm", "--network", netName, ALPINE, "sh", "-c", "ip addr show eth0 | grep global | awk ' /inet6 / {print $2}'"}) try.WaitWithDefaultTimeout() + Expect(try).To(Exit(0)) _, subnet, err := net.ParseCIDR("fd00:1:2:3:4::/64") Expect(err).To(BeNil()) @@ -219,11 +122,8 @@ var _ = Describe("Podman network create", func() { It("podman network create with name and IPv6 flag (dual-stack)", func() { SkipIfRootless("FIXME It needs the ip6tables modules loaded") - var ( - results []network.NcList - ) netName := "dual-" + stringid.GenerateNonCryptoID() - nc := podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:4:3:2:1::/64", "--ipv6", netName}) + nc := podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:4:3:2::/64", "--ipv6", netName}) nc.WaitWithDefaultTimeout() defer podmanTest.removeCNINetwork(netName) Expect(nc).Should(Exit(0)) @@ -231,38 +131,32 @@ var _ = Describe("Podman network create", func() { // Inspect the network configuration inspect := podmanTest.Podman([]string{"network", "inspect", netName}) inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) // JSON the network configuration into something usable + var results []types.Network err := json.Unmarshal([]byte(inspect.OutputToString()), &results) Expect(err).To(BeNil()) + Expect(results).To(HaveLen(1)) result := results[0] - Expect(result["name"]).To(Equal(netName)) - - // JSON the bridge info - bridgePlugin, err := genericPluginsToBridge(result["plugins"], "bridge") - Expect(err).To(BeNil()) - Expect(bridgePlugin.IPAM.Routes[0].Dest).To(Equal("::/0")) - Expect(bridgePlugin.IPAM.Routes[1].Dest).To(Equal("0.0.0.0/0")) - - Expect(bridgePlugin.IPAM.Ranges).To(HaveLen(2)) - Expect(bridgePlugin.IPAM.Ranges[0]).To(HaveLen(1)) - Expect(bridgePlugin.IPAM.Ranges[0][0].Subnet).ToNot(BeEmpty()) - Expect(bridgePlugin.IPAM.Ranges[1]).To(HaveLen(1)) - Expect(bridgePlugin.IPAM.Ranges[1][0].Subnet).ToNot(BeEmpty()) + Expect(result.Name).To(Equal(netName)) + Expect(result.Subnets).To(HaveLen(2)) + Expect(result.Subnets[0].Subnet.IP).ToNot(BeNil()) + Expect(result.Subnets[1].Subnet.IP).ToNot(BeNil()) - _, subnet11, err := net.ParseCIDR(bridgePlugin.IPAM.Ranges[0][0].Subnet) + _, subnet11, err := net.ParseCIDR(result.Subnets[0].Subnet.String()) Expect(err).To(BeNil()) - _, subnet12, err := net.ParseCIDR(bridgePlugin.IPAM.Ranges[1][0].Subnet) + _, subnet12, err := net.ParseCIDR(result.Subnets[1].Subnet.String()) Expect(err).To(BeNil()) // Once a container executes a new network, the nic will be created. We should clean those up // best we can - defer removeNetworkDevice(bridgePlugin.BrName) + defer removeNetworkDevice(result.NetworkInterface) // create a second network to check the auto assigned ipv4 subnet does not overlap // https://github.com/containers/podman/issues/11032 netName2 := "dual-" + stringid.GenerateNonCryptoID() - nc = podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:6:3:2:1::/64", "--ipv6", netName2}) + nc = podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:10:3:2::/64", "--ipv6", netName2}) nc.WaitWithDefaultTimeout() defer podmanTest.removeCNINetwork(netName2) Expect(nc).Should(Exit(0)) @@ -270,27 +164,21 @@ var _ = Describe("Podman network create", func() { // Inspect the network configuration inspect = podmanTest.Podman([]string{"network", "inspect", netName2}) inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) // JSON the network configuration into something usable err = json.Unmarshal([]byte(inspect.OutputToString()), &results) Expect(err).To(BeNil()) + Expect(results).To(HaveLen(1)) result = results[0] - Expect(result["name"]).To(Equal(netName2)) + Expect(result.Name).To(Equal(netName2)) + Expect(result.Subnets).To(HaveLen(2)) + Expect(result.Subnets[0].Subnet.IP).ToNot(BeNil()) + Expect(result.Subnets[1].Subnet.IP).ToNot(BeNil()) - // JSON the bridge info - bridgePlugin, err = genericPluginsToBridge(result["plugins"], "bridge") - Expect(err).To(BeNil()) - Expect(bridgePlugin.IPAM.Routes[0].Dest).To(Equal("::/0")) - Expect(bridgePlugin.IPAM.Routes[1].Dest).To(Equal("0.0.0.0/0")) - Expect(bridgePlugin.IPAM.Ranges).To(HaveLen(2)) - Expect(bridgePlugin.IPAM.Ranges[0]).To(HaveLen(1)) - Expect(bridgePlugin.IPAM.Ranges[0][0].Subnet).ToNot(BeEmpty()) - Expect(bridgePlugin.IPAM.Ranges[1]).To(HaveLen(1)) - Expect(bridgePlugin.IPAM.Ranges[1][0].Subnet).ToNot(BeEmpty()) - - _, subnet21, err := net.ParseCIDR(bridgePlugin.IPAM.Ranges[0][0].Subnet) + _, subnet21, err := net.ParseCIDR(result.Subnets[0].Subnet.String()) Expect(err).To(BeNil()) - _, subnet22, err := net.ParseCIDR(bridgePlugin.IPAM.Ranges[1][0].Subnet) + _, subnet22, err := net.ParseCIDR(result.Subnets[1].Subnet.String()) Expect(err).To(BeNil()) // check that the subnets do not overlap @@ -321,15 +209,31 @@ var _ = Describe("Podman network create", func() { }) It("podman network create with ipv4 subnet and ipv6 flag", func() { - nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.12.0/24", "--ipv6", stringid.GenerateNonCryptoID()}) + name := stringid.GenerateNonCryptoID() + nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.12.0/24", "--ipv6", name}) nc.WaitWithDefaultTimeout() - Expect(nc).To(ExitWithError()) + Expect(nc).To(Exit(0)) + defer podmanTest.removeCNINetwork(name) + + nc = podmanTest.Podman([]string{"network", "inspect", name}) + nc.WaitWithDefaultTimeout() + Expect(nc).To(Exit(0)) + Expect(nc.OutputToString()).To(ContainSubstring(`::/64`)) + Expect(nc.OutputToString()).To(ContainSubstring(`10.11.12.0/24`)) }) It("podman network create with empty subnet and ipv6 flag", func() { - nc := podmanTest.Podman([]string{"network", "create", "--ipv6", stringid.GenerateNonCryptoID()}) + name := stringid.GenerateNonCryptoID() + nc := podmanTest.Podman([]string{"network", "create", "--ipv6", name}) nc.WaitWithDefaultTimeout() - Expect(nc).To(ExitWithError()) + Expect(nc).To(Exit(0)) + defer podmanTest.removeCNINetwork(name) + + nc = podmanTest.Podman([]string{"network", "inspect", name}) + nc.WaitWithDefaultTimeout() + Expect(nc).To(Exit(0)) + Expect(nc.OutputToString()).To(ContainSubstring(`::/64`)) + Expect(nc.OutputToString()).To(ContainSubstring(`.0/24`)) }) It("podman network create with invalid IP", func() { @@ -401,7 +305,7 @@ var _ = Describe("Podman network create", func() { nc = podmanTest.Podman([]string{"network", "inspect", net}) nc.WaitWithDefaultTimeout() Expect(nc).Should(Exit(0)) - Expect(nc.OutputToString()).To(ContainSubstring(`"mtu": 9000,`)) + Expect(nc.OutputToString()).To(ContainSubstring(`"mtu": "9000"`)) }) It("podman network create with vlan option", func() { @@ -414,7 +318,7 @@ var _ = Describe("Podman network create", func() { nc = podmanTest.Podman([]string{"network", "inspect", net}) nc.WaitWithDefaultTimeout() Expect(nc).Should(Exit(0)) - Expect(nc.OutputToString()).To(ContainSubstring(`"vlan": 9`)) + Expect(nc.OutputToString()).To(ContainSubstring(`"vlan": "9"`)) }) It("podman network create with invalid option", func() { @@ -434,7 +338,7 @@ var _ = Describe("Podman network create", func() { // Not performing this check on remote tests because it is a logrus error which does // not come back via stderr on the remote client. if !IsRemote() { - Expect(nc.ErrorToString()).To(ContainSubstring("dnsname and --internal networks are incompatible")) + Expect(nc.ErrorToString()).To(ContainSubstring("dnsname and internal networks are incompatible")) } nc = podmanTest.Podman([]string{"network", "inspect", net}) nc.WaitWithDefaultTimeout() diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go index 1959ed555..7e56b8a25 100644 --- a/test/e2e/network_test.go +++ b/test/e2e/network_test.go @@ -1,11 +1,13 @@ package integration import ( + "encoding/json" "fmt" "os" "strings" "time" + "github.com/containers/podman/v3/libpod/network/types" "github.com/containers/podman/v3/pkg/rootless" . "github.com/containers/podman/v3/test/utils" "github.com/containers/storage/pkg/stringid" @@ -61,17 +63,17 @@ var _ = Describe("Podman network", func() { name, path := generateNetworkConfig(podmanTest) defer removeConf(path) - session := podmanTest.Podman([]string{"network", "ls", "--filter", "plugin=bridge"}) + session := podmanTest.Podman([]string{"network", "ls", "--filter", "driver=bridge"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) Expect(session.LineInOutputContains(name)).To(BeTrue()) }) - It("podman network list --filter plugin and name", func() { + It("podman network list --filter driver and name", func() { name, path := generateNetworkConfig(podmanTest) defer removeConf(path) - session := podmanTest.Podman([]string{"network", "ls", "--filter", "plugin=bridge", "--filter", "name=" + name}) + session := podmanTest.Podman([]string{"network", "ls", "--filter", "driver=bridge", "--filter", "name=" + name}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) Expect(session.OutputToString()).To(ContainSubstring(name)) @@ -136,7 +138,7 @@ var _ = Describe("Podman network", func() { name, path := generateNetworkConfig(podmanTest) defer removeConf(path) - session := podmanTest.Podman([]string{"network", "ls", "--filter", "plugin=test"}) + session := podmanTest.Podman([]string{"network", "ls", "--filter", "label=abc"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) Expect(session.LineInOutputContains(name)).To(BeFalse()) @@ -155,7 +157,7 @@ var _ = Describe("Podman network", func() { session = podmanTest.Podman([]string{"network", "ls", "--filter", "id=" + netID}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - expectedTable := "NETWORK ID NAME VERSION PLUGINS" + expectedTable := "NETWORK ID NAME DRIVER" Expect(session.OutputToString()).To(ContainSubstring(expectedTable)) session = podmanTest.Podman([]string{"network", "ls", "--format", "{{.Name}} {{.ID}}", "--filter", "id=" + netID}) @@ -176,7 +178,7 @@ var _ = Describe("Podman network", func() { session = podmanTest.Podman([]string{"network", "inspect", netID[1:]}) session.WaitWithDefaultTimeout() Expect(session).Should(ExitWithError()) - Expect(session.ErrorToString()).To(ContainSubstring("no such network")) + Expect(session.ErrorToString()).To(ContainSubstring("network not found")) session = podmanTest.Podman([]string{"network", "rm", netID}) session.WaitWithDefaultTimeout() @@ -239,10 +241,10 @@ var _ = Describe("Podman network", func() { name, path := generateNetworkConfig(podmanTest) defer removeConf(path) - session := podmanTest.Podman([]string{"network", "inspect", name, "--format", "{{.cniVersion}}"}) + session := podmanTest.Podman([]string{"network", "inspect", name, "--format", "{{.Driver}}"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - Expect(session.LineInOutputContains("0.3.0")).To(BeTrue()) + Expect(session.OutputToString()).To(ContainSubstring("bridge")) }) It("podman inspect container single CNI network", func() { @@ -512,9 +514,14 @@ var _ = Describe("Podman network", func() { inspect.WaitWithDefaultTimeout() Expect(inspect).Should(Exit(0)) - out, err := inspect.jq(".[0].plugins[0].master") + // JSON the network configuration into something usable + var results []types.Network + err := json.Unmarshal([]byte(inspect.OutputToString()), &results) Expect(err).To(BeNil()) - Expect(out).To(Equal("\"\"")) + Expect(results).To(HaveLen(1)) + result := results[0] + Expect(result.NetworkInterface).To(Equal("")) + Expect(result.IPAMOptions).To(HaveKeyWithValue("driver", "dhcp")) nc = podmanTest.Podman([]string{"network", "rm", net}) nc.WaitWithDefaultTimeout() @@ -532,13 +539,16 @@ var _ = Describe("Podman network", func() { inspect.WaitWithDefaultTimeout() Expect(inspect).Should(Exit(0)) - out, err := inspect.jq(".[0].plugins[0].master") + var results []types.Network + err := json.Unmarshal([]byte(inspect.OutputToString()), &results) Expect(err).To(BeNil()) - Expect(out).To(Equal(`"lo"`)) + Expect(results).To(HaveLen(1)) + result := results[0] - ipamType, err := inspect.jq(".[0].plugins[0].ipam.type") - Expect(err).To(BeNil()) - Expect(ipamType).To(Equal(`"dhcp"`)) + Expect(result.Driver).To(Equal("macvlan")) + Expect(result.NetworkInterface).To(Equal("lo")) + Expect(result.IPAMOptions).To(HaveKeyWithValue("driver", "dhcp")) + Expect(result.Subnets).To(HaveLen(0)) nc = podmanTest.Podman([]string{"network", "rm", net}) nc.WaitWithDefaultTimeout() @@ -572,33 +582,20 @@ var _ = Describe("Podman network", func() { inspect.WaitWithDefaultTimeout() Expect(inspect).Should(Exit(0)) - mtu, err := inspect.jq(".[0].plugins[0].mtu") - Expect(err).To(BeNil()) - Expect(mtu).To(Equal("1500")) - - name, err := inspect.jq(".[0].plugins[0].type") + var results []types.Network + err := json.Unmarshal([]byte(inspect.OutputToString()), &results) Expect(err).To(BeNil()) - Expect(name).To(Equal(`"macvlan"`)) + Expect(results).To(HaveLen(1)) + result := results[0] - netInt, err := inspect.jq(".[0].plugins[0].master") - Expect(err).To(BeNil()) - Expect(netInt).To(Equal(`"lo"`)) - - ipamType, err := inspect.jq(".[0].plugins[0].ipam.type") - Expect(err).To(BeNil()) - Expect(ipamType).To(Equal(`"host-local"`)) + Expect(result.Options).To(HaveKeyWithValue("mtu", "1500")) + Expect(result.Driver).To(Equal("macvlan")) + Expect(result.NetworkInterface).To(Equal("lo")) + Expect(result.IPAMOptions).To(HaveKeyWithValue("driver", "host-local")) - gw, err := inspect.jq(".[0].plugins[0].ipam.ranges[0][0].gateway") - Expect(err).To(BeNil()) - Expect(gw).To(Equal(`"192.168.1.254"`)) - - subnet, err := inspect.jq(".[0].plugins[0].ipam.ranges[0][0].subnet") - Expect(err).To(BeNil()) - Expect(subnet).To(Equal(`"192.168.1.0/24"`)) - - routes, err := inspect.jq(".[0].plugins[0].ipam.routes[0].dst") - Expect(err).To(BeNil()) - Expect(routes).To(Equal(`"0.0.0.0/0"`)) + Expect(result.Subnets).To(HaveLen(1)) + Expect(result.Subnets[0].Subnet.String()).To(Equal("192.168.1.0/24")) + Expect(result.Subnets[0].Gateway.String()).To(Equal("192.168.1.254")) nc = podmanTest.Podman([]string{"network", "rm", net}) nc.WaitWithDefaultTimeout() diff --git a/test/system/500-networking.bats b/test/system/500-networking.bats index bdedfae19..ef00d0366 100644 --- a/test/system/500-networking.bats +++ b/test/system/500-networking.bats @@ -6,7 +6,7 @@ load helpers @test "podman network - basic tests" { - heading="*NETWORK*ID*NAME*VERSION*PLUGINS*" + heading="*NETWORK*ID*NAME*DRIVER*" run_podman network ls if [[ ${output} != ${heading} ]]; then die "network ls expected heading is not available" @@ -151,7 +151,7 @@ load helpers local mysubnet=$(random_rfc1918_subnet) run_podman network create --subnet "${mysubnet}.0/24" $mynetname - is "$output" ".*/cni/net.d/$mynetname.conflist" "output of 'network create'" + is "$output" "$mynetname" "output of 'network create'" # (Assert that output is formatted, not a one-line blob: #8011) run_podman network inspect $mynetname @@ -189,7 +189,7 @@ load helpers # Cannot create network with the same name run_podman 125 network create $mynetname - is "$output" "Error: the network name $mynetname is already used" \ + is "$output" "Error: network name $mynetname already used: network already exists" \ "Trying to create an already-existing network" run_podman rm $cid @@ -208,14 +208,8 @@ load helpers INDEX1=$PODMAN_TMPDIR/hello.txt echo $random_1 > $INDEX1 - # use default network for root + # use default network local netname=podman - # for rootless we have to create a custom network since there is no default network - if is_rootless; then - netname=testnet-$(random_string 10) - run_podman network create $netname - is "$output" ".*/cni/net.d/$netname.conflist" "output of 'network create'" - fi # Bind-mount this file with a different name to a container running httpd run_podman run -d --name myweb -p "$HOST_PORT:80" \ @@ -226,9 +220,9 @@ load helpers cid=$output run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname\").IPAddress}}" - ip="$output" + ip1="$output" run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname\").MacAddress}}" - mac="$output" + mac1="$output" # Verify http contents: curl from localhost run curl -s $SERVER/index.txt @@ -248,22 +242,51 @@ load helpers # reload the network to recreate the iptables rules run_podman network reload $cid - is "$output" "$cid" "Output does not match container ID" + is "$output" "$cid" "Output does match container ID" # check that we still have the same mac and ip run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname\").IPAddress}}" - is "$output" "$ip" "IP address changed after podman network reload" + is "$output" "$ip1" "IP address changed after podman network reload" run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname\").MacAddress}}" - is "$output" "$mac" "MAC address changed after podman network reload" + is "$output" "$mac1" "MAC address changed after podman network reload" # check that we can still curl run curl -s $SERVER/index.txt is "$output" "$random_1" "curl 127.0.0.1:/index.txt" + # create second network + netname2=testnet-$(random_string 10) + # TODO add --ipv6 and uncomment the ipv6 checks below once cni plugins 1.0 is available on ubuntu CI VMs. + run_podman network create $netname2 + is "$output" "$netname2" "output of 'network create'" + + # connect the container to the second network + run_podman network connect $netname2 $cid + + run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname2\").IPAddress}}" + ip2="$output" + #run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname2\").GlobalIPv6Address}}" + #is "$output" "fd.*:.*" "IPv6 address should start with fd..." + #ipv6="$output" + run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname2\").MacAddress}}" + mac2="$output" + # make sure --all is working and that this # cmd also works if the iptables still exists run_podman network reload --all - is "$output" "$cid" "Output does not match container ID" + is "$output" "$cid" "Output does match container ID" + + # check that both network keep there ip and mac + run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname\").IPAddress}}" + is "$output" "$ip1" "IP address changed after podman network reload ($netname)" + run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname\").MacAddress}}" + is "$output" "$mac1" "MAC address changed after podman network reload ($netname)" + run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname2\").IPAddress}}" + is "$output" "$ip2" "IP address changed after podman network reload ($netname2)" + #run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname2\").GlobalIPv6Address}}" + #is "$output" "$ipv6" "IPv6 address changed after podman network reload ($netname2)" + run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname2\").MacAddress}}" + is "$output" "$mac2" "MAC address changed after podman network reload ($netname2)" # check that we can still curl run curl -s $SERVER/index.txt @@ -272,9 +295,11 @@ load helpers # cleanup the container run_podman rm -f $cid - if is_rootless; then - run_podman network rm -f $netname - fi + # test that we cannot remove the default network + run_podman 125 network rm -f $netname + is "$output" "Error: default network $netname cannot be removed" "Remove default network" + + run_podman network rm -f $netname2 } @test "podman rootless cni adds /usr/sbin to PATH" { @@ -325,7 +350,7 @@ load helpers local netname=testnet-$(random_string 10) run_podman network create --subnet $mysubnet.0/24 $netname - is "$output" ".*/cni/net.d/$netname.conflist" "output of 'network create'" + is "$output" "$netname" "output of 'network create'" run_podman run --rm --network $netname $IMAGE cat /etc/resolv.conf if grep -E "$ipv6_regex" <<< $output; then @@ -339,7 +364,7 @@ load helpers netname=testnet-$(random_string 10) run_podman network create --subnet $mysubnet $netname - is "$output" ".*/cni/net.d/$netname.conflist" "output of 'network create'" + is "$output" "$netname" "output of 'network create'" run_podman run --rm --network $netname $IMAGE cat /etc/resolv.conf # "is" does not like the ipv6 regex @@ -362,11 +387,11 @@ load helpers local netname=testnet-$(random_string 10) run_podman network create $netname - is "$output" ".*/cni/net.d/$netname.conflist" "output of 'network create'" + is "$output" "$netname" "output of 'network create'" local netname2=testnet2-$(random_string 10) run_podman network create $netname2 - is "$output" ".*/cni/net.d/$netname2.conflist" "output of 'network create'" + is "$output" "$netname2" "output of 'network create'" # First, run a container in background to ensure that the rootless cni ns # is not destroyed after network disconnect. @@ -447,7 +472,7 @@ load helpers local netname=testnet-$(random_string 10) run_podman network create $netname - is "$output" ".*/cni/net.d/$netname.conflist" "output of 'network create'" + is "$output" "$netname" "output of 'network create'" for network in "slirp4netns" "$netname"; do # Start container with the restart always policy -- cgit v1.2.3-54-g00ecf