Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various CNI delegation corrections related to framework bump, and central IPAM support #123

Merged
merged 2 commits into from
Aug 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/danm/danm.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (

func main() {
var err error
f, err := os.OpenFile("/var/log/plugin.log", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0640)
f, err := os.OpenFile("/var/log/danm.log", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0640)
if err == nil {
log.SetOutput(f)
defer f.Close()
Expand Down
2 changes: 1 addition & 1 deletion cmd/fakeipam/fakeipam.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func reserveIp(args *skel.CmdArgs) error {
cniRes,err := createCniResult(ipamConf)
if err != nil {
return err
}
}
return cniRes.Print()
}

Expand Down
1 change: 1 addition & 0 deletions integration/cni_config/00-danm.conf
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"cniVersion": "0.3.1",
"name": "meta_cni",
"name_comment": "Mandatory parameter, but can be anything",
"type": "danm",
Expand Down
41 changes: 28 additions & 13 deletions pkg/cnidel/cnidel.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/nokia/danm/pkg/danmep"
"github.com/nokia/danm/pkg/datastructs"
"github.com/nokia/danm/pkg/ipam"
"github.com/nokia/danm/pkg/netcontrol"
danmtypes "github.com/nokia/danm/crd/apis/danm/v1"
danmclientset "github.com/nokia/danm/crd/client/clientset/versioned"
)
Expand Down Expand Up @@ -50,14 +51,14 @@ func DelegateInterfaceSetup(netConf *datastructs.NetConf, danmClient danmclients
ipamOptions datastructs.IpamConfig
)
if isIpamNeeded(netInfo, ep) {
ep.Spec.Iface.Address, ep.Spec.Iface.AddressIPv6, _, err = ipam.Reserve(danmClient, *netInfo, ep.Spec.Iface.Address, ep.Spec.Iface.AddressIPv6)
ep.Spec.Iface.Address, ep.Spec.Iface.AddressIPv6, _, err = ipam.Reserve(danmClient, *netInfo, ep.Spec.Iface.Address, ep.Spec.Iface.AddressIPv6)
if err != nil {
return nil, errors.New("IP address reservation failed for network:" + netInfo.ObjectMeta.Name + " with error:" + err.Error())
}
//TODO: as netInfo is only copied to IPAM above, the IP allocation is not refreshed in the original copy.
//Therefore, anyone wishing to further update the same network object later on will use an outdated representation as the input.
//IPAM should be refactored to always pass back the up-to-date object.
//I guess it is okay now because we only want to free IPs, and RV differences are resolved by the generated client code.
//As netInfo is only copied to IPAM above, the IP allocation is not refreshed in the original copy.
//Without re-reading the network body we risk leaking IPs if error happens later on within the same thread!
netInfo,err = netcontrol.GetNetworkFromEp(danmClient, *ep)
if err != nil {log.Println("lofasz:" + err.Error())}
ipamOptions = getCniIpamConfig(netInfo, ep.Spec.Iface.Address, ep.Spec.Iface.AddressIPv6)
}
rawConfig, err := getCniPluginConfig(netConf, netInfo, ipamOptions, ep)
Expand Down Expand Up @@ -185,7 +186,15 @@ func setEpIfaceAddress(cniResult *current.Result, epIface *danmtypes.DanmEpIface
// DelegateInterfaceDelete delegates Ks8 Pod network interface delete task to the input 3rd party CNI plugin
// Returns an error if interface creation was unsuccessful, or if the 3rd party CNI config could not be loaded
func DelegateInterfaceDelete(netConf *datastructs.NetConf, danmClient danmclientset.Interface, netInfo *danmtypes.DanmNet, ep *danmtypes.DanmEp) error {
rawConfig, err := getCniPluginConfig(netConf, netInfo, datastructs.IpamConfig{Type: ipamType}, ep)
var ip4, ip6 string
if wasIpAllocatedByDanm(ep.Spec.Iface.Address, netInfo.Spec.Options.Cidr) {
ip4 = ep.Spec.Iface.Address
}
if wasIpAllocatedByDanm(ep.Spec.Iface.AddressIPv6, netInfo.Spec.Options.Net6) {
ip6 = ep.Spec.Iface.AddressIPv6
}
ipamForDelete := getCniIpamConfig(netInfo, ip4, ip6)
rawConfig, err := getCniPluginConfig(netConf, netInfo, ipamForDelete, ep)
if err != nil {
FreeDelegatedIps(danmClient, netInfo, ep.Spec.Iface.Address, ep.Spec.Iface.AddressIPv6)
return err
Expand All @@ -212,14 +221,8 @@ func freeDelegatedIp(danmClient danmclientset.Interface, netInfo *danmtypes.Danm
if netInfo.Spec.NetworkType == "flannel" && ip != ""{
flannelIpExhaustionWorkaround(ip)
}
_, v4Subnet, _ := net.ParseCIDR(netInfo.Spec.Options.Cidr)
_, v6Subnet, _ := net.ParseCIDR(netInfo.Spec.Options.Net6)
parsedIp := net.ParseIP(ip)
if parsedIp == nil {
parsedIp,_,_ = net.ParseCIDR(ip)
}
//We only need to Free an IP if it was allocated by DANM IPAM, and it was allocated by DANM only if it falls into any of the defined subnets
if parsedIp != nil && ((v4Subnet != nil && v4Subnet.Contains(parsedIp)) || (v6Subnet != nil && v6Subnet.Contains(parsedIp))) {
if wasIpAllocatedByDanm(ip, netInfo.Spec.Options.Cidr) || wasIpAllocatedByDanm(ip, netInfo.Spec.Options.Net6) {
err := ipam.Free(danmClient, *netInfo, ip)
if err != nil {
return errors.New("cannot give back ip address: " + ip + " for network:" + netInfo.ObjectMeta.Name +
Expand All @@ -229,6 +232,18 @@ func freeDelegatedIp(danmClient danmclientset.Interface, netInfo *danmtypes.Danm
return nil
}

func wasIpAllocatedByDanm(ip, cidr string) bool {
_, subnet, _ := net.ParseCIDR(cidr)
parsedIp := net.ParseIP(ip)
if parsedIp == nil {
parsedIp,_,_ = net.ParseCIDR(ip)
}
if parsedIp != nil && (subnet != nil && subnet.Contains(parsedIp)) {
return true
}
return false
}

// Host-local IPAM management plugin uses disk-local Store by default.
// Right now it is buggy in a sense that it does not try to free IPs if the container being deleted does not exist already.
// But it should!
Expand Down
2 changes: 1 addition & 1 deletion pkg/datastructs/datastructs.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const (
)

var (
SupportedCniVersions = version.PluginSupports("0.1.0", "0.2.0", "0.3.0", "0.3.1")
SupportedCniVersions = version.PluginSupports("0.3.1")
)

type NetConf struct {
Expand Down
3 changes: 3 additions & 0 deletions pkg/metacni/metacni.go
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,9 @@ func createDanmInterface(syncher *syncher.Syncher, danmClient danmclientset.Inte
syncher.PushResult(netInfo.ObjectMeta.Name, errors.New("IP address reservation failed for network:" + netInfo.ObjectMeta.Name + " with error:" + err.Error()), nil)
return
}
//As netInfo is only copied to IPAM above, the IP allocation is not refreshed in the original copy.
//Without re-reading the network body we risk leaking IPs if an error happens later on within the same thread!
netInfo,_ = netcontrol.GetNetworkFromInterface(danmClient, iface, netInfo.ObjectMeta.Namespace)
epSpec := danmtypes.DanmEpIface {
Name: cnidel.CalculateIfaceName(DanmConfig.NamingScheme, netInfo.Spec.Options.Prefix, iface.DefaultIfaceName, iface.SequenceId),
Address: ip4,
Expand Down
15 changes: 9 additions & 6 deletions test/stubs/danm/netclient_stub.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,20 @@ func (netClient *NetClientStub) Update(obj *danmtypes.DanmNet) (*danmtypes.DanmN
}
}
}
if strings.Contains(obj.Spec.NetworkID, "conflict") && obj.ObjectMeta.ResourceVersion != magicVersion {
for index, net := range netClient.TestNets {
if net.Spec.NetworkID == obj.Spec.NetworkID {
netClient.TestNets[index].ObjectMeta.ResourceVersion = magicVersion
}
var netIndex int
for index, net := range netClient.TestNets {
if net.ObjectMeta.Name == obj.ObjectMeta.Name {
netIndex = index
}
}
if strings.Contains(obj.Spec.NetworkID, "conflict") && obj.ObjectMeta.ResourceVersion != magicVersion {
netClient.TestNets[netIndex].ObjectMeta.ResourceVersion = magicVersion
return nil, errors.New(datastructs.OptimisticLockErrorMsg)
}
if strings.Contains(obj.Spec.NetworkID, "error") {
return nil, errors.New("fatal error, don't retry")
}
netClient.TestNets[netIndex] = *obj
return obj, nil
}

Expand All @@ -84,7 +87,7 @@ func (netClient *NetClientStub) Get(netName string, options meta_v1.GetOptions)
return nil, errors.New("fatal error, don't retry")
}
for _, testNet := range netClient.TestNets {
if testNet.Spec.NetworkID == netName {
if testNet.ObjectMeta.Name == netName {
return &testNet, nil
}
}
Expand Down
Loading