diff --git a/pkg/config/provider.go b/pkg/config/provider.go index a37b7487..558c3ba0 100644 --- a/pkg/config/provider.go +++ b/pkg/config/provider.go @@ -136,7 +136,7 @@ type Provider struct { // TerraformProvider is the Terraform schema of the provider. TerraformProvider *schema.Provider - TerraformPluginFrameworkProvider *fwprovider.Provider + TerraformPluginFrameworkProvider fwprovider.Provider // refInjectors is an ordered list of `ReferenceInjector`s for // injecting references across this Provider's resources. @@ -197,7 +197,7 @@ func WithTerraformProvider(tp *schema.Provider) ProviderOption { } } -func WithTerraformPluginFrameworkProvider(tp *fwprovider.Provider) ProviderOption { +func WithTerraformPluginFrameworkProvider(tp fwprovider.Provider) ProviderOption { return func(p *Provider) { p.TerraformPluginFrameworkProvider = tp } @@ -325,7 +325,7 @@ func NewProvider(ctx context.Context, schema []byte, prefix string, modulePath s // TODO(cem): Consider creating a new context here, rather than getting one as input to this function. // TODO(cem): Currently, terraformPluginFrameworkResourceFunctions is calculated for each plugin framework resource. Doing so is wasteful, because the result is independent of the resource. It should be called once, outside the loop. - terraformPluginFrameworkResourceFunctions := (*p.TerraformPluginFrameworkProvider).Resources(ctx) + terraformPluginFrameworkResourceFunctions := p.TerraformPluginFrameworkProvider.Resources(ctx) for _, resourceFunc := range terraformPluginFrameworkResourceFunctions { resource := resourceFunc() diff --git a/pkg/controller/external_async_terraform_plugin_framework.go b/pkg/controller/external_async_terraform_plugin_framework.go index b61f97ba..e638230b 100644 --- a/pkg/controller/external_async_terraform_plugin_framework.go +++ b/pkg/controller/external_async_terraform_plugin_framework.go @@ -35,7 +35,7 @@ func NewTerraformPluginFrameworkAsyncConnector(kube client.Client, ots *OperationTrackerStore, sf terraform.SetupFn, cfg *config.Resource, - provider *provider.Provider, + provider provider.Provider, opts ...TerraformPluginFrameworkAsyncOption) *TerraformPluginFrameworkAsyncConnector { nfac := &TerraformPluginFrameworkAsyncConnector{ TerraformPluginFrameworkConnector: NewTerraformPluginFrameworkConnector(kube, sf, cfg, ots, provider), diff --git a/pkg/controller/external_terraform_plugin_framework.go b/pkg/controller/external_terraform_plugin_framework.go index fbc51f41..575acbdf 100644 --- a/pkg/controller/external_terraform_plugin_framework.go +++ b/pkg/controller/external_terraform_plugin_framework.go @@ -43,7 +43,7 @@ type TerraformPluginFrameworkConnector struct { metricRecorder *metrics.MetricRecorder operationTrackerStore *OperationTrackerStore isManagementPoliciesEnabled bool - terraformPluginFrameworkProvider *fwprovider.Provider + terraformPluginFrameworkProvider fwprovider.Provider } // TerraformPluginFrameworkConnectorOption allows you to configure TerraformPluginFrameworkConnector. @@ -72,7 +72,7 @@ func WithTerraformPluginFrameworkManagementPolicies(isManagementPoliciesEnabled } } -func NewTerraformPluginFrameworkConnector(kube client.Client, sf terraform.SetupFn, cfg *config.Resource, ots *OperationTrackerStore, terraformPluginFrameworkProvider *fwprovider.Provider, opts ...TerraformPluginFrameworkConnectorOption) *TerraformPluginFrameworkConnector { +func NewTerraformPluginFrameworkConnector(kube client.Client, sf terraform.SetupFn, cfg *config.Resource, ots *OperationTrackerStore, terraformPluginFrameworkProvider fwprovider.Provider, opts ...TerraformPluginFrameworkConnectorOption) *TerraformPluginFrameworkConnector { connector := &TerraformPluginFrameworkConnector{ getTerraformSetup: sf, kube: kube, @@ -118,7 +118,17 @@ func (c *TerraformPluginFrameworkConnector) Connect(ctx context.Context, mg xpre return nil, errors.Wrapf(err, "failed to get the extended parameters for resource %q", mg.GetName()) } - if !opTracker.HasFrameworkTFState() { + resourceSchema, err := c.getResourceSchema(ctx) + if err != nil { + return nil, errors.Wrap(err, "could not retrieve resource schema") + } + hasState := false + if opTracker.HasFrameworkTFState() { + tfStateValue, err := opTracker.GetFrameworkTFState().Unmarshal(resourceSchema.Type().TerraformType(ctx)) + hasState = err == nil && !tfStateValue.IsNull() + } + + if !hasState { logger.Debug("Instance state not found in cache, reconstructing...") tfState, err := tr.GetObservation() if err != nil { @@ -150,11 +160,6 @@ func (c *TerraformPluginFrameworkConnector) Connect(ctx context.Context, mg xpre return nil, errors.Wrap(err, "could not configure provider server") } - resourceSchema, err := c.getResourceSchema(ctx) - if err != nil { - return nil, errors.Wrap(err, "could not retrieve resource schema") - } - return &terraformPluginFrameworkExternalClient{ ts: ts, config: c.config, @@ -180,7 +185,7 @@ func (c *TerraformPluginFrameworkConnector) getResourceSchema(ctx context.Contex } func (c *TerraformPluginFrameworkConnector) configureProvider(ctx context.Context, ts terraform.Setup) (tfprotov5.ProviderServer, error) { - providerServer := providerserver.NewProtocol5(*c.terraformPluginFrameworkProvider)() + providerServer := providerserver.NewProtocol5(ts.FrameworkProvider)() tsBytes, err := json.Marshal(ts.Configuration) if err != nil { return nil, errors.Wrap(err, "cannot marshal ts config") @@ -245,6 +250,7 @@ func (n *terraformPluginFrameworkExternalClient) getDiffPlan(ctx context.Context prcReq := &tfprotov5.PlanResourceChangeRequest{ TypeName: n.config.Name, + PriorState: n.opTracker.GetFrameworkTFState(), Config: &tfConfig, ProposedNewState: &tfPlannedState, } diff --git a/pkg/terraform/store.go b/pkg/terraform/store.go index 862dab7c..09ffae94 100644 --- a/pkg/terraform/store.go +++ b/pkg/terraform/store.go @@ -19,6 +19,7 @@ import ( "github.com/crossplane/crossplane-runtime/pkg/logging" "github.com/crossplane/crossplane-runtime/pkg/meta" xpresource "github.com/crossplane/crossplane-runtime/pkg/resource" + fwprovider "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/mitchellh/go-ps" "github.com/pkg/errors" "github.com/spf13/afero" @@ -122,6 +123,8 @@ type Setup struct { Scheduler ProviderScheduler Meta any + + FrameworkProvider fwprovider.Provider } // Map returns the Setup object in map form. The initial reason was so that