mirror of
https://github.com/opentofu/opentofu.git
synced 2026-06-10 00:50:50 -04:00
Some checks failed
build / Build for freebsd_386 (push) Has been cancelled
build / Build for linux_386 (push) Has been cancelled
build / Build for openbsd_386 (push) Has been cancelled
build / Build for windows_386 (push) Has been cancelled
build / Build for freebsd_amd64 (push) Has been cancelled
build / Build for linux_amd64 (push) Has been cancelled
build / Build for openbsd_amd64 (push) Has been cancelled
build / Build for solaris_amd64 (push) Has been cancelled
build / Build for windows_amd64 (push) Has been cancelled
build / Build for freebsd_arm (push) Has been cancelled
build / Build for linux_arm (push) Has been cancelled
build / Build for linux_arm64 (push) Has been cancelled
build / Build for darwin_amd64 (push) Has been cancelled
build / Build for darwin_arm64 (push) Has been cancelled
build / End-to-end Tests for linux_386 (push) Has been cancelled
build / End-to-end Tests for windows_386 (push) Has been cancelled
build / End-to-end Tests for darwin_amd64 (push) Has been cancelled
build / End-to-end Tests for linux_amd64 (push) Has been cancelled
build / End-to-end Tests for windows_amd64 (push) Has been cancelled
Quick Checks / List files changed for pull request (push) Has been cancelled
Quick Checks / License Checks (push) Has been cancelled
Website checks / List files changed for pull request (push) Has been cancelled
Quick Checks / Unit tests for linux_386 (push) Has been cancelled
Quick Checks / Unit tests for linux_amd64 (push) Has been cancelled
Quick Checks / Unit tests for windows_amd64 (push) Has been cancelled
Quick Checks / Unit tests for linux_arm (push) Has been cancelled
Quick Checks / Unit tests for darwin_arm64 (push) Has been cancelled
Quick Checks / Unit tests for linux_arm64 (push) Has been cancelled
Quick Checks / Race Tests (push) Has been cancelled
Quick Checks / End-to-end Tests (push) Has been cancelled
Quick Checks / Code Consistency Checks (push) Has been cancelled
Website checks / Build (push) Has been cancelled
Website checks / Test Installation Instructions (push) Has been cancelled
Our new language runtime uses a set of new methods on SyncState to work with its preferred "full" representation of resource instance objects, but those are implemented in terms of methods that already existed for the old runtime's benefit and so we need to deal with some quirks of those existing methods. One such quirk is that the operations to write or remove objects also want to update some resource-level and instance-level metadata as a side-effect, and we need to carry through that metadata even when we're intending to completely remove a resource instance object. To preserve our goal of leaving the existing codepaths untouched for now, this pushes a little complexity back up into the main caller in the apply engine, forcing it to call a different method when it knows it has deleted an object. That new method then only takes the metadata we need and not an actual resource instance object, so it gels better with the underlying ModuleState methods it's implemented in terms of. Hopefully in the long run we'll rethink the state models to not rely on these hidden side-effects, but that's beyond the scope of our current phase of work on the new language runtime. Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
128 lines
5.1 KiB
Go
128 lines
5.1 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/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) (*resourceInstanceObject, tfdiags.Diagnostics) {
|
|
var diags tfdiags.Diagnostics
|
|
|
|
ret := &resourceInstanceObject{
|
|
Addr: inst.Addr.CurrentObject(),
|
|
Dependencies: addrs.MakeSet[addrs.AbsResourceInstanceObject](),
|
|
Provider: inst.Provider,
|
|
|
|
// We'll start off with a completely-unknown placeholder value, but
|
|
// we might refine this to be more specific as we learn more below.
|
|
PlaceholderValue: cty.DynamicVal,
|
|
|
|
// NOTE: PlannedChange remains nil until we actually produce a plan,
|
|
// so early returns with errors are not guaranteed to have a valid
|
|
// change object. Evaluation falls back on using PlaceholderValue
|
|
// when no planned change is present.
|
|
}
|
|
for dep := range inst.RequiredResourceInstances.All() {
|
|
ret.Dependencies.Add(dep.CurrentObject())
|
|
}
|
|
|
|
validateDiags := p.planCtx.providers.ValidateResourceConfig(ctx, inst.Provider, inst.ResourceMode, inst.ResourceType, inst.ConfigVal)
|
|
diags = diags.Append(validateDiags)
|
|
if diags.HasErrors() {
|
|
return ret, diags
|
|
}
|
|
|
|
if inst.ProviderInstance == nil {
|
|
// TODO: Record that this was deferred because we don't yet know which
|
|
// provider instance it belongs to.
|
|
return ret, diags
|
|
}
|
|
|
|
// 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 set ret.PlannedChange
|
|
// to an object using the [plans.Read] action, without writing a new
|
|
// object into the refreshed state yet.
|
|
|
|
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 ret, 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 ret, diags
|
|
}
|
|
// TODO: Verify that the object the provider returned is a valid completion
|
|
// of the configuration value.
|
|
|
|
// TODO: Update the refreshed state to match what we've just read.
|
|
|
|
// Since we've already read the data source during the planning phase,
|
|
// we don't need a PlannedChange here and can instead just use the result
|
|
// as the PlaceholderValue.
|
|
ret.PlaceholderValue = resp.State
|
|
|
|
return ret, diags
|
|
}
|
|
|
|
func (p *planGlue) planOrphanDataResourceInstance(_ context.Context, addr addrs.AbsResourceInstance, state *states.ResourceInstanceObjectFullSrc) (*resourceInstanceObject, 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.RemoveResourceInstanceObjectFull(addr.CurrentObject(), state.ProviderInstanceAddr)
|
|
|
|
return &resourceInstanceObject{
|
|
Addr: addr.CurrentObject(),
|
|
Dependencies: addrs.MakeSet[addrs.AbsResourceInstanceObject](),
|
|
Provider: state.ProviderInstanceAddr.Config.Config.Provider,
|
|
PlaceholderValue: cty.NullVal(cty.DynamicPseudoType),
|
|
}, diags
|
|
}
|