mirror of
https://github.com/hashicorp/terraform.git
synced 2026-04-28 01:27:46 -04:00
add ability to forward PlannedPrivate data
Terraform providers sometimes want to be able to plan a computed field which may not be deterministically generated. For example, a random GUID could be generated during plan, making the overall Terraform plan more precise, but there is currently no way to carry that planned value forward to apply. The problem is that there are always two entirely independent plans for every resource change. Terraform compares these two plans for consistency, so a provider may not return a different computed value, but there is no way for the provider to see what the prior planned value was. This means that a planned value which is not reproducible from the given inputs is not plan-able at all. This PR allows Terraform to take the private data from the first plan, which is usually discarded, and send it along in the second plan request. The provider can then use that data to recreate any previously planned values, either because they are stored directly, or contain enough seed data to recreate the same result.
This commit is contained in:
parent
a42d5b9f62
commit
1f4bf797ff
6 changed files with 27 additions and 4 deletions
|
|
@ -1,9 +1,9 @@
|
|||
// Copyright IBM Corp. 2014, 2026
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
// Terraform Plugin RPC protocol version 6.10
|
||||
// Terraform Plugin RPC protocol version 6.11
|
||||
//
|
||||
// This file defines version 6.10 of the RPC protocol. To implement a plugin
|
||||
// This file defines version 6.11 of the RPC protocol. To implement a plugin
|
||||
// against this protocol, copy this definition into your own codebase and
|
||||
// use protoc to generate stubs for your target language.
|
||||
//
|
||||
|
|
@ -312,6 +312,11 @@ message ClientCapabilities {
|
|||
// The write_only_attributes_allowed capability signals that the client
|
||||
// is able to handle write_only attributes for managed resources.
|
||||
bool write_only_attributes_allowed = 2;
|
||||
|
||||
// store_planned_private indicates that the client will store the private data
|
||||
// returned with an initial plan, and send it back to the provider as
|
||||
// PlannedPrivate data in a subsequent plan request.
|
||||
bool store_planned_private = 3;
|
||||
}
|
||||
|
||||
// Deferred is a message that indicates that change is deferred for a reason.
|
||||
|
|
@ -643,6 +648,7 @@ message PlanResourceChange {
|
|||
DynamicValue provider_meta = 6;
|
||||
ClientCapabilities client_capabilities = 7;
|
||||
ResourceIdentityData prior_identity = 8;
|
||||
bytes planned_private = 9;
|
||||
}
|
||||
|
||||
message Response {
|
||||
|
|
|
|||
|
|
@ -673,6 +673,7 @@ func (p *GRPCProvider) PlanResourceChange(r providers.PlanResourceChangeRequest)
|
|||
ProposedNewState: &proto6.DynamicValue{Msgpack: propMP},
|
||||
PriorPrivate: r.PriorPrivate,
|
||||
ClientCapabilities: clientCapabilitiesToProto(r.ClientCapabilities),
|
||||
PlannedPrivate: r.PlannedPrivate,
|
||||
}
|
||||
|
||||
if metaSchema.Body != nil {
|
||||
|
|
@ -2071,6 +2072,7 @@ func clientCapabilitiesToProto(c providers.ClientCapabilities) *proto6.ClientCap
|
|||
return &proto6.ClientCapabilities{
|
||||
DeferralAllowed: c.DeferralAllowed,
|
||||
WriteOnlyAttributesAllowed: c.WriteOnlyAttributesAllowed,
|
||||
StorePlannedPrivate: c.StorePlannedPrivate,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -307,6 +307,11 @@ type ClientCapabilities struct {
|
|||
// The write_only_attributes_allowed capability signals that the client
|
||||
// is able to handle write_only attributes for managed resources.
|
||||
WriteOnlyAttributesAllowed bool
|
||||
|
||||
// StorePlannedPrivate indicates that the client is will store private data
|
||||
// returned from PlanResourceChange, and return it with the final
|
||||
// PlanResourceChange call.
|
||||
StorePlannedPrivate bool
|
||||
}
|
||||
|
||||
type ValidateProviderConfigRequest struct {
|
||||
|
|
@ -556,6 +561,11 @@ type PlanResourceChangeRequest struct {
|
|||
// provider during the last apply.
|
||||
PriorPrivate []byte
|
||||
|
||||
// PlannedPrivate is the private data stored from the the last plan.
|
||||
// PlannedPrivate will only be supplied in the plan immediately preceding an
|
||||
// ApplyResourceChange call.
|
||||
PlannedPrivate []byte
|
||||
|
||||
// ProviderMeta is the configuration for the provider_meta block for the
|
||||
// module and provider this resource belongs to. Its use is defined by
|
||||
// each provider, and it should not be used without coordination with
|
||||
|
|
|
|||
|
|
@ -1748,6 +1748,7 @@ func TestContext2Plan_blockNestingGroup(t *testing.T) {
|
|||
ClientCapabilities: providers.ClientCapabilities{
|
||||
DeferralAllowed: false,
|
||||
WriteOnlyAttributesAllowed: true,
|
||||
StorePlannedPrivate: true,
|
||||
},
|
||||
}
|
||||
if !cmp.Equal(got, want, valueTrans) {
|
||||
|
|
|
|||
|
|
@ -660,6 +660,7 @@ func (ctx *BuiltinEvalContext) ClientCapabilities() providers.ClientCapabilities
|
|||
return providers.ClientCapabilities{
|
||||
DeferralAllowed: ctx.Deferrals().DeferralAllowed(),
|
||||
WriteOnlyAttributesAllowed: true,
|
||||
StorePlannedPrivate: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -835,10 +835,12 @@ func (n *NodeAbstractResourceInstance) plan(
|
|||
if n.preDestroyRefresh {
|
||||
checkRuleSeverity = tfdiags.Warning
|
||||
}
|
||||
|
||||
var plannedPrivate []byte
|
||||
if plannedChange != nil {
|
||||
// If we already planned the action, we stick to that plan
|
||||
createBeforeDestroy = plannedChange.Action == plans.CreateThenDelete
|
||||
|
||||
plannedPrivate = plannedChange.Private
|
||||
}
|
||||
|
||||
// Evaluate the configuration
|
||||
|
|
@ -991,6 +993,7 @@ func (n *NodeAbstractResourceInstance) plan(
|
|||
ProviderMeta: metaConfigVal,
|
||||
ClientCapabilities: ctx.ClientCapabilities(),
|
||||
PriorIdentity: priorIdentity,
|
||||
PlannedPrivate: plannedPrivate,
|
||||
})
|
||||
// If we don't support deferrals, but the provider reports a deferral and does not
|
||||
// emit any error level diagnostics, we should emit an error.
|
||||
|
|
@ -1012,7 +1015,7 @@ func (n *NodeAbstractResourceInstance) plan(
|
|||
}
|
||||
|
||||
plannedNewVal := resp.PlannedState
|
||||
plannedPrivate := resp.PlannedPrivate
|
||||
plannedPrivate = resp.PlannedPrivate
|
||||
plannedIdentity := resp.PlannedIdentity
|
||||
|
||||
// These checks are only relevant if the provider is not deferring the
|
||||
|
|
|
|||
Loading…
Reference in a new issue