@@ -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.
5455type 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
6163func init () {
@@ -127,6 +129,7 @@ func (cs *CSCloud) getManagementServerVersion() (semver.Version, error) {
127129
128130// Initialize passes a Kubernetes clientBuilder interface to the cloud provider
129131func (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+ }
0 commit comments