This is an automated email from the ASF dual-hosted git repository.

vishesh pushed a commit to branch main
in repository 
https://gitbox.apache.org/repos/asf/cloudstack-kubernetes-provider.git


The following commit(s) were added to refs/heads/main by this push:
     new 96f1b18c Fix providerID & getZone Implementation (#85)
96f1b18c is described below

commit 96f1b18c0c456125afeb9de9ae92885d8c68bb86
Author: Vishesh <[email protected]>
AuthorDate: Thu Dec 11 17:19:13 2025 +0530

    Fix providerID & getZone Implementation (#85)
---
 cloudstack.go           | 75 +++++++++++++++++++++++++++++++++++++++++++------
 cloudstack_instances.go | 30 ++++++++++++++++----
 deployment.yaml         |  7 +++++
 3 files changed, 98 insertions(+), 14 deletions(-)

diff --git a/cloudstack.go b/cloudstack.go
index 8d78a861..5ea15071 100644
--- a/cloudstack.go
+++ b/cloudstack.go
@@ -28,6 +28,7 @@ import (
 
        "github.com/apache/cloudstack-go/v2/cloudstack"
        "gopkg.in/gcfg.v1"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        "k8s.io/apimachinery/pkg/types"
        cloudprovider "k8s.io/cloud-provider"
        "k8s.io/klog/v2"
@@ -50,9 +51,10 @@ type CSConfig struct {
 
 // CSCloud is an implementation of Interface for CloudStack.
 type CSCloud struct {
-       client    *cloudstack.CloudStackClient
-       projectID string // If non-"", all resources will be created within 
this project
-       zone      string
+       client        *cloudstack.CloudStackClient
+       projectID     string // If non-"", all resources will be created within 
this project
+       zone          string
+       clientBuilder cloudprovider.ControllerClientBuilder
 }
 
 func init() {
@@ -100,6 +102,7 @@ func newCSCloud(cfg *CSConfig) (*CSCloud, error) {
 
 // Initialize passes a Kubernetes clientBuilder interface to the cloud provider
 func (cs *CSCloud) Initialize(clientBuilder 
cloudprovider.ControllerClientBuilder, stop <-chan struct{}) {
+       cs.clientBuilder = clientBuilder
 }
 
 // LoadBalancer returns an implementation of LoadBalancer for CloudStack.
@@ -172,15 +175,20 @@ func (cs *CSCloud) GetZone(ctx context.Context) 
(cloudprovider.Zone, error) {
        zone := cloudprovider.Zone{}
 
        if cs.zone == "" {
-               hostname, err := os.Hostname()
+               // In Kubernetes pods, os.Hostname() returns the pod name, not 
the node hostname.
+               // We need to get the node name from the pod's spec.nodeName 
using the Kubernetes API.
+               nodeName, err := cs.getNodeNameFromPod(ctx)
                if err != nil {
-                       return zone, fmt.Errorf("failed to get hostname for 
retrieving the zone: %v", err)
+                       return zone, fmt.Errorf("failed to get node name for 
retrieving the zone: %v", err)
                }
 
-               instance, count, err := 
cs.client.VirtualMachine.GetVirtualMachineByName(hostname)
+               instance, count, err := 
cs.client.VirtualMachine.GetVirtualMachineByName(
+                       nodeName,
+                       cloudstack.WithProject(cs.projectID),
+               )
                if err != nil {
                        if count == 0 {
-                               return zone, fmt.Errorf("could not find 
instance for retrieving the zone: %v", err)
+                               return zone, fmt.Errorf("could not find 
CloudStack instance with name %s for retrieving the zone: %v", nodeName, err)
                        }
                        return zone, fmt.Errorf("error getting instance for 
retrieving the zone: %v", err)
                }
@@ -200,7 +208,7 @@ func (cs *CSCloud) GetZoneByProviderID(ctx context.Context, 
providerID string) (
        zone := cloudprovider.Zone{}
 
        instance, count, err := cs.client.VirtualMachine.GetVirtualMachineByID(
-               providerID,
+               cs.getInstanceIDFromProviderID(providerID),
                cloudstack.WithProject(cs.projectID),
        )
        if err != nil {
@@ -238,3 +246,54 @@ func (cs *CSCloud) GetZoneByNodeName(ctx context.Context, 
nodeName types.NodeNam
 
        return zone, nil
 }
+
+// getNodeNameFromPod gets the node name where this pod is running by querying 
the Kubernetes API.
+// It uses the pod's name and namespace (from environment variables or 
hostname) to look up the pod
+// and retrieve its spec.nodeName field.
+func (cs *CSCloud) getNodeNameFromPod(ctx context.Context) (string, error) {
+       if cs.clientBuilder == nil {
+               return "", fmt.Errorf("clientBuilder not initialized, cannot 
query Kubernetes API")
+       }
+
+       client, err := cs.clientBuilder.Client("cloud-controller-manager")
+       if err != nil {
+               return "", fmt.Errorf("failed to get Kubernetes client: %v", 
err)
+       }
+
+       // Get pod name and namespace
+       // In Kubernetes, the pod name is available as HOSTNAME environment 
variable
+       // or we can use os.Hostname() which returns the pod name
+       podName := os.Getenv("HOSTNAME")
+       if podName == "" {
+               var err error
+               podName, err = os.Hostname()
+               if err != nil {
+                       return "", fmt.Errorf("failed to get pod name: %v", err)
+               }
+       }
+
+       // Get namespace from environment variable or default to kube-system 
for CCM
+       namespace := os.Getenv("POD_NAMESPACE")
+       if namespace == "" {
+               // Try reading from service account namespace file (available 
in pods)
+               if data, err := 
os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == 
nil {
+                       namespace = string(data)
+               } else {
+                       // Default namespace for cloud controller manager
+                       namespace = "kube-system"
+               }
+       }
+
+       // Get the pod object from Kubernetes API
+       pod, err := client.CoreV1().Pods(namespace).Get(ctx, podName, 
metav1.GetOptions{})
+       if err != nil {
+               return "", fmt.Errorf("failed to get pod %s/%s from Kubernetes 
API: %v", namespace, podName, err)
+       }
+
+       if pod.Spec.NodeName == "" {
+               return "", fmt.Errorf("pod %s/%s does not have a nodeName 
assigned yet", namespace, podName)
+       }
+
+       klog.V(4).Infof("found node name %s for pod %s/%s", pod.Spec.NodeName, 
namespace, podName)
+       return pod.Spec.NodeName, nil
+}
diff --git a/cloudstack_instances.go b/cloudstack_instances.go
index 91d65751..f79b90f7 100644
--- a/cloudstack_instances.go
+++ b/cloudstack_instances.go
@@ -24,6 +24,7 @@ import (
        "errors"
        "fmt"
        "regexp"
+       "strings"
 
        "github.com/apache/cloudstack-go/v2/cloudstack"
        corev1 "k8s.io/api/core/v1"
@@ -53,7 +54,7 @@ func (cs *CSCloud) NodeAddresses(ctx context.Context, name 
types.NodeName) ([]co
 // NodeAddressesByProviderID returns the addresses of the specified instance.
 func (cs *CSCloud) NodeAddressesByProviderID(ctx context.Context, providerID 
string) ([]corev1.NodeAddress, error) {
        instance, count, err := cs.client.VirtualMachine.GetVirtualMachineByID(
-               providerID,
+               cs.getInstanceIDFromProviderID(providerID),
                cloudstack.WithProject(cs.projectID),
        )
        if err != nil {
@@ -125,7 +126,7 @@ func (cs *CSCloud) InstanceType(ctx context.Context, name 
types.NodeName) (strin
 // InstanceTypeByProviderID returns the type of the specified instance.
 func (cs *CSCloud) InstanceTypeByProviderID(ctx context.Context, providerID 
string) (string, error) {
        instance, count, err := cs.client.VirtualMachine.GetVirtualMachineByID(
-               providerID,
+               cs.getInstanceIDFromProviderID(providerID),
                cloudstack.WithProject(cs.projectID),
        )
        if err != nil {
@@ -151,7 +152,7 @@ func (cs *CSCloud) CurrentNodeName(ctx context.Context, 
hostname string) (types.
 // InstanceExistsByProviderID returns if the instance still exists.
 func (cs *CSCloud) InstanceExistsByProviderID(ctx context.Context, providerID 
string) (bool, error) {
        _, count, err := cs.client.VirtualMachine.GetVirtualMachineByID(
-               providerID,
+               cs.getInstanceIDFromProviderID(providerID),
                cloudstack.WithProject(cs.projectID),
        )
        if err != nil {
@@ -185,6 +186,11 @@ func (cs *CSCloud) InstanceShutdown(ctx context.Context, 
node *corev1.Node) (boo
 
 func (cs *CSCloud) InstanceMetadata(ctx context.Context, node *corev1.Node) 
(*cloudprovider.InstanceMetadata, error) {
 
+       instanceID, err := cs.InstanceID(ctx, types.NodeName(node.Name))
+       if err != nil {
+               return nil, err
+       }
+
        instanceType, err := cs.InstanceType(ctx, types.NodeName(node.Name))
        if err != nil {
                return nil, err
@@ -195,16 +201,28 @@ func (cs *CSCloud) InstanceMetadata(ctx context.Context, 
node *corev1.Node) (*cl
                return nil, err
        }
 
-       zone, err := cs.GetZone(ctx)
+       zone, err := cs.GetZoneByNodeName(ctx, types.NodeName(node.Name))
        if err != nil {
                return nil, err
        }
 
        return &cloudprovider.InstanceMetadata{
-               ProviderID:    cs.ProviderName(),
+               ProviderID:    cs.getProviderIDFromInstanceID(instanceID),
                InstanceType:  instanceType,
                NodeAddresses: addresses,
-               Zone:          cs.zone,
+               Zone:          zone.FailureDomain,
                Region:        zone.Region,
        }, nil
 }
+
+func (cs *CSCloud) getProviderIDFromInstanceID(instanceID string) string {
+       return fmt.Sprintf("%s://%s", cs.ProviderName(), instanceID)
+}
+
+func (cs *CSCloud) getInstanceIDFromProviderID(providerID string) string {
+       parts := strings.Split(providerID, "://")
+       if len(parts) == 1 {
+               return providerID
+       }
+       return parts[1]
+}
diff --git a/deployment.yaml b/deployment.yaml
index 0cc59528..a5cb01f7 100644
--- a/deployment.yaml
+++ b/deployment.yaml
@@ -43,6 +43,13 @@ rules:
   - nodes
   verbs:
   - '*'
+- apiGroups:
+  - ""
+  resources:
+  - pods
+  verbs:
+  - list
+  - get
 - apiGroups:
   - ""
   resources:

Reply via email to