Skip to content

Commit a57a498

Browse files
committed
test(vmnetcfg): add complex test case for sync handler
Signed-off-by: Zespre Chang <zespre.chang@suse.com> (cherry picked from commit 0efc388)
1 parent a759f92 commit a57a498

File tree

3 files changed

+105
-14
lines changed

3 files changed

+105
-14
lines changed

pkg/controller/vm/controller.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ func (h *Handler) OnChange(key string, vm *kubevirtv1.VirtualMachine) (*kubevirt
106106
vmNetCfgCpy := oldVmNetCfg.DeepCopy()
107107
vmNetCfgCpy.Spec.NetworkConfigs = vmNetCfg.Spec.NetworkConfigs
108108

109+
// The following block is a two-step process. Ideally,
110+
// 1. if the network config of the VirtualMachine has been changed, update the status of the VirtualMachineNetworkConfig
111+
// to out-of-sync so that the vmnetcfg-controller can handle it accordingly, and
112+
// 2. since the spec of the VirtualMachineNetworkConfig hasn't been changed, update it to reflect the new network config.
113+
// This is to throttle the vmnetcfg-controller and to avoid allocate-before-deallocate from happening.
109114
if !reflect.DeepEqual(vmNetCfgCpy.Spec.NetworkConfigs, oldVmNetCfg.Spec.NetworkConfigs) {
110115
if networkv1.InSynced.IsFalse(oldVmNetCfg) {
111116
logrus.Infof("(vm.OnChange) vmnetcfg %s/%s is deemed out-of-sync, updating it", vmNetCfgCpy.Namespace, vmNetCfgCpy.Name)

pkg/controller/vmnetcfg/controller.go

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -228,10 +228,6 @@ func (h *Handler) Sync(vmNetCfg *networkv1.VirtualMachineNetworkConfig, status n
228228
return status, fmt.Errorf("vmnetcfg %s/%s was administratively disabled", vmNetCfg.Namespace, vmNetCfg.Name)
229229
}
230230

231-
if len(vmNetCfg.Spec.NetworkConfigs) == 0 {
232-
return status, fmt.Errorf("vmnetcfg %s/%s has no network configs", vmNetCfg.Namespace, vmNetCfg.Name)
233-
}
234-
235231
// Nothing to do if the VirtualMachineNetworkConfig is already in-sync
236232
if networkv1.InSynced.IsTrue(vmNetCfg) {
237233
logrus.Debugf("(vmnetcfg.InSynced) vmnetcfg %s/%s is in-sync", vmNetCfg.Namespace, vmNetCfg.Name)
@@ -246,25 +242,23 @@ func (h *Handler) Sync(vmNetCfg *networkv1.VirtualMachineNetworkConfig, status n
246242
macAddressSet[nc.MACAddress] = struct{}{}
247243
}
248244

249-
// Mark the NetworkConfigStatus as stale if the MAC address is not in the Spec
245+
// Mark the NetworkConfigStatus as stale if the MAC address is not in
246+
// the Spec; otherwise, add it to the non-stale list.
247+
var nonStaleNetworkConfigs []networkv1.NetworkConfigStatus
250248
for i, ncStatus := range status.NetworkConfigs {
251249
if _, ok := macAddressSet[ncStatus.MACAddress]; !ok {
252250
status.NetworkConfigs[i].State = networkv1.StaleState
251+
continue
253252
}
253+
nonStaleNetworkConfigs = append(nonStaleNetworkConfigs, ncStatus)
254254
}
255255

256256
// Cleanup the stale records
257257
if err := h.cleanup(vmNetCfg, true); err != nil {
258258
return status, err
259259
}
260260

261-
// Remove the stale NetworkConfigStatus from the status
262-
var nonStaleNetworkConfigs []networkv1.NetworkConfigStatus
263-
for _, ncStatus := range status.NetworkConfigs {
264-
if ncStatus.State != networkv1.StaleState {
265-
nonStaleNetworkConfigs = append(nonStaleNetworkConfigs, ncStatus)
266-
}
267-
}
261+
// Update the VirtualMachineNetworkConfig status after cleanup
268262
status.NetworkConfigs = nonStaleNetworkConfigs
269263

270264
return status, nil

pkg/controller/vmnetcfg/controller_test.go

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,11 @@ const (
3737
testIPAddress1 = "192.168.0.111"
3838
testIPAddress2 = "192.168.0.177"
3939
testIPAddress3 = "192.168.0.189"
40+
testIPAddress4 = "192.168.0.199"
4041
testMACAddress1 = "11:22:33:44:55:66"
4142
testMACAddress2 = "22:33:44:55:66:77"
4243
testMACAddress3 = "33:44:55:66:77:88"
44+
testMACAddress4 = "44:55:66:77:88:99"
4345
)
4446

4547
func newTestVmNetCfgBuilder() *vmNetCfgBuilder {
@@ -655,7 +657,7 @@ func TestHandler_Sync(t *testing.T) {
655657
assert.Equal(t, expectedCacheAllocator, handler.cacheAllocator)
656658
})
657659

658-
t.Run("sync new vmnetcfg with empty network config should error", func(t *testing.T) {
660+
t.Run("sync new vmnetcfg with empty network config should succeed", func(t *testing.T) {
659661
givenVmNetCfg := newTestVmNetCfgBuilder().Build()
660662
givenIPPool := newTestIPPoolBuilder().
661663
ServerIP(testServerIP).
@@ -691,7 +693,7 @@ func TestHandler_Sync(t *testing.T) {
691693
}
692694

693695
status, err := handler.Sync(givenVmNetCfg, givenVmNetCfg.Status)
694-
assert.Equal(t, fmt.Sprintf("vmnetcfg %s/%s has no network configs", testVmNetCfgNamespace, testVmNetCfgName), err.Error())
696+
assert.Nil(t, err)
695697

696698
SanitizeStatus(&expectedStatus)
697699
SanitizeStatus(&status)
@@ -1006,4 +1008,94 @@ func TestHandler_Sync(t *testing.T) {
10061008
assert.Equal(t, expectedIPAllocator, handler.ipAllocator)
10071009
assert.Equal(t, expectedCacheAllocator, handler.cacheAllocator)
10081010
})
1011+
1012+
t.Run("sync out-of-sync vmnetcfg with additional, modified, and missing network configs should succeed and stale records should be removed", func(t *testing.T) {
1013+
givenVmNetCfg := newTestVmNetCfgBuilder().
1014+
WithNetworkConfig(testIPAddress1, testMACAddress1, testNetworkName).
1015+
WithNetworkConfig(testIPAddress4, testMACAddress4, testNetworkName).
1016+
WithNetworkConfigStatus(testIPAddress1, testMACAddress1, testNetworkName, networkv1.AllocatedState).
1017+
WithNetworkConfigStatus(testIPAddress2, testMACAddress2, testNetworkName, networkv1.AllocatedState).
1018+
WithNetworkConfigStatus(testIPAddress3, testMACAddress3, testNetworkName, networkv1.AllocatedState).Build()
1019+
givenIPPool := newTestIPPoolBuilder().
1020+
ServerIP(testServerIP).
1021+
CIDR(testCIDR).
1022+
PoolRange(testStartIP, testEndIP).
1023+
NetworkName(testNetworkName).
1024+
Allocated(testIPAddress1, testMACAddress1).
1025+
Allocated(testIPAddress2, testMACAddress2).
1026+
Allocated(testIPAddress3, testMACAddress3).
1027+
CacheReadyCondition(corev1.ConditionTrue, "", "").Build()
1028+
givenCacheAllocator := newTestCacheAllocatorBuilder().
1029+
MACSet(testNetworkName).
1030+
Add(testNetworkName, testMACAddress1, testIPAddress1).
1031+
Add(testNetworkName, testMACAddress2, testIPAddress2).
1032+
Add(testNetworkName, testMACAddress3, testIPAddress3).Build()
1033+
givenIPAllocator := newTestIPAllocatorBuilder().
1034+
IPSubnet(testNetworkName, testCIDR, testStartIP, testEndIP).
1035+
Allocate(testNetworkName, testIPAddress1, testIPAddress2, testIPAddress3).Build()
1036+
givenNAD := newTestNetworkAttachmentDefinitionBuilder().
1037+
Label(util.IPPoolNamespaceLabelKey, testIPPoolNamespace).
1038+
Label(util.IPPoolNameLabelKey, testIPPoolName).Build()
1039+
1040+
expectedStatus := newTestVmNetCfgStatusBuilder().
1041+
WithNetworkConfigStatus(testIPAddress1, testMACAddress1, testNetworkName, networkv1.AllocatedState).Build()
1042+
expectedIPPool := newTestIPPoolBuilder().
1043+
ServerIP(testServerIP).
1044+
CIDR(testCIDR).
1045+
PoolRange(testStartIP, testEndIP).
1046+
NetworkName(testNetworkName).
1047+
Allocated(testIPAddress1, testMACAddress1).
1048+
CacheReadyCondition(corev1.ConditionTrue, "", "").Build()
1049+
expectedCacheAllocator := newTestCacheAllocatorBuilder().
1050+
MACSet(testNetworkName).
1051+
Add(testNetworkName, testMACAddress1, testIPAddress1).Build()
1052+
expectedIPAllocator := newTestIPAllocatorBuilder().
1053+
IPSubnet(testNetworkName, testCIDR, testStartIP, testEndIP).
1054+
Allocate(testNetworkName, testIPAddress1).Build()
1055+
1056+
nadGVR := schema.GroupVersionResource{
1057+
Group: "k8s.cni.cncf.io",
1058+
Version: "v1",
1059+
Resource: "network-attachment-definitions",
1060+
}
1061+
1062+
clientset := fake.NewSimpleClientset()
1063+
err := clientset.Tracker().Create(nadGVR, givenNAD, givenNAD.Namespace)
1064+
assert.Nil(t, err, "mock resource should add into fake controller tracker")
1065+
1066+
err = clientset.Tracker().Add(givenVmNetCfg)
1067+
if err != nil {
1068+
t.Fatal(err)
1069+
}
1070+
err = clientset.Tracker().Add(givenIPPool)
1071+
if err != nil {
1072+
t.Fatal(err)
1073+
}
1074+
1075+
handler := Handler{
1076+
cacheAllocator: givenCacheAllocator,
1077+
ipAllocator: givenIPAllocator,
1078+
metricsAllocator: metrics.New(),
1079+
ippoolClient: fakeclient.IPPoolClient(clientset.NetworkV1alpha1().IPPools),
1080+
ippoolCache: fakeclient.IPPoolCache(clientset.NetworkV1alpha1().IPPools),
1081+
nadCache: fakeclient.NetworkAttachmentDefinitionCache(clientset.K8sCniCncfIoV1().NetworkAttachmentDefinitions),
1082+
}
1083+
1084+
status, err := handler.Sync(givenVmNetCfg, givenVmNetCfg.Status)
1085+
assert.Nil(t, err)
1086+
1087+
SanitizeStatus(&expectedStatus)
1088+
SanitizeStatus(&status)
1089+
assert.Equal(t, expectedStatus, status)
1090+
1091+
ipPool, err := handler.ippoolClient.Get(testIPPoolNamespace, testIPPoolName, metav1.GetOptions{})
1092+
assert.Nil(t, err)
1093+
1094+
ippool.SanitizeStatus(&expectedIPPool.Status)
1095+
ippool.SanitizeStatus(&ipPool.Status)
1096+
assert.Equal(t, expectedIPPool, ipPool)
1097+
1098+
assert.Equal(t, expectedIPAllocator, handler.ipAllocator)
1099+
assert.Equal(t, expectedCacheAllocator, handler.cacheAllocator)
1100+
})
10091101
}

0 commit comments

Comments
 (0)