Skip to content

Commit 96f1b18

Browse files
authored
Fix providerID & getZone Implementation (#85)
1 parent 282ef97 commit 96f1b18

File tree

3 files changed

+98
-14
lines changed

3 files changed

+98
-14
lines changed

cloudstack.go

Lines changed: 67 additions & 8 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
}
@@ -200,7 +208,7 @@ func (cs *CSCloud) GetZoneByProviderID(ctx context.Context, providerID string) (
200208
zone := cloudprovider.Zone{}
201209

202210
instance, count, err := cs.client.VirtualMachine.GetVirtualMachineByID(
203-
providerID,
211+
cs.getInstanceIDFromProviderID(providerID),
204212
cloudstack.WithProject(cs.projectID),
205213
)
206214
if err != nil {
@@ -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+
}

cloudstack_instances.go

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"errors"
2525
"fmt"
2626
"regexp"
27+
"strings"
2728

2829
"github.com/apache/cloudstack-go/v2/cloudstack"
2930
corev1 "k8s.io/api/core/v1"
@@ -53,7 +54,7 @@ func (cs *CSCloud) NodeAddresses(ctx context.Context, name types.NodeName) ([]co
5354
// NodeAddressesByProviderID returns the addresses of the specified instance.
5455
func (cs *CSCloud) NodeAddressesByProviderID(ctx context.Context, providerID string) ([]corev1.NodeAddress, error) {
5556
instance, count, err := cs.client.VirtualMachine.GetVirtualMachineByID(
56-
providerID,
57+
cs.getInstanceIDFromProviderID(providerID),
5758
cloudstack.WithProject(cs.projectID),
5859
)
5960
if err != nil {
@@ -125,7 +126,7 @@ func (cs *CSCloud) InstanceType(ctx context.Context, name types.NodeName) (strin
125126
// InstanceTypeByProviderID returns the type of the specified instance.
126127
func (cs *CSCloud) InstanceTypeByProviderID(ctx context.Context, providerID string) (string, error) {
127128
instance, count, err := cs.client.VirtualMachine.GetVirtualMachineByID(
128-
providerID,
129+
cs.getInstanceIDFromProviderID(providerID),
129130
cloudstack.WithProject(cs.projectID),
130131
)
131132
if err != nil {
@@ -151,7 +152,7 @@ func (cs *CSCloud) CurrentNodeName(ctx context.Context, hostname string) (types.
151152
// InstanceExistsByProviderID returns if the instance still exists.
152153
func (cs *CSCloud) InstanceExistsByProviderID(ctx context.Context, providerID string) (bool, error) {
153154
_, count, err := cs.client.VirtualMachine.GetVirtualMachineByID(
154-
providerID,
155+
cs.getInstanceIDFromProviderID(providerID),
155156
cloudstack.WithProject(cs.projectID),
156157
)
157158
if err != nil {
@@ -185,6 +186,11 @@ func (cs *CSCloud) InstanceShutdown(ctx context.Context, node *corev1.Node) (boo
185186

186187
func (cs *CSCloud) InstanceMetadata(ctx context.Context, node *corev1.Node) (*cloudprovider.InstanceMetadata, error) {
187188

189+
instanceID, err := cs.InstanceID(ctx, types.NodeName(node.Name))
190+
if err != nil {
191+
return nil, err
192+
}
193+
188194
instanceType, err := cs.InstanceType(ctx, types.NodeName(node.Name))
189195
if err != nil {
190196
return nil, err
@@ -195,16 +201,28 @@ func (cs *CSCloud) InstanceMetadata(ctx context.Context, node *corev1.Node) (*cl
195201
return nil, err
196202
}
197203

198-
zone, err := cs.GetZone(ctx)
204+
zone, err := cs.GetZoneByNodeName(ctx, types.NodeName(node.Name))
199205
if err != nil {
200206
return nil, err
201207
}
202208

203209
return &cloudprovider.InstanceMetadata{
204-
ProviderID: cs.ProviderName(),
210+
ProviderID: cs.getProviderIDFromInstanceID(instanceID),
205211
InstanceType: instanceType,
206212
NodeAddresses: addresses,
207-
Zone: cs.zone,
213+
Zone: zone.FailureDomain,
208214
Region: zone.Region,
209215
}, nil
210216
}
217+
218+
func (cs *CSCloud) getProviderIDFromInstanceID(instanceID string) string {
219+
return fmt.Sprintf("%s://%s", cs.ProviderName(), instanceID)
220+
}
221+
222+
func (cs *CSCloud) getInstanceIDFromProviderID(providerID string) string {
223+
parts := strings.Split(providerID, "://")
224+
if len(parts) == 1 {
225+
return providerID
226+
}
227+
return parts[1]
228+
}

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)