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

backend/pg: Stop using legacy helper/schema #34987

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
142 changes: 71 additions & 71 deletions internal/backend/remote-state/pg/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,110 +4,110 @@
package pg

import (
"context"
"database/sql"
"fmt"
"os"
"strconv"

"github.com/hashicorp/terraform/internal/backend"
"github.com/hashicorp/terraform/internal/legacy/helper/schema"
"github.com/lib/pq"
"github.com/zclconf/go-cty/cty"

"github.com/hashicorp/terraform/internal/backend"
"github.com/hashicorp/terraform/internal/backend/backendbase"
"github.com/hashicorp/terraform/internal/configs/configschema"
"github.com/hashicorp/terraform/internal/tfdiags"
)

const (
statesTableName = "states"
statesIndexName = "states_by_name"
)

func defaultBoolFunc(k string, dv bool) schema.SchemaDefaultFunc {
return func() (interface{}, error) {
if v := os.Getenv(k); v != "" {
return strconv.ParseBool(v)
}

return dv, nil
}
}

// New creates a new backend for Postgres remote state.
func New() backend.Backend {
s := &schema.Backend{
Schema: map[string]*schema.Schema{
"conn_str": {
Type: schema.TypeString,
Optional: true,
Description: "Postgres connection string; a `postgres://` URL",
DefaultFunc: schema.EnvDefaultFunc("PG_CONN_STR", nil),
return &Backend{
Base: backendbase.Base{
Schema: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"conn_str": {
Type: cty.String,
Optional: true,
Description: "Postgres connection string; a `postgres://` URL",
},
"schema_name": {
Type: cty.String,
Optional: true,
Description: "Name of the automatically managed Postgres schema to store state",
},
"skip_schema_creation": {
Type: cty.Bool,
Optional: true,
Description: "If set to `true`, Terraform won't try to create the Postgres schema",
},
"skip_table_creation": {
Type: cty.Bool,
Optional: true,
Description: "If set to `true`, Terraform won't try to create the Postgres table",
},
"skip_index_creation": {
Type: cty.Bool,
Optional: true,
Description: "If set to `true`, Terraform won't try to create the Postgres index",
},
},
},

"schema_name": {
Type: schema.TypeString,
Optional: true,
Description: "Name of the automatically managed Postgres schema to store state",
DefaultFunc: schema.EnvDefaultFunc("PG_SCHEMA_NAME", "terraform_remote_state"),
},

"skip_schema_creation": {
Type: schema.TypeBool,
Optional: true,
Description: "If set to `true`, Terraform won't try to create the Postgres schema",
DefaultFunc: defaultBoolFunc("PG_SKIP_SCHEMA_CREATION", false),
},

"skip_table_creation": {
Type: schema.TypeBool,
Optional: true,
Description: "If set to `true`, Terraform won't try to create the Postgres table",
DefaultFunc: defaultBoolFunc("PG_SKIP_TABLE_CREATION", false),
},

"skip_index_creation": {
Type: schema.TypeBool,
Optional: true,
Description: "If set to `true`, Terraform won't try to create the Postgres index",
DefaultFunc: defaultBoolFunc("PG_SKIP_INDEX_CREATION", false),
SDKLikeDefaults: backendbase.SDKLikeDefaults{
"conn_str": {
EnvVars: []string{"PG_CONN_STR"},
},
"schema_name": {
EnvVars: []string{"PG_SCHEMA_NAME"},
Fallback: "terraform_remote_state",
},
"skip_schema_creation": {
EnvVars: []string{"PG_SKIP_SCHEMA_CREATION"},
Fallback: "false",
},
"skip_table_creation": {
EnvVars: []string{"PG_SKIP_TABLE_CREATION"},
Fallback: "false",
},
"skip_index_creation": {
EnvVars: []string{"PG_SKIP_INDEX_CREATION"},
Fallback: "false",
},
},
},
}

result := &Backend{Backend: s}
result.Backend.ConfigureFunc = result.configure
return result
}

type Backend struct {
*schema.Backend
backendbase.Base

// The fields below are set from configure
db *sql.DB
configData *schema.ResourceData
connStr string
schemaName string
}

func (b *Backend) configure(ctx context.Context) error {
// Grab the resource data
b.configData = schema.FromContextBackendConfig(ctx)
data := b.configData
func (b *Backend) Configure(configVal cty.Value) tfdiags.Diagnostics {
data := backendbase.NewSDKLikeData(configVal)

b.connStr = data.Get("conn_str").(string)
b.schemaName = pq.QuoteIdentifier(data.Get("schema_name").(string))
b.connStr = data.String("conn_str")
b.schemaName = pq.QuoteIdentifier(data.String("schema_name"))

db, err := sql.Open("postgres", b.connStr)
if err != nil {
return err
return backendbase.ErrorAsDiagnostics(err)
}

// Prepare database schema, tables, & indexes.
var query string

if !data.Get("skip_schema_creation").(bool) {
if !data.Bool("skip_schema_creation") {
// list all schemas to see if it exists
var count int
query = `select count(1) from information_schema.schemata where schema_name = $1`
if err := db.QueryRow(query, data.Get("schema_name").(string)).Scan(&count); err != nil {
return err
if err := db.QueryRow(query, data.String("schema_name")).Scan(&count); err != nil {
return backendbase.ErrorAsDiagnostics(err)
}

// skip schema creation if schema already exists
Expand All @@ -117,14 +117,14 @@ func (b *Backend) configure(ctx context.Context) error {
// 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
return backendbase.ErrorAsDiagnostics(err)
}
}
}

if !data.Get("skip_table_creation").(bool) {
if !data.Bool("skip_table_creation") {
if _, err := db.Exec("CREATE SEQUENCE IF NOT EXISTS public.global_states_id_seq AS bigint"); err != nil {
return err
return backendbase.ErrorAsDiagnostics(err)
}

query = `CREATE TABLE IF NOT EXISTS %s.%s (
Expand All @@ -133,14 +133,14 @@ func (b *Backend) configure(ctx context.Context) error {
data text
)`
if _, err := db.Exec(fmt.Sprintf(query, b.schemaName, statesTableName)); err != nil {
return err
return backendbase.ErrorAsDiagnostics(err)
}
}

if !data.Get("skip_index_creation").(bool) {
if !data.Bool("skip_index_creation") {
query = `CREATE UNIQUE INDEX IF NOT EXISTS %s ON %s.%s (name)`
if _, err := db.Exec(fmt.Sprintf(query, statesIndexName, b.schemaName, statesTableName)); err != nil {
return err
return backendbase.ErrorAsDiagnostics(err)
}
}

Expand Down
4 changes: 2 additions & 2 deletions internal/backend/remote-state/pg/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func TestBackendConfig(t *testing.T) {
"conn_str": connStr,
"schema_name": fmt.Sprintf("terraform_%s", t.Name()),
},
ExpectConnectionError: `role "baduser" does not exist`,
ExpectConnectionError: `password authentication failed for user "baduser"`,
},
{
Name: "host-in-env-vars",
Expand Down Expand Up @@ -130,7 +130,7 @@ func TestBackendConfig(t *testing.T) {
Config: map[string]interface{}{
"schema_name": fmt.Sprintf("terraform_%s", t.Name()),
},
ExpectConfigurationError: `error getting default for "skip_schema_creation"`,
ExpectConfigurationError: `invalid value for "skip_schema_creation"`,
},
}

Expand Down
6 changes: 1 addition & 5 deletions internal/backend/remote-state/pg/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ require (
github.com/hashicorp/go-uuid v1.0.3
github.com/hashicorp/hcl/v2 v2.20.0
github.com/hashicorp/terraform v0.0.0-00010101000000-000000000000
github.com/hashicorp/terraform/internal/legacy v0.0.0-00010101000000-000000000000
github.com/lib/pq v1.10.3
github.com/zclconf/go-cty v1.14.3
)

require (
Expand All @@ -21,14 +21,10 @@ require (
github.com/hashicorp/terraform-registry-address v0.2.3 // indirect
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/rogpeppe/go-internal v1.10.0 // indirect
github.com/sergi/go-diff v1.2.0 // indirect
github.com/spf13/afero v1.9.3 // indirect
github.com/zclconf/go-cty v1.14.3 // indirect
golang.org/x/mod v0.16.0 // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/sys v0.18.0 // indirect
Expand Down
6 changes: 0 additions & 6 deletions internal/backend/remote-state/pg/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -207,18 +207,12 @@ github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxec
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
Expand Down