mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-26 08:51:02 -06:00
343279110a
Previously our graph walker expected to recieve a data structure containing schemas for all of the provider and provisioner plugins used in the configuration and state. That made sense back when terraform.NewContext was responsible for loading all of the schemas before taking any other action, but it no longer has that responsiblity. Instead, we'll now make sure that the "contextPlugins" object reaches all of the locations where we need schema -- many of which already had access to that object anyway -- and then load the needed schemas just in time. The contextPlugins object memoizes schema lookups, so we can safely call it many times with the same provider address or provisioner type name and know that it'll still only load each distinct plugin once per Context object. As of this commit, the Context.Schemas method is now a public interface only and not used by logic in the "terraform" package at all. However, that does leave us in a rather tenuous situation of relying on the fact that all practical users of terraform.Context end up calling "Schemas" at some point in order to verify that we have all of the expected versions of plugins. That's a non-obvious implicit dependency, and so in subsequent commits we'll gradually move all responsibility for verifying plugin versions into the caller of terraform.NewContext, which'll heal a long-standing architectural wart whereby the caller is responsible for installing and locating the plugin executables but not for verifying that what's installed is conforming to the current configuration and dependency lock file.
81 lines
2.6 KiB
Go
81 lines
2.6 KiB
Go
package terraform
|
|
|
|
import (
|
|
"log"
|
|
|
|
"github.com/hashicorp/terraform/internal/addrs"
|
|
"github.com/hashicorp/terraform/internal/configs"
|
|
"github.com/hashicorp/terraform/internal/states"
|
|
"github.com/hashicorp/terraform/internal/tfdiags"
|
|
"github.com/zclconf/go-cty/cty"
|
|
)
|
|
|
|
// Validate performs semantic validation of a configuration, and returns
|
|
// any warnings or errors.
|
|
//
|
|
// Syntax and structural checks are performed by the configuration loader,
|
|
// and so are not repeated here.
|
|
//
|
|
// Validate considers only the configuration and so it won't catch any
|
|
// errors caused by current values in the state, or other external information
|
|
// such as root module input variables. However, the Plan function includes
|
|
// all of the same checks as Validate, in addition to the other work it does
|
|
// to consider the previous run state and the planning options.
|
|
func (c *Context) Validate(config *configs.Config) tfdiags.Diagnostics {
|
|
defer c.acquireRun("validate")()
|
|
|
|
var diags tfdiags.Diagnostics
|
|
|
|
moreDiags := CheckCoreVersionRequirements(config)
|
|
diags = diags.Append(moreDiags)
|
|
// If version constraints are not met then we'll bail early since otherwise
|
|
// we're likely to just see a bunch of other errors related to
|
|
// incompatibilities, which could be overwhelming for the user.
|
|
if diags.HasErrors() {
|
|
return diags
|
|
}
|
|
|
|
log.Printf("[DEBUG] Building and walking validate graph")
|
|
|
|
graph, moreDiags := ValidateGraphBuilder(&PlanGraphBuilder{
|
|
Config: config,
|
|
Plugins: c.plugins,
|
|
Validate: true,
|
|
State: states.NewState(),
|
|
}).Build(addrs.RootModuleInstance)
|
|
diags = diags.Append(moreDiags)
|
|
if moreDiags.HasErrors() {
|
|
return diags
|
|
}
|
|
|
|
// Validate is to check if the given module is valid regardless of
|
|
// input values, current state, etc. Therefore we populate all of the
|
|
// input values with unknown values of the expected type, allowing us
|
|
// to perform a type check without assuming any particular values.
|
|
varValues := make(InputValues)
|
|
for name, variable := range config.Module.Variables {
|
|
ty := variable.Type
|
|
if ty == cty.NilType {
|
|
// Can't predict the type at all, so we'll just mark it as
|
|
// cty.DynamicVal (unknown value of cty.DynamicPseudoType).
|
|
ty = cty.DynamicPseudoType
|
|
}
|
|
varValues[name] = &InputValue{
|
|
Value: cty.UnknownVal(ty),
|
|
SourceType: ValueFromUnknown,
|
|
}
|
|
}
|
|
|
|
walker, walkDiags := c.walk(graph, walkValidate, &graphWalkOpts{
|
|
Config: config,
|
|
RootVariableValues: varValues,
|
|
})
|
|
diags = diags.Append(walker.NonFatalDiagnostics)
|
|
diags = diags.Append(walkDiags)
|
|
if walkDiags.HasErrors() {
|
|
return diags
|
|
}
|
|
|
|
return diags
|
|
}
|