static: prioritize the input sources for IPs
This change introduce priorities for IPs input among CNI_ARGS, 'args' and runtimeConfig. Fix #399. Signed-off-by: Tomofumi Hayashi <tohayash@redhat.com>
This commit is contained in:
parent
411d060b81
commit
2290fc8d8a
@ -60,3 +60,9 @@ The plugin also support following [capability argument](https://github.com/conta
|
|||||||
The following [args conventions](https://github.com/containernetworking/cni/blob/master/CONVENTIONS.md#args-in-network-config) are supported:
|
The following [args conventions](https://github.com/containernetworking/cni/blob/master/CONVENTIONS.md#args-in-network-config) are supported:
|
||||||
|
|
||||||
* `ips` (array of strings): A list of custom IPs to attempt to allocate, with prefix (e.g. '10.10.0.1/24')
|
* `ips` (array of strings): A list of custom IPs to attempt to allocate, with prefix (e.g. '10.10.0.1/24')
|
||||||
|
|
||||||
|
Notice: If some of above are used at same time, only one will work according to the priorities below
|
||||||
|
|
||||||
|
1. [capability argument](https://github.com/containernetworking/cni/blob/master/CONVENTIONS.md)
|
||||||
|
1. [args conventions](https://github.com/containernetworking/cni/blob/master/CONVENTIONS.md#args-in-network-config)
|
||||||
|
1. [CNI_ARGS](https://github.com/containernetworking/cni/blob/master/SPEC.md#parameters)
|
||||||
|
@ -145,11 +145,44 @@ func LoadIPAMConfig(bytes []byte, envArgs string) (*IPAMConfig, string, error) {
|
|||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(n.RuntimeConfig.IPs) != 0 {
|
// load IP from CNI_ARGS
|
||||||
// args IP overwrites IP, so clear IPAM Config
|
if envArgs != "" {
|
||||||
n.IPAM.Addresses = make([]Address, 0, len(n.RuntimeConfig.IPs))
|
e := IPAMEnvArgs{}
|
||||||
for _, addr := range n.RuntimeConfig.IPs {
|
err := types.LoadArgs(envArgs, &e)
|
||||||
n.IPAM.Addresses = append(n.IPAM.Addresses, Address{AddressStr: addr})
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.IP != "" {
|
||||||
|
for _, item := range strings.Split(string(e.IP), ",") {
|
||||||
|
ipstr := strings.TrimSpace(item)
|
||||||
|
|
||||||
|
ip, subnet, err := net.ParseCIDR(ipstr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", fmt.Errorf("invalid CIDR %s: %s", ipstr, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
addr := Address{
|
||||||
|
Address: net.IPNet{IP: ip, Mask: subnet.Mask},
|
||||||
|
AddressStr: ipstr,
|
||||||
|
}
|
||||||
|
n.IPAM.Addresses = append(n.IPAM.Addresses, addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.GATEWAY != "" {
|
||||||
|
for _, item := range strings.Split(string(e.GATEWAY), ",") {
|
||||||
|
gwip := net.ParseIP(strings.TrimSpace(item))
|
||||||
|
if gwip == nil {
|
||||||
|
return nil, "", fmt.Errorf("invalid gateway address: %s", item)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range n.IPAM.Addresses {
|
||||||
|
if n.IPAM.Addresses[i].Address.Contains(gwip) {
|
||||||
|
n.IPAM.Addresses[i].Gateway = gwip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,6 +195,15 @@ func LoadIPAMConfig(bytes []byte, envArgs string) (*IPAMConfig, string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// import address from runtimeConfig
|
||||||
|
if len(n.RuntimeConfig.IPs) != 0 {
|
||||||
|
// runtimeConfig IP overwrites IP, so clear IPAM Config
|
||||||
|
n.IPAM.Addresses = make([]Address, 0, len(n.RuntimeConfig.IPs))
|
||||||
|
for _, addr := range n.RuntimeConfig.IPs {
|
||||||
|
n.IPAM.Addresses = append(n.IPAM.Addresses, Address{AddressStr: addr})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if n.IPAM == nil {
|
if n.IPAM == nil {
|
||||||
return nil, "", fmt.Errorf("IPAM config missing 'ipam' key")
|
return nil, "", fmt.Errorf("IPAM config missing 'ipam' key")
|
||||||
}
|
}
|
||||||
@ -191,50 +233,6 @@ func LoadIPAMConfig(bytes []byte, envArgs string) (*IPAMConfig, string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if envArgs != "" {
|
|
||||||
e := IPAMEnvArgs{}
|
|
||||||
err := types.LoadArgs(envArgs, &e)
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.IP != "" {
|
|
||||||
for _, item := range strings.Split(string(e.IP), ",") {
|
|
||||||
ipstr := strings.TrimSpace(item)
|
|
||||||
|
|
||||||
ip, subnet, err := net.ParseCIDR(ipstr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", fmt.Errorf("invalid CIDR %s: %s", ipstr, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
addr := Address{Address: net.IPNet{IP: ip, Mask: subnet.Mask}}
|
|
||||||
if addr.Address.IP.To4() != nil {
|
|
||||||
addr.Version = "4"
|
|
||||||
numV4++
|
|
||||||
} else {
|
|
||||||
addr.Version = "6"
|
|
||||||
numV6++
|
|
||||||
}
|
|
||||||
n.IPAM.Addresses = append(n.IPAM.Addresses, addr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.GATEWAY != "" {
|
|
||||||
for _, item := range strings.Split(string(e.GATEWAY), ",") {
|
|
||||||
gwip := net.ParseIP(strings.TrimSpace(item))
|
|
||||||
if gwip == nil {
|
|
||||||
return nil, "", fmt.Errorf("invalid gateway address: %s", item)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range n.IPAM.Addresses {
|
|
||||||
if n.IPAM.Addresses[i].Address.Contains(gwip) {
|
|
||||||
n.IPAM.Addresses[i].Gateway = gwip
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CNI spec 0.2.0 and below supported only one v4 and v6 address
|
// CNI spec 0.2.0 and below supported only one v4 and v6 address
|
||||||
if numV4 > 1 || numV6 > 1 {
|
if numV4 > 1 || numV6 > 1 {
|
||||||
for _, v := range types020.SupportedVersions {
|
for _, v := range types020.SupportedVersions {
|
||||||
|
@ -404,6 +404,82 @@ var _ = Describe("static Operations", func() {
|
|||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("allocates and releases multiple addresses with ADD/DEL, from RuntimeConfig/ARGS/CNI_ARGS", func() {
|
||||||
|
const ifname string = "eth0"
|
||||||
|
const nspath string = "/some/where"
|
||||||
|
|
||||||
|
conf := `{
|
||||||
|
"cniVersion": "0.3.1",
|
||||||
|
"name": "mynet",
|
||||||
|
"type": "ipvlan",
|
||||||
|
"master": "foo0",
|
||||||
|
"capabilities": {"ips": true},
|
||||||
|
"ipam": {
|
||||||
|
"type": "static",
|
||||||
|
"routes": [
|
||||||
|
{ "dst": "0.0.0.0/0", "gw": "10.10.0.254" },
|
||||||
|
{ "dst": "3ffe:ffff:0:01ff::1/64",
|
||||||
|
"gw": "3ffe:ffff:0::1" } ],
|
||||||
|
"dns": {
|
||||||
|
"nameservers" : ["8.8.8.8"],
|
||||||
|
"domain": "example.com",
|
||||||
|
"search": [ "example.com" ]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RuntimeConfig": {
|
||||||
|
"ips" : ["10.10.0.1/24", "3ffe:ffff:0:01ff::1/64"]
|
||||||
|
},
|
||||||
|
"args": {
|
||||||
|
"cni": {
|
||||||
|
"ips" : ["10.10.0.2/24", "3ffe:ffff:0:01ff::2/64"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "dummy",
|
||||||
|
Netns: nspath,
|
||||||
|
IfName: ifname,
|
||||||
|
StdinData: []byte(conf),
|
||||||
|
Args: "IP=10.10.0.3/24,11.11.0.3/24;GATEWAY=10.10.0.254",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate the IP
|
||||||
|
r, raw, err := testutils.CmdAddWithArgs(args, func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(strings.Index(string(raw), "\"version\":")).Should(BeNumerically(">", 0))
|
||||||
|
|
||||||
|
result, err := current.GetResult(r)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
// only addresses in runtimeConfig configured because of its priorities
|
||||||
|
Expect(*result.IPs[0]).To(Equal(
|
||||||
|
current.IPConfig{
|
||||||
|
Version: "4",
|
||||||
|
Address: mustCIDR("10.10.0.1/24"),
|
||||||
|
}))
|
||||||
|
Expect(*result.IPs[1]).To(Equal(
|
||||||
|
current.IPConfig{
|
||||||
|
Version: "6",
|
||||||
|
Address: mustCIDR("3ffe:ffff:0:01ff::1/64"),
|
||||||
|
},
|
||||||
|
))
|
||||||
|
Expect(len(result.IPs)).To(Equal(2))
|
||||||
|
Expect(result.Routes).To(Equal([]*types.Route{
|
||||||
|
{Dst: mustCIDR("0.0.0.0/0"), GW: net.ParseIP("10.10.0.254")},
|
||||||
|
{Dst: mustCIDR("3ffe:ffff:0:01ff::1/64"), GW: net.ParseIP("3ffe:ffff:0::1")},
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Release the IP
|
||||||
|
err = testutils.CmdDelWithArgs(args, func() error {
|
||||||
|
return cmdDel(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
func mustCIDR(s string) net.IPNet {
|
func mustCIDR(s string) net.IPNet {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user