main: new global option -chdir
This new option is intended to address the previous inconsistencies where some older subcommands supported partially changing the target directory (where Terraform would use the new directory inconsistently) where newer commands did not support that override at all. Instead, now Terraform will accept a -chdir command at the start of the command line (before the subcommand) and will interpret it as a request to direct all actions that would normally be taken in the current working directory into the target directory instead. This is similar to options offered by some other similar tools, such as the -C option in "make". The new option is only accepted at the start of the command line (before the subcommand) as a way to reflect that it is a global command (not specific to a particular subcommand) and that it takes effect _before_ executing the subcommand. This also means it'll be forced to appear before any other command-specific arguments that take file paths, which hopefully communicates that those other arguments are interpreted relative to the overridden path. As a measure of pragmatism for existing uses, the path.cwd object in the Terraform language will continue to return the _original_ working directory (ignoring -chdir), in case that is important in some exceptional workflows. The path.root object gives the root module directory, which will always match the overriden working directory unless the user simultaneously uses one of the legacy directory override arguments, which is not a pattern we intend to support in the long run. As a first step down the deprecation path, this commit adjusts the documentation to de-emphasize the inconsistent old command line arguments, including specific guidance on what to use instead for the main three workflow commands, but all of those options remain supported in the same way as they were before. In a later commit we'll make those arguments produce a visible deprecation warning in Terraform's output, and then in an even later commit we'll remove them entirely so that -chdir is the single supported way to run Terraform from a directory other than the one containing the root module configuration.
This commit is contained in:
parent
883e4487a2
commit
efe78b2910
|
@ -9,6 +9,7 @@ import (
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/hashicorp/terraform/e2e"
|
"github.com/hashicorp/terraform/e2e"
|
||||||
|
"github.com/zclconf/go-cty/cty"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The tests in this file are for the "primary workflow", which includes
|
// The tests in this file are for the "primary workflow", which includes
|
||||||
|
@ -126,3 +127,90 @@ func TestPrimarySeparatePlan(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPrimaryChdirOption(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// This test case does not include any provider dependencies, so it's
|
||||||
|
// safe to run it even when network access is disallowed.
|
||||||
|
|
||||||
|
fixturePath := filepath.Join("testdata", "chdir-option")
|
||||||
|
tf := e2e.NewBinary(terraformBin, fixturePath)
|
||||||
|
defer tf.Close()
|
||||||
|
|
||||||
|
//// INIT
|
||||||
|
stdout, stderr, err := tf.Run("-chdir=subdir", "init")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected init error: %s\nstderr:\n%s", err, stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
//// PLAN
|
||||||
|
stdout, stderr, err = tf.Run("-chdir=subdir", "plan", "-out=tfplan")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected plan error: %s\nstderr:\n%s", err, stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(stdout, "0 to add, 0 to change, 0 to destroy") {
|
||||||
|
t.Errorf("incorrect plan tally; want 0 to add:\n%s", stdout)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(stdout, "This plan was saved to: tfplan") {
|
||||||
|
t.Errorf("missing \"This plan was saved to...\" message in plan output\n%s", stdout)
|
||||||
|
}
|
||||||
|
if !strings.Contains(stdout, "terraform apply \"tfplan\"") {
|
||||||
|
t.Errorf("missing next-step instruction in plan output\n%s", stdout)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The saved plan is in the subdirectory because -chdir switched there
|
||||||
|
plan, err := tf.Plan("subdir/tfplan")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to read plan file: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
diffResources := plan.Changes.Resources
|
||||||
|
if len(diffResources) != 0 {
|
||||||
|
t.Errorf("incorrect diff in plan; want no resource changes, but have:\n%s", spew.Sdump(diffResources))
|
||||||
|
}
|
||||||
|
|
||||||
|
//// APPLY
|
||||||
|
stdout, stderr, err = tf.Run("-chdir=subdir", "apply", "tfplan")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected apply error: %s\nstderr:\n%s", err, stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(stdout, "Resources: 0 added, 0 changed, 0 destroyed") {
|
||||||
|
t.Errorf("incorrect apply tally; want 0 added:\n%s", stdout)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The state file is in subdir because -chdir changed the current working directory.
|
||||||
|
state, err := tf.StateFromFile("subdir/terraform.tfstate")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to read state file: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
gotOutput := state.RootModule().OutputValues["cwd"]
|
||||||
|
wantOutputValue := cty.StringVal(tf.Path()) // path.cwd returns the original path, because path.root is how we get the overridden path
|
||||||
|
if gotOutput == nil || !wantOutputValue.RawEquals(gotOutput.Value) {
|
||||||
|
t.Errorf("incorrect value for cwd output\ngot: %#v\nwant Value: %#v", gotOutput, wantOutputValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
gotOutput = state.RootModule().OutputValues["root"]
|
||||||
|
wantOutputValue = cty.StringVal(tf.Path("subdir")) // path.root is a relative path, but the text fixture uses abspath on it.
|
||||||
|
if gotOutput == nil || !wantOutputValue.RawEquals(gotOutput.Value) {
|
||||||
|
t.Errorf("incorrect value for root output\ngot: %#v\nwant Value: %#v", gotOutput, wantOutputValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(state.RootModule().Resources) != 0 {
|
||||||
|
t.Errorf("unexpected resources in state")
|
||||||
|
}
|
||||||
|
|
||||||
|
//// DESTROY
|
||||||
|
stdout, stderr, err = tf.Run("-chdir=subdir", "destroy", "-auto-approve")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected destroy error: %s\nstderr:\n%s", err, stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(stdout, "Resources: 0 destroyed") {
|
||||||
|
t.Errorf("incorrect destroy tally; want 0 destroyed:\n%s", stdout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
output "cwd" {
|
||||||
|
value = path.cwd
|
||||||
|
}
|
||||||
|
|
||||||
|
output "root" {
|
||||||
|
value = abspath(path.root)
|
||||||
|
}
|
|
@ -39,6 +39,17 @@ type Meta struct {
|
||||||
// command with a Meta field. These are expected to be set externally
|
// command with a Meta field. These are expected to be set externally
|
||||||
// (not from within the command itself).
|
// (not from within the command itself).
|
||||||
|
|
||||||
|
// OriginalWorkingDir, if set, is the actual working directory where
|
||||||
|
// Terraform was run from. This might not be the _actual_ current working
|
||||||
|
// directory, because users can add the -chdir=... option to the beginning
|
||||||
|
// of their command line to ask Terraform to switch.
|
||||||
|
//
|
||||||
|
// Most things should just use the current working directory in order to
|
||||||
|
// respect the user's override, but we retain this for exceptional
|
||||||
|
// situations where we need to refer back to the original working directory
|
||||||
|
// for some reason.
|
||||||
|
OriginalWorkingDir string
|
||||||
|
|
||||||
Color bool // True if output should be colored
|
Color bool // True if output should be colored
|
||||||
GlobalPluginDirs []string // Additional paths to search for plugins
|
GlobalPluginDirs []string // Additional paths to search for plugins
|
||||||
PluginOverrides *PluginOverrides // legacy overrides from .terraformrc file
|
PluginOverrides *PluginOverrides // legacy overrides from .terraformrc file
|
||||||
|
@ -385,6 +396,7 @@ func (m *Meta) contextOpts() (*terraform.ContextOpts, error) {
|
||||||
|
|
||||||
opts.Meta = &terraform.ContextMeta{
|
opts.Meta = &terraform.ContextMeta{
|
||||||
Env: workspace,
|
Env: workspace,
|
||||||
|
OriginalWorkingDir: m.OriginalWorkingDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &opts, nil
|
return &opts, nil
|
||||||
|
|
|
@ -40,7 +40,7 @@ const (
|
||||||
OutputPrefix = "o:"
|
OutputPrefix = "o:"
|
||||||
)
|
)
|
||||||
|
|
||||||
func initCommands(config *cliconfig.Config, services *disco.Disco, providerSrc getproviders.Source, unmanagedProviders map[addrs.Provider]*plugin.ReattachConfig) {
|
func initCommands(originalWorkingDir string, config *cliconfig.Config, services *disco.Disco, providerSrc getproviders.Source, unmanagedProviders map[addrs.Provider]*plugin.ReattachConfig) {
|
||||||
var inAutomation bool
|
var inAutomation bool
|
||||||
if v := os.Getenv(runningInAutomationEnvName); v != "" {
|
if v := os.Getenv(runningInAutomationEnvName); v != "" {
|
||||||
inAutomation = true
|
inAutomation = true
|
||||||
|
@ -64,6 +64,8 @@ func initCommands(config *cliconfig.Config, services *disco.Disco, providerSrc g
|
||||||
dataDir := os.Getenv("TF_DATA_DIR")
|
dataDir := os.Getenv("TF_DATA_DIR")
|
||||||
|
|
||||||
meta := command.Meta{
|
meta := command.Meta{
|
||||||
|
OriginalWorkingDir: originalWorkingDir,
|
||||||
|
|
||||||
Color: true,
|
Color: true,
|
||||||
GlobalPluginDirs: globalPluginDirs(),
|
GlobalPluginDirs: globalPluginDirs(),
|
||||||
PluginOverrides: &PluginOverrides,
|
PluginOverrides: &PluginOverrides,
|
||||||
|
|
|
@ -180,7 +180,13 @@ func (b *binary) FileExists(path ...string) bool {
|
||||||
// LocalState is a helper for easily reading the local backend's state file
|
// LocalState is a helper for easily reading the local backend's state file
|
||||||
// terraform.tfstate from the working directory.
|
// terraform.tfstate from the working directory.
|
||||||
func (b *binary) LocalState() (*states.State, error) {
|
func (b *binary) LocalState() (*states.State, error) {
|
||||||
f, err := b.OpenFile("terraform.tfstate")
|
return b.StateFromFile("terraform.tfstate")
|
||||||
|
}
|
||||||
|
|
||||||
|
// StateFromFile is a helper for easily reading a state snapshot from a file
|
||||||
|
// on disk relative to the working directory.
|
||||||
|
func (b *binary) StateFromFile(filename string) (*states.State, error) {
|
||||||
|
f, err := b.OpenFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
9
help.go
9
help.go
|
@ -32,7 +32,7 @@ func helpFunc(commands map[string]cli.CommandFactory) string {
|
||||||
// website/source/docs/commands/index.html.markdown; if you
|
// website/source/docs/commands/index.html.markdown; if you
|
||||||
// change this then consider updating that to match.
|
// change this then consider updating that to match.
|
||||||
helpText := fmt.Sprintf(`
|
helpText := fmt.Sprintf(`
|
||||||
Usage: terraform [-version] [-help] <command> [args]
|
Usage: terraform [global options] <subcommand> [args]
|
||||||
|
|
||||||
The available commands for execution are listed below.
|
The available commands for execution are listed below.
|
||||||
The most common, useful commands are shown first, followed by
|
The most common, useful commands are shown first, followed by
|
||||||
|
@ -44,6 +44,13 @@ Common commands:
|
||||||
%s
|
%s
|
||||||
All other commands:
|
All other commands:
|
||||||
%s
|
%s
|
||||||
|
|
||||||
|
Global options (use these before the subcommand, if any):
|
||||||
|
-chdir=DIR Switch to a different working directory before executing
|
||||||
|
the given subcommand.
|
||||||
|
-help Show this help output, or the help for a specified
|
||||||
|
subcommand.
|
||||||
|
-version An alias for the "version" subcommand.
|
||||||
`, listCommands(porcelain, maxKeyLen), listCommands(plumbing, maxKeyLen))
|
`, listCommands(porcelain, maxKeyLen), listCommands(plumbing, maxKeyLen))
|
||||||
|
|
||||||
return strings.TrimSpace(helpText)
|
return strings.TrimSpace(helpText)
|
||||||
|
|
88
main.go
88
main.go
|
@ -129,6 +129,11 @@ func wrappedMain() int {
|
||||||
log.Printf("[INFO] Go runtime version: %s", runtime.Version())
|
log.Printf("[INFO] Go runtime version: %s", runtime.Version())
|
||||||
log.Printf("[INFO] CLI args: %#v", os.Args)
|
log.Printf("[INFO] CLI args: %#v", os.Args)
|
||||||
|
|
||||||
|
// NOTE: We're intentionally calling LoadConfig _before_ handling a possible
|
||||||
|
// -chdir=... option on the command line, so that a possible relative
|
||||||
|
// path in the TERRAFORM_CONFIG_FILE environment variable (though probably
|
||||||
|
// ill-advised) will be resolved relative to the true working directory,
|
||||||
|
// not the overridden one.
|
||||||
config, diags := cliconfig.LoadConfig()
|
config, diags := cliconfig.LoadConfig()
|
||||||
|
|
||||||
if len(diags) > 0 {
|
if len(diags) > 0 {
|
||||||
|
@ -203,9 +208,40 @@ func wrappedMain() int {
|
||||||
// Initialize the backends.
|
// Initialize the backends.
|
||||||
backendInit.Init(services)
|
backendInit.Init(services)
|
||||||
|
|
||||||
|
// Get the command line args.
|
||||||
|
binName := filepath.Base(os.Args[0])
|
||||||
|
args := os.Args[1:]
|
||||||
|
|
||||||
|
originalWd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
// It would be very strange to end up here
|
||||||
|
Ui.Error(fmt.Sprintf("Failed to determine current working directory: %s", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// The arguments can begin with a -chdir option to ask Terraform to switch
|
||||||
|
// to a different working directory for the rest of its work. If that
|
||||||
|
// option is present then extractChdirOption returns a trimmed args with that option removed.
|
||||||
|
overrideWd, args, err := extractChdirOption(args)
|
||||||
|
if err != nil {
|
||||||
|
Ui.Error(fmt.Sprintf("Invalid -chdir option: %s", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if overrideWd != "" {
|
||||||
|
os.Chdir(overrideWd)
|
||||||
|
if err != nil {
|
||||||
|
Ui.Error(fmt.Sprintf("Error handling -chdir option: %s", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// In tests, Commands may already be set to provide mock commands
|
// In tests, Commands may already be set to provide mock commands
|
||||||
if Commands == nil {
|
if Commands == nil {
|
||||||
initCommands(config, services, providerSrc, unmanagedProviders)
|
// Commands get to hold on to the original working directory here,
|
||||||
|
// in case they need to refer back to it for any special reason, though
|
||||||
|
// they should primarily be working with the override working directory
|
||||||
|
// that we've now switched to above.
|
||||||
|
initCommands(originalWd, config, services, providerSrc, unmanagedProviders)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run checkpoint
|
// Run checkpoint
|
||||||
|
@ -214,10 +250,6 @@ func wrappedMain() int {
|
||||||
// Make sure we clean up any managed plugins at the end of this
|
// Make sure we clean up any managed plugins at the end of this
|
||||||
defer plugin.CleanupClients()
|
defer plugin.CleanupClients()
|
||||||
|
|
||||||
// Get the command line args.
|
|
||||||
binName := filepath.Base(os.Args[0])
|
|
||||||
args := os.Args[1:]
|
|
||||||
|
|
||||||
// Build the CLI so far, we do this so we can query the subcommand.
|
// Build the CLI so far, we do this so we can query the subcommand.
|
||||||
cliRunner := &cli.CLI{
|
cliRunner := &cli.CLI{
|
||||||
Args: args,
|
Args: args,
|
||||||
|
@ -433,3 +465,49 @@ func parseReattachProviders(in string) (map[addrs.Provider]*plugin.ReattachConfi
|
||||||
}
|
}
|
||||||
return unmanagedProviders, nil
|
return unmanagedProviders, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func extractChdirOption(args []string) (string, []string, error) {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return "", args, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const argName = "-chdir"
|
||||||
|
const argPrefix = argName + "="
|
||||||
|
var argValue string
|
||||||
|
var argPos int
|
||||||
|
|
||||||
|
for i, arg := range args {
|
||||||
|
if !strings.HasPrefix(arg, "-") {
|
||||||
|
// Because the chdir option is a subcommand-agnostic one, we require
|
||||||
|
// it to appear before any subcommand argument, so if we find a
|
||||||
|
// non-option before we find -chdir then we are finished.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if arg == argName || arg == argPrefix {
|
||||||
|
return "", args, fmt.Errorf("must include an equals sign followed by a directory path, like -chdir=example")
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(arg, argPrefix) {
|
||||||
|
argPos = i
|
||||||
|
argValue = arg[len(argPrefix):]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When we fall out here, we'll have populated argValue with a non-empty
|
||||||
|
// string if the -chdir=... option was present and valid, or left it
|
||||||
|
// empty if it wasn't present.
|
||||||
|
if argValue == "" {
|
||||||
|
return "", args, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we did find the option then we'll need to produce a new args that
|
||||||
|
// doesn't include it anymore.
|
||||||
|
if argPos == 0 {
|
||||||
|
// Easy case: we can just slice off the front
|
||||||
|
return argValue, args[1:], nil
|
||||||
|
}
|
||||||
|
// Otherwise we need to construct a new array and copy to it.
|
||||||
|
newArgs := make([]string, len(args)-1)
|
||||||
|
copy(newArgs, args[:argPos])
|
||||||
|
copy(newArgs[argPos:], args[argPos+1:])
|
||||||
|
return argValue, newArgs, nil
|
||||||
|
}
|
||||||
|
|
|
@ -74,6 +74,19 @@ type ContextOpts struct {
|
||||||
// initializer.
|
// initializer.
|
||||||
type ContextMeta struct {
|
type ContextMeta struct {
|
||||||
Env string // Env is the state environment
|
Env string // Env is the state environment
|
||||||
|
|
||||||
|
// OriginalWorkingDir is the working directory where the Terraform CLI
|
||||||
|
// was run from, which may no longer actually be the current working
|
||||||
|
// directory if the user included the -chdir=... option.
|
||||||
|
//
|
||||||
|
// If this string is empty then the original working directory is the same
|
||||||
|
// as the current working directory.
|
||||||
|
//
|
||||||
|
// In most cases we should respect the user's override by ignoring this
|
||||||
|
// path and just using the current working directory, but this is here
|
||||||
|
// for some exceptional cases where the original working directory is
|
||||||
|
// needed.
|
||||||
|
OriginalWorkingDir string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Context represents all the context that Terraform needs in order to
|
// Context represents all the context that Terraform needs in order to
|
||||||
|
|
|
@ -553,7 +553,15 @@ func (d *evaluationStateData) GetPathAttr(addr addrs.PathAttr, rng tfdiags.Sourc
|
||||||
switch addr.Name {
|
switch addr.Name {
|
||||||
|
|
||||||
case "cwd":
|
case "cwd":
|
||||||
wd, err := os.Getwd()
|
var err error
|
||||||
|
var wd string
|
||||||
|
if d.Evaluator.Meta != nil {
|
||||||
|
// Meta is always non-nil in the normal case, but some test cases
|
||||||
|
// are not so realistic.
|
||||||
|
wd = d.Evaluator.Meta.OriginalWorkingDir
|
||||||
|
}
|
||||||
|
if wd == "" {
|
||||||
|
wd, err = os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
diags = diags.Append(&hcl.Diagnostic{
|
diags = diags.Append(&hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
|
@ -563,6 +571,21 @@ func (d *evaluationStateData) GetPathAttr(addr addrs.PathAttr, rng tfdiags.Sourc
|
||||||
})
|
})
|
||||||
return cty.DynamicVal, diags
|
return cty.DynamicVal, diags
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// The current working directory should always be absolute, whether we
|
||||||
|
// just looked it up or whether we were relying on ContextMeta's
|
||||||
|
// (possibly non-normalized) path.
|
||||||
|
wd, err = filepath.Abs(wd)
|
||||||
|
if err != nil {
|
||||||
|
diags = diags.Append(&hcl.Diagnostic{
|
||||||
|
Severity: hcl.DiagError,
|
||||||
|
Summary: `Failed to get working directory`,
|
||||||
|
Detail: fmt.Sprintf(`The value for path.cwd cannot be determined due to a system error: %s`, err),
|
||||||
|
Subject: rng.ToHCL().Ptr(),
|
||||||
|
})
|
||||||
|
return cty.DynamicVal, diags
|
||||||
|
}
|
||||||
|
|
||||||
return cty.StringVal(filepath.ToSlash(wd)), diags
|
return cty.StringVal(filepath.ToSlash(wd)), diags
|
||||||
|
|
||||||
case "module":
|
case "module":
|
||||||
|
|
|
@ -16,16 +16,15 @@ set of actions generated by a `terraform plan` execution plan.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Usage: `terraform apply [options] [dir-or-plan]`
|
Usage: `terraform apply [options] [plan]`
|
||||||
|
|
||||||
By default, `apply` scans the current directory for the configuration
|
By default, `apply` scans the current directory for the configuration
|
||||||
and applies the changes appropriately. However, a path to another configuration
|
and applies the changes appropriately. However, you can optionally give the
|
||||||
or an execution plan can be provided. Explicit execution plan files can be
|
path to a saved plan file that was previously created with
|
||||||
used to split plan and apply into separate steps within
|
[`terraform plan`](plan.html).
|
||||||
[automation systems](https://learn.hashicorp.com/terraform/development/running-terraform-in-automation).
|
|
||||||
|
|
||||||
If no explicit plan file is given on the command line, `terraform apply` will
|
If you don't give a plan file on the command line, `terraform apply` will
|
||||||
create a new plan automatically and prompt for approval to apply it. If the
|
create a new plan automatically and then prompt for approval to apply it. If the
|
||||||
created plan does not include any changes to resources or to root module
|
created plan does not include any changes to resources or to root module
|
||||||
output values then `terraform apply` will exit immediately, without prompting.
|
output values then `terraform apply` will exit immediately, without prompting.
|
||||||
|
|
||||||
|
@ -83,3 +82,24 @@ The command-line flags are all optional. The list of available flags are:
|
||||||
first and the `.auto.tfvars` files after in alphabetical order. Any files
|
first and the `.auto.tfvars` files after in alphabetical order. Any files
|
||||||
specified by `-var-file` override any values set automatically from files in
|
specified by `-var-file` override any values set automatically from files in
|
||||||
the working directory. This flag can be used multiple times.
|
the working directory. This flag can be used multiple times.
|
||||||
|
|
||||||
|
## Passing a Different Configuration Directory
|
||||||
|
|
||||||
|
Terraform v0.13 and earlier also accepted a directory path in place of the
|
||||||
|
plan file argument to `terraform apply`, in which case Terraform would use
|
||||||
|
that directory as the root module instead of the current working directory.
|
||||||
|
|
||||||
|
That usage is still supported in Terraform v0.14, but is now deprecated and we
|
||||||
|
plan to remove it in Terraform v0.15. If your workflow relies on overriding
|
||||||
|
the root module directory, use
|
||||||
|
[the `-chdir` global option](./#switching-working-directory-with--chdir)
|
||||||
|
instead, which works across all commands and makes Terraform consistently look
|
||||||
|
in the given directory for all files it would normaly read or write in the
|
||||||
|
current working directory.
|
||||||
|
|
||||||
|
If your previous use of this legacy pattern was also relying on Terraform
|
||||||
|
writing the `.terraform` subdirectory into the current working directory even
|
||||||
|
though the root module directory was overridden, use
|
||||||
|
[the `TF_DATA_DIR` environment variable](environment-variables.html#TF_DATA_DIR)
|
||||||
|
to direct Terraform to write the `.terraform` directory to a location other
|
||||||
|
than the current working directory.
|
||||||
|
|
|
@ -14,7 +14,7 @@ evaluating [expressions](/docs/configuration/expressions.html).
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Usage: `terraform console [options] [dir]`
|
Usage: `terraform console [options]`
|
||||||
|
|
||||||
This command provides an interactive command-line console for evaluating and
|
This command provides an interactive command-line console for evaluating and
|
||||||
experimenting with [expressions](/docs/configuration/expressions.html).
|
experimenting with [expressions](/docs/configuration/expressions.html).
|
||||||
|
@ -26,9 +26,6 @@ If the current state is empty or has not yet been created, the console can be
|
||||||
used to experiment with the expression syntax and
|
used to experiment with the expression syntax and
|
||||||
[built-in functions](/docs/configuration/functions.html).
|
[built-in functions](/docs/configuration/functions.html).
|
||||||
|
|
||||||
The `dir` argument specifies the directory of the root module to use.
|
|
||||||
If a path is not specified, the current working directory is used.
|
|
||||||
|
|
||||||
The supported options are:
|
The supported options are:
|
||||||
|
|
||||||
* `-state=path` - Path to a local state file. Expressions will be evaluated
|
* `-state=path` - Path to a local state file. Expressions will be evaluated
|
||||||
|
|
|
@ -13,12 +13,12 @@ infrastructure.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Usage: `terraform destroy [options] [dir]`
|
Usage: `terraform destroy [options]`
|
||||||
|
|
||||||
Infrastructure managed by Terraform will be destroyed. This will ask for
|
Infrastructure managed by Terraform will be destroyed. This will ask for
|
||||||
confirmation before destroying.
|
confirmation before destroying.
|
||||||
|
|
||||||
This command accepts all the arguments and flags that the [apply
|
This command accepts all the arguments and options that the [apply
|
||||||
command](/docs/commands/apply.html) accepts, with the exception of a plan file
|
command](/docs/commands/apply.html) accepts, with the exception of a plan file
|
||||||
argument.
|
argument.
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ process.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Usage: terraform force-unlock LOCK_ID [DIR]
|
Usage: terraform force-unlock LOCK_ID
|
||||||
|
|
||||||
Manually unlock the state for the defined configuration.
|
Manually unlock the state for the defined configuration.
|
||||||
|
|
||||||
|
|
|
@ -13,19 +13,13 @@ The `terraform get` command is used to download and update
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Usage: `terraform get [options] [dir]`
|
Usage: `terraform get [options]`
|
||||||
|
|
||||||
The modules are downloaded into a local `.terraform` folder. This
|
The modules are downloaded into a `.terraform` subdirectory of the current
|
||||||
folder should not be committed to version control. The `.terraform`
|
working directory. Don't commit this directory to your version control
|
||||||
folder is created relative to your current working directory
|
repository.
|
||||||
regardless of the `dir` argument given to this command.
|
|
||||||
|
|
||||||
If a module is already downloaded and the `-update` flag is _not_ set,
|
The `get` command supports the following option:
|
||||||
Terraform will do nothing. As a result, it is safe (and fast) to run this
|
|
||||||
command multiple times.
|
|
||||||
|
|
||||||
The command-line flags are all optional. The list of available flags are:
|
|
||||||
|
|
||||||
* `-update` - If specified, modules that are already downloaded will be
|
* `-update` - If specified, modules that are already downloaded will be
|
||||||
checked for updates and the updates will be downloaded if present.
|
checked for updates and the updates will be downloaded if present.
|
||||||
* `dir` - Sets the path of the [root module](/docs/modules/index.html#definitions).
|
|
||||||
|
|
|
@ -16,10 +16,10 @@ The output is in the DOT format, which can be used by
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Usage: `terraform graph [options] [DIR]`
|
Usage: `terraform graph [options]`
|
||||||
|
|
||||||
Outputs the visual dependency graph of Terraform resources according to
|
Outputs the visual dependency graph of Terraform resources represented by the
|
||||||
configuration files in DIR (or the current directory if omitted).
|
configuration in the current working directory.
|
||||||
|
|
||||||
The graph is outputted in DOT format. The typical program that can
|
The graph is outputted in DOT format. The typical program that can
|
||||||
read this format is GraphViz, but many web services are also available
|
read this format is GraphViz, but many web services are also available
|
||||||
|
|
|
@ -22,8 +22,7 @@ most likely expect.
|
||||||
To view a list of the available commands at any time, just run terraform with no arguments:
|
To view a list of the available commands at any time, just run terraform with no arguments:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
$ terraform
|
Usage: terraform [global options] <subcommand> [args]
|
||||||
Usage: terraform [-version] [-help] <command> [args]
|
|
||||||
|
|
||||||
The available commands for execution are listed below.
|
The available commands for execution are listed below.
|
||||||
The most common, useful commands are shown first, followed by
|
The most common, useful commands are shown first, followed by
|
||||||
|
@ -41,6 +40,8 @@ Common commands:
|
||||||
graph Create a visual graph of Terraform resources
|
graph Create a visual graph of Terraform resources
|
||||||
import Import existing infrastructure into Terraform
|
import Import existing infrastructure into Terraform
|
||||||
init Initialize a Terraform working directory
|
init Initialize a Terraform working directory
|
||||||
|
login Obtain and save credentials for a remote host
|
||||||
|
logout Remove locally-stored credentials for a remote host
|
||||||
output Read an output from a state file
|
output Read an output from a state file
|
||||||
plan Generate and show an execution plan
|
plan Generate and show an execution plan
|
||||||
providers Prints a tree of the providers used in the configuration
|
providers Prints a tree of the providers used in the configuration
|
||||||
|
@ -53,18 +54,24 @@ Common commands:
|
||||||
workspace Workspace management
|
workspace Workspace management
|
||||||
|
|
||||||
All other commands:
|
All other commands:
|
||||||
0.12upgrade Rewrites pre-0.12 module source code for v0.12
|
|
||||||
debug Debug output management (experimental)
|
debug Debug output management (experimental)
|
||||||
force-unlock Manually unlock the terraform state
|
force-unlock Manually unlock the terraform state
|
||||||
push Obsolete command for Terraform Enterprise legacy (v1)
|
|
||||||
state Advanced state management
|
state Advanced state management
|
||||||
|
|
||||||
|
|
||||||
|
Global options (use these before the subcommand, if any):
|
||||||
|
-chdir=DIR Switch to a different working directory before executing
|
||||||
|
the given subcommand.
|
||||||
|
-help Show this help output, or the help for a specified
|
||||||
|
subcommand.
|
||||||
|
-version An alias for the "version" subcommand.
|
||||||
```
|
```
|
||||||
|
|
||||||
To get help for any specific command, pass the -h flag to the relevant subcommand. For example,
|
To get help for any specific command, use the -help option to the relevant
|
||||||
to see help about the graph subcommand:
|
subcommand. For example, to see help about the graph subcommand:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
$ terraform graph -h
|
$ terraform graph -help
|
||||||
Usage: terraform graph [options] PATH
|
Usage: terraform graph [options] PATH
|
||||||
|
|
||||||
Outputs the visual graph of Terraform resources. If the path given is
|
Outputs the visual graph of Terraform resources. If the path given is
|
||||||
|
@ -77,6 +84,39 @@ Usage: terraform graph [options] PATH
|
||||||
to read this format.
|
to read this format.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Switching working directory with `-chdir`
|
||||||
|
|
||||||
|
The usual way to run Terraform is to first switch to the directory containing
|
||||||
|
the `.tf` files for your root module (for example, using the `cd` command), so
|
||||||
|
that Terraform will find those files automatically without any extra arguments.
|
||||||
|
|
||||||
|
In some cases though — particularly when wrapping Terraform in automation
|
||||||
|
scripts — it can be convenient to run Terraform from a different directory than
|
||||||
|
the root module directory. To allow that, Terraform supports a global option
|
||||||
|
`-chdir=...` which you can include before the name of the subcommand you intend
|
||||||
|
to run:
|
||||||
|
|
||||||
|
```
|
||||||
|
terraform -chdir=environments/production apply
|
||||||
|
```
|
||||||
|
|
||||||
|
The `chdir` option instructs Terraform to change its working directory to the
|
||||||
|
given directory before running the given subcommand. This means that any files
|
||||||
|
that Terraform would normally read or write in the current working directory
|
||||||
|
will be read or written in the given directory instead.
|
||||||
|
|
||||||
|
There are two exceptions where Terraform will use the original working directory
|
||||||
|
even when you specify `-chdir=...`:
|
||||||
|
|
||||||
|
* Settings in the [CLI Configuration](cli-config.html) are not for a specific
|
||||||
|
subcommand and Terraform processes them before acting on the `-chdir`
|
||||||
|
option.
|
||||||
|
|
||||||
|
* In case you need to use files from the original working directory as part
|
||||||
|
of your configuration, a reference to `path.cwd` in the configuration will
|
||||||
|
produce the original working directory instead of the overridden working
|
||||||
|
directory. Use `path.root` to get the root module directory.
|
||||||
|
|
||||||
## Shell Tab-completion
|
## Shell Tab-completion
|
||||||
|
|
||||||
If you use either `bash` or `zsh` as your command shell, Terraform can provide
|
If you use either `bash` or `zsh` as your command shell, Terraform can provide
|
||||||
|
|
|
@ -17,23 +17,18 @@ from version control. It is safe to run this command multiple times.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Usage: `terraform init [options] [DIR]`
|
Usage: `terraform init [options]`
|
||||||
|
|
||||||
This command performs several different initialization steps in order to
|
This command performs several different initialization steps in order to
|
||||||
prepare a working directory for use. More details on these are in the
|
prepare the current working directory for use with Terraform. More details on
|
||||||
sections below, but in most cases it is not necessary to worry about these
|
these are in the sections below, but in most cases it is not necessary to worry
|
||||||
individual steps.
|
about these individual steps.
|
||||||
|
|
||||||
This command is always safe to run multiple times, to bring the working
|
This command is always safe to run multiple times, to bring the working
|
||||||
directory up to date with changes in the configuration. Though subsequent runs
|
directory up to date with changes in the configuration. Though subsequent runs
|
||||||
may give errors, this command will never delete your existing configuration or
|
may give errors, this command will never delete your existing configuration or
|
||||||
state.
|
state.
|
||||||
|
|
||||||
If no arguments are given, the configuration in the current working directory
|
|
||||||
is initialized. It is recommended to run Terraform with the current working
|
|
||||||
directory set to the root directory of the configuration, and omit the `DIR`
|
|
||||||
argument.
|
|
||||||
|
|
||||||
## General Options
|
## General Options
|
||||||
|
|
||||||
The following options apply to all of (or several of) the initialization steps:
|
The following options apply to all of (or several of) the initialization steps:
|
||||||
|
@ -166,3 +161,24 @@ There are some special concerns when running `init` in such an environment,
|
||||||
including optionally making plugins available locally to avoid repeated
|
including optionally making plugins available locally to avoid repeated
|
||||||
re-installation. For more information, see
|
re-installation. For more information, see
|
||||||
[`Running Terraform in Automation`](https://learn.hashicorp.com/terraform/development/running-terraform-in-automation).
|
[`Running Terraform in Automation`](https://learn.hashicorp.com/terraform/development/running-terraform-in-automation).
|
||||||
|
|
||||||
|
## Passing a Different Configuration Directory
|
||||||
|
|
||||||
|
Terraform v0.13 and earlier also accepted a directory path in place of the
|
||||||
|
plan file argument to `terraform apply`, in which case Terraform would use
|
||||||
|
that directory as the root module instead of the current working directory.
|
||||||
|
|
||||||
|
That usage is still supported in Terraform v0.14, but is now deprecated and we
|
||||||
|
plan to remove it in Terraform v0.15. If your workflow relies on overriding
|
||||||
|
the root module directory, use
|
||||||
|
[the `-chdir` global option](./#switching-working-directory-with--chdir)
|
||||||
|
instead, which works across all commands and makes Terraform consistently look
|
||||||
|
in the given directory for all files it would normaly read or write in the
|
||||||
|
current working directory.
|
||||||
|
|
||||||
|
If your previous use of this legacy pattern was also relying on Terraform
|
||||||
|
writing the `.terraform` subdirectory into the current working directory even
|
||||||
|
though the root module directory was overridden, use
|
||||||
|
[the `TF_DATA_DIR` environment variable](environment-variables.html#TF_DATA_DIR)
|
||||||
|
to direct Terraform to write the `.terraform` directory to a location other
|
||||||
|
than the current working directory.
|
||||||
|
|
|
@ -30,12 +30,12 @@ If Terraform detects no changes to resource or to root module output values,
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Usage: `terraform plan [options] [dir]`
|
Usage: `terraform plan [options]`
|
||||||
|
|
||||||
By default, `plan` requires no flags and looks in the current directory
|
The `plan` subcommand looks in the current working directory for the root module
|
||||||
for the configuration and state file to refresh.
|
configuration.
|
||||||
|
|
||||||
The command-line flags are all optional. The list of available flags are:
|
The available options are:
|
||||||
|
|
||||||
* `-compact-warnings` - If Terraform produces any warnings that are not
|
* `-compact-warnings` - If Terraform produces any warnings that are not
|
||||||
accompanied by errors, show them in a more compact form that includes only
|
accompanied by errors, show them in a more compact form that includes only
|
||||||
|
@ -132,3 +132,24 @@ or keep it at rest for an extended period of time.
|
||||||
|
|
||||||
Future versions of Terraform will make plan files more
|
Future versions of Terraform will make plan files more
|
||||||
secure.
|
secure.
|
||||||
|
|
||||||
|
## Passing a Different Configuration Directory
|
||||||
|
|
||||||
|
Terraform v0.13 and earlier accepted an additional positional argument giving
|
||||||
|
a directory path, in which case Terraform would use that directory as the root
|
||||||
|
module instead of the current working directory.
|
||||||
|
|
||||||
|
That usage is still supported in Terraform v0.14, but is now deprecated and we
|
||||||
|
plan to remove it in Terraform v0.15. If your workflow relies on overriding
|
||||||
|
the root module directory, use
|
||||||
|
[the `-chdir` global option](./#switching-working-directory-with--chdir)
|
||||||
|
instead, which works across all commands and makes Terraform consistently look
|
||||||
|
in the given directory for all files it would normaly read or write in the
|
||||||
|
current working directory.
|
||||||
|
|
||||||
|
If your previous use of this legacy pattern was also relying on Terraform
|
||||||
|
writing the `.terraform` subdirectory into the current working directory even
|
||||||
|
though the root module directory was overridden, use
|
||||||
|
[the `TF_DATA_DIR` environment variable](environment-variables.html#TF_DATA_DIR)
|
||||||
|
to direct Terraform to write the `.terraform` directory to a location other
|
||||||
|
than the current working directory.
|
||||||
|
|
|
@ -9,36 +9,14 @@ description: |-
|
||||||
|
|
||||||
# Command: providers
|
# Command: providers
|
||||||
|
|
||||||
The `terraform providers` command prints information about the providers
|
The `terraform providers` command shows information about the
|
||||||
used in the current configuration.
|
[provider requirements](/docs/configuration/provider-requirements.html) of the
|
||||||
|
configuration in the current working directory, as an aid to understanding
|
||||||
|
where each requirement was detected from.
|
||||||
|
|
||||||
Provider dependencies are created in several different ways:
|
This command also has several subcommands with different purposes, which
|
||||||
|
are listed in the navigation bar.
|
||||||
* Explicit use of a `terraform.required_providers` block in configuration,
|
|
||||||
optionally including a version constraint.
|
|
||||||
|
|
||||||
* Explicit use of a `provider` block in configuration, optionally including
|
|
||||||
a version constraint.
|
|
||||||
|
|
||||||
* Use of any resource belonging to a particular provider in a `resource` or
|
|
||||||
`data` block in configuration.
|
|
||||||
|
|
||||||
* Existence of any resource instance belonging to a particular provider in
|
|
||||||
the current _state_. For example, if a particular resource is removed
|
|
||||||
from configuration, it continues to create a dependency on its provider
|
|
||||||
until its instances have been destroyed.
|
|
||||||
|
|
||||||
This command gives an overview of all of the current dependencies, as an aid
|
|
||||||
to understanding why a particular provider is needed.
|
|
||||||
|
|
||||||
This command is a nested subcommand, meaning that it has further subcommands.
|
|
||||||
These subcommands are listed to the left.
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Usage: `terraform providers [config-path]`
|
Usage: `terraform providers`
|
||||||
|
|
||||||
Pass an explicit configuration path to override the default of using the
|
|
||||||
current working directory.
|
|
||||||
|
|
||||||
Please refer to the subcommands to the left for additional usages.
|
|
||||||
|
|
|
@ -19,12 +19,9 @@ plan or apply.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Usage: `terraform refresh [options] [dir]`
|
Usage: `terraform refresh [options]`
|
||||||
|
|
||||||
By default, `refresh` requires no flags and looks in the current directory
|
The `terraform refresh` command accepts the following options:
|
||||||
for the configuration and state file to refresh.
|
|
||||||
|
|
||||||
The command-line flags are all optional. The list of available flags are:
|
|
||||||
|
|
||||||
* `-backup=path` - Path to the backup file. Defaults to `-state-out` with
|
* `-backup=path` - Path to the backup file. Defaults to `-state-out` with
|
||||||
the ".backup" extension. Disabled by setting to "-".
|
the ".backup" extension. Disabled by setting to "-".
|
||||||
|
|
|
@ -32,12 +32,13 @@ The output format is covered in detail in [JSON Output Format](/docs/internals/j
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Usage: `terraform show [options] [path]`
|
Usage: `terraform show [options] [file]`
|
||||||
|
|
||||||
You may use `show` with a path to either a Terraform state file or plan
|
You may use `show` with a path to either a Terraform state file or plan
|
||||||
file. If no path is specified, the current state will be shown.
|
file. If you don't specify a file path, Terraform will show the latest state
|
||||||
|
snapshot.
|
||||||
|
|
||||||
The command-line flags are all optional. The list of available flags are:
|
This command accepts the following options:
|
||||||
|
|
||||||
* `-no-color` - Disables output with coloring
|
* `-no-color` - Disables output with coloring
|
||||||
|
|
||||||
|
|
|
@ -29,20 +29,15 @@ validation without accessing any configured remote backend, use:
|
||||||
$ terraform init -backend=false
|
$ terraform init -backend=false
|
||||||
```
|
```
|
||||||
|
|
||||||
If dir is not specified, then the current directory will be used.
|
|
||||||
|
|
||||||
To verify configuration in the context of a particular run (a particular
|
To verify configuration in the context of a particular run (a particular
|
||||||
target workspace, input variable values, etc), use the `terraform plan`
|
target workspace, input variable values, etc), use the `terraform plan`
|
||||||
command instead, which includes an implied validation check.
|
command instead, which includes an implied validation check.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Usage: `terraform validate [options] [dir]`
|
Usage: `terraform validate [options]`
|
||||||
|
|
||||||
By default, `validate` requires no flags and looks in the current directory
|
This command accepts the following options:
|
||||||
for the configurations.
|
|
||||||
|
|
||||||
The command-line flags are all optional. The available flags are:
|
|
||||||
|
|
||||||
- `-json` - Produce output in a machine-readable JSON format, suitable for
|
- `-json` - Produce output in a machine-readable JSON format, suitable for
|
||||||
use in text editor integrations and other automated systems. Always disables
|
use in text editor integrations and other automated systems. Always disables
|
||||||
|
|
Loading…
Reference in New Issue