Skip to content

Commit 2093fe3

Browse files
Fix PF dynamic type diff error (#3098)
In #2945 we accidentally changed the behaviour for providers where RawStateDeltas were not enabled. After 2945 we would unconditionally produce the JSON serialization of the state even if it isn't used. It is only used for upgrading state and for RawStateDeltas. The unintended effect here is that we exposed #3078 to all users of attributes of DynamicType even if no upgrades or RawStateDeltas are used. This PR changes that to not produce the JSON serialization if not necessary. I've also added some tests for both the behaviour fixed here and the behaviour which needs #3078 fixes #3095
1 parent d1e4da9 commit 2093fe3

File tree

2 files changed

+119
-5
lines changed

2 files changed

+119
-5
lines changed

pkg/pf/tests/diff_test/diff_test.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
package tfbridgetests
22

33
import (
4+
"context"
5+
"math/big"
6+
"os"
47
"testing"
58

9+
"github.com/hashicorp/terraform-plugin-framework/resource"
610
rschema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
711
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
812
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
913
"github.com/hexops/autogold/v2"
14+
"github.com/pulumi/pulumi/sdk/v3/go/common/util/cmdutil"
1015
"github.com/zclconf/go-cty/cty"
1116

1217
pb "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/pf/internal/providerbuilder"
@@ -176,3 +181,111 @@ func TestPFDetailedDiffStringAttribute(t *testing.T) {
176181
})
177182
}
178183
}
184+
185+
func TestPFDetailedDiffDynamicType(t *testing.T) {
186+
t.Parallel()
187+
if d, ok := os.LookupEnv("PULUMI_RAW_STATE_DELTA_ENABLED"); ok && cmdutil.IsTruthy(d) {
188+
// TODO[pulumi/pulumi-terraform-bridge#3078]
189+
t.Skip("Does not work with PULUMI_RAW_STATE_DELTA_ENABLED=true")
190+
}
191+
192+
attributeSchema := rschema.Schema{
193+
Attributes: map[string]rschema.Attribute{
194+
"key": rschema.DynamicAttribute{
195+
Optional: true,
196+
},
197+
},
198+
}
199+
res := pb.NewResource(pb.NewResourceArgs{
200+
ResourceSchema: attributeSchema,
201+
})
202+
203+
t.Run("no change", func(t *testing.T) {
204+
crosstests.Diff(t, res,
205+
map[string]cty.Value{"key": cty.StringVal("value")},
206+
map[string]cty.Value{"key": cty.StringVal("value")},
207+
)
208+
})
209+
210+
t.Run("change", func(t *testing.T) {
211+
crosstests.Diff(t, res,
212+
map[string]cty.Value{"key": cty.StringVal("value")},
213+
map[string]cty.Value{"key": cty.StringVal("value1")},
214+
)
215+
})
216+
217+
t.Run("int no change", func(t *testing.T) {
218+
crosstests.Diff(t, res,
219+
map[string]cty.Value{"key": cty.NumberVal(big.NewFloat(1))},
220+
map[string]cty.Value{"key": cty.NumberVal(big.NewFloat(1))},
221+
)
222+
})
223+
224+
t.Run("type change", func(t *testing.T) {
225+
// TODO[pulumi/pulumi-terraform-bridge#3078]
226+
t.Skip(`Error converting tftypes.Number<"1"> (value2) at "AttributeName(\"key\")": can't unmarshal tftypes.Number into *string, expected string`)
227+
crosstests.Diff(t, res,
228+
map[string]cty.Value{"key": cty.StringVal("value")},
229+
map[string]cty.Value{"key": cty.NumberVal(big.NewFloat(1))},
230+
)
231+
})
232+
}
233+
234+
func TestPFDetailedDiffDynamicTypeWithMigration(t *testing.T) {
235+
t.Parallel()
236+
// TODO[pulumi/pulumi-terraform-bridge#3078]
237+
t.Skip("DynamicPseudoType is not supported")
238+
239+
attributeSchema := rschema.Schema{
240+
Attributes: map[string]rschema.Attribute{
241+
"key": rschema.DynamicAttribute{
242+
Optional: true,
243+
},
244+
},
245+
}
246+
res1 := pb.NewResource(pb.NewResourceArgs{
247+
ResourceSchema: attributeSchema,
248+
})
249+
250+
schema2 := rschema.Schema{
251+
Attributes: map[string]rschema.Attribute{
252+
"key": rschema.DynamicAttribute{
253+
Optional: true,
254+
},
255+
},
256+
Version: 1,
257+
}
258+
res2 := pb.NewResource(pb.NewResourceArgs{
259+
ResourceSchema: schema2,
260+
UpgradeStateFunc: func(ctx context.Context) map[int64]resource.StateUpgrader {
261+
return map[int64]resource.StateUpgrader{
262+
0: {
263+
PriorSchema: &res1.ResourceSchema,
264+
StateUpgrader: func(ctx context.Context, usr1 resource.UpgradeStateRequest, usr2 *resource.UpgradeStateResponse) {
265+
usr2.State = *usr1.State
266+
},
267+
},
268+
}
269+
},
270+
})
271+
272+
t.Run("no change", func(t *testing.T) {
273+
crosstests.Diff(t, res1,
274+
map[string]cty.Value{"key": cty.StringVal("value")},
275+
map[string]cty.Value{"key": cty.StringVal("value")},
276+
crosstests.DiffProviderUpgradedSchema(
277+
res2,
278+
),
279+
)
280+
})
281+
282+
t.Run("change", func(t *testing.T) {
283+
crosstests.Diff(t, res1,
284+
map[string]cty.Value{"key": cty.StringVal("value")},
285+
map[string]cty.Value{"key": cty.StringVal("value1")},
286+
crosstests.DiffProviderUpgradedSchema(
287+
res2,
288+
),
289+
)
290+
})
291+
}

pkg/pf/tfbridge/resource_state.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -251,15 +251,10 @@ func (p *provider) parseAndUpgradeResourceState(
251251
}
252252

253253
// Otherwise fallback to imprecise legacy parsing.
254-
tfType := rh.schema.Type(ctx).(tftypes.Object)
255254
value, err := convert.EncodePropertyMap(rh.encoder, props)
256255
if err != nil {
257256
return nil, fmt.Errorf("[pf/tfbridge] Error calling EncodePropertyMap: %w", err)
258257
}
259-
rawState, err := pfutils.NewRawState(tfType, value)
260-
if err != nil {
261-
return nil, fmt.Errorf("[pf/tfbridge] Error calling NewRawState: %w", err)
262-
}
263258

264259
// Before EnableRawStateDelta rollout, the behavior used to be to skip the upgrade method in case of an exact
265260
// version match. This seems incorrect, but to derisk fixing this problem it is flagged together with
@@ -272,6 +267,12 @@ func (p *provider) parseAndUpgradeResourceState(
272267
}, nil
273268
}
274269

270+
tfType := rh.schema.Type(ctx).(tftypes.Object)
271+
rawState, err := pfutils.NewRawState(tfType, value)
272+
if err != nil {
273+
return nil, fmt.Errorf("[pf/tfbridge] Error calling NewRawState: %w", err)
274+
}
275+
275276
return p.upgradeResourceState(ctx, rh, rawState, parsedMeta.PrivateState, stateVersion)
276277
}
277278

0 commit comments

Comments
 (0)