Skip to content

Commit 40a9b2b

Browse files
committed
Make domain_id required in cloudstack_account resource and update documentation with usage examples
1 parent 16915b6 commit 40a9b2b

3 files changed

Lines changed: 291 additions & 9 deletions

File tree

cloudstack/resource_cloudstack_account.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func resourceCloudStackAccount() *schema.Resource {
6868
},
6969
"domain_id": {
7070
Type: schema.TypeString,
71-
Optional: true,
71+
Required: true,
7272
},
7373
},
7474
}
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
//
2+
// Licensed to the Apache Software Foundation (ASF) under one
3+
// or more contributor license agreements. See the NOTICE file
4+
// distributed with this work for additional information
5+
// regarding copyright ownership. The ASF licenses this file
6+
// to you under the Apache License, Version 2.0 (the
7+
// "License"); you may not use this file except in compliance
8+
// with the License. You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing,
13+
// software distributed under the License is distributed on an
14+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
// KIND, either express or implied. See the License for the
16+
// specific language governing permissions and limitations
17+
// under the License.
18+
//
19+
20+
package cloudstack
21+
22+
import (
23+
"fmt"
24+
"testing"
25+
26+
"github.com/apache/cloudstack-go/v2/cloudstack"
27+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
28+
"github.com/hashicorp/terraform-plugin-testing/terraform"
29+
)
30+
31+
func TestAccCloudStackAccount_basic(t *testing.T) {
32+
var account cloudstack.Account
33+
34+
resource.Test(t, resource.TestCase{
35+
PreCheck: func() { testAccPreCheck(t) },
36+
Providers: testAccProviders,
37+
CheckDestroy: testAccCheckCloudStackAccountDestroy,
38+
Steps: []resource.TestStep{
39+
{
40+
Config: testAccCloudStackAccount_basic,
41+
Check: resource.ComposeTestCheckFunc(
42+
testAccCheckCloudStackAccountExists("cloudstack_account.foo", &account),
43+
resource.TestCheckResourceAttr(
44+
"cloudstack_account.foo", "username", "terraform-test-user"),
45+
resource.TestCheckResourceAttr(
46+
"cloudstack_account.foo", "email", "terraform@example.com"),
47+
resource.TestCheckResourceAttr(
48+
"cloudstack_account.foo", "first_name", "Terraform"),
49+
resource.TestCheckResourceAttr(
50+
"cloudstack_account.foo", "last_name", "Test"),
51+
resource.TestCheckResourceAttr(
52+
"cloudstack_account.foo", "account_type", "0"),
53+
),
54+
},
55+
},
56+
})
57+
}
58+
59+
func TestAccCloudStackAccount_rootDomain(t *testing.T) {
60+
var account cloudstack.Account
61+
62+
resource.Test(t, resource.TestCase{
63+
PreCheck: func() { testAccPreCheck(t) },
64+
Providers: testAccProviders,
65+
CheckDestroy: testAccCheckCloudStackAccountDestroy,
66+
Steps: []resource.TestStep{
67+
{
68+
Config: testAccCloudStackAccount_rootDomain,
69+
Check: resource.ComposeTestCheckFunc(
70+
testAccCheckCloudStackAccountExists("cloudstack_account.root_account", &account),
71+
resource.TestCheckResourceAttr(
72+
"cloudstack_account.root_account", "username", "terraform-root-user"),
73+
resource.TestCheckResourceAttr(
74+
"cloudstack_account.root_account", "email", "root@example.com"),
75+
resource.TestCheckResourceAttr(
76+
"cloudstack_account.root_account", "first_name", "Root"),
77+
resource.TestCheckResourceAttr(
78+
"cloudstack_account.root_account", "last_name", "Admin"),
79+
resource.TestCheckResourceAttr(
80+
"cloudstack_account.root_account", "account_type", "1"),
81+
resource.TestCheckResourceAttrSet(
82+
"cloudstack_account.root_account", "domain_id"),
83+
),
84+
},
85+
},
86+
})
87+
}
88+
89+
func TestAccCloudStackAccount_withCustomAccount(t *testing.T) {
90+
var account cloudstack.Account
91+
92+
resource.Test(t, resource.TestCase{
93+
PreCheck: func() { testAccPreCheck(t) },
94+
Providers: testAccProviders,
95+
CheckDestroy: testAccCheckCloudStackAccountDestroy,
96+
Steps: []resource.TestStep{
97+
{
98+
Config: testAccCloudStackAccount_withCustomAccount,
99+
Check: resource.ComposeTestCheckFunc(
100+
testAccCheckCloudStackAccountExists("cloudstack_account.custom", &account),
101+
resource.TestCheckResourceAttr(
102+
"cloudstack_account.custom", "username", "terraform-custom-user"),
103+
resource.TestCheckResourceAttr(
104+
"cloudstack_account.custom", "account", "custom-account-name"),
105+
resource.TestCheckResourceAttr(
106+
"cloudstack_account.custom", "account_type", "2"),
107+
),
108+
},
109+
},
110+
})
111+
}
112+
113+
func testAccCheckCloudStackAccountExists(n string, account *cloudstack.Account) resource.TestCheckFunc {
114+
return func(s *terraform.State) error {
115+
rs, ok := s.RootModule().Resources[n]
116+
if !ok {
117+
return fmt.Errorf("Not found: %s", n)
118+
}
119+
120+
if rs.Primary.ID == "" {
121+
return fmt.Errorf("No Account ID is set")
122+
}
123+
124+
cs := testAccProvider.Meta().(*cloudstack.CloudStackClient)
125+
a, _, err := cs.Account.GetAccountByID(rs.Primary.ID)
126+
127+
if err != nil {
128+
return err
129+
}
130+
131+
if a.Id != rs.Primary.ID {
132+
return fmt.Errorf("Account not found")
133+
}
134+
135+
*account = *a
136+
137+
return nil
138+
}
139+
}
140+
141+
func testAccCheckCloudStackAccountDestroy(s *terraform.State) error {
142+
cs := testAccProvider.Meta().(*cloudstack.CloudStackClient)
143+
144+
for _, rs := range s.RootModule().Resources {
145+
if rs.Type != "cloudstack_account" {
146+
continue
147+
}
148+
149+
if rs.Primary.ID == "" {
150+
return fmt.Errorf("No Account ID is set")
151+
}
152+
153+
// Use a defer/recover to catch the panic that might occur when trying to access the account
154+
var err error
155+
func() {
156+
defer func() {
157+
if r := recover(); r != nil {
158+
// If a panic occurs, it means the account doesn't exist, which is what we want
159+
err = nil
160+
}
161+
}()
162+
a, _, e := cs.Account.GetAccountByID(rs.Primary.ID)
163+
if e == nil && a != nil && a.Id == rs.Primary.ID {
164+
err = fmt.Errorf("Account %s still exists", rs.Primary.ID)
165+
}
166+
}()
167+
168+
if err != nil {
169+
return err
170+
}
171+
}
172+
173+
return nil
174+
}
175+
176+
const testAccCloudStackAccount_basic = `
177+
data "cloudstack_domain" "root" {
178+
filter {
179+
name = "name"
180+
value = "ROOT"
181+
}
182+
}
183+
184+
data "cloudstack_role" "user_role" {
185+
filter {
186+
name = "type"
187+
value = "User"
188+
}
189+
}
190+
191+
resource "cloudstack_account" "foo" {
192+
email = "terraform@example.com"
193+
first_name = "Terraform"
194+
last_name = "Test"
195+
password = "P@ssw0rd123!"
196+
username = "terraform-test-user"
197+
account_type = 0
198+
role_id = data.cloudstack_role.user_role.id
199+
domain_id = data.cloudstack_domain.root.id
200+
}
201+
`
202+
203+
const testAccCloudStackAccount_rootDomain = `
204+
data "cloudstack_domain" "root" {
205+
filter {
206+
name = "name"
207+
value = "ROOT"
208+
}
209+
}
210+
211+
data "cloudstack_role" "admin_role" {
212+
filter {
213+
name = "type"
214+
value = "Admin"
215+
}
216+
}
217+
218+
resource "cloudstack_account" "root_account" {
219+
email = "root@example.com"
220+
first_name = "Root"
221+
last_name = "Admin"
222+
password = "P@ssw0rd123!"
223+
username = "terraform-root-user"
224+
account_type = 1
225+
role_id = data.cloudstack_role.admin_role.id
226+
domain_id = data.cloudstack_domain.root.id
227+
}
228+
`
229+
230+
const testAccCloudStackAccount_withCustomAccount = `
231+
data "cloudstack_domain" "root" {
232+
filter {
233+
name = "name"
234+
value = "ROOT"
235+
}
236+
}
237+
238+
data "cloudstack_role" "domain_admin_role" {
239+
filter {
240+
name = "type"
241+
value = "DomainAdmin"
242+
}
243+
}
244+
245+
resource "cloudstack_account" "custom" {
246+
email = "custom@example.com"
247+
first_name = "Custom"
248+
last_name = "Account"
249+
password = "P@ssw0rd123!"
250+
username = "terraform-custom-user"
251+
account = "custom-account-name"
252+
account_type = 2
253+
role_id = data.cloudstack_role.domain_admin_role.id
254+
domain_id = data.cloudstack_domain.root.id
255+
}
256+
`

website/docs/r/account.html.markdown

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,41 @@ A `cloudstack_account` resource manages an account within CloudStack.
1212

1313
## Example Usage
1414

15+
### Basic Account in Root Domain
16+
1517
```hcl
18+
data "cloudstack_domain" "root" {
19+
filter {
20+
name = "name"
21+
value = "ROOT"
22+
}
23+
}
24+
1625
resource "cloudstack_account" "example" {
17-
email = "user@example.com"
18-
first_name = "John"
19-
last_name = "Doe"
20-
password = "securepassword"
21-
username = "jdoe"
26+
email = "user@example.com"
27+
first_name = "John"
28+
last_name = "Doe"
29+
password = "securepassword"
30+
username = "jdoe"
2231
account_type = 1 # 1 for admin, 2 for domain admin, 0 for regular user
23-
role_id = "1234abcd" # ID of the role associated with the account
32+
role_id = "1234abcd" # ID of the role associated with the account
33+
domain_id = data.cloudstack_domain.root.id
34+
}
35+
```
36+
37+
### Account in Specific Domain
38+
39+
```hcl
40+
resource "cloudstack_account" "domain_account" {
41+
email = "admin@example.com"
42+
first_name = "Jane"
43+
last_name = "Smith"
44+
password = "securepassword"
45+
username = "jsmith"
46+
account_type = 2 # Domain admin
47+
role_id = "5678efgh"
48+
domain_id = "custom-domain-id"
49+
account = "custom-account-name"
2450
}
2551
```
2652

@@ -35,8 +61,8 @@ The following arguments are supported:
3561
* `username` - (Required) The username of the account.
3662
* `account_type` - (Required) The account type. Possible values are `0` for regular user, `1` for admin, and `2` for domain admin.
3763
* `role_id` - (Required) The ID of the role associated with the account.
64+
* `domain_id` - (Required) The ID of the domain where the account will be created. Use the `cloudstack_domain` data source to get the root domain ID.
3865
* `account` - (Optional) The account name. If not specified, the username will be used as the account name.
39-
* `domainid` - (Optional) Creates the user under the specified domain
4066

4167
## Attributes Reference
4268

@@ -49,5 +75,5 @@ The following attributes are exported:
4975
Accounts can be imported; use `<ACCOUNTID>` as the import ID. For example:
5076

5177
```shell
52-
$ terraform import cloudstack_account.example <ACCOUNTID>
78+
terraform import cloudstack_account.example <ACCOUNTID>
5379
```

0 commit comments

Comments
 (0)