From 6ccfdc817832b96169f681ca74f1f296bab470c6 Mon Sep 17 00:00:00 2001 From: Venelin Date: Mon, 27 Jan 2025 15:17:40 +0000 Subject: [PATCH] Remove v2Provider and v2InstanceDiff --- pkg/tfshim/sdk-v2/instance_diff.go | 136 -------------------- pkg/tfshim/sdk-v2/provider.go | 199 +---------------------------- pkg/tfshim/sdk-v2/provider2.go | 24 +++- pkg/tfshim/sdk-v2/provider_diff.go | 135 ------------------- 4 files changed, 21 insertions(+), 473 deletions(-) delete mode 100644 pkg/tfshim/sdk-v2/provider_diff.go diff --git a/pkg/tfshim/sdk-v2/instance_diff.go b/pkg/tfshim/sdk-v2/instance_diff.go index f9f4b3c27..d89544efe 100644 --- a/pkg/tfshim/sdk-v2/instance_diff.go +++ b/pkg/tfshim/sdk-v2/instance_diff.go @@ -1,19 +1,11 @@ package sdkv2 import ( - "fmt" - "strings" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "github.com/pulumi/pulumi/sdk/v3/go/common/util/contract" shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim" ) -var _ = shim.InstanceDiff(v2InstanceDiff{}) - func resourceAttrDiffToShim(d *terraform.ResourceAttrDiff) *shim.ResourceAttrDiff { if d == nil { return nil @@ -29,131 +21,3 @@ func resourceAttrDiffToShim(d *terraform.ResourceAttrDiff) *shim.ResourceAttrDif Type: shim.DiffAttrUnknown, } } - -type v2InstanceDiff struct { - tf *terraform.InstanceDiff -} - -func (d v2InstanceDiff) DiffEqualDecisionOverride() shim.DiffOverride { - return shim.DiffNoOverride -} - -func (d v2InstanceDiff) applyTimeoutOptions(opts shim.TimeoutOptions) { - // This method is no longer used with PlanResourceChange; we handle timeouts more directly. - if opts.ResourceTimeout != nil { - err := d.encodeTimeouts(opts.ResourceTimeout) - contract.AssertNoErrorf(err, "encodeTimeouts should never fail") - } - for timeoutKey, dur := range opts.TimeoutOverrides { - d.setTimeout(dur, timeoutKey) - } -} - -func (d v2InstanceDiff) Attribute(key string) *shim.ResourceAttrDiff { - return resourceAttrDiffToShim(d.tf.Attributes[key]) -} - -func (d v2InstanceDiff) HasNoChanges() bool { - return len(d.Attributes()) == 0 -} - -func (d v2InstanceDiff) Attributes() map[string]shim.ResourceAttrDiff { - m := map[string]shim.ResourceAttrDiff{} - for k, v := range d.tf.Attributes { - if v != nil { - m[k] = *resourceAttrDiffToShim(v) - } - } - return m -} - -func (d v2InstanceDiff) ProposedState(res shim.Resource, priorState shim.InstanceState) (shim.InstanceState, error) { - var prior *terraform.InstanceState - if priorState != nil { - prior = priorState.(v2InstanceState).tf - } else { - prior = &terraform.InstanceState{ - Attributes: map[string]string{}, - Meta: map[string]interface{}{}, - } - } - - return v2InstanceState{ - resource: res.(v2Resource).tf, - tf: prior, - diff: d.tf, - }, nil -} - -func (d v2InstanceDiff) PriorState() (shim.InstanceState, error) { - return nil, fmt.Errorf("prior state is not available") -} - -func (d v2InstanceDiff) Destroy() bool { - return d.tf.Destroy -} - -func (d v2InstanceDiff) RequiresNew() bool { - return d.tf.RequiresNew() -} - -func (d v2InstanceDiff) processIgnoreChanges(ignored shim.IgnoreChanges) { - i := ignored() - for k := range d.tf.Attributes { - if _, ok := i[k]; ok { - delete(d.tf.Attributes, k) - } else { - for attr := range i { - if strings.HasPrefix(k, attr+".") { - delete(d.tf.Attributes, k) - break - } - } - } - } -} - -func (d v2InstanceDiff) encodeTimeouts(timeouts *shim.ResourceTimeout) error { - v2Timeouts := &schema.ResourceTimeout{} - if timeouts != nil { - v2Timeouts.Create = timeouts.Create - v2Timeouts.Read = timeouts.Read - v2Timeouts.Update = timeouts.Update - v2Timeouts.Delete = timeouts.Delete - v2Timeouts.Default = timeouts.Default - } - return v2Timeouts.DiffEncode(d.tf) -} - -func (d v2InstanceDiff) setTimeout(timeout time.Duration, timeoutKey shim.TimeoutKey) { - // this turns seconds to nanoseconds - TF wants it in this format - timeoutValue := timeout.Nanoseconds() - - switch timeoutKey { - case shim.TimeoutCreate: - timeoutKey = schema.TimeoutCreate - case shim.TimeoutRead: - timeoutKey = schema.TimeoutRead - case shim.TimeoutUpdate: - timeoutKey = schema.TimeoutUpdate - case shim.TimeoutDelete: - timeoutKey = schema.TimeoutDelete - case shim.TimeoutDefault: - timeoutKey = schema.TimeoutDefault - default: - return - } - - if d.tf.Meta == nil { - d.tf.Meta = map[string]interface{}{} - } - - timeouts, ok := d.tf.Meta[schema.TimeoutKey].(map[string]interface{}) - if !ok { - d.tf.Meta[schema.TimeoutKey] = map[string]interface{}{ - string(timeoutKey): timeoutValue, - } - } else { - timeouts[string(timeoutKey)] = timeoutValue - } -} diff --git a/pkg/tfshim/sdk-v2/provider.go b/pkg/tfshim/sdk-v2/provider.go index 60065027d..36a52ca00 100644 --- a/pkg/tfshim/sdk-v2/provider.go +++ b/pkg/tfshim/sdk-v2/provider.go @@ -1,20 +1,12 @@ package sdkv2 import ( - "context" - "fmt" - - "github.com/golang/glog" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/logging" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - testing "github.com/mitchellh/go-testing-interface" shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim" ) -var _ = shim.Provider(v2Provider{}) - func configFromShim(c shim.ResourceConfig) *terraform.ResourceConfig { if c == nil { return nil @@ -22,13 +14,6 @@ func configFromShim(c shim.ResourceConfig) *terraform.ResourceConfig { return c.(v2ResourceConfig).tf } -func stateFromShim(s shim.InstanceState) *terraform.InstanceState { - if s == nil { - return nil - } - return s.(v2InstanceState).tf -} - func stateToShim(r *schema.Resource, s *terraform.InstanceState) shim.InstanceState { if s == nil { return nil @@ -40,192 +25,12 @@ func diffFromShim(d shim.InstanceDiff) *terraform.InstanceDiff { if d == nil { return nil } - return d.(v2InstanceDiff).tf + return d.(*v2InstanceDiff2).tf } func diffToShim(d *terraform.InstanceDiff) shim.InstanceDiff { if d == nil { return nil } - return v2InstanceDiff{d} -} - -type v2Provider struct { - tf *schema.Provider -} - -var _ shim.Provider = (*v2Provider)(nil) - -func (p v2Provider) Schema() shim.SchemaMap { - return v2SchemaMap(p.tf.Schema) -} - -func (p v2Provider) ResourcesMap() shim.ResourceMap { - return v2ResourceMap(p.tf.ResourcesMap) -} - -func (p v2Provider) DataSourcesMap() shim.ResourceMap { - return v2ResourceMap(p.tf.DataSourcesMap) -} - -func (p v2Provider) InternalValidate() error { - return p.tf.InternalValidate() -} - -func (p v2Provider) Validate(_ context.Context, c shim.ResourceConfig) ([]string, []error) { - return warningsAndErrors(p.tf.Validate(configFromShim(c))) -} - -func (p v2Provider) ValidateResource(_ context.Context, t string, c shim.ResourceConfig) ([]string, []error) { - return warningsAndErrors(p.tf.ValidateResource(t, configFromShim(c))) -} - -func (p v2Provider) ValidateDataSource(_ context.Context, t string, c shim.ResourceConfig) ([]string, []error) { - return warningsAndErrors(p.tf.ValidateDataSource(t, configFromShim(c))) -} - -func (p v2Provider) Configure(ctx context.Context, c shim.ResourceConfig) error { - // See ConfigureProvider e.g. - // https://github.com/hashicorp/terraform-plugin-sdk/blob/main/helper/schema/grpc_provider.go#L564 - ctxHack := context.WithValue(ctx, schema.StopContextKey, p.stopContext(context.Background())) - return errors(p.tf.Configure(ctxHack, configFromShim(c))) -} - -func (p v2Provider) stopContext(ctx context.Context) context.Context { - // TODO may want to follow StopContext implementation to make sure calling calling p.Stop() - // cancels the context returned here. - // - // See: https://github.com/hashicorp/terraform-plugin-sdk/blob/main/helper/schema/grpc_provider.go#L60C1-L60C80 - return ctx -} - -func (p v2Provider) Apply( - ctx context.Context, - t string, - s shim.InstanceState, - d shim.InstanceDiff, -) (shim.InstanceState, error) { - r, ok := p.tf.ResourcesMap[t] - if !ok { - return nil, fmt.Errorf("unknown resource %v", t) - } - state, err := upgradeResourceState(ctx, t, p.tf, r, stateFromShim(s)) - if err != nil { - return nil, fmt.Errorf("failed to upgrade resource state: %w", err) - } - state, diags := r.Apply(ctx, state, diffFromShim(d), p.tf.Meta()) - return stateToShim(r, state), errors(diags) -} - -func (p v2Provider) Refresh( - ctx context.Context, - t string, - s shim.InstanceState, - c shim.ResourceConfig, -) (shim.InstanceState, error) { - r, ok := p.tf.ResourcesMap[t] - if !ok { - return nil, fmt.Errorf("unknown resource %v", t) - } - - state, err := upgradeResourceState(ctx, t, 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(configFromShim(c), r) - } - - state, diags := r.RefreshWithoutUpgrade(context.TODO(), state, p.tf.Meta()) - return stateToShim(r, state), errors(diags) -} - -func (p v2Provider) ReadDataDiff( - ctx context.Context, - t string, - c shim.ResourceConfig, -) (shim.InstanceDiff, error) { - resource, ok := p.tf.DataSourcesMap[t] - if !ok { - return nil, fmt.Errorf("unknown resource %v", t) - } - - config := configFromShim(c) - rawConfig := makeResourceRawConfig(config, resource) - - diff, err := resource.Diff(ctx, nil, config, p.tf.Meta()) - if diff != nil { - diff.RawConfig = rawConfig - } - return diffToShim(diff), err -} - -func (p v2Provider) ReadDataApply( - ctx context.Context, - t string, - d shim.InstanceDiff, -) (shim.InstanceState, error) { - r, ok := p.tf.DataSourcesMap[t] - if !ok { - return nil, fmt.Errorf("unknown resource %v", t) - } - state, diags := r.ReadDataApply(ctx, diffFromShim(d), p.tf.Meta()) - return stateToShim(r, state), errors(diags) -} - -func (p v2Provider) Meta(_ context.Context) interface{} { - return p.tf.Meta() -} - -func (p v2Provider) Stop(_ context.Context) error { - return nil -} - -func (p v2Provider) InitLogging(_ context.Context) { - logging.SetOutput(&testing.RuntimeT{}) -} - -func (p v2Provider) NewDestroyDiff(_ context.Context, t string, opts shim.TimeoutOptions) shim.InstanceDiff { - d := v2InstanceDiff{&terraform.InstanceDiff{Destroy: true}} - d.applyTimeoutOptions(opts) - return d -} - -func (p v2Provider) NewResourceConfig( - _ context.Context, object map[string]interface{}, -) shim.ResourceConfig { - return v2ResourceConfig{&terraform.ResourceConfig{ - Raw: object, - Config: object, - }} -} - -func (p v2Provider) NewProviderConfig( - _ context.Context, object map[string]interface{}, -) shim.ResourceConfig { - tfConfig := &terraform.ResourceConfig{ - Raw: object, - Config: object, - } - typ := schema.InternalMap(p.tf.Schema).CoreConfigSchema().ImpliedType() - ctyVal, err := recoverCtyValueOfObjectType(typ, object) - if err != nil { - glog.V(9).Infof("Failed to recover cty value of object type: %v, falling back to old behaviour", err) - return v2ResourceConfig{tfConfig} - } - - tfConfig.CtyValue = ctyVal - return v2ResourceConfig{tfConfig} -} - -func (p v2Provider) IsSet(_ context.Context, v interface{}) ([]interface{}, bool) { - if set, ok := v.(*schema.Set); ok { - return set.List(), true - } - return nil, false -} - -func (p v2Provider) SupportsUnknownCollections() bool { - return true + return &v2InstanceDiff2{tf: d} } diff --git a/pkg/tfshim/sdk-v2/provider2.go b/pkg/tfshim/sdk-v2/provider2.go index 4a9cfc1af..ed76db884 100644 --- a/pkg/tfshim/sdk-v2/provider2.go +++ b/pkg/tfshim/sdk-v2/provider2.go @@ -189,6 +189,22 @@ func (d *v2InstanceDiff2) RequiresNew() bool { return d.tf.RequiresNew() } +func processIgnoreChanges(tf *terraform.InstanceDiff, ignored shim.IgnoreChanges) { + i := ignored() + for k := range tf.Attributes { + if _, ok := i[k]; ok { + delete(tf.Attributes, k) + } else { + for attr := range i { + if strings.HasPrefix(k, attr+".") { + delete(tf.Attributes, k) + break + } + } + } + } +} + // Provides PlanResourceChange handling for select resources. type planResourceChangeImpl struct { tf *schema.Provider @@ -560,9 +576,8 @@ func (p *planResourceChangeImpl) NewDestroyDiff( ) shim.InstanceDiff { res := p.tf.ResourcesMap[t] ty := res.CoreConfigSchema().ImpliedType() - dd := (&v2Provider{}).NewDestroyDiff(ctx, t, opts).(v2InstanceDiff) return &v2InstanceDiff2{ - tf: dd.tf, + tf: &terraform.InstanceDiff{Destroy: true}, config: cty.NullVal(ty), plannedState: cty.NullVal(ty), } @@ -722,11 +737,10 @@ func (s *grpcServer) PlanResourceChange( Config: &tfprotov5.DynamicValue{MsgPack: configVal}, }, TransformInstanceDiff: func(d *terraform.InstanceDiff) *terraform.InstanceDiff { - dd := &v2InstanceDiff{d} if ignores != nil { - dd.processIgnoreChanges(ignores) + processIgnoreChanges(d, ignores) } - return dd.tf + return d }, } if len(priorMeta) > 0 { diff --git a/pkg/tfshim/sdk-v2/provider_diff.go b/pkg/tfshim/sdk-v2/provider_diff.go deleted file mode 100644 index ca67a9b27..000000000 --- a/pkg/tfshim/sdk-v2/provider_diff.go +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2016-2023, Pulumi Corporation. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package sdkv2 - -import ( - "context" - "fmt" - - hcty "github.com/hashicorp/go-cty/cty" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim" -) - -func (p v2Provider) Diff( - ctx context.Context, - t string, - s shim.InstanceState, - c shim.ResourceConfig, - opts shim.DiffOptions, -) (theDiff shim.InstanceDiff, theError error) { - defer func() { - switch theDiff := theDiff.(type) { - case v2InstanceDiff: - theDiff.applyTimeoutOptions(opts.TimeoutOptions) - } - }() - if c == nil { - return diffToShim(&terraform.InstanceDiff{Destroy: true}), nil - } - - r, ok := p.tf.ResourcesMap[t] - if !ok { - return nil, fmt.Errorf("unknown resource %v", t) - } - - config, state := configFromShim(c), stateFromShim(s) - rawConfig := makeResourceRawConfig(config, r) - - if state == nil { - // When handling Create Pulumi passes nil for state, but this diverges from how Terraform does things, - // see: https://github.com/pulumi/pulumi-terraform-bridge/issues/911 and can lead to panics. Compensate - // by constructing an InstanceState. - - state = &terraform.InstanceState{ - RawConfig: rawConfig, - } - } else { - // Upgrades are needed only if we have non-empty prior state. - var err error - state, err = upgradeResourceState(ctx, t, p.tf, r, state) - if err != nil { - return nil, fmt.Errorf("failed to upgrade resource state: %w", err) - } - } - - diff, err := p.simpleDiff(ctx, r, state, config, rawConfig, p.tf.Meta()) - if err != nil { - return nil, err - } - if diff != nil { - diff.RawConfig = rawConfig - } - - resultingDiff := diffToShim(diff) - - if dd, ok := resultingDiff.(v2InstanceDiff); ok && opts.IgnoreChanges != nil { - dd.processIgnoreChanges(opts.IgnoreChanges) - } - - return resultingDiff, err -} - -func (p v2Provider) simpleDiff( - ctx context.Context, - res *schema.Resource, - s *terraform.InstanceState, - c *terraform.ResourceConfig, - rawConfigVal hcty.Value, - meta interface{}, -) (*terraform.InstanceDiff, error) { - priorStateVal, err := s.AttrsAsObjectValue(res.CoreConfigSchema().ImpliedType()) - if err != nil { - return nil, err - } - proposedNewStateVal, err := proposedNew(res, priorStateVal, rawConfigVal) - if err != nil { - return nil, err - } - - planned := terraform.NewResourceConfigShimmed(proposedNewStateVal, res.CoreConfigSchema()) - state := s.DeepCopy() - state.RawPlan = proposedNewStateVal - if state.RawState.IsNull() { - state.RawState = priorStateVal - } - if state.RawConfig.IsNull() { - state.RawConfig = rawConfigVal - } - diff, err := res.SimpleDiff(ctx, state, planned, meta) - if err != nil { - return nil, err - } - - // TF gRPC servers compensate for the fact that SimpleDiff may return - // terraform.NewInstanceDiff(), nil dropping any available information on RawPlan. - // - // See for example this code in PlanResourceChange: - // - // See https://github.com/hashicorp/terraform-plugin-sdk/blob/ - // 28e631776d97f0a5a5942b3524814addbef90875/helper/schema/grpc_provider.go#L797 - // - // In TF this is communicated from PlanResourceChange to ApplyResourceChange; unlike TF, in - // the current codebase InstanceDiff is passed directly to Apply. If RawPlan is not set on - // the diff it may cause nil panics in the provider. - if diff != nil && len(diff.Attributes) == 0 { - diff.RawPlan = priorStateVal - // TODO[pulumi/pulumi-terraform-bridge#1505] handle private state similar to upstream - } - - return diff, nil -}