Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add log_statement to role resource #392

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions postgresql/resource_postgresql_role.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const (
roleRolesAttr = "roles"
roleSearchPathAttr = "search_path"
roleStatementTimeoutAttr = "statement_timeout"
roleLogStatementAttr = "log_statement"
roleAssumeRoleAttr = "assume_role"

// Deprecated options
Expand Down Expand Up @@ -168,6 +169,13 @@ func resourcePostgreSQLRole() *schema.Resource {
Description: "Abort any statement that takes more than the specified number of milliseconds",
ValidateFunc: validation.IntAtLeast(0),
},
roleLogStatementAttr: {
Type: schema.TypeString,
Optional: true,
Default: "none",
Description: "Sets the type of statements logged by this role",
ValidateFunc: validation.StringInSlice([]string{"none", "ddl", "mod", "all"}, false),
},
roleAssumeRoleAttr: {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -307,6 +315,10 @@ func resourcePostgreSQLRoleCreate(db *DBConnection, d *schema.ResourceData) erro
return err
}

if err = setLogStatement(txn, d); err != nil {
return err
}

if err = setAssumeRole(txn, d); err != nil {
return err
}
Expand Down Expand Up @@ -472,6 +484,13 @@ func resourcePostgreSQLRoleReadImpl(db *DBConnection, d *schema.ResourceData) er

d.Set(roleIdleInTransactionSessionTimeoutAttr, idleInTransactionSessionTimeout)

logStatement, err := readLogStatement(roleConfig)
if err != nil {
return err
}

d.Set(roleLogStatementAttr, logStatement)

d.SetId(roleName)

password, err := readRolePassword(db, d, roleCanLogin)
Expand Down Expand Up @@ -533,6 +552,19 @@ func readStatementTimeout(roleConfig pq.ByteaArray) (int, error) {
return 0, nil
}

// readLogStatement searches for a log_statement entry in the rolconfig array.
// In case no such value is present, it returns empty string.
func readLogStatement(roleConfig pq.ByteaArray) (string, error) {
for _, v := range roleConfig {
config := string(v)
if strings.HasPrefix(config, roleLogStatementAttr) {
var result = strings.Split(strings.TrimPrefix(config, roleLogStatementAttr+"="), ", ")
return result[0], nil
}
}
return "", nil
}

// readAssumeRole searches for a role entry in the rolconfig array.
// In case no such value is present, it returns empty string.
func readAssumeRole(roleConfig pq.ByteaArray) string {
Expand Down Expand Up @@ -685,6 +717,10 @@ func resourcePostgreSQLRoleUpdate(db *DBConnection, d *schema.ResourceData) erro
return err
}

if err = setLogStatement(txn, d); err != nil {
return err
}

if err = setAssumeRole(txn, d); err != nil {
return err
}
Expand Down Expand Up @@ -1038,6 +1074,31 @@ func setIdleInTransactionSessionTimeout(txn *sql.Tx, d *schema.ResourceData) err
return nil
}

func setLogStatement(txn *sql.Tx, d *schema.ResourceData) error {
if !d.HasChange(roleLogStatementAttr) {
return nil
}

roleName := d.Get(roleNameAttr).(string)
logStatement := d.Get(roleLogStatementAttr).(string)
if logStatement != "" {
sql := fmt.Sprintf(
"ALTER ROLE %s SET log_statement TO %s", pq.QuoteIdentifier(roleName), logStatement,
)
if _, err := txn.Exec(sql); err != nil {
return fmt.Errorf("could not set log_statement %s for %s: %w", logStatement, roleName, err)
}
} else {
sql := fmt.Sprintf(
"ALTER ROLE %s RESET log_statement", pq.QuoteIdentifier(roleName),
)
if _, err := txn.Exec(sql); err != nil {
return fmt.Errorf("could not reset log_statement for %s: %w", roleName, err)
}
}
return nil
}

func setAssumeRole(txn *sql.Tx, d *schema.ResourceData) error {
if !d.HasChange(roleAssumeRoleAttr) {
return nil
Expand Down
6 changes: 6 additions & 0 deletions postgresql/resource_postgresql_role_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func TestAccPostgresqlRole_Basic(t *testing.T) {
resource.TestCheckResourceAttr("postgresql_role.role_with_defaults", "skip_reassign_owned", "false"),
resource.TestCheckResourceAttr("postgresql_role.role_with_defaults", "statement_timeout", "0"),
resource.TestCheckResourceAttr("postgresql_role.role_with_defaults", "idle_in_transaction_session_timeout", "0"),
resource.TestCheckResourceAttr("postgresql_role.role_with_defaults", "log_statement", "none"),
resource.TestCheckResourceAttr("postgresql_role.role_with_defaults", "assume_role", ""),

resource.TestCheckResourceAttr("postgresql_role.role_with_create_database", "name", "role_with_create_database"),
Expand Down Expand Up @@ -121,6 +122,7 @@ resource "postgresql_role" "update_role" {
search_path = ["mysearchpath"]
statement_timeout = 30000
idle_in_transaction_session_timeout = 60000
log_statement = "none"
assume_role = "${postgresql_role.group_role.name}"
}
`
Expand All @@ -145,6 +147,7 @@ resource "postgresql_role" "update_role" {
resource.TestCheckResourceAttr("postgresql_role.update_role", "search_path.#", "0"),
resource.TestCheckResourceAttr("postgresql_role.update_role", "statement_timeout", "0"),
resource.TestCheckResourceAttr("postgresql_role.update_role", "idle_in_transaction_session_timeout", "0"),
resource.TestCheckResourceAttr("postgresql_role.role_with_defaults", "log_statement", "none"),
resource.TestCheckResourceAttr("postgresql_role.update_role", "assume_role", ""),
testAccCheckRoleCanLogin(t, "update_role", "toto"),
),
Expand All @@ -166,6 +169,7 @@ resource "postgresql_role" "update_role" {
resource.TestCheckResourceAttr("postgresql_role.update_role", "search_path.0", "mysearchpath"),
resource.TestCheckResourceAttr("postgresql_role.update_role", "statement_timeout", "30000"),
resource.TestCheckResourceAttr("postgresql_role.update_role", "idle_in_transaction_session_timeout", "60000"),
resource.TestCheckResourceAttr("postgresql_role.role_with_defaults", "log_statement", "none"),
resource.TestCheckResourceAttr("postgresql_role.update_role", "assume_role", "group_role"),
testAccCheckRoleCanLogin(t, "update_role2", "titi"),
),
Expand All @@ -184,6 +188,7 @@ resource "postgresql_role" "update_role" {
resource.TestCheckResourceAttr("postgresql_role.update_role", "search_path.#", "0"),
resource.TestCheckResourceAttr("postgresql_role.update_role", "statement_timeout", "0"),
resource.TestCheckResourceAttr("postgresql_role.update_role", "idle_in_transaction_session_timeout", "0"),
resource.TestCheckResourceAttr("postgresql_role.role_with_defaults", "log_statement", "none"),
resource.TestCheckResourceAttr("postgresql_role.update_role", "assume_role", ""),
testAccCheckRoleCanLogin(t, "update_role", "toto"),
),
Expand Down Expand Up @@ -426,6 +431,7 @@ resource "postgresql_role" "role_with_defaults" {
valid_until = "infinity"
statement_timeout = 0
idle_in_transaction_session_timeout = 0
log_statement = "none"
assume_role = ""
}

Expand Down
2 changes: 2 additions & 0 deletions website/docs/r/postgresql_role.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ resource "postgresql_role" "my_replication_role" {

* `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.

* `log_statement` - (Optional) Defines [`log_statement`](https://www.postgresql.org/docs/current/runtime-config-logging.html#GUC-LOG-STATEMENT) setting for this role which allows to log each statement.

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

## Import Example
Expand Down
Loading