core: allow overriding environment name via env var

This allows you to run multiple concurrent terraform operations against
different environments from the same source directory.

Fixes #14447.

Also removes some dead code which appears to do the same thing as the function I
modified.
This commit is contained in:
David Glasser 2017-05-12 13:53:29 -07:00 committed by Martin Atkins
parent 73139ba6aa
commit c25d848ffb
6 changed files with 62 additions and 23 deletions

View File

@ -8,7 +8,6 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"sort" "sort"
"strings"
"sync" "sync"
"github.com/hashicorp/terraform/backend" "github.com/hashicorp/terraform/backend"
@ -391,22 +390,3 @@ func (b *Local) stateEnvDir() string {
return DefaultEnvDir return DefaultEnvDir
} }
// currentStateName returns the name of the current named state as set in the
// configuration files.
// If there are no configured environments, currentStateName returns "default"
func (b *Local) currentStateName() (string, error) {
contents, err := ioutil.ReadFile(filepath.Join(DefaultDataDir, DefaultEnvFile))
if os.IsNotExist(err) {
return backend.DefaultStateName, nil
}
if err != nil {
return "", err
}
if fromFile := strings.TrimSpace(string(contents)); fromFile != "" {
return fromFile, nil
}
return backend.DefaultStateName, nil
}

View File

@ -96,5 +96,28 @@ to another environment and try again.
envInvalidName = ` envInvalidName = `
The environment name %q is not allowed. The name must contain only URL safe The environment name %q is not allowed. The name must contain only URL safe
characters, and no path separators. characters, and no path separators.
`
envIsOverriddenNote = `
The active environment is being overridden using the TF_ENVIRONMENT environment
variable.
`
envIsOverriddenSelectError = `
The environment is currently overridden using the TF_ENVIRONMENT environment
variable.
To select a new environment, either update this environment variable or unset
it and then run this command again.
`
envIsOverriddenNewError = `
The environment is currently overridden using the TF_ENVIRONMENT environment
variable. You cannot create a different environment when using this setting.
To create a new environment, either unset this environment variable or update it
to match the environment name you are trying to create, and then run this command
again.
` `
) )

View File

@ -48,7 +48,7 @@ func (c *EnvListCommand) Run(args []string) int {
return 1 return 1
} }
env := c.Env() env, isOverridden := c.EnvOverridden()
var out bytes.Buffer var out bytes.Buffer
for _, s := range states { for _, s := range states {
@ -61,6 +61,11 @@ func (c *EnvListCommand) Run(args []string) int {
} }
c.Ui.Output(out.String()) c.Ui.Output(out.String())
if isOverridden {
c.Ui.Output(envIsOverriddenNote)
}
return 0 return 0
} }

View File

@ -40,6 +40,13 @@ func (c *EnvNewCommand) Run(args []string) int {
return 1 return 1
} }
// You can't ask to create an environment when you're overriding the
// environment name to be something different.
if current, isOverridden := c.EnvOverridden(); current != newEnv && isOverridden {
c.Ui.Error(envIsOverriddenNewError)
return 1
}
configPath, err := ModulePath(args[1:]) configPath, err := ModulePath(args[1:])
if err != nil { if err != nil {
c.Ui.Error(err.Error()) c.Ui.Error(err.Error())

View File

@ -34,6 +34,11 @@ func (c *EnvSelectCommand) Run(args []string) int {
conf, err := c.Config(configPath) conf, err := c.Config(configPath)
if err != nil { if err != nil {
c.Ui.Error(fmt.Sprintf("Failed to load root config module: %s", err)) c.Ui.Error(fmt.Sprintf("Failed to load root config module: %s", err))
}
current, isOverridden := c.EnvOverridden()
if isOverridden {
c.Ui.Error(envIsOverriddenSelectError)
return 1 return 1
} }
@ -59,7 +64,7 @@ func (c *EnvSelectCommand) Run(args []string) int {
return 1 return 1
} }
if name == c.Env() { if name == current {
// already using this env // already using this env
return 0 return 0
} }

View File

@ -454,9 +454,28 @@ func (m *Meta) outputShadowError(err error, output bool) bool {
return true return true
} }
// EnvironmentNameEnvVar is the name of the environment variable (ie, the POSIX
// feature) that can be used to set the name of the Terraform environment
// (overriding the environment chosen by `terraform env select`). Note that
// this environment variable is ignored by `terraform env new` and `terraform
// env delete`.
const EnvironmentNameEnvVar = "TF_ENVIRONMENT"
// Env returns the name of the currently configured environment, corresponding // Env returns the name of the currently configured environment, corresponding
// to the desired named state. // to the desired named state.
func (m *Meta) Env() string { func (m *Meta) Env() string {
current, _ := m.EnvOverridden()
return current
}
// EnvOverridden returns the name of the currently configured environment,
// corresponding to the desired named state, as well as a bool saying whether
// this was set via the TF_ENVIRONMENT environment variable.
func (m *Meta) EnvOverridden() (string, bool) {
if envVar := os.Getenv(EnvironmentNameEnvVar); envVar != "" {
return envVar, true
}
dataDir := m.dataDir dataDir := m.dataDir
if m.dataDir == "" { if m.dataDir == "" {
dataDir = DefaultDataDir dataDir = DefaultDataDir
@ -473,7 +492,7 @@ func (m *Meta) Env() string {
log.Printf("[ERROR] failed to read current environment: %s", err) log.Printf("[ERROR] failed to read current environment: %s", err)
} }
return current return current, false
} }
// SetEnv saves the named environment to the local filesystem. // SetEnv saves the named environment to the local filesystem.