cloud: assert import block compatibility (#33282)

* cloud: assert import block compatibility

* check for import <> TFC compatibility during init

* imports are not in alphabetical order 🙃

---------

Co-authored-by: CJ Horton <cjhorton@hashicorp.com>
This commit is contained in:
kmoe 2023-05-31 20:55:35 +01:00 committed by GitHub
parent 4386a15684
commit 5900d1177c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 47 additions and 0 deletions

View File

@ -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 {

View File

@ -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)