From 44248a3f4810a23f35efec675cb25af0c0ae75af Mon Sep 17 00:00:00 2001 From: Gaurav Mehta Date: Fri, 13 Sep 2024 11:21:45 +1000 Subject: [PATCH] address openstack network duplication when interface may have both ipv6 and ipv4 addresses and add preflight check to identify duplicate source network definitions (cherry picked from commit 03a8ef08e98605799b88cd7a1a9a2ef164eb16f1) --- pkg/controllers/migration/virtualmachine.go | 11 +++++ pkg/source/openstack/client.go | 52 ++++++++++++++------- pkg/source/openstack/client_test.go | 14 ++++++ 3 files changed, 61 insertions(+), 16 deletions(-) diff --git a/pkg/controllers/migration/virtualmachine.go b/pkg/controllers/migration/virtualmachine.go index 3fc6504..6d579b6 100644 --- a/pkg/controllers/migration/virtualmachine.go +++ b/pkg/controllers/migration/virtualmachine.go @@ -177,6 +177,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 d04897f..2a48758 100644 --- a/pkg/source/openstack/client.go +++ b/pkg/source/openstack/client.go @@ -334,23 +334,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, @@ -637,3 +625,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") + +}