2024-02-08 03:48:59 -06:00
// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
2023-05-02 10:33:06 -05:00
// SPDX-License-Identifier: MPL-2.0
2018-02-01 22:33:06 -06:00
package configs
import (
2024-06-24 08:13:07 -05:00
"fmt"
2019-09-09 17:58:44 -05:00
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hcldec"
2024-06-24 08:13:07 -05:00
"github.com/opentofu/opentofu/internal/addrs"
2023-09-20 06:35:35 -05:00
"github.com/opentofu/opentofu/internal/configs/configschema"
2024-06-24 08:13:07 -05:00
"github.com/opentofu/opentofu/internal/lang"
2024-10-03 09:46:58 -05:00
"github.com/opentofu/opentofu/internal/lang/marks"
2018-03-27 17:31:05 -05:00
"github.com/zclconf/go-cty/cty"
2018-02-01 22:33:06 -06:00
)
// Backend represents a "backend" block inside a "terraform" block in a module
// or file.
type Backend struct {
Type string
Config hcl . Body
2024-06-24 08:13:07 -05:00
Eval * StaticEvaluator
2018-02-01 22:33:06 -06:00
2018-02-02 19:22:25 -06:00
TypeRange hcl . Range
2018-02-01 22:33:06 -06:00
DeclRange hcl . Range
}
2018-02-02 19:22:25 -06:00
func decodeBackendBlock ( block * hcl . Block ) ( * Backend , hcl . Diagnostics ) {
return & Backend {
Type : block . Labels [ 0 ] ,
TypeRange : block . LabelRanges [ 0 ] ,
Config : block . Body ,
DeclRange : block . DefRange ,
} , nil
}
2018-03-27 17:31:05 -05:00
2024-08-29 12:20:33 -05:00
// Hash produces a hash value for the receiver that covers the type and the
2018-03-27 17:31:05 -05:00
// portions of the config that conform to the given schema.
//
// If the config does not conform to the schema then the result is not
// meaningful for comparison since it will be based on an incomplete result.
//
// As an exception, required attributes in the schema are treated as optional
// for the purpose of hashing, so that an incomplete configuration can still
// be hashed. Other errors, such as extraneous attributes, have no such special
// case.
2024-06-24 08:13:07 -05:00
func ( b * Backend ) Hash ( schema * configschema . Block ) ( int , hcl . Diagnostics ) {
2018-03-27 17:31:05 -05:00
// Don't fail if required attributes are not set. Instead, we'll just
// hash them as nulls.
schema = schema . NoneRequired ( )
2024-06-24 08:13:07 -05:00
// This is a bit of an odd workaround, but the decode below intentionally ignores
// errors. I don't want to try to change that at this point, but it may be worth doing
// at some point. For now, I'm just looking to see if there are any references that are
// not valid that the user should look at, instead of just producing an invalid backend object.
diags := b . referenceDiagnostics ( schema )
val , _ := b . Decode ( schema )
2018-03-27 17:31:05 -05:00
if val == cty . NilVal {
val = cty . UnknownVal ( schema . ImpliedType ( ) )
}
2024-10-03 09:46:58 -05:00
if marks . Contains ( val , marks . Sensitive ) {
return - 1 , diags . Append ( & hcl . Diagnostic {
Severity : hcl . DiagError ,
Summary : "Backend config contains sensitive values" ,
Detail : "The backend configuration is stored in .terraform/terraform.tfstate as well as plan files. It is recommended to instead supply sensitive credentials via backend specific environment variables" ,
Subject : b . DeclRange . Ptr ( ) ,
} )
}
2018-03-27 17:31:05 -05:00
toHash := cty . TupleVal ( [ ] cty . Value {
cty . StringVal ( b . Type ) ,
val ,
} )
2024-06-24 08:13:07 -05:00
return toHash . Hash ( ) , diags
}
func ( b * Backend ) Decode ( schema * configschema . Block ) ( cty . Value , hcl . Diagnostics ) {
return b . Eval . DecodeBlock ( b . Config , schema . DecoderSpec ( ) , StaticIdentifier {
Module : addrs . RootModule ,
Subject : fmt . Sprintf ( "backend.%s" , b . Type ) ,
DeclRange : b . DeclRange ,
} )
}
2024-09-09 06:51:39 -05:00
// This is a hack that may not be needed, but preserves the idea that invalid backends will show a cryptic error about running init during plan/apply startup.
2024-06-24 08:13:07 -05:00
func ( b * Backend ) referenceDiagnostics ( schema * configschema . Block ) hcl . Diagnostics {
var diags hcl . Diagnostics
refs , refsDiags := lang . References ( addrs . ParseRef , hcldec . Variables ( b . Config , schema . DecoderSpec ( ) ) )
diags = append ( diags , refsDiags . ToHCL ( ) ... )
if diags . HasErrors ( ) {
return diags
}
_ , ctxDiags := b . Eval . scope ( StaticIdentifier {
Module : addrs . RootModule ,
Subject : fmt . Sprintf ( "backend.%s" , b . Type ) ,
DeclRange : b . DeclRange ,
} ) . EvalContext ( refs )
diags = append ( diags , ctxDiags . ToHCL ( ) ... )
return diags
2018-03-27 17:31:05 -05:00
}