mirror of
https://github.com/hashicorp/terraform.git
synced 2026-03-21 18:10:30 -04:00
213 lines
7.9 KiB
Go
213 lines
7.9 KiB
Go
// 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
|
|
}
|