diff --git a/internal/cloud/backend_plan.go b/internal/cloud/backend_plan.go index f678738b67..b01943d410 100644 --- a/internal/cloud/backend_plan.go +++ b/internal/cloud/backend_plan.go @@ -20,8 +20,11 @@ import ( "time" tfe "github.com/hashicorp/go-tfe" + version "github.com/hashicorp/go-version" + "github.com/hashicorp/terraform/internal/backend" "github.com/hashicorp/terraform/internal/command/jsonformat" + "github.com/hashicorp/terraform/internal/configs" "github.com/hashicorp/terraform/internal/genconfig" "github.com/hashicorp/terraform/internal/plans" "github.com/hashicorp/terraform/internal/tfdiags" @@ -240,6 +243,7 @@ in order to capture the filesystem context the remote workspace expects: if configDiags.HasErrors() { return nil, fmt.Errorf("error loading config with snapshot: %w", configDiags.Errs()[0]) } + variables, varDiags := ParseCloudRunVariables(op.Variables, config.Module.Variables) if varDiags.HasErrors() { @@ -371,6 +375,39 @@ in order to capture the filesystem context the remote workspace expects: return r, nil } +// AssertImportCompatible errors if the user is attempting to use configuration- +// driven import and the version of the agent or API is too low to support it. +func (b *Cloud) AssertImportCompatible(config *configs.Config) error { + // Check TFC_RUN_ID is populated, indicating we are running in a remote TFC + // execution environment. + if len(config.Module.Import) > 0 && os.Getenv("TFC_RUN_ID") != "" { + // First, check the remote API version is high enough. + currentAPIVersion, err := version.NewVersion(b.client.RemoteAPIVersion()) + if err != nil { + return fmt.Errorf("Error parsing remote API version. To proceed, please remove any import blocks from your config. Please report the following error to the Terraform team: %s", err) + } + desiredAPIVersion, _ := version.NewVersion("2.6") + if currentAPIVersion.LessThan(desiredAPIVersion) { + return fmt.Errorf("Import blocks are not supported in this version of Terraform Enterprise. Please remove any import blocks from your config or upgrade Terraform Enterprise.") + } + + // Second, check the agent version is high enough. + agentEnv, isSet := os.LookupEnv("TFC_AGENT_VERSION") + if !isSet { + return fmt.Errorf("Error reading TFC agent version. To proceed, please remove any import blocks from your config. Please report the following error to the Terraform team: TFC_AGENT_VERSION not present.") + } + currentAgentVersion, err := version.NewVersion(agentEnv) + if err != nil { + return fmt.Errorf("Error parsing TFC agent version. To proceed, please remove any import blocks from your config. Please report the following error to the Terraform team: %s", err) + } + desiredAgentVersion, _ := version.NewVersion("1.10") + if currentAgentVersion.LessThan(desiredAgentVersion) { + return fmt.Errorf("Import blocks are not supported in this version of the Terraform Cloud Agent. You are using agent version %s, but this feature requires version %s. Please remove any import blocks from your config or upgrade your agent.", currentAgentVersion, desiredAgentVersion) + } + } + return nil +} + // renderPlanLogs reads the streamed plan JSON logs and calls the JSON Plan renderer (jsonformat.RenderPlan) to // render the plan output. The plan output is fetched from the redacted output endpoint. func (b *Cloud) renderPlanLogs(ctx context.Context, op *backend.Operation, run *tfe.Run) error { diff --git a/internal/command/init.go b/internal/command/init.go index 955aa87b1b..f3dea6bfaa 100644 --- a/internal/command/init.go +++ b/internal/command/init.go @@ -276,6 +276,16 @@ func (c *InitCommand) Run(args []string) int { return 1 } + if cb, ok := back.(*cloud.Cloud); ok { + if c.RunningInAutomation { + if err := cb.AssertImportCompatible(config); err != nil { + diags = diags.Append(tfdiags.Sourceless(tfdiags.Error, "Compatibility error", err.Error())) + c.showDiagnostics(diags) + return 1 + } + } + } + // Now that we have loaded all modules, check the module tree for missing providers. providersOutput, providersAbort, providerDiags := c.getProviders(config, state, flagUpgrade, flagPluginPath, flagLockfile) diags = diags.Append(providerDiags)