Skip to content

Commit a125364

Browse files
committed
MTV-2025 | NICs mapping is unordered
Issue: When migrating VMs with multiple NICs the mapping order must match source VM order Fix: Since rhel 6 swapping/renaming devices isn't supported anymore due to kernel issues. Since we can't prevent that we will add a validation to the NICs mapping to make sure the order is correct, if not we'll issue a warning during migration plan's creation so the user will be aware and could work this around by creating the network map in the same order as source VM. Ref: https://issues.redhat.com/browse/MTV-2025
1 parent 49971fe commit a125364

File tree

9 files changed

+91
-1
lines changed

9 files changed

+91
-1
lines changed

pkg/controller/plan/adapter/base/doc.go

+2
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ type Validator interface {
142142
DirectStorage(vmRef ref.Ref) (bool, error)
143143
// Validate that a VM's networks have been mapped.
144144
NetworksMapped(vmRef ref.Ref) (bool, error)
145+
// Validate the network mapping order.
146+
NetworkMappingOrder(vmRef ref.Ref) (bool, []string, error)
145147
// Validate that a VM's Host isn't in maintenance mode.
146148
MaintenanceMode(vmRef ref.Ref) (bool, error)
147149
// Validate whether warm migration is supported from this provider type.

pkg/controller/plan/adapter/ocp/validator.go

+5
Original file line numberDiff line numberDiff line change
@@ -203,3 +203,8 @@ func (r *Validator) StaticIPs(vmRef ref.Ref) (bool, error) {
203203
func (r *Validator) ChangeTrackingEnabled(vmRef ref.Ref) (bool, error) {
204204
return true, nil
205205
}
206+
207+
// NO-OP
208+
func (r *Validator) NetworkMappingOrder(vmRef ref.Ref) (bool, []string, error) {
209+
return true, nil, nil
210+
}

pkg/controller/plan/adapter/openstack/validator.go

+5
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,8 @@ func (r *Validator) StaticIPs(vmRef ref.Ref) (bool, error) {
127127
func (r *Validator) ChangeTrackingEnabled(vmRef ref.Ref) (bool, error) {
128128
return true, nil
129129
}
130+
131+
// NO-OP
132+
func (r *Validator) NetworkMappingOrder(vmRef ref.Ref) (bool, []string, error) {
133+
return true, nil, nil
134+
}

pkg/controller/plan/adapter/ova/validator.go

+5
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,8 @@ func (r *Validator) ChangeTrackingEnabled(vmRef ref.Ref) (bool, error) {
118118
// Validate that the vm has the change tracking enabled
119119
return true, nil
120120
}
121+
122+
// NO-OP
123+
func (r *Validator) NetworkMappingOrder(vmRef ref.Ref) (bool, []string, error) {
124+
return true, nil, nil
125+
}

pkg/controller/plan/adapter/ovirt/validator.go

+5
Original file line numberDiff line numberDiff line change
@@ -184,3 +184,8 @@ func (r *Validator) ChangeTrackingEnabled(vmRef ref.Ref) (bool, error) {
184184
// Validate that the vm has the change tracking enabled
185185
return true, nil
186186
}
187+
188+
// NO-OP
189+
func (r *Validator) NetworkMappingOrder(vmRef ref.Ref) (bool, []string, error) {
190+
return true, nil, nil
191+
}

pkg/controller/plan/adapter/vsphere/validator.go

+45
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,51 @@ func (r *Validator) WarmMigration() (ok bool) {
3434
return
3535
}
3636

37+
// Validate the VM's network mapping order.
38+
func (r *Validator) NetworkMappingOrder(vmRef ref.Ref) (ok bool, correctOrder []string, err error) {
39+
if r.plan.Referenced.Map.Network == nil {
40+
return false, nil, nil
41+
}
42+
43+
vm := &model.VM{}
44+
err = r.inventory.Find(vm, vmRef)
45+
if err != nil {
46+
return false, nil, liberr.Wrap(err, "vm", vmRef.String())
47+
}
48+
49+
mapping := r.plan.Referenced.Map.Network.Spec.Map
50+
51+
// Ensure both lists are of equal length
52+
if len(vm.NICs) != len(mapping) {
53+
return false, nil, nil
54+
}
55+
56+
// Create a slice to store the correct order of network IDs
57+
correctOrder = make([]string, len(vm.NICs))
58+
for i, nic := range vm.NICs {
59+
correctOrder[i] = nic.Network.ID
60+
}
61+
62+
// Iterate by index to ensure one-to-one mapping
63+
for i := range mapping {
64+
mapped := &mapping[i]
65+
network := &model.Network{}
66+
// Fetch the network at the corresponding index
67+
fErr := r.inventory.Find(network, mapped.Source)
68+
if fErr != nil {
69+
return false, nil, fErr
70+
}
71+
72+
// Ensure NIC and network IDs match exactly at the same index
73+
if vm.NICs[i].Network.ID != network.ID {
74+
return false, correctOrder, nil // Mismatch found, return the failing NIC
75+
}
76+
}
77+
78+
ok = true
79+
return ok, nil, nil
80+
}
81+
3782
// Validate that a VM's networks have been mapped.
3883
func (r *Validator) NetworksMapped(vmRef ref.Ref) (ok bool, err error) {
3984
if r.plan.Referenced.Map.Network == nil {

pkg/controller/plan/validation.go

+19
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"net"
1111
"path"
1212
"strconv"
13+
"strings"
1314
"text/template"
1415

1516
k8snet "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
@@ -78,6 +79,7 @@ const (
7879
ValidatingVDDK = "ValidatingVDDK"
7980
VDDKInitImageNotReady = "VDDKInitImageNotReady"
8081
VDDKInitImageUnavailable = "VDDKInitImageUnavailable"
82+
NetMapOrder = "NetworkMapUnordered"
8183
)
8284

8385
// Categories
@@ -573,6 +575,13 @@ func (r *Reconciler) validateVM(plan *api.Plan) error {
573575
Status: True,
574576
Category: Warn,
575577
Message: "VMs with shared disk can not be migrated.", // This should be set by the provider validator
578+
}
579+
unorderedNics := libcnd.Condition{
580+
Type: NetMapOrder,
581+
Status: True,
582+
Reason: NotValid,
583+
Category: Warn,
584+
Message: "VM network mapping is unordered.",
576585
Items: []string{},
577586
}
578587

@@ -660,6 +669,14 @@ func (r *Reconciler) validateVM(plan *api.Plan) error {
660669
if !ok {
661670
multiplePodNetworkMappings.Items = append(multiplePodNetworkMappings.Items, ref.String())
662671
}
672+
ok, correctOrder, err := validator.NetworkMappingOrder(*ref)
673+
if err != nil {
674+
return err
675+
}
676+
if !ok {
677+
unorderedNics.Message += fmt.Sprintf("\n Expected order: %s", strings.Join(correctOrder, ", "))
678+
unorderedNics.Items = append(unorderedNics.Items, ref.String())
679+
}
663680
}
664681
if plan.Referenced.Map.Storage != nil {
665682
ok, err := validator.StorageMapped(*ref)
@@ -829,6 +846,8 @@ func (r *Reconciler) validateVM(plan *api.Plan) error {
829846
}
830847
if len(targetNameNotUnique.Items) > 0 {
831848
plan.Status.SetCondition(targetNameNotUnique)
849+
if len(unorderedNics.Items) > 0 {
850+
plan.Status.SetCondition(unorderedNics)
832851
}
833852

834853
return nil

pkg/controller/provider/container/vsphere/model.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,7 @@ func (v *VmAdapter) Apply(u types.ObjectUpdate) {
717717
if devArray, cast := p.Val.(types.ArrayOfVirtualDevice); cast {
718718
devList := []model.Device{}
719719
nicList := []model.NIC{}
720+
nicsIndex := 0
720721
for _, dev := range devArray.VirtualDevice {
721722
var nic *types.VirtualEthernetCard
722723
switch device := dev.(type) {
@@ -763,12 +764,14 @@ func (v *VmAdapter) Apply(u types.ObjectUpdate) {
763764
nicList = append(
764765
nicList,
765766
model.NIC{
766-
MAC: nic.MacAddress,
767+
MAC: nic.MacAddress,
768+
Order: strconv.Itoa(nicsIndex),
767769
Network: model.Ref{
768770
Kind: model.NetKind,
769771
ID: network,
770772
},
771773
})
774+
nicsIndex++
772775
}
773776
}
774777
v.model.Devices = devList

pkg/controller/provider/model/vsphere/model.go

+1
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ type Device struct {
305305
type NIC struct {
306306
Network Ref `json:"network"`
307307
MAC string `json:"mac"`
308+
Order string `json:"order"`
308309
}
309310

310311
// Guest network.

0 commit comments

Comments
 (0)