You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
terraform/internal/command/arguments/init.go

214 lines
7.9 KiB

// Copyright IBM Corp. 2014, 2026
// SPDX-License-Identifier: BUSL-1.1
package arguments
import (
"os"
"time"
"github.com/hashicorp/terraform/internal/tfdiags"
)
// Init represents the command-line arguments for the init command.
type Init struct {
// FromModule identifies the module to copy into the target directory before init.
FromModule string
// Lockfile specifies a dependency lockfile mode.
Lockfile string
// TestDirectory is the directory containing any test files that should be
// validated alongside the main configuration. Should be relative to the
// Path.
TestsDirectory string
// ViewType specifies which init format to use: human or JSON.
ViewType ViewType
// Backend specifies whether to disable backend or HCP Terraform initialization.
Backend bool
// Cloud specifies whether to disable backend or HCP Terraform initialization.
Cloud bool
// Get specifies whether to disable downloading modules for this configuration
Get bool
// ForceInitCopy specifies whether to suppress prompts about copying state data.
ForceInitCopy bool
// StateLock specifies whether hold a state lock during backend migration.
StateLock bool
// StateLockTimeout specifies the duration to wait for a state lock.
StateLockTimeout time.Duration
// Reconfigure specifies whether to disregard any existing configuration, preventing migration of any existing state
Reconfigure bool
// MigrateState specifies whether to attempt to copy existing state to the new backend
MigrateState bool
// Upgrade specifies whether to upgrade modules and plugins as part of their respective installation steps
Upgrade bool
// Json specifies whether to output in JSON format
Json bool
// IgnoreRemoteVersion specifies whether to ignore remote and local Terraform versions compatibility
IgnoreRemoteVersion bool
BackendConfig FlagNameValueSlice
Vars *Vars
// InputEnabled is used to disable interactive input for unspecified
// variable and backend config values. Default is true.
InputEnabled bool
TargetFlags []string
CompactWarnings bool
PluginPath FlagStringSlice
Args []string
// The -enable-pluggable-state-storage-experiment flag is used in control flow logic in the init command.
// TODO(SarahFrench/radeksimko): Remove this once the feature is no longer
// experimental
EnablePssExperiment bool
// CreateDefaultWorkspace indicates whether the default workspace should be created by
// Terraform when initializing a state store for the first time.
CreateDefaultWorkspace bool
}
// ParseInit processes CLI arguments, returning an Init value and errors.
// If errors are encountered, an Init value is still returned representing
// the best effort interpretation of the arguments.
func ParseInit(args []string, experimentsEnabled bool) (*Init, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
init := &Init{
Vars: &Vars{},
}
init.BackendConfig = NewFlagNameValueSlice("-backend-config")
cmdFlags := extendedFlagSet("init", nil, nil, init.Vars)
cmdFlags.Var((*FlagStringSlice)(&init.TargetFlags), "target", "resource to target")
cmdFlags.BoolVar(&init.InputEnabled, "input", true, "input")
cmdFlags.BoolVar(&init.CompactWarnings, "compact-warnings", false, "use compact warnings")
cmdFlags.BoolVar(&init.Backend, "backend", true, "")
cmdFlags.BoolVar(&init.Cloud, "cloud", true, "")
cmdFlags.StringVar(&init.FromModule, "from-module", "", "copy the source of the given module into the directory before init")
cmdFlags.BoolVar(&init.Get, "get", true, "")
cmdFlags.BoolVar(&init.ForceInitCopy, "force-copy", false, "suppress prompts about copying state data")
cmdFlags.BoolVar(&init.StateLock, "lock", true, "lock state")
cmdFlags.DurationVar(&init.StateLockTimeout, "lock-timeout", 0, "lock timeout")
cmdFlags.BoolVar(&init.Reconfigure, "reconfigure", false, "reconfigure")
cmdFlags.BoolVar(&init.MigrateState, "migrate-state", false, "migrate state")
cmdFlags.BoolVar(&init.Upgrade, "upgrade", false, "")
cmdFlags.StringVar(&init.Lockfile, "lockfile", "", "Set a dependency lockfile mode")
cmdFlags.BoolVar(&init.IgnoreRemoteVersion, "ignore-remote-version", false, "continue even if remote and local Terraform versions are incompatible")
cmdFlags.StringVar(&init.TestsDirectory, "test-directory", "tests", "test-directory")
cmdFlags.BoolVar(&init.Json, "json", false, "json")
cmdFlags.Var(&init.BackendConfig, "backend-config", "")
cmdFlags.Var(&init.PluginPath, "plugin-dir", "plugin directory")
cmdFlags.BoolVar(&init.CreateDefaultWorkspace, "create-default-workspace", true, "when -input=false, use this flag to block creation of the default workspace")
// Used for enabling experimental code that's invoked before configuration is parsed.
cmdFlags.BoolVar(&init.EnablePssExperiment, "enable-pluggable-state-storage-experiment", false, "Enable the pluggable state storage experiment")
if err := cmdFlags.Parse(args); err != nil {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Failed to parse command-line flags",
err.Error(),
))
}
if v := os.Getenv("TF_ENABLE_PLUGGABLE_STATE_STORAGE"); v != "" {
init.EnablePssExperiment = true
}
if v := os.Getenv("TF_SKIP_CREATE_DEFAULT_WORKSPACE"); v != "" {
// If TF_SKIP_CREATE_DEFAULT_WORKSPACE is set it will override
// a -create-default-workspace=true flag that's set explicitly,
// as that's indistinguishable from the default value being used.
init.CreateDefaultWorkspace = false
}
if !experimentsEnabled {
// If experiments aren't enabled then these flags should not be used.
if init.EnablePssExperiment {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Cannot use -enable-pluggable-state-storage-experiment flag without experiments enabled",
"Terraform cannot use the -enable-pluggable-state-storage-experiment flag (or TF_ENABLE_PLUGGABLE_STATE_STORAGE environment variable) unless experiments are enabled.",
))
}
if !init.CreateDefaultWorkspace {
// Can only be set to false by using the flag
// and we cannot identify if -create-default-workspace=true is set explicitly.
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Cannot use -create-default-workspace flag without experiments enabled",
"Terraform cannot use the -create-default-workspace flag (or TF_SKIP_CREATE_DEFAULT_WORKSPACE environment variable) unless experiments are enabled.",
))
}
} else {
// Errors using flags despite experiments being enabled.
if !init.CreateDefaultWorkspace && !init.EnablePssExperiment {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Cannot use -create-default-workspace=false flag unless the pluggable state storage experiment is enabled",
"Terraform cannot use the -create-default-workspace=false flag (or TF_SKIP_CREATE_DEFAULT_WORKSPACE environment variable) unless you also supply the -enable-pluggable-state-storage-experiment flag (or set the TF_ENABLE_PLUGGABLE_STATE_STORAGE environment variable).",
))
}
}
if init.MigrateState && init.Json {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"The -migrate-state and -json options are mutually-exclusive",
"Terraform cannot ask for interactive approval when -json is set. To use the -migrate-state option, disable the -json option.",
))
}
if init.MigrateState && init.Reconfigure {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Invalid init options",
"The -migrate-state and -reconfigure options are mutually-exclusive.",
))
}
init.Args = cmdFlags.Args()
backendFlagSet := FlagIsSet(cmdFlags, "backend")
cloudFlagSet := FlagIsSet(cmdFlags, "cloud")
if backendFlagSet && cloudFlagSet {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Invalid init options",
"The -backend and -cloud options are aliases of one another and mutually-exclusive in their use",
))
} else if backendFlagSet {
init.Cloud = init.Backend
} else if cloudFlagSet {
init.Backend = init.Cloud
}
switch {
case init.Json:
init.ViewType = ViewJSON
default:
init.ViewType = ViewHuman
}
return init, diags
}