Update the postgresql_schema resource to accept policies.
It is now possible to begin specifying DCL for schemas.
This commit is contained in:
parent
fab7bd3daf
commit
38928b91ba
|
@ -67,7 +67,6 @@ func Provider() terraform.ResourceProvider {
|
|||
"postgresql_database": resourcePostgreSQLDatabase(),
|
||||
"postgresql_extension": resourcePostgreSQLExtension(),
|
||||
"postgresql_schema": resourcePostgreSQLSchema(),
|
||||
"postgresql_schema_policy": resourcePostgreSQLSchemaPolicy(),
|
||||
"postgresql_role": resourcePostgreSQLRole(),
|
||||
},
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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}"
|
||||
}
|
||||
`
|
|
@ -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}"
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
Loading…
Reference in New Issue