Skip to content

Commit

Permalink
PF re-plan in Diff after detecting a replace
Browse files Browse the repository at this point in the history
  • Loading branch information
VenelinMartinov committed Nov 27, 2024
1 parent 1aa2e64 commit 3a0c57a
Showing 1 changed file with 52 additions and 31 deletions.
83 changes: 52 additions & 31 deletions pkg/pf/tfbridge/provider_diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"fmt"
"sort"

"github.com/hashicorp/terraform-plugin-go/tfprotov6"
"github.com/hashicorp/terraform-plugin-go/tftypes"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource/plugin"
Expand All @@ -29,58 +30,38 @@ import (
"github.com/pulumi/pulumi-terraform-bridge/v3/unstable/propertyvalue"
)

// Diff checks what impacts a hypothetical update will have on the resource's properties. Receives checkedInputs from
// Check and the prior state. The implementation here calls PlanResourceChange Terraform method. Essentially:
//
// Diff(priorState, checkedInputs):
// proposedNewState = priorState.applyChanges(checkedInputs)
// plannedState = PlanResourceChange(priorState, proposedNewState)
// priorState.Diff(plannedState)
func (p *provider) DiffWithContext(
ctx context.Context,
urn resource.URN,
id resource.ID,
priorStateMap resource.PropertyMap,
checkedInputs resource.PropertyMap,
allowUnknowns bool,
ignoreChanges []string,
) (plugin.DiffResult, error) {
ctx = p.initLogging(ctx, p.logSink, urn)
rh, err := p.resourceHandle(ctx, urn)
if err != nil {
return plugin.DiffResult{}, err
}

priorStateMap, err = transformFromState(ctx, rh, priorStateMap)
func (p *provider) getPlanAndPriorState(
ctx context.Context, priorStateMap resource.PropertyMap, rh resourceHandle,
checkedInputs resource.PropertyMap, ignoreChanges []string,
) (*tfprotov6.PlanResourceChangeResponse, *upgradedResourceState, error) {
priorStateMap, err := transformFromState(ctx, rh, priorStateMap)
if err != nil {
return plugin.DiffResult{}, err
return nil, nil, err
}

checkedInputs, err = propertyvalue.ApplyIgnoreChanges(priorStateMap, checkedInputs, ignoreChanges)
if err != nil {
return plugin.DiffResult{}, fmt.Errorf("failed to apply ignore changes: %w", err)
return nil, nil, fmt.Errorf("failed to apply ignore changes: %w", err)
}

rawPriorState, err := parseResourceState(&rh, priorStateMap)
if err != nil {
return plugin.DiffResult{}, err
return nil, nil, err
}

priorState, err := p.UpgradeResourceState(ctx, &rh, rawPriorState)
if err != nil {
return plugin.DiffResult{}, err
return nil, nil, err
}

tfType := rh.schema.Type(ctx).(tftypes.Object)

checkedInputsValue, err := convert.EncodePropertyMap(rh.encoder, checkedInputs)
if err != nil {
return plugin.DiffResult{}, err
return nil, nil, err
}

planResp, err := p.plan(ctx, rh.terraformResourceName, rh.schema, priorState, checkedInputsValue)
if err != nil {
return plugin.DiffResult{}, err
return nil, nil, err
}

// NOTE: this currently ignores planRep.PlanedPrivate but it is unclear if it should signal differences between
Expand All @@ -89,9 +70,42 @@ func (p *provider) DiffWithContext(
// to surface private state differences to the user from the Diff method.

if err := p.processDiagnostics(planResp.Diagnostics); err != nil {
return nil, nil, err
}

return planResp, priorState, nil
}

// Diff checks what impacts a hypothetical update will have on the resource's properties. Receives checkedInputs from
// Check and the prior state. The implementation here calls PlanResourceChange Terraform method. Essentially:
//
// Diff(priorState, checkedInputs):
// proposedNewState = priorState.applyChanges(checkedInputs)
// plannedState = PlanResourceChange(priorState, proposedNewState)
// priorState.Diff(plannedState)
func (p *provider) DiffWithContext(
ctx context.Context,
urn resource.URN,
id resource.ID,
priorStateMap resource.PropertyMap,
checkedInputs resource.PropertyMap,
allowUnknowns bool,
ignoreChanges []string,
) (plugin.DiffResult, error) {
ctx = p.initLogging(ctx, p.logSink, urn)
rh, err := p.resourceHandle(ctx, urn)
if err != nil {
return plugin.DiffResult{}, err
}

planResp, priorState, err := p.getPlanAndPriorState(
ctx, priorStateMap, rh, checkedInputs, ignoreChanges)
if err != nil {
return plugin.DiffResult{}, err
}

tfType := rh.schema.Type(ctx).(tftypes.Object)

// TODO[pulumi/pulumi-terraform-bridge#751] ignoreChanges support
plannedStateValue, err := planResp.PlannedState.Unmarshal(tfType)
if err != nil {
Expand Down Expand Up @@ -135,6 +149,13 @@ func (p *provider) DiffWithContext(
}

if providerOpts.enableAccurateBridgePreview {
if len(planResp.RequiresReplace) > 0 {

Check failure on line 152 in pkg/pf/tfbridge/provider_diff.go

View workflow job for this annotation

GitHub Actions / Test and Lint / lint

empty-block: this block is empty, you can remove it (revive)

Check failure on line 152 in pkg/pf/tfbridge/provider_diff.go

View workflow job for this annotation

GitHub Actions / Test and Lint / lint

empty-block: this block is empty, you can remove it (revive)
// If we have a replace, we need to recompute the plan with a nil prior
// in order to correctly mark computed properties for recomputation.
//nolint:lll
// https://github.com/opentofu/opentofu/blob/864aa9d1d629090cfc4ddf9fdd344d34dee9793e/internal/tofu/node_resource_abstract_instance.go#L1054
// TODO plan again with nil prior
}
pluginDetailedDiff, err := calculateDetailedDiff(ctx, &rh, priorState, plannedStateValue, checkedInputs)
if err != nil {
return plugin.DiffResult{}, err
Expand Down

0 comments on commit 3a0c57a

Please sign in to comment.