backend/pg: Accept connection string in PGDATABASE environment variable

This commit is contained in:
janaurka 2023-04-06 00:42:44 +02:00 committed by GitHub
parent dfbb9c2e10
commit 1f603b1a7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 105 additions and 38 deletions

View File

@ -23,6 +23,7 @@ func New() backend.Backend {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
Description: "Postgres connection string; a `postgres://` URL", Description: "Postgres connection string; a `postgres://` URL",
DefaultFunc: schema.EnvDefaultFunc("PGDATABASE", nil),
}, },
"schema_name": { "schema_name": {

View File

@ -7,13 +7,15 @@ import (
"database/sql" "database/sql"
"fmt" "fmt"
"os" "os"
"strings"
"testing" "testing"
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/terraform/internal/backend" "github.com/hashicorp/terraform/internal/backend"
"github.com/hashicorp/terraform/internal/states/remote" "github.com/hashicorp/terraform/internal/states/remote"
"github.com/hashicorp/terraform/internal/states/statemgr" "github.com/hashicorp/terraform/internal/states/statemgr"
"github.com/hashicorp/terraform/internal/tfdiags"
"github.com/lib/pq" "github.com/lib/pq"
_ "github.com/lib/pq"
) )
// Function to skip a test unless in ACCeptance test mode. // Function to skip a test unless in ACCeptance test mode.
@ -38,46 +40,110 @@ func TestBackend_impl(t *testing.T) {
func TestBackendConfig(t *testing.T) { func TestBackendConfig(t *testing.T) {
testACC(t) testACC(t)
connStr := getDatabaseUrl() connStr := getDatabaseUrl()
schemaName := pq.QuoteIdentifier(fmt.Sprintf("terraform_%s", t.Name()))
config := backend.TestWrapConfig(map[string]interface{}{ testCases := []struct {
"conn_str": connStr, Name string
"schema_name": schemaName, EnvVars map[string]string
}) Config map[string]interface{}
schemaName = pq.QuoteIdentifier(schemaName) ExpectError string
}{
dbCleaner, err := sql.Open("postgres", connStr) {
if err != nil { Name: "valid-config",
t.Fatal(err) Config: map[string]interface{}{
} "conn_str": connStr,
defer dbCleaner.Query(fmt.Sprintf("DROP SCHEMA IF EXISTS %s CASCADE", schemaName)) "schema_name": fmt.Sprintf("terraform_%s", t.Name()),
},
b := backend.TestBackendConfig(t, New(), config).(*Backend) },
{
if b == nil { Name: "missing-conn-str",
t.Fatal("Backend could not be configured") Config: map[string]interface{}{
"schema_name": fmt.Sprintf("terraform_%s", t.Name()),
},
ExpectError: `The attribute "conn_str" is required, but no definition was found.`,
},
{
Name: "conn-str-env-var",
EnvVars: map[string]string{
"PGDATABASE": connStr,
},
Config: map[string]interface{}{
"schema_name": fmt.Sprintf("terraform_%s", t.Name()),
},
},
} }
_, err = b.db.Query(fmt.Sprintf("SELECT name, data FROM %s.%s LIMIT 1", schemaName, statesTableName)) for _, tc := range testCases {
if err != nil { t.Run(tc.Name, func(t *testing.T) {
t.Fatal(err) for k, v := range tc.EnvVars {
t.Setenv(k, v)
}
config := backend.TestWrapConfig(tc.Config)
schemaName := pq.QuoteIdentifier(tc.Config["schema_name"].(string))
dbCleaner, err := sql.Open("postgres", connStr)
if err != nil {
t.Fatal(err)
}
defer dbCleaner.Query(fmt.Sprintf("DROP SCHEMA IF EXISTS %s CASCADE", schemaName))
var diags tfdiags.Diagnostics
b := New().(*Backend)
schema := b.ConfigSchema()
spec := schema.DecoderSpec()
obj, decDiags := hcldec.Decode(config, spec, nil)
diags = diags.Append(decDiags)
newObj, valDiags := b.PrepareConfig(obj)
diags = diags.Append(valDiags.InConfigBody(config, ""))
if tc.ExpectError != "" {
if !diags.HasErrors() {
t.Fatal("error expected but got none")
}
if !strings.Contains(diags.ErrWithWarnings().Error(), tc.ExpectError) {
t.Fatalf("failed to find %q in %s", tc.ExpectError, diags.ErrWithWarnings())
}
return
} else if diags.HasErrors() {
t.Fatal(diags.ErrWithWarnings())
}
obj = newObj
confDiags := b.Configure(obj)
if len(confDiags) != 0 {
confDiags = confDiags.InConfigBody(config, "")
t.Fatal(confDiags.ErrWithWarnings())
}
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")
}
backend.TestBackendStates(t, b)
})
} }
_, 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")
}
backend.TestBackendStates(t, b)
} }
func TestBackendConfigSkipOptions(t *testing.T) { func TestBackendConfigSkipOptions(t *testing.T) {
@ -243,7 +309,7 @@ func TestBackendStates(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer dbCleaner.Query("DROP SCHEMA IF EXISTS %s CASCADE", pq.QuoteIdentifier(schemaName)) defer dbCleaner.Query(fmt.Sprintf("DROP SCHEMA IF EXISTS %s CASCADE", pq.QuoteIdentifier(schemaName)))
config := backend.TestWrapConfig(map[string]interface{}{ config := backend.TestWrapConfig(map[string]interface{}{
"conn_str": connStr, "conn_str": connStr,

View File

@ -68,7 +68,7 @@ data "terraform_remote_state" "network" {
The following configuration options or environment variables are supported: 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. `conn_str` can also be set using the `PGDATABASE` environment variable.
- `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, this is useful when it has already been created by a database administrator. - `skip_schema_creation` - If set to `true`, the Postgres schema must already exist. Terraform won't try to create the schema, this is useful when it has already been created by a database administrator.
- `skip_table_creation` - If set to `true`, the Postgres table must already exist. Terraform won't try to create the table, this is useful when it has already been created by a database administrator. - `skip_table_creation` - If set to `true`, the Postgres table must already exist. Terraform won't try to create the table, this is useful when it has already been created by a database administrator.