diff --git a/pkg/controllers/migration/virtualmachine.go b/pkg/controllers/migration/virtualmachine.go index 6ad0f56..e9652fd 100644 --- a/pkg/controllers/migration/virtualmachine.go +++ b/pkg/controllers/migration/virtualmachine.go @@ -226,6 +226,17 @@ func (h *virtualMachineHandler) preFlightChecks(vm *migration.VirtualMachineImpo } } + // dedup source network names as the same source network name cannot appear twice + sourceNetworkMap := make(map[string]bool) + for _, network := range vm.Spec.Mapping { + _, ok := sourceNetworkMap[network.SourceNetwork] + if !ok { + sourceNetworkMap[network.SourceNetwork] = true + continue + } + return fmt.Errorf("source network %s appears multiple times in vm spec", network.SourceNetwork) + } + return nil } diff --git a/pkg/source/openstack/client.go b/pkg/source/openstack/client.go index 7ba235e..354ddbf 100644 --- a/pkg/source/openstack/client.go +++ b/pkg/source/openstack/client.go @@ -337,23 +337,11 @@ func (c *Client) GenerateVirtualMachine(vm *migration.VirtualMachineImport) (*ku return nil, fmt.Errorf("error getting firware settings: %v", err) } - var networks []networkInfo - for network, values := range vmObj.Addresses { - valArr, ok := values.([]interface{}) - if !ok { - return nil, fmt.Errorf("error asserting interface []interface") - } - for _, v := range valArr { - valMap, ok := v.(map[string]interface{}) - if !ok { - return nil, fmt.Errorf("error asserting network array element into map[string]string") - } - networks = append(networks, networkInfo{ - NetworkName: network, - MAC: valMap["OS-EXT-IPS-MAC:mac_addr"].(string), - }) - } + networks, err := generateNetworkInfo(vmObj.Addresses) + if err != nil { + return nil, err } + newVM := &kubevirt.VirtualMachine{ ObjectMeta: metav1.ObjectMeta{ Name: vm.Spec.VirtualMachineName, @@ -640,3 +628,35 @@ func (c *Client) ImageFirmwareSettings(instance *servers.Server) (bool, bool, bo } return uefiType, tpmEnabled, secureBoot, nil } + +func generateNetworkInfo(info map[string]interface{}) ([]networkInfo, error) { + networks := make([]networkInfo, 0) + uniqueNetworks := make([]networkInfo, 0) + for network, values := range info { + valArr, ok := values.([]interface{}) + if !ok { + return nil, fmt.Errorf("error asserting interface []interface") + } + for _, v := range valArr { + valMap, ok := v.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("error asserting network array element into map[string]string") + } + networks = append(networks, networkInfo{ + NetworkName: network, + MAC: valMap["OS-EXT-IPS-MAC:mac_addr"].(string), + }) + } + } + // 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) + for _, v := range networks { + networksMap[v.MAC] = v + } + + 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 9e4cc52..123f773 100644 --- a/pkg/source/openstack/client_test.go +++ b/pkg/source/openstack/client_test.go @@ -2,6 +2,7 @@ package openstack import ( "context" + "encoding/json" "os" "testing" @@ -124,3 +125,16 @@ func Test_GenerateVirtualMachine(t *testing.T) { 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") } + +func Test_generateNetworkInfo(t *testing.T) { + networkInfoByte := []byte(`{"private":[{"OS-EXT-IPS-MAC:mac_addr":"fa:16:3e:92:5f:45","OS-EXT-IPS:type":"fixed","addr":"fd5b:731d:94e1:0:f816:3eff:fe92:5f45","version":6},{"OS-EXT-IPS-MAC:mac_addr":"fa:16:3e:92:5f:45","OS-EXT-IPS:type":"fixed","addr":"10.0.0.38","version":4}],"shared":[{"OS-EXT-IPS-MAC:mac_addr":"fa:16:3e:ec:49:11","OS-EXT-IPS:type":"fixed","addr":"192.168.233.233","version":4}]}`) + var networkInfoMap map[string]interface{} + assert := require.New(t) + err := json.Unmarshal(networkInfoByte, &networkInfoMap) + assert.NoError(err, "expected no error while unmarshalling network info") + + vmInterfaceDetails, err := generateNetworkInfo(networkInfoMap) + assert.NoError(err, "expected no error while generating network info") + assert.Len(vmInterfaceDetails, 2, "expected to find 2 interfaces only") + +}