From d3ad44e039dbfc7b9a8f538262cec4d02cfab484 Mon Sep 17 00:00:00 2001 From: Volker Theile Date: Mon, 26 May 2025 10:55:54 +0200 Subject: [PATCH] Add option to select network interface model while importing VM to Harvester using the vm-import-controller (#78) Add the field `DefaultNetworkInterfaceModel` to `VirtualMachineImportSpec` and `NetworkInterfaceModel` to `NetworkMapping`. With this new fields it is possible to customize the interface models of the VM NICs. Related to: https://github.com/harvester/harvester/issues/7999 Signed-off-by: Volker Theile --- go.mod | 2 +- .../v1beta1/virtualmachines.go | 38 +++++++- pkg/source/network.go | 83 ++++++++++++++++ pkg/source/openstack/client.go | 82 +++------------- pkg/source/openstack/client_test.go | 10 +- pkg/source/vmware/client.go | 94 +++++-------------- pkg/source/vmware/client_test.go | 15 +-- 7 files changed, 173 insertions(+), 151 deletions(-) create mode 100644 pkg/source/network.go diff --git a/go.mod b/go.mod index 137dff0..c1a2c2d 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,7 @@ require ( k8s.io/apiextensions-apiserver v0.31.3 k8s.io/apimachinery v0.31.3 k8s.io/client-go v12.0.0+incompatible + k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 kubevirt.io/api v1.1.0 kubevirt.io/kubevirt v1.1.0 sigs.k8s.io/cluster-api v1.9.4 @@ -110,7 +111,6 @@ require ( k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-aggregator v0.26.4 // indirect k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect - k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect kubevirt.io/client-go v1.1.0 // indirect kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 // indirect kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 // indirect diff --git a/pkg/apis/migration.harvesterhci.io/v1beta1/virtualmachines.go b/pkg/apis/migration.harvesterhci.io/v1beta1/virtualmachines.go index 8f0633b..3162a48 100644 --- a/pkg/apis/migration.harvesterhci.io/v1beta1/virtualmachines.go +++ b/pkg/apis/migration.harvesterhci.io/v1beta1/virtualmachines.go @@ -4,6 +4,7 @@ import ( "github.com/rancher/wrangler/pkg/condition" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" kubevirtv1 "kubevirt.io/api/core/v1" "github.com/harvester/vm-import-controller/pkg/apis/common" @@ -30,9 +31,17 @@ type VirtualMachineImportSpec struct { // Examples: "vm-1234", "my-VM" or "5649cac7-3871-4bb5-aab6-c72b8c18d0a2" VirtualMachineName string `json:"virtualMachineName"` - Folder string `json:"folder,omitempty"` - Mapping []NetworkMapping `json:"networkMapping,omitempty"` //If empty new VirtualMachineImport will be mapped to Management Network - StorageClass string `json:"storageClass,omitempty"` + Folder string `json:"folder,omitempty"` + + // If empty new VirtualMachineImport will be mapped to Management Network. + Mapping []NetworkMapping `json:"networkMapping,omitempty"` + // The default network interface model. This is always used when: + // - Auto-detection fails (OpenStack source client does not have auto-detection, therefore this field is used for every network interface). + // - No network mapping is provided and a "pod-network" is auto-created. + // Defaults to "virtio". + DefaultNetworkInterfaceModel *string `json:"defaultNetworkInterfaceModel,omitempty" wrangler:"type=string,options=e1000|e1000e|ne2k_pci|pcnet|rtl8139|virtio"` + + StorageClass string `json:"storageClass,omitempty"` } // VirtualMachineImportStatus tracks the status of the VirtualMachineImport export from migration and import into the Harvester cluster @@ -70,6 +79,9 @@ type DiskInfo struct { type NetworkMapping struct { SourceNetwork string `json:"sourceNetwork"` DestinationNetwork string `json:"destinationNetwork"` + // Override the network interface model that is auto-detected (VMware) + // or defaulted (OpenStack). + NetworkInterfaceModel *string `json:"networkInterfaceModel,omitempty" wrangler:"type=string,options=e1000|e1000e|ne2k_pci|pcnet|rtl8139|virtio"` } type ImportStatus string @@ -93,3 +105,23 @@ const ( VirtualMachineExportFailed condition.Cond = "VMExportFailed" VirtualMachineMigrationFailed ImportStatus = "VMMigrationFailed" ) + +// The supported network interface models. +// This can be: e1000, e1000e, ne2k_pci, pcnet, rtl8139, virtio. +// See https://kubevirt.io/user-guide/network/interfaces_and_networks/#interfaces +const ( + NetworkInterfaceModelE1000 = "e1000" + NetworkInterfaceModelE1000e = "e1000e" + NetworkInterfaceModelNe2kPci = "ne2k_pci" + NetworkInterfaceModelPcnet = "pcnet" + NetworkInterfaceModelRtl8139 = "rtl8139" + NetworkInterfaceModelVirtio = "virtio" +) + +func (in *VirtualMachineImport) GetDefaultNetworkInterfaceModel() string { + return ptr.Deref[string](in.Spec.DefaultNetworkInterfaceModel, NetworkInterfaceModelVirtio) +} + +func (in *NetworkMapping) GetNetworkInterfaceModel() string { + return ptr.Deref[string](in.NetworkInterfaceModel, NetworkInterfaceModelVirtio) +} diff --git a/pkg/source/network.go b/pkg/source/network.go new file mode 100644 index 0000000..2a6f8e8 --- /dev/null +++ b/pkg/source/network.go @@ -0,0 +1,83 @@ +package source + +import ( + "fmt" + + kubevirt "kubevirt.io/api/core/v1" + + migration "github.com/harvester/vm-import-controller/pkg/apis/migration.harvesterhci.io/v1beta1" +) + +type NetworkInfo struct { + NetworkName string + MAC string + MappedNetwork string + Model string +} + +func MapNetworks(networkInfos []NetworkInfo, networkMappings []migration.NetworkMapping) []NetworkInfo { + result := make([]NetworkInfo, 0) + + for _, ni := range networkInfos { + for _, nm := range networkMappings { + if nm.SourceNetwork == ni.NetworkName { + ni.MappedNetwork = nm.DestinationNetwork + + // Override the auto-detected interface model if it is + // customized by the user via the `NetworkMapping`. + if nm.NetworkInterfaceModel != nil { + ni.Model = nm.GetNetworkInterfaceModel() + } + + result = append(result, ni) + } + } + } + + return result +} + +func GenerateNetworkInterfaceConfigs(networkInfos []NetworkInfo, defaultNetworkInterfaceModel string) ([]kubevirt.Network, []kubevirt.Interface) { + networks := make([]kubevirt.Network, 0, len(networkInfos)) + interfaces := make([]kubevirt.Interface, 0, len(networkInfos)) + + for i, ni := range networkInfos { + networks = append(networks, kubevirt.Network{ + NetworkSource: kubevirt.NetworkSource{ + Multus: &kubevirt.MultusNetwork{ + NetworkName: ni.MappedNetwork, + }, + }, + Name: fmt.Sprintf("migrated-%d", i), + }) + + interfaces = append(interfaces, kubevirt.Interface{ + Name: fmt.Sprintf("migrated-%d", i), + MacAddress: ni.MAC, + Model: ni.Model, + InterfaceBindingMethod: kubevirt.InterfaceBindingMethod{ + Bridge: &kubevirt.InterfaceBridge{}, + }, + }) + } + + // If there is no network, attach to Pod network. Essential for VM to + // be booted up. + if len(networks) == 0 { + networks = append(networks, kubevirt.Network{ + Name: "pod-network", + NetworkSource: kubevirt.NetworkSource{ + Pod: &kubevirt.PodNetwork{}, + }, + }) + interfaces = append(interfaces, kubevirt.Interface{ + Name: "pod-network", + Model: defaultNetworkInterfaceModel, + InterfaceBindingMethod: kubevirt.InterfaceBindingMethod{ + Masquerade: &kubevirt.InterfaceMasquerade{}, + }, + }) + } + + return networks, interfaces +} diff --git a/pkg/source/openstack/client.go b/pkg/source/openstack/client.go index 5429053..fe63b71 100644 --- a/pkg/source/openstack/client.go +++ b/pkg/source/openstack/client.go @@ -435,7 +435,7 @@ func (c *Client) GenerateVirtualMachine(vm *migration.VirtualMachineImport) (*ku return nil, fmt.Errorf("error getting firware settings: %v", err) } - networkInfos, err := generateNetworkInfo(vmObj.Addresses) + networkInfos, err := generateNetworkInfos(vmObj.Addresses, vm.GetDefaultNetworkInterfaceModel()) if err != nil { return nil, err } @@ -488,46 +488,8 @@ func (c *Client) GenerateVirtualMachine(vm *migration.VirtualMachineImport) (*ku }, } - mappedNetwork := mapNetworkCards(networkInfos, vm.Spec.Mapping) - networkConfig := make([]kubevirt.Network, 0, len(mappedNetwork)) - for i, v := range mappedNetwork { - networkConfig = append(networkConfig, kubevirt.Network{ - NetworkSource: kubevirt.NetworkSource{ - Multus: &kubevirt.MultusNetwork{ - NetworkName: v.MappedNetwork, - }, - }, - Name: fmt.Sprintf("migrated-%d", i), - }) - } - - interfaces := make([]kubevirt.Interface, 0, len(mappedNetwork)) - for i, v := range mappedNetwork { - interfaces = append(interfaces, kubevirt.Interface{ - Name: fmt.Sprintf("migrated-%d", i), - MacAddress: v.MAC, - Model: "virtio", - InterfaceBindingMethod: kubevirt.InterfaceBindingMethod{ - Bridge: &kubevirt.InterfaceBridge{}, - }, - }) - } - // if there is no network, attach to Pod network. Essential for VM to be booted up - if len(networkConfig) == 0 { - networkConfig = append(networkConfig, kubevirt.Network{ - Name: "pod-network", - NetworkSource: kubevirt.NetworkSource{ - Pod: &kubevirt.PodNetwork{}, - }, - }) - interfaces = append(interfaces, kubevirt.Interface{ - Name: "pod-network", - Model: "virtio", - InterfaceBindingMethod: kubevirt.InterfaceBindingMethod{ - Masquerade: &kubevirt.InterfaceMasquerade{}, - }, - }) - } + mappedNetwork := source.MapNetworks(networkInfos, vm.Spec.Mapping) + networkConfig, interfaceConfig := source.GenerateNetworkInterfaceConfigs(mappedNetwork, vm.GetDefaultNetworkInterfaceModel()) // Setup BIOS/EFI, SecureBoot and TPM settings. if uefi { @@ -535,7 +497,7 @@ func (c *Client) GenerateVirtualMachine(vm *migration.VirtualMachineImport) (*ku } vmSpec.Template.Spec.Networks = networkConfig - vmSpec.Template.Spec.Domain.Devices.Interfaces = interfaces + vmSpec.Template.Spec.Domain.Devices.Interfaces = interfaceConfig newVM.Spec = vmSpec // disk attachment needs query by core controller for storage classes, so will be added by the migration controller @@ -663,26 +625,6 @@ func (c *Client) findVM(name string) (*ExtendedServer, error) { return &s, err } -type networkInfo struct { - NetworkName string - MAC string - MappedNetwork string -} - -func mapNetworkCards(networkCards []networkInfo, mapping []migration.NetworkMapping) []networkInfo { - var retNetwork []networkInfo - for _, nc := range networkCards { - for _, m := range mapping { - if m.SourceNetwork == nc.NetworkName { - nc.MappedNetwork = m.DestinationNetwork - retNetwork = append(retNetwork, nc) - } - } - } - - return retNetwork -} - func (c *Client) ImageFirmwareSettings(instance *servers.Server) (bool, bool, bool, error) { var imageID string var uefiType, tpmEnabled, secureBoot bool @@ -721,9 +663,10 @@ func (c *Client) ImageFirmwareSettings(instance *servers.Server) (bool, bool, bo return uefiType, tpmEnabled, secureBoot, nil } -func generateNetworkInfo(info map[string]interface{}) ([]networkInfo, error) { - networkInfos := make([]networkInfo, 0) - uniqueNetworks := make([]networkInfo, 0) +func generateNetworkInfos(info map[string]interface{}, defaultInterfaceModel string) ([]source.NetworkInfo, error) { + networkInfos := make([]source.NetworkInfo, 0) + uniqueNetworks := make([]source.NetworkInfo, 0) + for network, values := range info { valArr, ok := values.([]interface{}) if !ok { @@ -734,15 +677,19 @@ func generateNetworkInfo(info map[string]interface{}) ([]networkInfo, error) { if !ok { return nil, fmt.Errorf("error asserting network array element into map[string]string") } - networkInfos = append(networkInfos, networkInfo{ + networkInfos = append(networkInfos, source.NetworkInfo{ NetworkName: network, MAC: valMap["OS-EXT-IPS-MAC:mac_addr"].(string), + // Note, the interface model is not provided via the OpenStack + // Nova API, therefore we need to set it ourselves. + Model: defaultInterfaceModel, }) } } + // in case of interfaces with ipv6 and ipv4 addresses they are reported twice, so we need to dedup them // based on a mac address - networksMap := make(map[string]networkInfo) + networksMap := make(map[string]source.NetworkInfo) for _, v := range networkInfos { networksMap[v.MAC] = v } @@ -750,6 +697,7 @@ func generateNetworkInfo(info map[string]interface{}) ([]networkInfo, error) { for _, v := range networksMap { uniqueNetworks = append(uniqueNetworks, v) } + return uniqueNetworks, nil } diff --git a/pkg/source/openstack/client_test.go b/pkg/source/openstack/client_test.go index 3a0f5a5..20f609b 100644 --- a/pkg/source/openstack/client_test.go +++ b/pkg/source/openstack/client_test.go @@ -126,8 +126,9 @@ func Test_GenerateVirtualMachine(t *testing.T) { assert.NoError(err, "expected no error during GenerateVirtualMachine") assert.NotEmpty(newVM.Spec.Template.Spec.Domain.CPU, "expected CPU's to not be empty") assert.NotEmpty(newVM.Spec.Template.Spec.Domain.Resources.Limits.Memory(), "expected memory limit to not be empty") - assert.NotEmpty(newVM.Spec.Template.Spec.Networks, "expected to find atleast 1 network as pod network should have been applied") - assert.NotEmpty(newVM.Spec.Template.Spec.Domain.Devices.Interfaces, "expected to find atleast 1 interface for pod-network") + assert.NotEmpty(newVM.Spec.Template.Spec.Networks, "expected to find at least 1 network as pod network should have been applied") + assert.NotEmpty(newVM.Spec.Template.Spec.Domain.Devices.Interfaces, "expected to find at least 1 interface for pod-network") + assert.Equal(newVM.Spec.Template.Spec.Domain.Devices.Interfaces[0].Model, migration.NetworkInterfaceModelVirtio, "expected to have a NIC with virtio model") } func Test_generateNetworkInfo(t *testing.T) { @@ -137,10 +138,11 @@ func Test_generateNetworkInfo(t *testing.T) { err := json.Unmarshal(networkInfoByte, &networkInfoMap) assert.NoError(err, "expected no error while unmarshalling network info") - vmInterfaceDetails, err := generateNetworkInfo(networkInfoMap) + vmInterfaceDetails, err := generateNetworkInfos(networkInfoMap, migration.NetworkInterfaceModelVirtio) assert.NoError(err, "expected no error while generating network info") assert.Len(vmInterfaceDetails, 2, "expected to find 2 interfaces only") - + assert.Equal(vmInterfaceDetails[0].Model, migration.NetworkInterfaceModelVirtio, "expected to have a NIC with virtio model") + assert.Equal(vmInterfaceDetails[1].Model, migration.NetworkInterfaceModelVirtio, "expected to have a NIC with virtio model") } func Test_ClientOptions(t *testing.T) { diff --git a/pkg/source/vmware/client.go b/pkg/source/vmware/client.go index 791fd7a..f365f46 100644 --- a/pkg/source/vmware/client.go +++ b/pkg/source/vmware/client.go @@ -323,8 +323,7 @@ func (c *Client) GenerateVirtualMachine(vm *migration.VirtualMachineImport) (*ku "spec": o, }, []string{"spec"})).Info("Origin spec of the VM to be imported") - // Need CPU, Socket, Memory, VirtualNIC information to perform the mapping - networkInfo := identifyNetworkCards(o.Config.Hardware.Device) + networkInfos := generateNetworkInfos(o.Config.Hardware.Device) vmSpec := kubevirt.VirtualMachineSpec{ RunStrategy: &[]kubevirt.VirtualMachineRunStrategy{kubevirt.RunStrategyRerunOnFailure}[0], @@ -360,46 +359,8 @@ func (c *Client) GenerateVirtualMachine(vm *migration.VirtualMachineImport) (*ku }, } - mappedNetwork := mapNetworkCards(networkInfo, vm.Spec.Mapping) - networkConfig := make([]kubevirt.Network, 0, len(mappedNetwork)) - for i, v := range mappedNetwork { - networkConfig = append(networkConfig, kubevirt.Network{ - NetworkSource: kubevirt.NetworkSource{ - Multus: &kubevirt.MultusNetwork{ - NetworkName: v.MappedNetwork, - }, - }, - Name: fmt.Sprintf("migrated-%d", i), - }) - } - - interfaces := make([]kubevirt.Interface, 0, len(mappedNetwork)) - for i, v := range mappedNetwork { - interfaces = append(interfaces, kubevirt.Interface{ - Name: fmt.Sprintf("migrated-%d", i), - MacAddress: v.MAC, - Model: "virtio", - InterfaceBindingMethod: kubevirt.InterfaceBindingMethod{ - Bridge: &kubevirt.InterfaceBridge{}, - }, - }) - } - // if there is no network, attach to Pod network. Essential for VM to be booted up - if len(networkConfig) == 0 { - networkConfig = append(networkConfig, kubevirt.Network{ - Name: "pod-network", - NetworkSource: kubevirt.NetworkSource{ - Pod: &kubevirt.PodNetwork{}, - }, - }) - interfaces = append(interfaces, kubevirt.Interface{ - Name: "pod-network", - Model: "virtio", - InterfaceBindingMethod: kubevirt.InterfaceBindingMethod{ - Masquerade: &kubevirt.InterfaceMasquerade{}, - }, - }) - } + mappedNetwork := source.MapNetworks(networkInfos, vm.Spec.Mapping) + networkConfig, interfaceConfig := source.GenerateNetworkInterfaceConfigs(mappedNetwork, vm.GetDefaultNetworkInterfaceModel()) // Setup BIOS/EFI, SecureBoot and TPM settings. uefi := strings.EqualFold(o.Config.Firmware, string(types.GuestOsDescriptorFirmwareTypeEfi)) @@ -413,7 +374,7 @@ func (c *Client) GenerateVirtualMachine(vm *migration.VirtualMachineImport) (*ku } vmSpec.Template.Spec.Networks = networkConfig - vmSpec.Template.Spec.Domain.Devices.Interfaces = interfaces + vmSpec.Template.Spec.Domain.Devices.Interfaces = interfaceConfig newVM.Spec = vmSpec // disk attachment needs query by core controller for storage classes, so will be added by the migration controller @@ -430,64 +391,57 @@ func (c *Client) findVM(path, name string) (*object.VirtualMachine, error) { return f.VirtualMachine(c.ctx, vmPath) } -type networkInfo struct { - NetworkName string - MAC string - MappedNetwork string -} +func generateNetworkInfos(devices []types.BaseVirtualDevice) []source.NetworkInfo { + result := make([]source.NetworkInfo, 0, len(devices)) -func identifyNetworkCards(devices []types.BaseVirtualDevice) []networkInfo { - var resp []networkInfo for _, d := range devices { switch d := d.(type) { case *types.VirtualVmxnet: obj := d - resp = append(resp, networkInfo{ + result = append(result, source.NetworkInfo{ NetworkName: obj.DeviceInfo.GetDescription().Summary, MAC: obj.MacAddress, + Model: migration.NetworkInterfaceModelVirtio, }) case *types.VirtualE1000e: obj := d - resp = append(resp, networkInfo{ + result = append(result, source.NetworkInfo{ NetworkName: obj.DeviceInfo.GetDescription().Summary, MAC: obj.MacAddress, + Model: migration.NetworkInterfaceModelE1000e, }) case *types.VirtualE1000: obj := d - resp = append(resp, networkInfo{ + result = append(result, source.NetworkInfo{ NetworkName: obj.DeviceInfo.GetDescription().Summary, MAC: obj.MacAddress, + Model: migration.NetworkInterfaceModelE1000, }) case *types.VirtualVmxnet3: obj := d - resp = append(resp, networkInfo{ + result = append(result, source.NetworkInfo{ NetworkName: obj.DeviceInfo.GetDescription().Summary, MAC: obj.MacAddress, + Model: migration.NetworkInterfaceModelVirtio, }) case *types.VirtualVmxnet2: obj := d - resp = append(resp, networkInfo{ + result = append(result, source.NetworkInfo{ NetworkName: obj.DeviceInfo.GetDescription().Summary, MAC: obj.MacAddress, + Model: migration.NetworkInterfaceModelVirtio, + }) + case *types.VirtualPCNet32: + obj := d + result = append(result, source.NetworkInfo{ + NetworkName: obj.DeviceInfo.GetDescription().Summary, + MAC: obj.MacAddress, + Model: migration.NetworkInterfaceModelPcnet, }) } } - return resp -} - -func mapNetworkCards(networkCards []networkInfo, mapping []migration.NetworkMapping) []networkInfo { - var retNetwork []networkInfo - for _, nc := range networkCards { - for _, m := range mapping { - if m.SourceNetwork == nc.NetworkName { - nc.MappedNetwork = m.DestinationNetwork - retNetwork = append(retNetwork, nc) - } - } - } - - return retNetwork + return result } // adapterType tries to identify the disk bus type from vmware diff --git a/pkg/source/vmware/client_test.go b/pkg/source/vmware/client_test.go index 7f00e7a..726eb3d 100644 --- a/pkg/source/vmware/client_test.go +++ b/pkg/source/vmware/client_test.go @@ -19,6 +19,7 @@ import ( migration "github.com/harvester/vm-import-controller/pkg/apis/migration.harvesterhci.io/v1beta1" "github.com/harvester/vm-import-controller/pkg/server" + "github.com/harvester/vm-import-controller/pkg/source" ) var vcsimPort string @@ -256,7 +257,7 @@ func Test_GenerateVirtualMachine(t *testing.T) { assert.Len(newVM.Spec.Template.Spec.Domain.Devices.Interfaces, 1, "should have found a network map") assert.Equal(newVM.Spec.Template.Spec.Domain.Memory.Guest.String(), "32M", "expected VM to have 32M memory") assert.NotEmpty(newVM.Spec.Template.Spec.Domain.Resources.Limits, "expect to find resource requests to be present") - + assert.Equal(newVM.Spec.Template.Spec.Domain.Devices.Interfaces[0].Model, migration.NetworkInterfaceModelE1000, "expected to have a NIC with e1000 model") } func Test_GenerateVirtualMachine_secureboot(t *testing.T) { @@ -365,7 +366,7 @@ func Test_identifyNetworkCards(t *testing.T) { err = vmObj.Properties(c.ctx, vmObj.Reference(), []string{}, &o) assert.NoError(err, "expected no error looking up vmObj properties") - networkInfo := identifyNetworkCards(o.Config.Hardware.Device) + networkInfo := generateNetworkInfos(o.Config.Hardware.Device) assert.Len(networkInfo, 1, "expected to find only 1 item in the networkInfo") networkMapping := []migration.NetworkMapping{ { @@ -373,15 +374,17 @@ func Test_identifyNetworkCards(t *testing.T) { DestinationNetwork: "harvester1", }, { - SourceNetwork: "DVSwitch: fea97929-4b2d-5972-b146-930c6d0b4014", - DestinationNetwork: "pod-network", + SourceNetwork: "DVSwitch: fea97929-4b2d-5972-b146-930c6d0b4014", + DestinationNetwork: "pod-network", + NetworkInterfaceModel: pointer.String(migration.NetworkInterfaceModelRtl8139), }, } - mappedInfo := mapNetworkCards(networkInfo, networkMapping) + mappedInfo := source.MapNetworks(networkInfo, networkMapping) assert.Len(mappedInfo, 1, "expected to find only 1 item in the mapped networkinfo") + assert.Equal(mappedInfo[0].Model, "rtl8139", "expected to have a NIC with rtl8139 model") noNetworkMapping := []migration.NetworkMapping{} - noMappedInfo := mapNetworkCards(networkInfo, noNetworkMapping) + noMappedInfo := source.MapNetworks(networkInfo, noNetworkMapping) assert.Len(noMappedInfo, 0, "expected to find no item in the mapped networkinfo") }