opentofu/internal/engine/planning/plan_data.go
Christian Mesh 8ce780b4e0
engine/ephemeral: Wire together basic ephemeral functionality (#3710)
Signed-off-by: Christian Mesh <christianmesh1@gmail.com>
2026-02-04 16:44:20 -05:00

100 lines
4 KiB
Go

// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package planning
import (
"context"
"fmt"
"github.com/zclconf/go-cty/cty"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/engine/internal/execgraph"
"github.com/opentofu/opentofu/internal/lang/eval"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/tfdiags"
)
func (p *planGlue) planDesiredDataResourceInstance(ctx context.Context, inst *eval.DesiredResourceInstance, egb *execGraphBuilder) (cty.Value, execgraph.ResourceInstanceResultRef, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
validateDiags := p.planCtx.providers.ValidateResourceConfig(ctx, inst.Provider, inst.ResourceMode, inst.ResourceType, inst.ConfigVal)
diags = diags.Append(validateDiags)
if diags.HasErrors() {
return cty.DynamicVal, nil, diags
}
if inst.ProviderInstance == nil {
// TODO: Record that this was deferred because we don't yet know which
// provider instance it belongs to.
return deferredVal(cty.DynamicVal), nil, diags
}
// TODO: There are various other reasons why we might need to defer planning
// this until a future plan/apply round.
// The equivalent of "refreshing" a data resource is just to discard it
// completely, because we only retain the previous result in state snapshots
// to support unusual situations like "tofu console"; it's not expected that
// data resource instances persist between rounds and they cannot because
// the protocol doesn't include any way to "upgrade" them if the provider
// schema has changed since previous round.
// FIXME: State is still using the weird old representation of provider
// instance addresses, so we can't actually populate the provider instance
// arguments properly here.
p.planCtx.refreshedState.SetResourceInstanceCurrent(inst.Addr, nil, addrs.AbsProviderConfig{}, inst.ProviderInstance.Key)
// TODO: If the config value is not wholly known, or if any resource
// instance in inst.RequiredResourceInstances already has a planned change,
// then plan to read this during the apply phase and return a "proposed new
// value" for use during the planning phase.
providerClient, moreDiags := p.providerClient(ctx, *inst.ProviderInstance)
if providerClient == nil {
moreDiags = moreDiags.Append(tfdiags.AttributeValue(
tfdiags.Error,
"Provider instance not available",
fmt.Sprintf("Cannot plan %s because its associated provider instance %s cannot initialize.", inst.Addr, *inst.ProviderInstance),
nil,
))
}
diags = diags.Append(moreDiags)
if moreDiags.HasErrors() {
return cty.DynamicVal, nil, diags
}
resp := providerClient.ReadDataSource(ctx, providers.ReadDataSourceRequest{
TypeName: inst.ResourceType,
Config: inst.ConfigVal,
// TODO: ProviderMeta is a rarely-used feature that only really makes
// sense when the module and provider are both written by the same
// party and the module author is using the provider as a way to
// transport module usage telemetry. We should decide whether we want
// to keep supporting that, and if so design a way for the relevant
// meta value to get from the evaluator into here.
ProviderMeta: cty.NullVal(cty.DynamicPseudoType),
})
diags = diags.Append(resp.Diagnostics)
if resp.Diagnostics.HasErrors() {
return cty.DynamicVal, nil, diags
}
// TODO: Implement
panic("unimplemented")
}
func (p *planGlue) planOrphanDataResourceInstance(_ context.Context, addr addrs.AbsResourceInstance, state *states.ResourceInstanceObjectFullSrc, egb *execGraphBuilder) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
// An orphan data object is always just discarded completely, because
// OpenTofu retains them only for esoteric uses like the "tofu console"
// command: they are not actually expected to persist between rounds.
p.planCtx.refreshedState.SetResourceInstanceObjectFull(addr, states.NotDeposed, nil)
return diags
}