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: