diff --git a/cloudstack/resource_cloudstack_account.go b/cloudstack/resource_cloudstack_account.go index db6c1a2c..3149cb21 100644 --- a/cloudstack/resource_cloudstack_account.go +++ b/cloudstack/resource_cloudstack_account.go @@ -47,16 +47,19 @@ func resourceCloudStackAccount() *schema.Resource { Required: true, }, "password": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + Sensitive: true, }, "username": { Type: schema.TypeString, Required: true, + ForceNew: true, }, "account_type": { Type: schema.TypeInt, Required: true, + ForceNew: true, }, "role_id": { Type: schema.TypeString, @@ -110,9 +113,107 @@ func resourceCloudStackAccountCreate(d *schema.ResourceData, meta interface{}) e return resourceCloudStackAccountRead(d, meta) } -func resourceCloudStackAccountRead(d *schema.ResourceData, meta interface{}) error { return nil } +func resourceCloudStackAccountRead(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + log.Printf("[DEBUG] Reading Account %s", d.Id()) -func resourceCloudStackAccountUpdate(d *schema.ResourceData, meta interface{}) error { return nil } + p := cs.Account.NewListAccountsParams() + p.SetId(d.Id()) + + accounts, err := cs.Account.ListAccounts(p) + if err != nil { + return fmt.Errorf("Error retrieving Account %s: %s", d.Id(), err) + } + + if accounts.Count == 0 { + log.Printf("[DEBUG] Account %s does no longer exist", d.Id()) + d.SetId("") + return nil + } + + account := accounts.Accounts[0] + + d.Set("account_type", account.Accounttype) + d.Set("role_id", account.Roleid) + d.Set("account", account.Name) + d.Set("domain_id", account.Domainid) + + if len(account.User) > 0 { + user := account.User[0] + d.Set("email", user.Email) + d.Set("first_name", user.Firstname) + d.Set("last_name", user.Lastname) + d.Set("username", user.Username) + } + + log.Printf("[DEBUG] Account %s successfully read", d.Id()) + return nil +} + +func resourceCloudStackAccountUpdate(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + log.Printf("[DEBUG] Updating Account %s", d.Id()) + + // Handle account-level changes + if d.HasChange("role_id") || d.HasChange("account") || d.HasChange("domain_id") { + p := cs.Account.NewUpdateAccountParams() + p.SetId(d.Id()) + + if d.HasChange("role_id") { + p.SetRoleid(d.Get("role_id").(string)) + } + if d.HasChange("account") { + p.SetNewname(d.Get("account").(string)) + } + if d.HasChange("domain_id") { + p.SetDomainid(d.Get("domain_id").(string)) + } + + _, err := cs.Account.UpdateAccount(p) + if err != nil { + return fmt.Errorf("Error updating Account %s: %s", d.Id(), err) + } + } + + // Handle user-level changes via updateUser API + if d.HasChange("email") || d.HasChange("first_name") || d.HasChange("last_name") || d.HasChange("password") { + lp := cs.Account.NewListAccountsParams() + lp.SetId(d.Id()) + accounts, err := cs.Account.ListAccounts(lp) + if err != nil { + return fmt.Errorf("Error retrieving Account %s for user update: %s", d.Id(), err) + } + if accounts.Count == 0 || len(accounts.Accounts[0].User) == 0 { + return fmt.Errorf("Account %s has no users to update", d.Id()) + } + + userID := accounts.Accounts[0].User[0].Id + up := cs.User.NewUpdateUserParams(userID) + + if d.HasChange("email") { + up.SetEmail(d.Get("email").(string)) + } + if d.HasChange("first_name") { + up.SetFirstname(d.Get("first_name").(string)) + } + if d.HasChange("last_name") { + up.SetLastname(d.Get("last_name").(string)) + } + if d.HasChange("password") { + up.SetPassword(d.Get("password").(string)) + } + + _, err = cs.User.UpdateUser(up) + if err != nil { + return fmt.Errorf("Error updating user for Account %s: %s", d.Id(), err) + } + } + + log.Printf("[DEBUG] Account %s successfully updated", d.Id()) + return resourceCloudStackAccountRead(d, meta) +} func resourceCloudStackAccountDelete(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) diff --git a/cloudstack/resource_cloudstack_disk_offering.go b/cloudstack/resource_cloudstack_disk_offering.go index 197eaf4b..d82fd6e0 100644 --- a/cloudstack/resource_cloudstack_disk_offering.go +++ b/cloudstack/resource_cloudstack_disk_offering.go @@ -20,6 +20,7 @@ package cloudstack import ( + "fmt" "log" "github.com/apache/cloudstack-go/v2/cloudstack" @@ -44,6 +45,7 @@ func resourceCloudStackDiskOffering() *schema.Resource { "disk_size": { Type: schema.TypeInt, Required: true, + ForceNew: true, }, }, } @@ -72,8 +74,59 @@ func resourceCloudStackDiskOfferingCreate(d *schema.ResourceData, meta interface return resourceCloudStackDiskOfferingRead(d, meta) } -func resourceCloudStackDiskOfferingRead(d *schema.ResourceData, meta interface{}) error { return nil } +func resourceCloudStackDiskOfferingRead(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + log.Printf("[DEBUG] Retrieving disk offering %s", d.Get("name").(string)) + + offering, count, err := cs.DiskOffering.GetDiskOfferingByID(d.Id()) + if err != nil { + if count == 0 { + log.Printf("[DEBUG] Disk offering %s does no longer exist", d.Get("name").(string)) + d.SetId("") + return nil + } + return fmt.Errorf("Error retrieving disk offering %s: %s", d.Id(), err) + } + + d.Set("name", offering.Name) + d.Set("display_text", offering.Displaytext) + d.Set("disk_size", offering.Disksize) + + return nil +} + +func resourceCloudStackDiskOfferingUpdate(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + p := cs.DiskOffering.NewUpdateDiskOfferingParams(d.Id()) + + if d.HasChange("name") { + p.SetName(d.Get("name").(string)) + } + if d.HasChange("display_text") { + p.SetDisplaytext(d.Get("display_text").(string)) + } -func resourceCloudStackDiskOfferingUpdate(d *schema.ResourceData, meta interface{}) error { return nil } + log.Printf("[DEBUG] Updating disk offering %s", d.Get("name").(string)) + _, err := cs.DiskOffering.UpdateDiskOffering(p) + if err != nil { + return fmt.Errorf("Error updating disk offering: %s", err) + } -func resourceCloudStackDiskOfferingDelete(d *schema.ResourceData, meta interface{}) error { return nil } + return resourceCloudStackDiskOfferingRead(d, meta) +} + +func resourceCloudStackDiskOfferingDelete(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + p := cs.DiskOffering.NewDeleteDiskOfferingParams(d.Id()) + + log.Printf("[DEBUG] Deleting disk offering %s", d.Get("name").(string)) + _, err := cs.DiskOffering.DeleteDiskOffering(p) + if err != nil { + return fmt.Errorf("Error deleting disk offering: %s", err) + } + + return nil +} diff --git a/cloudstack/resource_cloudstack_domain.go b/cloudstack/resource_cloudstack_domain.go index 3e11b1a7..1c6b35a1 100644 --- a/cloudstack/resource_cloudstack_domain.go +++ b/cloudstack/resource_cloudstack_domain.go @@ -41,6 +41,8 @@ func resourceCloudStackDomain() *schema.Resource { "domain_id": { Type: schema.TypeString, Optional: true, + Computed: true, + ForceNew: true, }, "network_domain": { Type: schema.TypeString, @@ -49,6 +51,8 @@ func resourceCloudStackDomain() *schema.Resource { "parent_domain_id": { Type: schema.TypeString, Optional: true, + Computed: true, + ForceNew: true, }, }, } @@ -89,9 +93,62 @@ func resourceCloudStackDomainCreate(d *schema.ResourceData, meta interface{}) er return resourceCloudStackDomainRead(d, meta) } -func resourceCloudStackDomainRead(d *schema.ResourceData, meta interface{}) error { return nil } +func resourceCloudStackDomainRead(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + log.Printf("[DEBUG] Reading Domain %s", d.Id()) + + p := cs.Domain.NewListDomainsParams() + p.SetId(d.Id()) + + domains, err := cs.Domain.ListDomains(p) + if err != nil { + return fmt.Errorf("Error reading Domain %s: %s", d.Id(), err) + } + + if domains.Count == 0 { + log.Printf("[DEBUG] Domain %s does no longer exist", d.Id()) + d.SetId("") + return nil + } + + domain := domains.Domains[0] + log.Printf("[DEBUG] Domain %s found: %s", d.Id(), domain.Name) + + d.Set("name", domain.Name) + d.Set("domain_id", domain.Id) + d.Set("network_domain", domain.Networkdomain) + d.Set("parent_domain_id", domain.Parentdomainid) + + return nil +} + +func resourceCloudStackDomainUpdate(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + name := d.Get("name").(string) + + if d.HasChange("name") || d.HasChange("network_domain") { + p := cs.Domain.NewUpdateDomainParams(d.Id()) -func resourceCloudStackDomainUpdate(d *schema.ResourceData, meta interface{}) error { return nil } + if d.HasChange("name") { + p.SetName(name) + } + + if d.HasChange("network_domain") { + p.SetNetworkdomain(d.Get("network_domain").(string)) + } + + log.Printf("[DEBUG] Updating Domain %s", name) + _, err := cs.Domain.UpdateDomain(p) + if err != nil { + return fmt.Errorf("Error updating Domain %s: %s", name, err) + } + log.Printf("[DEBUG] Domain %s successfully updated", name) + } + + return resourceCloudStackDomainRead(d, meta) +} func resourceCloudStackDomainDelete(d *schema.ResourceData, meta interface{}) error { cs := meta.(*cloudstack.CloudStackClient) diff --git a/cloudstack/resource_cloudstack_user.go b/cloudstack/resource_cloudstack_user.go index 74fb84a9..5bef82a2 100644 --- a/cloudstack/resource_cloudstack_user.go +++ b/cloudstack/resource_cloudstack_user.go @@ -37,6 +37,7 @@ func resourceCloudStackUser() *schema.Resource { "account": { Type: schema.TypeString, Optional: true, + ForceNew: true, }, "email": { Type: schema.TypeString, @@ -51,12 +52,14 @@ func resourceCloudStackUser() *schema.Resource { Required: true, }, "password": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + Sensitive: true, }, "username": { Type: schema.TypeString, Required: true, + ForceNew: true, }, }, } @@ -88,6 +91,28 @@ func resourceCloudStackUserCreate(d *schema.ResourceData, meta interface{}) erro } func resourceCloudStackUserUpdate(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + p := cs.User.NewUpdateUserParams(d.Id()) + + if d.HasChange("email") { + p.SetEmail(d.Get("email").(string)) + } + if d.HasChange("first_name") { + p.SetFirstname(d.Get("first_name").(string)) + } + if d.HasChange("last_name") { + p.SetLastname(d.Get("last_name").(string)) + } + if d.HasChange("password") { + p.SetPassword(d.Get("password").(string)) + } + + _, err := cs.User.UpdateUser(p) + if err != nil { + return fmt.Errorf("Error updating User %s: %s", d.Id(), err) + } + return resourceCloudStackUserRead(d, meta) } @@ -106,5 +131,22 @@ func resourceCloudStackUserDelete(d *schema.ResourceData, meta interface{}) erro } func resourceCloudStackUserRead(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + user, count, err := cs.User.GetUserByID(d.Id()) + if err != nil { + if count == 0 { + d.SetId("") + return nil + } + return fmt.Errorf("Error reading User %s: %s", d.Id(), err) + } + + d.Set("account", user.Account) + d.Set("email", user.Email) + d.Set("first_name", user.Firstname) + d.Set("last_name", user.Lastname) + d.Set("username", user.Username) + return nil }