Skip to content

Add project support #356

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/book/src/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
secret-key: <cloudstackSecretKey>
api-url: <cloudstackApiUrl>
verify-ssl: "false"
project-id: <project id> # Optional. If provided, the provider will use this project id for all operations

```
- Apply this secret to the management cluster:
Expand Down
9 changes: 6 additions & 3 deletions pkg/cloud/affinity_groups.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package cloud

import (
"github.com/apache/cloudstack-go/v2/cloudstack"
"github.com/pkg/errors"
infrav1 "sigs.k8s.io/cluster-api-provider-cloudstack/api/v1beta3"
)
Expand All @@ -42,7 +43,7 @@ type AffinityGroupIface interface {

func (c *client) FetchAffinityGroup(group *AffinityGroup) (reterr error) {
if group.ID != "" {
affinityGroup, count, err := c.cs.AffinityGroup.GetAffinityGroupByID(group.ID)
affinityGroup, count, err := c.cs.AffinityGroup.GetAffinityGroupByID(group.ID, cloudstack.WithProject(c.config.ProjectID))
if err != nil {
// handle via multierr
c.customMetrics.EvaluateErrorAndIncrementAcsReconciliationErrorCounter(err)
Expand All @@ -57,7 +58,7 @@ func (c *client) FetchAffinityGroup(group *AffinityGroup) (reterr error) {
}
}
if group.Name != "" {
affinityGroup, count, err := c.cs.AffinityGroup.GetAffinityGroupByName(group.Name)
affinityGroup, count, err := c.cs.AffinityGroup.GetAffinityGroupByName(group.Name, cloudstack.WithProject(c.config.ProjectID))
if err != nil {
// handle via multierr
c.customMetrics.EvaluateErrorAndIncrementAcsReconciliationErrorCounter(err)
Expand All @@ -78,6 +79,7 @@ func (c *client) GetOrCreateAffinityGroup(group *AffinityGroup) (retErr error) {
if err := c.FetchAffinityGroup(group); err != nil { // Group not found?
p := c.cs.AffinityGroup.NewCreateAffinityGroupParams(group.Name, group.Type)
p.SetName(group.Name)
setIfNotEmpty(c.config.ProjectID, p.SetProjectid)
resp, err := c.cs.AffinityGroup.CreateAffinityGroup(p)
if err != nil {
c.customMetrics.EvaluateErrorAndIncrementAcsReconciliationErrorCounter(err)
Expand All @@ -92,6 +94,7 @@ func (c *client) DeleteAffinityGroup(group *AffinityGroup) (retErr error) {
p := c.cs.AffinityGroup.NewDeleteAffinityGroupParams()
setIfNotEmpty(group.ID, p.SetId)
setIfNotEmpty(group.Name, p.SetName)
setIfNotEmpty(c.config.ProjectID, p.SetProjectid)
_, retErr = c.cs.AffinityGroup.DeleteAffinityGroup(p)
c.customMetrics.EvaluateErrorAndIncrementAcsReconciliationErrorCounter(retErr)
return retErr
Expand All @@ -101,7 +104,7 @@ type affinityGroups []AffinityGroup

func (c *client) getCurrentAffinityGroups(csMachine *infrav1.CloudStackMachine) (affinityGroups, error) {
// Start by fetching VM details which includes an array of currently associated affinity groups.
if virtM, count, err := c.cs.VirtualMachine.GetVirtualMachineByID(*csMachine.Spec.InstanceID); err != nil {
if virtM, count, err := c.cs.VirtualMachine.GetVirtualMachineByID(*csMachine.Spec.InstanceID, cloudstack.WithProject(c.config.ProjectID)); err != nil {
c.customMetrics.EvaluateErrorAndIncrementAcsReconciliationErrorCounter(err)
return nil, err
} else if count > 1 {
Expand Down
18 changes: 9 additions & 9 deletions pkg/cloud/affinity_groups_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,21 @@ var _ = Describe("AffinityGroup Unit Tests", func() {
Context("Fetch or Create Affinity group", func() {
It("fetches an affinity group by Name", func() {
dummies.AffinityGroup.ID = "" // Force name fetching.
ags.EXPECT().GetAffinityGroupByName(dummies.AffinityGroup.Name).Return(&cloudstack.AffinityGroup{}, 1, nil)
ags.EXPECT().GetAffinityGroupByName(dummies.AffinityGroup.Name, gomock.Any()).Return(&cloudstack.AffinityGroup{}, 1, nil)

Ω(client.GetOrCreateAffinityGroup(dummies.AffinityGroup)).Should(Succeed())
})

It("fetches an affinity group by ID", func() {
ags.EXPECT().GetAffinityGroupByID(dummies.AffinityGroup.ID).Return(&cloudstack.AffinityGroup{}, 1, nil)
ags.EXPECT().GetAffinityGroupByID(dummies.AffinityGroup.ID, gomock.Any()).Return(&cloudstack.AffinityGroup{}, 1, nil)

Ω(client.GetOrCreateAffinityGroup(dummies.AffinityGroup)).Should(Succeed())
})

It("creates an affinity group", func() {
// dummies.SetDummyDomainAndAccount()
// dummies.SetDummyDomainID()
ags.EXPECT().GetAffinityGroupByID(dummies.AffinityGroup.ID).Return(nil, -1, fakeError)
ags.EXPECT().GetAffinityGroupByID(dummies.AffinityGroup.ID, gomock.Any()).Return(nil, -1, fakeError)
ags.EXPECT().NewCreateAffinityGroupParams(dummies.AffinityGroup.Name, dummies.AffinityGroup.Type).
Return(&cloudstack.CreateAffinityGroupParams{})
ags.EXPECT().CreateAffinityGroup(ParamMatch(And(NameEquals(dummies.AffinityGroup.Name)))).
Expand All @@ -84,7 +84,7 @@ var _ = Describe("AffinityGroup Unit Tests", func() {
It("creates an affinity group if Name provided returns more than one affinity group", func() {
dummies.AffinityGroup.ID = "" // Force name fetching.
agp := &cloudstack.CreateAffinityGroupParams{}
ags.EXPECT().GetAffinityGroupByName(dummies.AffinityGroup.Name).Return(&cloudstack.AffinityGroup{}, 2, nil)
ags.EXPECT().GetAffinityGroupByName(dummies.AffinityGroup.Name, gomock.Any()).Return(&cloudstack.AffinityGroup{}, 2, nil)
ags.EXPECT().NewCreateAffinityGroupParams(gomock.Any(), gomock.Any()).Return(agp)
ags.EXPECT().CreateAffinityGroup(agp).Return(&cloudstack.CreateAffinityGroupResponse{}, nil)

Expand All @@ -94,7 +94,7 @@ var _ = Describe("AffinityGroup Unit Tests", func() {
It("creates an affinity group if getting affinity group by name fails", func() {
dummies.AffinityGroup.ID = "" // Force name fetching.
agp := &cloudstack.CreateAffinityGroupParams{}
ags.EXPECT().GetAffinityGroupByName(dummies.AffinityGroup.Name).Return(nil, -1, fakeError)
ags.EXPECT().GetAffinityGroupByName(dummies.AffinityGroup.Name, gomock.Any()).Return(nil, -1, fakeError)
ags.EXPECT().NewCreateAffinityGroupParams(gomock.Any(), gomock.Any()).Return(agp)
ags.EXPECT().CreateAffinityGroup(agp).Return(&cloudstack.CreateAffinityGroupResponse{}, nil)

Expand All @@ -103,7 +103,7 @@ var _ = Describe("AffinityGroup Unit Tests", func() {

It("creates an affinity group if ID provided returns more than one affinity group", func() {
agp := &cloudstack.CreateAffinityGroupParams{}
ags.EXPECT().GetAffinityGroupByID(dummies.AffinityGroup.ID).Return(&cloudstack.AffinityGroup{}, 2, nil)
ags.EXPECT().GetAffinityGroupByID(dummies.AffinityGroup.ID, gomock.Any()).Return(&cloudstack.AffinityGroup{}, 2, nil)
ags.EXPECT().NewCreateAffinityGroupParams(gomock.Any(), gomock.Any()).Return(agp)
ags.EXPECT().CreateAffinityGroup(agp).Return(&cloudstack.CreateAffinityGroupResponse{}, nil)

Expand All @@ -112,7 +112,7 @@ var _ = Describe("AffinityGroup Unit Tests", func() {

It("creates an affinity group if getting affinity group by ID fails", func() {
agp := &cloudstack.CreateAffinityGroupParams{}
ags.EXPECT().GetAffinityGroupByID(dummies.AffinityGroup.ID).Return(nil, -1, fakeError)
ags.EXPECT().GetAffinityGroupByID(dummies.AffinityGroup.ID, gomock.Any()).Return(nil, -1, fakeError)
ags.EXPECT().NewCreateAffinityGroupParams(gomock.Any(), gomock.Any()).Return(agp)
ags.EXPECT().CreateAffinityGroup(agp).Return(&cloudstack.CreateAffinityGroupResponse{}, nil)

Expand Down Expand Up @@ -164,7 +164,7 @@ var _ = Describe("AffinityGroup Unit Tests", func() {
It("Associate affinity group", func() {
uagp := &cloudstack.UpdateVMAffinityGroupParams{}
vmp := &cloudstack.StartVirtualMachineParams{}
vms.EXPECT().GetVirtualMachineByID(*dummies.CSMachine1.Spec.InstanceID).Return(&cloudstack.VirtualMachine{}, 1, nil)
vms.EXPECT().GetVirtualMachineByID(*dummies.CSMachine1.Spec.InstanceID, gomock.Any()).Return(&cloudstack.VirtualMachine{}, 1, nil)
ags.EXPECT().NewUpdateVMAffinityGroupParams(*dummies.CSMachine1.Spec.InstanceID).Return(uagp)
vms.EXPECT().NewStopVirtualMachineParams(*dummies.CSMachine1.Spec.InstanceID).Return(&cloudstack.StopVirtualMachineParams{})
vms.EXPECT().StopVirtualMachine(&cloudstack.StopVirtualMachineParams{}).Return(&cloudstack.StopVirtualMachineResponse{State: "Stopping"}, nil)
Expand All @@ -177,7 +177,7 @@ var _ = Describe("AffinityGroup Unit Tests", func() {
It("Disassociate affinity group", func() {
uagp := &cloudstack.UpdateVMAffinityGroupParams{}
vmp := &cloudstack.StartVirtualMachineParams{}
vms.EXPECT().GetVirtualMachineByID(*dummies.CSMachine1.Spec.InstanceID).Return(&cloudstack.VirtualMachine{}, 1, nil)
vms.EXPECT().GetVirtualMachineByID(*dummies.CSMachine1.Spec.InstanceID, gomock.Any()).Return(&cloudstack.VirtualMachine{}, 1, nil)
ags.EXPECT().NewUpdateVMAffinityGroupParams(*dummies.CSMachine1.Spec.InstanceID).Return(uagp)
vms.EXPECT().NewStopVirtualMachineParams(*dummies.CSMachine1.Spec.InstanceID).Return(&cloudstack.StopVirtualMachineParams{})
vms.EXPECT().StopVirtualMachine(&cloudstack.StopVirtualMachineParams{}).Return(&cloudstack.StopVirtualMachineResponse{State: "Stopping"}, nil)
Expand Down
1 change: 1 addition & 0 deletions pkg/cloud/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ type Config struct {
APIKey string `yaml:"api-key"`
SecretKey string `yaml:"secret-key"`
VerifySSL string `yaml:"verify-ssl"`
ProjectID string `yaml:"project-id"`
}

type client struct {
Expand Down
23 changes: 13 additions & 10 deletions pkg/cloud/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func setMachineDataFromVMMetrics(vmResponse *cloudstack.VirtualMachinesMetric, c
func (c *client) ResolveVMInstanceDetails(csMachine *infrav1.CloudStackMachine) error {
// Attempt to fetch by ID.
if csMachine.Spec.InstanceID != nil {
vmResp, count, err := c.cs.VirtualMachine.GetVirtualMachinesMetricByID(*csMachine.Spec.InstanceID)
vmResp, count, err := c.cs.VirtualMachine.GetVirtualMachinesMetricByID(*csMachine.Spec.InstanceID, cloudstack.WithProject(c.config.ProjectID))
if err != nil && !strings.Contains(strings.ToLower(err.Error()), "no match found") {
c.customMetrics.EvaluateErrorAndIncrementAcsReconciliationErrorCounter(err)
return err
Expand All @@ -72,7 +72,7 @@ func (c *client) ResolveVMInstanceDetails(csMachine *infrav1.CloudStackMachine)

// Attempt fetch by name.
if csMachine.Name != "" {
vmResp, count, err := c.cs.VirtualMachine.GetVirtualMachinesMetricByName(csMachine.Name) // add opts usage
vmResp, count, err := c.cs.VirtualMachine.GetVirtualMachinesMetricByName(csMachine.Name, cloudstack.WithProject(c.config.ProjectID))
if err != nil && !strings.Contains(strings.ToLower(err.Error()), "no match") {
c.customMetrics.EvaluateErrorAndIncrementAcsReconciliationErrorCounter(err)
return err
Expand All @@ -88,7 +88,7 @@ func (c *client) ResolveVMInstanceDetails(csMachine *infrav1.CloudStackMachine)

func (c *client) ResolveServiceOffering(csMachine *infrav1.CloudStackMachine, zoneID string) (offering cloudstack.ServiceOffering, retErr error) {
if len(csMachine.Spec.Offering.ID) > 0 {
csOffering, count, err := c.cs.ServiceOffering.GetServiceOfferingByID(csMachine.Spec.Offering.ID)
csOffering, count, err := c.cs.ServiceOffering.GetServiceOfferingByID(csMachine.Spec.Offering.ID, cloudstack.WithProject(c.config.ProjectID))
if err != nil {
c.customMetrics.EvaluateErrorAndIncrementAcsReconciliationErrorCounter(err)
return cloudstack.ServiceOffering{}, multierror.Append(retErr, errors.Wrapf(
Expand All @@ -104,7 +104,7 @@ func (c *client) ResolveServiceOffering(csMachine *infrav1.CloudStackMachine, zo
}
return *csOffering, nil
}
csOffering, count, err := c.cs.ServiceOffering.GetServiceOfferingByName(csMachine.Spec.Offering.Name, cloudstack.WithZone(zoneID))
csOffering, count, err := c.cs.ServiceOffering.GetServiceOfferingByName(csMachine.Spec.Offering.Name, cloudstack.WithZone(zoneID), cloudstack.WithProject(c.config.ProjectID))
if err != nil {
c.customMetrics.EvaluateErrorAndIncrementAcsReconciliationErrorCounter(err)
return cloudstack.ServiceOffering{}, multierror.Append(retErr, errors.Wrapf(
Expand All @@ -122,7 +122,7 @@ func (c *client) ResolveTemplate(
zoneID string,
) (templateID string, retErr error) {
if len(csMachine.Spec.Template.ID) > 0 {
csTemplate, count, err := c.cs.Template.GetTemplateByID(csMachine.Spec.Template.ID, "executable")
csTemplate, count, err := c.cs.Template.GetTemplateByID(csMachine.Spec.Template.ID, "executable", cloudstack.WithProject(c.config.ProjectID))
if err != nil {
c.customMetrics.EvaluateErrorAndIncrementAcsReconciliationErrorCounter(err)
return "", multierror.Append(retErr, errors.Wrapf(
Expand All @@ -138,7 +138,7 @@ func (c *client) ResolveTemplate(
}
return csMachine.Spec.Template.ID, nil
}
templateID, count, err := c.cs.Template.GetTemplateID(csMachine.Spec.Template.Name, "executable", zoneID)
templateID, count, err := c.cs.Template.GetTemplateID(csMachine.Spec.Template.Name, "executable", zoneID, cloudstack.WithProject(c.config.ProjectID))
if err != nil {
c.customMetrics.EvaluateErrorAndIncrementAcsReconciliationErrorCounter(err)
return "", multierror.Append(retErr, errors.Wrapf(
Expand All @@ -156,7 +156,7 @@ func (c *client) ResolveTemplate(
func (c *client) ResolveDiskOffering(csMachine *infrav1.CloudStackMachine, zoneID string) (diskOfferingID string, retErr error) {
diskOfferingID = csMachine.Spec.DiskOffering.ID
if len(csMachine.Spec.DiskOffering.Name) > 0 {
diskID, count, err := c.cs.DiskOffering.GetDiskOfferingID(csMachine.Spec.DiskOffering.Name, cloudstack.WithZone(zoneID))
diskID, count, err := c.cs.DiskOffering.GetDiskOfferingID(csMachine.Spec.DiskOffering.Name, cloudstack.WithZone(zoneID), cloudstack.WithProject(c.config.ProjectID))
if err != nil {
c.customMetrics.EvaluateErrorAndIncrementAcsReconciliationErrorCounter(err)
return "", multierror.Append(retErr, errors.Wrapf(
Expand All @@ -183,7 +183,7 @@ func (c *client) ResolveDiskOffering(csMachine *infrav1.CloudStackMachine, zoneI
}

func verifyDiskoffering(csMachine *infrav1.CloudStackMachine, c *client, diskOfferingID string, retErr error) (string, error) {
csDiskOffering, count, err := c.cs.DiskOffering.GetDiskOfferingByID(diskOfferingID)
csDiskOffering, count, err := c.cs.DiskOffering.GetDiskOfferingByID(diskOfferingID, cloudstack.WithProject(c.config.ProjectID))
if err != nil {
c.customMetrics.EvaluateErrorAndIncrementAcsReconciliationErrorCounter(err)
return "", multierror.Append(retErr, errors.Wrapf(
Expand Down Expand Up @@ -300,6 +300,7 @@ func (c *client) DeployVM(
setIfNotEmpty(csMachine.Name, p.SetName)
setIfNotEmpty(capiMachine.Name, p.SetDisplayname)
setIfNotEmpty(diskOfferingID, p.SetDiskofferingid)
setIfNotEmpty(c.config.ProjectID, p.SetProjectid)
setIntIfPositive(csMachine.Spec.DiskOffering.CustomSize, p.SetSize)

setIfNotEmpty(csMachine.Spec.SSHKey, p.SetKeypair)
Expand Down Expand Up @@ -330,7 +331,7 @@ func (c *client) DeployVM(
// CloudStack may have created the VM even though it reported an error. We attempt to
// retrieve the VM so we can populate the CloudStackMachine for the user to manually
// clean up.
vm, findErr := findVirtualMachine(c.cs.VirtualMachine, templateID, fd, csMachine)
vm, findErr := findVirtualMachine(c.cs.VirtualMachine, templateID, fd, csMachine, c.config.ProjectID)
if findErr != nil {
c.customMetrics.EvaluateErrorAndIncrementAcsReconciliationErrorCounter(findErr)
return fmt.Errorf("%v; find virtual machine: %v", err, findErr)
Expand Down Expand Up @@ -394,13 +395,14 @@ func findVirtualMachine(
client cloudstack.VirtualMachineServiceIface,
templateID string,
failureDomain *infrav1.CloudStackFailureDomain,
machine *infrav1.CloudStackMachine,
machine *infrav1.CloudStackMachine, projectID string,
) (*cloudstack.VirtualMachine, error) {
params := client.NewListVirtualMachinesParams()
params.SetTemplateid(templateID)
params.SetZoneid(failureDomain.Spec.Zone.ID)
params.SetNetworkid(failureDomain.Spec.Zone.Network.ID)
params.SetName(machine.Name)
setIfNotEmpty(projectID, params.SetProjectid)

response, err := client.ListVirtualMachines(params)
if err != nil {
Expand Down Expand Up @@ -453,6 +455,7 @@ func (c *client) listVMInstanceDatadiskVolumeIDs(instanceID string) ([]string, e
p.SetVirtualmachineid(instanceID)
// VM root volumes are destroyed automatically, no need to explicitly include
p.SetType("DATADISK")
setIfNotEmpty(c.config.ProjectID, p.SetProjectid)

listVOLResp, err := c.csAsync.Volume.ListVolumes(p)
if err != nil {
Expand Down
Loading
Loading