From e292748534939879e926f3f2c6f76b4f6d459ed1 Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Fri, 16 Jun 2023 17:51:09 +0200 Subject: [PATCH] network create --ip-range allow for custom range The backend allows for any start/end ip in the subnet. There is no reason to limit the cli to only CIDR subnets. This allows for much more flexibility. Signed-off-by: Paul Holzinger --- cmd/podman/networks/create.go | 17 +++++++++ .../markdown/podman-network-create.1.md | 5 ++- docs/source/markdown/podman-systemd.unit.5.md | 4 +- test/e2e/network_create_test.go | 37 +++++++++++++++++++ 4 files changed, 60 insertions(+), 3 deletions(-) diff --git a/cmd/podman/networks/create.go b/cmd/podman/networks/create.go index 98f31f5f39..4998462602 100644 --- a/cmd/podman/networks/create.go +++ b/cmd/podman/networks/create.go @@ -245,6 +245,23 @@ func parseRoute(routeStr string) (*types.Route, error) { } func parseRange(iprange string) (*types.LeaseRange, error) { + split := strings.SplitN(iprange, "-", 2) + if len(split) > 1 { + // range contains dash so assume form is start-end + start := net.ParseIP(split[0]) + if start == nil { + return nil, fmt.Errorf("range start ip %q is not a ip address", split[0]) + } + end := net.ParseIP(split[1]) + if end == nil { + return nil, fmt.Errorf("range end ip %q is not a ip address", split[1]) + } + return &types.LeaseRange{ + StartIP: start, + EndIP: end, + }, nil + } + // no dash, so assume CIDR is given _, subnet, err := net.ParseCIDR(iprange) if err != nil { return nil, err diff --git a/docs/source/markdown/podman-network-create.1.md b/docs/source/markdown/podman-network-create.1.md index bb9df1c333..3a8728423a 100644 --- a/docs/source/markdown/podman-network-create.1.md +++ b/docs/source/markdown/podman-network-create.1.md @@ -66,8 +66,9 @@ Restrict external access of this network. Note when using this option, the dnsna #### **--ip-range**=*range* -Allocate container IP from a range. The range must be a complete subnet and in CIDR notation. The *ip-range* option -must be used with a *subnet* option. Can be specified multiple times. +Allocate container IP from a range. The range must be a either a complete subnet in CIDR notation or be in +the `-` syntax which allows for a more flexible range compared to the CIDR subnet. +The *ip-range* option must be used with a *subnet* option. Can be specified multiple times. The argument order of the **--subnet**, **--gateway** and **--ip-range** options must match. #### **--ipam-driver**=*driver* diff --git a/docs/source/markdown/podman-systemd.unit.5.md b/docs/source/markdown/podman-systemd.unit.5.md index 945dbb0b4b..5211b7f745 100644 --- a/docs/source/markdown/podman-systemd.unit.5.md +++ b/docs/source/markdown/podman-systemd.unit.5.md @@ -680,7 +680,9 @@ This is equivalent to the Podman `--ipam-driver` option ### `IPRange=` -Allocate container IP from a range. The range must be a complete subnet and in CIDR notation. The ip-range option must be used with a subnet option. +Allocate container IP from a range. The range must be a either a complete subnet in CIDR notation or be +in the `-` syntax which allows for a more flexible range compared to the CIDR subnet. +The ip-range option must be used with a subnet option. This is equivalent to the Podman `--ip-range` option diff --git a/test/e2e/network_create_test.go b/test/e2e/network_create_test.go index 84a98da72c..b7e42703b1 100644 --- a/test/e2e/network_create_test.go +++ b/test/e2e/network_create_test.go @@ -696,4 +696,41 @@ var _ = Describe("Podman network create", func() { Expect(bridge.Name).To(Equal(bridgeName)) } }) + + It("podman network create --ip-range sip-eip", func() { + netName := "subnet-" + stringid.GenerateRandomID() + nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.16.0/24", "--ip-range", "10.11.16.11-10.11.16.12", netName}) + nc.WaitWithDefaultTimeout() + defer podmanTest.removeNetwork(netName) + Expect(nc).Should(Exit(0)) + + // 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).ToNot(HaveOccurred()) + Expect(results).To(HaveLen(1)) + result := results[0] + Expect(result).To(HaveField("Name", netName)) + Expect(result.Subnets).To(HaveLen(1)) + Expect(result.Subnets[0].Subnet.String()).To(Equal("10.11.16.0/24")) + Expect(result.Subnets[0].Gateway.String()).To(Equal("10.11.16.1")) + Expect(result.Subnets[0].LeaseRange).ToNot(BeNil()) + Expect(result.Subnets[0].LeaseRange.StartIP.String()).To(Equal("10.11.16.11")) + Expect(result.Subnets[0].LeaseRange.EndIP.String()).To(Equal("10.11.16.12")) + + try := podmanTest.Podman([]string{"run", "--rm", "--network", netName, ALPINE, "sh", "-c", "ip addr show eth0 | awk ' /inet / {print $2}'"}) + try.WaitWithDefaultTimeout() + Expect(try).To(Exit(0)) + + containerIP, _, err := net.ParseCIDR(try.OutputToString()) + Expect(err).ToNot(HaveOccurred()) + // Note as of today (June 2023) we always get the first ip from netavark and cni but let's not depend on that. + // All we care about is the ip is from the range which allows for both. + Expect(containerIP.String()).To(Or(Equal("10.11.16.11"), Equal("10.11.16.12")), "ip address must be in --ip-range") + }) })