@@ -28,6 +28,7 @@ import (
2828
2929 "github.com/apache/cloudstack-go/v2/cloudstack"
3030 "gopkg.in/gcfg.v1"
31+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3132 "k8s.io/apimachinery/pkg/types"
3233 cloudprovider "k8s.io/cloud-provider"
3334 "k8s.io/klog/v2"
@@ -50,9 +51,10 @@ type CSConfig struct {
5051
5152// CSCloud is an implementation of Interface for CloudStack.
5253type CSCloud struct {
53- client * cloudstack.CloudStackClient
54- projectID string // If non-"", all resources will be created within this project
55- zone string
54+ client * cloudstack.CloudStackClient
55+ projectID string // If non-"", all resources will be created within this project
56+ zone string
57+ clientBuilder cloudprovider.ControllerClientBuilder
5658}
5759
5860func init () {
@@ -100,6 +102,7 @@ func newCSCloud(cfg *CSConfig) (*CSCloud, error) {
100102
101103// Initialize passes a Kubernetes clientBuilder interface to the cloud provider
102104func (cs * CSCloud ) Initialize (clientBuilder cloudprovider.ControllerClientBuilder , stop <- chan struct {}) {
105+ cs .clientBuilder = clientBuilder
103106}
104107
105108// LoadBalancer returns an implementation of LoadBalancer for CloudStack.
@@ -172,15 +175,20 @@ func (cs *CSCloud) GetZone(ctx context.Context) (cloudprovider.Zone, error) {
172175 zone := cloudprovider.Zone {}
173176
174177 if cs .zone == "" {
175- hostname , err := os .Hostname ()
178+ // In Kubernetes pods, os.Hostname() returns the pod name, not the node hostname.
179+ // We need to get the node name from the pod's spec.nodeName using the Kubernetes API.
180+ nodeName , err := cs .getNodeNameFromPod (ctx )
176181 if err != nil {
177- return zone , fmt .Errorf ("failed to get hostname for retrieving the zone: %v" , err )
182+ return zone , fmt .Errorf ("failed to get node name for retrieving the zone: %v" , err )
178183 }
179184
180- instance , count , err := cs .client .VirtualMachine .GetVirtualMachineByName (hostname )
185+ instance , count , err := cs .client .VirtualMachine .GetVirtualMachineByName (
186+ nodeName ,
187+ cloudstack .WithProject (cs .projectID ),
188+ )
181189 if err != nil {
182190 if count == 0 {
183- return zone , fmt .Errorf ("could not find instance for retrieving the zone: %v" , err )
191+ return zone , fmt .Errorf ("could not find CloudStack instance with name %s for retrieving the zone: %v" , nodeName , err )
184192 }
185193 return zone , fmt .Errorf ("error getting instance for retrieving the zone: %v" , err )
186194 }
@@ -238,3 +246,54 @@ func (cs *CSCloud) GetZoneByNodeName(ctx context.Context, nodeName types.NodeNam
238246
239247 return zone , nil
240248}
249+
250+ // getNodeNameFromPod gets the node name where this pod is running by querying the Kubernetes API.
251+ // It uses the pod's name and namespace (from environment variables or hostname) to look up the pod
252+ // and retrieve its spec.nodeName field.
253+ func (cs * CSCloud ) getNodeNameFromPod (ctx context.Context ) (string , error ) {
254+ if cs .clientBuilder == nil {
255+ return "" , fmt .Errorf ("clientBuilder not initialized, cannot query Kubernetes API" )
256+ }
257+
258+ client , err := cs .clientBuilder .Client ("cloud-controller-manager" )
259+ if err != nil {
260+ return "" , fmt .Errorf ("failed to get Kubernetes client: %v" , err )
261+ }
262+
263+ // Get pod name and namespace
264+ // In Kubernetes, the pod name is available as HOSTNAME environment variable
265+ // or we can use os.Hostname() which returns the pod name
266+ podName := os .Getenv ("HOSTNAME" )
267+ if podName == "" {
268+ var err error
269+ podName , err = os .Hostname ()
270+ if err != nil {
271+ return "" , fmt .Errorf ("failed to get pod name: %v" , err )
272+ }
273+ }
274+
275+ // Get namespace from environment variable or default to kube-system for CCM
276+ namespace := os .Getenv ("POD_NAMESPACE" )
277+ if namespace == "" {
278+ // Try reading from service account namespace file (available in pods)
279+ if data , err := os .ReadFile ("/var/run/secrets/kubernetes.io/serviceaccount/namespace" ); err == nil {
280+ namespace = string (data )
281+ } else {
282+ // Default namespace for cloud controller manager
283+ namespace = "kube-system"
284+ }
285+ }
286+
287+ // Get the pod object from Kubernetes API
288+ pod , err := client .CoreV1 ().Pods (namespace ).Get (ctx , podName , metav1.GetOptions {})
289+ if err != nil {
290+ return "" , fmt .Errorf ("failed to get pod %s/%s from Kubernetes API: %v" , namespace , podName , err )
291+ }
292+
293+ if pod .Spec .NodeName == "" {
294+ return "" , fmt .Errorf ("pod %s/%s does not have a nodeName assigned yet" , namespace , podName )
295+ }
296+
297+ klog .V (4 ).Infof ("found node name %s for pod %s/%s" , pod .Spec .NodeName , namespace , podName )
298+ return pod .Spec .NodeName , nil
299+ }
0 commit comments