Skip to content

Commit

Permalink
Merge 5eedf9f into cf8e93a
Browse files Browse the repository at this point in the history
  • Loading branch information
Levovar committed Nov 13, 2019
2 parents cf8e93a + 5eedf9f commit eaadc39
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 23 deletions.
2 changes: 2 additions & 0 deletions crd/apis/danm/v1/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
&ClusterNetworkList{},
&TenantNetwork{},
&TenantNetworkList{},
&TenantConfig{},
&TenantConfigList{},
)
meta_v1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
Expand Down
98 changes: 75 additions & 23 deletions pkg/confman/confman.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,19 @@ package confman
import (
"errors"
"log"
"strings"
danmtypes "github.com/nokia/danm/crd/apis/danm/v1"
danmclientset "github.com/nokia/danm/crd/client/clientset/versioned"
"github.com/nokia/danm/pkg/bitarray"
"github.com/nokia/danm/pkg/datastructs"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/kubelet/cm/cpuset"
)

const(
TenantConfigKind = "TenantConfig"
)

func GetTenantConfig(danmClient danmclientset.Interface) (*danmtypes.TenantConfig, error) {
reply, err := danmClient.DanmV1().TenantConfigs().List(metav1.ListOptions{})
if err != nil {
Expand All @@ -23,13 +29,36 @@ func GetTenantConfig(danmClient danmclientset.Interface) (*danmtypes.TenantConfi
}

func Reserve(danmClient danmclientset.Interface, tconf *danmtypes.TenantConfig, iface danmtypes.IfaceProfile) (int,error) {
for {
index := getIfaceIndex(tconf, iface.Name, iface.VniType)
if index == -1 {
return 0, errors.New("VNI cannot be reserved because selected interface does not exist. You should call for a tech priest, and start praying to the Omnissiah immediately.")
}
chosenVni, newAlloc, err := reserveVni(tconf.HostDevices[index])
if err != nil {
return 0, err
}
tconf.HostDevices[index].Alloc = newAlloc
newConf, wasRefreshed, err := updateTenantConf(danmClient, tconf)
if err != nil {
return chosenVni, err
}
if wasRefreshed {
tconf = newConf
continue
}
return chosenVni, nil
}
}

func reserveVni(iface danmtypes.IfaceProfile) (int,string,error) {
allocs := bitarray.NewBitArrayFromBase64(iface.Alloc)
if allocs.Len() == 0 {
return 0, errors.New("VNI allocations for interface:" + iface.Name + " is corrupt! Are you running without webhook?")
return 0, "", errors.New("VNI allocations for interface:" + iface.Name + " is corrupt! Are you running without webhook?")
}
vnis, err := cpuset.Parse(iface.VniRange)
if err != nil {
return 0, errors.New("vniRange for interface:" + iface.Name + " cannot be parsed because:" + err.Error())
return 0, "", errors.New("vniRange for interface:" + iface.Name + " cannot be parsed because:" + err.Error())
}
chosenVni := -1
vniSet := vnis.ToSlice()
Expand All @@ -38,23 +67,13 @@ func Reserve(danmClient danmclientset.Interface, tconf *danmtypes.TenantConfig,
continue
}
allocs.Set(uint32(vni))
iface.Alloc = allocs.Encode()
chosenVni = vni
break
}
if chosenVni == -1 {
return 0, errors.New("VNI cannot be allocated from interface profile:" + iface.Name + " because the whole range is already reserved")
return 0, "", errors.New("VNI cannot be allocated from interface profile:" + iface.Name + " because the whole range is already reserved")
}
index := getIfaceIndex(tconf, iface.Name, iface.VniType)
if index == -1 {
return 0, errors.New("VNI cannot be reserved because selected interface does not exist. You should call for a tech priest, and start praying to the Omnissiah immediately.")
}
tconf.HostDevices[index] = iface
//TODO: now, do we actually need to manually check for the OptimisticLockErrorMessage when we use a generated client,
//or that is actually dead code in ipam as well?
//Let's find out!
_, err = danmClient.DanmV1().TenantConfigs().Update(tconf)
return chosenVni, err
return chosenVni, allocs.Encode(), nil
}

func getIfaceIndex(tconf *danmtypes.TenantConfig, name, vniType string) int {
Expand All @@ -80,23 +99,56 @@ func Free(danmClient danmclientset.Interface, tconf *danmtypes.TenantConfig, dne
if dnet.Spec.Options.DevicePool != "" {
ifaceName = dnet.Spec.Options.DevicePool
}
index := getIfaceIndex(tconf,ifaceName,vniType)
if index < 0 {
log.Println("WARNING: There is a data incosistency between TenantNetwork:" + dnet.ObjectMeta.Name + " in namespace:" +
dnet.ObjectMeta.Namespace + " , and TenantConfig:" + tconf.ObjectMeta.Name +
" as the used network details (interface name, VNI type) doe not match any entries in TenantConfig. This means your APIs were possibly tampered with!")
for {
index := getIfaceIndex(tconf,ifaceName,vniType)
if index < 0 {
log.Println("WARNING: There is a data incosistency between TenantNetwork:" + dnet.ObjectMeta.Name + " in namespace:" +
dnet.ObjectMeta.Namespace + " , and TenantConfig:" + tconf.ObjectMeta.Name +
" as the used network details (interface name, VNI type) doe not match any entries in TenantConfig. This means your APIs were possibly tampered with!")
return nil
}
newAlloc, err := freeVni(dnet, tconf.HostDevices[index])
if err != nil {
return err
}
tconf.HostDevices[index].Alloc = newAlloc
newConf, wasRefreshed, err := updateTenantConf(danmClient, tconf)
if err != nil {
return err
}
if wasRefreshed {
tconf = newConf
continue
}
return nil
}
}

func freeVni(dnet *danmtypes.DanmNet, iface danmtypes.IfaceProfile) (string,error) {
vni := dnet.Spec.Options.Vlan
if dnet.Spec.Options.Vxlan != 0 {
vni = dnet.Spec.Options.Vxlan
}
allocs := bitarray.NewBitArrayFromBase64(tconf.HostDevices[index].Alloc)
allocs := bitarray.NewBitArrayFromBase64(iface.Alloc)
if allocs.Len() == 0 {
return errors.New("VNI allocations for interface:" + tconf.HostDevices[index].Name + " is corrupt! Are you running without webhook?")
return "", errors.New("VNI allocations for interface:" + iface.Name + " is corrupt! Are you running without webhook?")
}
allocs.Reset(uint32(vni))
tconf.HostDevices[index].Alloc = allocs.Encode()
return allocs.Encode(), nil
}

func updateTenantConf(danmClient danmclientset.Interface, tconf *danmtypes.TenantConfig) (*danmtypes.TenantConfig,bool,error) {
var wasRefreshed bool
var newConf *danmtypes.TenantConfig
_, err := danmClient.DanmV1().TenantConfigs().Update(tconf)
return err
if err != nil && strings.Contains(err.Error(), datastructs.OptimisticLockErrorMsg) {
newConf, err = danmClient.DanmV1().TenantConfigs().Get(tconf.ObjectMeta.Name, metav1.GetOptions{})
if err != nil {
return nil, wasRefreshed, err
}
//https://github.com/kubernetes/client-go/issues/308 rears its ugly head here as well
newConf.TypeMeta.Kind = TenantConfigKind
wasRefreshed = true
}
return newConf, wasRefreshed, err
}
2 changes: 2 additions & 0 deletions test/uts/confman_test/confman_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ func TestReserve(t *testing.T) {
iface := getIface(tc.ifaceName, tc.vniType, reserveIfaces)
if tc.reserveVnis != nil {
reserveVnis(&iface,tc.reserveVnis)
index, _ := getIfaceFromTconf(tc.ifaceName, tc.vniType, tconf)
tconf.HostDevices[index] = iface
}
testArtifacts := utils.TestArtifacts{TestTconfs: reserveConfs}
tconfClientStub := stubs.NewClientSetStub(testArtifacts)
Expand Down

0 comments on commit eaadc39

Please sign in to comment.