Skip to content

Commit 240b042

Browse files
committed
feat: use the node VM category value to set the nodes providerID if it exists
1 parent f85e1fa commit 240b042

File tree

5 files changed

+135
-5
lines changed

5 files changed

+135
-5
lines changed

internal/constants/constants.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,7 @@ const (
3333
CustomHostNameLabel string = "nutanix.com/prism-host-name"
3434

3535
PrismCentralService string = "PRISM_CENTRAL"
36+
37+
// AhvMetroCategoryKeyPrefix is the prefix for the ahvMetro category key.
38+
AhvMetroCategoryKeyPrefix string = "ahvMetro"
3639
)

internal/testing/mock/constants.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const (
3434
MockVMNamePoweredOnClusterCategories = "mock-vm-poweredon-cluster-categories"
3535
MockVMNameDpOffload = "mock-vm-dp-offload"
3636
MockVMNameSecondaryIPs = "mock-vm-secondary-ips"
37+
MockVMNameAhvMetro = "mock-vm-ahvmetro"
3738

3839
MockSecondaryIP1 = "2.2.2.2"
3940
MockSecondaryIP2 = "3.3.3.3"
@@ -65,6 +66,9 @@ const (
6566
MockVMPoweredOnClusterCategoriesUUID = "00000000-0000-0000-0000-000000000105"
6667
MockVMDpOffloadUUID = "00000000-0000-0000-0000-000000000106"
6768
MockVMSecondaryIPsUUID = "00000000-0000-0000-0000-000000000107"
69+
MockVMAhvMetroUUID = "00000000-0000-0000-0000-000000000108"
6870
MockCategoryRegionUUID = "00000000-0000-0000-0000-000000000200"
6971
MockCategoryZoneUUID = "00000000-0000-0000-0000-000000000201"
72+
MockCategoryAhvMetroUUID = "00000000-0000-0000-0000-000000000202"
73+
MockAhvMetroTargetVMUUID = "00000000-0000-0000-0000-000000000999"
7074
)

internal/testing/mock/mock_environment.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ func CreateMockEnvironment(ctx context.Context, kClient *fake.Clientset) (*MockE
8686
// Create categories with consistent UUIDs
8787
regionCategory := getDefaultCategory(MockDefaultRegion, MockCategoryRegionUUID, MockRegion)
8888
zoneCategory := getDefaultCategory(MockDefaultZone, MockCategoryZoneUUID, MockZone)
89+
// ahvMetro category key format: ahvMetro-<clusterName>-<vmName>
90+
ahvMetroCategoryKey := "ahvMetro-" + MockCluster + "-" + MockVMNameAhvMetro
91+
ahvMetroCategory := getDefaultCategory(ahvMetroCategoryKey, MockCategoryAhvMetroUUID, MockAhvMetroTargetVMUUID)
8992

9093
// Create VMs with consistent UUIDs
9194
poweredOnVM := getDefaultVM(MockVMNamePoweredOn, MockVMPoweredOnUUID, cluster, host)
@@ -181,6 +184,16 @@ func CreateMockEnvironment(ctx context.Context, kClient *fake.Clientset) (*MockE
181184
return nil, err
182185
}
183186

187+
// VM with ahvMetro category - the category value contains the target vmUUID for providerID
188+
ahvMetroVM := getDefaultVM(MockVMNameAhvMetro, MockVMAhvMetroUUID, cluster, host)
189+
ahvMetroVM.Categories = []vmmModels.CategoryReference{
190+
{ExtId: ahvMetroCategory.ExtId},
191+
}
192+
ahvMetroNode, err := createNodeForVM(ctx, kClient, ahvMetroVM)
193+
if err != nil {
194+
return nil, err
195+
}
196+
184197
return &MockEnvironment{
185198
managedMockMachines: map[string]*vmmModels.Vm{
186199
*poweredOnVM.ExtId: poweredOnVM,
@@ -191,6 +204,7 @@ func CreateMockEnvironment(ctx context.Context, kClient *fake.Clientset) (*MockE
191204
*filteredAddressesVM.ExtId: filteredAddressesVM,
192205
*dpOffloadVM.ExtId: dpOffloadVM,
193206
*secondaryIPsVM.ExtId: secondaryIPsVM,
207+
*ahvMetroVM.ExtId: ahvMetroVM,
194208
},
195209
managedMockClusters: map[string]*clusterModels.Cluster{
196210
*cluster.ExtId: cluster,
@@ -201,8 +215,9 @@ func CreateMockEnvironment(ctx context.Context, kClient *fake.Clientset) (*MockE
201215
*host.ExtId: host,
202216
},
203217
managedMockCategories: map[string]*prismModels.Category{
204-
*regionCategory.ExtId: regionCategory,
205-
*zoneCategory.ExtId: zoneCategory,
218+
*regionCategory.ExtId: regionCategory,
219+
*zoneCategory.ExtId: zoneCategory,
220+
*ahvMetroCategory.ExtId: ahvMetroCategory,
206221
},
207222
managedNodes: map[string]*v1.Node{
208223
MockVMNamePoweredOn: poweredOnNode,
@@ -215,6 +230,7 @@ func CreateMockEnvironment(ctx context.Context, kClient *fake.Clientset) (*MockE
215230
MockVMNameFilteredNodeAddresses: filteredAddressesNode,
216231
MockVMNameDpOffload: dpOffloadNode,
217232
MockVMNameSecondaryIPs: secondaryIPsNode,
233+
MockVMNameAhvMetro: ahvMetroNode,
218234
},
219235
vmNameToExtId: map[string]string{
220236
MockVMNamePoweredOn: *poweredOnVM.ExtId,
@@ -225,6 +241,7 @@ func CreateMockEnvironment(ctx context.Context, kClient *fake.Clientset) (*MockE
225241
MockVMNamePoweredOnClusterCategories: *poweredOnVMClusterCategories.ExtId,
226242
MockVMNameDpOffload: *dpOffloadVM.ExtId,
227243
MockVMNameSecondaryIPs: *secondaryIPsVM.ExtId,
244+
MockVMNameAhvMetro: *ahvMetroVM.ExtId,
228245
},
229246
}, nil
230247
}

pkg/provider/manager.go

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,15 +123,26 @@ func (n *nutanixManager) getInstanceMetadata(ctx context.Context, node *v1.Node)
123123
return nil, err
124124
}
125125

126-
providerID, err := n.generateProviderID(ctx, vmUUID)
126+
nClient, err := n.nutanixClient.Get()
127127
if err != nil {
128128
return nil, err
129129
}
130-
nClient, err := n.nutanixClient.Get()
130+
vm, err := nClient.GetVM(ctx, vmUUID)
131131
if err != nil {
132132
return nil, err
133133
}
134-
vm, err := nClient.GetVM(ctx, vmUUID)
134+
135+
// Check for ahvMetro category to determine the providerID vmUUID
136+
providerVMUUID, err := n.getVMUUIDFromAhvMetroCategory(ctx, nClient, vm)
137+
if err != nil {
138+
return nil, err
139+
}
140+
if providerVMUUID == "" {
141+
// No ahvMetro category found, use the SystemUUID as before
142+
providerVMUUID = vmUUID
143+
}
144+
145+
providerID, err := n.generateProviderID(ctx, providerVMUUID)
135146
if err != nil {
136147
return nil, err
137148
}
@@ -614,6 +625,61 @@ func (n *nutanixManager) getTopologyInfoFromVM(ctx context.Context, nClient inte
614625
return nil
615626
}
616627

628+
// getVMUUIDFromAhvMetroCategory checks if the VM has an ahvMetro category and returns its value.
629+
// The expected category key format is: ahvMetro-<clusterName>-<vmName>
630+
// The category value contains the vmUUID to be used for the providerID.
631+
// Returns empty string if no matching category is found.
632+
func (n *nutanixManager) getVMUUIDFromAhvMetroCategory(ctx context.Context, nClient interfaces.Prism, vm *vmmModels.Vm) (string, error) {
633+
if vm == nil {
634+
return "", fmt.Errorf("vm cannot be nil when searching for ahvMetro category")
635+
}
636+
if nClient == nil {
637+
return "", fmt.Errorf("nutanix client cannot be nil when searching for ahvMetro category")
638+
}
639+
640+
if vm.Cluster == nil || vm.Cluster.ExtId == nil || *vm.Cluster.ExtId == "" {
641+
klog.V(1).Infof("vm %s has no cluster reference, skipping ahvMetro category lookup", *vm.Name) //nolint:typecheck
642+
return "", nil
643+
}
644+
645+
// Get the cluster name for the expected category key
646+
cluster, err := nClient.GetCluster(ctx, *vm.Cluster.ExtId)
647+
if err != nil {
648+
return "", fmt.Errorf("failed to get cluster for ahvMetro category lookup: %v", err)
649+
}
650+
if cluster == nil || cluster.Name == nil {
651+
return "", nil
652+
}
653+
654+
// Build the expected category key: ahvMetro-<clusterName>-<vmName>
655+
expectedCategoryKey := fmt.Sprintf("%s-%s-%s", constants.AhvMetroCategoryKeyPrefix, *cluster.Name, *vm.Name)
656+
klog.V(1).Infof("looking for ahvMetro category with key: %s", expectedCategoryKey) //nolint:typecheck
657+
658+
// Iterate through VM categories to find the ahvMetro category
659+
for _, categoryRef := range vm.Categories {
660+
if categoryRef.ExtId == nil {
661+
continue
662+
}
663+
664+
category, err := nClient.GetCategory(ctx, *categoryRef.ExtId)
665+
if err != nil {
666+
klog.V(1).Infof("failed to get category %s: %v", *categoryRef.ExtId, err) //nolint:typecheck
667+
continue
668+
}
669+
if category == nil || category.Key == nil || category.Value == nil {
670+
continue
671+
}
672+
673+
if *category.Key == expectedCategoryKey {
674+
klog.V(1).Infof("found ahvMetro category with key %s, value (vmUUID): %s", *category.Key, *category.Value) //nolint:typecheck
675+
return strings.ToLower(*category.Value), nil
676+
}
677+
}
678+
679+
klog.V(1).Infof("no ahvMetro category found for VM %s", *vm.Name) //nolint:typecheck
680+
return "", nil
681+
}
682+
617683
func (n *nutanixManager) hasEmptyTopologyInfo(ti config.TopologyInfo) bool {
618684
if ti.Zone == "" {
619685
return true

pkg/provider/manager_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,4 +313,44 @@ var _ = Describe("Test Manager", func() { // nolint:typecheck
313313
Expect(err).Should(HaveOccurred())
314314
})
315315
})
316+
317+
Context("Test getVMUUIDFromAhvMetroCategory", func() {
318+
It("should fail if vm is nil", func() { // nolint:typecheck
319+
_, err := m.getVMUUIDFromAhvMetroCategory(ctx, nClient, nil)
320+
Expect(err).Should(HaveOccurred())
321+
})
322+
323+
It("should fail if nutanixClient is nil", func() { // nolint:typecheck
324+
vm := mockEnvironment.GetVM(ctx, mock.MockVMNamePoweredOn)
325+
_, err := m.getVMUUIDFromAhvMetroCategory(ctx, nil, vm)
326+
Expect(err).Should(HaveOccurred())
327+
})
328+
329+
It("should return empty string if VM has no ahvMetro category", func() { // nolint:typecheck
330+
vm := mockEnvironment.GetVM(ctx, mock.MockVMNamePoweredOn)
331+
Expect(vm).ToNot(BeNil())
332+
vmUUID, err := m.getVMUUIDFromAhvMetroCategory(ctx, nClient, vm)
333+
Expect(err).ShouldNot(HaveOccurred())
334+
Expect(vmUUID).To(BeEmpty())
335+
})
336+
337+
It("should return the ahvMetro category value when present", func() { // nolint:typecheck
338+
vm := mockEnvironment.GetVM(ctx, mock.MockVMNameAhvMetro)
339+
Expect(vm).ToNot(BeNil())
340+
vmUUID, err := m.getVMUUIDFromAhvMetroCategory(ctx, nClient, vm)
341+
Expect(err).ShouldNot(HaveOccurred())
342+
// The returned value should be lowercase
343+
Expect(vmUUID).To(Equal(mock.MockAhvMetroTargetVMUUID))
344+
})
345+
346+
It("should return empty string if VM has no cluster reference", func() { // nolint:typecheck
347+
vm := mockEnvironment.GetVM(ctx, mock.MockVMNamePoweredOn)
348+
Expect(vm).ToNot(BeNil())
349+
// Remove cluster reference
350+
vm.Cluster = nil
351+
vmUUID, err := m.getVMUUIDFromAhvMetroCategory(ctx, nClient, vm)
352+
Expect(err).ShouldNot(HaveOccurred())
353+
Expect(vmUUID).To(BeEmpty())
354+
})
355+
})
316356
})

0 commit comments

Comments
 (0)