Skip to content

Commit fa723cf

Browse files
timothegenzmerTimothe Genzmer
andauthored
Fix concurrency issue when granting privileges on databases (#224)
Co-authored-by: Timothe Genzmer <[email protected]>
1 parent d03ab42 commit fa723cf

File tree

3 files changed

+29
-2
lines changed

3 files changed

+29
-2
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Building The Provider
2020
Clone repository to: `$GOPATH/src/github.com/cyrilgdn/terraform-provider-postgresql`
2121

2222
```sh
23-
$ mkdir -p $GOPATH/src/github.com/terraform-providers; cd $GOPATH/src/github.com/terraform-providers
23+
$ mkdir -p $GOPATH/src/github.com/cyrilgdn; cd $GOPATH/src/github.com/cyrilgdn
2424
$ git clone [email protected]:cyrilgdn/terraform-provider-postgresql
2525
```
2626

postgresql/helpers.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,19 @@ func pgLockRole(txn *sql.Tx, role string) error {
477477
return nil
478478
}
479479

480+
// Lock a database and all his members to avoid concurrent updates on some resources
481+
func pgLockDatabase(txn *sql.Tx, database string) error {
482+
// Disable statement timeout for this connection otherwise the lock could fail
483+
if _, err := txn.Exec("SET statement_timeout = 0"); err != nil {
484+
return fmt.Errorf("could not disable statement_timeout: %w", err)
485+
}
486+
if _, err := txn.Exec("SELECT pg_advisory_xact_lock(oid::bigint) FROM pg_database WHERE datname = $1", database); err != nil {
487+
return fmt.Errorf("could not get advisory lock for database %s: %w", database, err)
488+
}
489+
490+
return nil
491+
}
492+
480493
func arrayDifference(a, b []interface{}) (diff []interface{}) {
481494
m := make(map[interface{}]bool)
482495

postgresql/resource_postgresql_grant.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,12 @@ func resourcePostgreSQLGrantCreate(db *DBConnection, d *schema.ResourceData) err
150150
return err
151151
}
152152

153+
if objectType == "database" {
154+
if err := pgLockDatabase(txn, database); err != nil {
155+
return err
156+
}
157+
}
158+
153159
owners, err := getRolesToGrant(txn, d)
154160
if err != nil {
155161
return err
@@ -189,7 +195,8 @@ func resourcePostgreSQLGrantDelete(db *DBConnection, d *schema.ResourceData) err
189195
return fmt.Errorf("feature is not supported: %v", err)
190196
}
191197

192-
txn, err := startTransaction(db.client, d.Get("database").(string))
198+
database := d.Get("database").(string)
199+
txn, err := startTransaction(db.client, database)
193200
if err != nil {
194201
return err
195202
}
@@ -200,6 +207,13 @@ func resourcePostgreSQLGrantDelete(db *DBConnection, d *schema.ResourceData) err
200207
return err
201208
}
202209

210+
objectType := d.Get("object_type").(string)
211+
if objectType == "database" {
212+
if err := pgLockDatabase(txn, database); err != nil {
213+
return err
214+
}
215+
}
216+
203217
owners, err := getRolesToGrant(txn, d)
204218
if err != nil {
205219
return err

0 commit comments

Comments
 (0)