Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
154 changes: 146 additions & 8 deletions cloudstack/resource_cloudstack_account.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,18 @@ func resourceCloudStackAccount() *schema.Resource {
Required: true,
},
"password": {
Type: schema.TypeString,
Required: true,
Type: schema.TypeString,
Required: true,
Sensitive: true,
},
Comment thread
kristofer-atlas marked this conversation as resolved.
"username": {
Type: schema.TypeString,
Required: true,
},
"account_type": {
Type: schema.TypeInt,
Required: true,
Optional: true,
Computed: true,
},
"role_id": {
Type: schema.TypeString,
Expand All @@ -65,10 +67,12 @@ func resourceCloudStackAccount() *schema.Resource {
"account": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"domain_id": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
},
}
Expand All @@ -82,20 +86,26 @@ func resourceCloudStackAccountCreate(d *schema.ResourceData, meta interface{}) e
username := d.Get("username").(string)
password := d.Get("password").(string)
role_id := d.Get("role_id").(string)
account_type := d.Get("account_type").(int)
account := d.Get("account").(string)
domain_id := d.Get("domain_id").(string)

// Create a new parameter struct
p := cs.Account.NewCreateAccountParams(email, first_name, last_name, password, username)
p.SetAccounttype(int(account_type))
// account_type is derived from the role when omitted; only send it when the
// user explicitly set it in config. GetRawConfig distinguishes an explicit
// 0 (a valid account type) from an omitted value, which GetOk cannot.
if cfg := d.GetRawConfig(); !cfg.IsNull() && !cfg.GetAttr("account_type").IsNull() {
p.SetAccounttype(d.Get("account_type").(int))
}
p.SetRoleid(role_id)
if account != "" {
p.SetAccount(account)
} else {
p.SetAccount(username)
}
p.SetDomainid(domain_id)
if domain_id != "" {
p.SetDomainid(domain_id)
}

log.Printf("[DEBUG] Creating Account %s", account)
a, err := cs.Account.CreateAccount(p)
Expand All @@ -110,9 +120,137 @@ 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())

Comment thread
kristofer-atlas marked this conversation as resolved.
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)

// Match the user this resource manages by username. CloudStack accounts can
// hold multiple users, so falling back to an arbitrary index could bind state
// to the wrong user; leave the user fields untouched when no match is found.
if user := accountUser(account, d.Get("username").(string)); user != nil {
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 { 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") {
if newName := d.Get("account").(string); newName != "" {
p.SetNewname(newName)
}
}
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") || d.HasChange("username") {
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 {
return fmt.Errorf("Account %s no longer exists", d.Id())
}

// Match the user by the username we manage. On a username change the
// state still holds the previous username, so look it up by the old value.
oldUsername, _ := d.GetChange("username")
user := accountUser(accounts.Accounts[0], oldUsername.(string))
if user == nil {
return fmt.Errorf("Account %s has no user %q to update", d.Id(), oldUsername)
}

up := cs.User.NewUpdateUserParams(user.Id)

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))
}
if d.HasChange("username") {
up.SetUsername(d.Get("username").(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)
}

// accountUser returns the user of the account whose username matches the given
// value, or nil when no user matches. CloudStack accounts can hold multiple
// users, so selecting by username keeps Read/Update operating on the user this
// resource manages instead of an arbitrary index.
func accountUser(account *cloudstack.Account, username string) *cloudstack.AccountUser {
if account == nil {
return nil
}
for i := range account.User {
if account.User[i].Username == username {
return &account.User[i]
}
}
return nil
}

func resourceCloudStackAccountDelete(d *schema.ResourceData, meta interface{}) error {
cs := meta.(*cloudstack.CloudStackClient)
Expand Down
59 changes: 56 additions & 3 deletions cloudstack/resource_cloudstack_disk_offering.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package cloudstack

import (
"fmt"
"log"

"github.com/apache/cloudstack-go/v2/cloudstack"
Expand All @@ -44,6 +45,7 @@ func resourceCloudStackDiskOffering() *schema.Resource {
"disk_size": {
Type: schema.TypeInt,
Required: true,
ForceNew: true,
},
},
}
Expand Down Expand Up @@ -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))
}
Comment thread
kristofer-atlas marked this conversation as resolved.

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
}
61 changes: 59 additions & 2 deletions cloudstack/resource_cloudstack_domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ func resourceCloudStackDomain() *schema.Resource {
"domain_id": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
"network_domain": {
Type: schema.TypeString,
Expand All @@ -49,6 +51,8 @@ func resourceCloudStackDomain() *schema.Resource {
"parent_domain_id": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
},
}
Expand Down Expand Up @@ -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)
Comment thread
kristofer-atlas marked this conversation as resolved.
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)
Expand Down
Loading