Skip to content

Commit b654232

Browse files
authored
Merge pull request #1528 from vr4manta/SPLAT-2297_upstream
Implement InstancesV2 and add node-label flag
2 parents 908aaf6 + 242ba60 commit b654232

File tree

7 files changed

+880
-7
lines changed

7 files changed

+880
-7
lines changed

cmd/vsphere-cloud-controller-manager/main.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@ import (
3030
"syscall"
3131
"time"
3232

33+
apivalidation "k8s.io/apimachinery/pkg/util/validation"
3334
cloudprovider "k8s.io/cloud-provider"
3435
"k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphere"
3536
"k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphere/loadbalancer"
37+
voptions "k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphere/options"
3638
"k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphereparavirtual"
3739
pvconfig "k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphereparavirtual/config"
3840
"k8s.io/cloud-provider/app"
@@ -98,6 +100,8 @@ func main() {
98100
globalflag.Register(namedFlagSets.FlagSet("generic"), "is-legacy-paravirtual")
99101
}
100102

103+
voptions.AddFlags(namedFlagSets.FlagSet("cloud-node-controller"))
104+
101105
for _, f := range namedFlagSets.FlagSets {
102106
fs.AddFlagSet(f)
103107
}
@@ -158,6 +162,14 @@ func main() {
158162
verflag.PrintAndExitIfRequested()
159163
cliflag.PrintFlags(cmd.Flags())
160164

165+
// Validate --node-labels keys follow Kubernetes label key formatting
166+
for key := range vsphere.AdditionalLabels {
167+
errList := apivalidation.IsQualifiedName(key)
168+
if len(errList) > 0 {
169+
klog.Fatalf("invalid --node-labels key %q: %s", key, strings.Join(errList, "; "))
170+
}
171+
}
172+
161173
c, err := ccmOptions.Config(app.ControllerNames(app.DefaultInitFuncConstructors), app.ControllersDisabledByDefault.List(), names.CCMControllerAliases(), app.AllWebhooks, app.DisabledByDefaultWebhooks)
162174
if err != nil {
163175
// explicitly ignore the error by Fprintf, exiting anyway

pkg/cloudprovider/vsphere/cloud.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -184,10 +184,8 @@ func (vs *VSphere) Instances() (cloudprovider.Instances, bool) {
184184
}
185185

186186
// InstancesV2 returns an implementation of cloudprovider.InstancesV2.
187-
//
188-
// TODO: implement this for v1.20
189187
func (vs *VSphere) InstancesV2() (cloudprovider.InstancesV2, bool) {
190-
return nil, false
188+
return vs.instancesV2, true
191189
}
192190

193191
// Zones returns a zones interface. Also returns true if the interface
@@ -262,6 +260,10 @@ func buildVSphereFromConfig(cfg *ccfg.CPIConfig, nsxtcfg *ncfg.Config, lbcfg *lc
262260
nsxtSecretNamespace = nsxtcfg.SecretNamespace
263261
}
264262

263+
instancesObj := newInstances(nm)
264+
zonesObj := newZones(nm, cfg.Labels.Zone, cfg.Labels.Region)
265+
instancesV2Obj := newInstancesV2(instancesObj, zonesObj)
266+
265267
vs := VSphere{
266268
cfg: cfg,
267269
cfgLB: lbcfg,
@@ -270,8 +272,9 @@ func buildVSphereFromConfig(cfg *ccfg.CPIConfig, nsxtcfg *ncfg.Config, lbcfg *lc
270272
nsxtSecretNamespace: nsxtSecretNamespace,
271273
loadbalancer: lb,
272274
routes: routes,
273-
instances: newInstances(nm),
274-
zones: newZones(nm, cfg.Labels.Zone, cfg.Labels.Region),
275+
instances: instancesObj,
276+
instancesV2: instancesV2Obj,
277+
zones: zonesObj,
275278
}
276279
return &vs, nil
277280
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
Copyright 2025 The Kubernetes Authors.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
package vsphere
15+
16+
// This file implements the InstancesV2 interface.
17+
18+
import (
19+
"context"
20+
21+
v1 "k8s.io/api/core/v1"
22+
"k8s.io/apimachinery/pkg/types"
23+
cloudprovider "k8s.io/cloud-provider"
24+
"k8s.io/klog/v2"
25+
)
26+
27+
// AdditionalLabels contains additional labels to add to all nodes when generating the metadata information
28+
var AdditionalLabels map[string]string
29+
30+
func newInstancesV2(instances cloudprovider.Instances, zones cloudprovider.Zones) cloudprovider.InstancesV2 {
31+
return &instancesV2{
32+
instances: instances,
33+
zones: zones,
34+
}
35+
}
36+
37+
func (c *instancesV2) getProviderID(ctx context.Context, node *v1.Node) (string, error) {
38+
klog.V(4).Infof("instancesV2.getProviderID() called for node %s", node.Name)
39+
if node.Spec.ProviderID != "" {
40+
return node.Spec.ProviderID, nil
41+
}
42+
43+
instanceID, err := c.instances.InstanceID(ctx, types.NodeName(node.Name))
44+
if err != nil {
45+
return "", err
46+
}
47+
48+
return ProviderName + "://" + instanceID, nil
49+
}
50+
51+
// InstanceExists returns true if the instance for the given node exists according to the cloud provider.
52+
// Use the node.name or node.spec.providerID field to find the node in the cloud provider.
53+
func (c *instancesV2) InstanceExists(ctx context.Context, node *v1.Node) (bool, error) {
54+
klog.V(4).Infof("instancesV2.InstanceExists() called for node %s", node.Name)
55+
providerID, err := c.getProviderID(ctx, node)
56+
if err != nil {
57+
return false, err
58+
}
59+
60+
return c.instances.InstanceExistsByProviderID(ctx, providerID)
61+
}
62+
63+
// InstanceShutdown returns true if the instance is shutdown according to the cloud provider.
64+
// Use the node.name or node.spec.providerID field to find the node in the cloud provider.
65+
func (c *instancesV2) InstanceShutdown(ctx context.Context, node *v1.Node) (bool, error) {
66+
klog.V(4).Infof("instancesV2.InstanceShutdown() called for node %s", node.Name)
67+
providerID, err := c.getProviderID(ctx, node)
68+
if err != nil {
69+
return false, err
70+
}
71+
72+
return c.instances.InstanceShutdownByProviderID(ctx, providerID)
73+
}
74+
75+
func (c *instancesV2) getAdditionalLabels() (map[string]string, error) {
76+
return AdditionalLabels, nil
77+
}
78+
79+
// InstanceMetadata returns the instance's metadata. The values returned in InstanceMetadata are
80+
// translated into specific fields and labels in the Node object on registration.
81+
// Implementations should always check node.spec.providerID first when trying to discover the instance
82+
// for a given node. In cases where node.spec.providerID is empty, implementations can use other
83+
// properties of the node like its name, labels and annotations.
84+
func (c *instancesV2) InstanceMetadata(ctx context.Context, node *v1.Node) (*cloudprovider.InstanceMetadata, error) {
85+
klog.V(4).Infof("instancesV2.InstanceMetadata() called with node %s", node.Name)
86+
87+
providerID, err := c.getProviderID(ctx, node)
88+
if err != nil {
89+
return nil, err
90+
}
91+
klog.V(4).Infof("instancesV2.InstanceMetadata() got provider ID %s", providerID)
92+
93+
instanceType, err := c.instances.InstanceTypeByProviderID(ctx, providerID)
94+
if err != nil {
95+
return nil, err
96+
}
97+
klog.V(4).Infof("instancesV2.InstanceMetadata() got instanceType %s", instanceType)
98+
99+
zone, err := c.zones.GetZoneByProviderID(ctx, providerID)
100+
if err != nil {
101+
return nil, err
102+
}
103+
klog.V(4).InfoS("instancesV2.InstanceMetadata() got zone info", "zone", zone)
104+
105+
nodeAddresses, err := c.instances.NodeAddressesByProviderID(ctx, providerID)
106+
if err != nil {
107+
return nil, err
108+
}
109+
klog.V(4).InfoS("instancesV2.InstanceMetadata() got nodeAddresses", "nodeAddresses", nodeAddresses)
110+
111+
// Generate additionalLabels
112+
additionalLabels, err := c.getAdditionalLabels()
113+
if err != nil {
114+
return nil, err
115+
}
116+
klog.V(4).InfoS("instancesV2.InstanceMetadata() got additionalLabels", "additionalLabels", additionalLabels)
117+
118+
return &cloudprovider.InstanceMetadata{
119+
ProviderID: providerID,
120+
InstanceType: instanceType,
121+
NodeAddresses: nodeAddresses,
122+
Zone: zone.FailureDomain,
123+
Region: zone.Region,
124+
AdditionalLabels: additionalLabels,
125+
}, nil
126+
}

0 commit comments

Comments
 (0)