diff --git a/common/libnetwork/internal/util/validate.go b/common/libnetwork/internal/util/validate.go index 9efad564fb..011a101ac6 100644 --- a/common/libnetwork/internal/util/validate.go +++ b/common/libnetwork/internal/util/validate.go @@ -145,12 +145,12 @@ func ValidateSetupOptions(n NetUtil, namespacePath string, options types.SetupOp if len(options.Networks) == 0 { return errors.New("must specify at least one network") } - for name, netOpts := range options.Networks { - network, err := n.Network(name) + for _, net := range options.Networks { + network, err := n.Network(net.Name) if err != nil { return err } - err = validatePerNetworkOpts(network, &netOpts) + err = validatePerNetworkOpts(network, &net.PerNetworkOptions) if err != nil { return err } diff --git a/common/libnetwork/netavark/ipam.go b/common/libnetwork/netavark/ipam.go index 3c95a44ffd..c1d1ed4ff7 100644 --- a/common/libnetwork/netavark/ipam.go +++ b/common/libnetwork/netavark/ipam.go @@ -77,10 +77,10 @@ func (n *netavarkNetwork) allocIPs(opts *types.NetworkOptions) error { defer db.Close() err = db.Update(func(tx *bbolt.Tx) error { - for netName, netOpts := range opts.Networks { - network := n.networks[netName] + for index, namedNet := range opts.Networks { + network := n.networks[namedNet.Name] if network == nil { - return newIPAMError(nil, "could not find network %q", netName) + return newIPAMError(nil, "could not find network %q", namedNet.Name) } // check if we have to alloc ips @@ -89,23 +89,23 @@ func (n *netavarkNetwork) allocIPs(opts *types.NetworkOptions) error { } // create/get network bucket - netBkt, err := tx.CreateBucketIfNotExists([]byte(netName)) + netBkt, err := tx.CreateBucketIfNotExists([]byte(namedNet.Name)) if err != nil { - return newIPAMError(err, "failed to create/get network bucket for network %s", netName) + return newIPAMError(err, "failed to create/get network bucket for network %s", namedNet.Name) } // requestIPs is the list of ips which should be used for this container - requestIPs := make([]net.IP, 0, len(netOpts.StaticIPs)) + requestIPs := make([]net.IP, 0, len(namedNet.PerNetworkOptions.StaticIPs)) for i, subnet := range network.Subnets { subnetBkt, err := netBkt.CreateBucketIfNotExists([]byte(subnet.Subnet.String())) if err != nil { - return newIPAMError(err, "failed to create/get subnet bucket for network %s", netName) + return newIPAMError(err, "failed to create/get subnet bucket for network %s", namedNet.Name) } // check for static ips requested for this subnet and allocate them if available hasSubnetStaticIP := false - for _, staticIP := range netOpts.StaticIPs { + for _, staticIP := range namedNet.PerNetworkOptions.StaticIPs { if subnet.Subnet.Contains(staticIP) { hasSubnetStaticIP = true @@ -146,7 +146,7 @@ func (n *netavarkNetwork) allocIPs(opts *types.NetworkOptions) error { idsBucket, err := netBkt.CreateBucketIfNotExists(idBucketKey) if err != nil { - return newIPAMError(err, "failed to create/get id bucket for network %s", netName) + return newIPAMError(err, "failed to create/get id bucket for network %s", namedNet.Name) } ipsBytes, err := json.Marshal(requestIPs) @@ -159,8 +159,8 @@ func (n *netavarkNetwork) allocIPs(opts *types.NetworkOptions) error { return newIPAMError(err, "failed to store ips in database") } - netOpts.StaticIPs = requestIPs - opts.Networks[netName] = netOpts + namedNet.PerNetworkOptions.StaticIPs = requestIPs + opts.Networks[index].PerNetworkOptions = namedNet.PerNetworkOptions } return nil }) @@ -249,10 +249,10 @@ func (n *netavarkNetwork) getAssignedIPs(opts *types.NetworkOptions) error { defer db.Close() err = db.View(func(tx *bbolt.Tx) error { - for netName, netOpts := range opts.Networks { - network := n.networks[netName] + for index, namedNet := range opts.Networks { + network := n.networks[namedNet.Name] if network == nil { - return newIPAMError(nil, "could not find network %q", netName) + return newIPAMError(nil, "could not find network %q", namedNet.Name) } // check if we have to alloc ips @@ -260,19 +260,19 @@ func (n *netavarkNetwork) getAssignedIPs(opts *types.NetworkOptions) error { continue } // get network bucket - netBkt := tx.Bucket([]byte(netName)) + netBkt := tx.Bucket([]byte(namedNet.Name)) if netBkt == nil { - return newIPAMError(nil, "failed to get network bucket for network %s", netName) + return newIPAMError(nil, "failed to get network bucket for network %s", namedNet.Name) } idBkt := netBkt.Bucket(idBucketKey) if idBkt == nil { - return newIPAMError(nil, "failed to get id bucket for network %s", netName) + return newIPAMError(nil, "failed to get id bucket for network %s", namedNet.Name) } ipJSON := idBkt.Get([]byte(opts.ContainerID)) if ipJSON == nil { - return newIPAMError(nil, "failed to get ips for container ID %s on network %s", opts.ContainerID, netName) + return newIPAMError(nil, "failed to get ips for container ID %s on network %s", opts.ContainerID, namedNet.Name) } // assignedIPs is the list of ips which should be used for this container @@ -287,8 +287,8 @@ func (n *netavarkNetwork) getAssignedIPs(opts *types.NetworkOptions) error { util.NormalizeIP(&assignedIPs[i]) } - netOpts.StaticIPs = assignedIPs - opts.Networks[netName] = netOpts + namedNet.PerNetworkOptions.StaticIPs = assignedIPs + opts.Networks[index].PerNetworkOptions = namedNet.PerNetworkOptions } return nil }) @@ -306,10 +306,10 @@ func (n *netavarkNetwork) deallocIPs(opts *types.NetworkOptions) error { defer db.Close() err = db.Update(func(tx *bbolt.Tx) error { - for netName, netOpts := range opts.Networks { - network := n.networks[netName] + for _, namedNet := range opts.Networks { + network := n.networks[namedNet.Name] if network == nil { - return newIPAMError(nil, "could not find network %q", netName) + return newIPAMError(nil, "could not find network %q", namedNet.Name) } // check if we have to alloc ips @@ -317,45 +317,45 @@ func (n *netavarkNetwork) deallocIPs(opts *types.NetworkOptions) error { continue } // get network bucket - netBkt := tx.Bucket([]byte(netName)) + netBkt := tx.Bucket([]byte(namedNet.Name)) if netBkt == nil { - return newIPAMError(nil, "failed to get network bucket for network %s", netName) + return newIPAMError(nil, "failed to get network bucket for network %s", namedNet.Name) } for _, subnet := range network.Subnets { subnetBkt := netBkt.Bucket([]byte(subnet.Subnet.String())) if subnetBkt == nil { - return newIPAMError(nil, "failed to get subnet bucket for network %s", netName) + return newIPAMError(nil, "failed to get subnet bucket for network %s", namedNet.Name) } // search for a static ip which matches the current subnet // in this case the user wants this one and we should not assign a free one removed := false - for _, assignedIP := range netOpts.StaticIPs { + for _, assignedIP := range namedNet.PerNetworkOptions.StaticIPs { if subnet.Subnet.Contains(assignedIP) { removed = true util.NormalizeIP(&assignedIP) err = subnetBkt.Delete(assignedIP) if err != nil { - return newIPAMError(err, "failed to remove ip %s from subnet bucket for network %s", assignedIP.String(), netName) + return newIPAMError(err, "failed to remove ip %s from subnet bucket for network %s", assignedIP.String(), namedNet.Name) } } } if !removed { - return newIPAMError(nil, "failed to find ip for subnet %s on network %s", subnet.Subnet.String(), netName) + return newIPAMError(nil, "failed to find ip for subnet %s on network %s", subnet.Subnet.String(), namedNet.Name) } } idBkt := netBkt.Bucket(idBucketKey) if idBkt == nil { - return newIPAMError(nil, "failed to get id bucket for network %s", netName) + return newIPAMError(nil, "failed to get id bucket for network %s", namedNet.Name) } err = idBkt.Delete([]byte(opts.ContainerID)) if err != nil { - return newIPAMError(err, "failed to remove allocated ips for container ID %s on network %s", opts.ContainerID, netName) + return newIPAMError(err, "failed to remove allocated ips for container ID %s on network %s", opts.ContainerID, namedNet.Name) } } return nil diff --git a/common/libnetwork/netavark/ipam_test.go b/common/libnetwork/netavark/ipam_test.go index 459c7f385f..0a457a9084 100644 --- a/common/libnetwork/netavark/ipam_test.go +++ b/common/libnetwork/netavark/ipam_test.go @@ -49,16 +49,17 @@ var _ = Describe("IPAM", func() { for i := 2; i < 100; i++ { opts := &types.NetworkOptions{ ContainerID: "someContainerID", - Networks: map[string]types.PerNetworkOptions{ - netName: {}, - }, + Networks: []types.NamedPerNetworkOptions{{ + Name: netName, + }}, } err := networkInterface.allocIPs(opts) Expect(err).ToNot(HaveOccurred()) - Expect(opts.Networks).To(HaveKey(netName)) - Expect(opts.Networks[netName].StaticIPs).To(HaveLen(1)) - Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(net.ParseIP(fmt.Sprintf("10.88.0.%d", i)).To4())) + Expect(opts.Networks).To(HaveLen(1)) + Expect(opts.Networks[0].Name).To(Equal(netName)) + Expect(opts.Networks[0].StaticIPs).To(HaveLen(1)) + Expect(opts.Networks[0].StaticIPs[0]).To(Equal(net.ParseIP(fmt.Sprintf("10.88.0.%d", i)).To4())) } }) @@ -66,22 +67,26 @@ var _ = Describe("IPAM", func() { netName := types.DefaultNetworkName opts := &types.NetworkOptions{ ContainerID: "someContainerID", - Networks: map[string]types.PerNetworkOptions{ - netName: {}, - }, + Networks: []types.NamedPerNetworkOptions{{ + Name: netName, + }}, } err := networkInterface.allocIPs(opts) Expect(err).ToNot(HaveOccurred()) - Expect(opts.Networks).To(HaveKey(netName)) - Expect(opts.Networks[netName].StaticIPs).To(HaveLen(1)) - Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(net.ParseIP("10.88.0.2").To4())) + Expect(opts.Networks).To(HaveLen(1)) + Expect(opts.Networks[0].Name).To(Equal(netName)) + Expect(opts.Networks[0].StaticIPs).To(HaveLen(1)) + Expect(opts.Networks[0].StaticIPs[0]).To(Equal(net.ParseIP("10.88.0.2").To4())) opts = &types.NetworkOptions{ ContainerID: "otherID", - Networks: map[string]types.PerNetworkOptions{ - netName: {StaticIPs: []net.IP{net.ParseIP("10.88.0.2")}}, - }, + Networks: []types.NamedPerNetworkOptions{{ + Name: netName, + PerNetworkOptions: types.PerNetworkOptions{ + StaticIPs: []net.IP{net.ParseIP("10.88.0.2")}, + }, + }}, } err = networkInterface.allocIPs(opts) Expect(err).To(HaveOccurred()) @@ -111,23 +116,24 @@ var _ = Describe("IPAM", func() { for i := 10; i < 21; i++ { opts := &types.NetworkOptions{ ContainerID: fmt.Sprintf("someContainerID-%d", i), - Networks: map[string]types.PerNetworkOptions{ - netName: {}, - }, + Networks: []types.NamedPerNetworkOptions{{ + Name: netName, + }}, } err = networkInterface.allocIPs(opts) Expect(err).ToNot(HaveOccurred()) - Expect(opts.Networks).To(HaveKey(netName)) - Expect(opts.Networks[netName].StaticIPs).To(HaveLen(1)) - Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(net.ParseIP(fmt.Sprintf("10.0.0.%d", i)).To4())) + Expect(opts.Networks).To(HaveLen(1)) + Expect(opts.Networks[0].Name).To(Equal(netName)) + Expect(opts.Networks[0].StaticIPs).To(HaveLen(1)) + Expect(opts.Networks[0].StaticIPs[0]).To(Equal(net.ParseIP(fmt.Sprintf("10.0.0.%d", i)).To4())) } opts := &types.NetworkOptions{ ContainerID: "someContainerID-22", - Networks: map[string]types.PerNetworkOptions{ - netName: {}, - }, + Networks: []types.NamedPerNetworkOptions{{ + Name: netName, + }}, } // now this should fail because all free ips are already assigned @@ -140,29 +146,31 @@ var _ = Describe("IPAM", func() { netName := types.DefaultNetworkName opts := &types.NetworkOptions{ ContainerID: "someContainerID", - Networks: map[string]types.PerNetworkOptions{ - netName: {}, - }, + Networks: []types.NamedPerNetworkOptions{{ + Name: netName, + }}, } expectedIP := net.ParseIP("10.88.0.2").To4() err := networkInterface.allocIPs(opts) Expect(err).ToNot(HaveOccurred()) - Expect(opts.Networks).To(HaveKey(netName)) - Expect(opts.Networks[netName].StaticIPs).To(HaveLen(1)) - Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(expectedIP)) + Expect(opts.Networks).To(HaveLen(1)) + Expect(opts.Networks[0].Name).To(Equal(netName)) + Expect(opts.Networks[0].StaticIPs).To(HaveLen(1)) + Expect(opts.Networks[0].StaticIPs[0]).To(Equal(expectedIP)) // remove static ips from opts - netOpts := opts.Networks[netName] - netOpts.StaticIPs = nil - opts.Networks[netName] = netOpts + netPerNetworkOptions := opts.Networks[0].PerNetworkOptions + netPerNetworkOptions.StaticIPs = nil + opts.Networks[0].PerNetworkOptions = netPerNetworkOptions err = networkInterface.getAssignedIPs(opts) Expect(err).ToNot(HaveOccurred()) - Expect(opts.Networks).To(HaveKey(netName)) - Expect(opts.Networks[netName].StaticIPs).To(HaveLen(1)) - Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(expectedIP)) + Expect(opts.Networks).To(HaveLen(1)) + Expect(opts.Networks[0].Name).To(Equal(netName)) + Expect(opts.Networks[0].StaticIPs).To(HaveLen(1)) + Expect(opts.Networks[0].StaticIPs[0]).To(Equal(expectedIP)) err = networkInterface.allocIPs(opts) Expect(err).To(HaveOccurred()) @@ -174,9 +182,10 @@ var _ = Describe("IPAM", func() { err = networkInterface.allocIPs(opts) Expect(err).ToNot(HaveOccurred()) - Expect(opts.Networks).To(HaveKey(netName)) - Expect(opts.Networks[netName].StaticIPs).To(HaveLen(1)) - Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(expectedIP)) + Expect(opts.Networks).To(HaveLen(1)) + Expect(opts.Networks[0].Name).To(Equal(netName)) + Expect(opts.Networks[0].StaticIPs).To(HaveLen(1)) + Expect(opts.Networks[0].StaticIPs[0]).To(Equal(expectedIP)) }) It("ipam dual stack", func() { @@ -201,29 +210,31 @@ var _ = Describe("IPAM", func() { opts := &types.NetworkOptions{ ContainerID: "someContainerID", - Networks: map[string]types.PerNetworkOptions{ - netName: {}, - }, + Networks: []types.NamedPerNetworkOptions{{ + Name: netName, + }}, } err = networkInterface.allocIPs(opts) Expect(err).ToNot(HaveOccurred()) - Expect(opts.Networks).To(HaveKey(netName)) - Expect(opts.Networks[netName].StaticIPs).To(HaveLen(2)) - Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(net.ParseIP("10.0.0.2").To4())) - Expect(opts.Networks[netName].StaticIPs[1]).To(Equal(net.ParseIP("fd80::2"))) + Expect(opts.Networks).To(HaveLen(1)) + Expect(opts.Networks[0].Name).To(Equal(netName)) + Expect(opts.Networks[0].StaticIPs).To(HaveLen(2)) + Expect(opts.Networks[0].StaticIPs[0]).To(Equal(net.ParseIP("10.0.0.2").To4())) + Expect(opts.Networks[0].StaticIPs[1]).To(Equal(net.ParseIP("fd80::2"))) // remove static ips from opts - netOpts := opts.Networks[netName] - netOpts.StaticIPs = nil - opts.Networks[netName] = netOpts + netPerNetworkOptions := opts.Networks[0].PerNetworkOptions + netPerNetworkOptions.StaticIPs = nil + opts.Networks[0].PerNetworkOptions = netPerNetworkOptions err = networkInterface.getAssignedIPs(opts) Expect(err).ToNot(HaveOccurred()) - Expect(opts.Networks).To(HaveKey(netName)) - Expect(opts.Networks[netName].StaticIPs).To(HaveLen(2)) - Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(net.ParseIP("10.0.0.2").To4())) - Expect(opts.Networks[netName].StaticIPs[1]).To(Equal(net.ParseIP("fd80::2"))) + Expect(opts.Networks).To(HaveLen(1)) + Expect(opts.Networks[0].Name).To(Equal(netName)) + Expect(opts.Networks[0].StaticIPs).To(HaveLen(2)) + Expect(opts.Networks[0].StaticIPs[0]).To(Equal(net.ParseIP("10.0.0.2").To4())) + Expect(opts.Networks[0].StaticIPs[1]).To(Equal(net.ParseIP("fd80::2"))) err = networkInterface.deallocIPs(opts) Expect(err).ToNot(HaveOccurred()) @@ -231,10 +242,11 @@ var _ = Describe("IPAM", func() { // try to alloc the same again err = networkInterface.allocIPs(opts) Expect(err).ToNot(HaveOccurred()) - Expect(opts.Networks).To(HaveKey(netName)) - Expect(opts.Networks[netName].StaticIPs).To(HaveLen(2)) - Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(net.ParseIP("10.0.0.2").To4())) - Expect(opts.Networks[netName].StaticIPs[1]).To(Equal(net.ParseIP("fd80::2"))) + Expect(opts.Networks).To(HaveLen(1)) + Expect(opts.Networks[0].Name).To(Equal(netName)) + Expect(opts.Networks[0].StaticIPs).To(HaveLen(2)) + Expect(opts.Networks[0].StaticIPs[0]).To(Equal(net.ParseIP("10.0.0.2").To4())) + Expect(opts.Networks[0].StaticIPs[1]).To(Equal(net.ParseIP("fd80::2"))) }) It("ipam with two networks", func() { @@ -270,37 +282,43 @@ var _ = Describe("IPAM", func() { opts := &types.NetworkOptions{ ContainerID: "someContainerID", - Networks: map[string]types.PerNetworkOptions{ - netName1: {}, - netName2: {}, + Networks: []types.NamedPerNetworkOptions{ + { + Name: netName1, + }, + { + Name: netName2, + }, }, } err = networkInterface.allocIPs(opts) Expect(err).ToNot(HaveOccurred()) - Expect(opts.Networks).To(HaveKey(netName1)) - Expect(opts.Networks[netName1].StaticIPs).To(HaveLen(1)) - Expect(opts.Networks[netName1].StaticIPs[0]).To(Equal(net.ParseIP("10.0.0.2").To4())) - Expect(opts.Networks).To(HaveKey(netName2)) - Expect(opts.Networks[netName2].StaticIPs).To(HaveLen(1)) - Expect(opts.Networks[netName2].StaticIPs[0]).To(Equal(net.ParseIP("10.0.1.2").To4())) + Expect(opts.Networks).To(HaveLen(2)) + Expect(opts.Networks[0].Name).To(Equal(netName1)) + Expect(opts.Networks[0].StaticIPs).To(HaveLen(1)) + Expect(opts.Networks[0].StaticIPs[0]).To(Equal(net.ParseIP("10.0.0.2").To4())) + Expect(opts.Networks[1].Name).To(Equal(netName2)) + Expect(opts.Networks[1].StaticIPs).To(HaveLen(1)) + Expect(opts.Networks[1].StaticIPs[0]).To(Equal(net.ParseIP("10.0.1.2").To4())) // remove static ips from opts - netOpts := opts.Networks[netName1] - netOpts.StaticIPs = nil - opts.Networks[netName1] = netOpts - netOpts = opts.Networks[netName2] - netOpts.StaticIPs = nil - opts.Networks[netName2] = netOpts + netPerNetworkOptions := opts.Networks[0].PerNetworkOptions + netPerNetworkOptions.StaticIPs = nil + opts.Networks[0].PerNetworkOptions = netPerNetworkOptions + netPerNetworkOptions = opts.Networks[1].PerNetworkOptions + netPerNetworkOptions.StaticIPs = nil + opts.Networks[1].PerNetworkOptions = netPerNetworkOptions err = networkInterface.getAssignedIPs(opts) Expect(err).ToNot(HaveOccurred()) - Expect(opts.Networks).To(HaveKey(netName1)) - Expect(opts.Networks[netName1].StaticIPs).To(HaveLen(1)) - Expect(opts.Networks[netName1].StaticIPs[0]).To(Equal(net.ParseIP("10.0.0.2").To4())) - Expect(opts.Networks).To(HaveKey(netName2)) - Expect(opts.Networks[netName2].StaticIPs).To(HaveLen(1)) - Expect(opts.Networks[netName2].StaticIPs[0]).To(Equal(net.ParseIP("10.0.1.2").To4())) + Expect(opts.Networks).To(HaveLen(2)) + Expect(opts.Networks[0].Name).To(Equal(netName1)) + Expect(opts.Networks[0].StaticIPs).To(HaveLen(1)) + Expect(opts.Networks[0].StaticIPs[0]).To(Equal(net.ParseIP("10.0.0.2").To4())) + Expect(opts.Networks[1].Name).To(Equal(netName2)) + Expect(opts.Networks[1].StaticIPs).To(HaveLen(1)) + Expect(opts.Networks[1].StaticIPs[0]).To(Equal(net.ParseIP("10.0.1.2").To4())) err = networkInterface.deallocIPs(opts) Expect(err).ToNot(HaveOccurred()) @@ -308,12 +326,13 @@ var _ = Describe("IPAM", func() { // try to alloc the same again err = networkInterface.allocIPs(opts) Expect(err).ToNot(HaveOccurred()) - Expect(opts.Networks).To(HaveKey(netName1)) - Expect(opts.Networks[netName1].StaticIPs).To(HaveLen(1)) - Expect(opts.Networks[netName1].StaticIPs[0]).To(Equal(net.ParseIP("10.0.0.2").To4())) - Expect(opts.Networks).To(HaveKey(netName2)) - Expect(opts.Networks[netName2].StaticIPs).To(HaveLen(1)) - Expect(opts.Networks[netName2].StaticIPs[0]).To(Equal(net.ParseIP("10.0.1.2").To4())) + Expect(opts.Networks).To(HaveLen(2)) + Expect(opts.Networks[0].Name).To(Equal(netName1)) + Expect(opts.Networks[0].StaticIPs).To(HaveLen(1)) + Expect(opts.Networks[0].StaticIPs[0]).To(Equal(net.ParseIP("10.0.0.2").To4())) + Expect(opts.Networks[1].Name).To(Equal(netName2)) + Expect(opts.Networks[1].StaticIPs).To(HaveLen(1)) + Expect(opts.Networks[1].StaticIPs[0]).To(Equal(net.ParseIP("10.0.1.2").To4())) }) It("ipam alloc more ips as in subnet", func() { @@ -335,16 +354,17 @@ var _ = Describe("IPAM", func() { for i := 2; i < 64; i++ { opts := &types.NetworkOptions{ ContainerID: fmt.Sprintf("id-%d", i), - Networks: map[string]types.PerNetworkOptions{ - netName: {}, - }, + Networks: []types.NamedPerNetworkOptions{{ + Name: netName, + }}, } err = networkInterface.allocIPs(opts) if i < 63 { Expect(err).ToNot(HaveOccurred()) - Expect(opts.Networks).To(HaveKey(netName)) - Expect(opts.Networks[netName].StaticIPs).To(HaveLen(1)) - Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(net.ParseIP(fmt.Sprintf("10.0.0.%d", i)).To4())) + Expect(opts.Networks).To(HaveLen(1)) + Expect(opts.Networks[0].Name).To(Equal(netName)) + Expect(opts.Networks[0].StaticIPs).To(HaveLen(1)) + Expect(opts.Networks[0].StaticIPs[0]).To(Equal(net.ParseIP(fmt.Sprintf("10.0.0.%d", i)).To4())) } else { Expect(err).To(HaveOccurred()) Expect(err.Error()).To(Equal("IPAM error: failed to find free IP in range: 10.0.0.1 - 10.0.0.62")) @@ -371,15 +391,16 @@ var _ = Describe("IPAM", func() { for i := 2; i < 10; i++ { opts := types.NetworkOptions{ ContainerID: fmt.Sprintf("id-%d", i), - Networks: map[string]types.PerNetworkOptions{ - netName: {}, - }, + Networks: []types.NamedPerNetworkOptions{{ + Name: netName, + }}, } err = networkInterface.allocIPs(&opts) Expect(err).ToNot(HaveOccurred()) - Expect(opts.Networks).To(HaveKey(netName)) - Expect(opts.Networks[netName].StaticIPs).To(HaveLen(1)) - Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(net.ParseIP(fmt.Sprintf("10.0.0.%d", i)).To4())) + Expect(opts.Networks).To(HaveLen(1)) + Expect(opts.Networks[0].Name).To(Equal(netName)) + Expect(opts.Networks[0].StaticIPs).To(HaveLen(1)) + Expect(opts.Networks[0].StaticIPs[0]).To(Equal(net.ParseIP(fmt.Sprintf("10.0.0.%d", i)).To4())) err = networkInterface.deallocIPs(&opts) Expect(err).ToNot(HaveOccurred()) @@ -388,20 +409,21 @@ var _ = Describe("IPAM", func() { for i := range 30 { opts := types.NetworkOptions{ ContainerID: fmt.Sprintf("id-%d", i), - Networks: map[string]types.PerNetworkOptions{ - netName: {}, - }, + Networks: []types.NamedPerNetworkOptions{{ + Name: netName, + }}, } err = networkInterface.allocIPs(&opts) if i < 29 { Expect(err).ToNot(HaveOccurred()) - Expect(opts.Networks).To(HaveKey(netName)) - Expect(opts.Networks[netName].StaticIPs).To(HaveLen(1)) + Expect(opts.Networks).To(HaveLen(1)) + Expect(opts.Networks[0].Name).To(Equal(netName)) + Expect(opts.Networks[0].StaticIPs).To(HaveLen(1)) // The (i+8)%29+2 part looks cryptic but it is actually simple, we already have 8 ips allocated above // so we expect the 8 available ip. We have 29 assignable ip addresses in this subnet because "i"+8 can // be greater than 30 we have to modulo by 29 to go back to the beginning. Also the first free ip is // network address + 2, so we have to add 2 to the result - Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(net.ParseIP(fmt.Sprintf("10.0.0.%d", (i+8)%29+2)).To4())) + Expect(opts.Networks[0].StaticIPs[0]).To(Equal(net.ParseIP(fmt.Sprintf("10.0.0.%d", (i+8)%29+2)).To4())) } else { Expect(err).To(HaveOccurred()) Expect(err.Error()).To(Equal("IPAM error: failed to find free IP in range: 10.0.0.1 - 10.0.0.30")) @@ -424,20 +446,22 @@ var _ = Describe("IPAM", func() { opts := &types.NetworkOptions{ ContainerID: "someContainerID", - Networks: map[string]types.PerNetworkOptions{ - netName: {}, - }, + Networks: []types.NamedPerNetworkOptions{{ + Name: netName, + }}, } err = networkInterface.allocIPs(opts) Expect(err).ToNot(HaveOccurred()) - Expect(opts.Networks).To(HaveKey(netName)) - Expect(opts.Networks[netName].StaticIPs).To(BeEmpty()) + Expect(opts.Networks).To(HaveLen(1)) + Expect(opts.Networks[0].Name).To(Equal(netName)) + Expect(opts.Networks[0].StaticIPs).To(BeEmpty()) err = networkInterface.getAssignedIPs(opts) Expect(err).ToNot(HaveOccurred()) - Expect(opts.Networks).To(HaveKey(netName)) - Expect(opts.Networks[netName].StaticIPs).To(BeEmpty()) + Expect(opts.Networks).To(HaveLen(1)) + Expect(opts.Networks[0].Name).To(Equal(netName)) + Expect(opts.Networks[0].StaticIPs).To(BeEmpty()) // dealloc the ip err = networkInterface.deallocIPs(opts) @@ -473,16 +497,17 @@ var _ = Describe("IPAM", func() { for i := 2; i < 64; i++ { opts := &types.NetworkOptions{ ContainerID: fmt.Sprintf("id-%d", i), - Networks: map[string]types.PerNetworkOptions{ - netName: {}, - }, + Networks: []types.NamedPerNetworkOptions{{ + Name: netName, + }}, } err = networkInterface.allocIPs(opts) if i < 63 { Expect(err).ToNot(HaveOccurred()) - Expect(opts.Networks).To(HaveKey(netName)) - Expect(opts.Networks[netName].StaticIPs).To(HaveLen(1)) - Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(net.ParseIP(fmt.Sprintf("10.0.0.%d", i)).To4())) + Expect(opts.Networks).To(HaveLen(1)) + Expect(opts.Networks[0].Name).To(Equal(netName)) + Expect(opts.Networks[0].StaticIPs).To(HaveLen(1)) + Expect(opts.Networks[0].StaticIPs[0]).To(Equal(net.ParseIP(fmt.Sprintf("10.0.0.%d", i)).To4())) } else { Expect(err).To(HaveOccurred()) Expect(err.Error()).To(Equal("IPAM error: failed to find free IP in range: 10.0.0.1 - 10.0.0.62")) @@ -509,16 +534,17 @@ var _ = Describe("IPAM", func() { opts := &types.NetworkOptions{ ContainerID: "someContainerID", - Networks: map[string]types.PerNetworkOptions{ - netName: {}, - }, + Networks: []types.NamedPerNetworkOptions{{ + Name: netName, + }}, } err = networkInterface.allocIPs(opts) Expect(err).ToNot(HaveOccurred()) - Expect(opts.Networks).To(HaveKey(netName)) - Expect(opts.Networks[netName].StaticIPs).To(HaveLen(1)) - Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(net.ParseIP("10.0.0.2").To4())) + Expect(opts.Networks).To(HaveLen(1)) + Expect(opts.Networks[0].Name).To(Equal(netName)) + Expect(opts.Networks[0].StaticIPs).To(HaveLen(1)) + Expect(opts.Networks[0].StaticIPs[0]).To(Equal(net.ParseIP("10.0.0.2").To4())) // dealloc the ip err = networkInterface.deallocIPs(opts) @@ -547,16 +573,17 @@ var _ = Describe("IPAM", func() { opts = &types.NetworkOptions{ ContainerID: "someContainerID", - Networks: map[string]types.PerNetworkOptions{ - netName: {}, - }, + Networks: []types.NamedPerNetworkOptions{{ + Name: netName, + }}, } err = networkInterface.allocIPs(opts) Expect(err).ToNot(HaveOccurred()) - Expect(opts.Networks).To(HaveKey(netName)) - Expect(opts.Networks[netName].StaticIPs).To(HaveLen(1)) - Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(net.ParseIP("10.0.0.10").To4())) + Expect(opts.Networks).To(HaveLen(1)) + Expect(opts.Networks[0].Name).To(Equal(netName)) + Expect(opts.Networks[0].StaticIPs).To(HaveLen(1)) + Expect(opts.Networks[0].StaticIPs[0]).To(Equal(net.ParseIP("10.0.0.10").To4())) }) DescribeTable("ipam alloc and dealloc multiple static IPs", @@ -582,17 +609,19 @@ var _ = Describe("IPAM", func() { opts := &types.NetworkOptions{ ContainerID: "someContainerID", - Networks: map[string]types.PerNetworkOptions{ - netName: {StaticIPs: staticIPs}, - }, + Networks: []types.NamedPerNetworkOptions{{ + Name: netName, + PerNetworkOptions: types.PerNetworkOptions{StaticIPs: staticIPs}, + }}, } err = networkInterface.allocIPs(opts) Expect(err).ToNot(HaveOccurred()) - Expect(opts.Networks).To(HaveKey(netName)) - Expect(opts.Networks[netName].StaticIPs).To(HaveLen(expectedTotal)) + Expect(opts.Networks).To(HaveLen(1)) + Expect(opts.Networks[0].Name).To(Equal(netName)) + Expect(opts.Networks[0].StaticIPs).To(HaveLen(expectedTotal)) for _, ip := range staticIPs { - Expect(opts.Networks[netName].StaticIPs).To(ContainElement(WithTransform(func(i net.IP) string { return i.String() }, Equal(ip.String())))) + Expect(opts.Networks[0].StaticIPs).To(ContainElement(WithTransform(func(i net.IP) string { return i.String() }, Equal(ip.String())))) } err = networkInterface.deallocIPs(opts) diff --git a/common/libnetwork/netavark/run.go b/common/libnetwork/netavark/run.go index a57f2761af..1fd1a41567 100644 --- a/common/libnetwork/netavark/run.go +++ b/common/libnetwork/netavark/run.go @@ -169,12 +169,12 @@ func (n *netavarkNetwork) convertNetOpts(opts types.NetworkOptions) (*netavarkOp needsPlugin := false - for network := range opts.Networks { - net, err := n.getNetwork(network) + for _, network := range opts.Networks { + net, err := n.getNetwork(network.Name) if err != nil { return nil, false, err } - netavarkOptions.Networks[network] = net + netavarkOptions.Networks[network.Name] = net if !slices.Contains(builtinDrivers, net.Driver) { needsPlugin = true } diff --git a/common/libnetwork/netavark/run_test.go b/common/libnetwork/netavark/run_test.go index 416c4ba7d0..072a8f1275 100644 --- a/common/libnetwork/netavark/run_test.go +++ b/common/libnetwork/netavark/run_test.go @@ -124,12 +124,13 @@ var _ = Describe("run netavark", func() { NetworkOptions: types.NetworkOptions{ ContainerID: "someID", ContainerName: "someName", - Networks: map[string]types.PerNetworkOptions{ - defNet: { + Networks: []types.NamedPerNetworkOptions{{ + Name: defNet, + PerNetworkOptions: types.PerNetworkOptions{ InterfaceName: intName, StaticMAC: types.HardwareAddr{0x44, 0x33, 0x22, 0x44, 0x33, 0x22}, }, - }, + }}, }, } @@ -220,12 +221,13 @@ var _ = Describe("run netavark", func() { NetworkOptions: types.NetworkOptions{ ContainerID: "someID", ContainerName: "someName", - Networks: map[string]types.PerNetworkOptions{ - defNet: { + Networks: []types.NamedPerNetworkOptions{{ + Name: defNet, + PerNetworkOptions: types.PerNetworkOptions{ InterfaceName: intName, StaticMAC: mac, }, - }, + }}, }, } @@ -258,9 +260,12 @@ var _ = Describe("run netavark", func() { setupOpts1 := types.SetupOptions{ NetworkOptions: types.NetworkOptions{ ContainerID: stringid.GenerateNonCryptoID(), - Networks: map[string]types.PerNetworkOptions{ - defNet: {InterfaceName: intName}, - }, + Networks: []types.NamedPerNetworkOptions{{ + Name: defNet, + PerNetworkOptions: types.PerNetworkOptions{ + InterfaceName: intName, + }, + }}, }, } res, err := libpodNet.Setup(netNSContainer.Path(), setupOpts1) @@ -276,9 +281,12 @@ var _ = Describe("run netavark", func() { setupOpts2 := types.SetupOptions{ NetworkOptions: types.NetworkOptions{ ContainerID: stringid.GenerateNonCryptoID(), - Networks: map[string]types.PerNetworkOptions{ - defNet: {InterfaceName: intName}, - }, + Networks: []types.NamedPerNetworkOptions{{ + Name: defNet, + PerNetworkOptions: types.PerNetworkOptions{ + InterfaceName: intName, + }, + }}, }, } @@ -325,9 +333,12 @@ var _ = Describe("run netavark", func() { setupOpts := types.SetupOptions{ NetworkOptions: types.NetworkOptions{ ContainerID: stringid.GenerateNonCryptoID(), - Networks: map[string]types.PerNetworkOptions{ - netName: {InterfaceName: intName}, - }, + Networks: []types.NamedPerNetworkOptions{{ + Name: netName, + PerNetworkOptions: types.PerNetworkOptions{ + InterfaceName: intName, + }, + }}, }, } res, err := libpodNet.Setup(netNSContainer.Path(), setupOpts) @@ -422,9 +433,19 @@ var _ = Describe("run netavark", func() { setupOpts := types.SetupOptions{ NetworkOptions: types.NetworkOptions{ ContainerID: stringid.GenerateNonCryptoID(), - Networks: map[string]types.PerNetworkOptions{ - netName1: {InterfaceName: intName1}, - netName2: {InterfaceName: intName2}, + Networks: []types.NamedPerNetworkOptions{ + { + Name: netName1, + PerNetworkOptions: types.PerNetworkOptions{ + InterfaceName: intName1, + }, + }, + { + Name: netName2, + PerNetworkOptions: types.PerNetworkOptions{ + InterfaceName: intName2, + }, + }, }, }, } @@ -526,9 +547,12 @@ var _ = Describe("run netavark", func() { HostPort: 5000, ContainerPort: 5000, }}, - Networks: map[string]types.PerNetworkOptions{ - defNet: {InterfaceName: intName}, - }, + Networks: []types.NamedPerNetworkOptions{{ + Name: defNet, + PerNetworkOptions: types.PerNetworkOptions{ + InterfaceName: intName, + }, + }}, }, } res, err := libpodNet.Setup(netNSContainer.Path(), setupOpts) @@ -579,9 +603,12 @@ var _ = Describe("run netavark", func() { ContainerPort: 5000, Range: 3, }}, - Networks: map[string]types.PerNetworkOptions{ - defNet: {InterfaceName: intName}, - }, + Networks: []types.NamedPerNetworkOptions{{ + Name: defNet, + PerNetworkOptions: types.PerNetworkOptions{ + InterfaceName: intName, + }, + }}, }, } res, err := libpodNet.Setup(netNSContainer.Path(), setupOpts) @@ -634,11 +661,12 @@ var _ = Describe("run netavark", func() { NetworkOptions: types.NetworkOptions{ ContainerID: "someID", ContainerName: "someName", - Networks: map[string]types.PerNetworkOptions{ - defNet: { + Networks: []types.NamedPerNetworkOptions{{ + Name: defNet, + PerNetworkOptions: types.PerNetworkOptions{ InterfaceName: intName, }, - }, + }}, }, } res, err := libpodNet.Setup(netNSContainer.Path(), opts) @@ -691,11 +719,12 @@ var _ = Describe("run netavark", func() { NetworkOptions: types.NetworkOptions{ ContainerID: "someID", ContainerName: "someName", - Networks: map[string]types.PerNetworkOptions{ - defNet: { + Networks: []types.NamedPerNetworkOptions{{ + Name: defNet, + PerNetworkOptions: types.PerNetworkOptions{ InterfaceName: intName, }, - }, + }}, }, } _, err = libpodNet.Setup(netNSContainer.Path(), opts) @@ -721,11 +750,12 @@ var _ = Describe("run netavark", func() { setupOpts := types.SetupOptions{ NetworkOptions: types.NetworkOptions{ ContainerID: stringid.GenerateNonCryptoID(), - Networks: map[string]types.PerNetworkOptions{ - netName1: { + Networks: []types.NamedPerNetworkOptions{{ + Name: netName1, + PerNetworkOptions: types.PerNetworkOptions{ InterfaceName: intName1, }, - }, + }}, }, } diff --git a/common/libnetwork/types/network.go b/common/libnetwork/types/network.go index c46c470ec6..92096cbfc0 100644 --- a/common/libnetwork/types/network.go +++ b/common/libnetwork/types/network.go @@ -253,6 +253,12 @@ type NetAddress struct { Gateway net.IP `json:"gateway,omitempty"` } +// NamedPerNetworkOptions includes both options to apply to a network and the name of the network. +type NamedPerNetworkOptions struct { + Name string `json:"name"` + PerNetworkOptions +} + // PerNetworkOptions are options which should be set on a per network basis. type PerNetworkOptions struct { // StaticIPs for this container. Optional. @@ -284,7 +290,7 @@ type NetworkOptions struct { PortMappings []PortMapping `json:"port_mappings,omitempty"` // Networks contains all networks with the PerNetworkOptions. // The map should contain at least one element. - Networks map[string]PerNetworkOptions `json:"networks"` + Networks []NamedPerNetworkOptions `json:"networks"` // List of custom DNS server for podman's DNS resolver. // Priority order will be kept as defined by user in the configuration. DNSServers []string `json:"dns_servers,omitempty"` diff --git a/storage/contrib/cirrus/setup.sh b/storage/contrib/cirrus/setup.sh index 97e79b8521..9c573be341 100755 --- a/storage/contrib/cirrus/setup.sh +++ b/storage/contrib/cirrus/setup.sh @@ -24,5 +24,28 @@ case "$OS_RELEASE_ID" in ;; esac +### HACK HACK HACK: We need to build netavark from source. +case "$OS_RELEASE_ID" in + fedora) + dnf -y install rust cargo + ;; + debian) + DEBIAN_FRONTEND=noninteractive apt install -y rustc cargo + ;; + *) + bad_os_id_ver + ;; +esac +mkdir /usr/local/libexec/podman +cwd=$(pwd) +cd /usr/local/libexec/podman +git clone https://github.com/containers/netavark.git nv +cd nv +make +cp bin/netavark /usr/local/libexec/podman +cd $cwd +rm -rf /usr/local/libexec/nv +### END HACK + install_fuse_overlayfs_from_git install_bats_from_git