Skip to content

Commit 2ef42e6

Browse files
committed
feat: add reassign_owned_to parameter to role ressource
1 parent 450ce85 commit 2ef42e6

File tree

3 files changed

+64
-3
lines changed

3 files changed

+64
-3
lines changed

postgresql/resource_postgresql_role.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const (
3232
roleReplicationAttr = "replication"
3333
roleSkipDropRoleAttr = "skip_drop_role"
3434
roleSkipReassignOwnedAttr = "skip_reassign_owned"
35+
roleReassignOwnedToAttr = "reassign_owned_to"
3536
roleSuperuserAttr = "superuser"
3637
roleValidUntilAttr = "valid_until"
3738
roleRolesAttr = "roles"
@@ -182,6 +183,11 @@ func resourcePostgreSQLRole() *schema.Resource {
182183
Default: false,
183184
Description: "Skip actually running the REASSIGN OWNED command when removing a role from PostgreSQL",
184185
},
186+
roleReassignOwnedToAttr: {
187+
Type: schema.TypeString,
188+
Optional: true,
189+
Description: "Role to reassign owned objects to when removing a role from PostgreSQL. If not specified, defaults to the current user",
190+
},
185191
roleStatementTimeoutAttr: {
186192
Type: schema.TypeInt,
187193
Optional: true,
@@ -394,9 +400,13 @@ func resourcePostgreSQLRoleDelete(db *DBConnection, d *schema.ResourceData) erro
394400

395401
if !d.Get(roleSkipReassignOwnedAttr).(bool) {
396402
if err := withRolesGranted(txn, []string{roleName}, func() error {
397-
currentUser := db.client.config.getDatabaseUsername()
398-
if _, err := txn.Exec(fmt.Sprintf("REASSIGN OWNED BY %s TO %s", pq.QuoteIdentifier(roleName), pq.QuoteIdentifier(currentUser))); err != nil {
399-
return fmt.Errorf("could not reassign owned by role %s to %s: %w", roleName, currentUser, err)
403+
// Use the specified reassign_owned_to user, or fall back to current user
404+
reassignTo := d.Get(roleReassignOwnedToAttr).(string)
405+
if reassignTo == "" {
406+
reassignTo = db.client.config.getDatabaseUsername()
407+
}
408+
if _, err := txn.Exec(fmt.Sprintf("REASSIGN OWNED BY %s TO %s", pq.QuoteIdentifier(roleName), pq.QuoteIdentifier(reassignTo))); err != nil {
409+
return fmt.Errorf("could not reassign owned by role %s to %s: %w", roleName, reassignTo, err)
400410
}
401411

402412
if _, err := txn.Exec(fmt.Sprintf("DROP OWNED BY %s", pq.QuoteIdentifier(roleName))); err != nil {
@@ -509,6 +519,7 @@ func resourcePostgreSQLRoleReadImpl(db *DBConnection, d *schema.ResourceData) er
509519
d.Set(roleLoginAttr, roleCanLogin)
510520
d.Set(roleSkipDropRoleAttr, d.Get(roleSkipDropRoleAttr).(bool))
511521
d.Set(roleSkipReassignOwnedAttr, d.Get(roleSkipReassignOwnedAttr).(bool))
522+
d.Set(roleReassignOwnedToAttr, d.Get(roleReassignOwnedToAttr).(string))
512523
d.Set(roleSuperuserAttr, roleSuperuser)
513524
d.Set(roleValidUntilAttr, roleValidUntil)
514525
d.Set(roleReplicationAttr, roleReplication)

postgresql/resource_postgresql_role_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ func TestAccPostgresqlRole_Basic(t *testing.T) {
4545
resource.TestCheckResourceAttr("postgresql_role.role_with_defaults", "valid_until", "infinity"),
4646
resource.TestCheckResourceAttr("postgresql_role.role_with_defaults", "skip_drop_role", "false"),
4747
resource.TestCheckResourceAttr("postgresql_role.role_with_defaults", "skip_reassign_owned", "false"),
48+
resource.TestCheckResourceAttr("postgresql_role.role_with_defaults", "reassign_owned_to", ""),
4849
resource.TestCheckResourceAttr("postgresql_role.role_with_defaults", "statement_timeout", "0"),
4950
resource.TestCheckResourceAttr("postgresql_role.role_with_defaults", "idle_in_transaction_session_timeout", "0"),
5051
resource.TestCheckResourceAttr("postgresql_role.role_with_defaults", "assume_role", ""),
@@ -238,6 +239,43 @@ resource "postgresql_role" "test_role" {
238239
})
239240
}
240241

242+
// Test reassign_owned_to parameter
243+
func TestAccPostgresqlRole_ReassignOwnedTo(t *testing.T) {
244+
// Get the admin user (usually postgres) who will receive the reassigned objects
245+
admin := os.Getenv("PGUSER")
246+
if admin == "" {
247+
admin = "postgres"
248+
}
249+
250+
config := fmt.Sprintf(`
251+
resource "postgresql_role" "temp_role" {
252+
name = "temp_role"
253+
login = true
254+
password = "temppass"
255+
reassign_owned_to = "%s"
256+
}
257+
`, admin)
258+
259+
resource.Test(t, resource.TestCase{
260+
PreCheck: func() {
261+
testAccPreCheck(t)
262+
testCheckCompatibleVersion(t, featurePrivileges)
263+
},
264+
Providers: testAccProviders,
265+
CheckDestroy: testAccCheckPostgresqlRoleDestroy,
266+
Steps: []resource.TestStep{
267+
{
268+
Config: config,
269+
Check: resource.ComposeTestCheckFunc(
270+
testAccCheckPostgresqlRoleExists("temp_role", nil, nil),
271+
resource.TestCheckResourceAttr("postgresql_role.temp_role", "name", "temp_role"),
272+
resource.TestCheckResourceAttr("postgresql_role.temp_role", "reassign_owned_to", admin),
273+
),
274+
},
275+
},
276+
})
277+
}
278+
241279
func testAccCheckPostgresqlRoleDestroy(s *terraform.State) error {
242280
client := testAccProvider.Meta().(*Client)
243281

website/docs/r/postgresql_role.html.markdown

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ resource "postgresql_role" "secure_role" {
5252
password_wo = "secure_password_123"
5353
password_wo_version = "1"
5454
}
55+
56+
# Example with reassign_owned_to
57+
resource "postgresql_role" "temp_role" {
58+
name = "temp_role"
59+
login = true
60+
password = "temppass"
61+
reassign_owned_to = "admin_role" # Objects will be reassigned to admin_role when this role is dropped
62+
}
5563
```
5664

5765
## Write-Only Password Management
@@ -166,6 +174,10 @@ resource "postgresql_role" "app_user" {
166174
an implicit
167175
[`DROP OWNED`](https://www.postgresql.org/docs/current/static/sql-drop-owned.html)).
168176

177+
* `reassign_owned_to` - (Optional) Specifies the role to which objects owned by the role being
178+
dropped should be reassigned. If not specified, defaults to the current database user
179+
(the user configured in the provider). This is only used when `skip_reassign_owned` is `false`.
180+
169181
* `statement_timeout` - (Optional) Defines [`statement_timeout`](https://www.postgresql.org/docs/current/runtime-config-client.html#RUNTIME-CONFIG-CLIENT-STATEMENT) setting for this role which allows to abort any statement that takes more than the specified amount of time.
170182

171183
* `assume_role` - (Optional) Defines the role to switch to at login via [`SET ROLE`](https://www.postgresql.org/docs/current/sql-set-role.html).

0 commit comments

Comments
 (0)