remote-state/pg: add option to skip schema creation (#21607)
* add `skip_schema_creation` option * add sanity check to avoid situations where postgres users hasn't been granted the "CREATE SCHEMA" right closes #21604 Signed-off-by: yann degat <yann@2kmail.net>
This commit is contained in:
parent
c93b0199f3
commit
be5280e4e1
|
@ -31,6 +31,13 @@ func New() backend.Backend {
|
||||||
Description: "Name of the automatically managed Postgres schema to store state",
|
Description: "Name of the automatically managed Postgres schema to store state",
|
||||||
Default: "terraform_remote_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,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,10 +71,26 @@ func (b *Backend) configure(ctx context.Context) error {
|
||||||
|
|
||||||
// Prepare database schema, tables, & indexes.
|
// Prepare database schema, tables, & indexes.
|
||||||
var query string
|
var query string
|
||||||
|
|
||||||
|
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`
|
query = `CREATE SCHEMA IF NOT EXISTS %s`
|
||||||
if _, err := db.Exec(fmt.Sprintf(query, b.schemaName)); err != nil {
|
if _, err := db.Exec(fmt.Sprintf(query, b.schemaName)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
query = `CREATE TABLE IF NOT EXISTS %s.%s (
|
query = `CREATE TABLE IF NOT EXISTS %s.%s (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
name TEXT,
|
name TEXT,
|
||||||
|
|
|
@ -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) {
|
func TestBackendStates(t *testing.T) {
|
||||||
testACC(t)
|
testACC(t)
|
||||||
connStr := getDatabaseUrl()
|
connStr := getDatabaseUrl()
|
||||||
|
|
|
@ -71,6 +71,7 @@ The following configuration options or environment variables are supported:
|
||||||
|
|
||||||
* `conn_str` - (Required) Postgres connection string; a `postgres://` URL
|
* `conn_str` - (Required) Postgres connection string; a `postgres://` URL
|
||||||
* `schema_name` - Name of the automatically-managed Postgres schema, default `terraform_remote_state`.
|
* `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
|
## Technical Design
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue