diff --git a/deploy/k8s/controller-deployment.yaml b/deploy/k8s/controller-deployment.yaml index 2ab16d5..ab20ca2 100644 --- a/deploy/k8s/controller-deployment.yaml +++ b/deploy/k8s/controller-deployment.yaml @@ -45,6 +45,8 @@ spec: mountPath: /var/lib/csi/sockets/pluginproxy/ - name: cloudstack-conf mountPath: /etc/cloudstack-csi-driver + - name: cloud-init-dir + mountPath: /run/cloud-init/ - name: external-provisioner image: k8s.gcr.io/sig-storage/csi-provisioner:v2.0.4 @@ -79,3 +81,7 @@ spec: - name: cloudstack-conf secret: secretName: cloudstack-secret + - name: cloud-init-dir + hostPath: + path: /run/cloud-init/ + type: Directory \ No newline at end of file diff --git a/pkg/cloud/cloud.go b/pkg/cloud/cloud.go index c376303..2738c9b 100644 --- a/pkg/cloud/cloud.go +++ b/pkg/cloud/cloud.go @@ -54,10 +54,11 @@ var ( // client is the implementation of Interface. type client struct { *cloudstack.CloudStackClient + projectID string } // New creates a new cloud connector, given its configuration. func New(config *Config) Interface { csClient := cloudstack.NewAsyncClient(config.APIURL, config.APIKey, config.SecretKey, config.VerifySSL) - return &client{csClient} + return &client{csClient, config.ProjectID} } diff --git a/pkg/cloud/config.go b/pkg/cloud/config.go index 691be99..069de49 100644 --- a/pkg/cloud/config.go +++ b/pkg/cloud/config.go @@ -12,6 +12,7 @@ type Config struct { APIKey string SecretKey string VerifySSL bool + ProjectID string } // csConfig wraps the config for the CloudStack cloud provider. @@ -42,5 +43,6 @@ func ReadConfig(configFilePath string) (*Config, error) { APIKey: cfg.Global.APIKey, SecretKey: cfg.Global.SecretKey, VerifySSL: cfg.Global.SSLNoVerify, + ProjectID: cfg.Global.ProjectID, }, nil } diff --git a/pkg/cloud/metadata.go b/pkg/cloud/metadata.go index b2b5638..33028de 100644 --- a/pkg/cloud/metadata.go +++ b/pkg/cloud/metadata.go @@ -49,8 +49,31 @@ func (c *client) metadataInstanceID(ctx context.Context) string { return "" } +func (c *client) metadataProjectID(ctx context.Context) string { + slog := ctxzap.Extract(ctx).Sugar() + + // Try cloud-init + slog.Debug("Try with cloud-init") + if _, err := os.Stat(cloudInitInstanceFilePath); err == nil { + slog.Debugf("File %s exists", cloudInitInstanceFilePath) + ciData, err := c.readCloudInit(ctx, cloudInitInstanceFilePath) + if err != nil { + slog.Errorf("Cannot read cloud-init instance data: %v", err) + } else { + if ciData.Ds.Metadata.ProjectID != "" { + return ciData.Ds.Metadata.ProjectID + } + } + slog.Error("cloud-init project ID is not provided") + } + + slog.Debug("CloudStack project ID not found in meta-data.") + return "" +} + type cloudInitInstanceData struct { V1 cloudInitV1 `json:"v1"` + Ds cloudInitDs `json:"ds"` } type cloudInitV1 struct { @@ -59,6 +82,14 @@ type cloudInitV1 struct { Zone string `json:"availability_zone"` } +type cloudInitDs struct { + Metadata cloudInitMetadata `json:"meta_data"` +} + +type cloudInitMetadata struct { + ProjectID string `json:"project-uuid"` +} + func (c *client) readCloudInit(ctx context.Context, instanceFilePath string) (*cloudInitInstanceData, error) { slog := ctxzap.Extract(ctx).Sugar() diff --git a/pkg/cloud/vms.go b/pkg/cloud/vms.go index 29124c3..1ba4d77 100644 --- a/pkg/cloud/vms.go +++ b/pkg/cloud/vms.go @@ -12,6 +12,16 @@ func (c *client) GetVMByID(ctx context.Context, vmID string) (*VM, error) { ctxzap.Extract(ctx).Sugar().Infow("CloudStack API call", "command", "ListVirtualMachines", "params", map[string]string{ "id": vmID, }) + + if c.projectID == "" { + //get projectid from metadata + c.projectID = c.metadataProjectID(ctx) + } + + if c.projectID != "" { + p.SetProjectid(c.projectID) + } + l, err := c.VirtualMachine.ListVirtualMachines(p) if err != nil { return nil, err @@ -35,6 +45,16 @@ func (c *client) getVMByName(ctx context.Context, name string) (*VM, error) { ctxzap.Extract(ctx).Sugar().Infow("CloudStack API call", "command", "ListVirtualMachines", "params", map[string]string{ "name": name, }) + + if c.projectID == "" { + //get projectid from metadata + c.projectID = c.metadataProjectID(ctx) + } + + if c.projectID != "" { + p.SetProjectid(c.projectID) + } + l, err := c.VirtualMachine.ListVirtualMachines(p) if err != nil { return nil, err diff --git a/pkg/cloud/volumes.go b/pkg/cloud/volumes.go index 394be39..fd0f2d7 100644 --- a/pkg/cloud/volumes.go +++ b/pkg/cloud/volumes.go @@ -14,6 +14,16 @@ func (c *client) GetVolumeByID(ctx context.Context, volumeID string) (*Volume, e ctxzap.Extract(ctx).Sugar().Infow("CloudStack API call", "command", "ListVolumes", "params", map[string]string{ "id": volumeID, }) + + if c.projectID == "" { + //get projectid from metadata + c.projectID = c.metadataProjectID(ctx) + } + + if c.projectID != "" { + p.SetProjectid(c.projectID) + } + l, err := c.Volume.ListVolumes(p) if err != nil { return nil, err @@ -43,6 +53,16 @@ func (c *client) GetVolumeByName(ctx context.Context, name string) (*Volume, err ctxzap.Extract(ctx).Sugar().Infow("CloudStack API call", "command", "ListVolumes", "params", map[string]string{ "name": name, }) + + if c.projectID == "" { + //get projectid from metadata + c.projectID = c.metadataProjectID(ctx) + } + + if c.projectID != "" { + p.SetProjectid(c.projectID) + } + l, err := c.Volume.ListVolumes(p) if err != nil { return nil, err @@ -72,6 +92,15 @@ func (c *client) CreateVolume(ctx context.Context, diskOfferingID, zoneID, name p.SetZoneid(zoneID) p.SetName(name) p.SetSize(sizeInGB) + + if c.projectID == "" { + //get projectid from metadata + c.projectID = c.metadataProjectID(ctx) + } + + if c.projectID != "" { + p.SetProjectid(c.projectID) + } ctxzap.Extract(ctx).Sugar().Infow("CloudStack API call", "command", "CreateVolume", "params", map[string]string{ "diskofferingid": diskOfferingID, "zoneid": zoneID,