mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-19 17:59:05 -05:00
Do not handle yet the deferred signal from providers for actions other than open ephemeral resource
Signed-off-by: Andrei Ciobanu <andrei.ciobanu@opentofu.org>
This commit is contained in:
@@ -34,14 +34,6 @@ type GRPCProviderPlugin struct {
|
||||
}
|
||||
|
||||
var clientCapabilities = &proto.ClientCapabilities{
|
||||
// DeferralAllowed tells the provider that it is allowed to respond to
|
||||
// all of the various post-configuration requests (as described by the
|
||||
// [providers.Configured] interface) by reporting that the request
|
||||
// must be "deferred" because there isn't yet enough information to
|
||||
// satisfy the request. Setting this means that we need to be prepared
|
||||
// for there to be a "deferred" object in the response from various
|
||||
// other provider RPC functions.
|
||||
DeferralAllowed: true,
|
||||
// WriteOnlyAttributesAllowed indicates that the current system version
|
||||
// supports write-only attributes.
|
||||
// This enables the SDK to run specific validations and enable the
|
||||
@@ -502,11 +494,6 @@ func (p *GRPCProvider) ReadResource(ctx context.Context, r providers.ReadResourc
|
||||
return resp
|
||||
}
|
||||
resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
|
||||
if protoDeferred := protoResp.Deferred; protoDeferred != nil {
|
||||
reason := convert.DeferralReasonFromProto(protoDeferred.Reason)
|
||||
resp.Diagnostics = resp.Diagnostics.Append(providers.NewDeferralDiagnostic(reason))
|
||||
return resp
|
||||
}
|
||||
|
||||
state, err := decodeDynamicValue(protoResp.NewState, resSchema.Block.ImpliedType())
|
||||
if err != nil {
|
||||
@@ -589,11 +576,6 @@ func (p *GRPCProvider) PlanResourceChange(ctx context.Context, r providers.PlanR
|
||||
return resp
|
||||
}
|
||||
resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
|
||||
if protoDeferred := protoResp.Deferred; protoDeferred != nil {
|
||||
reason := convert.DeferralReasonFromProto(protoDeferred.Reason)
|
||||
resp.Diagnostics = resp.Diagnostics.Append(providers.NewDeferralDiagnostic(reason))
|
||||
return resp
|
||||
}
|
||||
|
||||
state, err := decodeDynamicValue(protoResp.PlannedState, resSchema.Block.ImpliedType())
|
||||
if err != nil {
|
||||
@@ -716,11 +698,6 @@ func (p *GRPCProvider) ImportResourceState(ctx context.Context, r providers.Impo
|
||||
return resp
|
||||
}
|
||||
resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
|
||||
if protoDeferred := protoResp.Deferred; protoDeferred != nil {
|
||||
reason := convert.DeferralReasonFromProto(protoDeferred.Reason)
|
||||
resp.Diagnostics = resp.Diagnostics.Append(providers.NewDeferralDiagnostic(reason))
|
||||
return resp
|
||||
}
|
||||
|
||||
for _, imported := range protoResp.ImportedResources {
|
||||
resource := providers.ImportedResource{
|
||||
@@ -839,11 +816,6 @@ func (p *GRPCProvider) ReadDataSource(ctx context.Context, r providers.ReadDataS
|
||||
return resp
|
||||
}
|
||||
resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
|
||||
if protoDeferred := protoResp.Deferred; protoDeferred != nil {
|
||||
reason := convert.DeferralReasonFromProto(protoDeferred.Reason)
|
||||
resp.Diagnostics = resp.Diagnostics.Append(providers.NewDeferralDiagnostic(reason))
|
||||
return resp
|
||||
}
|
||||
|
||||
state, err := decodeDynamicValue(protoResp.State, dataSchema.Block.ImpliedType())
|
||||
if err != nil {
|
||||
@@ -881,7 +853,10 @@ func (p *GRPCProvider) OpenEphemeralResource(ctx context.Context, r providers.Op
|
||||
Config: &proto.DynamicValue{
|
||||
Msgpack: config,
|
||||
},
|
||||
ClientCapabilities: clientCapabilities,
|
||||
ClientCapabilities: &proto.ClientCapabilities{
|
||||
DeferralAllowed: true,
|
||||
WriteOnlyAttributesAllowed: clientCapabilities.WriteOnlyAttributesAllowed,
|
||||
},
|
||||
}
|
||||
|
||||
protoResp, err := p.client.OpenEphemeralResource(ctx, protoReq)
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
"github.com/zclconf/go-cty/cty/msgpack"
|
||||
@@ -826,52 +825,6 @@ func TestGRPCProvider_PlanResourceChange(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGRPCProvider_PlanResourceChange_deferred(t *testing.T) {
|
||||
client := mockProviderClient(t)
|
||||
p := &GRPCProvider{
|
||||
client: client,
|
||||
}
|
||||
|
||||
client.EXPECT().PlanResourceChange(
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
).Return(&proto.PlanResourceChange_Response{
|
||||
PlannedState: &proto.DynamicValue{
|
||||
Msgpack: []byte("\x81\xa4attr\xa3bar"),
|
||||
},
|
||||
Deferred: &proto.Deferred{
|
||||
Reason: proto.Deferred_PROVIDER_CONFIG_UNKNOWN,
|
||||
},
|
||||
}, nil)
|
||||
|
||||
resp := p.PlanResourceChange(t.Context(), providers.PlanResourceChangeRequest{
|
||||
TypeName: "resource",
|
||||
PriorState: cty.ObjectVal(map[string]cty.Value{
|
||||
"attr": cty.StringVal("foo"),
|
||||
}),
|
||||
ProposedNewState: cty.ObjectVal(map[string]cty.Value{
|
||||
"attr": cty.StringVal("bar"),
|
||||
}),
|
||||
Config: cty.ObjectVal(map[string]cty.Value{
|
||||
"attr": cty.StringVal("bar"),
|
||||
}),
|
||||
})
|
||||
|
||||
if len(resp.Diagnostics) != 1 {
|
||||
t.Fatal("wrong number of diagnostics; want one\n" + spew.Sdump(resp.Diagnostics))
|
||||
}
|
||||
desc := resp.Diagnostics[0].Description()
|
||||
if got, want := desc.Summary, `Provider configuration is incomplete`; got != want {
|
||||
t.Errorf("wrong error summary\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
if got, want := desc.Detail, `The provider was unable to work with this resource because the associated provider configuration makes use of values from other resources that will not be known until after apply.`; got != want {
|
||||
t.Errorf("wrong error detail\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
if !providers.IsDeferralDiagnostic(resp.Diagnostics[0]) {
|
||||
t.Errorf("diagnostic is not marked as being a \"deferral diagnostic\"")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGRPCProvider_PlanResourceChangeJSON(t *testing.T) {
|
||||
client := mockProviderClient(t)
|
||||
p := &GRPCProvider{
|
||||
|
||||
@@ -34,14 +34,6 @@ type GRPCProviderPlugin struct {
|
||||
}
|
||||
|
||||
var clientCapabilities = &proto6.ClientCapabilities{
|
||||
// DeferralAllowed tells the provider that it is allowed to respond to
|
||||
// all of the various post-configuration requests (as described by the
|
||||
// [providers.Configured] interface) by reporting that the request
|
||||
// must be "deferred" because there isn't yet enough information to
|
||||
// satisfy the request. Setting this means that we need to be prepared
|
||||
// for there to be a "deferred" object in the response from various
|
||||
// other provider RPC functions.
|
||||
DeferralAllowed: true,
|
||||
// WriteOnlyAttributesAllowed indicates that the current system version
|
||||
// supports write-only attributes.
|
||||
// This enables the SDK to run specific validations and enable the
|
||||
@@ -491,11 +483,6 @@ func (p *GRPCProvider) ReadResource(ctx context.Context, r providers.ReadResourc
|
||||
return resp
|
||||
}
|
||||
resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
|
||||
if protoDeferred := protoResp.Deferred; protoDeferred != nil {
|
||||
reason := convert.DeferralReasonFromProto(protoDeferred.Reason)
|
||||
resp.Diagnostics = resp.Diagnostics.Append(providers.NewDeferralDiagnostic(reason))
|
||||
return resp
|
||||
}
|
||||
|
||||
state, err := decodeDynamicValue(protoResp.NewState, resSchema.Block.ImpliedType())
|
||||
if err != nil {
|
||||
@@ -578,11 +565,6 @@ func (p *GRPCProvider) PlanResourceChange(ctx context.Context, r providers.PlanR
|
||||
return resp
|
||||
}
|
||||
resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
|
||||
if protoDeferred := protoResp.Deferred; protoDeferred != nil {
|
||||
reason := convert.DeferralReasonFromProto(protoDeferred.Reason)
|
||||
resp.Diagnostics = resp.Diagnostics.Append(providers.NewDeferralDiagnostic(reason))
|
||||
return resp
|
||||
}
|
||||
|
||||
state, err := decodeDynamicValue(protoResp.PlannedState, resSchema.Block.ImpliedType())
|
||||
if err != nil {
|
||||
@@ -705,11 +687,6 @@ func (p *GRPCProvider) ImportResourceState(ctx context.Context, r providers.Impo
|
||||
return resp
|
||||
}
|
||||
resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
|
||||
if protoDeferred := protoResp.Deferred; protoDeferred != nil {
|
||||
reason := convert.DeferralReasonFromProto(protoDeferred.Reason)
|
||||
resp.Diagnostics = resp.Diagnostics.Append(providers.NewDeferralDiagnostic(reason))
|
||||
return resp
|
||||
}
|
||||
|
||||
for _, imported := range protoResp.ImportedResources {
|
||||
resource := providers.ImportedResource{
|
||||
@@ -828,11 +805,6 @@ func (p *GRPCProvider) ReadDataSource(ctx context.Context, r providers.ReadDataS
|
||||
return resp
|
||||
}
|
||||
resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
|
||||
if protoDeferred := protoResp.Deferred; protoDeferred != nil {
|
||||
reason := convert.DeferralReasonFromProto(protoDeferred.Reason)
|
||||
resp.Diagnostics = resp.Diagnostics.Append(providers.NewDeferralDiagnostic(reason))
|
||||
return resp
|
||||
}
|
||||
|
||||
state, err := decodeDynamicValue(protoResp.State, dataSchema.Block.ImpliedType())
|
||||
if err != nil {
|
||||
@@ -870,7 +842,10 @@ func (p *GRPCProvider) OpenEphemeralResource(ctx context.Context, r providers.Op
|
||||
Config: &proto6.DynamicValue{
|
||||
Msgpack: config,
|
||||
},
|
||||
ClientCapabilities: clientCapabilities,
|
||||
ClientCapabilities: &proto6.ClientCapabilities{
|
||||
DeferralAllowed: true,
|
||||
WriteOnlyAttributesAllowed: clientCapabilities.WriteOnlyAttributesAllowed,
|
||||
},
|
||||
}
|
||||
|
||||
protoResp, err := p.client.OpenEphemeralResource(ctx, protoReq)
|
||||
|
||||
@@ -833,52 +833,6 @@ func TestGRPCProvider_PlanResourceChange(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGRPCProvider_PlanResourceChange_deferred(t *testing.T) {
|
||||
client := mockProviderClient(t)
|
||||
p := &GRPCProvider{
|
||||
client: client,
|
||||
}
|
||||
|
||||
client.EXPECT().PlanResourceChange(
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
).Return(&proto.PlanResourceChange_Response{
|
||||
PlannedState: &proto.DynamicValue{
|
||||
Msgpack: []byte("\x81\xa4attr\xa3bar"),
|
||||
},
|
||||
Deferred: &proto.Deferred{
|
||||
Reason: proto.Deferred_PROVIDER_CONFIG_UNKNOWN,
|
||||
},
|
||||
}, nil)
|
||||
|
||||
resp := p.PlanResourceChange(t.Context(), providers.PlanResourceChangeRequest{
|
||||
TypeName: "resource",
|
||||
PriorState: cty.ObjectVal(map[string]cty.Value{
|
||||
"attr": cty.StringVal("foo"),
|
||||
}),
|
||||
ProposedNewState: cty.ObjectVal(map[string]cty.Value{
|
||||
"attr": cty.StringVal("bar"),
|
||||
}),
|
||||
Config: cty.ObjectVal(map[string]cty.Value{
|
||||
"attr": cty.StringVal("bar"),
|
||||
}),
|
||||
})
|
||||
|
||||
if len(resp.Diagnostics) != 1 {
|
||||
t.Fatal("wrong number of diagnostics; want one\n" + spew.Sdump(resp.Diagnostics))
|
||||
}
|
||||
desc := resp.Diagnostics[0].Description()
|
||||
if got, want := desc.Summary, `Provider configuration is incomplete`; got != want {
|
||||
t.Errorf("wrong error summary\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
if got, want := desc.Detail, `The provider was unable to work with this resource because the associated provider configuration makes use of values from other resources that will not be known until after apply.`; got != want {
|
||||
t.Errorf("wrong error detail\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
if !providers.IsDeferralDiagnostic(resp.Diagnostics[0]) {
|
||||
t.Errorf("diagnostic is not marked as being a \"deferral diagnostic\"")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGRPCProvider_PlanResourceChangeJSON(t *testing.T) {
|
||||
client := mockProviderClient(t)
|
||||
p := &GRPCProvider{
|
||||
|
||||
@@ -5064,97 +5064,6 @@ func TestContext2Plan_dataSourceReadPlanError(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestContext2Plan_providerDefersPlanning(t *testing.T) {
|
||||
m := testModuleInline(t, map[string]string{
|
||||
"main.tf": `
|
||||
resource "test" "test" {
|
||||
}
|
||||
`,
|
||||
})
|
||||
|
||||
tests := []struct {
|
||||
DeferralReason providers.DeferralReason
|
||||
WantDiagSummary, WantDiagDetail string
|
||||
}{
|
||||
{
|
||||
DeferralReason: providers.DeferredBecauseProviderConfigUnknown,
|
||||
WantDiagSummary: `Provider configuration is incomplete`,
|
||||
WantDiagDetail: `The provider was unable to work with this resource because the associated provider configuration makes use of values from other resources that will not be known until after apply.
|
||||
|
||||
To work around this, use the planning option -exclude="test.test" to first apply without this object, and then apply normally to converge.`,
|
||||
},
|
||||
{
|
||||
DeferralReason: providers.DeferredBecauseResourceConfigUnknown,
|
||||
WantDiagSummary: `Resource configuration is incomplete`,
|
||||
WantDiagDetail: `The provider was unable to act on this resource configuration because it makes use of values from other resources that will not be known until after apply.
|
||||
|
||||
To work around this, use the planning option -exclude="test.test" to first apply without this object, and then apply normally to converge.`,
|
||||
},
|
||||
{
|
||||
// This one is currently a generic fallback message because it's
|
||||
// unclear what this reason is intended to mean and no providers
|
||||
// are using it yet at the time of writing.
|
||||
DeferralReason: providers.DeferredBecausePrereqAbsent,
|
||||
WantDiagSummary: `Operation cannot be completed yet`,
|
||||
WantDiagDetail: `The provider reported that it is not able to perform the requested operation until more information is available.
|
||||
|
||||
To work around this, use the planning option -exclude="test.test" to first apply without this object, and then apply normally to converge.`,
|
||||
},
|
||||
{
|
||||
// This special reason is the one we use if a provider returns
|
||||
// a later-added reason that the current OpenTofu version doesn't
|
||||
// know about.
|
||||
DeferralReason: providers.DeferredReasonUnknown,
|
||||
WantDiagSummary: `Operation cannot be completed yet`,
|
||||
WantDiagDetail: `The provider reported that it is not able to perform the requested operation until more information is available.
|
||||
|
||||
To work around this, use the planning option -exclude="test.test" to first apply without this object, and then apply normally to converge.`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.DeferralReason.String(), func(t *testing.T) {
|
||||
provider := &MockProvider{
|
||||
GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
|
||||
ResourceTypes: map[string]providers.Schema{
|
||||
"test": {
|
||||
Block: &configschema.Block{},
|
||||
},
|
||||
},
|
||||
},
|
||||
PlanResourceChangeFn: func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
|
||||
var diags tfdiags.Diagnostics
|
||||
diags = diags.Append(providers.NewDeferralDiagnostic(
|
||||
test.DeferralReason,
|
||||
))
|
||||
return providers.PlanResourceChangeResponse{
|
||||
Diagnostics: diags,
|
||||
}
|
||||
},
|
||||
}
|
||||
tofuCtx := testContext2(t, &ContextOpts{
|
||||
Providers: map[addrs.Provider]providers.Factory{
|
||||
addrs.NewDefaultProvider("test"): testProviderFuncFixed(provider),
|
||||
},
|
||||
})
|
||||
_, diags := tofuCtx.Plan(t.Context(), m, states.NewState(), DefaultPlanOpts)
|
||||
if !diags.HasErrors() {
|
||||
t.Fatal("plan succeeded; want an error")
|
||||
}
|
||||
if len(diags) != 1 {
|
||||
t.Fatal("wrong number of diagnostics; want one\n" + spew.Sdump(diags.ForRPC()))
|
||||
}
|
||||
desc := diags[0].Description()
|
||||
if got, want := test.WantDiagSummary, desc.Summary; got != want {
|
||||
t.Errorf("wrong error summary\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
if got, want := test.WantDiagDetail, desc.Detail; got != want {
|
||||
t.Errorf("wrong error detail\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestContext2Plan_ignoredMarkedValue(t *testing.T) {
|
||||
m := testModuleInline(t, map[string]string{
|
||||
"main.tf": `
|
||||
|
||||
@@ -3257,63 +3257,6 @@ func (n *NodeAbstractResourceInstance) getProvider(ctx context.Context, evalCtx
|
||||
return underlyingProvider, schema, err
|
||||
}
|
||||
|
||||
func maybeImproveResourceInstanceDiagnostics(diags tfdiags.Diagnostics, excludeAddr addrs.Targetable) tfdiags.Diagnostics {
|
||||
// We defer allocating a new diagnostics array until we know we need to
|
||||
// change something, because most of the time we'll just be returning
|
||||
// the given diagnostics verbatim.
|
||||
var ret tfdiags.Diagnostics
|
||||
for i, diag := range diags {
|
||||
if excludeAddr != nil && providers.IsDeferralDiagnostic(diag) {
|
||||
// We've found a diagnostic we want to change, so we'll allocate
|
||||
// a new diagnostics array if we didn't already.
|
||||
if ret == nil {
|
||||
ret = make(tfdiags.Diagnostics, len(diags))
|
||||
copy(ret, diags)
|
||||
}
|
||||
// FIXME: The following is a hack to slightly modify the diagnostic
|
||||
// with an extra paragraph of detail content. If this becomes a
|
||||
// more common need elsewhere then we should find a less clunky way
|
||||
// to do this, probably with a new feature in tfdiags.
|
||||
desc := diag.Description()
|
||||
src := diag.Source()
|
||||
extraDetail := fmt.Sprintf(
|
||||
// FIXME: This should use a technique similar to evalchecks.commandLineArgumentsSuggestion
|
||||
// to generate appropriate quoting/escaping of the address for the current platform.
|
||||
"\n\nTo work around this, use the planning option -exclude=%q to first apply without this object, and then apply normally to converge.",
|
||||
excludeAddr.String(),
|
||||
)
|
||||
newDiag := &hcl.Diagnostic{
|
||||
Severity: diag.Severity().ToHCL(),
|
||||
Summary: desc.Summary,
|
||||
Detail: desc.Detail + extraDetail,
|
||||
}
|
||||
if src.Subject != nil {
|
||||
newDiag.Subject = src.Subject.ToHCL().Ptr()
|
||||
}
|
||||
if src.Context != nil {
|
||||
newDiag.Context = src.Context.ToHCL().Ptr()
|
||||
}
|
||||
// The following is a little awkward because of how tfdiags is
|
||||
// designed: we need to "append" a new diagnostic over the
|
||||
// one we're trying to replace so that tfdiags has an opportunity
|
||||
// to transform it, so we'll make a zero-length slice whose
|
||||
// capacity covers the one element we're trying to replace.
|
||||
appendTo := ret[i : i : i+1]
|
||||
appendTo = appendTo.Append(newDiag)
|
||||
// appendTo.Append isn't _actually_ required to use the
|
||||
// capacity we gave it (that's an implementation detail)
|
||||
// so just to make sure we'll copy from what was returned
|
||||
// into the final slot. This is likely to be a no-op in most
|
||||
// cases.
|
||||
ret[i] = appendTo[0]
|
||||
}
|
||||
}
|
||||
if ret == nil { // We didn't change anything
|
||||
return diags
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (n *NodeAbstractResourceInstance) applyEphemeralResource(ctx context.Context, evalCtx EvalContext) (*states.ResourceInstanceObject, instances.RepetitionData, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
var keyData instances.RepetitionData
|
||||
|
||||
@@ -15,9 +15,7 @@ import (
|
||||
"github.com/opentofu/opentofu/internal/addrs"
|
||||
"github.com/opentofu/opentofu/internal/configs"
|
||||
"github.com/opentofu/opentofu/internal/configs/configschema"
|
||||
"github.com/opentofu/opentofu/internal/providers"
|
||||
"github.com/opentofu/opentofu/internal/states"
|
||||
"github.com/opentofu/opentofu/internal/tfdiags"
|
||||
)
|
||||
|
||||
func TestNodeAbstractResourceInstanceProvider(t *testing.T) {
|
||||
@@ -268,72 +266,3 @@ func TestFilterResourceProvisioners(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaybeImproveResourceInstanceDiagnostics(t *testing.T) {
|
||||
// This test is focused mainly on whether
|
||||
// maybeImproveResourceInstanceDiagnostics is able to correctly identify
|
||||
// deferral-related diagnostics and transform them, while keeping
|
||||
// other unrelated diagnostics intact and unmodified.
|
||||
// TestContext2Plan_providerDefersPlanning tests that the effect of
|
||||
// this function is exposed externally when a provider's PlanResourceChange
|
||||
// method returns a suitable diagnostic.
|
||||
|
||||
var input tfdiags.Diagnostics
|
||||
input = input.Append(tfdiags.Sourceless(
|
||||
tfdiags.Warning,
|
||||
"This is not a deferral-related diagnostic",
|
||||
"This one should not be modified at all.",
|
||||
))
|
||||
input = input.Append(providers.NewDeferralDiagnostic(providers.DeferredBecauseProviderConfigUnknown))
|
||||
input = input.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"This is not a deferral-related diagnostic",
|
||||
"This one should not be modified at all.",
|
||||
))
|
||||
input = input.Append(providers.NewDeferralDiagnostic(providers.DeferredBecauseResourceConfigUnknown))
|
||||
input = input.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"This is not a deferral-related diagnostic either",
|
||||
"Leave this one alone too.",
|
||||
))
|
||||
|
||||
// We'll use ForRPC here just to make the diagnostics easier to compare,
|
||||
// since we care primarily about their description test here.
|
||||
got := maybeImproveResourceInstanceDiagnostics(input, mustAbsResourceAddr("foo.bar").Instance(addrs.IntKey(1))).ForRPC()
|
||||
var want tfdiags.Diagnostics
|
||||
want = want.Append(tfdiags.Sourceless(
|
||||
tfdiags.Warning,
|
||||
"This is not a deferral-related diagnostic",
|
||||
"This one should not be modified at all.",
|
||||
))
|
||||
want = want.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Provider configuration is incomplete",
|
||||
`The provider was unable to work with this resource because the associated provider configuration makes use of values from other resources that will not be known until after apply.
|
||||
|
||||
To work around this, use the planning option -exclude="foo.bar[1]" to first apply without this object, and then apply normally to converge.`,
|
||||
))
|
||||
want = want.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"This is not a deferral-related diagnostic",
|
||||
"This one should not be modified at all.",
|
||||
))
|
||||
want = want.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Resource configuration is incomplete",
|
||||
`The provider was unable to act on this resource configuration because it makes use of values from other resources that will not be known until after apply.
|
||||
|
||||
To work around this, use the planning option -exclude="foo.bar[1]" to first apply without this object, and then apply normally to converge.`,
|
||||
))
|
||||
want = want.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"This is not a deferral-related diagnostic either",
|
||||
"Leave this one alone too.",
|
||||
))
|
||||
want = want.ForRPC()
|
||||
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Error("wrong result\n" + diff)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ func (n *graphNodeImportState) Execute(ctx context.Context, evalCtx EvalContext,
|
||||
TypeName: n.Addr.Resource.Resource.Type,
|
||||
ID: n.ID,
|
||||
})
|
||||
diags = diags.Append(maybeImproveResourceInstanceDiagnostics(resp.Diagnostics, n.Addr))
|
||||
diags = diags.Append(resp.Diagnostics)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
|
||||
@@ -351,7 +351,7 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx context.Conte
|
||||
// The import process handles its own refresh
|
||||
if !n.skipRefresh && !importing {
|
||||
s, refreshDiags := n.refresh(ctx, evalCtx, states.NotDeposed, instanceRefreshState)
|
||||
diags = diags.Append(maybeImproveResourceInstanceDiagnostics(refreshDiags, addr))
|
||||
diags = diags.Append(refreshDiags)
|
||||
if diags.HasErrors() {
|
||||
return diags
|
||||
}
|
||||
@@ -389,7 +389,7 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx context.Conte
|
||||
change, instancePlanState, repeatData, planDiags := n.plan(
|
||||
ctx, evalCtx, nil, instanceRefreshState, n.ForceCreateBeforeDestroy, n.forceReplace,
|
||||
)
|
||||
diags = diags.Append(maybeImproveResourceInstanceDiagnostics(planDiags, addr))
|
||||
diags = diags.Append(planDiags)
|
||||
if diags.HasErrors() {
|
||||
// If we are importing and generating a configuration, we need to
|
||||
// ensure the change is written out so the configuration can be
|
||||
|
||||
@@ -111,7 +111,7 @@ func upgradeResourceStateTransform(args stateTransformArgs) (cty.Value, []byte,
|
||||
}
|
||||
|
||||
resp := args.provider.UpgradeResourceState(context.TODO(), req)
|
||||
diags := maybeImproveResourceInstanceDiagnostics(resp.Diagnostics, args.currentAddr)
|
||||
diags := resp.Diagnostics
|
||||
if diags.HasErrors() {
|
||||
log.Printf("[TRACE] upgradeResourceStateTransform: failed - address: %s", args.currentAddr)
|
||||
return cty.NilVal, nil, diags
|
||||
|
||||
Reference in New Issue
Block a user