Skip to content

Commit 652f53c

Browse files
committed
feat: use the node VM customAttributes to set the nodes providerID if it exists
1 parent dc54e21 commit 652f53c

File tree

5 files changed

+154
-5
lines changed

5 files changed

+154
-5
lines changed

internal/testing/mock/constants.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@ const (
3434
MockVMNamePoweredOnClusterCategories = "mock-vm-poweredon-cluster-categories"
3535
MockVMNameDpOffload = "mock-vm-dp-offload"
3636
MockVMNameSecondaryIPs = "mock-vm-secondary-ips"
37+
MockVMNameCustomProviderID = "mock-vm-custom-provider-id"
3738

38-
MockSecondaryIP1 = "2.2.2.2"
39-
MockSecondaryIP2 = "3.3.3.3"
39+
MockSecondaryIP1 = "2.2.2.2"
40+
MockSecondaryIP2 = "3.3.3.3"
41+
MockCustomProviderID = "custom-provider-uuid-1234"
4042

4143
MockNodeNameVMNotExisting = "mock-node-no-vm-exists"
4244
MockNodeNameNoSystemUUID = "mock-node-no-system-uuid"
@@ -65,6 +67,7 @@ const (
6567
MockVMPoweredOnClusterCategoriesUUID = "00000000-0000-0000-0000-000000000105"
6668
MockVMDpOffloadUUID = "00000000-0000-0000-0000-000000000106"
6769
MockVMSecondaryIPsUUID = "00000000-0000-0000-0000-000000000107"
70+
MockVMCustomProviderIDUUID = "00000000-0000-0000-0000-000000000108"
6871
MockCategoryRegionUUID = "00000000-0000-0000-0000-000000000200"
6972
MockCategoryZoneUUID = "00000000-0000-0000-0000-000000000201"
7073
)

internal/testing/mock/helpers.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,49 @@ func getDefaultVMWithSecondaryIPs(vmName string, vmUUID string, cluster *cluster
175175
return vm
176176
}
177177

178+
func getDefaultVMWithCustomAttributes(vmName string, vmUUID string, cluster *clusterModels.Cluster, host *clusterModels.Host, customAttributes []string) *vmmModels.Vm {
179+
nic := vmmModels.NewNic()
180+
nicNetInfo := vmmModels.NewVirtualEthernetNicNetworkInfo()
181+
182+
nicNetInfo.Ipv4Config = vmmModels.NewIpv4Config()
183+
nicNetInfo.Ipv4Config.IpAddress = &vmmCommonModels.IPv4Address{
184+
Value: ptr.To(MockIP),
185+
}
186+
187+
nicNetInfo.Ipv4Info = vmmModels.NewIpv4Info()
188+
nicNetInfo.Ipv4Info.LearnedIpAddresses = []vmmCommonModels.IPv4Address{
189+
{
190+
Value: ptr.To(MockIP),
191+
},
192+
}
193+
194+
err := nic.SetNicNetworkInfo(*nicNetInfo)
195+
if err != nil {
196+
fmt.Printf("error setting nic network info: %+v\n", err)
197+
return nil
198+
}
199+
200+
vm := &vmmModels.Vm{
201+
ExtId: ptr.To(vmUUID),
202+
Categories: make([]vmmModels.CategoryReference, 0),
203+
PowerState: vmmModels.POWERSTATE_ON.Ref(),
204+
Name: ptr.To(vmName),
205+
CustomAttributes: customAttributes,
206+
Cluster: &vmmModels.ClusterReference{
207+
ExtId: cluster.ExtId,
208+
},
209+
Nics: []vmmModels.Nic{
210+
*nic,
211+
},
212+
}
213+
if host != nil {
214+
vm.Host = &vmmModels.HostReference{
215+
ExtId: host.ExtId,
216+
}
217+
}
218+
return vm
219+
}
220+
178221
func getDefaultCluster(clusterName string, clusterUUID string) *clusterModels.Cluster {
179222
cluster := clusterModels.NewCluster()
180223
cluster.ExtId = ptr.To(clusterUUID)

internal/testing/mock/mock_environment.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,18 @@ func CreateMockEnvironment(ctx context.Context, kClient *fake.Clientset) (*MockE
181181
return nil, err
182182
}
183183

184+
customProviderIDVM := getDefaultVMWithCustomAttributes(
185+
MockVMNameCustomProviderID,
186+
MockVMCustomProviderIDUUID,
187+
cluster,
188+
host,
189+
[]string{"providerID:" + MockCustomProviderID, "otherKey:otherValue"},
190+
)
191+
customProviderIDNode, err := createNodeForVM(ctx, kClient, customProviderIDVM)
192+
if err != nil {
193+
return nil, err
194+
}
195+
184196
return &MockEnvironment{
185197
managedMockMachines: map[string]*vmmModels.Vm{
186198
*poweredOnVM.ExtId: poweredOnVM,
@@ -191,6 +203,7 @@ func CreateMockEnvironment(ctx context.Context, kClient *fake.Clientset) (*MockE
191203
*filteredAddressesVM.ExtId: filteredAddressesVM,
192204
*dpOffloadVM.ExtId: dpOffloadVM,
193205
*secondaryIPsVM.ExtId: secondaryIPsVM,
206+
*customProviderIDVM.ExtId: customProviderIDVM,
194207
},
195208
managedMockClusters: map[string]*clusterModels.Cluster{
196209
*cluster.ExtId: cluster,
@@ -215,6 +228,7 @@ func CreateMockEnvironment(ctx context.Context, kClient *fake.Clientset) (*MockE
215228
MockVMNameFilteredNodeAddresses: filteredAddressesNode,
216229
MockVMNameDpOffload: dpOffloadNode,
217230
MockVMNameSecondaryIPs: secondaryIPsNode,
231+
MockVMNameCustomProviderID: customProviderIDNode,
218232
},
219233
vmNameToExtId: map[string]string{
220234
MockVMNamePoweredOn: *poweredOnVM.ExtId,
@@ -225,6 +239,7 @@ func CreateMockEnvironment(ctx context.Context, kClient *fake.Clientset) (*MockE
225239
MockVMNamePoweredOnClusterCategories: *poweredOnVMClusterCategories.ExtId,
226240
MockVMNameDpOffload: *dpOffloadVM.ExtId,
227241
MockVMNameSecondaryIPs: *secondaryIPsVM.ExtId,
242+
MockVMNameCustomProviderID: *customProviderIDVM.ExtId,
228243
},
229244
}, nil
230245
}

pkg/provider/manager.go

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,15 +123,17 @@ 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+
// Generate providerID from VM (checks customAttributes first, then falls back to vmUUID)
136+
providerID, err := n.generateProviderIDFromVM(ctx, vm)
135137
if err != nil {
136138
return nil, err
137139
}
@@ -322,6 +324,39 @@ func (n *nutanixManager) generateProviderID(ctx context.Context, vmUUID string)
322324
return fmt.Sprintf("%s://%s", constants.ProviderName, strings.ToLower(vmUUID)), nil
323325
}
324326

327+
// generateProviderIDFromVM generates the providerID for a node from the VM object.
328+
// It first checks if the VM's customAttributes field has "providerID:<UUID>".
329+
// If yes, it uses this UUID value to set the providerID.
330+
// If not, it falls back to using the vmUUID (backward compatible).
331+
func (n *nutanixManager) generateProviderIDFromVM(ctx context.Context, vm *vmmModels.Vm) (string, error) {
332+
if vm == nil {
333+
return "", fmt.Errorf("VM cannot be nil when generating nutanix provider ID for node")
334+
}
335+
336+
// Check if customAttributes contains providerID
337+
if vm.CustomAttributes != nil {
338+
for _, attr := range vm.CustomAttributes {
339+
// customAttributes are in the format "key:value"
340+
parts := strings.SplitN(attr, ":", 2)
341+
if len(parts) == 2 && strings.TrimSpace(parts[0]) == "providerID" {
342+
customProviderID := strings.TrimSpace(parts[1])
343+
if customProviderID != "" {
344+
klog.V(2).Infof("Using custom providerID from customAttributes: %s", customProviderID) //nolint:typecheck
345+
return fmt.Sprintf("%s://%s", constants.ProviderName, strings.ToLower(customProviderID)), nil
346+
}
347+
}
348+
}
349+
}
350+
351+
// Fallback to using vmUUID
352+
if vm.ExtId == nil || *vm.ExtId == "" {
353+
return "", fmt.Errorf("VM ExtId cannot be empty when generating nutanix provider ID for node")
354+
}
355+
356+
klog.V(2).Infof("Using VM ExtId as providerID: %s", *vm.ExtId) //nolint:typecheck
357+
return fmt.Sprintf("%s://%s", constants.ProviderName, strings.ToLower(*vm.ExtId)), nil
358+
}
359+
325360
func (n *nutanixManager) isNodeAddressesSet(node *v1.Node) bool {
326361
if node == nil {
327362
return false

pkg/provider/manager_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,59 @@ var _ = Describe("Test Manager", func() { // nolint:typecheck
268268
})
269269
})
270270

271+
Context("Test generateProviderIDFromVM", func() {
272+
It("should fail if VM is nil", func() { // nolint:typecheck
273+
_, err := m.generateProviderIDFromVM(ctx, nil)
274+
Expect(err).Should(HaveOccurred())
275+
})
276+
277+
It("should return providerID from VM ExtId when no customAttributes", func() { // nolint:typecheck
278+
vm := mockEnvironment.GetVM(ctx, mock.MockVMNamePoweredOn)
279+
Expect(vm).ToNot(BeNil())
280+
providerID, err := m.generateProviderIDFromVM(ctx, vm)
281+
Expect(err).ToNot(HaveOccurred())
282+
Expect(providerID).To(Equal(fmt.Sprintf("nutanix://%s", *vm.ExtId)))
283+
})
284+
285+
It("should return providerID from customAttributes when present", func() { // nolint:typecheck
286+
vm := mockEnvironment.GetVM(ctx, mock.MockVMNameCustomProviderID)
287+
Expect(vm).ToNot(BeNil())
288+
providerID, err := m.generateProviderIDFromVM(ctx, vm)
289+
Expect(err).ToNot(HaveOccurred())
290+
Expect(providerID).To(Equal(fmt.Sprintf("nutanix://%s", mock.MockCustomProviderID)))
291+
})
292+
293+
It("should handle customAttributes with spaces around providerID", func() { // nolint:typecheck
294+
vm := mockEnvironment.GetVM(ctx, mock.MockVMNamePoweredOn)
295+
Expect(vm).ToNot(BeNil())
296+
// Add customAttributes with spaces
297+
vm.CustomAttributes = []string{" providerID : test-uuid-with-spaces ", "otherKey:value"}
298+
providerID, err := m.generateProviderIDFromVM(ctx, vm)
299+
Expect(err).ToNot(HaveOccurred())
300+
Expect(providerID).To(Equal("nutanix://test-uuid-with-spaces"))
301+
})
302+
303+
It("should fallback to ExtId when customAttributes has no providerID", func() { // nolint:typecheck
304+
vm := mockEnvironment.GetVM(ctx, mock.MockVMNamePoweredOn)
305+
Expect(vm).ToNot(BeNil())
306+
// Add customAttributes without providerID
307+
vm.CustomAttributes = []string{"someKey:someValue", "anotherKey:anotherValue"}
308+
providerID, err := m.generateProviderIDFromVM(ctx, vm)
309+
Expect(err).ToNot(HaveOccurred())
310+
Expect(providerID).To(Equal(fmt.Sprintf("nutanix://%s", *vm.ExtId)))
311+
})
312+
313+
It("should fallback to ExtId when providerID value is empty", func() { // nolint:typecheck
314+
vm := mockEnvironment.GetVM(ctx, mock.MockVMNamePoweredOn)
315+
Expect(vm).ToNot(BeNil())
316+
// Add customAttributes with empty providerID value
317+
vm.CustomAttributes = []string{"providerID:", "otherKey:value"}
318+
providerID, err := m.generateProviderIDFromVM(ctx, vm)
319+
Expect(err).ToNot(HaveOccurred())
320+
Expect(providerID).To(Equal(fmt.Sprintf("nutanix://%s", *vm.ExtId)))
321+
})
322+
})
323+
271324
Context("Test getTopologyInfoFromVM", func() {
272325
It("should fail if vm is empty", func() { // nolint:typecheck
273326
err := m.getTopologyInfoFromVM(ctx, nClient, nil, &config.TopologyInfo{})

0 commit comments

Comments
 (0)