github.com/skyscape-cloud-services/terraform@v0.9.2-0.20170609144644-7ece028a1747/builtin/providers/postgresql/resource_postgresql_role.go (about)

     1  package postgresql
     2  
     3  import (
     4  	"database/sql"
     5  	"errors"
     6  	"fmt"
     7  	"log"
     8  	"strings"
     9  
    10  	"github.com/hashicorp/errwrap"
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  	"github.com/lib/pq"
    13  )
    14  
    15  const (
    16  	roleBypassRLSAttr         = "bypass_row_level_security"
    17  	roleConnLimitAttr         = "connection_limit"
    18  	roleCreateDBAttr          = "create_database"
    19  	roleCreateRoleAttr        = "create_role"
    20  	roleEncryptedPassAttr     = "encrypted_password"
    21  	roleInheritAttr           = "inherit"
    22  	roleLoginAttr             = "login"
    23  	roleNameAttr              = "name"
    24  	rolePasswordAttr          = "password"
    25  	roleReplicationAttr       = "replication"
    26  	roleSkipDropRoleAttr      = "skip_drop_role"
    27  	roleSkipReassignOwnedAttr = "skip_reassign_owned"
    28  	roleSuperuserAttr         = "superuser"
    29  	roleValidUntilAttr        = "valid_until"
    30  
    31  	// Deprecated options
    32  	roleDepEncryptedAttr = "encrypted"
    33  )
    34  
    35  func resourcePostgreSQLRole() *schema.Resource {
    36  	return &schema.Resource{
    37  		Create: resourcePostgreSQLRoleCreate,
    38  		Read:   resourcePostgreSQLRoleRead,
    39  		Update: resourcePostgreSQLRoleUpdate,
    40  		Delete: resourcePostgreSQLRoleDelete,
    41  		Exists: resourcePostgreSQLRoleExists,
    42  		Importer: &schema.ResourceImporter{
    43  			State: schema.ImportStatePassthrough,
    44  		},
    45  
    46  		Schema: map[string]*schema.Schema{
    47  			roleNameAttr: {
    48  				Type:        schema.TypeString,
    49  				Required:    true,
    50  				Description: "The name of the role",
    51  			},
    52  			rolePasswordAttr: {
    53  				Type:        schema.TypeString,
    54  				Optional:    true,
    55  				Computed:    true,
    56  				Sensitive:   true,
    57  				DefaultFunc: schema.EnvDefaultFunc("PGPASSWORD", nil),
    58  				Description: "Sets the role's password",
    59  			},
    60  			roleDepEncryptedAttr: {
    61  				Type:       schema.TypeString,
    62  				Optional:   true,
    63  				Deprecated: fmt.Sprintf("Rename PostgreSQL role resource attribute %q to %q", roleDepEncryptedAttr, roleEncryptedPassAttr),
    64  			},
    65  			roleEncryptedPassAttr: {
    66  				Type:        schema.TypeBool,
    67  				Optional:    true,
    68  				Default:     true,
    69  				Description: "Control whether the password is stored encrypted in the system catalogs",
    70  			},
    71  			roleValidUntilAttr: {
    72  				Type:        schema.TypeString,
    73  				Optional:    true,
    74  				Default:     "infinity",
    75  				Description: "Sets a date and time after which the role's password is no longer valid",
    76  			},
    77  			roleConnLimitAttr: {
    78  				Type:         schema.TypeInt,
    79  				Optional:     true,
    80  				Default:      -1,
    81  				Description:  "How many concurrent connections can be made with this role",
    82  				ValidateFunc: validateConnLimit,
    83  			},
    84  			roleSuperuserAttr: {
    85  				Type:        schema.TypeBool,
    86  				Optional:    true,
    87  				Default:     false,
    88  				Description: `Determine whether the new role is a "superuser"`,
    89  			},
    90  			roleCreateDBAttr: {
    91  				Type:        schema.TypeBool,
    92  				Optional:    true,
    93  				Default:     false,
    94  				Description: "Define a role's ability to create databases",
    95  			},
    96  			roleCreateRoleAttr: {
    97  				Type:        schema.TypeBool,
    98  				Optional:    true,
    99  				Default:     false,
   100  				Description: "Determine whether this role will be permitted to create new roles",
   101  			},
   102  			roleInheritAttr: {
   103  				Type:        schema.TypeBool,
   104  				Optional:    true,
   105  				Default:     true,
   106  				Description: `Determine whether a role "inherits" the privileges of roles it is a member of`,
   107  			},
   108  			roleLoginAttr: {
   109  				Type:        schema.TypeBool,
   110  				Optional:    true,
   111  				Default:     false,
   112  				Description: "Determine whether a role is allowed to log in",
   113  			},
   114  			roleReplicationAttr: {
   115  				Type:        schema.TypeBool,
   116  				Optional:    true,
   117  				Default:     false,
   118  				Description: "Determine whether a role is allowed to initiate streaming replication or put the system in and out of backup mode",
   119  			},
   120  			roleBypassRLSAttr: {
   121  				Type:        schema.TypeBool,
   122  				Optional:    true,
   123  				Default:     false,
   124  				Description: "Determine whether a role bypasses every row-level security (RLS) policy",
   125  			},
   126  			roleSkipDropRoleAttr: {
   127  				Type:        schema.TypeBool,
   128  				Optional:    true,
   129  				Default:     false,
   130  				Description: "Skip actually running the DROP ROLE command when removing a ROLE from PostgreSQL",
   131  			},
   132  			roleSkipReassignOwnedAttr: {
   133  				Type:        schema.TypeBool,
   134  				Optional:    true,
   135  				Default:     false,
   136  				Description: "Skip actually running the REASSIGN OWNED command when removing a role from PostgreSQL",
   137  			},
   138  		},
   139  	}
   140  }
   141  
   142  func resourcePostgreSQLRoleCreate(d *schema.ResourceData, meta interface{}) error {
   143  	c := meta.(*Client)
   144  	c.catalogLock.Lock()
   145  	defer c.catalogLock.Unlock()
   146  
   147  	conn, err := c.Connect()
   148  	if err != nil {
   149  		return errwrap.Wrapf("Error connecting to PostgreSQL: {{err}}", err)
   150  	}
   151  	defer conn.Close()
   152  
   153  	stringOpts := []struct {
   154  		hclKey string
   155  		sqlKey string
   156  	}{
   157  		{rolePasswordAttr, "PASSWORD"},
   158  		{roleValidUntilAttr, "VALID UNTIL"},
   159  	}
   160  	intOpts := []struct {
   161  		hclKey string
   162  		sqlKey string
   163  	}{
   164  		{roleConnLimitAttr, "CONNECTION LIMIT"},
   165  	}
   166  	boolOpts := []struct {
   167  		hclKey        string
   168  		sqlKeyEnable  string
   169  		sqlKeyDisable string
   170  	}{
   171  		{roleSuperuserAttr, "CREATEDB", "NOCREATEDB"},
   172  		{roleCreateRoleAttr, "CREATEROLE", "NOCREATEROLE"},
   173  		{roleInheritAttr, "INHERIT", "NOINHERIT"},
   174  		{roleLoginAttr, "LOGIN", "NOLOGIN"},
   175  		{roleReplicationAttr, "REPLICATION", "NOREPLICATION"},
   176  		{roleBypassRLSAttr, "BYPASSRLS", "NOBYPASSRLS"},
   177  
   178  		// roleEncryptedPassAttr is used only when rolePasswordAttr is set.
   179  		// {roleEncryptedPassAttr, "ENCRYPTED", "UNENCRYPTED"},
   180  	}
   181  
   182  	createOpts := make([]string, 0, len(stringOpts)+len(intOpts)+len(boolOpts))
   183  
   184  	for _, opt := range stringOpts {
   185  		v, ok := d.GetOk(opt.hclKey)
   186  		if !ok {
   187  			continue
   188  		}
   189  
   190  		val := v.(string)
   191  		if val != "" {
   192  			switch {
   193  			case opt.hclKey == rolePasswordAttr:
   194  				if strings.ToUpper(v.(string)) == "NULL" {
   195  					createOpts = append(createOpts, "PASSWORD NULL")
   196  				} else {
   197  					if d.Get(roleEncryptedPassAttr).(bool) {
   198  						createOpts = append(createOpts, "ENCRYPTED")
   199  					} else {
   200  						createOpts = append(createOpts, "UNENCRYPTED")
   201  					}
   202  					createOpts = append(createOpts, fmt.Sprintf("%s '%s'", opt.sqlKey, pqQuoteLiteral(val)))
   203  				}
   204  			case opt.hclKey == roleValidUntilAttr:
   205  				switch {
   206  				case v.(string) == "", strings.ToLower(v.(string)) == "infinity":
   207  					createOpts = append(createOpts, fmt.Sprintf("%s '%s'", opt.sqlKey, "infinity"))
   208  				default:
   209  					createOpts = append(createOpts, fmt.Sprintf("%s %s", opt.sqlKey, pq.QuoteIdentifier(val)))
   210  				}
   211  			default:
   212  				createOpts = append(createOpts, fmt.Sprintf("%s %s", opt.sqlKey, pq.QuoteIdentifier(val)))
   213  			}
   214  		}
   215  	}
   216  
   217  	for _, opt := range intOpts {
   218  		val := d.Get(opt.hclKey).(int)
   219  		createOpts = append(createOpts, fmt.Sprintf("%s %d", opt.sqlKey, val))
   220  	}
   221  
   222  	for _, opt := range boolOpts {
   223  		if opt.hclKey == roleEncryptedPassAttr {
   224  			// This attribute is handled above in the stringOpts
   225  			// loop.
   226  			continue
   227  		}
   228  		val := d.Get(opt.hclKey).(bool)
   229  		valStr := opt.sqlKeyDisable
   230  		if val {
   231  			valStr = opt.sqlKeyEnable
   232  		}
   233  		createOpts = append(createOpts, valStr)
   234  	}
   235  
   236  	roleName := d.Get(roleNameAttr).(string)
   237  	createStr := strings.Join(createOpts, " ")
   238  	if len(createOpts) > 0 {
   239  		// FIXME(seanc@): Work around ParAccel/AWS RedShift's ancient fork of PostgreSQL
   240  		// createStr = " WITH " + createStr
   241  		createStr = " " + createStr
   242  	}
   243  
   244  	query := fmt.Sprintf("CREATE ROLE %s%s", pq.QuoteIdentifier(roleName), createStr)
   245  	_, err = conn.Query(query)
   246  	if err != nil {
   247  		return errwrap.Wrapf(fmt.Sprintf("Error creating role %s: {{err}}", roleName), err)
   248  	}
   249  
   250  	d.SetId(roleName)
   251  
   252  	return resourcePostgreSQLRoleReadImpl(d, meta)
   253  }
   254  
   255  func resourcePostgreSQLRoleDelete(d *schema.ResourceData, meta interface{}) error {
   256  	c := meta.(*Client)
   257  	c.catalogLock.Lock()
   258  	defer c.catalogLock.Unlock()
   259  
   260  	conn, err := c.Connect()
   261  	if err != nil {
   262  		return err
   263  	}
   264  	defer conn.Close()
   265  
   266  	txn, err := conn.Begin()
   267  	if err != nil {
   268  		return err
   269  	}
   270  	defer txn.Rollback()
   271  
   272  	roleName := d.Get(roleNameAttr).(string)
   273  
   274  	queries := make([]string, 0, 3)
   275  	if !d.Get(roleSkipReassignOwnedAttr).(bool) {
   276  		queries = append(queries, fmt.Sprintf("REASSIGN OWNED BY %s TO CURRENT_USER", pq.QuoteIdentifier(roleName)))
   277  		queries = append(queries, fmt.Sprintf("DROP OWNED BY %s", pq.QuoteIdentifier(roleName)))
   278  	}
   279  
   280  	if !d.Get(roleSkipDropRoleAttr).(bool) {
   281  		queries = append(queries, fmt.Sprintf("DROP ROLE %s", pq.QuoteIdentifier(roleName)))
   282  	}
   283  
   284  	if len(queries) > 0 {
   285  		for _, query := range queries {
   286  			_, err = conn.Query(query)
   287  			if err != nil {
   288  				return errwrap.Wrapf("Error deleting role: {{err}}", err)
   289  			}
   290  		}
   291  
   292  		if err := txn.Commit(); err != nil {
   293  			return errwrap.Wrapf("Error committing schema: {{err}}", err)
   294  		}
   295  	}
   296  
   297  	d.SetId("")
   298  
   299  	return nil
   300  }
   301  
   302  func resourcePostgreSQLRoleExists(d *schema.ResourceData, meta interface{}) (bool, error) {
   303  	c := meta.(*Client)
   304  	c.catalogLock.RLock()
   305  	defer c.catalogLock.RUnlock()
   306  
   307  	conn, err := c.Connect()
   308  	if err != nil {
   309  		return false, err
   310  	}
   311  	defer conn.Close()
   312  
   313  	var roleName string
   314  	err = conn.QueryRow("SELECT rolname FROM pg_catalog.pg_roles WHERE rolname=$1", d.Id()).Scan(&roleName)
   315  	switch {
   316  	case err == sql.ErrNoRows:
   317  		return false, nil
   318  	case err != nil:
   319  		return false, err
   320  	}
   321  
   322  	return true, nil
   323  }
   324  
   325  func resourcePostgreSQLRoleRead(d *schema.ResourceData, meta interface{}) error {
   326  	c := meta.(*Client)
   327  	c.catalogLock.RLock()
   328  	defer c.catalogLock.RUnlock()
   329  
   330  	return resourcePostgreSQLRoleReadImpl(d, meta)
   331  }
   332  
   333  func resourcePostgreSQLRoleReadImpl(d *schema.ResourceData, meta interface{}) error {
   334  	c := meta.(*Client)
   335  	conn, err := c.Connect()
   336  	if err != nil {
   337  		return err
   338  	}
   339  	defer conn.Close()
   340  
   341  	roleId := d.Id()
   342  	var roleSuperuser, roleInherit, roleCreateRole, roleCreateDB, roleCanLogin, roleReplication, roleBypassRLS bool
   343  	var roleConnLimit int
   344  	var roleName, roleValidUntil string
   345  	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)
   346  	switch {
   347  	case err == sql.ErrNoRows:
   348  		log.Printf("[WARN] PostgreSQL role (%s) not found", roleId)
   349  		d.SetId("")
   350  		return nil
   351  	case err != nil:
   352  		return errwrap.Wrapf("Error reading role: {{err}}", err)
   353  	default:
   354  		d.Set(roleNameAttr, roleName)
   355  		d.Set(roleBypassRLSAttr, roleBypassRLS)
   356  		d.Set(roleConnLimitAttr, roleConnLimit)
   357  		d.Set(roleCreateDBAttr, roleCreateDB)
   358  		d.Set(roleCreateRoleAttr, roleCreateRole)
   359  		d.Set(roleEncryptedPassAttr, true)
   360  		d.Set(roleInheritAttr, roleInherit)
   361  		d.Set(roleLoginAttr, roleCanLogin)
   362  		d.Set(roleReplicationAttr, roleReplication)
   363  		d.Set(roleSkipDropRoleAttr, d.Get(roleSkipDropRoleAttr).(bool))
   364  		d.Set(roleSkipReassignOwnedAttr, d.Get(roleSkipReassignOwnedAttr).(bool))
   365  		d.Set(roleSuperuserAttr, roleSuperuser)
   366  		d.Set(roleValidUntilAttr, roleValidUntil)
   367  		d.SetId(roleName)
   368  	}
   369  
   370  	if !roleSuperuser {
   371  		// Return early if not superuser user
   372  		return nil
   373  	}
   374  
   375  	var rolePassword string
   376  	err = conn.QueryRow("SELECT COALESCE(passwd, '') FROM pg_catalog.pg_shadow AS s WHERE s.usename = $1", roleId).Scan(&rolePassword)
   377  	switch {
   378  	case err == sql.ErrNoRows:
   379  		return errwrap.Wrapf(fmt.Sprintf("PostgreSQL role (%s) not found in shadow database: {{err}}", roleId), err)
   380  	case err != nil:
   381  		return errwrap.Wrapf("Error reading role: {{err}}", err)
   382  	default:
   383  		d.Set(rolePasswordAttr, rolePassword)
   384  		return nil
   385  	}
   386  }
   387  
   388  func resourcePostgreSQLRoleUpdate(d *schema.ResourceData, meta interface{}) error {
   389  	c := meta.(*Client)
   390  	c.catalogLock.Lock()
   391  	defer c.catalogLock.Unlock()
   392  
   393  	conn, err := c.Connect()
   394  	if err != nil {
   395  		return err
   396  	}
   397  	defer conn.Close()
   398  
   399  	if err := setRoleName(conn, d); err != nil {
   400  		return err
   401  	}
   402  
   403  	if err := setRoleBypassRLS(conn, d); err != nil {
   404  		return err
   405  	}
   406  
   407  	if err := setRoleConnLimit(conn, d); err != nil {
   408  		return err
   409  	}
   410  
   411  	if err := setRoleCreateDB(conn, d); err != nil {
   412  		return err
   413  	}
   414  
   415  	if err := setRoleCreateRole(conn, d); err != nil {
   416  		return err
   417  	}
   418  
   419  	if err := setRoleInherit(conn, d); err != nil {
   420  		return err
   421  	}
   422  
   423  	if err := setRoleLogin(conn, d); err != nil {
   424  		return err
   425  	}
   426  
   427  	if err := setRoleReplication(conn, d); err != nil {
   428  		return err
   429  	}
   430  
   431  	if err := setRoleSuperuser(conn, d); err != nil {
   432  		return err
   433  	}
   434  
   435  	if err := setRoleValidUntil(conn, d); err != nil {
   436  		return err
   437  	}
   438  
   439  	return resourcePostgreSQLRoleReadImpl(d, meta)
   440  }
   441  
   442  func setRoleName(conn *sql.DB, d *schema.ResourceData) error {
   443  	if !d.HasChange(roleNameAttr) {
   444  		return nil
   445  	}
   446  
   447  	oraw, nraw := d.GetChange(roleNameAttr)
   448  	o := oraw.(string)
   449  	n := nraw.(string)
   450  	if n == "" {
   451  		return errors.New("Error setting role name to an empty string")
   452  	}
   453  
   454  	query := fmt.Sprintf("ALTER ROLE %s RENAME TO %s", pq.QuoteIdentifier(o), pq.QuoteIdentifier(n))
   455  	if _, err := conn.Query(query); err != nil {
   456  		return errwrap.Wrapf("Error updating role NAME: {{err}}", err)
   457  	}
   458  	d.SetId(n)
   459  
   460  	return nil
   461  }
   462  
   463  func setRoleBypassRLS(conn *sql.DB, d *schema.ResourceData) error {
   464  	if !d.HasChange(roleBypassRLSAttr) {
   465  		return nil
   466  	}
   467  
   468  	bypassRLS := d.Get(roleBypassRLSAttr).(bool)
   469  	tok := "NOBYPASSRLS"
   470  	if bypassRLS {
   471  		tok = "BYPASSRLS"
   472  	}
   473  	roleName := d.Get(roleNameAttr).(string)
   474  	query := fmt.Sprintf("ALTER ROLE %s WITH %s", pq.QuoteIdentifier(roleName), tok)
   475  	if _, err := conn.Query(query); err != nil {
   476  		return errwrap.Wrapf("Error updating role BYPASSRLS: {{err}}", err)
   477  	}
   478  
   479  	return nil
   480  }
   481  
   482  func setRoleConnLimit(conn *sql.DB, d *schema.ResourceData) error {
   483  	if !d.HasChange(roleConnLimitAttr) {
   484  		return nil
   485  	}
   486  
   487  	connLimit := d.Get(roleConnLimitAttr).(int)
   488  	roleName := d.Get(roleNameAttr).(string)
   489  	query := fmt.Sprintf("ALTER ROLE %s CONNECTION LIMIT %d", pq.QuoteIdentifier(roleName), connLimit)
   490  	if _, err := conn.Query(query); err != nil {
   491  		return errwrap.Wrapf("Error updating role CONNECTION LIMIT: {{err}}", err)
   492  	}
   493  
   494  	return nil
   495  }
   496  
   497  func setRoleCreateDB(conn *sql.DB, d *schema.ResourceData) error {
   498  	if !d.HasChange(roleCreateDBAttr) {
   499  		return nil
   500  	}
   501  
   502  	createDB := d.Get(roleCreateDBAttr).(bool)
   503  	tok := "NOCREATEDB"
   504  	if createDB {
   505  		tok = "CREATEDB"
   506  	}
   507  	roleName := d.Get(roleNameAttr).(string)
   508  	query := fmt.Sprintf("ALTER ROLE %s WITH %s", pq.QuoteIdentifier(roleName), tok)
   509  	if _, err := conn.Query(query); err != nil {
   510  		return errwrap.Wrapf("Error updating role CREATEDB: {{err}}", err)
   511  	}
   512  
   513  	return nil
   514  }
   515  
   516  func setRoleCreateRole(conn *sql.DB, d *schema.ResourceData) error {
   517  	if !d.HasChange(roleCreateRoleAttr) {
   518  		return nil
   519  	}
   520  
   521  	createRole := d.Get(roleCreateRoleAttr).(bool)
   522  	tok := "NOCREATEROLE"
   523  	if createRole {
   524  		tok = "CREATEROLE"
   525  	}
   526  	roleName := d.Get(roleNameAttr).(string)
   527  	query := fmt.Sprintf("ALTER ROLE %s WITH %s", pq.QuoteIdentifier(roleName), tok)
   528  	if _, err := conn.Query(query); err != nil {
   529  		return errwrap.Wrapf("Error updating role CREATEROLE: {{err}}", err)
   530  	}
   531  
   532  	return nil
   533  }
   534  
   535  func setRoleInherit(conn *sql.DB, d *schema.ResourceData) error {
   536  	if !d.HasChange(roleInheritAttr) {
   537  		return nil
   538  	}
   539  
   540  	inherit := d.Get(roleInheritAttr).(bool)
   541  	tok := "NOINHERIT"
   542  	if inherit {
   543  		tok = "INHERIT"
   544  	}
   545  	roleName := d.Get(roleNameAttr).(string)
   546  	query := fmt.Sprintf("ALTER ROLE %s WITH %s", pq.QuoteIdentifier(roleName), tok)
   547  	if _, err := conn.Query(query); err != nil {
   548  		return errwrap.Wrapf("Error updating role INHERIT: {{err}}", err)
   549  	}
   550  
   551  	return nil
   552  }
   553  
   554  func setRoleLogin(conn *sql.DB, d *schema.ResourceData) error {
   555  	if !d.HasChange(roleLoginAttr) {
   556  		return nil
   557  	}
   558  
   559  	login := d.Get(roleLoginAttr).(bool)
   560  	tok := "NOLOGIN"
   561  	if login {
   562  		tok = "LOGIN"
   563  	}
   564  	roleName := d.Get(roleNameAttr).(string)
   565  	query := fmt.Sprintf("ALTER ROLE %s WITH %s", pq.QuoteIdentifier(roleName), tok)
   566  	if _, err := conn.Query(query); err != nil {
   567  		return errwrap.Wrapf("Error updating role LOGIN: {{err}}", err)
   568  	}
   569  
   570  	return nil
   571  }
   572  
   573  func setRoleReplication(conn *sql.DB, d *schema.ResourceData) error {
   574  	if !d.HasChange(roleReplicationAttr) {
   575  		return nil
   576  	}
   577  
   578  	replication := d.Get(roleReplicationAttr).(bool)
   579  	tok := "NOREPLICATION"
   580  	if replication {
   581  		tok = "REPLICATION"
   582  	}
   583  	roleName := d.Get(roleNameAttr).(string)
   584  	query := fmt.Sprintf("ALTER ROLE %s WITH %s", pq.QuoteIdentifier(roleName), tok)
   585  	if _, err := conn.Query(query); err != nil {
   586  		return errwrap.Wrapf("Error updating role REPLICATION: {{err}}", err)
   587  	}
   588  
   589  	return nil
   590  }
   591  
   592  func setRoleSuperuser(conn *sql.DB, d *schema.ResourceData) error {
   593  	if !d.HasChange(roleSuperuserAttr) {
   594  		return nil
   595  	}
   596  
   597  	superuser := d.Get(roleSuperuserAttr).(bool)
   598  	tok := "NOSUPERUSER"
   599  	if superuser {
   600  		tok = "SUPERUSER"
   601  	}
   602  	roleName := d.Get(roleNameAttr).(string)
   603  	query := fmt.Sprintf("ALTER ROLE %s WITH %s", pq.QuoteIdentifier(roleName), tok)
   604  	if _, err := conn.Query(query); err != nil {
   605  		return errwrap.Wrapf("Error updating role SUPERUSER: {{err}}", err)
   606  	}
   607  
   608  	return nil
   609  }
   610  
   611  func setRoleValidUntil(conn *sql.DB, d *schema.ResourceData) error {
   612  	if !d.HasChange(roleValidUntilAttr) {
   613  		return nil
   614  	}
   615  
   616  	validUntil := d.Get(roleValidUntilAttr).(string)
   617  	if validUntil == "" {
   618  		return nil
   619  	} else if strings.ToLower(validUntil) == "infinity" {
   620  		validUntil = "infinity"
   621  	}
   622  
   623  	roleName := d.Get(roleNameAttr).(string)
   624  	query := fmt.Sprintf("ALTER ROLE %s VALID UNTIL '%s'", pq.QuoteIdentifier(roleName), pqQuoteLiteral(validUntil))
   625  
   626  	if _, err := conn.Query(query); err != nil {
   627  		return errwrap.Wrapf("Error updating role VALID UNTIL: {{err}}", err)
   628  	}
   629  
   630  	return nil
   631  }