Skip to content
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
e1d0c57
fix parsing pf dynamic type
VenelinMartinov May 29, 2025
aaa4cc5
Add a test for DynamicPseudoType reproducing the error
t0yv0 May 16, 2025
c626c8b
Update valueshim to handle DynamicPseudoType
t0yv0 May 16, 2025
fdbec2a
Allow walking types
t0yv0 May 16, 2025
fe899a5
Type walker
t0yv0 May 16, 2025
7cd12de
Link schema type propagation together
t0yv0 May 16, 2025
fe7ba20
Replace pfutils
t0yv0 May 16, 2025
b3b7f98
fix function calls
VenelinMartinov May 29, 2025
97127f9
lint
VenelinMartinov May 29, 2025
01f750d
fix type propagation
VenelinMartinov May 29, 2025
b877eda
ensure dynamic types always get replace deltas
VenelinMartinov Jun 6, 2025
e82d4f6
re-enable deltas tests
VenelinMartinov Jun 6, 2025
e18d775
nested dynamic test
VenelinMartinov Jun 6, 2025
70974d6
fix tests
VenelinMartinov Jun 6, 2025
653b53e
add isDynamicType to value shim
VenelinMartinov Jun 6, 2025
2cefb8d
use the valueshim type instead of the schema map
VenelinMartinov Jun 6, 2025
daab918
try without the timeout removal
VenelinMartinov Jun 6, 2025
1ffc615
fix test
VenelinMartinov Jun 6, 2025
b559048
bring back tftype serialization, add tests
VenelinMartinov Jun 9, 2025
2a50b2b
remove unused
VenelinMartinov Jun 9, 2025
a8ad0b6
add todo for type changes
VenelinMartinov Jun 9, 2025
ecfb99d
lint
VenelinMartinov Jun 9, 2025
9de5088
fix float serialization
VenelinMartinov Jun 9, 2025
fd00d4d
fix serialization of empty lists and sets
VenelinMartinov Jun 9, 2025
a580ec9
remove redundant cty shim
VenelinMartinov Jun 9, 2025
50d6045
Revert "remove redundant cty shim"
VenelinMartinov Jun 9, 2025
9908589
lint
VenelinMartinov Jun 9, 2025
478e3cb
fix marshalling of dynamic type values
VenelinMartinov Jun 9, 2025
e14db58
fix null dynamic type handling
VenelinMartinov Jun 9, 2025
6276979
restore timeouts removal in turnaround check
VenelinMartinov Jun 10, 2025
2c92446
handle sdkv2 timeouts as before
VenelinMartinov Jun 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 0 additions & 28 deletions pkg/pf/internal/pfutils/raw_state.go

This file was deleted.

11 changes: 11 additions & 0 deletions pkg/pf/internal/schemashim/datasource.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@
package schemashim

import (
"context"

"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"

"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/internal/internalinter"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/pf/internal/runtypes"
shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/valueshim"
)

type schemaOnlyDataSource struct {
Expand All @@ -27,6 +32,12 @@ type schemaOnlyDataSource struct {

var _ shim.Resource = (*schemaOnlyDataSource)(nil)

func (r *schemaOnlyDataSource) SchemaType() valueshim.Type {
protoSchema, err := r.tf.ResourceProtoSchema(context.Background())
contract.AssertNoErrorf(err, "ResourceProtoSchema failed")
return valueshim.FromTType(protoSchema.ValueType())
}

func (r *schemaOnlyDataSource) Schema() shim.SchemaMap {
return r.tf.Shim()
}
Expand Down
9 changes: 9 additions & 0 deletions pkg/pf/internal/schemashim/object_pseudoresource.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/internal/internalinter"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/pf/internal/pfutils"
shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/valueshim"
)

// An Object type that masquerades as a Resource. This is a workaround to reusing tfgen code for generating schemas,
Expand Down Expand Up @@ -77,6 +78,10 @@ func (r *objectPseudoResource) Schema() shim.SchemaMap {
return r
}

func (r *objectPseudoResource) SchemaType() valueshim.Type {
return valueshim.FromTType(tftypes.Object{})
}

func (*objectPseudoResource) SchemaVersion() int {
panic("This is an Object type encoded as a shim.Resource, and " +
"SchemaVersion() should not be called on this entity during schema generation")
Expand Down Expand Up @@ -200,6 +205,10 @@ func newTuplePseudoResource(t attr.TypeWithElementTypes) shim.Resource {
}
}

func (r *tuplePseudoResource) SchemaType() valueshim.Type {
return valueshim.FromTType(tftypes.Object{})
}

func (*tuplePseudoResource) SchemaVersion() int { panic("TODO") }
func (*tuplePseudoResource) DeprecationMessage() string { panic("TODO") }

Expand Down
11 changes: 11 additions & 0 deletions pkg/pf/internal/schemashim/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@
package schemashim

import (
"context"

"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"

"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/internal/internalinter"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/pf/internal/runtypes"
shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/valueshim"
)

type schemaOnlyResource struct {
Expand All @@ -43,6 +48,12 @@ func (r *schemaOnlyResource) DeprecationMessage() string {
return r.tf.DeprecationMessage()
}

func (r *schemaOnlyResource) SchemaType() valueshim.Type {
s, err := r.tf.ResourceProtoSchema(context.Background())
contract.AssertNoErrorf(err, "failed to extract schema")
return valueshim.FromTType(s.ValueType())
}

func (*schemaOnlyResource) Importer() shim.ImportFunc {
panic("schemaOnlyResource does not implement runtime operation ImporterFunc")
}
Expand Down
5 changes: 5 additions & 0 deletions pkg/pf/proto/element.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (

"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/internal/internalinter"
shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/valueshim"
)

var (
Expand Down Expand Up @@ -113,6 +114,10 @@ func (o elementObject) Schema() shim.SchemaMap {
return elementObjectMap(o.typ)
}

func (o elementObject) SchemaType() valueshim.Type {
return valueshim.FromTType(o.typ)
}

func (m elementObjectMap) Len() int { return len(m.AttributeTypes) }

func (m elementObjectMap) Get(key string) shim.Schema { return getSchemaMap(m, key) }
Expand Down
6 changes: 6 additions & 0 deletions pkg/pf/proto/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/internal/internalinter"
shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/valueshim"
)

var (
Expand All @@ -33,6 +34,11 @@ type object struct {
internalinter.Internal
}

func (o object) SchemaType() valueshim.Type {
ty := o.obj.ValueType()
return valueshim.FromTType(ty)
}

func (o object) Schema() shim.SchemaMap {
contract.Assertf(o.obj.Nesting != tfprotov6.SchemaObjectNestingModeMap,
"%T cannot be a map, since that would require `o` to represent a Map<Object> type", o)
Expand Down
6 changes: 6 additions & 0 deletions pkg/pf/proto/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/internal/internalinter"
shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/valueshim"
)

var (
Expand Down Expand Up @@ -70,6 +71,11 @@ func newResource(r *tfprotov6.Schema) *resource {
return &resource{r, internalinter.Internal{}}
}

func (r resource) SchemaType() valueshim.Type {
ty := r.r.Block.ValueType()
return valueshim.FromTType(ty)
}

func (r resource) Schema() shim.SchemaMap {
return blockMap{r.r.Block}
}
Expand Down
7 changes: 6 additions & 1 deletion pkg/pf/proto/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,19 @@
package proto

import (
// "github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
"github.com/hashicorp/terraform-plugin-go/tftypes"

shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/valueshim"
)

// pseudoResource represents a type that must pretent to be a [shim.Resource], but does not represent a resource.
type pseudoResource struct{}

func (pseudoResource) SchemaType() valueshim.Type {
return valueshim.FromTType(tftypes.Object{}) // not a top-level resource
}

func (pseudoResource) SchemaVersion() int { return 0 }
func (pseudoResource) Importer() shim.ImportFunc { return nil }
func (pseudoResource) Timeouts() *shim.ResourceTimeout { return nil }
Expand Down
60 changes: 51 additions & 9 deletions pkg/pf/tests/diff_test/diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ package tfbridgetests
import (
"context"
"math/big"
"os"
"testing"

"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/resource"
rschema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hexops/autogold/v2"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/cmdutil"
"github.com/zclconf/go-cty/cty"

pb "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/pf/internal/providerbuilder"
Expand Down Expand Up @@ -184,10 +184,6 @@ func TestPFDetailedDiffStringAttribute(t *testing.T) {

func TestPFDetailedDiffDynamicType(t *testing.T) {
t.Parallel()
if d, ok := os.LookupEnv("PULUMI_RAW_STATE_DELTA_ENABLED"); ok && cmdutil.IsTruthy(d) {
// TODO[pulumi/pulumi-terraform-bridge#3078]
t.Skip("Does not work with PULUMI_RAW_STATE_DELTA_ENABLED=true")
}

attributeSchema := rschema.Schema{
Attributes: map[string]rschema.Attribute{
Expand Down Expand Up @@ -222,7 +218,7 @@ func TestPFDetailedDiffDynamicType(t *testing.T) {
})

t.Run("type change", func(t *testing.T) {
// TODO[pulumi/pulumi-terraform-bridge#3078]
// TODO[pulumi/pulumi-terraform-bridge#3122]
t.Skip(`Error converting tftypes.Number<"1"> (value2) at "AttributeName(\"key\")": can't unmarshal tftypes.Number into *string, expected string`)
crosstests.Diff(t, res,
map[string]cty.Value{"key": cty.StringVal("value")},
Expand All @@ -231,10 +227,56 @@ func TestPFDetailedDiffDynamicType(t *testing.T) {
})
}

func TestPFDetailedDiffNestedDynamicType(t *testing.T) {
t.Parallel()

attributeSchema := rschema.Schema{
Attributes: map[string]rschema.Attribute{
"key": rschema.ObjectAttribute{
Optional: true,
AttributeTypes: map[string]attr.Type{
"nested": types.DynamicType,
},
},
},
}
res := pb.NewResource(pb.NewResourceArgs{
ResourceSchema: attributeSchema,
})

t.Run("no change", func(t *testing.T) {
crosstests.Diff(t, res,
map[string]cty.Value{"key": cty.ObjectVal(map[string]cty.Value{"nested": cty.StringVal("value")})},
map[string]cty.Value{"key": cty.ObjectVal(map[string]cty.Value{"nested": cty.StringVal("value")})},
)
})

t.Run("change", func(t *testing.T) {
crosstests.Diff(t, res,
map[string]cty.Value{"key": cty.ObjectVal(map[string]cty.Value{"nested": cty.StringVal("value")})},
map[string]cty.Value{"key": cty.ObjectVal(map[string]cty.Value{"nested": cty.StringVal("value1")})},
)
})

t.Run("int no change", func(t *testing.T) {
crosstests.Diff(t, res,
map[string]cty.Value{"key": cty.ObjectVal(map[string]cty.Value{"nested": cty.NumberVal(big.NewFloat(1))})},
map[string]cty.Value{"key": cty.ObjectVal(map[string]cty.Value{"nested": cty.NumberVal(big.NewFloat(1))})},
)
})

t.Run("type change", func(t *testing.T) {
// TODO[pulumi/pulumi-terraform-bridge#3122]
t.Skip(`Error converting tftypes.Number<"1"> (value2) at "AttributeName(\"key\")": can't unmarshal tftypes.Number into *string, expected string`)
crosstests.Diff(t, res,
map[string]cty.Value{"key": cty.ObjectVal(map[string]cty.Value{"nested": cty.StringVal("value")})},
map[string]cty.Value{"key": cty.ObjectVal(map[string]cty.Value{"nested": cty.NumberVal(big.NewFloat(1))})},
)
})
}

func TestPFDetailedDiffDynamicTypeWithMigration(t *testing.T) {
t.Parallel()
// TODO[pulumi/pulumi-terraform-bridge#3078]
t.Skip("DynamicPseudoType is not supported")

attributeSchema := rschema.Schema{
Attributes: map[string]rschema.Attribute{
Expand Down
3 changes: 2 additions & 1 deletion pkg/pf/tfbridge/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,8 @@ func (p *provider) returnTerraformConfig() (resource.PropertyMap, error) {
}
// use valueshim package to marshal tfConfigValue into raw json,
// which can be unmarshaled into a map[string]interface{}
configJSONMessage, err := valueshim.FromTValue(tfConfigValue).Marshal()
value := valueshim.FromTValue(tfConfigValue)
configJSONMessage, err := value.Marshal(value.Type())
if err != nil {
return nil, fmt.Errorf("error marshaling into raw JSON message: %v", err)
}
Expand Down
7 changes: 4 additions & 3 deletions pkg/pf/tfbridge/resource_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"

"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/convert"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/pf/internal/pfutils"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/reservedkeys"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/valueshim"
Expand Down Expand Up @@ -185,7 +184,8 @@ func insertRawStateDelta(ctx context.Context, rh *resourceHandle, pm resource.Pr
schemaInfos := rh.pulumiResourceInfo.GetFields()
v := valueshim.FromTValue(state)

delta, err := tfbridge.RawStateComputeDelta(ctx, rh.schema.Shim(), schemaInfos, pm, v)
st := valueshim.FromTType(rh.schema.Type(ctx))
delta, err := tfbridge.RawStateComputeDelta(ctx, rh.schema.Shim(), schemaInfos, pm, st, v)
if err != nil {
return err
}
Expand Down Expand Up @@ -268,10 +268,11 @@ func (p *provider) parseAndUpgradeResourceState(
}

tfType := rh.schema.Type(ctx).(tftypes.Object)
rawState, err := pfutils.NewRawState(tfType, value)
rawStateBytes, err := valueshim.FromTValue(value).Marshal(valueshim.FromTType(tfType))
if err != nil {
return nil, fmt.Errorf("[pf/tfbridge] Error calling NewRawState: %w", err)
}
rawState := &tfprotov6.RawState{JSON: []byte(rawStateBytes)}

return p.upgradeResourceState(ctx, rh, rawState, parsedMeta.PrivateState, stateVersion)
}
Expand Down
9 changes: 6 additions & 3 deletions pkg/tfbridge/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -1371,7 +1371,8 @@ func (p *Provider) Create(ctx context.Context, req *pulumirpc.CreateRequest) (*p
}

if p.info.RawStateDeltaEnabled() {
if err := RawStateInjectDelta(ctx, res.TF.Schema(), res.Schema.Fields, props, newstate); err != nil {
s := res.TF.SchemaType()
if err := RawStateInjectDelta(ctx, res.TF.Schema(), res.Schema.Fields, props, s, newstate); err != nil {
return nil, err
}
}
Expand Down Expand Up @@ -1521,7 +1522,8 @@ func (p *Provider) Read(ctx context.Context, req *pulumirpc.ReadRequest) (*pulum
}

if p.info.RawStateDeltaEnabled() {
err := RawStateInjectDelta(ctx, res.TF.Schema(), res.Schema.Fields, props, newstate)
s := res.TF.SchemaType()
err := RawStateInjectDelta(ctx, res.TF.Schema(), res.Schema.Fields, props, s, newstate)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -1750,7 +1752,8 @@ func (p *Provider) Update(ctx context.Context, req *pulumirpc.UpdateRequest) (*p
}

if p.info.RawStateDeltaEnabled() {
if err := RawStateInjectDelta(ctx, res.TF.Schema(), res.Schema.Fields, props, newstate); err != nil {
s := res.TF.SchemaType()
if err := RawStateInjectDelta(ctx, res.TF.Schema(), res.Schema.Fields, props, s, newstate); err != nil {
return nil, err
}
}
Expand Down
Loading