Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

remote-state/pg: skip schema creation instruction if exists #21607

Merged
merged 1 commit into from
Aug 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions backend/remote-state/pg/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ func New() backend.Backend {
Description: "Name of the automatically managed Postgres schema to store state",
Default: "terraform_remote_state",
},

"skip_schema_creation": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Description: "If set to `true`, Terraform won't try to create the Postgres schema",
Default: false,
},
},
}

Expand Down Expand Up @@ -64,9 +71,25 @@ func (b *Backend) configure(ctx context.Context) error {

// Prepare database schema, tables, & indexes.
var query string
query = `CREATE SCHEMA IF NOT EXISTS %s`
if _, err := db.Exec(fmt.Sprintf(query, b.schemaName)); err != nil {
return err

if !data.Get("skip_schema_creation").(bool) {
// list all schemas to see if it exists
var count int
query = `select count(1) from information_schema.schemata where lower(schema_name) = lower('%s')`
if err := db.QueryRow(fmt.Sprintf(query, b.schemaName)).Scan(&count); err != nil {
return err
}

// skip schema creation if schema already exists
// `CREATE SCHEMA IF NOT EXISTS` is to be avoided if ever
// a user hasn't been granted the `CREATE SCHEMA` privilege
if count < 1 {
// tries to create the schema
query = `CREATE SCHEMA IF NOT EXISTS %s`
if _, err := db.Exec(fmt.Sprintf(query, b.schemaName)); err != nil {
return err
}
}
}
query = `CREATE TABLE IF NOT EXISTS %s.%s (
id SERIAL PRIMARY KEY,
Expand Down
44 changes: 44 additions & 0 deletions backend/remote-state/pg/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,50 @@ func TestBackendConfig(t *testing.T) {
}
}

func TestBackendConfigSkipSchema(t *testing.T) {
testACC(t)
connStr := getDatabaseUrl()
schemaName := fmt.Sprintf("terraform_%s", t.Name())
db, err := sql.Open("postgres", connStr)
if err != nil {
t.Fatal(err)
}

// create the schema as a prerequisites
db.Query(fmt.Sprintf("CREATE SCHEMA IF NOT EXISTS %s", schemaName))
defer db.Query(fmt.Sprintf("DROP SCHEMA IF EXISTS %s CASCADE", schemaName))

config := backend.TestWrapConfig(map[string]interface{}{
"conn_str": connStr,
"schema_name": schemaName,
"skip_schema_creation": true,
})
b := backend.TestBackendConfig(t, New(), config).(*Backend)

if b == nil {
t.Fatal("Backend could not be configured")
}

_, err = b.db.Query(fmt.Sprintf("SELECT name, data FROM %s.%s LIMIT 1", schemaName, statesTableName))
if err != nil {
t.Fatal(err)
}

_, err = b.StateMgr(backend.DefaultStateName)
if err != nil {
t.Fatal(err)
}

s, err := b.StateMgr(backend.DefaultStateName)
if err != nil {
t.Fatal(err)
}
c := s.(*remote.State).Client.(*RemoteClient)
if c.Name != backend.DefaultStateName {
t.Fatal("RemoteClient name is not configured")
}
}

func TestBackendStates(t *testing.T) {
testACC(t)
connStr := getDatabaseUrl()
Expand Down
3 changes: 2 additions & 1 deletion website/docs/backends/types/pg.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ The following configuration options or environment variables are supported:

* `conn_str` - (Required) Postgres connection string; a `postgres://` URL
* `schema_name` - Name of the automatically-managed Postgres schema, default `terraform_remote_state`.

* `skip_schema_creation` - If set to `true`, the Postgres schema must already exist. Terraform won't try to create the schema. Useful when the Postgres user does not have "create schema" permission on the database.

## Technical Design

Postgres version 9.5 or newer is required to support advisory locks and the "ON CONFLICT" upsert syntax.
Expand Down