Skip to content

Commit 67dc886

Browse files
committed
Fix getZone implementation
1 parent d2ddd95 commit 67dc886

File tree

2 files changed

+73
-7
lines changed

2 files changed

+73
-7
lines changed

cloudstack.go

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
5253
type 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

5860
func init() {
@@ -100,6 +102,7 @@ func newCSCloud(cfg *CSConfig) (*CSCloud, error) {
100102

101103
// Initialize passes a Kubernetes clientBuilder interface to the cloud provider
102104
func (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+
}

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)