mirror of
https://github.com/containers/podman
synced 2024-10-21 01:34:37 +00:00
network create: allow multiple subnets
podman network create --subnet, --gateway and --ip-range can now be specified multiple times to join the network to more than one subnet. This is very useful if you want to use a dual stack network and assign a fixed ipv4 and ipv6 subnet. The order of the options is important here, the first --gateway/--ip-range will be assigned to the first subnet and so on. Signed-off-by: Paul Holzinger <pholzing@redhat.com>
This commit is contained in:
parent
5659b0734c
commit
6961d91206
|
@ -47,13 +47,13 @@ func networkCreateFlags(cmd *cobra.Command) {
|
|||
_ = cmd.RegisterFlagCompletionFunc(optFlagName, completion.AutocompleteNone)
|
||||
|
||||
gatewayFlagName := "gateway"
|
||||
flags.IPVar(&networkCreateOptions.Gateway, gatewayFlagName, nil, "IPv4 or IPv6 gateway for the subnet")
|
||||
flags.IPSliceVar(&networkCreateOptions.Gateways, gatewayFlagName, nil, "IPv4 or IPv6 gateway for the subnet")
|
||||
_ = cmd.RegisterFlagCompletionFunc(gatewayFlagName, completion.AutocompleteNone)
|
||||
|
||||
flags.BoolVar(&networkCreateOptions.Internal, "internal", false, "restrict external access from this network")
|
||||
|
||||
ipRangeFlagName := "ip-range"
|
||||
flags.IPNetVar(&networkCreateOptions.Range, ipRangeFlagName, net.IPNet{}, "allocate container IP from range")
|
||||
flags.StringArrayVar(&networkCreateOptions.Ranges, ipRangeFlagName, nil, "allocate container IP from range")
|
||||
_ = cmd.RegisterFlagCompletionFunc(ipRangeFlagName, completion.AutocompleteNone)
|
||||
|
||||
// TODO consider removing this for 4.0
|
||||
|
@ -72,7 +72,7 @@ func networkCreateFlags(cmd *cobra.Command) {
|
|||
flags.BoolVar(&networkCreateOptions.IPv6, "ipv6", false, "enable IPv6 networking")
|
||||
|
||||
subnetFlagName := "subnet"
|
||||
flags.IPNetVar(&networkCreateOptions.Subnet, subnetFlagName, net.IPNet{}, "subnet in CIDR format")
|
||||
flags.StringArrayVar(&networkCreateOptions.Subnets, subnetFlagName, nil, "subnets in CIDR format")
|
||||
_ = cmd.RegisterFlagCompletionFunc(subnetFlagName, completion.AutocompleteNone)
|
||||
|
||||
flags.BoolVar(&networkCreateOptions.DisableDNS, "disable-dns", false, "disable dns plugin")
|
||||
|
@ -125,27 +125,35 @@ func networkCreate(cmd *cobra.Command, args []string) error {
|
|||
}
|
||||
}
|
||||
|
||||
if networkCreateOptions.Subnet.IP != nil {
|
||||
s := types.Subnet{
|
||||
Subnet: types.IPNet{IPNet: networkCreateOptions.Subnet},
|
||||
Gateway: networkCreateOptions.Gateway,
|
||||
if len(networkCreateOptions.Subnets) > 0 {
|
||||
if len(networkCreateOptions.Gateways) > len(networkCreateOptions.Subnets) {
|
||||
return errors.New("cannot set more gateways than subnets")
|
||||
}
|
||||
if networkCreateOptions.Range.IP != nil {
|
||||
startIP, err := util.FirstIPInSubnet(&networkCreateOptions.Range)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get first ip in range")
|
||||
}
|
||||
lastIP, err := util.LastIPInSubnet(&networkCreateOptions.Range)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get last ip in range")
|
||||
}
|
||||
s.LeaseRange = &types.LeaseRange{
|
||||
StartIP: startIP,
|
||||
EndIP: lastIP,
|
||||
}
|
||||
if len(networkCreateOptions.Ranges) > len(networkCreateOptions.Subnets) {
|
||||
return errors.New("cannot set more ranges than subnets")
|
||||
}
|
||||
network.Subnets = append(network.Subnets, s)
|
||||
} else if networkCreateOptions.Range.IP != nil || networkCreateOptions.Gateway != nil {
|
||||
|
||||
for i := range networkCreateOptions.Subnets {
|
||||
subnet, err := types.ParseCIDR(networkCreateOptions.Subnets[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s := types.Subnet{
|
||||
Subnet: subnet,
|
||||
}
|
||||
if len(networkCreateOptions.Ranges) > i {
|
||||
leaseRange, err := parseRange(networkCreateOptions.Ranges[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.LeaseRange = leaseRange
|
||||
}
|
||||
if len(networkCreateOptions.Gateways) > i {
|
||||
s.Gateway = networkCreateOptions.Gateways[i]
|
||||
}
|
||||
network.Subnets = append(network.Subnets, s)
|
||||
}
|
||||
} else if len(networkCreateOptions.Ranges) > 0 || len(networkCreateOptions.Gateways) > 0 {
|
||||
return errors.New("cannot set gateway or range without subnet")
|
||||
}
|
||||
|
||||
|
@ -156,3 +164,23 @@ func networkCreate(cmd *cobra.Command, args []string) error {
|
|||
fmt.Println(response.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseRange(iprange string) (*types.LeaseRange, error) {
|
||||
_, subnet, err := net.ParseCIDR(iprange)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
startIP, err := util.FirstIPInSubnet(subnet)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get first ip in range")
|
||||
}
|
||||
lastIP, err := util.LastIPInSubnet(subnet)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get last ip in range")
|
||||
}
|
||||
return &types.LeaseRange{
|
||||
StartIP: startIP,
|
||||
EndIP: lastIP,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -46,7 +46,8 @@ The `macvlan` and `ipvlan` driver support the following options:
|
|||
#### **--gateway**
|
||||
|
||||
Define a gateway for the subnet. If you want to provide a gateway address, you must also provide a
|
||||
*subnet* option.
|
||||
*subnet* option. Can be specified multiple times.
|
||||
The argument order of the **--subnet**, **--gateway** and **--ip-range** options must match.
|
||||
|
||||
#### **--internal**
|
||||
|
||||
|
@ -56,7 +57,8 @@ automatically disabled.
|
|||
#### **--ip-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.
|
||||
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.
|
||||
|
||||
#### **--label**
|
||||
|
||||
|
@ -64,11 +66,13 @@ Set metadata for a network (e.g., --label mykey=value).
|
|||
|
||||
#### **--subnet**
|
||||
|
||||
The subnet in CIDR notation.
|
||||
The subnet in CIDR notation. Can be specified multiple times to allocate more than one subnet for this network.
|
||||
The argument order of the **--subnet**, **--gateway** and **--ip-range** options must match.
|
||||
This is useful to set a static ipv4 and ipv6 subnet.
|
||||
|
||||
#### **--ipv6**
|
||||
|
||||
Enable IPv6 (Dual Stack) networking.
|
||||
Enable IPv6 (Dual Stack) networking. If not subnets are given it will allocate a ipv4 and ipv6 subnet.
|
||||
|
||||
## EXAMPLE
|
||||
|
||||
|
@ -102,6 +106,12 @@ $ podman network create --subnet 192.168.55.0/24 --ip-range 192.168.55.128/25
|
|||
cni-podman5
|
||||
```
|
||||
|
||||
Create a network with a static ipv4 and ipv6 subnet and set a gateway.
|
||||
```
|
||||
$ podman network create --subnet 192.168.55.0/24 --gateway 192.168.55.3 --subnet fd52:2a5a:747e:3acd::/64 --gateway fd52:2a5a:747e:3acd::10
|
||||
podman4
|
||||
```
|
||||
|
||||
Create a Macvlan based network using the host interface eth0. Macvlan networks can only be used as root.
|
||||
```
|
||||
# podman network create -d macvlan -o parent=eth0 newnet
|
||||
|
|
|
@ -43,12 +43,12 @@ type NetworkRmReport struct {
|
|||
type NetworkCreateOptions struct {
|
||||
DisableDNS bool
|
||||
Driver string
|
||||
Gateway net.IP
|
||||
Gateways []net.IP
|
||||
Internal bool
|
||||
Labels map[string]string
|
||||
MacVLAN string
|
||||
Range net.IPNet
|
||||
Subnet net.IPNet
|
||||
Ranges []string
|
||||
Subnets []string
|
||||
IPv6 bool
|
||||
// Mapping of driver options and values.
|
||||
Options map[string]string
|
||||
|
|
|
@ -356,4 +356,82 @@ var _ = Describe("Podman network create", func() {
|
|||
}
|
||||
})
|
||||
|
||||
It("podman network create with multiple subnets", func() {
|
||||
name := "subnets-" + stringid.GenerateNonCryptoID()
|
||||
subnet1 := "10.10.0.0/24"
|
||||
subnet2 := "10.10.1.0/24"
|
||||
nc := podmanTest.Podman([]string{"network", "create", "--subnet", subnet1, "--subnet", subnet2, name})
|
||||
nc.WaitWithDefaultTimeout()
|
||||
defer podmanTest.removeCNINetwork(name)
|
||||
Expect(nc).To(Exit(0))
|
||||
Expect(nc.OutputToString()).To(Equal(name))
|
||||
|
||||
inspect := podmanTest.Podman([]string{"network", "inspect", name})
|
||||
inspect.WaitWithDefaultTimeout()
|
||||
Expect(inspect).To(Exit(0))
|
||||
Expect(inspect.OutputToString()).To(ContainSubstring(`"subnet": "` + subnet1))
|
||||
Expect(inspect.OutputToString()).To(ContainSubstring(`"subnet": "` + subnet2))
|
||||
Expect(inspect.OutputToString()).To(ContainSubstring(`"ipv6_enabled": false`))
|
||||
})
|
||||
|
||||
It("podman network create with multiple subnets dual stack", func() {
|
||||
name := "subnets-" + stringid.GenerateNonCryptoID()
|
||||
subnet1 := "10.10.2.0/24"
|
||||
subnet2 := "fd52:2a5a:747e:3acd::/64"
|
||||
nc := podmanTest.Podman([]string{"network", "create", "--subnet", subnet1, "--subnet", subnet2, name})
|
||||
nc.WaitWithDefaultTimeout()
|
||||
defer podmanTest.removeCNINetwork(name)
|
||||
Expect(nc).To(Exit(0))
|
||||
Expect(nc.OutputToString()).To(Equal(name))
|
||||
|
||||
inspect := podmanTest.Podman([]string{"network", "inspect", name})
|
||||
inspect.WaitWithDefaultTimeout()
|
||||
Expect(inspect).To(Exit(0))
|
||||
Expect(inspect.OutputToString()).To(ContainSubstring(`"subnet": "` + subnet1))
|
||||
Expect(inspect.OutputToString()).To(ContainSubstring(`"subnet": "` + subnet2))
|
||||
Expect(inspect.OutputToString()).To(ContainSubstring(`"ipv6_enabled": true`))
|
||||
})
|
||||
|
||||
It("podman network create with multiple subnets dual stack with gateway and range", func() {
|
||||
name := "subnets-" + stringid.GenerateNonCryptoID()
|
||||
subnet1 := "10.10.3.0/24"
|
||||
gw1 := "10.10.3.10"
|
||||
range1 := "10.10.3.0/26"
|
||||
subnet2 := "fd52:2a5a:747e:3acd::/64"
|
||||
gw2 := "fd52:2a5a:747e:3acd::10"
|
||||
nc := podmanTest.Podman([]string{"network", "create", "--subnet", subnet1, "--gateway", gw1, "--ip-range", range1, "--subnet", subnet2, "--gateway", gw2, name})
|
||||
nc.WaitWithDefaultTimeout()
|
||||
defer podmanTest.removeCNINetwork(name)
|
||||
Expect(nc).To(Exit(0))
|
||||
Expect(nc.OutputToString()).To(Equal(name))
|
||||
|
||||
inspect := podmanTest.Podman([]string{"network", "inspect", name})
|
||||
inspect.WaitWithDefaultTimeout()
|
||||
Expect(inspect).To(Exit(0))
|
||||
Expect(inspect.OutputToString()).To(ContainSubstring(`"subnet": "` + subnet1))
|
||||
Expect(inspect.OutputToString()).To(ContainSubstring(`"gateway": "` + gw1))
|
||||
Expect(inspect.OutputToString()).To(ContainSubstring(`"start_ip": "10.10.3.1",`))
|
||||
Expect(inspect.OutputToString()).To(ContainSubstring(`"end_ip": "10.10.3.63"`))
|
||||
Expect(inspect.OutputToString()).To(ContainSubstring(`"subnet": "` + subnet2))
|
||||
Expect(inspect.OutputToString()).To(ContainSubstring(`"gateway": "` + gw2))
|
||||
Expect(inspect.OutputToString()).To(ContainSubstring(`"ipv6_enabled": true`))
|
||||
})
|
||||
|
||||
It("podman network create invalid options with multiple subnets", func() {
|
||||
name := "subnets-" + stringid.GenerateNonCryptoID()
|
||||
subnet1 := "10.10.3.0/24"
|
||||
gw1 := "10.10.3.10"
|
||||
gw2 := "fd52:2a5a:747e:3acd::10"
|
||||
nc := podmanTest.Podman([]string{"network", "create", "--subnet", subnet1, "--gateway", gw1, "--gateway", gw2, name})
|
||||
nc.WaitWithDefaultTimeout()
|
||||
Expect(nc).To(Exit(125))
|
||||
Expect(nc.ErrorToString()).To(Equal("Error: cannot set more gateways than subnets"))
|
||||
|
||||
range1 := "10.10.3.0/26"
|
||||
range2 := "10.10.3.0/28"
|
||||
nc = podmanTest.Podman([]string{"network", "create", "--subnet", subnet1, "--ip-range", range1, "--ip-range", range2, name})
|
||||
nc.WaitWithDefaultTimeout()
|
||||
Expect(nc).To(Exit(125))
|
||||
Expect(nc.ErrorToString()).To(Equal("Error: cannot set more ranges than subnets"))
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue