mirror of
https://github.com/opentofu/opentofu.git
synced 2025-01-17 12:12:59 -06:00
a3403f2766
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.
193 lines
5.4 KiB
Go
193 lines
5.4 KiB
Go
package terraform
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/hashicorp/terraform/states"
|
|
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
"github.com/hashicorp/terraform/addrs"
|
|
"github.com/hashicorp/terraform/configs"
|
|
"github.com/hashicorp/terraform/plans"
|
|
)
|
|
|
|
// EvalReadDataDiff is an EvalNode implementation that executes a data
|
|
// resource's ReadDataDiff method to discover what attributes it exports.
|
|
type EvalReadDataDiff struct {
|
|
Addr addrs.ResourceInstance
|
|
Config *configs.Resource
|
|
Provider *ResourceProvider
|
|
ProviderSchema **ProviderSchema
|
|
|
|
Output **plans.ResourceInstanceChange
|
|
OutputValue *cty.Value
|
|
OutputState **states.ResourceInstanceObject
|
|
|
|
// Set Previous when re-evaluating diff during apply, to ensure that
|
|
// the "Destroy" flag is preserved.
|
|
Previous **plans.ResourceInstanceChange
|
|
}
|
|
|
|
func (n *EvalReadDataDiff) Eval(ctx EvalContext) (interface{}, error) {
|
|
return nil, fmt.Errorf("EvalReadDataDiff not yet updated for new state/plan/provider types")
|
|
/*
|
|
absAddr := n.Addr.Absolute(ctx.Path())
|
|
|
|
if n.ProviderSchema == nil || *n.ProviderSchema == nil {
|
|
return nil, fmt.Errorf("provider schema not available for %s", n.Addr)
|
|
}
|
|
|
|
var diags tfdiags.Diagnostics
|
|
|
|
// The provider API still expects our legacy InstanceInfo type.
|
|
legacyInfo := NewInstanceInfo(n.Addr.Absolute(ctx.Path()))
|
|
|
|
err := ctx.Hook(func(h Hook) (HookAction, error) {
|
|
return h.PreDiff(absAddr, cty.NullVal(cty.DynamicPseudoType), cty.NullVal(cty.DynamicPseudoType))
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var diff *InstanceDiff
|
|
var configVal cty.Value
|
|
|
|
if n.Previous != nil && *n.Previous != nil && (*n.Previous).GetDestroy() {
|
|
// If we're re-diffing for a diff that was already planning to
|
|
// destroy, then we'll just continue with that plan.
|
|
diff = &InstanceDiff{Destroy: true}
|
|
} else {
|
|
provider := *n.Provider
|
|
config := *n.Config
|
|
providerSchema := *n.ProviderSchema
|
|
schema := providerSchema.DataSources[n.Addr.Resource.Type]
|
|
if schema == nil {
|
|
// Should be caught during validation, so we don't bother with a pretty error here
|
|
return nil, fmt.Errorf("provider does not support data source %q", n.Addr.Resource.Type)
|
|
}
|
|
|
|
keyData := EvalDataForInstanceKey(n.Addr.Key)
|
|
|
|
var configDiags tfdiags.Diagnostics
|
|
configVal, _, configDiags = ctx.EvaluateBlock(config.Config, schema, nil, keyData)
|
|
diags = diags.Append(configDiags)
|
|
if configDiags.HasErrors() {
|
|
return nil, diags.Err()
|
|
}
|
|
|
|
// The provider API still expects our legacy ResourceConfig type.
|
|
legacyRC := NewResourceConfigShimmed(configVal, schema)
|
|
|
|
var err error
|
|
diff, err = provider.ReadDataDiff(legacyInfo, legacyRC)
|
|
if err != nil {
|
|
diags = diags.Append(err)
|
|
return nil, diags.Err()
|
|
}
|
|
if diff == nil {
|
|
diff = new(InstanceDiff)
|
|
}
|
|
|
|
// if id isn't explicitly set then it's always computed, because we're
|
|
// always "creating a new resource".
|
|
diff.init()
|
|
if _, ok := diff.Attributes["id"]; !ok {
|
|
diff.SetAttribute("id", &ResourceAttrDiff{
|
|
Old: "",
|
|
NewComputed: true,
|
|
RequiresNew: true,
|
|
Type: DiffAttrOutput,
|
|
})
|
|
}
|
|
}
|
|
|
|
err = ctx.Hook(func(h Hook) (HookAction, error) {
|
|
return h.PostDiff(legacyInfo, diff)
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
*n.Output = diff
|
|
|
|
if n.OutputValue != nil {
|
|
*n.OutputValue = configVal
|
|
}
|
|
|
|
if n.OutputState != nil {
|
|
state := &InstanceState{}
|
|
*n.OutputState = state
|
|
|
|
// Apply the diff to the returned state, so the state includes
|
|
// any attribute values that are not computed.
|
|
if !diff.Empty() && n.OutputState != nil {
|
|
*n.OutputState = state.MergeDiff(diff)
|
|
}
|
|
}
|
|
|
|
return nil, diags.ErrWithWarnings()
|
|
*/
|
|
}
|
|
|
|
// EvalReadDataApply is an EvalNode implementation that executes a data
|
|
// resource's ReadDataApply method to read data from the data source.
|
|
type EvalReadDataApply struct {
|
|
Addr addrs.ResourceInstance
|
|
Provider *ResourceProvider
|
|
Output **states.ResourceInstanceObject
|
|
Change **plans.ResourceInstanceChange
|
|
}
|
|
|
|
func (n *EvalReadDataApply) Eval(ctx EvalContext) (interface{}, error) {
|
|
return nil, fmt.Errorf("EvalReadDataApply not yet updated for new state/plan/provider types")
|
|
/*
|
|
provider := *n.Provider
|
|
change := *n.Change
|
|
absAddr := n.Addr.Absolute(ctx.Path())
|
|
|
|
// The provider and hook APIs still expect our legacy InstanceInfo type.
|
|
legacyInfo := NewInstanceInfo(n.Addr.Absolute(ctx.Path()))
|
|
|
|
// If the diff is for *destroying* this resource then we'll
|
|
// just drop its state and move on, since data resources don't
|
|
// support an actual "destroy" action.
|
|
if diff != nil && diff.GetDestroy() {
|
|
if n.Output != nil {
|
|
*n.Output = nil
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
// For the purpose of external hooks we present a data apply as a
|
|
// "Refresh" rather than an "Apply" because creating a data source
|
|
// is presented to users/callers as a "read" operation.
|
|
err := ctx.Hook(func(h Hook) (HookAction, error) {
|
|
// We don't have a state yet, so we'll just give the hook an
|
|
// empty one to work with.
|
|
return h.PreRefresh(absAddr, cty.NullVal(cty.DynamicPseudoType))
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
state, err := provider.ReadDataApply(legacyInfo, diff)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%s: %s", n.Addr.Absolute(ctx.Path()).String(), err)
|
|
}
|
|
|
|
err = ctx.Hook(func(h Hook) (HookAction, error) {
|
|
return h.PostRefresh(absAddr, state)
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if n.Output != nil {
|
|
*n.Output = state
|
|
}
|
|
|
|
return nil, nil
|
|
*/
|
|
}
|