Skip to content

Commit e439ddd

Browse files
committed
100% coverage achieved for the whole package... and not just statement-wise
1 parent c173274 commit e439ddd

5 files changed

Lines changed: 163 additions & 55 deletions

File tree

pkg/ipam/ipam.go

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,14 @@ import (
99
"time"
1010
"math/big"
1111
"math/rand"
12+
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1213
danmtypes "github.com/nokia/danm/crd/apis/danm/v1"
1314
danmclientset "github.com/nokia/danm/crd/client/clientset/versioned"
14-
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
15+
client "github.com/nokia/danm/crd/client/clientset/versioned/typed/danm/v1"
1516
"github.com/nokia/danm/pkg/netcontrol"
1617
"github.com/nokia/danm/pkg/bitarray"
1718
)
1819

19-
const (
20-
backOffTimer = 50
21-
)
22-
2320
// Reserve inspects the DanmNet object received as an input, and allocates an IPv4 or IPv6 address from the appropriate allocation pool
2421
// In case static IP allocation is requested, it will try reserver the requested error. If it is not possible, it returns an error
2522
// The reserved IP address is represented by setting a bit in the network's BitArray type allocation matrix
@@ -29,12 +26,13 @@ func Reserve(danmClient danmclientset.Interface, netInfo danmtypes.DanmNet, req4
2926
return "", "", "", errors.New("Invalid network: " + netInfo.Spec.NetworkID)
3027
}
3128
tempNetSpec := netInfo
29+
netClient := danmClient.DanmV1().DanmNets(netInfo.ObjectMeta.Namespace)
3230
for {
3331
ip4, ip6, macAddr, err := allocateIP(&tempNetSpec, req4, req6)
3432
if err != nil {
3533
return "", "", "", errors.New("failed to allocate IP address for network:" + netInfo.Spec.NetworkID + " with error:" + err.Error())
3634
}
37-
retryNeeded, err, newNetSpec := updateDanmNetAllocation(danmClient, tempNetSpec)
35+
retryNeeded, err, newNetSpec := updateDanmNetAllocation(netClient, tempNetSpec)
3836
if err != nil {
3937
return "", "", "", err
4038
}
@@ -55,9 +53,10 @@ func Free(danmClient danmclientset.Interface, netInfo danmtypes.DanmNet, ip stri
5553
return nil
5654
}
5755
tempNetSpec := netInfo
56+
netClient := danmClient.DanmV1().DanmNets(netInfo.ObjectMeta.Namespace)
5857
for {
5958
resetIP(&tempNetSpec, ip)
60-
retryNeeded, err, newNetSpec := updateDanmNetAllocation(danmClient, tempNetSpec)
59+
retryNeeded, err, newNetSpec := updateDanmNetAllocation(netClient, tempNetSpec)
6160
if err != nil {
6261
return err
6362
}
@@ -69,18 +68,15 @@ func Free(danmClient danmclientset.Interface, netInfo danmtypes.DanmNet, ip stri
6968
}
7069
}
7170

72-
func updateDanmNetAllocation (danmClient danmclientset.Interface, netInfo danmtypes.DanmNet) (bool,error,danmtypes.DanmNet) {
73-
resourceConflicted, err := netcontrol.PutDanmNet(danmClient, &netInfo)
71+
func updateDanmNetAllocation (netClient client.DanmNetInterface, netInfo danmtypes.DanmNet) (bool,error,danmtypes.DanmNet) {
72+
resourceConflicted, err := netcontrol.PutDanmNet(netClient, &netInfo)
7473
if err != nil {
7574
return false, errors.New("DanmNet update failed with error:" + err.Error()), danmtypes.DanmNet{}
7675
}
7776
if resourceConflicted {
78-
//Randomizing backoff time to decrease the possibility of conflicts
79-
randomBackoff := rand.Intn(backOffTimer)
80-
time.Sleep(time.Duration(randomBackoff) * time.Millisecond)
81-
newNetSpec, err := danmClient.DanmV1().DanmNets(netInfo.ObjectMeta.Namespace).Get(netInfo.Spec.NetworkID, meta_v1.GetOptions{})
77+
newNetSpec, err := netClient.Get(netInfo.Spec.NetworkID, meta_v1.GetOptions{})
8278
if err != nil {
83-
return false, errors.New("After IP address reservation conflict, network cannot be read again!"), danmtypes.DanmNet{}
79+
return false, errors.New("After IP address reservation conflict, network cannot be read again!"), danmtypes.DanmNet{}
8480
}
8581
return true, nil, *newNetSpec
8682
}
@@ -92,8 +88,16 @@ func resetIP(netInfo *danmtypes.DanmNet, rip string) {
9288
ba := bitarray.NewBitArrayFromBase64(netInfo.Spec.Options.Alloc)
9389
_, ipnet, _ := net.ParseCIDR(netInfo.Spec.Options.Cidr)
9490
ipnetNum := netcontrol.Ip2int(ipnet.IP)
95-
ip, _, _ := net.ParseCIDR(rip)
91+
ip, _, err := net.ParseCIDR(rip)
92+
if err != nil {
93+
//Invalid IP, nothing to do here. Next call would crash if we wouldn't return
94+
return
95+
}
9696
reserved := netcontrol.Ip2int(ip)
97+
if !ipnet.Contains(ip) {
98+
//IP is outside of CIDR, nothing to do here. Next call would crash if we wouldn't return
99+
return
100+
}
97101
ba.Reset(reserved - ipnetNum)
98102
netInfo.Spec.Options.Alloc = ba.Encode()
99103
}

pkg/netcontrol/netcontrol.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"k8s.io/client-go/rest"
99
"k8s.io/client-go/tools/cache"
1010
danmtypes "github.com/nokia/danm/crd/apis/danm/v1"
11+
client "github.com/nokia/danm/crd/client/clientset/versioned/typed/danm/v1"
1112
danmclientset "github.com/nokia/danm/crd/client/clientset/versioned"
1213
danminformers "github.com/nokia/danm/crd/client/informers/externalversions"
1314
)
@@ -47,9 +48,9 @@ func (dnetHandler Handler) CreateController() cache.Controller {
4748
return controller
4849
}
4950

50-
func PutDanmNet(client danmclientset.Interface, dnet *danmtypes.DanmNet) (bool,error) {
51+
func PutDanmNet(client client.DanmNetInterface, dnet *danmtypes.DanmNet) (bool,error) {
5152
var wasResourceAlreadyUpdated bool = false
52-
_, err := client.DanmV1().DanmNets(dnet.Namespace).Update(dnet)
53+
_, err := client.Update(dnet)
5354
if err != nil {
5455
if strings.Contains(err.Error(),danmtypes.OptimisticLockErrorMsg) {
5556
wasResourceAlreadyUpdated = true
@@ -87,7 +88,8 @@ func addDanmNet(client danmclientset.Interface, dn danmtypes.DanmNet) {
8788
}
8889

8990
func updateValidity(client danmclientset.Interface, dn *danmtypes.DanmNet) {
90-
updateConflicted, err := PutDanmNet(client, dn)
91+
netClient := client.DanmV1().DanmNets(dn.ObjectMeta.Namespace)
92+
updateConflicted, err := PutDanmNet(netClient, dn)
9193
if err != nil {
9294
log.Println("ERROR: Cannot update network:" + dn.Spec.NetworkID + ",err:" + err.Error())
9395
}

test/stubs/clientset_stub.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@ type ClientSetStub struct {
1212

1313
type ReservedIpsList struct {
1414
NetworkId string
15-
Ips []string
15+
Reservations []Reservation
16+
}
17+
18+
type Reservation struct {
19+
Ip string
20+
Set bool
1621
}
1722

1823
func (c *ClientSetStub) DanmV1() danmv1.DanmV1Interface {

test/stubs/netclient_stub.go

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,53 +3,81 @@ package stubs
33
import (
44
"errors"
55
"net"
6+
"strings"
67
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
78
types "k8s.io/apimachinery/pkg/types"
89
watch "k8s.io/apimachinery/pkg/watch"
910
danmtypes "github.com/nokia/danm/crd/apis/danm/v1"
1011
"github.com/nokia/danm/pkg/bitarray"
1112
"github.com/nokia/danm/pkg/netcontrol"
1213
)
14+
const (
15+
magicVersion = "42"
16+
)
1317

1418
type NetClientStub struct{
1519
testNets []danmtypes.DanmNet
1620
reservedIpsList []ReservedIpsList
1721
}
1822

19-
func newNetClientStub(nets []danmtypes.DanmNet, ips []ReservedIpsList) NetClientStub {
20-
return NetClientStub{testNets: nets, reservedIpsList: ips}
23+
func newNetClientStub(nets []danmtypes.DanmNet, ips []ReservedIpsList) *NetClientStub {
24+
return &NetClientStub{testNets: nets, reservedIpsList: ips}
2125
}
2226

23-
func (netClient NetClientStub) Create(obj *danmtypes.DanmNet) (*danmtypes.DanmNet, error) {
27+
func (netClient *NetClientStub) Create(obj *danmtypes.DanmNet) (*danmtypes.DanmNet, error) {
2428
return nil, nil
2529
}
2630

27-
func (netClient NetClientStub) Update(obj *danmtypes.DanmNet) (*danmtypes.DanmNet, error) {
28-
for _, reservation := range netClient.reservedIpsList {
29-
if obj.Spec.NetworkID == reservation.NetworkId {
31+
func (netClient *NetClientStub) Update(obj *danmtypes.DanmNet) (*danmtypes.DanmNet, error) {
32+
for _, netReservation := range netClient.reservedIpsList {
33+
if obj.Spec.NetworkID == netReservation.NetworkId {
3034
ba := bitarray.NewBitArrayFromBase64(obj.Spec.Options.Alloc)
3135
_, ipnet, _ := net.ParseCIDR(obj.Spec.Options.Cidr)
3236
ipnetNum := netcontrol.Ip2int(ipnet.IP)
33-
for _, ipToBeChecked := range reservation.Ips {
34-
ipInInt := netcontrol.Ip2int(net.ParseIP(ipToBeChecked)) - ipnetNum
35-
if !ba.Get(uint32(ipInInt)) {
36-
return nil, errors.New("Reservation failure, IP:" + ipToBeChecked + " must be reserved in DanmNet:" + obj.Spec.NetworkID)
37+
for _, reservation := range netReservation.Reservations {
38+
ip,_,err := net.ParseCIDR(reservation.Ip)
39+
if err != nil {
40+
continue
41+
}
42+
ipInInt := netcontrol.Ip2int(ip) - ipnetNum
43+
if !ipnet.Contains(ip) {
44+
continue
45+
}
46+
if !ba.Get(uint32(ipInInt)) && reservation.Set {
47+
return nil, errors.New("Reservation failure, IP:" + reservation.Ip + " must be reserved in DanmNet:" + obj.Spec.NetworkID)
48+
}
49+
if ba.Get(uint32(ipInInt)) && !reservation.Set {
50+
return nil, errors.New("Reservation failure, IP:" + reservation.Ip + " must be free in DanmNet:" + obj.Spec.NetworkID)
3751
}
3852
}
3953
}
4054
}
55+
if strings.Contains(obj.Spec.NetworkID, "conflict") && obj.ObjectMeta.ResourceVersion != magicVersion {
56+
for index, net := range netClient.testNets {
57+
if net.Spec.NetworkID == obj.Spec.NetworkID {
58+
netClient.testNets[index].ObjectMeta.ResourceVersion = magicVersion
59+
}
60+
}
61+
return nil, errors.New(danmtypes.OptimisticLockErrorMsg)
62+
}
63+
if strings.Contains(obj.Spec.NetworkID, "error") {
64+
return nil, errors.New("fatal error, don't retry")
65+
}
4166
return obj, nil
4267
}
4368

44-
func (netClient NetClientStub) Delete(name string, options *meta_v1.DeleteOptions) error {
69+
func (netClient *NetClientStub) Delete(name string, options *meta_v1.DeleteOptions) error {
4570
return nil
4671
}
4772

48-
func (netClient NetClientStub) DeleteCollection(options *meta_v1.DeleteOptions, listOptions meta_v1.ListOptions) error {
73+
func (netClient *NetClientStub) DeleteCollection(options *meta_v1.DeleteOptions, listOptions meta_v1.ListOptions) error {
4974
return nil
5075
}
5176

52-
func (netClient NetClientStub) Get(netName string, options meta_v1.GetOptions) (*danmtypes.DanmNet, error) {
77+
func (netClient *NetClientStub) Get(netName string, options meta_v1.GetOptions) (*danmtypes.DanmNet, error) {
78+
if strings.Contains(netName, "error") {
79+
return nil, errors.New("fatal error, don't retry")
80+
}
5381
for _, testNet := range netClient.testNets {
5482
if testNet.Spec.NetworkID == netName {
5583
return &testNet, nil
@@ -58,19 +86,19 @@ func (netClient NetClientStub) Get(netName string, options meta_v1.GetOptions) (
5886
return nil, errors.New("let's test error case as well")
5987
}
6088

61-
func (netClient NetClientStub) Watch(opts meta_v1.ListOptions) (watch.Interface, error) {
89+
func (netClient *NetClientStub) Watch(opts meta_v1.ListOptions) (watch.Interface, error) {
6290
watch := watch.NewEmptyWatch()
6391
return watch, nil
6492
}
6593

66-
func (netClient NetClientStub) List(opts meta_v1.ListOptions) (*danmtypes.DanmNetList, error) {
94+
func (netClient *NetClientStub) List(opts meta_v1.ListOptions) (*danmtypes.DanmNetList, error) {
6795
return nil, nil
6896
}
6997

70-
func (netClient NetClientStub) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *danmtypes.DanmNet, err error) {
98+
func (netClient *NetClientStub) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *danmtypes.DanmNet, err error) {
7199
return nil, nil
72100
}
73101

74-
func (netClient NetClientStub) AddReservedIpsList(reservedIps []ReservedIpsList) {
102+
func (netClient *NetClientStub) AddReservedIpsList(reservedIps []ReservedIpsList) {
75103
netClient.reservedIpsList = reservedIps
76104
}

0 commit comments

Comments
 (0)