terraform/builtin/providers/postgresql/resource_postgresql_databas...

161 lines
4.0 KiB
Go

package postgresql
import (
"database/sql"
"fmt"
"strings"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/terraform/helper/schema"
"github.com/lib/pq"
)
func resourcePostgreSQLDatabase() *schema.Resource {
return &schema.Resource{
Create: resourcePostgreSQLDatabaseCreate,
Read: resourcePostgreSQLDatabaseRead,
Update: resourcePostgreSQLDatabaseUpdate,
Delete: resourcePostgreSQLDatabaseDelete,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"owner": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
},
}
}
func resourcePostgreSQLDatabaseCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Client)
conn, err := client.Connect()
if err != nil {
return errwrap.Wrapf("Error connecting to PostgreSQL: {{err}}", err)
}
defer conn.Close()
dbName := d.Get("name").(string)
dbOwner := d.Get("owner").(string)
connUsername := client.username
var dbOwnerCfg string
if dbOwner != "" {
dbOwnerCfg = fmt.Sprintf("WITH OWNER=%s", pq.QuoteIdentifier(dbOwner))
} else {
dbOwnerCfg = ""
}
//needed in order to set the owner of the db if the connection user is not a superuser
err = grantRoleMembership(conn, dbOwner, connUsername)
if err != nil {
return err
}
query := fmt.Sprintf("CREATE DATABASE %s %s", pq.QuoteIdentifier(dbName), dbOwnerCfg)
_, err = conn.Query(query)
if err != nil {
return errwrap.Wrapf(fmt.Sprintf("Error creating database %s: {{err}}", dbName), err)
}
d.SetId(dbName)
return resourcePostgreSQLDatabaseRead(d, meta)
}
func resourcePostgreSQLDatabaseDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Client)
conn, err := client.Connect()
if err != nil {
return errwrap.Wrapf("Error connecting to PostgreSQL: {{err}}", err)
}
defer conn.Close()
dbName := d.Get("name").(string)
connUsername := client.username
dbOwner := d.Get("owner").(string)
//needed in order to set the owner of the db if the connection user is not a superuser
err = grantRoleMembership(conn, dbOwner, connUsername)
if err != nil {
return err
}
query := fmt.Sprintf("DROP DATABASE %s", pq.QuoteIdentifier(dbName))
_, err = conn.Query(query)
if err != nil {
return errwrap.Wrapf("Error dropping database: {{err}}", err)
}
d.SetId("")
return nil
}
func resourcePostgreSQLDatabaseRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Client)
conn, err := client.Connect()
if err != nil {
return err
}
defer conn.Close()
dbName := d.Get("name").(string)
var owner string
err = conn.QueryRow("SELECT pg_catalog.pg_get_userbyid(d.datdba) from pg_database d WHERE datname=$1", dbName).Scan(&owner)
switch {
case err == sql.ErrNoRows:
d.SetId("")
return nil
case err != nil:
return errwrap.Wrapf("Error reading database: {{err}}", err)
default:
d.Set("owner", owner)
return nil
}
}
func resourcePostgreSQLDatabaseUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Client)
conn, err := client.Connect()
if err != nil {
return err
}
defer conn.Close()
dbName := d.Get("name").(string)
if d.HasChange("owner") {
owner := d.Get("owner").(string)
if owner != "" {
query := fmt.Sprintf("ALTER DATABASE %s OWNER TO %s", pq.QuoteIdentifier(dbName), pq.QuoteIdentifier(owner))
_, err := conn.Query(query)
if err != nil {
return errwrap.Wrapf("Error updating owner: {{err}}", err)
}
}
}
return resourcePostgreSQLDatabaseRead(d, meta)
}
func grantRoleMembership(conn *sql.DB, dbOwner string, connUsername string) error {
if dbOwner != "" && dbOwner != connUsername {
query := fmt.Sprintf("GRANT %s TO %s", pq.QuoteIdentifier(dbOwner), pq.QuoteIdentifier(connUsername))
_, err := conn.Query(query)
if err != nil {
//is already member or role
if strings.Contains(err.Error(), "duplicate key value violates unique constraint") {
return nil
}
return errwrap.Wrapf("Error granting membership: {{err}}", err)
}
}
return nil
}