Update the postgresql_schema resource to accept policies.

It is now possible to begin specifying DCL for schemas.
This commit is contained in:
Sean Chittenden 2016-12-25 04:18:32 -08:00
parent fab7bd3daf
commit 38928b91ba
No known key found for this signature in database
GPG Key ID: 4EBC9DC16C2E5E16
5 changed files with 636 additions and 640 deletions

View File

@ -67,7 +67,6 @@ func Provider() terraform.ResourceProvider {
"postgresql_database": resourcePostgreSQLDatabase(),
"postgresql_extension": resourcePostgreSQLExtension(),
"postgresql_schema": resourcePostgreSQLSchema(),
"postgresql_schema_policy": resourcePostgreSQLSchemaPolicy(),
"postgresql_role": resourcePostgreSQLRole(),
},

View File

@ -6,15 +6,26 @@ import (
"errors"
"fmt"
"log"
"reflect"
"strings"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/terraform/helper/schema"
"github.com/lib/pq"
"github.com/sean-/postgresql-acl"
)
const (
schemaNameAttr = "name"
schemaOwnerAttr = "owner"
schemaPolicyAttr = "policy"
schemaIfNotExists = "if_not_exists"
schemaPolicyCreateAttr = "create"
schemaPolicyCreateWithGrantAttr = "create_with_grant"
schemaPolicyRoleAttr = "role"
schemaPolicyUsageAttr = "usage"
schemaPolicyUsageWithGrantAttr = "usage_with_grant"
)
func resourcePostgreSQLSchema() *schema.Resource {
@ -39,11 +50,105 @@ func resourcePostgreSQLSchema() *schema.Resource {
Computed: true,
Description: "The ROLE name who owns the schema",
},
schemaIfNotExists: {
Type: schema.TypeBool,
Optional: true,
Default: true,
Description: "When true, use the existing schema if it exsts",
},
schemaPolicyAttr: &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
schemaPolicyCreateAttr: {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "If true, allow the specified ROLEs to CREATE new objects within the schema(s)",
ConflictsWith: []string{schemaPolicyAttr + "." + schemaPolicyCreateWithGrantAttr},
},
schemaPolicyCreateWithGrantAttr: {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "If true, allow the specified ROLEs to CREATE new objects within the schema(s) and GRANT the same CREATE privilege to different ROLEs",
ConflictsWith: []string{schemaPolicyAttr + "." + schemaPolicyCreateAttr},
},
schemaPolicyRoleAttr: {
Type: schema.TypeString,
Elem: &schema.Schema{Type: schema.TypeString},
Required: true,
Description: "ROLE who will receive this policy",
},
schemaPolicyUsageAttr: {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "If true, allow the specified ROLEs to use objects within the schema(s)",
ConflictsWith: []string{schemaPolicyAttr + "." + schemaPolicyUsageWithGrantAttr},
},
schemaPolicyUsageWithGrantAttr: {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "If true, allow the specified ROLEs to use objects within the schema(s) and GRANT the same USAGE privilege to different ROLEs",
ConflictsWith: []string{schemaPolicyAttr + "." + schemaPolicyUsageAttr},
},
},
},
},
},
}
}
func resourcePostgreSQLSchemaCreate(d *schema.ResourceData, meta interface{}) error {
queries := []string{}
schemaName := d.Get(schemaNameAttr).(string)
{
b := bytes.NewBufferString("CREATE SCHEMA ")
if v := d.Get(schemaIfNotExists); v.(bool) {
fmt.Fprint(b, "IF NOT EXISTS ")
}
fmt.Fprint(b, pq.QuoteIdentifier(schemaName))
switch v, ok := d.GetOk(schemaOwnerAttr); {
case ok:
fmt.Fprint(b, " AUTHORIZATION ", pq.QuoteIdentifier(v.(string)))
}
queries = append(queries, b.String())
}
// ACL objects that can generate the necessary SQL
type RoleKey string
var schemaPolicies map[RoleKey]acl.Schema
if policiesRaw, ok := d.GetOk(schemaPolicyAttr); ok {
policiesList := policiesRaw.(*schema.Set).List()
// NOTE: len(policiesList) doesn't take into account multiple
// roles per policy.
schemaPolicies = make(map[RoleKey]acl.Schema, len(policiesList))
for _, policyRaw := range policiesList {
policyMap := policyRaw.(map[string]interface{})
rolePolicy := schemaPolicyToACL(policyMap)
roleKey := RoleKey(strings.ToLower(rolePolicy.Role))
if existingRolePolicy, ok := schemaPolicies[roleKey]; ok {
schemaPolicies[roleKey] = existingRolePolicy.Merge(rolePolicy)
} else {
schemaPolicies[roleKey] = rolePolicy
}
}
}
for _, policy := range schemaPolicies {
queries = append(queries, policy.Grants(schemaName)...)
}
c := meta.(*Client)
conn, err := c.Connect()
if err != nil {
@ -51,20 +156,22 @@ func resourcePostgreSQLSchemaCreate(d *schema.ResourceData, meta interface{}) er
}
defer conn.Close()
schemaName := d.Get(schemaNameAttr).(string)
b := bytes.NewBufferString("CREATE SCHEMA ")
fmt.Fprintf(b, pq.QuoteIdentifier(schemaName))
switch v, ok := d.GetOk(schemaOwnerAttr); {
case ok:
fmt.Fprint(b, " AUTHORIZATION ", pq.QuoteIdentifier(v.(string)))
txn, err := conn.Begin()
if err != nil {
return err
}
defer txn.Rollback()
query := b.String()
_, err = conn.Query(query)
for _, query := range queries {
_, err = txn.Query(query)
if err != nil {
return errwrap.Wrapf(fmt.Sprintf("Error creating schema %s: {{err}}", schemaName), err)
}
}
if err := txn.Commit(); err != nil {
return errwrap.Wrapf("Error committing schema: {{err}}", err)
}
d.SetId(schemaName)
@ -79,13 +186,25 @@ func resourcePostgreSQLSchemaDelete(d *schema.ResourceData, meta interface{}) er
}
defer conn.Close()
txn, err := conn.Begin()
if err != nil {
return err
}
defer txn.Rollback()
schemaName := d.Get(schemaNameAttr).(string)
// NOTE(sean@): Deliberately not performing a cascading drop.
query := fmt.Sprintf("DROP SCHEMA %s", pq.QuoteIdentifier(schemaName))
_, err = conn.Query(query)
_, err = txn.Query(query)
if err != nil {
return errwrap.Wrapf("Error deleting schema: {{err}}", err)
}
if err := txn.Commit(); err != nil {
return errwrap.Wrapf("Error committing schema: {{err}}", err)
}
d.SetId("")
return nil
@ -101,7 +220,8 @@ func resourcePostgreSQLSchemaRead(d *schema.ResourceData, meta interface{}) erro
schemaId := d.Id()
var schemaName, schemaOwner string
err = conn.QueryRow("SELECT nspname, pg_catalog.pg_get_userbyid(nspowner) FROM pg_catalog.pg_namespace WHERE nspname=$1", schemaId).Scan(&schemaName, &schemaOwner)
var schemaACLs []string
err = conn.QueryRow("SELECT n.nspname, pg_catalog.pg_get_userbyid(n.nspowner), COALESCE(n.nspacl, '{}'::aclitem[])::TEXT[] FROM pg_catalog.pg_namespace n WHERE n.nspname=$1", schemaId).Scan(&schemaName, &schemaOwner, pq.Array(&schemaACLs))
switch {
case err == sql.ErrNoRows:
log.Printf("[WARN] PostgreSQL schema (%s) not found", schemaId)
@ -110,6 +230,29 @@ func resourcePostgreSQLSchemaRead(d *schema.ResourceData, meta interface{}) erro
case err != nil:
return errwrap.Wrapf("Error reading schema: {{err}}", err)
default:
type RoleKey string
schemaPolicies := make(map[RoleKey]acl.Schema, len(schemaACLs))
for _, aclStr := range schemaACLs {
aclItem, err := acl.Parse(aclStr)
if err != nil {
return errwrap.Wrapf("Error parsing aclitem: {{err}}", err)
}
schemaACL, err := acl.NewSchema(aclItem)
if err != nil {
return errwrap.Wrapf("invalid perms for schema: {{err}}", err)
}
roleKey := RoleKey(strings.ToLower(schemaACL.Role))
var mergedPolicy acl.Schema
if existingRolePolicy, ok := schemaPolicies[roleKey]; ok {
mergedPolicy = existingRolePolicy.Merge(schemaACL)
} else {
mergedPolicy = schemaACL
}
schemaPolicies[roleKey] = mergedPolicy
}
d.Set(schemaNameAttr, schemaName)
d.Set(schemaOwnerAttr, schemaOwner)
d.SetId(schemaName)
@ -125,18 +268,32 @@ func resourcePostgreSQLSchemaUpdate(d *schema.ResourceData, meta interface{}) er
}
defer conn.Close()
if err := setSchemaName(conn, d); err != nil {
txn, err := conn.Begin()
if err != nil {
return err
}
defer txn.Rollback()
if err := setSchemaName(txn, d); err != nil {
return err
}
if err := setSchemaOwner(conn, d); err != nil {
if err := setSchemaOwner(txn, d); err != nil {
return err
}
if err := setSchemaPolicy(txn, d); err != nil {
return err
}
if err := txn.Commit(); err != nil {
return errwrap.Wrapf("Error committing schema: {{err}}", err)
}
return resourcePostgreSQLSchemaRead(d, meta)
}
func setSchemaName(conn *sql.DB, d *schema.ResourceData) error {
func setSchemaName(txn *sql.Tx, d *schema.ResourceData) error {
if !d.HasChange(schemaNameAttr) {
return nil
}
@ -149,7 +306,7 @@ func setSchemaName(conn *sql.DB, d *schema.ResourceData) error {
}
query := fmt.Sprintf("ALTER SCHEMA %s RENAME TO %s", pq.QuoteIdentifier(o), pq.QuoteIdentifier(n))
if _, err := conn.Query(query); err != nil {
if _, err := txn.Query(query); err != nil {
return errwrap.Wrapf("Error updating schema NAME: {{err}}", err)
}
d.SetId(n)
@ -157,7 +314,7 @@ func setSchemaName(conn *sql.DB, d *schema.ResourceData) error {
return nil
}
func setSchemaOwner(conn *sql.DB, d *schema.ResourceData) error {
func setSchemaOwner(txn *sql.Tx, d *schema.ResourceData) error {
if !d.HasChange(schemaOwnerAttr) {
return nil
}
@ -170,9 +327,157 @@ func setSchemaOwner(conn *sql.DB, d *schema.ResourceData) error {
}
query := fmt.Sprintf("ALTER SCHEMA %s OWNER TO %s", pq.QuoteIdentifier(o), pq.QuoteIdentifier(n))
if _, err := conn.Query(query); err != nil {
if _, err := txn.Query(query); err != nil {
return errwrap.Wrapf("Error updating schema OWNER: {{err}}", err)
}
return nil
}
func setSchemaPolicy(txn *sql.Tx, d *schema.ResourceData) error {
if !d.HasChange(schemaPolicyAttr) {
return nil
}
schemaName := d.Get(schemaNameAttr).(string)
oraw, nraw := d.GetChange(schemaPolicyAttr)
oldList := oraw.(*schema.Set).List()
newList := nraw.(*schema.Set).List()
queries := make([]string, 0, len(oldList)+len(newList))
dropped, added, updated, _ := schemaChangedPolicies(oldList, newList)
for _, p := range dropped {
pMap := p.(map[string]interface{})
rolePolicy := schemaPolicyToACL(pMap)
queries = append(queries, rolePolicy.Revokes(schemaName)...)
}
for _, p := range added {
pMap := p.(map[string]interface{})
rolePolicy := schemaPolicyToACL(pMap)
queries = append(queries, rolePolicy.Grants(schemaName)...)
}
for _, p := range updated {
policies := p.([]interface{})
if len(policies) != 2 {
panic("expected 2 policies, old and new")
}
{
oldPolicies := policies[0].(map[string]interface{})
rolePolicy := schemaPolicyToACL(oldPolicies)
queries = append(queries, rolePolicy.Revokes(schemaName)...)
}
{
newPolicies := policies[1].(map[string]interface{})
rolePolicy := schemaPolicyToACL(newPolicies)
queries = append(queries, rolePolicy.Grants(schemaName)...)
}
}
for _, query := range queries {
if _, err := txn.Query(query); err != nil {
return errwrap.Wrapf("Error updating schema DCL: {{err}}", err)
}
}
return nil
}
// schemaChangedPolicies walks old and new to create a set of queries that can
// be executed to enact each type of state change (roles that have been dropped
// from the policy, added to a policy, have updated privilges, or are
// unchanged).
func schemaChangedPolicies(old, new []interface{}) (dropped, added, update, unchanged map[string]interface{}) {
type RoleKey string
oldLookupMap := make(map[RoleKey]interface{}, len(old))
for idx, _ := range old {
v := old[idx]
schemaPolicy := v.(map[string]interface{})
if roleRaw, ok := schemaPolicy[schemaPolicyRoleAttr]; ok {
role := roleRaw.(string)
roleKey := strings.ToLower(role)
oldLookupMap[RoleKey(roleKey)] = schemaPolicy
}
}
newLookupMap := make(map[RoleKey]interface{}, len(new))
for idx, _ := range new {
v := new[idx]
schemaPolicy := v.(map[string]interface{})
if roleRaw, ok := schemaPolicy[schemaPolicyRoleAttr]; ok {
role := roleRaw.(string)
roleKey := strings.ToLower(role)
newLookupMap[RoleKey(roleKey)] = schemaPolicy
}
}
droppedRoles := make(map[string]interface{}, len(old))
for kOld, vOld := range oldLookupMap {
if _, ok := newLookupMap[kOld]; !ok {
droppedRoles[string(kOld)] = vOld
}
}
addedRoles := make(map[string]interface{}, len(new))
for kNew, vNew := range newLookupMap {
if _, ok := oldLookupMap[kNew]; !ok {
addedRoles[string(kNew)] = vNew
}
}
updatedRoles := make(map[string]interface{}, len(new))
unchangedRoles := make(map[string]interface{}, len(new))
for kOld, vOld := range oldLookupMap {
if vNew, ok := newLookupMap[kOld]; ok {
if reflect.DeepEqual(vOld, vNew) {
unchangedRoles[string(kOld)] = vOld
} else {
updatedRoles[string(kOld)] = []interface{}{vOld, vNew}
}
}
}
return droppedRoles, addedRoles, updatedRoles, unchangedRoles
}
func schemaPolicyToHCL(s *acl.Schema) map[string]interface{} {
return map[string]interface{}{
schemaPolicyRoleAttr: s.Role,
schemaPolicyCreateAttr: s.GetPrivilege(acl.Create),
schemaPolicyCreateWithGrantAttr: s.GetGrantOption(acl.Create),
schemaPolicyUsageAttr: s.GetPrivilege(acl.Usage),
schemaPolicyUsageWithGrantAttr: s.GetGrantOption(acl.Usage),
}
}
func schemaPolicyToACL(policyMap map[string]interface{}) acl.Schema {
var rolePolicy acl.Schema
if policyMap[schemaPolicyCreateAttr].(bool) {
rolePolicy.Privileges |= acl.Create
}
if policyMap[schemaPolicyCreateWithGrantAttr].(bool) {
rolePolicy.Privileges |= acl.Create
rolePolicy.GrantOptions |= acl.Create
}
if policyMap[schemaPolicyUsageAttr].(bool) {
rolePolicy.Privileges |= acl.Usage
}
if policyMap[schemaPolicyUsageWithGrantAttr].(bool) {
rolePolicy.Privileges |= acl.Usage
rolePolicy.GrantOptions |= acl.Usage
}
if roleRaw, ok := policyMap[schemaPolicyRoleAttr]; ok {
rolePolicy.Role = roleRaw.(string)
}
return rolePolicy
}

View File

@ -1,442 +0,0 @@
package postgresql
import (
"bytes"
"database/sql"
"fmt"
"log"
"strings"
"github.com/hashicorp/errwrap"
uuid "github.com/hashicorp/go-uuid"
"github.com/hashicorp/terraform/helper/schema"
"github.com/lib/pq"
"github.com/sean-/pgacl"
)
const (
schemaPolicyCreateAttr = "create"
schemaPolicyCreateWithGrantAttr = "create_with_grant"
schemaPolicyRoleAttr = "role"
schemaPolicySchemaAttr = "schema"
schemaPolicyUsageAttr = "usage"
schemaPolicyUsageWithGrantAttr = "usage_with_grant"
// schemaPolicyRolesAttr = "roles"
// schemaPolicySchemasAttr = "schemas"
)
func resourcePostgreSQLSchemaPolicy() *schema.Resource {
return &schema.Resource{
Create: resourcePostgreSQLSchemaPolicyCreate,
Read: resourcePostgreSQLSchemaPolicyRead,
Update: resourcePostgreSQLSchemaPolicyUpdate,
Delete: resourcePostgreSQLSchemaPolicyDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Schema: map[string]*schema.Schema{
schemaPolicyCreateAttr: {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "If true, allow the specified ROLEs to CREATE new objects within the schema(s)",
ConflictsWith: []string{schemaPolicyCreateWithGrantAttr},
},
schemaPolicyCreateWithGrantAttr: {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "If true, allow the specified ROLEs to CREATE new objects within the schema(s) and GRANT the same CREATE privilege to different ROLEs",
ConflictsWith: []string{schemaPolicyCreateAttr},
},
// schemaPolicyRolesAttr: {
// Type: schema.TypeList,
// Elem: &schema.Schema{Type: schema.TypeString},
// Description: "List of ROLEs who will receive this policy",
// },
schemaPolicyRoleAttr: {
Type: schema.TypeString,
Required: true,
Description: "ROLE who will receive this policy",
},
schemaPolicySchemaAttr: {
Type: schema.TypeString,
Required: true,
Description: "Target SCHEMA who will have this policy applied to it",
},
schemaPolicyUsageAttr: {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "If true, allow the specified ROLEs to use objects within the schema(s)",
ConflictsWith: []string{schemaPolicyUsageWithGrantAttr},
},
schemaPolicyUsageWithGrantAttr: {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "If true, allow the specified ROLEs to use objects within the schema(s) and GRANT the same USAGE privilege to different ROLEs",
ConflictsWith: []string{schemaPolicyUsageAttr},
},
},
}
}
func resourcePostgreSQLSchemaPolicyCreate(d *schema.ResourceData, meta interface{}) error {
id, err := uuid.GenerateUUID()
if err != nil {
return errwrap.Wrapf("Unable to generate schema policy ID: {{err}}", err)
}
d.SetId(id)
acl := pgacl.Schema{}
role := d.Get(schemaPolicyRoleAttr).(string)
if strings.ToUpper(role) != "PUBLIC" {
role = pq.QuoteIdentifier(role)
}
acl.CreateGrant = d.Get(schemaPolicyCreateWithGrantAttr).(bool)
if acl.CreateGrant {
acl.Create = true
} else {
acl.Create = d.Get(schemaPolicyCreateAttr).(bool)
}
acl.UsageGrant = d.Get(schemaPolicyUsageWithGrantAttr).(bool)
if acl.UsageGrant {
acl.Usage = true
} else {
acl.Usage = d.Get(schemaPolicyUsageAttr).(bool)
}
schema := d.Get(schemaPolicySchemaAttr).(string)
queries := make([]string, 0, 2)
if acl.Create {
b := bytes.NewBufferString("GRANT CREATE ON SCHEMA ")
fmt.Fprintf(b, "%s TO %s", pq.QuoteIdentifier(schema), role)
if acl.CreateGrant {
fmt.Fprint(b, " WITH GRANT OPTION")
}
queries = append(queries, b.String())
}
if acl.Usage {
b := bytes.NewBufferString("GRANT USAGE ON SCHEMA ")
fmt.Fprintf(b, "%s TO %s", pq.QuoteIdentifier(schema), role)
if acl.UsageGrant {
fmt.Fprint(b, " WITH GRANT OPTION")
}
queries = append(queries, b.String())
}
c := meta.(*Client)
conn, err := c.Connect()
if err != nil {
return err
}
defer conn.Close()
txn, err := conn.Begin()
if err != nil {
return err
}
defer txn.Rollback()
for _, query := range queries {
_, err = txn.Query(query)
if err != nil {
return errwrap.Wrapf(fmt.Sprintf("Error applying policy on schema (%+q): {{err}}", query), err)
}
}
if err := txn.Commit(); err != nil {
return errwrap.Wrapf("Error committing schema policy: {{err}}", err)
}
return resourcePostgreSQLSchemaPolicyRead(d, meta)
}
func resourcePostgreSQLSchemaPolicyDelete(d *schema.ResourceData, meta interface{}) error {
role := d.Get(schemaPolicyRoleAttr).(string)
schema := d.Get(schemaPolicySchemaAttr).(string)
acl := pgacl.Schema{}
if strings.ToUpper(role) != "PUBLIC" {
role = pq.QuoteIdentifier(role)
}
acl.CreateGrant = d.Get(schemaPolicyCreateWithGrantAttr).(bool)
if acl.CreateGrant {
acl.Create = true
} else {
acl.Create = d.Get(schemaPolicyCreateAttr).(bool)
}
acl.UsageGrant = d.Get(schemaPolicyUsageWithGrantAttr).(bool)
if acl.UsageGrant {
acl.Usage = true
} else {
acl.Usage = d.Get(schemaPolicyUsageAttr).(bool)
}
queries := make([]string, 0, 2)
switch {
case !acl.Create:
b := bytes.NewBufferString("REVOKE CREATE ON SCHEMA ")
fmt.Fprintf(b, "%s FROM %s", pq.QuoteIdentifier(schema), role)
queries = append(queries, b.String())
case acl.Create && !acl.CreateGrant:
b := bytes.NewBufferString("REVOKE GRANT OPTION FOR CREATE ON SCHEMA ")
fmt.Fprintf(b, "%s FROM %s", pq.QuoteIdentifier(schema), role)
queries = append(queries, b.String())
}
switch {
case !acl.Usage:
b := bytes.NewBufferString("REVOKE USAGE ON SCHEMA ")
fmt.Fprintf(b, "%s FROM %s", pq.QuoteIdentifier(schema), role)
queries = append(queries, b.String())
case acl.Usage && !acl.UsageGrant:
b := bytes.NewBufferString("REVOKE GRANT OPTION FOR USAGE ON SCHEMA ")
fmt.Fprintf(b, "%s FROM %s", pq.QuoteIdentifier(schema), role)
queries = append(queries, b.String())
}
c := meta.(*Client)
conn, err := c.Connect()
if err != nil {
return err
}
defer conn.Close()
txn, err := conn.Begin()
if err != nil {
return err
}
defer txn.Rollback()
for _, query := range queries {
_, err = txn.Query(query)
if err != nil {
return errwrap.Wrapf(fmt.Sprintf("Error removing policy on schema (%+q): {{err}}", query), err)
}
}
txn.Commit()
d.SetId("")
return resourcePostgreSQLSchemaPolicyRead(d, meta)
}
func resourcePostgreSQLSchemaPolicyRead(d *schema.ResourceData, meta interface{}) error {
c := meta.(*Client)
conn, err := c.Connect()
if err != nil {
return err
}
defer conn.Close()
oraw, _ := d.GetChange(schemaPolicySchemaAttr)
o := oraw.(string)
var schemaName, schemaOwner, schemaACL string
err = conn.QueryRow("SELECT n.nspname, pg_catalog.pg_get_userbyid(n.nspowner), n.nspacl FROM pg_catalog.pg_namespace n WHERE n.nspname = $1", o).Scan(&schemaName, &schemaOwner, &schemaACL)
switch {
case err == sql.ErrNoRows:
log.Printf("[WARN] PostgreSQL schema (%s) not found", o)
d.SetId("")
return nil
case err != nil:
return errwrap.Wrapf("Error reading schema ACLs: {{err}}", err)
default:
acl, err := pgacl.NewSchema(schemaACL)
if err != nil {
return err
}
switch {
case acl.CreateGrant:
d.Set(schemaPolicyCreateWithGrantAttr, true)
d.Set(schemaPolicyCreateAttr, false)
case acl.Create:
d.Set(schemaPolicyCreateAttr, true)
d.Set(schemaPolicyCreateWithGrantAttr, false)
default:
d.Set(schemaPolicyCreateWithGrantAttr, false)
d.Set(schemaPolicyCreateAttr, false)
}
switch {
case acl.UsageGrant:
d.Set(schemaPolicyUsageWithGrantAttr, true)
d.Set(schemaPolicyUsageAttr, false)
case acl.Usage:
d.Set(schemaPolicyUsageAttr, true)
d.Set(schemaPolicyUsageWithGrantAttr, false)
default:
d.Set(schemaPolicyUsageWithGrantAttr, false)
d.Set(schemaPolicyUsageAttr, false)
}
d.Set(schemaPolicySchemaAttr, acl.Role)
d.Set(schemaPolicySchemaAttr, schemaName)
return nil
}
}
func resourcePostgreSQLSchemaPolicyUpdate(d *schema.ResourceData, meta interface{}) error {
c := meta.(*Client)
conn, err := c.Connect()
if err != nil {
return err
}
defer conn.Close()
txn, err := conn.Begin()
if err != nil {
return err
}
defer txn.Rollback()
if err := setSchemaPolicyCreate(txn, d); err != nil {
return err
}
if err := setSchemaPolicyUsage(txn, d); err != nil {
return err
}
txn.Commit()
return resourcePostgreSQLSchemaRead(d, meta)
}
func setSchemaPolicyCreate(txn *sql.Tx, d *schema.ResourceData) error {
if !d.HasChange(schemaPolicyCreateAttr) && !d.HasChange(schemaPolicyCreateWithGrantAttr) {
return nil
}
oldCreateRaw, newCreateRaw := d.GetChange(schemaPolicyCreateAttr)
oldCreate := oldCreateRaw.(bool)
newCreate := newCreateRaw.(bool)
oldGrantRaw, newGrantRaw := d.GetChange(schemaPolicyCreateWithGrantAttr)
oldGrant := oldGrantRaw.(bool)
newGrant := newGrantRaw.(bool)
var grant, revoke, withGrant bool
switch {
case oldCreate == newCreate:
// nothing changed
case oldCreate && !newCreate:
// Lost create privs
revoke = true
case !oldCreate && newCreate:
// Gaining create privs
grant = true
}
switch {
case newGrant == oldGrant:
// Nothing changed
case newGrant && !oldGrant, // Getting WITH GRANT OPTION priv
!newGrant && oldGrant: // Loosing WITH GRANT OPTION priv
withGrant = true
}
role := d.Get(schemaPolicyRoleAttr).(string)
if strings.ToUpper(role) != "PUBLIC" {
role = pq.QuoteIdentifier(role)
}
schema := d.Get(schemaPolicySchemaAttr).(string)
b := &bytes.Buffer{}
switch {
case grant:
b = bytes.NewBufferString("GRANT CREATE ON SCHEMA ")
fmt.Fprintf(b, "%s TO %s", pq.QuoteIdentifier(schema), role)
if withGrant {
fmt.Fprint(b, " WITH GRANT OPTION")
}
case revoke:
b = bytes.NewBufferString("REVOKE")
if withGrant {
fmt.Fprint(b, " GRANT OPTION FOR")
}
fmt.Fprintf(b, " CREATE ON SCHEMA %s FROM %s", pq.QuoteIdentifier(schema), role)
}
query := b.String()
if _, err := txn.Query(query); err != nil {
return errwrap.Wrapf("Error updating schema create privileges: {{err}}", err)
}
return nil
}
func setSchemaPolicyUsage(txn *sql.Tx, d *schema.ResourceData) error {
if !d.HasChange(schemaPolicyUsageAttr) && !d.HasChange(schemaPolicyUsageWithGrantAttr) {
return nil
}
oldUsageRaw, newUsageRaw := d.GetChange(schemaPolicyUsageAttr)
oldUsage := oldUsageRaw.(bool)
newUsage := newUsageRaw.(bool)
oldGrantRaw, newGrantRaw := d.GetChange(schemaPolicyUsageWithGrantAttr)
oldGrant := oldGrantRaw.(bool)
newGrant := newGrantRaw.(bool)
var grant, revoke, withGrant bool
switch {
case oldUsage == newUsage:
// nothing changed
case oldUsage && !newUsage:
// Lost usage privs
revoke = true
case !oldUsage && newUsage:
// Gaining usage privs
grant = true
}
switch {
case newGrant == oldGrant:
// Nothing changed
case newGrant && !oldGrant, // Getting WITH GRANT OPTION priv
!newGrant && oldGrant: // Loosing WITH GRANT OPTION priv
withGrant = true
}
role := d.Get(schemaPolicyRoleAttr).(string)
if strings.ToUpper(role) != "PUBLIC" {
role = pq.QuoteIdentifier(role)
}
schema := d.Get(schemaPolicySchemaAttr).(string)
b := &bytes.Buffer{}
switch {
case grant:
b = bytes.NewBufferString("GRANT USAGE ON SCHEMA ")
fmt.Fprintf(b, "%s TO %s", pq.QuoteIdentifier(schema), role)
if withGrant {
fmt.Fprint(b, " WITH GRANT OPTION")
}
case revoke:
b = bytes.NewBufferString("REVOKE")
if withGrant {
fmt.Fprint(b, " GRANT OPTION FOR")
}
fmt.Fprintf(b, " USAGE ON SCHEMA %s FROM %s", pq.QuoteIdentifier(schema), role)
}
query := b.String()
if _, err := txn.Query(query); err != nil {
return errwrap.Wrapf("Error updating schema usage privileges: {{err}}", err)
}
return nil
}

View File

@ -1,159 +0,0 @@
package postgresql
import (
"database/sql"
"fmt"
"testing"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccPostgreSQLSchemaPolicy_Basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckPostgreSQLSchemaPolicyDestroy,
Steps: []resource.TestStep{
{
Config: testAccPostgreSQLSchemaPolicyConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckPostgreSQLSchemaPolicyExists("postgresql_schema.test1", "foo"),
resource.TestCheckResourceAttr(
"postgresql_role.dba", "name", "dba"),
resource.TestCheckResourceAttr(
"postgresql_role.app1", "name", "app1"),
resource.TestCheckResourceAttr(
"postgresql_role.app2", "name", "app2"),
resource.TestCheckResourceAttr(
"postgresql_schema.foo", "name", "foo"),
resource.TestCheckResourceAttr(
"postgresql_schema.owner", "name", "dba"),
resource.TestCheckResourceAttr(
"postgresql_schema_policy.foo_allow", "create", "false"),
resource.TestCheckResourceAttr(
"postgresql_schema_policy.foo_allow", "create_with_grant", "true"),
resource.TestCheckResourceAttr(
"postgresql_schema_policy.foo_allow", "usage", "false"),
resource.TestCheckResourceAttr(
"postgresql_schema_policy.foo_allow", "usage_with_grant", "true"),
resource.TestCheckResourceAttr(
"postgresql_schema_policy.foo_allow", "schema", "foo"),
resource.TestCheckResourceAttr(
"postgresql_schema_policy.foo_allow", "role", "app1"),
resource.TestCheckResourceAttr(
"postgresql_schema_policy.foo_deny", "schema", "foo"),
resource.TestCheckResourceAttr(
"postgresql_schema_policy.foo_deny", "role", "app2"),
),
},
},
})
}
func testAccCheckPostgreSQLSchemaPolicyDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*Client)
for _, rs := range s.RootModule().Resources {
if rs.Type != "postgresql_schema" {
continue
}
exists, err := checkSchemaExists(client, rs.Primary.ID)
if err != nil {
return fmt.Errorf("Error checking schema %s", err)
}
if exists {
return fmt.Errorf("Schema still exists after destroy")
}
}
return nil
}
func testAccCheckPostgreSQLSchemaPolicyExists(n string, schemaName string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Resource not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}
actualSchemaName := rs.Primary.Attributes["name"]
if actualSchemaName != schemaName {
return fmt.Errorf("Wrong value for schema name expected %s got %s", schemaName, actualSchemaName)
}
client := testAccProvider.Meta().(*Client)
exists, err := checkSchemaExists(client, rs.Primary.ID)
if err != nil {
return fmt.Errorf("Error checking schema %s", err)
}
if !exists {
return fmt.Errorf("Schema not found")
}
return nil
}
}
func checkSchemaPolicyExists(client *Client, schemaName string) (bool, error) {
conn, err := client.Connect()
if err != nil {
return false, err
}
defer conn.Close()
var _rez string
err = conn.QueryRow("SELECT nspname FROM pg_catalog.pg_namespace WHERE nspname=$1", schemaName).Scan(&_rez)
switch {
case err == sql.ErrNoRows:
return false, nil
case err != nil:
return false, fmt.Errorf("Error reading info about schema: %s", err)
default:
return true, nil
}
}
var testAccPostgreSQLSchemaPolicyConfig = `
resource "postgresql_role" "dba" {
name = "dba"
}
resource "postgresql_role" "app1" {
name = "app1"
# depends_on = ["postgresql_schema_policy.foo_allow"]
}
resource "postgresql_role" "app2" {
name = "app2"
}
resource "postgresql_schema" "foo" {
name = "foo"
owner = "${postgresql_role.dba.name}"
}
resource "postgresql_schema_policy" "foo_allow" {
create_with_grant = true
usage_with_grant = true
schema = "${postgresql_schema.foo.name}"
role = "${postgresql_role.app1.name}"
}
resource "postgresql_schema_policy" "foo_deny" {
schema = "${postgresql_schema.foo.name}"
role = "${postgresql_role.app2.name}"
}
`

View File

@ -19,18 +19,142 @@ func TestAccPostgresqlSchema_Basic(t *testing.T) {
Config: testAccPostgresqlSchemaConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckPostgresqlSchemaExists("postgresql_schema.test1", "foo"),
resource.TestCheckResourceAttr(
"postgresql_role.myrole3", "name", "myrole3"),
resource.TestCheckResourceAttr(
"postgresql_role.myrole3", "login", "true"),
resource.TestCheckResourceAttr("postgresql_role.role_all_without_grant", "name", "role_all_without_grant"),
resource.TestCheckResourceAttr("postgresql_role.role_all_without_grant", "login", "true"),
resource.TestCheckResourceAttr(
"postgresql_schema.test1", "name", "foo"),
resource.TestCheckResourceAttr("postgresql_role.role_all_with_grant", "name", "role_all_with_grant"),
resource.TestCheckResourceAttr(
"postgresql_schema.test2", "name", "bar"),
resource.TestCheckResourceAttr(
"postgresql_schema.test2", "owner", "myrole3"),
resource.TestCheckResourceAttr("postgresql_schema.test1", "name", "foo"),
resource.TestCheckResourceAttr("postgresql_schema.test2", "name", "bar"),
resource.TestCheckResourceAttr("postgresql_schema.test2", "owner", "role_all_without_grant"),
resource.TestCheckResourceAttr("postgresql_schema.test2", "if_not_exists", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test2", "policy.#", "1"),
resource.TestCheckResourceAttr("postgresql_schema.test2", "policy.1948480595.create", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test2", "policy.1948480595.create_with_grant", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test2", "policy.1948480595.usage", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test2", "policy.1948480595.usage_with_grant", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test2", "policy.1948480595.role", "role_all_without_grant"),
resource.TestCheckResourceAttr("postgresql_schema.test3", "name", "baz"),
resource.TestCheckResourceAttr("postgresql_schema.test3", "owner", "role_all_without_grant"),
resource.TestCheckResourceAttr("postgresql_schema.test3", "if_not_exists", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test3", "policy.#", "2"),
resource.TestCheckResourceAttr("postgresql_schema.test3", "policy.1013320538.create_with_grant", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test3", "policy.1013320538.usage_with_grant", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test3", "policy.1013320538.role", "role_all_with_grant"),
resource.TestCheckResourceAttr("postgresql_schema.test3", "policy.1948480595.create", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test3", "policy.1948480595.usage", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test3", "policy.1948480595.role", "role_all_without_grant"),
),
},
},
})
}
func TestAccPostgresqlSchema_AddPolicy(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckPostgresqlSchemaDestroy,
Steps: []resource.TestStep{
{
Config: testAccPostgresqlSchemaGrant1,
Check: resource.ComposeTestCheckFunc(
testAccCheckPostgresqlSchemaExists("postgresql_schema.test4", "test4"),
resource.TestCheckResourceAttr("postgresql_role.all_without_grant_stay", "name", "all_without_grant_stay"),
resource.TestCheckResourceAttr("postgresql_role.all_without_grant_drop", "name", "all_without_grant_drop"),
resource.TestCheckResourceAttr("postgresql_role.policy_compose", "name", "policy_compose"),
resource.TestCheckResourceAttr("postgresql_role.policy_move", "name", "policy_move"),
resource.TestCheckResourceAttr("postgresql_role.all_with_grantstay", "name", "all_with_grantstay"),
resource.TestCheckResourceAttr("postgresql_role.all_with_grantdrop", "name", "all_with_grantdrop"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "name", "test4"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "owner", "all_without_grant_stay"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.#", "7"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.108605972.create", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.108605972.create_with_grant", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.108605972.role", "all_with_grantstay"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.108605972.usage", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.108605972.usage_with_grant", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.1417738359.create", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.1417738359.create_with_grant", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.1417738359.role", "policy_move"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.1417738359.usage", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.1417738359.usage_with_grant", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.1762357194.create", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.1762357194.create_with_grant", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.1762357194.role", "all_without_grant_drop"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.1762357194.usage", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.1762357194.usage_with_grant", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.2524457447.create", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.2524457447.create_with_grant", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.2524457447.role", "all_without_grant_stay"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.2524457447.usage", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.2524457447.usage_with_grant", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.3959936977.create", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.3959936977.create_with_grant", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.3959936977.role", "policy_compose"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.3959936977.usage", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.3959936977.usage_with_grant", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.4178211897.create", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.4178211897.create_with_grant", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.4178211897.role", "all_with_grantdrop"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.4178211897.usage", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.4178211897.usage_with_grant", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.815478369.create", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.815478369.create_with_grant", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.815478369.role", "policy_compose"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.815478369.usage", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.815478369.usage_with_grant", "false"),
),
},
{
Config: testAccPostgresqlSchemaGrant2,
Check: resource.ComposeTestCheckFunc(
testAccCheckPostgresqlSchemaExists("postgresql_schema.test4", "test4"),
resource.TestCheckResourceAttr("postgresql_role.all_without_grant_stay", "name", "all_without_grant_stay"),
resource.TestCheckResourceAttr("postgresql_role.all_without_grant_drop", "name", "all_without_grant_drop"),
resource.TestCheckResourceAttr("postgresql_role.policy_compose", "name", "policy_compose"),
resource.TestCheckResourceAttr("postgresql_role.policy_move", "name", "policy_move"),
resource.TestCheckResourceAttr("postgresql_role.all_with_grantstay", "name", "all_with_grantstay"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "name", "test4"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "owner", "all_without_grant_stay"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.#", "6"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.108605972.create", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.108605972.create_with_grant", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.108605972.role", "all_with_grantstay"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.108605972.usage", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.108605972.usage_with_grant", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.2524457447.create", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.2524457447.create_with_grant", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.2524457447.role", "all_without_grant_stay"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.2524457447.usage", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.2524457447.usage_with_grant", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.3831594020.create", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.3831594020.create_with_grant", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.3831594020.role", "policy_move"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.3831594020.usage", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.3831594020.usage_with_grant", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.3959936977.create", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.3959936977.create_with_grant", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.3959936977.role", "policy_compose"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.3959936977.usage", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.3959936977.usage_with_grant", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.468685299.create", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.468685299.create_with_grant", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.468685299.role", "policy_new"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.468685299.usage", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.468685299.usage_with_grant", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.815478369.create", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.815478369.create_with_grant", "false"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.815478369.role", "policy_compose"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.815478369.usage", "true"),
resource.TestCheckResourceAttr("postgresql_schema.test4", "policy.815478369.usage_with_grant", "false"),
),
},
},
@ -108,18 +232,187 @@ func checkSchemaExists(client *Client, schemaName string) (bool, error) {
}
}
var testAccPostgresqlSchemaConfig = `
resource "postgresql_role" "myrole3" {
name = "myrole3"
const testAccPostgresqlSchemaConfig = `
resource "postgresql_role" "role_all_without_grant" {
name = "role_all_without_grant"
login = true
}
resource "postgresql_role" "role_all_with_grant" {
name = "role_all_with_grant"
}
resource "postgresql_schema" "test1" {
name = "foo"
}
resource "postgresql_schema" "test2" {
name = "bar"
owner = "${postgresql_role.myrole3.name}"
owner = "${postgresql_role.role_all_without_grant.name}"
if_not_exists = false
policy {
create = true
usage = true
role = "${postgresql_role.role_all_without_grant.name}"
}
}
resource "postgresql_schema" "test3" {
name = "baz"
owner = "${postgresql_role.role_all_without_grant.name}"
if_not_exists = true
policy {
create_with_grant = true
usage_with_grant = true
role = "${postgresql_role.role_all_with_grant.name}"
}
policy {
create = true
usage = true
role = "${postgresql_role.role_all_without_grant.name}"
}
}
`
const testAccPostgresqlSchemaGrant1 = `
resource "postgresql_role" "all_without_grant_stay" {
name = "all_without_grant_stay"
}
resource "postgresql_role" "all_without_grant_drop" {
name = "all_without_grant_drop"
}
resource "postgresql_role" "policy_compose" {
name = "policy_compose"
}
resource "postgresql_role" "policy_move" {
name = "policy_move"
}
resource "postgresql_role" "all_with_grantstay" {
name = "all_with_grantstay"
}
resource "postgresql_role" "all_with_grantdrop" {
name = "all_with_grantdrop"
}
resource "postgresql_schema" "test4" {
name = "test4"
owner = "${postgresql_role.all_without_grant_stay.name}"
policy {
create = true
usage = true
role = "${postgresql_role.all_without_grant_stay.name}"
}
policy {
create = true
usage = true
role = "${postgresql_role.all_without_grant_drop.name}"
}
policy {
create = true
usage = true
role = "${postgresql_role.policy_compose.name}"
}
policy {
create = true
usage = true
role = "${postgresql_role.policy_move.name}"
}
policy {
create_with_grant = true
usage_with_grant = true
role = "${postgresql_role.all_with_grantstay.name}"
}
policy {
create_with_grant = true
usage_with_grant = true
role = "${postgresql_role.all_with_grantdrop.name}"
}
policy {
create_with_grant = true
usage_with_grant = true
role = "${postgresql_role.policy_compose.name}"
}
}
`
const testAccPostgresqlSchemaGrant2 = `
resource "postgresql_role" "all_without_grant_stay" {
name = "all_without_grant_stay"
}
resource "postgresql_role" "all_without_grant_drop" {
name = "all_without_grant_drop"
}
resource "postgresql_role" "policy_compose" {
name = "policy_compose"
}
resource "postgresql_role" "policy_move" {
name = "policy_move"
}
resource "postgresql_role" "all_with_grantstay" {
name = "all_with_grantstay"
}
resource "postgresql_role" "policy_new" {
name = "policy_new"
}
resource "postgresql_schema" "test4" {
name = "test4"
owner = "${postgresql_role.all_without_grant_stay.name}"
policy {
create = true
usage = true
role = "${postgresql_role.all_without_grant_stay.name}"
}
policy {
create = true
usage = true
role = "${postgresql_role.policy_compose.name}"
}
policy {
create_with_grant = true
usage_with_grant = true
role = "${postgresql_role.all_with_grantstay.name}"
}
policy {
create_with_grant = true
usage_with_grant = true
role = "${postgresql_role.policy_compose.name}"
}
policy {
create_with_grant = true
usage_with_grant = true
role = "${postgresql_role.policy_move.name}"
}
policy {
create = true
usage = true
role = "${postgresql_role.policy_new.name}"
}
}
`