Expand postgresql_role support to include all known options.

This commit is contained in:
Sean Chittenden 2016-12-12 01:37:00 -08:00
parent 4c6c52ee8d
commit 1a93309e50
No known key found for this signature in database
GPG Key ID: 4EBC9DC16C2E5E16
1 changed files with 253 additions and 60 deletions

View File

@ -181,10 +181,7 @@ func resourcePostgreSQLRoleCreate(d *schema.ResourceData, meta interface{}) erro
} else {
createOpts = append(createOpts, "UNENCRYPTED")
}
escapedPassword := strconv.Quote(val)
escapedPassword = strings.TrimLeft(escapedPassword, `"`)
escapedPassword = strings.TrimRight(escapedPassword, `"`)
createOpts = append(createOpts, fmt.Sprintf("%s '%s'", opt.sqlKey, escapedPassword))
createOpts = append(createOpts, fmt.Sprintf("%s '%s'", opt.sqlKey, pqQuoteLiteral(val)))
}
case opt.hclKey == roleValidUntilAttr:
switch {
@ -211,7 +208,6 @@ func resourcePostgreSQLRoleCreate(d *schema.ResourceData, meta interface{}) erro
continue
}
val := d.Get(opt.hclKey).(bool)
valStr := opt.sqlKeyDisable
if val {
valStr = opt.sqlKeyEnable
@ -245,7 +241,6 @@ func resourcePostgreSQLRoleDelete(d *schema.ResourceData, meta interface{}) erro
defer conn.Close()
roleName := d.Get(roleNameAttr).(string)
query := fmt.Sprintf("DROP ROLE %s", pq.QuoteIdentifier(roleName))
_, err = conn.Query(query)
if err != nil {
@ -265,91 +260,289 @@ func resourcePostgreSQLRoleRead(d *schema.ResourceData, meta interface{}) error
}
defer conn.Close()
roleName := d.Get(roleNameAttr).(string)
if roleName == "" {
roleName = d.Id()
}
var roleCanLogin bool
err = conn.QueryRow("SELECT rolcanlogin FROM pg_roles WHERE rolname=$1", roleName).Scan(&roleCanLogin)
roleId := d.Id()
var roleSuperuser, roleInherit, roleCreateRole, roleCreateDB, roleCanLogin, roleReplication, roleBypassRLS bool
var roleConnLimit int
var roleName, roleValidUntil string
err = conn.QueryRow("SELECT rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb, rolcanlogin, rolreplication, rolconnlimit, COALESCE(rolvaliduntil::TEXT, 'infinity'), rolbypassrls FROM pg_catalog.pg_roles WHERE rolname=$1", roleId).Scan(&roleName, &roleSuperuser, &roleInherit, &roleCreateRole, &roleCreateDB, &roleCanLogin, &roleReplication, &roleConnLimit, &roleValidUntil, &roleBypassRLS)
switch {
case err == sql.ErrNoRows:
log.Printf("[WARN] PostgreSQL database (%s) not found", d.Id())
log.Printf("[WARN] PostgreSQL role (%s) not found", roleId)
d.SetId("")
return nil
case err != nil:
return errwrap.Wrapf("Error reading role: {{err}}", err)
default:
d.Set(roleNameAttr, roleName)
d.Set(roleBypassRLSAttr, roleBypassRLS)
d.Set(roleConnLimitAttr, roleConnLimit)
d.Set(roleCreateDBAttr, roleCreateDB)
d.Set(roleCreateRoleAttr, roleCreateRole)
d.Set(roleEncryptedPassAttr, true)
d.Set(roleInheritAttr, roleInherit)
d.Set(roleLoginAttr, roleCanLogin)
d.Set("encrypted", true)
d.Set(roleReplicationAttr, roleReplication)
d.Set(roleSuperuserAttr, roleSuperuser)
d.Set(roleValidUntilAttr, roleValidUntil)
d.SetId(roleName)
}
if !roleSuperuser {
// Return early if not superuser user
return nil
}
var rolePassword string
err = conn.QueryRow("SELECT COALESCE(passwd, '') FROM pg_catalog.pg_shadow AS s WHERE s.usename = $1", roleId).Scan(&rolePassword)
switch {
case err == sql.ErrNoRows:
return fmt.Errorf("PostgreSQL role (%s) not found in shadow database: {{err}}", roleId)
case err != nil:
return errwrap.Wrapf("Error reading role: {{err}}", err)
default:
d.Set(rolePasswordAttr, rolePassword)
return nil
}
}
func resourcePostgreSQLRoleUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Client)
conn, err := client.Connect()
c := meta.(*Client)
conn, err := c.Connect()
if err != nil {
return err
}
defer conn.Close()
d.Partial(true)
roleName := d.Get(roleNameAttr).(string)
if d.HasChange(roleLoginAttr) {
loginAttr := getLoginStr(d.Get(roleLoginAttr).(bool))
query := fmt.Sprintf("ALTER ROLE %s %s", pq.QuoteIdentifier(roleName), pq.QuoteIdentifier(loginAttr))
_, err := conn.Query(query)
if err != nil {
return errwrap.Wrapf("Error updating login attribute for role: {{err}}", err)
}
d.SetPartial(roleLoginAttr)
if err := setRoleName(conn, d); err != nil {
return err
}
password := d.Get(rolePasswordAttr).(string)
if d.HasChange(rolePasswordAttr) {
encryptedCfg := getEncryptedStr(d.Get("encrypted").(bool))
query := fmt.Sprintf("ALTER ROLE %s %s PASSWORD '%s'", pq.QuoteIdentifier(roleName), encryptedCfg, password)
_, err := conn.Query(query)
if err != nil {
return errwrap.Wrapf("Error updating password attribute for role: {{err}}", err)
}
d.SetPartial(rolePasswordAttr)
if err := setRoleBypassRLS(conn, d); err != nil {
return err
}
if d.HasChange("encrypted") {
encryptedCfg := getEncryptedStr(d.Get("encrypted").(bool))
query := fmt.Sprintf("ALTER ROLE %s %s PASSWORD '%s'", pq.QuoteIdentifier(roleName), encryptedCfg, password)
_, err := conn.Query(query)
if err != nil {
return errwrap.Wrapf("Error updating encrypted attribute for role: {{err}}", err)
}
d.SetPartial("encrypted")
if err := setRoleConnLimit(conn, d); err != nil {
return err
}
if err := setRoleCreateDB(conn, d); err != nil {
return err
}
if err := setRoleCreateRole(conn, d); err != nil {
return err
}
if err := setRoleInherit(conn, d); err != nil {
return err
}
if err := setRoleLogin(conn, d); err != nil {
return err
}
if err := setRoleReplication(conn, d); err != nil {
return err
}
if err := setRoleSuperuser(conn, d); err != nil {
return err
}
if err := setRoleValidUntil(conn, d); err != nil {
return err
}
d.Partial(false)
return resourcePostgreSQLRoleRead(d, meta)
}
func getLoginStr(canLogin bool) string {
if canLogin {
return "login"
func setRoleName(conn *sql.DB, d *schema.ResourceData) error {
if !d.HasChange(roleNameAttr) {
return nil
}
return "nologin"
oraw, nraw := d.GetChange(roleNameAttr)
o := oraw.(string)
n := nraw.(string)
if n == "" {
return errors.New("Error setting role name to an empty string")
}
query := fmt.Sprintf("ALTER ROLE %s RENAME TO %s", pq.QuoteIdentifier(o), pq.QuoteIdentifier(n))
if _, err := conn.Query(query); err != nil {
return errwrap.Wrapf("Error updating role NAME: {{err}}", err)
}
d.SetId(n)
return nil
}
func getEncryptedStr(isEncrypted bool) string {
if isEncrypted {
return "encrypted"
func setRoleBypassRLS(conn *sql.DB, d *schema.ResourceData) error {
if !d.HasChange(roleBypassRLSAttr) {
return nil
}
return "unencrypted"
bypassRLS := d.Get(roleBypassRLSAttr).(bool)
tok := "NOBYPASSRLS"
if bypassRLS {
tok = "BYPASSRLS"
}
roleName := d.Get(roleNameAttr).(string)
query := fmt.Sprintf("ALTER ROLE %s WITH %s", pq.QuoteIdentifier(roleName), tok)
if _, err := conn.Query(query); err != nil {
return errwrap.Wrapf("Error updating role BYPASSRLS: {{err}}", err)
}
return nil
}
func setRoleConnLimit(conn *sql.DB, d *schema.ResourceData) error {
if !d.HasChange(roleConnLimitAttr) {
return nil
}
connLimit := d.Get(roleConnLimitAttr).(int)
roleName := d.Get(roleNameAttr).(string)
query := fmt.Sprintf("ALTER ROLE %s CONNECTION LIMIT = %d", pq.QuoteIdentifier(roleName), connLimit)
if _, err := conn.Query(query); err != nil {
return errwrap.Wrapf("Error updating role CONNECTION LIMIT: {{err}}", err)
}
return nil
}
func setRoleCreateDB(conn *sql.DB, d *schema.ResourceData) error {
if !d.HasChange(roleCreateDBAttr) {
return nil
}
createDB := d.Get(roleCreateDBAttr).(bool)
tok := "NOCREATEDB"
if createDB {
tok = "CREATEDB"
}
roleName := d.Get(roleNameAttr).(string)
query := fmt.Sprintf("ALTER ROLE %s WITH %s", pq.QuoteIdentifier(roleName), tok)
if _, err := conn.Query(query); err != nil {
return errwrap.Wrapf("Error updating role CREATEDB: {{err}}", err)
}
return nil
}
func setRoleCreateRole(conn *sql.DB, d *schema.ResourceData) error {
if !d.HasChange(roleCreateRoleAttr) {
return nil
}
createRole := d.Get(roleCreateRoleAttr).(bool)
tok := "NOCREATEROLE"
if createRole {
tok = "CREATEROLE"
}
roleName := d.Get(roleNameAttr).(string)
query := fmt.Sprintf("ALTER ROLE %s WITH %s", pq.QuoteIdentifier(roleName), tok)
if _, err := conn.Query(query); err != nil {
return errwrap.Wrapf("Error updating role CREATEROLE: {{err}}", err)
}
return nil
}
func setRoleInherit(conn *sql.DB, d *schema.ResourceData) error {
if !d.HasChange(roleInheritAttr) {
return nil
}
inherit := d.Get(roleInheritAttr).(bool)
tok := "NOINHERIT"
if inherit {
tok = "INHERIT"
}
roleName := d.Get(roleNameAttr).(string)
query := fmt.Sprintf("ALTER ROLE %s WITH %s", pq.QuoteIdentifier(roleName), tok)
if _, err := conn.Query(query); err != nil {
return errwrap.Wrapf("Error updating role INHERIT: {{err}}", err)
}
return nil
}
func setRoleLogin(conn *sql.DB, d *schema.ResourceData) error {
if !d.HasChange(roleLoginAttr) {
return nil
}
login := d.Get(roleLoginAttr).(bool)
tok := "NOLOGIN"
if login {
tok = "LOGIN"
}
roleName := d.Get(roleNameAttr).(string)
query := fmt.Sprintf("ALTER ROLE %s WITH %s", pq.QuoteIdentifier(roleName), tok)
if _, err := conn.Query(query); err != nil {
return errwrap.Wrapf("Error updating role LOGIN: {{err}}", err)
}
return nil
}
func setRoleReplication(conn *sql.DB, d *schema.ResourceData) error {
if !d.HasChange(roleReplicationAttr) {
return nil
}
replication := d.Get(roleReplicationAttr).(bool)
tok := "NOREPLICATION"
if replication {
tok = "REPLICATION"
}
roleName := d.Get(roleNameAttr).(string)
query := fmt.Sprintf("ALTER ROLE %s WITH %s", pq.QuoteIdentifier(roleName), tok)
if _, err := conn.Query(query); err != nil {
return errwrap.Wrapf("Error updating role REPLICATION: {{err}}", err)
}
return nil
}
func setRoleSuperuser(conn *sql.DB, d *schema.ResourceData) error {
if !d.HasChange(roleSuperuserAttr) {
return nil
}
superuser := d.Get(roleSuperuserAttr).(bool)
tok := "NOSUPERUSER"
if superuser {
tok = "SUPERUSER"
}
roleName := d.Get(roleNameAttr).(string)
query := fmt.Sprintf("ALTER ROLE %s WITH %s", pq.QuoteIdentifier(roleName), tok)
if _, err := conn.Query(query); err != nil {
return errwrap.Wrapf("Error updating role SUPERUSER: {{err}}", err)
}
return nil
}
func setRoleValidUntil(conn *sql.DB, d *schema.ResourceData) error {
if !d.HasChange(roleValidUntilAttr) {
return nil
}
validUntil := d.Get(roleValidUntilAttr).(string)
if validUntil == "" {
return nil
} else if strings.ToLower(validUntil) == "infinity" {
validUntil = "infinity"
}
roleName := d.Get(roleNameAttr).(string)
query := fmt.Sprintf("ALTER ROLE %s VALID UNTIL '%s'", pq.QuoteIdentifier(roleName), pqQuoteLiteral(validUntil))
if _, err := conn.Query(query); err != nil {
return errwrap.Wrapf("Error updating role VALID UNTIL: {{err}}", err)
}
return nil
}