Flesh out the CREATE DATABASE for PostgreSQL.
This commit is contained in:
parent
2aee081e4b
commit
f3add9e7ef
|
@ -21,13 +21,61 @@ func resourcePostgreSQLDatabase() *schema.Resource {
|
||||||
"name": {
|
"name": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Required: true,
|
Required: true,
|
||||||
ForceNew: true,
|
|
||||||
},
|
},
|
||||||
"owner": {
|
"owner": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
},
|
},
|
||||||
|
"template": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Description: "The name of the template from which to create the new database.",
|
||||||
|
},
|
||||||
|
"encoding": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Character set encoding to use in the new database.",
|
||||||
|
},
|
||||||
|
"lc_collate": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Collation order (LC_COLLATE) to use in the new database.",
|
||||||
|
},
|
||||||
|
"lc_ctype": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Character classification (LC_CTYPE) to use in the new database.",
|
||||||
|
},
|
||||||
|
"tablespace_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Description: "The name of the tablespace that will be associated with the new database.",
|
||||||
|
},
|
||||||
|
"connection_limit": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "How many concurrent connections can be made to this database.",
|
||||||
|
ValidateFunc: func(v interface{}, key string) (warnings []string, errors []error) {
|
||||||
|
value := v.(int)
|
||||||
|
if value < -1 {
|
||||||
|
errors = append(errors, fmt.Errorf("%d can not be less than -1", key))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"allow_connections": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: true,
|
||||||
|
Description: "If false then no one can connect to this database.",
|
||||||
|
},
|
||||||
|
"is_template": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
Description: "If true, then this database can be cloned by any user with CREATEDB privileges.",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,24 +88,85 @@ func resourcePostgreSQLDatabaseCreate(d *schema.ResourceData, meta interface{})
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
dbName := d.Get("name").(string)
|
|
||||||
dbOwner := d.Get("owner").(string)
|
|
||||||
connUsername := client.username
|
connUsername := client.username
|
||||||
|
|
||||||
var dbOwnerCfg string
|
const numOptions = 9
|
||||||
if dbOwner != "" {
|
createOpts := make([]string, 0, numOptions)
|
||||||
dbOwnerCfg = fmt.Sprintf("WITH OWNER=%s", pq.QuoteIdentifier(dbOwner))
|
|
||||||
} else {
|
stringOpts := []struct {
|
||||||
dbOwnerCfg = ""
|
hclKey string
|
||||||
|
sqlKey string
|
||||||
|
}{
|
||||||
|
{"owner", "OWNER"},
|
||||||
|
{"template", "TEMPLATE"},
|
||||||
|
{"encoding", "ENCODING"},
|
||||||
|
{"lc_collate", "LC_COLLATE"},
|
||||||
|
{"lc_ctype", "LC_CTYPE"},
|
||||||
|
{"tablespace_name", "TABLESPACE"},
|
||||||
|
}
|
||||||
|
for _, opt := range stringOpts {
|
||||||
|
v, ok := d.GetOk(opt.hclKey)
|
||||||
|
var val string
|
||||||
|
if !ok {
|
||||||
|
// Set the owner to the connection username
|
||||||
|
if opt.hclKey == "owner" && v.(string) == "" {
|
||||||
|
val = connUsername
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val = v.(string)
|
||||||
|
|
||||||
|
// Set the owner to the connection username
|
||||||
|
if opt.hclKey == "owner" && val == "" {
|
||||||
|
val = connUsername
|
||||||
|
}
|
||||||
|
|
||||||
|
if val != "" {
|
||||||
|
createOpts = append(createOpts, fmt.Sprintf("%s=%s", opt.sqlKey, pq.QuoteIdentifier(val)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//needed in order to set the owner of the db if the connection user is not a superuser
|
intOpts := []struct {
|
||||||
err = grantRoleMembership(conn, dbOwner, connUsername)
|
hclKey string
|
||||||
if err != nil {
|
sqlKey string
|
||||||
return err
|
}{
|
||||||
|
{"connection_limit", "CONNECTION LIMIT"},
|
||||||
|
}
|
||||||
|
for _, opt := range intOpts {
|
||||||
|
v, ok := d.GetOk(opt.hclKey)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val := v.(int)
|
||||||
|
createOpts = append(createOpts, fmt.Sprintf("%s=%d", opt.sqlKey, val))
|
||||||
}
|
}
|
||||||
|
|
||||||
query := fmt.Sprintf("CREATE DATABASE %s %s", pq.QuoteIdentifier(dbName), dbOwnerCfg)
|
boolOpts := []struct {
|
||||||
|
hclKey string
|
||||||
|
sqlKey string
|
||||||
|
}{
|
||||||
|
{"allow_connections", "ALLOW_CONNECTIONS"},
|
||||||
|
{"is_template", "IS_TEMPLATE"},
|
||||||
|
}
|
||||||
|
for _, opt := range boolOpts {
|
||||||
|
v, ok := d.GetOk(opt.hclKey)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val := v.(bool)
|
||||||
|
createOpts = append(createOpts, fmt.Sprintf("%s=%t", opt.sqlKey, val))
|
||||||
|
}
|
||||||
|
|
||||||
|
dbName := d.Get("name").(string)
|
||||||
|
createStr := strings.Join(createOpts, " ")
|
||||||
|
if len(createOpts) > 0 {
|
||||||
|
createStr = " WITH " + createStr
|
||||||
|
}
|
||||||
|
query := fmt.Sprintf("CREATE DATABASE %s%s", pq.QuoteIdentifier(dbName), createStr)
|
||||||
_, err = conn.Query(query)
|
_, err = conn.Query(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errwrap.Wrapf(fmt.Sprintf("Error creating database %s: {{err}}", dbName), err)
|
return errwrap.Wrapf(fmt.Sprintf("Error creating database %s: {{err}}", dbName), err)
|
||||||
|
|
|
@ -6,19 +6,19 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/helper/resource"
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAccPostgresqlDatabase_Basic(t *testing.T) {
|
func TestAccPostgresqlDatabase_Basic(t *testing.T) {
|
||||||
|
|
||||||
resource.Test(t, resource.TestCase{
|
resource.Test(t, resource.TestCase{
|
||||||
PreCheck: func() { testAccPreCheck(t) },
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
Providers: testAccProviders,
|
Providers: testAccProviders,
|
||||||
CheckDestroy: testAccCheckPostgresqlDatabaseDestroy,
|
CheckDestroy: testAccCheckPostgresqlDatabaseDestroy,
|
||||||
Steps: []resource.TestStep{
|
Steps: []resource.TestStep{
|
||||||
{
|
{
|
||||||
Config: testAccPostgresqlDatabaseConfig,
|
Config: testAccPostgreSQLDatabaseConfig,
|
||||||
Check: resource.ComposeTestCheckFunc(
|
Check: resource.ComposeTestCheckFunc(
|
||||||
testAccCheckPostgresqlDatabaseExists("postgresql_database.mydb"),
|
testAccCheckPostgresqlDatabaseExists("postgresql_database.mydb"),
|
||||||
resource.TestCheckResourceAttr(
|
resource.TestCheckResourceAttr(
|
||||||
|
@ -32,14 +32,13 @@ func TestAccPostgresqlDatabase_Basic(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAccPostgresqlDatabase_DefaultOwner(t *testing.T) {
|
func TestAccPostgresqlDatabase_DefaultOwner(t *testing.T) {
|
||||||
|
|
||||||
resource.Test(t, resource.TestCase{
|
resource.Test(t, resource.TestCase{
|
||||||
PreCheck: func() { testAccPreCheck(t) },
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
Providers: testAccProviders,
|
Providers: testAccProviders,
|
||||||
CheckDestroy: testAccCheckPostgresqlDatabaseDestroy,
|
CheckDestroy: testAccCheckPostgresqlDatabaseDestroy,
|
||||||
Steps: []resource.TestStep{
|
Steps: []resource.TestStep{
|
||||||
{
|
{
|
||||||
Config: testAccPostgresqlDatabaseConfig,
|
Config: testAccPostgreSQLDatabaseConfig,
|
||||||
Check: resource.ComposeTestCheckFunc(
|
Check: resource.ComposeTestCheckFunc(
|
||||||
testAccCheckPostgresqlDatabaseExists("postgresql_database.mydb_default_owner"),
|
testAccCheckPostgresqlDatabaseExists("postgresql_database.mydb_default_owner"),
|
||||||
resource.TestCheckResourceAttr(
|
resource.TestCheckResourceAttr(
|
||||||
|
@ -119,7 +118,7 @@ func checkDatabaseExists(client *Client, dbName string) (bool, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var testAccPostgresqlDatabaseConfig = `
|
var testAccPostgreSQLDatabaseConfig = `
|
||||||
resource "postgresql_role" "myrole" {
|
resource "postgresql_role" "myrole" {
|
||||||
name = "myrole"
|
name = "myrole"
|
||||||
login = true
|
login = true
|
||||||
|
@ -135,6 +134,19 @@ resource "postgresql_database" "mydb2" {
|
||||||
owner = "${postgresql_role.myrole.name}"
|
owner = "${postgresql_role.myrole.name}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resource "postgresql_database" "mydb3" {
|
||||||
|
name = "mydb3"
|
||||||
|
owner = "${postgresql_role.myrole.name}"
|
||||||
|
template = "template1"
|
||||||
|
encoding = "SQL_ASCII"
|
||||||
|
lc_collate = "C"
|
||||||
|
lc_ctype = "C"
|
||||||
|
tablespace_name = "pg_default"
|
||||||
|
connection_limit = -1
|
||||||
|
allow_connections = false
|
||||||
|
is_template = false
|
||||||
|
}
|
||||||
|
|
||||||
resource "postgresql_database" "mydb_default_owner" {
|
resource "postgresql_database" "mydb_default_owner" {
|
||||||
name = "mydb_default_owner"
|
name = "mydb_default_owner"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue