diff --git a/internal/testprovider/schema.go b/internal/testprovider/schema.go index 1d195d12d..3cec9430a 100644 --- a/internal/testprovider/schema.go +++ b/internal/testprovider/schema.go @@ -567,7 +567,12 @@ func ProviderV2() *schemav2.Provider { MustSetIfUnset(data, "bool_property_value", false) MustSetIfUnset(data, "number_property_value", 42) MustSetIfUnset(data, "float_property_value", 99.6767932) - MustSetIfUnset(data, "string_property_value", "ognirts") + if data.Id() == "set-raw-config-id" { + v := data.GetRawConfig().AsValueMap()["raw_config_value"] + MustSet(data, "string_property_value", v.AsString()) + } else { + MustSetIfUnset(data, "string_property_value", "ognirts") + } MustSetIfUnset(data, "array_property_value", []interface{}{"an array"}) MustSetIfUnset(data, "object_property_value", map[string]interface{}{ "property_a": "a", diff --git a/pf/internal/schemashim/provider.go b/pf/internal/schemashim/provider.go index c16058712..da0155291 100644 --- a/pf/internal/schemashim/provider.go +++ b/pf/internal/schemashim/provider.go @@ -86,7 +86,7 @@ func (p *SchemaOnlyProvider) Apply(t string, s shim.InstanceState, panic("schemaOnlyProvider does not implement runtime operation Apply") } -func (p *SchemaOnlyProvider) Refresh(t string, s shim.InstanceState) (shim.InstanceState, error) { +func (p *SchemaOnlyProvider) Refresh(string, shim.InstanceState, shim.ResourceConfig) (shim.InstanceState, error) { panic("schemaOnlyProvider does not implement runtime operation Refresh") } diff --git a/pkg/tfbridge/provider.go b/pkg/tfbridge/provider.go index 92b111a82..9655a25b1 100644 --- a/pkg/tfbridge/provider.go +++ b/pkg/tfbridge/provider.go @@ -825,7 +825,12 @@ func (p *Provider) Read(ctx context.Context, req *pulumirpc.ReadRequest) (*pulum } } - newstate, err := p.tf.Refresh(res.TFName, state) + config, _, err := MakeTerraformConfig(p, oldInputs, res.TF.Schema(), res.Schema.Fields) + if err != nil { + return nil, errors.Wrapf(err, "preparing %s's new property state", urn) + } + + newstate, err := p.tf.Refresh(res.TFName, state, config) if err != nil { return nil, errors.Wrapf(err, "refreshing %s", urn) } diff --git a/pkg/tfbridge/provider_test.go b/pkg/tfbridge/provider_test.go index f110feba5..448f5671c 100644 --- a/pkg/tfbridge/provider_test.go +++ b/pkg/tfbridge/provider_test.go @@ -550,14 +550,19 @@ func TestProviderCheckV2(t *testing.T) { assert.Equal(t, "", failures[2].Property) } -func testProviderRead(t *testing.T, provider *Provider, typeName tokens.Type) { +func testProviderRead(t *testing.T, provider *Provider, typeName tokens.Type, checkRawConfig bool) { urn := resource.NewURN("stack", "project", "", typeName, "name") + props, err := structpb.NewStruct(map[string]interface{}{ + "rawConfigValue": "fromRawConfig", + }) + require.NoError(t, err) readResp, err := provider.Read(context.Background(), &pulumirpc.ReadRequest{ Id: string("resource-id"), Urn: string(urn), Properties: nil, + Inputs: props, }) - assert.NoError(t, err) + require.NoError(t, err) assert.NotNil(t, readResp.GetInputs()) assert.NotNil(t, readResp.GetProperties()) @@ -592,6 +597,19 @@ func testProviderRead(t *testing.T, provider *Provider, typeName tokens.Type) { assert.Equal(t, resource.NewStringProperty("some ${interpolated:value} with syntax errors"), ins["stringWithBadInterpolation"]) + if checkRawConfig { + readResp, err := provider.Read(context.Background(), &pulumirpc.ReadRequest{ + Id: string("set-raw-config-id"), + Urn: string(urn), + Inputs: props, + }) + require.NoError(t, err) + outs, err := plugin.UnmarshalProperties(readResp.GetProperties(), + plugin.MarshalOptions{KeepUnknowns: true}) + require.NoError(t, err) + assert.Equal(t, "fromRawConfig", outs["stringPropertyValue"].StringValue()) + } + // Read again with the ID that results in all the optinal fields not being set readResp, err = provider.Read(context.Background(), &pulumirpc.ReadRequest{ Id: string("empty-resource-id"), @@ -632,7 +650,7 @@ func TestProviderReadV1(t *testing.T) { }, } - testProviderRead(t, provider, "ExampleResource") + testProviderRead(t, provider, "ExampleResource", false /* CheckRawConfig */) } func TestProviderReadV2(t *testing.T) { @@ -648,7 +666,7 @@ func TestProviderReadV2(t *testing.T) { }, } - testProviderRead(t, provider, "ExampleResource") + testProviderRead(t, provider, "ExampleResource", true /* CheckRawConfig */) } func testProviderReadNestedSecret(t *testing.T, provider *Provider, typeName tokens.Type) { diff --git a/pkg/tfbridge/schema_test.go b/pkg/tfbridge/schema_test.go index 2602ad647..0bfb53f57 100644 --- a/pkg/tfbridge/schema_test.go +++ b/pkg/tfbridge/schema_test.go @@ -641,7 +641,7 @@ func TestMetaProperties(t *testing.T) { res := prov.ResourcesMap().Get(resName) state := f.NewInstanceState("0") - read, err := prov.Refresh(resName, state) + read, err := prov.Refresh(resName, state, nil) assert.NoError(t, err) assert.NotNil(t, read) @@ -655,7 +655,7 @@ func TestMetaProperties(t *testing.T) { assert.Equal(t, strconv.Itoa(res.SchemaVersion()), state.Meta()["schema_version"]) - read2, err := prov.Refresh(resName, state) + read2, err := prov.Refresh(resName, state, nil) assert.NoError(t, err) assert.NotNil(t, read2) assert.Equal(t, read, read2) @@ -716,7 +716,7 @@ func TestInjectingCustomTimeouts(t *testing.T) { res := prov.ResourcesMap().Get(resName) state := f.NewInstanceState("0") - read, err := prov.Refresh(resName, state) + read, err := prov.Refresh(resName, state, nil) assert.NoError(t, err) assert.NotNil(t, read) @@ -730,7 +730,7 @@ func TestInjectingCustomTimeouts(t *testing.T) { assert.Equal(t, strconv.Itoa(res.SchemaVersion()), state.Meta()["schema_version"]) - read2, err := prov.Refresh(resName, state) + read2, err := prov.Refresh(resName, state, nil) assert.NoError(t, err) assert.NotNil(t, read2) assert.Equal(t, read, read2) @@ -821,7 +821,7 @@ func TestResultAttributesRoundTrip(t *testing.T) { res := prov.ResourcesMap().Get("example_resource") state := f.NewInstanceState("0") - read, err := prov.Refresh(resName, state) + read, err := prov.Refresh(resName, state, nil) assert.NoError(t, err) assert.NotNil(t, read) diff --git a/pkg/tfshim/schema/provider.go b/pkg/tfshim/schema/provider.go index 368dc9d19..8006016e2 100644 --- a/pkg/tfshim/schema/provider.go +++ b/pkg/tfshim/schema/provider.go @@ -64,7 +64,7 @@ func (ProviderShim) Apply(t string, s shim.InstanceState, d shim.InstanceDiff) ( panic("this provider is schema-only and does not support runtime operations") } -func (ProviderShim) Refresh(t string, s shim.InstanceState) (shim.InstanceState, error) { +func (ProviderShim) Refresh(t string, s shim.InstanceState, c shim.ResourceConfig) (shim.InstanceState, error) { panic("this provider is schema-only and does not support runtime operations") } diff --git a/pkg/tfshim/sdk-v1/provider.go b/pkg/tfshim/sdk-v1/provider.go index a931464fb..935631d96 100644 --- a/pkg/tfshim/sdk-v1/provider.go +++ b/pkg/tfshim/sdk-v1/provider.go @@ -98,7 +98,7 @@ func (p v1Provider) Apply(t string, s shim.InstanceState, d shim.InstanceDiff) ( return stateToShim(state), err } -func (p v1Provider) Refresh(t string, s shim.InstanceState) (shim.InstanceState, error) { +func (p v1Provider) Refresh(t string, s shim.InstanceState, _ shim.ResourceConfig) (shim.InstanceState, error) { state, err := p.tf.Refresh(instanceInfo(t), stateFromShim(s)) return stateToShim(state), err } diff --git a/pkg/tfshim/sdk-v2/provider.go b/pkg/tfshim/sdk-v2/provider.go index 78709867a..f90b86f0e 100644 --- a/pkg/tfshim/sdk-v2/provider.go +++ b/pkg/tfshim/sdk-v2/provider.go @@ -101,15 +101,26 @@ func (p v2Provider) Apply(t string, s shim.InstanceState, d shim.InstanceDiff) ( return stateToShim(r, state), errors(diags) } -func (p v2Provider) Refresh(t string, s shim.InstanceState) (shim.InstanceState, error) { +func (p v2Provider) Refresh(t string, s shim.InstanceState, c shim.ResourceConfig) (shim.InstanceState, error) { + opts, err := getProviderOptions(p.opts) + if err != nil { + return nil, err + } + r, ok := p.tf.ResourcesMap[t] if !ok { return nil, fmt.Errorf("unknown resource %v", t) } + state, err := upgradeResourceState(p.tf, r, stateFromShim(s)) if err != nil { return nil, fmt.Errorf("failed to upgrade resource state: %w", err) } + + if c != nil { + state.RawConfig = makeResourceRawConfig(opts.diffStrategy, configFromShim(c), r) + } + state, diags := r.RefreshWithoutUpgrade(context.TODO(), state, p.tf.Meta()) return stateToShim(r, state), errors(diags) } diff --git a/pkg/tfshim/shim.go b/pkg/tfshim/shim.go index 767c888b2..1663b0ca0 100644 --- a/pkg/tfshim/shim.go +++ b/pkg/tfshim/shim.go @@ -194,7 +194,7 @@ type Provider interface { Configure(c ResourceConfig) error Diff(t string, s InstanceState, c ResourceConfig) (InstanceDiff, error) Apply(t string, s InstanceState, d InstanceDiff) (InstanceState, error) - Refresh(t string, s InstanceState) (InstanceState, error) + Refresh(t string, s InstanceState, c ResourceConfig) (InstanceState, error) ReadDataDiff(t string, c ResourceConfig) (InstanceDiff, error) ReadDataApply(t string, d InstanceDiff) (InstanceState, error) diff --git a/pkg/tfshim/tfplugin5/provider.go b/pkg/tfshim/tfplugin5/provider.go index 07c62a8a0..c3b620556 100644 --- a/pkg/tfshim/tfplugin5/provider.go +++ b/pkg/tfshim/tfplugin5/provider.go @@ -421,7 +421,7 @@ func (p *provider) Apply(t string, s shim.InstanceState, d shim.InstanceDiff) (s return newState, unmarshalErrors(resp.Diagnostics) } -func (p *provider) Refresh(t string, s shim.InstanceState) (shim.InstanceState, error) { +func (p *provider) Refresh(t string, s shim.InstanceState, _ shim.ResourceConfig) (shim.InstanceState, error) { state, ok := s.(*instanceState) if s != nil && !ok { return nil, fmt.Errorf("internal error: foreign resource state") diff --git a/pkg/tfshim/tfplugin5/provider_test.go b/pkg/tfshim/tfplugin5/provider_test.go index 04c52da13..10a20d547 100644 --- a/pkg/tfshim/tfplugin5/provider_test.go +++ b/pkg/tfshim/tfplugin5/provider_test.go @@ -1294,7 +1294,7 @@ func TestRefresh(t *testing.T) { "string_with_bad_interpolation": cty.StringVal("some ${interpolated:value} with syntax errors"), } - state, err = p.Refresh("example_resource", state) + state, err = p.Refresh("example_resource", state, nil) require.NoError(t, err) expectedObject, err := ctyToGo(cty.ObjectVal(expected)) diff --git a/pkg/tfshim/util/filter.go b/pkg/tfshim/util/filter.go index 9eedbb7f6..a7aec1260 100644 --- a/pkg/tfshim/util/filter.go +++ b/pkg/tfshim/util/filter.go @@ -81,8 +81,8 @@ func (p *FilteringProvider) Apply(t string, s shim.InstanceState, d shim.Instanc return p.Provider.Apply(t, s, d) } -func (p *FilteringProvider) Refresh(t string, s shim.InstanceState) (shim.InstanceState, error) { - return p.Provider.Refresh(t, s) +func (p *FilteringProvider) Refresh(t string, s shim.InstanceState, c shim.ResourceConfig) (shim.InstanceState, error) { + return p.Provider.Refresh(t, s, c) } func (p *FilteringProvider) ReadDataDiff(t string, c shim.ResourceConfig) (shim.InstanceDiff, error) { diff --git a/pkg/tfshim/util/util.go b/pkg/tfshim/util/util.go index 86bb3938c..a48ce99e0 100644 --- a/pkg/tfshim/util/util.go +++ b/pkg/tfshim/util/util.go @@ -44,7 +44,7 @@ func (UnimplementedProvider) Diff(t string, s shim.InstanceState, c shim.Resourc func (UnimplementedProvider) Apply(t string, s shim.InstanceState, d shim.InstanceDiff) (shim.InstanceState, error) { panic("unimplemented") } -func (UnimplementedProvider) Refresh(t string, s shim.InstanceState) (shim.InstanceState, error) { +func (UnimplementedProvider) Refresh(string, shim.InstanceState, shim.ResourceConfig) (shim.InstanceState, error) { panic("unimplemented") }