Skip to content

Commit ab01135

Browse files
author
Paul Ezvan
authored
feat(rdb): add scaleway_rdb_user_resource_beta (#520)
1 parent f047481 commit ab01135

File tree

7 files changed

+356
-8
lines changed

7 files changed

+356
-8
lines changed

scaleway/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ func Provider() terraform.ResourceProvider {
215215
"scaleway_lb_frontend_beta": resourceScalewayLbFrontendBeta(),
216216
"scaleway_registry_namespace_beta": resourceScalewayRegistryNamespaceBeta(),
217217
"scaleway_rdb_instance_beta": resourceScalewayRdbInstanceBeta(),
218+
"scaleway_rdb_user_beta": resourceScalewayRdbUserBeta(),
218219
"scaleway_object_bucket": resourceScalewayObjectBucket(),
219220
"scaleway_user_data": resourceScalewayUserData(),
220221
"scaleway_server": resourceScalewayServer(),

scaleway/resource_rdb_instance_beta.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,14 @@ func resourceScalewayRdbInstanceBeta() *schema.Resource {
5151
},
5252
"user_name": {
5353
Type: schema.TypeString,
54-
Required: true,
5554
ForceNew: true,
55+
Optional: true,
5656
Description: "Identifier for the first user of the database instance",
5757
},
5858
"password": {
5959
Type: schema.TypeString,
60-
Required: true,
6160
Sensitive: true,
61+
Optional: true,
6262
Description: "Password for the first user of the database instance",
6363
},
6464
"tags": {

scaleway/resource_rdb_user_beta.go

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
package scaleway
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
8+
"github.com/scaleway/scaleway-sdk-go/api/rdb/v1"
9+
"github.com/scaleway/scaleway-sdk-go/scw"
10+
)
11+
12+
func resourceScalewayRdbUserBeta() *schema.Resource {
13+
return &schema.Resource{
14+
Create: resourceScalewayRdbUserBetaCreate,
15+
Read: resourceScalewayRdbUserBetaRead,
16+
Update: resourceScalewayRdbUserBetaUpdate,
17+
Delete: resourceScalewayRdbUserBetaDelete,
18+
Importer: &schema.ResourceImporter{
19+
State: schema.ImportStatePassthrough,
20+
},
21+
SchemaVersion: 0,
22+
Schema: map[string]*schema.Schema{
23+
"instance_id": {
24+
Type: schema.TypeString,
25+
Required: true,
26+
ForceNew: true,
27+
ValidateFunc: validationUUIDorUUIDWithLocality(),
28+
Description: "Instance on which the user is created",
29+
},
30+
"name": {
31+
Type: schema.TypeString,
32+
Description: "Database user name",
33+
Required: true,
34+
ForceNew: true,
35+
},
36+
"password": {
37+
Type: schema.TypeString,
38+
Required: true,
39+
Sensitive: true,
40+
Description: "Database user password",
41+
},
42+
"is_admin": {
43+
Type: schema.TypeBool,
44+
Optional: true,
45+
Description: "Grant admin permissions to database user",
46+
},
47+
// Common
48+
"region": regionSchema(),
49+
},
50+
}
51+
}
52+
53+
func resourceScalewayRdbUserBetaCreate(d *schema.ResourceData, m interface{}) error {
54+
rdbAPI, region, err := rdbAPIWithRegion(d, m)
55+
if err != nil {
56+
return err
57+
}
58+
instanceID := d.Get("instance_id").(string)
59+
createReq := &rdb.CreateUserRequest{
60+
Region: region,
61+
InstanceID: expandID(instanceID),
62+
Name: d.Get("name").(string),
63+
Password: d.Get("password").(string),
64+
IsAdmin: d.Get("is_admin").(bool),
65+
}
66+
67+
res, err := rdbAPI.CreateUser(createReq)
68+
if err != nil {
69+
return err
70+
}
71+
72+
d.SetId(resourceScalewayRdbUserBetaID(region, expandID(instanceID), res.Name))
73+
74+
return resourceScalewayRdbUserBetaRead(d, m)
75+
}
76+
77+
func resourceScalewayRdbUserBetaRead(d *schema.ResourceData, m interface{}) error {
78+
rdbAPI, region, err := rdbAPIWithRegion(d, m)
79+
if err != nil {
80+
return err
81+
}
82+
83+
instanceID, userName, err := resourceScalewayRdbUserBetaParseID(d.Id())
84+
85+
if err != nil {
86+
return err
87+
}
88+
89+
res, err := rdbAPI.ListUsers(&rdb.ListUsersRequest{
90+
Region: region,
91+
InstanceID: instanceID,
92+
Name: &userName,
93+
})
94+
95+
if err != nil {
96+
if is404Error(err) {
97+
d.SetId("")
98+
return nil
99+
}
100+
return err
101+
}
102+
103+
var user = res.Users[0]
104+
d.Set("instance_id", newRegionalID(region, instanceID))
105+
d.Set("name", user.Name)
106+
d.Set("is_admin", user.IsAdmin)
107+
108+
d.SetId(resourceScalewayRdbUserBetaID(region, instanceID, user.Name))
109+
110+
return nil
111+
}
112+
113+
func resourceScalewayRdbUserBetaUpdate(d *schema.ResourceData, m interface{}) error {
114+
rdbAPI, region, err := rdbAPIWithRegion(d, m)
115+
if err != nil {
116+
return err
117+
}
118+
119+
instanceID, userName, err := resourceScalewayRdbUserBetaParseID(d.Id())
120+
121+
if err != nil {
122+
return err
123+
}
124+
125+
req := &rdb.UpdateUserRequest{
126+
Region: region,
127+
InstanceID: instanceID,
128+
Name: userName,
129+
}
130+
131+
if d.HasChange("password") {
132+
req.Password = scw.StringPtr(d.Get("password").(string))
133+
}
134+
if d.HasChange("is_admin") {
135+
req.IsAdmin = scw.BoolPtr(d.Get("is_admin").(bool))
136+
}
137+
138+
_, err = rdbAPI.UpdateUser(req)
139+
if err != nil {
140+
return err
141+
}
142+
143+
return resourceScalewayRdbUserBetaRead(d, m)
144+
}
145+
146+
func resourceScalewayRdbUserBetaDelete(d *schema.ResourceData, m interface{}) error {
147+
rdbAPI, region, err := rdbAPIWithRegion(d, m)
148+
if err != nil {
149+
return err
150+
}
151+
152+
instanceID, userName, err := resourceScalewayRdbUserBetaParseID(d.Id())
153+
154+
if err != nil {
155+
return err
156+
}
157+
158+
err = rdbAPI.DeleteUser(&rdb.DeleteUserRequest{
159+
Region: region,
160+
InstanceID: instanceID,
161+
Name: userName,
162+
})
163+
164+
if err != nil && !is404Error(err) {
165+
return err
166+
}
167+
168+
return nil
169+
}
170+
171+
// Build the resource identifier
172+
// The resource identifier format is "Region/InstanceId/UserName"
173+
func resourceScalewayRdbUserBetaID(region scw.Region, instanceID string, userName string) (resourceID string) {
174+
return fmt.Sprintf("%s/%s/%s", region, instanceID, userName)
175+
}
176+
177+
// Extract instance ID and username from the resource identifier.
178+
// The resource identifier format is "Region/InstanceId/UserName"
179+
func resourceScalewayRdbUserBetaParseID(resourceId string) (instanceID string, userName string, err error) {
180+
idParts := strings.Split(resourceId, "/")
181+
if len(idParts) != 3 {
182+
return "", "", fmt.Errorf("can't parse user resource id: %s", resourceId)
183+
}
184+
return idParts[1], idParts[2], nil
185+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package scaleway
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
8+
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
9+
"github.com/hashicorp/terraform-plugin-sdk/terraform"
10+
"github.com/scaleway/scaleway-sdk-go/api/rdb/v1"
11+
)
12+
13+
func init() {
14+
resource.AddTestSweepers("scaleway_rdb_user_beta", &resource.Sweeper{
15+
Name: "scaleway_rdb_user_beta",
16+
F: testSweepRDBInstance,
17+
})
18+
}
19+
20+
func TestAccScalewayRdbUserBeta(t *testing.T) {
21+
resourceName := "scaleway_rdb_user_beta.db_user"
22+
rName := acctest.RandomWithPrefix("tf-acc-test")
23+
resource.ParallelTest(t, resource.TestCase{
24+
PreCheck: func() { testAccPreCheck(t) },
25+
Providers: testAccProviders,
26+
CheckDestroy: testAccCheckScalewayRdbInstanceBetaDestroy,
27+
Steps: []resource.TestStep{
28+
{
29+
Config: testAccScalewayRdbUserConfig(rName, "titi", "true"),
30+
Check: resource.ComposeTestCheckFunc(
31+
testAccCheckRdbUserBetaExists("scaleway_rdb_instance_beta.main", resourceName),
32+
resource.TestCheckResourceAttr(resourceName, "name", "titi"),
33+
resource.TestCheckResourceAttr(resourceName, "is_admin", "true"),
34+
),
35+
},
36+
{
37+
Config: testAccScalewayRdbUserConfig(rName, "tata", "false"),
38+
Check: resource.ComposeTestCheckFunc(
39+
testAccCheckRdbUserBetaExists("scaleway_rdb_instance_beta.main", resourceName),
40+
resource.TestCheckResourceAttr(resourceName, "name", "tata"),
41+
resource.TestCheckResourceAttr(resourceName, "is_admin", "false"),
42+
),
43+
},
44+
},
45+
})
46+
47+
}
48+
49+
func testAccCheckRdbUserBetaExists(instance string, user string) resource.TestCheckFunc {
50+
return func(s *terraform.State) error {
51+
instanceResource, ok := s.RootModule().Resources[instance]
52+
if !ok {
53+
return fmt.Errorf("resource not found: %s", instance)
54+
}
55+
56+
userResource, ok := s.RootModule().Resources[user]
57+
if !ok {
58+
return fmt.Errorf("resource not found: %s", user)
59+
}
60+
61+
rdbAPI, region, _, err := rdbAPIWithRegionAndID(testAccProvider.Meta(), instanceResource.Primary.ID)
62+
if err != nil {
63+
return err
64+
}
65+
66+
instanceId, userName, err := resourceScalewayRdbUserBetaParseID(userResource.Primary.ID)
67+
if err != nil {
68+
return err
69+
}
70+
71+
users, err := rdbAPI.ListUsers(&rdb.ListUsersRequest{
72+
InstanceID: instanceId,
73+
Region: region,
74+
Name: &userName,
75+
})
76+
77+
if len(users.Users) != 1 {
78+
return fmt.Errorf("No user found")
79+
}
80+
81+
if err != nil {
82+
return err
83+
}
84+
85+
return nil
86+
}
87+
}
88+
89+
func testAccScalewayRdbUserConfigBase(rName string) string {
90+
return fmt.Sprintf(`
91+
resource scaleway_rdb_instance_beta main {
92+
name = %[1]q
93+
node_type = "db-dev-s"
94+
engine = "PostgreSQL-12"
95+
is_ha_cluster = false
96+
tags = [ "terraform-test", "scaleway_rdb_user_beta", "minimal" ]
97+
}`, rName)
98+
}
99+
100+
func testAccScalewayRdbUserConfig(rName, userName, isAdmin string) string {
101+
return testAccScalewayRdbUserConfigBase(rName) + fmt.Sprintf(`
102+
resource scaleway_rdb_user_beta db_user {
103+
instance_id = scaleway_rdb_instance_beta.main.id
104+
name = %[1]q
105+
password = "R34lP4sSw#Rd"
106+
is_admin = %[2]q
107+
}`, userName, isAdmin)
108+
}

website/docs/r/rdb_instance_beta.html.markdown

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ description: |-
1212
Creates and manages Scaleway Database Instances. For more information, see [the documentation](https://developers.scaleway.com/en/products/rdb/api).
1313

1414
## Examples
15-
15+
1616
### Basic
1717

1818
```hcl
@@ -39,13 +39,11 @@ The following arguments are supported:
3939

4040
~> **Important:** Updates to `engine` will recreate the Database Instance.
4141

42-
- `user_name` - (Required) Identifier for the first user of the database instance.
42+
- `user_name` - (Optional) Identifier for the first user of the database instance.
4343

4444
~> **Important:** Updates to `user_name` will recreate the Database Instance.
4545

46-
- `password` - (Required) Password for the first user of the database instance.
47-
48-
~> **Important:** Updates to `password` will recreate the Database Instance.
46+
- `password` - (Optional) Password for the first user of the database instance.
4947

5048
- `is_ha_cluster` - (Optional) Enable or disable high availability for the database instance.
5149

@@ -69,7 +67,7 @@ In addition to all arguments above, the following attributes are exported:
6967
- `id` - The ID of the Database Instance.
7068
- `endpoint_ip` - The IP of the Database Instance.
7169
- `endpoint_port` - The port of the Database Instance.
72-
- `read_replicas` - List of read replicas of the database instance.
70+
- `read_replicas` - List of read replicas of the database instance.
7371
- `ip` - IP of the replica.
7472
- `port` - Port of the replica.
7573
- `name` - Name of the replica.

0 commit comments

Comments
 (0)