Skip to content

Commit d53937d

Browse files
committed
rdb: surface effective_permission and permission_status for privileges; warn on drift; docs updated
1 parent f89b981 commit d53937d

File tree

3 files changed

+140
-5
lines changed

3 files changed

+140
-5
lines changed

docs/resources/rdb_privilege.md

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ The following arguments are supported:
5151

5252
- `database_name` - (Required) Name of the database (e.g. `my-db-name`).
5353

54-
- `permission` - (Required) Permission to set. Valid values are `readonly`, `readwrite`, `all`, `custom` and `none`.
54+
- `permission` - (Required) Desired permission level. Valid values are `readonly`, `readwrite`, `all`, `custom` and `none`.
5555

5656
- `region` - (Defaults to [provider](../index.md#region) `region`) The [region](../guides/regions_and_zones.md#regions) in which the resource exists.
5757

@@ -61,6 +61,49 @@ In addition to all arguments above, the following attributes are exported:
6161

6262
- `id` - The ID of the user privileges, which is of the form `{region}/{instance_id}/{database_name}/{user_name}`, e.g. `fr-par/11111111-1111-1111-1111-111111111111/database_name/foo`
6363

64+
- `effective_permission` - The actual permission currently set in Scaleway. May differ from `permission` after database schema changes (new tables, views, or sequences created).
65+
66+
- `permission_status` - Permission synchronization status. Possible values:
67+
- `synced`: The effective permission matches the desired permission
68+
- `drifted`: The effective permission differs from the desired permission (requires `terraform apply` to resync)
69+
70+
## Permission Drift Management
71+
72+
### Understanding Permission Drift
73+
74+
When you configure a privilege (e.g., `readwrite`), Scaleway applies it to **database objects that exist at that moment**. If new tables, views, or sequences are created later, they won't automatically inherit these permissions. In that case, the API may return `custom`.
75+
76+
**Example:**
77+
78+
```terraform
79+
resource "scaleway_rdb_privilege" "app" {
80+
instance_id = scaleway_rdb_instance.main.id
81+
user_name = "app_user"
82+
database_name = "mydb"
83+
permission = "readwrite"
84+
85+
# Later, after new objects are created externally:
86+
# effective_permission = "custom" (computed)
87+
# permission_status = "drifted" (computed)
88+
}
89+
```
90+
91+
### Handling Permission Drift
92+
93+
Run `terraform apply` to reapply the configured permission to all objects (existing and new):
94+
95+
```bash
96+
terraform apply
97+
```
98+
99+
The plan will typically show:
100+
101+
```diff
102+
~ resource "scaleway_rdb_privilege" "app" {
103+
~ permission = "custom" -> "readwrite"
104+
}
105+
```
106+
64107
## Import
65108

66109
The user privileges can be imported using the `{region}/{instance_id}/{database_name}/{user_name}`, e.g.

internal/services/rdb/privilege.go

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"strings"
77

8+
"github.com/hashicorp/go-cty/cty"
89
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
910
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
1011
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -57,10 +58,20 @@ func ResourcePrivilege() *schema.Resource {
5758
},
5859
"permission": {
5960
Type: schema.TypeString,
60-
Description: "Privilege",
61+
Description: "Desired permission (readonly, readwrite, all, custom, none)",
6162
ValidateDiagFunc: verify.ValidateEnum[rdb.Permission](),
6263
Required: true,
6364
},
65+
"effective_permission": {
66+
Type: schema.TypeString,
67+
Description: "Actual permission currently set in Scaleway. May differ from 'permission' after database schema changes",
68+
Computed: true,
69+
},
70+
"permission_status": {
71+
Type: schema.TypeString,
72+
Description: "Permission synchronization status: 'synced' if effective matches desired, 'drifted' if they differ",
73+
Computed: true,
74+
},
6475
// Common
6576
"region": regional.Schema(),
6677
},
@@ -120,6 +131,10 @@ func ResourceRdbPrivilegeCreate(ctx context.Context, d *schema.ResourceData, m a
120131

121132
d.SetId(ResourceRdbUserPrivilegeID(region, locality.ExpandID(instanceID), databaseName, userName))
122133

134+
configuredPermission := d.Get("permission").(string)
135+
_ = d.Set("effective_permission", configuredPermission)
136+
_ = d.Set("permission_status", "synced")
137+
123138
return ResourceRdbPrivilegeRead(ctx, d, m)
124139
}
125140

@@ -184,13 +199,47 @@ func ResourceRdbPrivilegeRead(ctx context.Context, d *schema.ResourceData, m any
184199
}
185200

186201
privilege := res.Privileges[0]
202+
effectivePermission := string(privilege.Permission)
203+
configuredPermission := d.Get("permission").(string)
204+
187205
_ = d.Set("database_name", privilege.DatabaseName)
188206
_ = d.Set("user_name", privilege.UserName)
189-
_ = d.Set("permission", privilege.Permission)
190207
_ = d.Set("instance_id", regional.NewIDString(region, instanceID))
191208
_ = d.Set("region", region)
209+
_ = d.Set("permission", privilege.Permission)
210+
_ = d.Set("effective_permission", effectivePermission)
211+
212+
var diags diag.Diagnostics
213+
214+
if effectivePermission != configuredPermission {
215+
_ = d.Set("permission_status", "drifted")
216+
217+
diags = append(diags, diag.Diagnostic{
218+
Severity: diag.Warning,
219+
Summary: "Database privilege drift detected",
220+
Detail: fmt.Sprintf(
221+
"The privilege for user '%s' on database '%s' has drifted:\n"+
222+
" • Configured permission: '%s'\n"+
223+
" • Effective permission: '%s'\n\n"+
224+
"This usually happens after database schema changes (new tables, views, or sequences created).\n"+
225+
"The configured permission was applied to objects existing at the time, but new objects created "+
226+
"afterward don't automatically inherit these permissions.\n\n"+
227+
"To fix this:\n"+
228+
" 1. Run 'terraform apply' to reapply the configured permission to all objects\n"+
229+
" 2. Or use PostgreSQL default privileges to automatically grant permissions to future objects\n"+
230+
" 3. Or set 'permission = \"%s\"' if you want to keep the current state\n\n"+
231+
"See: https://www.scaleway.com/en/docs/managed-databases/postgresql-and-mysql/how-to/manage-users/",
232+
userName, databaseName,
233+
configuredPermission, effectivePermission,
234+
effectivePermission,
235+
),
236+
AttributePath: cty.GetAttrPath("permission"),
237+
})
238+
} else {
239+
_ = d.Set("permission_status", "synced")
240+
}
192241

193-
return nil
242+
return diags
194243
}
195244

196245
func ResourceRdbPrivilegeUpdate(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics {

templates/resources/rdb_privilege.md.tmpl

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ The following arguments are supported:
5252

5353
- `database_name` - (Required) Name of the database (e.g. `my-db-name`).
5454

55-
- `permission` - (Required) Permission to set. Valid values are `readonly`, `readwrite`, `all`, `custom` and `none`.
55+
- `permission` - (Required) Desired permission level. Valid values are `readonly`, `readwrite`, `all`, `custom` and `none`.
5656

5757
- `region` - (Defaults to [provider](../index.md#region) `region`) The [region](../guides/regions_and_zones.md#regions) in which the resource exists.
5858

@@ -62,6 +62,49 @@ In addition to all arguments above, the following attributes are exported:
6262

6363
- `id` - The ID of the user privileges, which is of the form `{region}/{instance_id}/{database_name}/{user_name}`, e.g. `fr-par/11111111-1111-1111-1111-111111111111/database_name/foo`
6464

65+
- `effective_permission` - The actual permission currently set in Scaleway. May differ from `permission` after database schema changes (new tables, views, or sequences created).
66+
67+
- `permission_status` - Permission synchronization status. Possible values:
68+
- `synced`: The effective permission matches the desired permission
69+
- `drifted`: The effective permission differs from the desired permission (requires `terraform apply` to resync)
70+
71+
## Permission Drift Management
72+
73+
### Understanding Permission Drift
74+
75+
When you configure a privilege (e.g., `readwrite`), Scaleway applies it to **database objects that exist at that moment**. If new tables, views, or sequences are created later, they won't automatically inherit these permissions. In that case, the API may return `custom`.
76+
77+
**Example:**
78+
79+
```terraform
80+
resource "scaleway_rdb_privilege" "app" {
81+
instance_id = scaleway_rdb_instance.main.id
82+
user_name = "app_user"
83+
database_name = "mydb"
84+
permission = "readwrite"
85+
86+
# Later, after new objects are created externally:
87+
# effective_permission = "custom" (computed)
88+
# permission_status = "drifted" (computed)
89+
}
90+
```
91+
92+
### Handling Permission Drift
93+
94+
Run `terraform apply` to reapply the configured permission to all objects (existing and new):
95+
96+
```bash
97+
terraform apply
98+
```
99+
100+
The plan will typically show:
101+
102+
```diff
103+
~ resource "scaleway_rdb_privilege" "app" {
104+
~ permission = "custom" -> "readwrite"
105+
}
106+
```
107+
65108
## Import
66109

67110
The user privileges can be imported using the `{region}/{instance_id}/{database_name}/{user_name}`, e.g.

0 commit comments

Comments
 (0)