diff --git a/libnetwork/cni/cni_conversion.go b/libnetwork/cni/cni_conversion.go index 5574b2b1c..127a5ddc1 100644 --- a/libnetwork/cni/cni_conversion.go +++ b/libnetwork/cni/cni_conversion.go @@ -128,15 +128,21 @@ func findPluginByName(plugins []*libcni.NetworkConfig, name string) bool { // It returns an array of subnets and an extra bool if dhcp is configured. func convertIPAMConfToNetwork(network *types.Network, ipam *ipamConfig, confPath string) error { if ipam.PluginType == types.DHCPIPAMDriver { - network.IPAMOptions["driver"] = types.DHCPIPAMDriver + network.IPAMOptions[types.Driver] = types.DHCPIPAMDriver return nil } if ipam.PluginType != types.HostLocalIPAMDriver { - return errors.Errorf("unsupported ipam plugin %s in %s", ipam.PluginType, confPath) + // This is not an error. While we only support certain ipam drivers, we + // cannot make it fail for unsupported ones. CNI is still able to use them, + // just our translation logic cannot convert this into a Network. + // For the same reason this is not warning, it would just be annoying for + // everyone using a unknown ipam driver. + logrus.Infof("unsupported ipam plugin %q in %s", ipam.PluginType, confPath) + return nil } - network.IPAMOptions["driver"] = types.HostLocalIPAMDriver + network.IPAMOptions[types.Driver] = types.HostLocalIPAMDriver for _, r := range ipam.Ranges { for _, ipam := range r { s := types.Subnet{} diff --git a/libnetwork/cni/config.go b/libnetwork/cni/config.go index e801e1469..6215c1581 100644 --- a/libnetwork/cni/config.go +++ b/libnetwork/cni/config.go @@ -197,12 +197,12 @@ func createIPMACVLAN(network *types.Network) error { } } if len(network.Subnets) == 0 { - network.IPAMOptions["driver"] = types.DHCPIPAMDriver + network.IPAMOptions[types.Driver] = types.DHCPIPAMDriver if network.Internal { return errors.New("internal is not supported with macvlan and dhcp ipam driver") } } else { - network.IPAMOptions["driver"] = types.HostLocalIPAMDriver + network.IPAMOptions[types.Driver] = types.HostLocalIPAMDriver } return nil } diff --git a/libnetwork/cni/config_test.go b/libnetwork/cni/config_test.go index 2c90480ec..2dd62c722 100644 --- a/libnetwork/cni/config_test.go +++ b/libnetwork/cni/config_test.go @@ -34,6 +34,7 @@ var _ = Describe("Config", func() { } logBuffer = bytes.Buffer{} logrus.SetOutput(&logBuffer) + logrus.SetLevel(logrus.InfoLevel) }) JustBeforeEach(func() { @@ -45,6 +46,7 @@ var _ = Describe("Config", func() { }) AfterEach(func() { + logrus.SetLevel(logrus.InfoLevel) os.RemoveAll(cniConfDir) }) @@ -1071,6 +1073,8 @@ var _ = Describe("Config", func() { Context("network load valid existing ones", func() { + numberOfConfigFiles := 0 + BeforeEach(func() { dir := "testfiles/valid" files, err := ioutil.ReadDir(dir) @@ -1088,26 +1092,41 @@ var _ = Describe("Config", func() { Fail("Failed to copy test files") } } + numberOfConfigFiles = len(files) }) It("load networks from disk", func() { + logrus.SetLevel(logrus.WarnLevel) nets, err := libpodNet.NetworkList() Expect(err).To(BeNil()) - Expect(nets).To(HaveLen(9)) + Expect(nets).To(HaveLen(numberOfConfigFiles)) // test the we do not show logrus warnings/errors logString := logBuffer.String() Expect(logString).To(BeEmpty()) }) + It("load networks from disk with log level debug", func() { + logrus.SetLevel(logrus.DebugLevel) + nets, err := libpodNet.NetworkList() + Expect(err).To(BeNil()) + Expect(nets).To(HaveLen(numberOfConfigFiles)) + // check for the unsupported ipam plugin message + logString := logBuffer.String() + Expect(logString).ToNot(BeEmpty()) + Expect(logString).To(ContainSubstring("unsupported ipam plugin \\\"\\\" in %s", cniConfDir+"/ipam-none.conflist")) + Expect(logString).To(ContainSubstring("unsupported ipam plugin \\\"\\\" in %s", cniConfDir+"/ipam-empty.conflist")) + Expect(logString).To(ContainSubstring("unsupported ipam plugin \\\"static\\\" in %s", cniConfDir+"/ipam-static.conflist")) + }) + It("change network struct fields should not affect network struct in the backend", func() { nets, err := libpodNet.NetworkList() Expect(err).To(BeNil()) - Expect(nets).To(HaveLen(9)) + Expect(nets).To(HaveLen(numberOfConfigFiles)) nets[0].Name = "myname" nets, err = libpodNet.NetworkList() Expect(err).To(BeNil()) - Expect(nets).To(HaveLen(9)) + Expect(nets).To(HaveLen(numberOfConfigFiles)) Expect(nets).ToNot(ContainElement(HaveNetworkName("myname"))) network, err := libpodNet.NetworkInspect("bridge") @@ -1144,6 +1163,7 @@ var _ = Describe("Config", func() { Expect(network.Driver).To(Equal("macvlan")) Expect(network.Subnets).To(HaveLen(0)) // DHCP + Expect(network.IPAMOptions).To(HaveKeyWithValue("driver", "dhcp")) }) It("internal network", func() { @@ -1230,6 +1250,15 @@ var _ = Describe("Config", func() { )) }) + It("ipam static network", func() { + network, err := libpodNet.NetworkInspect("ipam-static") + Expect(err).To(BeNil()) + Expect(network.Name).To(Equal("ipam-static")) + Expect(network.ID).To(HaveLen(64)) + Expect(network.Driver).To(Equal("bridge")) + Expect(network.Subnets).To(HaveLen(0)) + }) + It("network list with filters (name)", func() { filters := map[string][]string{ "name": {"internal", "bridge"}, @@ -1304,10 +1333,12 @@ var _ = Describe("Config", func() { networks, err := libpodNet.NetworkList(filterFuncs...) Expect(err).To(BeNil()) - Expect(networks).To(HaveLen(9)) + Expect(networks).To(HaveLen(numberOfConfigFiles)) Expect(networks).To(ConsistOf(HaveNetworkName("internal"), HaveNetworkName("bridge"), HaveNetworkName("mtu"), HaveNetworkName("vlan"), HaveNetworkName("podman"), - HaveNetworkName("label"), HaveNetworkName("macvlan"), HaveNetworkName("macvlan_mtu"), HaveNetworkName("dualstack"))) + HaveNetworkName("label"), HaveNetworkName("macvlan"), HaveNetworkName("macvlan_mtu"), + HaveNetworkName("dualstack"), HaveNetworkName("ipam-none"), HaveNetworkName("ipam-empty"), + HaveNetworkName("ipam-static"))) }) It("network list with filters (label)", func() { diff --git a/libnetwork/cni/run_test.go b/libnetwork/cni/run_test.go index 0d445f7e1..c53f5ee49 100644 --- a/libnetwork/cni/run_test.go +++ b/libnetwork/cni/run_test.go @@ -93,6 +93,7 @@ var _ = Describe("run CNI", func() { if err != nil { Fail("Failed to create netns") } + logrus.SetLevel(logrus.WarnLevel) }) JustBeforeEach(func() { @@ -104,6 +105,7 @@ var _ = Describe("run CNI", func() { }) AfterEach(func() { + logrus.SetLevel(logrus.InfoLevel) os.RemoveAll(cniConfDir) netns.UnmountNS(netNSTest) diff --git a/libnetwork/cni/testfiles/valid/ipam-empty.conflist b/libnetwork/cni/testfiles/valid/ipam-empty.conflist new file mode 100644 index 000000000..4383cc0ec --- /dev/null +++ b/libnetwork/cni/testfiles/valid/ipam-empty.conflist @@ -0,0 +1,34 @@ +{ + "cniVersion": "0.4.0", + "name": "ipam-empty", + "plugins": [ + { + "type": "bridge", + "bridge": "cni-podman124", + "isGateway": true, + "ipMasq": true, + "hairpinMode": true, + "ipam": {} + }, + { + "type": "portmap", + "capabilities": { + "portMappings": true + } + }, + { + "type": "firewall", + "backend": "" + }, + { + "type": "tuning" + }, + { + "type": "dnsname", + "domainName": "dns.podman", + "capabilities": { + "aliases": true + } + } + ] +} diff --git a/libnetwork/cni/testfiles/valid/ipam-none.conflist b/libnetwork/cni/testfiles/valid/ipam-none.conflist new file mode 100644 index 000000000..90cecbca9 --- /dev/null +++ b/libnetwork/cni/testfiles/valid/ipam-none.conflist @@ -0,0 +1,33 @@ +{ + "cniVersion": "0.4.0", + "name": "ipam-none", + "plugins": [ + { + "type": "bridge", + "bridge": "cni-podman123", + "isGateway": true, + "ipMasq": true, + "hairpinMode": true + }, + { + "type": "portmap", + "capabilities": { + "portMappings": true + } + }, + { + "type": "firewall", + "backend": "" + }, + { + "type": "tuning" + }, + { + "type": "dnsname", + "domainName": "dns.podman", + "capabilities": { + "aliases": true + } + } + ] +} diff --git a/libnetwork/cni/testfiles/valid/ipam-static.conflist b/libnetwork/cni/testfiles/valid/ipam-static.conflist new file mode 100644 index 000000000..b9e70f4c7 --- /dev/null +++ b/libnetwork/cni/testfiles/valid/ipam-static.conflist @@ -0,0 +1,49 @@ +{ + "cniVersion": "0.4.0", + "name": "ipam-static", + "plugins": [ + { + "type": "bridge", + "bridge": "cni-podman125", + "isGateway": true, + "ipMasq": true, + "hairpinMode": true, + "ipam": { + "type": "static", + "routes": [ + { + "dst": "0.0.0.0/0" + } + ], + "addresses": [ + [ + { + "subnet": "10.89.0.89/16", + "gateway": "10.89.0.1" + } + ] + ] + } + }, + { + "type": "portmap", + "capabilities": { + "portMappings": true + } + }, + { + "type": "firewall", + "backend": "" + }, + { + "type": "tuning" + }, + { + "type": "dnsname", + "domainName": "dns.podman", + "capabilities": { + "aliases": true + } + } + ] +} diff --git a/libnetwork/internal/util/bridge.go b/libnetwork/internal/util/bridge.go index d81b78a6f..5a4752e2b 100644 --- a/libnetwork/internal/util/bridge.go +++ b/libnetwork/internal/util/bridge.go @@ -27,7 +27,7 @@ func CreateBridge(n NetUtil, network *types.Network, usedNetworks []*net.IPNet, } } - if network.IPAMOptions["driver"] != types.DHCPIPAMDriver { + if network.IPAMOptions[types.Driver] != types.DHCPIPAMDriver { if len(network.Subnets) == 0 { freeSubnet, err := GetFreeIPv4NetworkSubnet(usedNetworks, subnetPools) if err != nil { @@ -63,7 +63,7 @@ func CreateBridge(n NetUtil, network *types.Network, usedNetworks []*net.IPNet, network.Subnets = append(network.Subnets, *freeSubnet) } } - network.IPAMOptions["driver"] = types.HostLocalIPAMDriver + network.IPAMOptions[types.Driver] = types.HostLocalIPAMDriver } return nil } diff --git a/libnetwork/internal/util/validate.go b/libnetwork/internal/util/validate.go index ac3934f8d..4dd44110a 100644 --- a/libnetwork/internal/util/validate.go +++ b/libnetwork/internal/util/validate.go @@ -109,7 +109,7 @@ func validatePerNetworkOpts(network *types.Network, netOpts *types.PerNetworkOpt if netOpts.InterfaceName == "" { return errors.Errorf("interface name on network %s is empty", network.Name) } - if network.IPAMOptions["driver"] == types.HostLocalIPAMDriver { + if network.IPAMOptions[types.Driver] == types.HostLocalIPAMDriver { outer: for _, ip := range netOpts.StaticIPs { for _, s := range network.Subnets { diff --git a/libnetwork/netavark/config.go b/libnetwork/netavark/config.go index 101354eb0..e950e1bff 100644 --- a/libnetwork/netavark/config.go +++ b/libnetwork/netavark/config.go @@ -155,7 +155,7 @@ func createMacvlan(network *types.Network) error { if len(network.Subnets) == 0 { return errors.Errorf("macvlan driver needs at least one subnet specified, DHCP is not supported with netavark") } - network.IPAMOptions["driver"] = types.HostLocalIPAMDriver + network.IPAMOptions[types.Driver] = types.HostLocalIPAMDriver // validate the given options, we do not need them but just check to make sure they are valid for key, value := range network.Options { diff --git a/libnetwork/netavark/ipam.go b/libnetwork/netavark/ipam.go index f99d099ca..9a1803d54 100644 --- a/libnetwork/netavark/ipam.go +++ b/libnetwork/netavark/ipam.go @@ -361,7 +361,7 @@ func (n *netavarkNetwork) deallocIPs(opts *types.NetworkOptions) error { // it checks the ipam driver and if subnets are set func requiresIPAMAlloc(network *types.Network) bool { // only do host allocation when driver is set to HostLocalIPAMDriver or unset - switch network.IPAMOptions["driver"] { + switch network.IPAMOptions[types.Driver] { case "", types.HostLocalIPAMDriver: default: return false diff --git a/libnetwork/types/const.go b/libnetwork/types/const.go index b2d4a4538..5690a6058 100644 --- a/libnetwork/types/const.go +++ b/libnetwork/types/const.go @@ -11,6 +11,7 @@ const ( IPVLANNetworkDriver = "ipvlan" // IPAM drivers + Driver = "driver" // HostLocalIPAMDriver store the ip HostLocalIPAMDriver = "host-local" // DHCPIPAMDriver get subnet and ip from dhcp server diff --git a/libnetwork/util/filters.go b/libnetwork/util/filters.go index b27ca1f9a..58d79d25b 100644 --- a/libnetwork/util/filters.go +++ b/libnetwork/util/filters.go @@ -29,7 +29,7 @@ func createFilterFuncs(key string, filterValues []string) (types.FilterFunc, err return util.StringMatchRegexSlice(net.Name, filterValues) }, nil - case "driver": + case types.Driver: // matches network driver return func(net types.Network) bool { return util.StringInSlice(net.Driver, filterValues)