Skip to content

Commit c01c8fc

Browse files
committed
vsphereparavirtual: add support for VM Operator API version v1alpha6
1 parent 31593b6 commit c01c8fc

18 files changed

Lines changed: 1639 additions & 54 deletions

File tree

go.mod

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@ module k8s.io/cloud-provider-vsphere
22

33
go 1.26.0
44

5-
replace github.com/vmware-tanzu/vm-operator/pkg/constants/testlabels => github.com/vmware-tanzu/vm-operator/pkg/constants/testlabels v1.9.1-0.20251029150609-93918c59a719
5+
replace github.com/vmware-tanzu/vm-operator/pkg/constants/testlabels => github.com/vmware-tanzu/vm-operator/pkg/constants/testlabels v0.0.0-20260502065817-4ee333ccd54c
66

7-
// vm-operator version is aligned with CAPV https://github.com/kubernetes-sigs/cluster-api-provider-vsphere/blob/main/go.mod#L11
7+
// Temporary local fork of nsx-operator/pkg/apis pending PR #1418 (IPAddressType, AllocationPrefixLength on IPAddressAllocationSpec).
8+
// Remove this replace and bump to the merged version once PR #1418 lands.
9+
replace github.com/vmware-tanzu/nsx-operator/pkg/apis => ./hack/nsx-operator-apis-fork
10+
11+
// vm-operator version: prefer alignment with CAPV https://github.com/kubernetes-sigs/cluster-api-provider-vsphere/blob/main/go.mod#L11
12+
// (may temporarily diverge when CPI needs a newer api/v1alpha6 commit before CAPV bumps).
813
require (
914
github.com/fsnotify/fsnotify v1.9.0
1015
github.com/golang/mock v1.6.0
@@ -14,9 +19,9 @@ require (
1419
github.com/spf13/cobra v1.10.2
1520
github.com/spf13/pflag v1.0.10
1621
github.com/stretchr/testify v1.11.1
17-
github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20240827061921-8f0982975508
18-
github.com/vmware-tanzu/nsx-operator/pkg/client v0.0.0-20240827061921-8f0982975508
19-
github.com/vmware-tanzu/vm-operator/api v1.9.1-0.20251029150609-93918c59a719
22+
github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20260423081355-beab2417344a
23+
github.com/vmware-tanzu/nsx-operator/pkg/client v0.0.0-20260423081355-beab2417344a
24+
github.com/vmware-tanzu/vm-operator/api v1.9.1-0.20260502065817-4ee333ccd54c
2025
github.com/vmware/govmomi v0.53.0
2126
github.com/vmware/vsphere-automation-sdk-go/lib v0.7.0
2227
github.com/vmware/vsphere-automation-sdk-go/runtime v0.7.0

go.sum

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -159,12 +159,10 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
159159
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
160160
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE=
161161
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk=
162-
github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20240827061921-8f0982975508 h1:NBjcpxDcurBzM3uMfX7LpkDE6okU+x7XdDSqVdqXVO8=
163-
github.com/vmware-tanzu/nsx-operator/pkg/apis v0.0.0-20240827061921-8f0982975508/go.mod h1:Q4JzNkNMvjo7pXtlB5/R3oME4Nhah7fAObWgghVmtxk=
164-
github.com/vmware-tanzu/nsx-operator/pkg/client v0.0.0-20240827061921-8f0982975508 h1:oLcoseDTk/8eVXMu74aZQWxaiMTB/ym3CP8NNQ4qRqg=
165-
github.com/vmware-tanzu/nsx-operator/pkg/client v0.0.0-20240827061921-8f0982975508/go.mod h1:Hsn4QLNjQA6wQYGI6IlQJrTqM+29KWCVdyFgS7a2Sck=
166-
github.com/vmware-tanzu/vm-operator/api v1.9.1-0.20251029150609-93918c59a719 h1:nb/5ytRj7E/5eo9UzLfaR29JytMtbGpqMVs3hjaRwZ0=
167-
github.com/vmware-tanzu/vm-operator/api v1.9.1-0.20251029150609-93918c59a719/go.mod h1:nWTPpxfe4gHuuYuFcrs86+NMxfkqPk3a3IlvI8TCWak=
162+
github.com/vmware-tanzu/nsx-operator/pkg/client v0.0.0-20260423081355-beab2417344a h1:3+uFGz+qweWuBXNBfpb7dEahIy1kNWe2tmaVXZbw1c4=
163+
github.com/vmware-tanzu/nsx-operator/pkg/client v0.0.0-20260423081355-beab2417344a/go.mod h1:MNz/PlAeJyKGt+X+nQE2bpiMghzpaP5XKaUlH0Stgh4=
164+
github.com/vmware-tanzu/vm-operator/api v1.9.1-0.20260502065817-4ee333ccd54c h1:xJzEwgcm+w72/Da+0wiv/EXUmAj0JJ0DnF7TeSjGJIw=
165+
github.com/vmware-tanzu/vm-operator/api v1.9.1-0.20260502065817-4ee333ccd54c/go.mod h1:nWTPpxfe4gHuuYuFcrs86+NMxfkqPk3a3IlvI8TCWak=
168166
github.com/vmware/govmomi v0.53.0 h1:e1bZCotAq7wm4xy95ePN2uoWwz28pNp/ewZZhpBY7/4=
169167
github.com/vmware/govmomi v0.53.0/go.mod h1:EWfuzPfxT5NV+aS2we02SLFdhvJkgeY7t7+TszgBSMY=
170168
github.com/vmware/vsphere-automation-sdk-go/lib v0.7.0 h1:pT+oqJ8FD5eUBQkl+e7LZwwtbwPvW5kDyyGXvt66gOM=

pkg/cloudprovider/vsphereparavirtual/cloud.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func init() {
9999
flag.BoolVar(&vpcModeEnabled, "enable-vpc-mode", false, "If true, routable pod controller will start with VPC mode. It is useful only when route controller is enabled in vsphereparavirtual mode")
100100
flag.StringVar(&podIPPoolType, "pod-ip-pool-type", "", "Specify if Pod IP address is Public or Private routable in VPC network. Valid values are Public and Private")
101101
flag.BoolVar(&serviceAnnotationPropagationEnabled, "enable-service-annotation-propagation", false, "If true, will propagate the service annotation to resource in supervisor cluster.")
102-
flag.StringVar(&vmopAPIVersion, "vm-operator-api-version", factory.V1alpha2, "the API version to use when communicating with VM Operator in supervisor mode. Valid values are: "+factory.V1alpha2+", "+factory.V1alpha5)
102+
flag.StringVar(&vmopAPIVersion, "vm-operator-api-version", factory.V1alpha2, "the API version to use when communicating with VM Operator in supervisor mode. Valid values are: "+factory.V1alpha2+", "+factory.V1alpha5+", "+factory.V1alpha6)
103103
}
104104

105105
// Creates new Controller node interface and returns

pkg/cloudprovider/vsphereparavirtual/instances.go

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -85,31 +85,20 @@ func NewInstances(clusterNS string, vmClient vmop.Interface) (cloudprovider.Inst
8585
}
8686

8787
func createNodeAddresses(vm *vmoptypes.VirtualMachineInfo) []v1.NodeAddress {
88-
// TODO: Currently, dual-stack (IPv4 and IPv6) is not supported.
89-
// Cluster will be assumed as IPv4 Primary by default.
90-
// In the future, when dual-stack support is implemented, this code should be updated to
91-
// dynamically determine the IP format based on the cluster's IP family.
92-
// https://github.com/kubernetes/cloud-provider-vsphere/issues/1129
9388
if vm.PrimaryIP4 == "" && vm.PrimaryIP6 == "" {
9489
klog.V(4).Info("instance found, but no address yet")
9590
return []v1.NodeAddress{}
9691
}
9792

98-
address := vm.PrimaryIP4
99-
if address == "" {
100-
address = vm.PrimaryIP6
93+
addrs := make([]v1.NodeAddress, 0, 3)
94+
if vm.PrimaryIP4 != "" {
95+
addrs = append(addrs, v1.NodeAddress{Type: v1.NodeInternalIP, Address: vm.PrimaryIP4})
10196
}
102-
103-
return []v1.NodeAddress{
104-
{
105-
Type: v1.NodeInternalIP,
106-
Address: address,
107-
},
108-
{
109-
Type: v1.NodeHostName,
110-
Address: "",
111-
},
97+
if vm.PrimaryIP6 != "" {
98+
addrs = append(addrs, v1.NodeAddress{Type: v1.NodeInternalIP, Address: vm.PrimaryIP6})
11299
}
100+
addrs = append(addrs, v1.NodeAddress{Type: v1.NodeHostName, Address: ""})
101+
return addrs
113102
}
114103

115104
// NodeAddresses returns the addresses of the specified instance if one exists, otherwise nil

pkg/cloudprovider/vsphereparavirtual/instances_test.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,6 @@ func createTestVM(name, namespace, biosUUID string) *vmopv1.VirtualMachine {
5656
}
5757

5858
func createTestVMWithVMIPAndHost(name, namespace, biosUUID string) *vmopv1.VirtualMachine {
59-
// TODO: Currently, dual-stack (IPv4 and IPv6) is not supported.
60-
// Cluster will be assumed as IPv4 Primary by default.
61-
// In the future, when dual-stack support is implemented, this code should be updated to
62-
// dynamically determine the IP format based on the cluster's IP family.
63-
// https://github.com/kubernetes/cloud-provider-vsphere/issues/1129
6459
return &vmopv1.VirtualMachine{
6560
ObjectMeta: metav1.ObjectMeta{
6661
Name: name,

pkg/cloudprovider/vsphereparavirtual/loadbalancer.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -161,16 +161,17 @@ func (l *loadBalancer) EnsureLoadBalancerDeleted(ctx context.Context, clusterNam
161161
}
162162

163163
func toStatus(vms *vmoptypes.VirtualMachineServiceInfo) *v1.LoadBalancerStatus {
164-
if len(vms.Status.LoadBalancerIngress) > 0 {
165-
return &v1.LoadBalancerStatus{
166-
Ingress: []v1.LoadBalancerIngress{
167-
{
168-
IP: vms.Status.LoadBalancerIngress[0].IP,
169-
},
170-
},
164+
st := &v1.LoadBalancerStatus{}
165+
for _, ing := range vms.Status.LoadBalancerIngress {
166+
if ing.IP == "" && ing.Hostname == "" {
167+
continue
171168
}
169+
st.Ingress = append(st.Ingress, v1.LoadBalancerIngress{
170+
IP: ing.IP,
171+
Hostname: ing.Hostname,
172+
})
172173
}
173-
return &v1.LoadBalancerStatus{}
174+
return st
174175
}
175176

176177
func namespacedName(service *v1.Service) string {

pkg/cloudprovider/vsphereparavirtual/loadbalancer_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,60 @@ func TestEnsureLoadBalancer_VMServiceCreatedIPFound(t *testing.T) {
324324
assert.NoError(t, err)
325325
}
326326

327+
func TestEnsureLoadBalancer_DualStackIngressInStatus(t *testing.T) {
328+
lb, fc := newTestLoadBalancer()
329+
testK8sService := &v1.Service{
330+
ObjectMeta: metav1.ObjectMeta{
331+
Name: testK8sServiceName,
332+
Namespace: testK8sServiceNameSpace,
333+
},
334+
Spec: v1.ServiceSpec{
335+
IPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
336+
Ports: []v1.ServicePort{
337+
{Name: "http", Port: 80, NodePort: 30800, Protocol: v1.ProtocolTCP},
338+
},
339+
},
340+
}
341+
fc.PrependReactor("create", "virtualmachineservices", func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) {
342+
unstructuredObj, _ := runtime.DefaultUnstructuredConverter.ToUnstructured(&vmopv1.VirtualMachineService{
343+
Status: vmopv1.VirtualMachineServiceStatus{
344+
LoadBalancer: vmopv1.LoadBalancerStatus{
345+
Ingress: []vmopv1.LoadBalancerIngress{
346+
{IP: "10.10.10.10"},
347+
{IP: "2001:db8::1"},
348+
},
349+
},
350+
},
351+
ObjectMeta: metav1.ObjectMeta{
352+
Name: "test-vm-service-name",
353+
OwnerReferences: []metav1.OwnerReference{
354+
testOwnerReference,
355+
},
356+
},
357+
Spec: vmopv1.VirtualMachineServiceSpec{
358+
Type: vmopv1.VirtualMachineServiceTypeLoadBalancer,
359+
Ports: []vmopv1.VirtualMachineServicePort{
360+
{Name: "test-port", Port: 80, TargetPort: 30800, Protocol: "TCP"},
361+
},
362+
Selector: map[string]string{
363+
vmservice.ClusterSelectorKey: testClustername,
364+
vmservice.NodeSelectorKey: vmservice.NodeRole,
365+
},
366+
},
367+
})
368+
return true, &unstructured.Unstructured{Object: unstructuredObj}, nil
369+
})
370+
371+
status, ensureErr := lb.EnsureLoadBalancer(context.Background(), testClustername, testK8sService, []*v1.Node{})
372+
assert.NoError(t, ensureErr)
373+
assert.Len(t, status.Ingress, 2)
374+
assert.Equal(t, "10.10.10.10", status.Ingress[0].IP)
375+
assert.Equal(t, "2001:db8::1", status.Ingress[1].IP)
376+
377+
err := lb.EnsureLoadBalancerDeleted(context.Background(), testClustername, testK8sService)
378+
assert.NoError(t, err)
379+
}
380+
327381
func TestEnsureLoadBalancer_DeleteLB(t *testing.T) {
328382
testCases := []struct {
329383
name string

0 commit comments

Comments
 (0)