mirror of
https://github.com/opentofu/opentofu.git
synced 2025-01-15 19:22:46 -06:00
c814f2da37
This mirrors the change made for providers, so that default values can be inserted into the config by the backend implementation. This is only the interface and method name changes, it does not yet add any default values.
168 lines
4.3 KiB
Go
168 lines
4.3 KiB
Go
package terraform
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
|
|
"github.com/hashicorp/terraform/backend"
|
|
"github.com/hashicorp/terraform/configs/configschema"
|
|
"github.com/hashicorp/terraform/providers"
|
|
"github.com/hashicorp/terraform/tfdiags"
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
backendInit "github.com/hashicorp/terraform/backend/init"
|
|
)
|
|
|
|
func dataSourceRemoteStateGetSchema() providers.Schema {
|
|
return providers.Schema{
|
|
Block: &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"backend": {
|
|
Type: cty.String,
|
|
Required: true,
|
|
},
|
|
"config": {
|
|
Type: cty.DynamicPseudoType,
|
|
Optional: true,
|
|
},
|
|
"defaults": {
|
|
Type: cty.DynamicPseudoType,
|
|
Optional: true,
|
|
},
|
|
"outputs": {
|
|
Type: cty.DynamicPseudoType,
|
|
Computed: true,
|
|
},
|
|
"workspace": {
|
|
Type: cty.String,
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func dataSourceRemoteStateRead(d *cty.Value) (cty.Value, tfdiags.Diagnostics) {
|
|
var diags tfdiags.Diagnostics
|
|
|
|
newState := make(map[string]cty.Value)
|
|
newState["backend"] = d.GetAttr("backend")
|
|
|
|
backendType := d.GetAttr("backend").AsString()
|
|
|
|
// Don't break people using the old _local syntax - but note warning above
|
|
if backendType == "_local" {
|
|
log.Println(`[INFO] Switching old (unsupported) backend "_local" to "local"`)
|
|
backendType = "local"
|
|
}
|
|
|
|
// Create the client to access our remote state
|
|
log.Printf("[DEBUG] Initializing remote state backend: %s", backendType)
|
|
f := backendInit.Backend(backendType)
|
|
if f == nil {
|
|
diags = diags.Append(tfdiags.AttributeValue(
|
|
tfdiags.Error,
|
|
"Invalid backend configuration",
|
|
fmt.Sprintf("Unknown backend type: %s", backendType),
|
|
cty.Path(nil).GetAttr("backend"),
|
|
))
|
|
return cty.NilVal, diags
|
|
}
|
|
b := f()
|
|
|
|
config := d.GetAttr("config")
|
|
if config.IsNull() {
|
|
// We'll treat this as an empty configuration and see if the backend's
|
|
// schema and validation code will accept it.
|
|
config = cty.EmptyObjectVal
|
|
}
|
|
newState["config"] = config
|
|
|
|
schema := b.ConfigSchema()
|
|
// Try to coerce the provided value into the desired configuration type.
|
|
configVal, err := schema.CoerceValue(config)
|
|
if err != nil {
|
|
diags = diags.Append(tfdiags.AttributeValue(
|
|
tfdiags.Error,
|
|
"Invalid backend configuration",
|
|
fmt.Sprintf("The given configuration is not valid for backend %q: %s.", backendType,
|
|
tfdiags.FormatError(err)),
|
|
cty.Path(nil).GetAttr("config"),
|
|
))
|
|
return cty.NilVal, diags
|
|
}
|
|
|
|
newVal, validateDiags := b.PrepareConfig(configVal)
|
|
diags = diags.Append(validateDiags)
|
|
if validateDiags.HasErrors() {
|
|
return cty.NilVal, diags
|
|
}
|
|
configVal = newVal
|
|
|
|
configureDiags := b.Configure(configVal)
|
|
if configureDiags.HasErrors() {
|
|
diags = diags.Append(configureDiags.Err())
|
|
return cty.NilVal, diags
|
|
}
|
|
|
|
name := backend.DefaultStateName
|
|
|
|
if workspaceVal := d.GetAttr("workspace"); !workspaceVal.IsNull() {
|
|
newState["workspace"] = workspaceVal
|
|
name = workspaceVal.AsString()
|
|
}
|
|
|
|
newState["workspace"] = cty.StringVal(name)
|
|
|
|
state, err := b.StateMgr(name)
|
|
if err != nil {
|
|
diags = diags.Append(tfdiags.AttributeValue(
|
|
tfdiags.Error,
|
|
"Error loading state error",
|
|
fmt.Sprintf("error loading the remote state: %s", err),
|
|
cty.Path(nil).GetAttr("backend"),
|
|
))
|
|
return cty.NilVal, diags
|
|
}
|
|
|
|
if err := state.RefreshState(); err != nil {
|
|
diags = diags.Append(err)
|
|
return cty.NilVal, diags
|
|
}
|
|
|
|
outputs := make(map[string]cty.Value)
|
|
|
|
if defaultsVal := d.GetAttr("defaults"); !defaultsVal.IsNull() {
|
|
newState["defaults"] = defaultsVal
|
|
it := defaultsVal.ElementIterator()
|
|
for it.Next() {
|
|
k, v := it.Element()
|
|
outputs[k.AsString()] = v
|
|
}
|
|
} else {
|
|
newState["defaults"] = cty.NullVal(cty.DynamicPseudoType)
|
|
}
|
|
|
|
remoteState := state.State()
|
|
if remoteState == nil {
|
|
diags = diags.Append(tfdiags.AttributeValue(
|
|
tfdiags.Error,
|
|
"Unable to find remote state",
|
|
"No stored state was found for the given workspace in the given backend.",
|
|
cty.Path(nil).GetAttr("workspace"),
|
|
))
|
|
newState["outputs"] = cty.EmptyObjectVal
|
|
return cty.ObjectVal(newState), diags
|
|
}
|
|
mod := remoteState.RootModule()
|
|
if mod != nil { // should always have a root module in any valid state
|
|
for k, os := range mod.OutputValues {
|
|
outputs[k] = os.Value
|
|
}
|
|
}
|
|
|
|
newState["outputs"] = cty.ObjectVal(outputs)
|
|
|
|
return cty.ObjectVal(newState), diags
|
|
}
|