Skip to content

Commit

Permalink
Add nad validator test code
Browse files Browse the repository at this point in the history
Signed-off-by: Jian Wang <[email protected]>
  • Loading branch information
w13915984028 committed Jan 31, 2025
1 parent 9df6c7c commit ce8ac01
Show file tree
Hide file tree
Showing 4 changed files with 312 additions and 4 deletions.
7 changes: 6 additions & 1 deletion pkg/webhook/nad/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
cniv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
admissionregv1 "k8s.io/api/admissionregistration/v1"
"k8s.io/apimachinery/pkg/runtime"
kubevirtv1 "kubevirt.io/api/core/v1"

"github.com/harvester/harvester-network-controller/pkg/network/iface"
"github.com/harvester/harvester-network-controller/pkg/utils"
Expand Down Expand Up @@ -132,14 +133,18 @@ func (v *Validator) checkVmi(nad *cniv1.NetworkAttachmentDefinition) error {
return err
}

return v.generateVmiNoneStopError(nad, vmis)
}

// for convenicen of test code
func (v *Validator) generateVmiNoneStopError(_ *cniv1.NetworkAttachmentDefinition, vmis []*kubevirtv1.VirtualMachineInstance) error {
if len(vmis) > 0 {
vmiNameList := make([]string, 0, len(vmis))
for _, vmi := range vmis {
vmiNameList = append(vmiNameList, vmi.Namespace+"/"+vmi.Name)
}
return fmt.Errorf("it's still used by VM(s) %s which must be stopped at first", strings.Join(vmiNameList, ", "))
}

return nil
}

Expand Down
302 changes: 302 additions & 0 deletions pkg/webhook/nad/validator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,302 @@
package nad

import (
"strings"
"testing"

"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kubevirtv1 "kubevirt.io/api/core/v1"

cniv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"

networkv1 "github.com/harvester/harvester-network-controller/pkg/apis/network.harvesterhci.io/v1beta1"

harvesterfake "github.com/harvester/harvester/pkg/generated/clientset/versioned/fake"
harvesterfakeclients "github.com/harvester/harvester/pkg/util/fakeclients"

"github.com/harvester/harvester-network-controller/pkg/generated/clientset/versioned/fake"
"github.com/harvester/harvester-network-controller/pkg/utils"
"github.com/harvester/harvester-network-controller/pkg/utils/fakeclients"
)

const (
testCnName = "test-cn"
testNADConfig = "{\"cniVersion\":\"0.3.1\",\"name\":\"net1-vlan\",\"type\":\"bridge\",\"bridge\":\"harvester-br0\",\"promiscMode\":true,\"vlan\":300,\"ipam\":{}}"
testNADName = "testNad"
testVMName = "vm1"
testNamespace = "test"
)

func TestCreateNAD(t *testing.T) {
tests := []struct {
name string
returnErr bool
errKey string
currentCN *networkv1.ClusterNetwork
currentVC *networkv1.VlanConfig
currentNAD *cniv1.NetworkAttachmentDefinition
newNAD *cniv1.NetworkAttachmentDefinition
}{
{
name: "NAD is valid to create",
returnErr: false,
errKey: "",
currentCN: &networkv1.ClusterNetwork{
ObjectMeta: metav1.ObjectMeta{
Name: testCnName,
Annotations: map[string]string{"test": "test"},
},
},
newNAD: &cniv1.NetworkAttachmentDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: testNADName,
Namespace: testNamespace,
Annotations: map[string]string{"test": "test"},
Labels: map[string]string{utils.KeyClusterNetworkLabel: testCnName},
},
Spec: cniv1.NetworkAttachmentDefinitionSpec{
Config: testNADConfig,
},
},
},
{
name: "NAD has invalid config string",
returnErr: true,
errKey: "unmarshal",
currentCN: &networkv1.ClusterNetwork{
ObjectMeta: metav1.ObjectMeta{
Name: testCnName,
Annotations: map[string]string{"test": "test"},
},
},
newNAD: &cniv1.NetworkAttachmentDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: testNADName,
Namespace: testNamespace,
Annotations: map[string]string{"test": "test"},
Labels: map[string]string{utils.KeyClusterNetworkLabel: testCnName},
},
Spec: cniv1.NetworkAttachmentDefinitionSpec{
Config: "{\"cniVersion\",\"name\":\"net1-vlan\",\"type\":\"bridge\",\"bridge\":\"harvester-br0\",\"promiscMode\":true,\"vlan\":300,\"ipam\":{}}",
},
},
},
{
name: "NAD has invalid VLAN id which is -1",
returnErr: true,
errKey: "VLAN ID must",
currentCN: &networkv1.ClusterNetwork{
ObjectMeta: metav1.ObjectMeta{
Name: testCnName,
Annotations: map[string]string{"test": "test"},
},
},
newNAD: &cniv1.NetworkAttachmentDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: testNADName,
Namespace: testNamespace,
Annotations: map[string]string{"test": "test"},
Labels: map[string]string{utils.KeyClusterNetworkLabel: testCnName},
},
Spec: cniv1.NetworkAttachmentDefinitionSpec{
Config: "{\"cniVersion\":\"0.3.1\",\"name\":\"net1-vlan\",\"type\":\"bridge\",\"bridge\":\"harvester-br0\",\"promiscMode\":true,\"vlan\":-1,\"ipam\":{}}",
},
},
},
{
name: "NAD has invalid VLAN id which is 4095",
returnErr: true,
errKey: "VLAN ID must",
currentCN: &networkv1.ClusterNetwork{
ObjectMeta: metav1.ObjectMeta{
Name: testCnName,
Annotations: map[string]string{"test": "test"},
},
},
newNAD: &cniv1.NetworkAttachmentDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: testNADName,
Namespace: testNamespace,
Annotations: map[string]string{"test": "test"},
Labels: map[string]string{utils.KeyClusterNetworkLabel: testCnName},
},
Spec: cniv1.NetworkAttachmentDefinitionSpec{
Config: "{\"cniVersion\":\"0.3.1\",\"name\":\"net1-vlan\",\"type\":\"bridge\",\"bridge\":\"harvester-br0\",\"promiscMode\":true,\"vlan\":4095,\"ipam\":{}}",
},
},
},
{
name: "NAD has too long bridge name",
returnErr: true,
errKey: "the length of the brName",
currentCN: &networkv1.ClusterNetwork{
ObjectMeta: metav1.ObjectMeta{
Name: testCnName,
Annotations: map[string]string{"test": "test"},
},
},
newNAD: &cniv1.NetworkAttachmentDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: testNADName,
Namespace: testNamespace,
Annotations: map[string]string{"test": "test"},
Labels: map[string]string{utils.KeyClusterNetworkLabel: testCnName},
},
Spec: cniv1.NetworkAttachmentDefinitionSpec{
Config: "{\"cniVersion\":\"0.3.1\",\"name\":\"net1-vlan\",\"type\":\"bridge\",\"bridge\":\"harvester-br0-too-long\",\"promiscMode\":true,\"vlan\":300,\"ipam\":{}}",
},
},
},
{
name: "NAD has too short bridge name",
returnErr: true,
errKey: "the suffix of the brName",
currentCN: &networkv1.ClusterNetwork{
ObjectMeta: metav1.ObjectMeta{
Name: testCnName,
Annotations: map[string]string{"test": "test"},
},
},
newNAD: &cniv1.NetworkAttachmentDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: testNADName,
Namespace: testNamespace,
Annotations: map[string]string{"test": "test"},
Labels: map[string]string{utils.KeyClusterNetworkLabel: testCnName},
},
Spec: cniv1.NetworkAttachmentDefinitionSpec{
Config: "{\"cniVersion\":\"0.3.1\",\"name\":\"net1-vlan\",\"type\":\"bridge\",\"bridge\":\"a\",\"promiscMode\":true,\"vlan\":300,\"ipam\":{}}",
},
},
},
{
name: "NAD has invalid bridge suffix",
returnErr: true,
errKey: "the suffix of the brName",
currentCN: &networkv1.ClusterNetwork{
ObjectMeta: metav1.ObjectMeta{
Name: testCnName,
Annotations: map[string]string{"test": "test"},
},
},
newNAD: &cniv1.NetworkAttachmentDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: testNADName,
Namespace: testNamespace,
Annotations: map[string]string{"test": "test"},
Labels: map[string]string{utils.KeyClusterNetworkLabel: testCnName},
},
Spec: cniv1.NetworkAttachmentDefinitionSpec{
Config: "{\"cniVersion\":\"0.3.1\",\"name\":\"net1-vlan\",\"type\":\"bridge\",\"suffix-br-\":\"a\",\"promiscMode\":true,\"vlan\":300,\"ipam\":{}}",
},
},
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {

assert.NotNil(t, tc.newNAD)
if tc.newNAD == nil {
return
}

nchclientset := fake.NewSimpleClientset()
harvesterclientset := harvesterfake.NewSimpleClientset()

vmiCache := harvesterfakeclients.VirtualMachineInstanceCache(harvesterclientset.KubevirtV1().VirtualMachineInstances)

// client to inject test data
vcClient := fakeclients.VlanConfigClient(nchclientset.NetworkV1beta1().VlanConfigs)
cnClient := fakeclients.ClusterNetworkClient(nchclientset.NetworkV1beta1().ClusterNetworks)

if tc.currentVC != nil {
vcClient.Create(tc.currentVC)
}
if tc.currentCN != nil {
cnClient.Create(tc.currentCN)
}

validator := NewNadValidator(vmiCache)

err := validator.Create(nil, tc.newNAD)
if tc.returnErr {
assert.NotNil(t, err)
assert.True(t, strings.Contains(err.Error(), tc.errKey))
}
})
}
}

func TestDeleteNAD(t *testing.T) {
tests := []struct {
name string
returnErr bool
errKey string
currentNAD *cniv1.NetworkAttachmentDefinition
usedVMs []*kubevirtv1.VirtualMachineInstance
}{
{
name: "NAD has used VMs and can't be deleted",
returnErr: true,
errKey: testVMName,
currentNAD: &cniv1.NetworkAttachmentDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: testNADName,
Namespace: testNamespace,
Annotations: map[string]string{"test": "test"},
Labels: map[string]string{utils.KeyClusterNetworkLabel: testCnName},
},
Spec: cniv1.NetworkAttachmentDefinitionSpec{
Config: testNADConfig,
},
},
usedVMs: []*kubevirtv1.VirtualMachineInstance{
{
ObjectMeta: metav1.ObjectMeta{
Name: testVMName,
Namespace: testNamespace,
Annotations: map[string]string{"test": "test"},
},
},
},
},
{
name: "NAD has no used VMs and can be deleted",
returnErr: false,
errKey: "",
currentNAD: &cniv1.NetworkAttachmentDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: testNADName,
Namespace: testNamespace,
Annotations: map[string]string{"test": "test"},
Labels: map[string]string{utils.KeyClusterNetworkLabel: testCnName},
},
Spec: cniv1.NetworkAttachmentDefinitionSpec{
Config: testNADConfig,
},
},
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
assert.NotNil(t, tc.currentNAD)
if tc.currentNAD == nil {
return
}

harvesterclientset := harvesterfake.NewSimpleClientset()
vmiCache := harvesterfakeclients.VirtualMachineInstanceCache(harvesterclientset.KubevirtV1().VirtualMachineInstances)
validator := NewNadValidator(vmiCache)

// due to fake vmiCache limitation, just test generateVmiNoneStopError() instead of Delete()
err := validator.generateVmiNoneStopError(tc.currentNAD, tc.usedVMs)
if tc.returnErr {
assert.NotNil(t, err)
assert.True(t, strings.Contains(err.Error(), tc.errKey))
}
})
}
}
2 changes: 1 addition & 1 deletion pkg/webhook/vlanconfig/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func NewVlanConfigValidator(
vcCache ctlnetworkv1.VlanConfigCache,
vsCache ctlnetworkv1.VlanStatusCache,
vmiCache ctlkubevirtv1.VirtualMachineInstanceCache,
cnCache ctlnetworkv1.ClusterNetworkCache) *Validator {
cnCache ctlnetworkv1.ClusterNetworkCache) *Validator {
return &Validator{
nadCache: nadCache,
vcCache: vcCache,
Expand Down
5 changes: 3 additions & 2 deletions pkg/webhook/vlanconfig/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import (
"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

harvesterfake "github.com/harvester/harvester/pkg/generated/clientset/versioned/fake"
harvesterfakeclients "github.com/harvester/harvester/pkg/util/fakeclients"

networkv1 "github.com/harvester/harvester-network-controller/pkg/apis/network.harvesterhci.io/v1beta1"
"github.com/harvester/harvester-network-controller/pkg/generated/clientset/versioned/fake"
"github.com/harvester/harvester-network-controller/pkg/utils"
"github.com/harvester/harvester-network-controller/pkg/utils/fakeclients"
harvesterfake "github.com/harvester/harvester/pkg/generated/clientset/versioned/fake"
harvesterfakeclients "github.com/harvester/harvester/pkg/util/fakeclients"
)

const testCnName = "test-cn"
Expand Down

0 comments on commit ce8ac01

Please sign in to comment.