Skip to content

Commit 5964ce3

Browse files
authored
Merge branch 'main' into update-source-cidrs
2 parents f1aaa2a + 96f1b18 commit 5964ce3

File tree

3 files changed

+99
-15
lines changed

3 files changed

+99
-15
lines changed

cloudstack.go

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/apache/cloudstack-go/v2/cloudstack"
3131
"github.com/blang/semver/v4"
3232
"gopkg.in/gcfg.v1"
33+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3334
"k8s.io/apimachinery/pkg/types"
3435
cloudprovider "k8s.io/cloud-provider"
3536
"k8s.io/klog/v2"
@@ -52,10 +53,11 @@ type CSConfig struct {
5253

5354
// CSCloud is an implementation of Interface for CloudStack.
5455
type CSCloud struct {
55-
client *cloudstack.CloudStackClient
56-
projectID string // If non-"", all resources will be created within this project
57-
zone string
58-
version semver.Version
56+
client *cloudstack.CloudStackClient
57+
projectID string // If non-"", all resources will be created within this project
58+
zone string
59+
clientBuilder cloudprovider.ControllerClientBuilder
60+
version semver.Version
5961
}
6062

6163
func init() {
@@ -127,6 +129,7 @@ func (cs *CSCloud) getManagementServerVersion() (semver.Version, error) {
127129

128130
// Initialize passes a Kubernetes clientBuilder interface to the cloud provider
129131
func (cs *CSCloud) Initialize(clientBuilder cloudprovider.ControllerClientBuilder, stop <-chan struct{}) {
132+
cs.clientBuilder = clientBuilder
130133
}
131134

132135
// LoadBalancer returns an implementation of LoadBalancer for CloudStack.
@@ -199,15 +202,20 @@ func (cs *CSCloud) GetZone(ctx context.Context) (cloudprovider.Zone, error) {
199202
zone := cloudprovider.Zone{}
200203

201204
if cs.zone == "" {
202-
hostname, err := os.Hostname()
205+
// In Kubernetes pods, os.Hostname() returns the pod name, not the node hostname.
206+
// We need to get the node name from the pod's spec.nodeName using the Kubernetes API.
207+
nodeName, err := cs.getNodeNameFromPod(ctx)
203208
if err != nil {
204-
return zone, fmt.Errorf("failed to get hostname for retrieving the zone: %v", err)
209+
return zone, fmt.Errorf("failed to get node name for retrieving the zone: %v", err)
205210
}
206211

207-
instance, count, err := cs.client.VirtualMachine.GetVirtualMachineByName(hostname)
212+
instance, count, err := cs.client.VirtualMachine.GetVirtualMachineByName(
213+
nodeName,
214+
cloudstack.WithProject(cs.projectID),
215+
)
208216
if err != nil {
209217
if count == 0 {
210-
return zone, fmt.Errorf("could not find instance for retrieving the zone: %v", err)
218+
return zone, fmt.Errorf("could not find CloudStack instance with name %s for retrieving the zone: %v", nodeName, err)
211219
}
212220
return zone, fmt.Errorf("error getting instance for retrieving the zone: %v", err)
213221
}
@@ -227,7 +235,7 @@ func (cs *CSCloud) GetZoneByProviderID(ctx context.Context, providerID string) (
227235
zone := cloudprovider.Zone{}
228236

229237
instance, count, err := cs.client.VirtualMachine.GetVirtualMachineByID(
230-
providerID,
238+
cs.getInstanceIDFromProviderID(providerID),
231239
cloudstack.WithProject(cs.projectID),
232240
)
233241
if err != nil {
@@ -265,3 +273,54 @@ func (cs *CSCloud) GetZoneByNodeName(ctx context.Context, nodeName types.NodeNam
265273

266274
return zone, nil
267275
}
276+
277+
// getNodeNameFromPod gets the node name where this pod is running by querying the Kubernetes API.
278+
// It uses the pod's name and namespace (from environment variables or hostname) to look up the pod
279+
// and retrieve its spec.nodeName field.
280+
func (cs *CSCloud) getNodeNameFromPod(ctx context.Context) (string, error) {
281+
if cs.clientBuilder == nil {
282+
return "", fmt.Errorf("clientBuilder not initialized, cannot query Kubernetes API")
283+
}
284+
285+
client, err := cs.clientBuilder.Client("cloud-controller-manager")
286+
if err != nil {
287+
return "", fmt.Errorf("failed to get Kubernetes client: %v", err)
288+
}
289+
290+
// Get pod name and namespace
291+
// In Kubernetes, the pod name is available as HOSTNAME environment variable
292+
// or we can use os.Hostname() which returns the pod name
293+
podName := os.Getenv("HOSTNAME")
294+
if podName == "" {
295+
var err error
296+
podName, err = os.Hostname()
297+
if err != nil {
298+
return "", fmt.Errorf("failed to get pod name: %v", err)
299+
}
300+
}
301+
302+
// Get namespace from environment variable or default to kube-system for CCM
303+
namespace := os.Getenv("POD_NAMESPACE")
304+
if namespace == "" {
305+
// Try reading from service account namespace file (available in pods)
306+
if data, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil {
307+
namespace = string(data)
308+
} else {
309+
// Default namespace for cloud controller manager
310+
namespace = "kube-system"
311+
}
312+
}
313+
314+
// Get the pod object from Kubernetes API
315+
pod, err := client.CoreV1().Pods(namespace).Get(ctx, podName, metav1.GetOptions{})
316+
if err != nil {
317+
return "", fmt.Errorf("failed to get pod %s/%s from Kubernetes API: %v", namespace, podName, err)
318+
}
319+
320+
if pod.Spec.NodeName == "" {
321+
return "", fmt.Errorf("pod %s/%s does not have a nodeName assigned yet", namespace, podName)
322+
}
323+
324+
klog.V(4).Infof("found node name %s for pod %s/%s", pod.Spec.NodeName, namespace, podName)
325+
return pod.Spec.NodeName, nil
326+
}

cloudstack_instances.go

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"errors"
2525
"fmt"
2626
"regexp"
27+
"strings"
2728

2829
"github.com/apache/cloudstack-go/v2/cloudstack"
2930
corev1 "k8s.io/api/core/v1"
@@ -53,7 +54,7 @@ func (cs *CSCloud) NodeAddresses(ctx context.Context, name types.NodeName) ([]co
5354
// NodeAddressesByProviderID returns the addresses of the specified instance.
5455
func (cs *CSCloud) NodeAddressesByProviderID(ctx context.Context, providerID string) ([]corev1.NodeAddress, error) {
5556
instance, count, err := cs.client.VirtualMachine.GetVirtualMachineByID(
56-
providerID,
57+
cs.getInstanceIDFromProviderID(providerID),
5758
cloudstack.WithProject(cs.projectID),
5859
)
5960
if err != nil {
@@ -125,7 +126,7 @@ func (cs *CSCloud) InstanceType(ctx context.Context, name types.NodeName) (strin
125126
// InstanceTypeByProviderID returns the type of the specified instance.
126127
func (cs *CSCloud) InstanceTypeByProviderID(ctx context.Context, providerID string) (string, error) {
127128
instance, count, err := cs.client.VirtualMachine.GetVirtualMachineByID(
128-
providerID,
129+
cs.getInstanceIDFromProviderID(providerID),
129130
cloudstack.WithProject(cs.projectID),
130131
)
131132
if err != nil {
@@ -151,7 +152,7 @@ func (cs *CSCloud) CurrentNodeName(ctx context.Context, hostname string) (types.
151152
// InstanceExistsByProviderID returns if the instance still exists.
152153
func (cs *CSCloud) InstanceExistsByProviderID(ctx context.Context, providerID string) (bool, error) {
153154
_, count, err := cs.client.VirtualMachine.GetVirtualMachineByID(
154-
providerID,
155+
cs.getInstanceIDFromProviderID(providerID),
155156
cloudstack.WithProject(cs.projectID),
156157
)
157158
if err != nil {
@@ -185,6 +186,11 @@ func (cs *CSCloud) InstanceShutdown(ctx context.Context, node *corev1.Node) (boo
185186

186187
func (cs *CSCloud) InstanceMetadata(ctx context.Context, node *corev1.Node) (*cloudprovider.InstanceMetadata, error) {
187188

189+
instanceID, err := cs.InstanceID(ctx, types.NodeName(node.Name))
190+
if err != nil {
191+
return nil, err
192+
}
193+
188194
instanceType, err := cs.InstanceType(ctx, types.NodeName(node.Name))
189195
if err != nil {
190196
return nil, err
@@ -195,16 +201,28 @@ func (cs *CSCloud) InstanceMetadata(ctx context.Context, node *corev1.Node) (*cl
195201
return nil, err
196202
}
197203

198-
zone, err := cs.GetZone(ctx)
204+
zone, err := cs.GetZoneByNodeName(ctx, types.NodeName(node.Name))
199205
if err != nil {
200206
return nil, err
201207
}
202208

203209
return &cloudprovider.InstanceMetadata{
204-
ProviderID: cs.ProviderName(),
210+
ProviderID: cs.getProviderIDFromInstanceID(instanceID),
205211
InstanceType: instanceType,
206212
NodeAddresses: addresses,
207-
Zone: cs.zone,
213+
Zone: zone.FailureDomain,
208214
Region: zone.Region,
209215
}, nil
210216
}
217+
218+
func (cs *CSCloud) getProviderIDFromInstanceID(instanceID string) string {
219+
return fmt.Sprintf("%s://%s", cs.ProviderName(), instanceID)
220+
}
221+
222+
func (cs *CSCloud) getInstanceIDFromProviderID(providerID string) string {
223+
parts := strings.Split(providerID, "://")
224+
if len(parts) == 1 {
225+
return providerID
226+
}
227+
return parts[1]
228+
}

deployment.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ rules:
4343
- nodes
4444
verbs:
4545
- '*'
46+
- apiGroups:
47+
- ""
48+
resources:
49+
- pods
50+
verbs:
51+
- list
52+
- get
4653
- apiGroups:
4754
- ""
4855
resources:

0 commit comments

Comments
 (0)