terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
package terraform
import (
2018-05-03 20:28:12 -05:00
"fmt"
2020-07-23 16:17:06 -05:00
"log"
2018-05-03 20:28:12 -05:00
"os"
2018-12-19 14:29:29 -06:00
"path/filepath"
terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
"sync"
2018-05-03 20:28:12 -05:00
"github.com/agext/levenshtein"
2019-09-09 17:58:44 -05:00
"github.com/hashicorp/hcl/v2"
terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
"github.com/zclconf/go-cty/cty"
2018-05-03 20:28:12 -05:00
"github.com/zclconf/go-cty/cty/convert"
terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
2021-05-17 14:00:50 -05:00
"github.com/hashicorp/terraform/internal/addrs"
2021-05-17 14:17:09 -05:00
"github.com/hashicorp/terraform/internal/configs"
"github.com/hashicorp/terraform/internal/configs/configschema"
2021-05-17 12:34:40 -05:00
"github.com/hashicorp/terraform/internal/instances"
2021-05-17 14:23:42 -05:00
"github.com/hashicorp/terraform/internal/lang"
2021-06-23 15:24:58 -05:00
"github.com/hashicorp/terraform/internal/lang/marks"
2021-05-17 14:33:17 -05:00
"github.com/hashicorp/terraform/internal/plans"
2021-05-17 14:43:35 -05:00
"github.com/hashicorp/terraform/internal/states"
2021-05-17 12:11:06 -05:00
"github.com/hashicorp/terraform/internal/tfdiags"
terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
)
// Evaluator provides the necessary contextual data for evaluating expressions
// for a particular walk operation.
type Evaluator struct {
// Operation defines what type of operation this evaluator is being used
// for.
Operation walkOperation
// Meta is contextual metadata about the current operation.
Meta * ContextMeta
// Config is the root node in the configuration tree.
Config * configs . Config
2018-05-03 20:25:16 -05:00
// VariableValues is a map from variable names to their associated values,
// within the module indicated by ModulePath. VariableValues is modified
// concurrently, and so it must be accessed only while holding
// VariableValuesLock.
//
// The first map level is string representations of addr.ModuleInstance
// values, while the second level is variable names.
VariableValues map [ string ] map [ string ] cty . Value
VariableValuesLock * sync . Mutex
terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
2021-08-31 19:53:03 -05:00
// Plugins is the library of available plugin components (providers and
// provisioners) that we have available to help us evaluate expressions
// that interact with plugin-provided objects.
2018-06-01 14:36:55 -05:00
//
2021-08-31 19:53:03 -05:00
// From this we only access the schemas of the plugins, and don't otherwise
// interact with plugin instances.
Plugins * contextPlugins
2018-05-03 20:28:12 -05:00
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 16:24:45 -05:00
// State is the current state, embedded in a wrapper that ensures that
// it can be safely accessed and modified concurrently.
State * states . SyncState
2018-08-28 18:30:52 -05:00
// Changes is the set of proposed changes, embedded in a wrapper that
// ensures they can be safely accessed and modified concurrently.
Changes * plans . ChangesSync
terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
}
// Scope creates an evaluation scope for the given module path and optional
// resource.
//
// If the "self" argument is nil then the "self" object is not available
// in evaluated expressions. Otherwise, it behaves as an alias for the given
// address.
2018-05-03 19:24:49 -05:00
func ( e * Evaluator ) Scope ( data lang . Data , self addrs . Referenceable ) * lang . Scope {
terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
return & lang . Scope {
2018-05-03 19:24:49 -05:00
Data : data ,
terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
SelfAddr : self ,
2020-07-01 08:43:07 -05:00
PureOnly : e . Operation != walkApply && e . Operation != walkDestroy && e . Operation != walkEval ,
terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
BaseDir : "." , // Always current working directory for now.
}
}
// evaluationStateData is an implementation of lang.Data that resolves
// references primarily (but not exclusively) using information from a State.
type evaluationStateData struct {
Evaluator * Evaluator
// ModulePath is the path through the dynamic module tree to the module
// that references will be resolved relative to.
ModulePath addrs . ModuleInstance
2018-05-03 20:28:12 -05:00
2018-06-22 15:04:19 -05:00
// InstanceKeyData describes the values, if any, that are accessible due
// to repetition of a containing object using "count" or "for_each"
// arguments. (It is _not_ used for the for_each inside "dynamic" blocks,
// since the user specifies in that case which variable name to locally
// shadow.)
InstanceKeyData InstanceKeyEvalData
2018-12-16 20:59:44 -06:00
// Operation records the type of walk the evaluationStateData is being used
// for.
Operation walkOperation
terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
}
2019-11-21 20:54:19 -06:00
// InstanceKeyEvalData is the old name for instances.RepetitionData, aliased
// here for compatibility. In new code, use instances.RepetitionData instead.
type InstanceKeyEvalData = instances . RepetitionData
2018-06-22 15:04:19 -05:00
// EvalDataForInstanceKey constructs a suitable InstanceKeyEvalData for
// evaluating in a context that has the given instance key.
2020-02-19 15:54:41 -06:00
//
// The forEachMap argument can be nil when preparing for evaluation
// in a context where each.value is prohibited, such as a destroy-time
// provisioner. In that case, the returned EachValue will always be
// cty.NilVal.
2019-06-12 10:07:32 -05:00
func EvalDataForInstanceKey ( key addrs . InstanceKey , forEachMap map [ string ] cty . Value ) InstanceKeyEvalData {
2020-02-17 15:07:38 -06:00
var evalData InstanceKeyEvalData
if key == nil {
return evalData
2019-06-12 10:07:32 -05:00
}
2020-02-17 15:07:38 -06:00
keyValue := key . Value ( )
switch keyValue . Type ( ) {
case cty . String :
evalData . EachKey = keyValue
evalData . EachValue = forEachMap [ keyValue . AsString ( ) ]
case cty . Number :
evalData . CountIndex = keyValue
2018-06-22 15:04:19 -05:00
}
2020-02-17 15:07:38 -06:00
return evalData
2018-06-22 15:04:19 -05:00
}
// EvalDataForNoInstanceKey is a value of InstanceKeyData that sets no instance
// key values at all, suitable for use in contexts where no keyed instance
// is relevant.
var EvalDataForNoInstanceKey = InstanceKeyEvalData { }
terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
// evaluationStateData must implement lang.Data
var _ lang . Data = ( * evaluationStateData ) ( nil )
2018-05-03 20:28:12 -05:00
func ( d * evaluationStateData ) GetCountAttr ( addr addrs . CountAttr , rng tfdiags . SourceRange ) ( cty . Value , tfdiags . Diagnostics ) {
var diags tfdiags . Diagnostics
switch addr . Name {
case "index" :
2018-06-22 15:04:19 -05:00
idxVal := d . InstanceKeyData . CountIndex
if idxVal == cty . NilVal {
2018-05-03 20:28:12 -05:00
diags = diags . Append ( & hcl . Diagnostic {
Severity : hcl . DiagError ,
Summary : ` Reference to "count" in non-counted context ` ,
2020-11-30 16:42:08 -06:00
Detail : ` The "count" object can only be used in "module", "resource", and "data" blocks, and only when the "count" argument is set. ` ,
2018-05-03 20:28:12 -05:00
Subject : rng . ToHCL ( ) . Ptr ( ) ,
} )
return cty . UnknownVal ( cty . Number ) , diags
}
2018-06-22 15:04:19 -05:00
return idxVal , diags
2018-05-03 20:28:12 -05:00
default :
diags = diags . Append ( & hcl . Diagnostic {
Severity : hcl . DiagError ,
Summary : ` Invalid "count" attribute ` ,
Detail : fmt . Sprintf ( ` The "count" object does not have an attribute named %q. The only supported attribute is count.index, which is the index of each instance of a resource block that has the "count" argument set. ` , addr . Name ) ,
Subject : rng . ToHCL ( ) . Ptr ( ) ,
} )
return cty . DynamicVal , diags
}
}
2019-06-12 10:07:32 -05:00
func ( d * evaluationStateData ) GetForEachAttr ( addr addrs . ForEachAttr , rng tfdiags . SourceRange ) ( cty . Value , tfdiags . Diagnostics ) {
var diags tfdiags . Diagnostics
var returnVal cty . Value
switch addr . Name {
case "key" :
returnVal = d . InstanceKeyData . EachKey
case "value" :
returnVal = d . InstanceKeyData . EachValue
2019-10-22 14:16:43 -05:00
if returnVal == cty . NilVal {
diags = diags . Append ( & hcl . Diagnostic {
Severity : hcl . DiagError ,
2019-10-23 10:18:10 -05:00
Summary : ` each.value cannot be used in this context ` ,
2020-11-30 16:42:08 -06:00
Detail : ` A reference to "each.value" has been used in a context in which it unavailable, such as when the configuration no longer contains the value in its "for_each" expression. Remove this reference to each.value in your configuration to work around this error. ` ,
2019-10-22 14:16:43 -05:00
Subject : rng . ToHCL ( ) . Ptr ( ) ,
} )
return cty . UnknownVal ( cty . DynamicPseudoType ) , diags
}
2019-06-12 10:07:32 -05:00
default :
diags = diags . Append ( & hcl . Diagnostic {
Severity : hcl . DiagError ,
Summary : ` Invalid "each" attribute ` ,
Detail : fmt . Sprintf ( ` The "each" object does not have an attribute named %q. The supported attributes are each.key and each.value, the current key and value pair of the "for_each" attribute set. ` , addr . Name ) ,
Subject : rng . ToHCL ( ) . Ptr ( ) ,
} )
return cty . DynamicVal , diags
}
if returnVal == cty . NilVal {
diags = diags . Append ( & hcl . Diagnostic {
Severity : hcl . DiagError ,
Summary : ` Reference to "each" in context without for_each ` ,
2020-11-30 16:42:08 -06:00
Detail : ` The "each" object can be used only in "module" or "resource" blocks, and only when the "for_each" argument is set. ` ,
2019-06-12 10:07:32 -05:00
Subject : rng . ToHCL ( ) . Ptr ( ) ,
} )
return cty . UnknownVal ( cty . DynamicPseudoType ) , diags
}
return returnVal , diags
}
2018-05-03 20:28:12 -05:00
func ( d * evaluationStateData ) GetInputVariable ( addr addrs . InputVariable , rng tfdiags . SourceRange ) ( cty . Value , tfdiags . Diagnostics ) {
var diags tfdiags . Diagnostics
// First we'll make sure the requested value is declared in configuration,
// so we can produce a nice message if not.
moduleConfig := d . Evaluator . Config . DescendentForInstance ( d . ModulePath )
if moduleConfig == nil {
// should never happen, since we can't be evaluating in a module
// that wasn't mentioned in configuration.
panic ( fmt . Sprintf ( "input variable read from %s, which has no configuration" , d . ModulePath ) )
}
config := moduleConfig . Module . Variables [ addr . Name ]
if config == nil {
var suggestions [ ] string
for k := range moduleConfig . Module . Variables {
suggestions = append ( suggestions , k )
}
suggestion := nameSuggestion ( addr . Name , suggestions )
if suggestion != "" {
suggestion = fmt . Sprintf ( " Did you mean %q?" , suggestion )
} else {
suggestion = fmt . Sprintf ( " This variable can be declared with a variable %q {} block." , addr . Name )
}
diags = diags . Append ( & hcl . Diagnostic {
Severity : hcl . DiagError ,
Summary : ` Reference to undeclared input variable ` ,
Detail : fmt . Sprintf ( ` An input variable with the name %q has not been declared.%s ` , addr . Name , suggestion ) ,
Subject : rng . ToHCL ( ) . Ptr ( ) ,
} )
return cty . DynamicVal , diags
}
d . Evaluator . VariableValuesLock . Lock ( )
defer d . Evaluator . VariableValuesLock . Unlock ( )
2019-04-17 10:48:39 -05:00
// During the validate walk, input variables are always unknown so
// that we are validating the configuration for all possible input values
// rather than for a specific set. Checking against a specific set of
// input values then happens during the plan walk.
//
// This is important because otherwise the validation walk will tend to be
// overly strict, requiring expressions throughout the configuration to
// be complicated to accommodate all possible inputs, whereas returning
// known here allows for simpler patterns like using input values as
// guards to broadly enable/disable resources, avoid processing things
// that are disabled, etc. Terraform's static validation leans towards
// being liberal in what it accepts because the subsequent plan walk has
// more information available and so can be more conservative.
if d . Operation == walkValidate {
2020-11-05 15:02:40 -06:00
// Ensure variable sensitivity is captured in the validate walk
if config . Sensitive {
2021-09-10 10:11:06 -05:00
return cty . UnknownVal ( config . Type ) . Mark ( marks . Sensitive ) , diags
2020-11-05 15:02:40 -06:00
}
2021-09-10 10:11:06 -05:00
return cty . UnknownVal ( config . Type ) , diags
2019-04-17 10:48:39 -05:00
}
2018-05-03 20:28:12 -05:00
moduleAddrStr := d . ModulePath . String ( )
vals := d . Evaluator . VariableValues [ moduleAddrStr ]
if vals == nil {
2021-09-10 10:11:06 -05:00
return cty . UnknownVal ( config . Type ) , diags
2018-05-03 20:28:12 -05:00
}
val , isSet := vals [ addr . Name ]
2021-10-27 09:33:00 -05:00
switch {
case ! isSet :
// The config loader will ensure there is a default if the value is not
// set at all.
val = config . Default
case val . IsNull ( ) && ! config . Nullable && config . Default != cty . NilVal :
// If nullable=false a null value will use the configured default.
val = config . Default
2018-05-03 20:28:12 -05:00
}
var err error
2021-09-10 10:11:06 -05:00
val , err = convert . Convert ( val , config . ConstraintType )
2018-05-03 20:28:12 -05:00
if err != nil {
// We should never get here because this problem should've been caught
// during earlier validation, but we'll do something reasonable anyway.
diags = diags . Append ( & hcl . Diagnostic {
Severity : hcl . DiagError ,
Summary : ` Incorrect variable type ` ,
Detail : fmt . Sprintf ( ` The resolved value of variable %q is not appropriate: %s. ` , addr . Name , err ) ,
Subject : & config . DeclRange ,
} )
2021-09-10 10:11:06 -05:00
val = cty . UnknownVal ( config . Type )
2018-05-03 20:28:12 -05:00
}
2021-06-23 15:24:58 -05:00
// Mark if sensitive
if config . Sensitive {
2021-06-24 16:53:43 -05:00
val = val . Mark ( marks . Sensitive )
2020-08-07 10:59:06 -05:00
}
2018-05-03 20:28:12 -05:00
return val , diags
}
func ( d * evaluationStateData ) GetLocalValue ( addr addrs . LocalValue , rng tfdiags . SourceRange ) ( cty . Value , tfdiags . Diagnostics ) {
var diags tfdiags . Diagnostics
// First we'll make sure the requested value is declared in configuration,
// so we can produce a nice message if not.
moduleConfig := d . Evaluator . Config . DescendentForInstance ( d . ModulePath )
if moduleConfig == nil {
// should never happen, since we can't be evaluating in a module
// that wasn't mentioned in configuration.
panic ( fmt . Sprintf ( "local value read from %s, which has no configuration" , d . ModulePath ) )
}
config := moduleConfig . Module . Locals [ addr . Name ]
if config == nil {
var suggestions [ ] string
for k := range moduleConfig . Module . Locals {
suggestions = append ( suggestions , k )
}
suggestion := nameSuggestion ( addr . Name , suggestions )
if suggestion != "" {
suggestion = fmt . Sprintf ( " Did you mean %q?" , suggestion )
}
diags = diags . Append ( & hcl . Diagnostic {
Severity : hcl . DiagError ,
Summary : ` Reference to undeclared local value ` ,
Detail : fmt . Sprintf ( ` A local value with the name %q has not been declared.%s ` , addr . Name , suggestion ) ,
Subject : rng . ToHCL ( ) . Ptr ( ) ,
} )
return cty . DynamicVal , diags
}
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 16:24:45 -05:00
val := d . Evaluator . State . LocalValue ( addr . Absolute ( d . ModulePath ) )
if val == cty . NilVal {
2018-05-03 20:28:12 -05:00
// Not evaluated yet?
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 16:24:45 -05:00
val = cty . DynamicVal
2018-05-03 20:28:12 -05:00
}
return val , diags
}
2020-04-13 15:23:24 -05:00
func ( d * evaluationStateData ) GetModule ( addr addrs . ModuleCall , rng tfdiags . SourceRange ) ( cty . Value , tfdiags . Diagnostics ) {
2018-05-03 20:28:12 -05:00
var diags tfdiags . Diagnostics
// Output results live in the module that declares them, which is one of
// the child module instances of our current module path.
2020-04-13 15:23:24 -05:00
moduleAddr := d . ModulePath . Module ( ) . Child ( addr . Name )
parentCfg := d . Evaluator . Config . DescendentForInstance ( d . ModulePath )
callConfig , ok := parentCfg . Module . ModuleCalls [ addr . Name ]
if ! ok {
diags = diags . Append ( & hcl . Diagnostic {
Severity : hcl . DiagError ,
Summary : ` Reference to undeclared module ` ,
Detail : fmt . Sprintf ( ` The configuration contains no %s. ` , moduleAddr ) ,
Subject : rng . ToHCL ( ) . Ptr ( ) ,
} )
return cty . DynamicVal , diags
}
2018-05-03 20:28:12 -05:00
// We'll consult the configuration to see what output names we are
// expecting, so we can ensure the resulting object is of the expected
// type even if our data is incomplete for some reason.
2020-04-13 15:23:24 -05:00
moduleConfig := d . Evaluator . Config . Descendent ( moduleAddr )
2018-05-03 20:28:12 -05:00
if moduleConfig == nil {
2020-04-13 15:23:24 -05:00
// should never happen, since we have a valid module call above, this
// should be caught during static validation.
2018-05-03 20:28:12 -05:00
panic ( fmt . Sprintf ( "output value read from %s, which has no configuration" , moduleAddr ) )
}
outputConfigs := moduleConfig . Module . Outputs
2020-04-13 15:23:24 -05:00
// Collect all the relevant outputs that current exist in the state.
// We know the instance path up to this point, and the child module name,
// so we only need to store these by instance key.
stateMap := map [ addrs . InstanceKey ] map [ string ] cty . Value { }
2020-04-13 17:17:08 -05:00
for _ , output := range d . Evaluator . State . ModuleOutputs ( d . ModulePath , addr ) {
_ , callInstance := output . Addr . Module . CallInstance ( )
2020-04-13 15:23:24 -05:00
instance , ok := stateMap [ callInstance . Key ]
if ! ok {
instance = map [ string ] cty . Value { }
stateMap [ callInstance . Key ] = instance
}
2020-04-13 17:17:08 -05:00
instance [ output . Addr . OutputValue . Name ] = output . Value
2020-04-13 15:23:24 -05:00
}
// Get all changes that reside for this module call within our path.
// The change contains the full addr, so we can key these with strings.
changesMap := map [ addrs . InstanceKey ] map [ string ] * plans . OutputChangeSrc { }
for _ , change := range d . Evaluator . Changes . GetOutputChanges ( d . ModulePath , addr ) {
_ , callInstance := change . Addr . Module . CallInstance ( )
instance , ok := changesMap [ callInstance . Key ]
if ! ok {
instance = map [ string ] * plans . OutputChangeSrc { }
changesMap [ callInstance . Key ] = instance
}
instance [ change . Addr . OutputValue . Name ] = change
}
// Build up all the module objects, creating a map of values for each
// module instance.
moduleInstances := map [ addrs . InstanceKey ] map [ string ] cty . Value { }
2020-04-23 15:13:45 -05:00
// create a dummy object type for validation below
unknownMap := map [ string ] cty . Type { }
2020-04-13 15:23:24 -05:00
// the structure is based on the configuration, so iterate through all the
// defined outputs, and add any instance state or changes we find.
for _ , cfg := range outputConfigs {
2020-04-23 15:13:45 -05:00
// record the output names for validation
unknownMap [ cfg . Name ] = cty . DynamicPseudoType
2020-04-13 15:23:24 -05:00
// get all instance output for this path from the state
for key , states := range stateMap {
outputState , ok := states [ cfg . Name ]
if ! ok {
2020-04-17 11:36:17 -05:00
continue
2020-04-13 15:23:24 -05:00
}
instance , ok := moduleInstances [ key ]
if ! ok {
instance = map [ string ] cty . Value { }
moduleInstances [ key ] = instance
}
instance [ cfg . Name ] = outputState
2020-10-06 11:53:49 -05:00
2021-06-23 15:24:58 -05:00
if cfg . Sensitive {
2021-06-24 16:53:43 -05:00
instance [ cfg . Name ] = outputState . Mark ( marks . Sensitive )
2020-10-06 11:53:49 -05:00
}
2020-04-13 15:23:24 -05:00
}
// any pending changes override the state state values
for key , changes := range changesMap {
changeSrc , ok := changes [ cfg . Name ]
if ! ok {
continue
}
instance , ok := moduleInstances [ key ]
if ! ok {
instance = map [ string ] cty . Value { }
moduleInstances [ key ] = instance
}
2018-05-03 20:28:12 -05:00
2018-11-01 19:41:35 -05:00
change , err := changeSrc . Decode ( )
if err != nil {
// This should happen only if someone has tampered with a plan
// file, so we won't bother with a pretty error for it.
diags = diags . Append ( fmt . Errorf ( "planned change for %s could not be decoded: %s" , addr , err ) )
2020-04-13 15:23:24 -05:00
instance [ cfg . Name ] = cty . DynamicVal
2018-11-01 19:41:35 -05:00
continue
}
2020-04-13 15:23:24 -05:00
2021-05-12 10:43:13 -05:00
instance [ cfg . Name ] = change . After
2020-10-06 11:53:49 -05:00
2021-06-23 15:24:58 -05:00
if change . Sensitive {
2021-06-24 16:53:43 -05:00
instance [ cfg . Name ] = change . After . Mark ( marks . Sensitive )
2020-10-06 11:53:49 -05:00
}
2020-04-13 15:23:24 -05:00
}
}
2020-04-17 11:36:17 -05:00
var ret cty . Value
2020-04-13 15:23:24 -05:00
// compile the outputs into the correct value type for the each mode
switch {
case callConfig . Count != nil :
2020-04-22 22:04:30 -05:00
// figure out what the last index we have is
length := - 1
for key := range moduleInstances {
2020-04-13 15:23:24 -05:00
intKey , ok := key . ( addrs . IntKey )
if ! ok {
// old key from state which is being dropped
continue
}
2020-04-22 22:04:30 -05:00
if int ( intKey ) >= length {
length = int ( intKey ) + 1
}
2020-04-13 15:23:24 -05:00
}
2020-04-22 22:04:30 -05:00
if length > 0 {
vals := make ( [ ] cty . Value , length )
for key , instance := range moduleInstances {
intKey , ok := key . ( addrs . IntKey )
if ! ok {
// old key from state which is being dropped
continue
}
vals [ int ( intKey ) ] = cty . ObjectVal ( instance )
}
// Insert unknown values where there are any missing instances
2020-04-17 11:36:17 -05:00
for i , v := range vals {
if v . IsNull ( ) {
vals [ i ] = cty . DynamicVal
continue
}
2018-11-01 19:41:35 -05:00
}
2020-04-22 16:12:05 -05:00
ret = cty . TupleVal ( vals )
2020-04-17 11:36:17 -05:00
} else {
2020-04-22 22:04:30 -05:00
ret = cty . EmptyTupleVal
2018-11-01 19:41:35 -05:00
}
2020-04-13 15:23:24 -05:00
case callConfig . ForEach != nil :
vals := make ( map [ string ] cty . Value )
for key , instance := range moduleInstances {
strKey , ok := key . ( addrs . StringKey )
if ! ok {
continue
}
vals [ string ( strKey ) ] = cty . ObjectVal ( instance )
}
2020-04-17 11:36:17 -05:00
if len ( vals ) > 0 {
2020-04-22 16:12:05 -05:00
ret = cty . ObjectVal ( vals )
2020-04-17 11:36:17 -05:00
} else {
2020-04-22 22:04:30 -05:00
ret = cty . EmptyObjectVal
2020-04-17 11:36:17 -05:00
}
2020-04-13 15:23:24 -05:00
default :
val , ok := moduleInstances [ addrs . NoKey ]
if ! ok {
2020-04-17 11:36:17 -05:00
// create the object if there wasn't one known
2020-04-13 15:23:24 -05:00
val = map [ string ] cty . Value { }
for k := range outputConfigs {
val [ k ] = cty . DynamicVal
}
}
2020-04-17 11:36:17 -05:00
ret = cty . ObjectVal ( val )
}
// The module won't be expanded during validation, so we need to return an
// unknown value. This will ensure the types looks correct, since we built
// the objects based on the configuration.
if d . Operation == walkValidate {
2020-04-23 14:17:46 -05:00
// While we know the type here and it would be nice to validate whether
2020-04-23 15:13:45 -05:00
// indexes are valid or not, because tuples and objects have fixed
// numbers of elements we can't simply return an unknown value of the
// same type since we have not expanded any instances during
// validation.
//
// In order to validate the expression a little precisely, we'll create
// an unknown map or list here to get more type information.
ty := cty . Object ( unknownMap )
switch {
case callConfig . Count != nil :
ret = cty . UnknownVal ( cty . List ( ty ) )
case callConfig . ForEach != nil :
ret = cty . UnknownVal ( cty . Map ( ty ) )
default :
ret = cty . UnknownVal ( ty )
}
2018-05-03 20:28:12 -05:00
}
2020-04-17 11:36:17 -05:00
return ret , diags
2018-05-03 20:28:12 -05:00
}
func ( d * evaluationStateData ) GetPathAttr ( addr addrs . PathAttr , rng tfdiags . SourceRange ) ( cty . Value , tfdiags . Diagnostics ) {
var diags tfdiags . Diagnostics
switch addr . Name {
case "cwd" :
main: new global option -chdir
This new option is intended to address the previous inconsistencies where
some older subcommands supported partially changing the target directory
(where Terraform would use the new directory inconsistently) where newer
commands did not support that override at all.
Instead, now Terraform will accept a -chdir command at the start of the
command line (before the subcommand) and will interpret it as a request
to direct all actions that would normally be taken in the current working
directory into the target directory instead. This is similar to options
offered by some other similar tools, such as the -C option in "make".
The new option is only accepted at the start of the command line (before
the subcommand) as a way to reflect that it is a global command (not
specific to a particular subcommand) and that it takes effect _before_
executing the subcommand. This also means it'll be forced to appear before
any other command-specific arguments that take file paths, which hopefully
communicates that those other arguments are interpreted relative to the
overridden path.
As a measure of pragmatism for existing uses, the path.cwd object in
the Terraform language will continue to return the _original_ working
directory (ignoring -chdir), in case that is important in some exceptional
workflows. The path.root object gives the root module directory, which
will always match the overriden working directory unless the user
simultaneously uses one of the legacy directory override arguments, which
is not a pattern we intend to support in the long run.
As a first step down the deprecation path, this commit adjusts the
documentation to de-emphasize the inconsistent old command line arguments,
including specific guidance on what to use instead for the main three
workflow commands, but all of those options remain supported in the same
way as they were before. In a later commit we'll make those arguments
produce a visible deprecation warning in Terraform's output, and then
in an even later commit we'll remove them entirely so that -chdir is the
single supported way to run Terraform from a directory other than the
one containing the root module configuration.
2020-09-01 17:45:12 -05:00
var err error
var wd string
if d . Evaluator . Meta != nil {
// Meta is always non-nil in the normal case, but some test cases
// are not so realistic.
wd = d . Evaluator . Meta . OriginalWorkingDir
}
if wd == "" {
wd , err = os . Getwd ( )
if err != nil {
diags = diags . Append ( & hcl . Diagnostic {
Severity : hcl . DiagError ,
Summary : ` Failed to get working directory ` ,
Detail : fmt . Sprintf ( ` The value for path.cwd cannot be determined due to a system error: %s ` , err ) ,
Subject : rng . ToHCL ( ) . Ptr ( ) ,
} )
return cty . DynamicVal , diags
}
}
// The current working directory should always be absolute, whether we
// just looked it up or whether we were relying on ContextMeta's
// (possibly non-normalized) path.
wd , err = filepath . Abs ( wd )
2018-05-03 20:28:12 -05:00
if err != nil {
diags = diags . Append ( & hcl . Diagnostic {
Severity : hcl . DiagError ,
Summary : ` Failed to get working directory ` ,
Detail : fmt . Sprintf ( ` The value for path.cwd cannot be determined due to a system error: %s ` , err ) ,
Subject : rng . ToHCL ( ) . Ptr ( ) ,
} )
return cty . DynamicVal , diags
}
main: new global option -chdir
This new option is intended to address the previous inconsistencies where
some older subcommands supported partially changing the target directory
(where Terraform would use the new directory inconsistently) where newer
commands did not support that override at all.
Instead, now Terraform will accept a -chdir command at the start of the
command line (before the subcommand) and will interpret it as a request
to direct all actions that would normally be taken in the current working
directory into the target directory instead. This is similar to options
offered by some other similar tools, such as the -C option in "make".
The new option is only accepted at the start of the command line (before
the subcommand) as a way to reflect that it is a global command (not
specific to a particular subcommand) and that it takes effect _before_
executing the subcommand. This also means it'll be forced to appear before
any other command-specific arguments that take file paths, which hopefully
communicates that those other arguments are interpreted relative to the
overridden path.
As a measure of pragmatism for existing uses, the path.cwd object in
the Terraform language will continue to return the _original_ working
directory (ignoring -chdir), in case that is important in some exceptional
workflows. The path.root object gives the root module directory, which
will always match the overriden working directory unless the user
simultaneously uses one of the legacy directory override arguments, which
is not a pattern we intend to support in the long run.
As a first step down the deprecation path, this commit adjusts the
documentation to de-emphasize the inconsistent old command line arguments,
including specific guidance on what to use instead for the main three
workflow commands, but all of those options remain supported in the same
way as they were before. In a later commit we'll make those arguments
produce a visible deprecation warning in Terraform's output, and then
in an even later commit we'll remove them entirely so that -chdir is the
single supported way to run Terraform from a directory other than the
one containing the root module configuration.
2020-09-01 17:45:12 -05:00
2018-12-19 14:29:29 -06:00
return cty . StringVal ( filepath . ToSlash ( wd ) ) , diags
2018-05-03 20:28:12 -05:00
case "module" :
moduleConfig := d . Evaluator . Config . DescendentForInstance ( d . ModulePath )
if moduleConfig == nil {
// should never happen, since we can't be evaluating in a module
// that wasn't mentioned in configuration.
panic ( fmt . Sprintf ( "module.path read from module %s, which has no configuration" , d . ModulePath ) )
}
sourceDir := moduleConfig . Module . SourceDir
2018-12-19 14:29:29 -06:00
return cty . StringVal ( filepath . ToSlash ( sourceDir ) ) , diags
2018-05-03 20:28:12 -05:00
case "root" :
sourceDir := d . Evaluator . Config . Module . SourceDir
2018-12-19 14:29:29 -06:00
return cty . StringVal ( filepath . ToSlash ( sourceDir ) ) , diags
2018-05-03 20:28:12 -05:00
default :
suggestion := nameSuggestion ( addr . Name , [ ] string { "cwd" , "module" , "root" } )
if suggestion != "" {
suggestion = fmt . Sprintf ( " Did you mean %q?" , suggestion )
}
diags = diags . Append ( & hcl . Diagnostic {
Severity : hcl . DiagError ,
Summary : ` Invalid "path" attribute ` ,
Detail : fmt . Sprintf ( ` The "path" object does not have an attribute named %q.%s ` , addr . Name , suggestion ) ,
Subject : rng . ToHCL ( ) . Ptr ( ) ,
} )
return cty . DynamicVal , diags
}
terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
}
2019-08-23 18:20:47 -05:00
func ( d * evaluationStateData ) GetResource ( addr addrs . Resource , rng tfdiags . SourceRange ) ( cty . Value , tfdiags . Diagnostics ) {
2018-05-03 20:28:12 -05:00
var diags tfdiags . Diagnostics
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 16:24:45 -05:00
// First we'll consult the configuration to see if an resource of this
2018-05-11 19:39:32 -05:00
// name is declared at all.
moduleAddr := d . ModulePath
moduleConfig := d . Evaluator . Config . DescendentForInstance ( moduleAddr )
if moduleConfig == nil {
// should never happen, since we can't be evaluating in a module
// that wasn't mentioned in configuration.
panic ( fmt . Sprintf ( "resource value read from %s, which has no configuration" , moduleAddr ) )
}
2019-08-23 18:20:47 -05:00
config := moduleConfig . Module . ResourceByAddr ( addr )
2018-05-11 19:39:32 -05:00
if config == nil {
diags = diags . Append ( & hcl . Diagnostic {
Severity : hcl . DiagError ,
Summary : ` Reference to undeclared resource ` ,
2019-08-23 18:20:47 -05:00
Detail : fmt . Sprintf ( ` A resource %q %q has not been declared in %s ` , addr . Type , addr . Name , moduleDisplayAddr ( moduleAddr ) ) ,
2018-05-11 19:39:32 -05:00
Subject : rng . ToHCL ( ) . Ptr ( ) ,
} )
return cty . DynamicVal , diags
}
2021-11-02 14:06:49 -05:00
// Build the provider address from configuration, since we may not have
// state available in all cases.
// We need to build an abs provider address, but we can use a default
// instance since we're only interested in the schema.
2021-11-02 14:35:47 -05:00
schema := d . getResourceSchema ( addr , config . Provider )
2021-11-02 14:06:49 -05:00
if schema == nil {
// This shouldn't happen, since validation before we get here should've
// taken care of it, but we'll show a reasonable error message anyway.
diags = diags . Append ( & hcl . Diagnostic {
Severity : hcl . DiagError ,
Summary : ` Missing resource type schema ` ,
2021-11-02 14:35:47 -05:00
Detail : fmt . Sprintf ( "No schema is available for %s in %s. This is a bug in Terraform and should be reported." , addr , config . Provider ) ,
2021-11-02 14:06:49 -05:00
Subject : rng . ToHCL ( ) . Ptr ( ) ,
} )
return cty . DynamicVal , diags
}
ty := schema . ImpliedType ( )
2019-08-23 18:20:47 -05:00
rs := d . Evaluator . State . Resource ( addr . Absolute ( d . ModulePath ) )
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 16:24:45 -05:00
if rs == nil {
2020-07-23 16:17:06 -05:00
switch d . Operation {
2020-09-16 09:45:33 -05:00
case walkPlan , walkApply :
// During plan and apply as we evaluate each removed instance they
// are removed from the working state. Since we know there are no
// instances, return an empty container of the expected type.
2020-07-23 16:17:06 -05:00
switch {
case config . Count != nil :
return cty . EmptyTupleVal , diags
case config . ForEach != nil :
return cty . EmptyObjectVal , diags
default :
2020-09-11 09:55:39 -05:00
// While we can reference an expanded resource with 0
2020-07-23 16:17:06 -05:00
// instances, we cannot reference instances that do not exist.
2020-09-11 09:55:39 -05:00
// Due to the fact that we may have direct references to
// instances that may end up in a root output during destroy
// (since a planned destroy cannot yet remove root outputs), we
// need to return a dynamic value here to allow evaluation to
// continue.
2021-11-02 14:06:49 -05:00
log . Printf ( "[ERROR] unknown instance %q referenced during %s" , addr . Absolute ( d . ModulePath ) , d . Operation )
2020-07-23 16:17:06 -05:00
return cty . DynamicVal , diags
}
default :
2021-11-02 14:06:49 -05:00
if d . Operation != walkValidate {
log . Printf ( "[ERROR] missing state for %q while in %s\n" , addr . Absolute ( d . ModulePath ) , d . Operation )
}
2019-08-23 18:20:47 -05:00
2021-11-02 14:06:49 -05:00
// Validation is done with only the configuration, so generate
// unknown values of the correct shape for evaluation.
switch {
case config . Count != nil :
return cty . UnknownVal ( cty . List ( ty ) ) , diags
case config . ForEach != nil :
return cty . UnknownVal ( cty . Map ( ty ) ) , diags
default :
return cty . UnknownVal ( ty ) , diags
}
}
2018-05-03 20:28:12 -05:00
}
2020-04-22 21:09:47 -05:00
// Decode all instances in the current state
instances := map [ addrs . InstanceKey ] cty . Value { }
2020-10-05 09:50:25 -05:00
pendingDestroy := d . Evaluator . Changes . IsFullDestroy ( )
2020-04-22 21:09:47 -05:00
for key , is := range rs . Instances {
2019-09-19 08:08:17 -05:00
if is == nil || is . Current == nil {
// Assume we're dealing with an instance that hasn't been created yet.
2020-04-22 21:09:47 -05:00
instances [ key ] = cty . UnknownVal ( ty )
continue
2019-09-19 08:08:17 -05:00
}
2018-05-11 19:39:32 -05:00
2020-04-22 21:09:47 -05:00
instAddr := addr . Instance ( key ) . Absolute ( d . ModulePath )
2020-06-26 16:30:00 -05:00
change := d . Evaluator . Changes . GetResourceInstanceChange ( instAddr , states . CurrentGen )
if change != nil {
// Don't take any resources that are yet to be deleted into account.
// If the referenced resource is CreateBeforeDestroy, then orphaned
// instances will be in the state, as they are not destroyed until
// after their dependants are updated.
if change . Action == plans . Delete {
2020-10-01 16:11:46 -05:00
if ! pendingDestroy {
continue
}
2020-06-26 16:30:00 -05:00
}
}
2020-04-22 21:09:47 -05:00
// Planned resources are temporarily stored in state with empty values,
2020-10-12 13:39:09 -05:00
// and need to be replaced by the planned value here.
2019-09-19 08:08:17 -05:00
if is . Current . Status == states . ObjectPlanned {
2020-04-22 21:09:47 -05:00
if change == nil {
// If the object is in planned status then we should not get
// here, since we should have found a pending value in the plan
// above instead.
2018-09-19 13:24:04 -05:00
diags = diags . Append ( & hcl . Diagnostic {
Severity : hcl . DiagError ,
2019-09-19 08:08:17 -05:00
Summary : "Missing pending object in plan" ,
2020-04-22 21:09:47 -05:00
Detail : fmt . Sprintf ( "Instance %s is marked as having a change pending but that change is not recorded in the plan. This is a bug in Terraform; please report it." , instAddr ) ,
2018-09-19 13:24:04 -05:00
Subject : & config . DeclRange ,
} )
2020-04-22 21:09:47 -05:00
continue
2018-09-19 13:24:04 -05:00
}
2020-04-22 21:09:47 -05:00
val , err := change . After . Decode ( ty )
if err != nil {
diags = diags . Append ( & hcl . Diagnostic {
Severity : hcl . DiagError ,
Summary : "Invalid resource instance data in plan" ,
Detail : fmt . Sprintf ( "Instance %s data could not be decoded from the plan: %s." , instAddr , err ) ,
Subject : & config . DeclRange ,
} )
continue
}
2021-03-10 10:47:01 -06:00
// If our provider schema contains sensitive values, mark those as sensitive
2021-03-30 14:50:47 -05:00
afterMarks := change . AfterValMarks
2021-03-10 10:47:01 -06:00
if schema . ContainsSensitive ( ) {
2021-04-26 15:26:47 -05:00
afterMarks = append ( afterMarks , schema . ValueMarks ( val , nil ) ... )
2020-10-12 13:39:09 -05:00
}
2021-03-10 10:47:01 -06:00
2021-03-30 14:50:47 -05:00
instances [ key ] = val . MarkWithPaths ( afterMarks )
2020-04-22 21:09:47 -05:00
continue
2019-09-19 08:08:17 -05:00
}
ios , err := is . Current . Decode ( ty )
if err != nil {
2020-04-22 21:09:47 -05:00
// This shouldn't happen, since by the time we get here we
// should have upgraded the state data already.
2018-08-28 18:30:52 -05:00
diags = diags . Append ( & hcl . Diagnostic {
Severity : hcl . DiagError ,
2019-09-19 08:08:17 -05:00
Summary : "Invalid resource instance data in state" ,
2020-04-22 21:09:47 -05:00
Detail : fmt . Sprintf ( "Instance %s data could not be decoded from the state: %s." , instAddr , err ) ,
2018-08-28 18:30:52 -05:00
Subject : & config . DeclRange ,
} )
2020-04-22 21:09:47 -05:00
continue
2018-08-28 18:30:52 -05:00
}
2020-10-12 13:39:09 -05:00
val := ios . Value
2020-10-26 10:48:17 -05:00
2021-04-15 06:30:50 -05:00
// If our schema contains sensitive values, mark those as sensitive.
// Since decoding the instance object can also apply sensitivity marks,
// we must remove and combine those before remarking to avoid a double-
// mark error.
2021-03-10 10:47:01 -06:00
if schema . ContainsSensitive ( ) {
2021-04-15 06:30:50 -05:00
var marks [ ] cty . PathValueMarks
val , marks = val . UnmarkDeepWithPaths ( )
2021-04-26 15:26:47 -05:00
marks = append ( marks , schema . ValueMarks ( val , nil ) ... )
2021-04-15 06:30:50 -05:00
val = val . MarkWithPaths ( marks )
2020-10-12 13:39:09 -05:00
}
instances [ key ] = val
2020-04-22 21:09:47 -05:00
}
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 16:24:45 -05:00
2020-04-22 21:09:47 -05:00
var ret cty . Value
2018-05-03 20:28:12 -05:00
2020-04-22 21:09:47 -05:00
switch {
case config . Count != nil :
// figure out what the last index we have is
length := - 1
for key := range instances {
intKey , ok := key . ( addrs . IntKey )
if ! ok {
continue
}
if int ( intKey ) >= length {
length = int ( intKey ) + 1
2018-05-03 20:28:12 -05:00
}
}
2020-04-22 21:09:47 -05:00
if length > 0 {
vals := make ( [ ] cty . Value , length )
for key , instance := range instances {
intKey , ok := key . ( addrs . IntKey )
if ! ok {
// old key from state, which isn't valid for evaluation
continue
}
vals [ int ( intKey ) ] = instance
2019-12-03 10:16:42 -06:00
}
2018-08-28 18:30:52 -05:00
2020-04-22 21:09:47 -05:00
// Insert unknown values where there are any missing instances
for i , v := range vals {
if v == cty . NilVal {
vals [ i ] = cty . UnknownVal ( ty )
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 16:24:45 -05:00
}
}
2020-04-22 21:09:47 -05:00
ret = cty . TupleVal ( vals )
} else {
ret = cty . EmptyTupleVal
}
2019-12-03 10:16:42 -06:00
2020-04-22 21:09:47 -05:00
case config . ForEach != nil :
vals := make ( map [ string ] cty . Value )
for key , instance := range instances {
strKey , ok := key . ( addrs . StringKey )
if ! ok {
// old key that is being dropped and not used for evaluation
2019-12-03 10:16:42 -06:00
continue
}
2020-04-22 21:09:47 -05:00
vals [ string ( strKey ) ] = instance
2018-05-03 20:28:12 -05:00
}
2020-04-22 21:09:47 -05:00
if len ( vals ) > 0 {
// We use an object rather than a map here because resource schemas
// may include dynamically-typed attributes, which will then cause
// each instance to potentially have a different runtime type even
// though they all conform to the static schema.
ret = cty . ObjectVal ( vals )
} else {
ret = cty . EmptyObjectVal
}
2018-08-28 18:30:52 -05:00
2020-04-22 21:09:47 -05:00
default :
val , ok := instances [ addrs . NoKey ]
if ! ok {
// if the instance is missing, insert an unknown value
val = cty . UnknownVal ( ty )
2018-05-03 20:28:12 -05:00
}
2020-04-22 21:09:47 -05:00
ret = val
}
2018-05-03 20:28:12 -05:00
2020-04-22 21:09:47 -05:00
return ret , diags
2018-05-03 20:28:12 -05:00
}
2021-11-02 14:35:47 -05:00
func ( d * evaluationStateData ) getResourceSchema ( addr addrs . Resource , providerAddr addrs . Provider ) * configschema . Block {
schema , _ , err := d . Evaluator . Plugins . ResourceTypeSchema ( providerAddr , addr . Mode , addr . Type )
2021-08-31 19:53:03 -05:00
if err != nil {
// We have plently other codepaths that will detect and report
// schema lookup errors before we'd reach this point, so we'll just
// treat a failure here the same as having no schema.
return nil
}
2018-11-27 17:30:18 -06:00
return schema
terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
}
2018-05-03 20:28:12 -05:00
func ( d * evaluationStateData ) GetTerraformAttr ( addr addrs . TerraformAttr , rng tfdiags . SourceRange ) ( cty . Value , tfdiags . Diagnostics ) {
var diags tfdiags . Diagnostics
switch addr . Name {
case "workspace" :
workspaceName := d . Evaluator . Meta . Env
return cty . StringVal ( workspaceName ) , diags
case "env" :
// Prior to Terraform 0.12 there was an attribute "env", which was
// an alias name for "workspace". This was deprecated and is now
// removed.
diags = diags . Append ( & hcl . Diagnostic {
Severity : hcl . DiagError ,
Summary : ` Invalid "terraform" attribute ` ,
2021-09-13 14:21:26 -05:00
Detail : ` The terraform.env attribute was deprecated in v0.10 and removed in v0.12. The "state environment" concept was renamed to "workspace" in v0.12, and so the workspace name can now be accessed using the terraform.workspace attribute. ` ,
2018-05-03 20:28:12 -05:00
Subject : rng . ToHCL ( ) . Ptr ( ) ,
} )
return cty . DynamicVal , diags
default :
diags = diags . Append ( & hcl . Diagnostic {
Severity : hcl . DiagError ,
Summary : ` Invalid "terraform" attribute ` ,
Detail : fmt . Sprintf ( ` The "terraform" object does not have an attribute named %q. The only supported attribute is terraform.workspace, the name of the currently-selected workspace. ` , addr . Name ) ,
Subject : rng . ToHCL ( ) . Ptr ( ) ,
} )
return cty . DynamicVal , diags
}
terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
}
2018-05-03 20:28:12 -05:00
// nameSuggestion tries to find a name from the given slice of suggested names
// that is close to the given name and returns it if found. If no suggestion
// is close enough, returns the empty string.
//
// The suggestions are tried in order, so earlier suggestions take precedence
// if the given string is similar to two or more suggestions.
//
// This function is intended to be used with a relatively-small number of
// suggestions. It's not optimized for hundreds or thousands of them.
func nameSuggestion ( given string , suggestions [ ] string ) string {
for _ , suggestion := range suggestions {
dist := levenshtein . Distance ( given , suggestion , nil )
if dist < 3 { // threshold determined experimentally
return suggestion
}
}
return ""
terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
}
2018-09-28 19:15:35 -05:00
// moduleDisplayAddr returns a string describing the given module instance
// address that is appropriate for returning to users in situations where the
// root module is possible. Specifically, it returns "the root module" if the
// root module instance is given, or a string representation of the module
// address otherwise.
func moduleDisplayAddr ( addr addrs . ModuleInstance ) string {
switch {
case addr . IsRoot ( ) :
return "the root module"
default :
return addr . String ( )
}
}