Merge pull request #1119 from hashicorp/f-push
command: nest `push/pull` under `remote`, change `remote` to `remote config`
This commit is contained in:
commit
f0f799241a
|
@ -120,7 +120,7 @@ func (c *InitCommand) Run(args []string) int {
|
|||
}
|
||||
|
||||
// Initialize a blank state file with remote enabled
|
||||
remoteCmd := &RemoteCommand{
|
||||
remoteCmd := &RemoteConfigCommand{
|
||||
Meta: c.Meta,
|
||||
remoteConf: remoteConf,
|
||||
}
|
||||
|
|
|
@ -1,339 +1,57 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/state"
|
||||
"github.com/hashicorp/terraform/state/remote"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
// remoteCommandConfig is used to encapsulate our configuration
|
||||
type remoteCommandConfig struct {
|
||||
disableRemote bool
|
||||
pullOnDisable bool
|
||||
|
||||
statePath string
|
||||
backupPath string
|
||||
}
|
||||
|
||||
// RemoteCommand is a Command implementation that is used to
|
||||
// enable and disable remote state management
|
||||
type RemoteCommand struct {
|
||||
Meta
|
||||
conf remoteCommandConfig
|
||||
remoteConf terraform.RemoteState
|
||||
}
|
||||
|
||||
func (c *RemoteCommand) Run(args []string) int {
|
||||
func (c *RemoteCommand) Run(argsRaw []string) int {
|
||||
// Duplicate the args so we can munge them without affecting
|
||||
// future subcommand invocations which will do the same.
|
||||
args := make([]string, len(argsRaw))
|
||||
copy(args, argsRaw)
|
||||
args = c.Meta.process(args, false)
|
||||
config := make(map[string]string)
|
||||
cmdFlags := flag.NewFlagSet("remote", flag.ContinueOnError)
|
||||
cmdFlags.BoolVar(&c.conf.disableRemote, "disable", false, "")
|
||||
cmdFlags.BoolVar(&c.conf.pullOnDisable, "pull", true, "")
|
||||
cmdFlags.StringVar(&c.conf.statePath, "state", DefaultStateFilename, "path")
|
||||
cmdFlags.StringVar(&c.conf.backupPath, "backup", "", "path")
|
||||
cmdFlags.StringVar(&c.remoteConf.Type, "backend", "atlas", "")
|
||||
cmdFlags.Var((*FlagKV)(&config), "backend-config", "config")
|
||||
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
|
||||
if len(args) == 0 {
|
||||
c.Ui.Error(c.Help())
|
||||
return 1
|
||||
}
|
||||
|
||||
// Show help if given no inputs
|
||||
if !c.conf.disableRemote && c.remoteConf.Type == "atlas" && len(config) == 0 {
|
||||
cmdFlags.Usage()
|
||||
switch args[0] {
|
||||
case "config":
|
||||
cmd := &RemoteConfigCommand{Meta: c.Meta}
|
||||
return cmd.Run(args[1:])
|
||||
case "pull":
|
||||
cmd := &RemotePullCommand{Meta: c.Meta}
|
||||
return cmd.Run(args[1:])
|
||||
case "push":
|
||||
cmd := &RemotePushCommand{Meta: c.Meta}
|
||||
return cmd.Run(args[1:])
|
||||
default:
|
||||
c.Ui.Error(c.Help())
|
||||
return 1
|
||||
}
|
||||
|
||||
// Set the local state path
|
||||
c.statePath = c.conf.statePath
|
||||
|
||||
// Populate the various configurations
|
||||
c.remoteConf.Config = config
|
||||
|
||||
// Get the state information. We specifically request the cache only
|
||||
// for the remote state here because it is possible the remote state
|
||||
// is invalid and we don't want to error.
|
||||
stateOpts := c.StateOpts()
|
||||
stateOpts.RemoteCacheOnly = true
|
||||
if _, err := c.StateRaw(stateOpts); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error loading local state: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Get the local and remote [cached] state
|
||||
localState := c.stateResult.Local.State()
|
||||
var remoteState *terraform.State
|
||||
if remote := c.stateResult.Remote; remote != nil {
|
||||
remoteState = remote.State()
|
||||
}
|
||||
|
||||
// Check if remote state is being disabled
|
||||
if c.conf.disableRemote {
|
||||
if !remoteState.IsRemote() {
|
||||
c.Ui.Error(fmt.Sprintf("Remote state management not enabled! Aborting."))
|
||||
return 1
|
||||
}
|
||||
if !localState.Empty() {
|
||||
c.Ui.Error(fmt.Sprintf("State file already exists at '%s'. Aborting.",
|
||||
c.conf.statePath))
|
||||
return 1
|
||||
}
|
||||
|
||||
return c.disableRemoteState()
|
||||
}
|
||||
|
||||
// Ensure there is no conflict
|
||||
haveCache := !remoteState.Empty()
|
||||
haveLocal := !localState.Empty()
|
||||
switch {
|
||||
case haveCache && haveLocal:
|
||||
c.Ui.Error(fmt.Sprintf("Remote state is enabled, but non-managed state file '%s' is also present!",
|
||||
c.conf.statePath))
|
||||
return 1
|
||||
|
||||
case !haveCache && !haveLocal:
|
||||
// If we don't have either state file, initialize a blank state file
|
||||
return c.initBlankState()
|
||||
|
||||
case haveCache && !haveLocal:
|
||||
// Update the remote state target potentially
|
||||
return c.updateRemoteConfig()
|
||||
|
||||
case !haveCache && haveLocal:
|
||||
// Enable remote state management
|
||||
return c.enableRemoteState()
|
||||
}
|
||||
|
||||
panic("unhandled case")
|
||||
}
|
||||
|
||||
// disableRemoteState is used to disable remote state management,
|
||||
// and move the state file into place.
|
||||
func (c *RemoteCommand) disableRemoteState() int {
|
||||
if c.stateResult == nil {
|
||||
c.Ui.Error(fmt.Sprintf(
|
||||
"Internal error. State() must be called internally before remote\n" +
|
||||
"state can be disabled. Please report this as a bug."))
|
||||
return 1
|
||||
}
|
||||
if !c.stateResult.State.State().IsRemote() {
|
||||
c.Ui.Error(fmt.Sprintf(
|
||||
"Remote state is not enabled. Can't disable remote state."))
|
||||
return 1
|
||||
}
|
||||
local := c.stateResult.Local
|
||||
remote := c.stateResult.Remote
|
||||
|
||||
// Ensure we have the latest state before disabling
|
||||
if c.conf.pullOnDisable {
|
||||
log.Printf("[INFO] Refreshing local state from remote server")
|
||||
if err := remote.RefreshState(); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf(
|
||||
"Failed to refresh from remote state: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Exit if we were unable to update
|
||||
if change := remote.RefreshResult(); !change.SuccessfulPull() {
|
||||
c.Ui.Error(fmt.Sprintf("%s", change))
|
||||
return 1
|
||||
} else {
|
||||
log.Printf("[INFO] %s", change)
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the remote management, and copy into place
|
||||
newState := remote.State()
|
||||
newState.Remote = nil
|
||||
if err := local.WriteState(newState); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to encode state file '%s': %s",
|
||||
c.conf.statePath, err))
|
||||
return 1
|
||||
}
|
||||
if err := local.PersistState(); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to encode state file '%s': %s",
|
||||
c.conf.statePath, err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Remove the old state file
|
||||
if err := os.Remove(c.stateResult.RemotePath); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to remove the local state file: %v", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// validateRemoteConfig is used to verify that the remote configuration
|
||||
// we have is valid
|
||||
func (c *RemoteCommand) validateRemoteConfig() error {
|
||||
conf := c.remoteConf
|
||||
_, err := remote.NewClient(conf.Type, conf.Config)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("%s", err))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// initBlank state is used to initialize a blank state that is
|
||||
// remote enabled
|
||||
func (c *RemoteCommand) initBlankState() int {
|
||||
// Validate the remote configuration
|
||||
if err := c.validateRemoteConfig(); err != nil {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Make a blank state, attach the remote configuration
|
||||
blank := terraform.NewState()
|
||||
blank.Remote = &c.remoteConf
|
||||
|
||||
// Persist the state
|
||||
remote := &state.LocalState{Path: c.stateResult.RemotePath}
|
||||
if err := remote.WriteState(blank); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to initialize state file: %v", err))
|
||||
return 1
|
||||
}
|
||||
if err := remote.PersistState(); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to initialize state file: %v", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Success!
|
||||
c.Ui.Output("Initialized blank state with remote state enabled!")
|
||||
return 0
|
||||
}
|
||||
|
||||
// updateRemoteConfig is used to update the configuration of the
|
||||
// remote state store
|
||||
func (c *RemoteCommand) updateRemoteConfig() int {
|
||||
// Validate the remote configuration
|
||||
if err := c.validateRemoteConfig(); err != nil {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Read in the local state, which is just the cache of the remote state
|
||||
remote := c.stateResult.Remote.Cache
|
||||
|
||||
// Update the configuration
|
||||
state := remote.State()
|
||||
state.Remote = &c.remoteConf
|
||||
if err := remote.WriteState(state); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("%s", err))
|
||||
return 1
|
||||
}
|
||||
if err := remote.PersistState(); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("%s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Success!
|
||||
c.Ui.Output("Remote configuration updated")
|
||||
return 0
|
||||
}
|
||||
|
||||
// enableRemoteState is used to enable remote state management
|
||||
// and to move a state file into place
|
||||
func (c *RemoteCommand) enableRemoteState() int {
|
||||
// Validate the remote configuration
|
||||
if err := c.validateRemoteConfig(); err != nil {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Read the local state
|
||||
local := c.stateResult.Local
|
||||
if err := local.RefreshState(); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to read local state: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Backup the state file before we modify it
|
||||
backupPath := c.conf.backupPath
|
||||
if backupPath != "-" {
|
||||
// Provide default backup path if none provided
|
||||
if backupPath == "" {
|
||||
backupPath = c.conf.statePath + DefaultBackupExtention
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Writing backup state to: %s", backupPath)
|
||||
backup := &state.LocalState{Path: backupPath}
|
||||
if err := backup.WriteState(local.State()); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error writing backup state file: %s", err))
|
||||
return 1
|
||||
}
|
||||
if err := backup.PersistState(); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error writing backup state file: %s", err))
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
// Update the local configuration, move into place
|
||||
state := local.State()
|
||||
state.Remote = &c.remoteConf
|
||||
remote := c.stateResult.Remote
|
||||
if err := remote.WriteState(state); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("%s", err))
|
||||
return 1
|
||||
}
|
||||
if err := remote.PersistState(); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("%s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Remove the original, local state file
|
||||
log.Printf("[INFO] Removing state file: %s", c.conf.statePath)
|
||||
if err := os.Remove(c.conf.statePath); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to remove state file '%s': %v",
|
||||
c.conf.statePath, err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Success!
|
||||
c.Ui.Output("Remote state management enabled")
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *RemoteCommand) Help() string {
|
||||
helpText := `
|
||||
Usage: terraform remote [options]
|
||||
Usage: terraform remote <subcommand> [options]
|
||||
|
||||
Configures Terraform to use a remote state server. This allows state
|
||||
to be pulled down when necessary and then pushed to the server when
|
||||
updated. In this mode, the state file does not need to be stored durably
|
||||
since the remote server provides the durability.
|
||||
Configure remote state storage with Terraform.
|
||||
|
||||
Options:
|
||||
Available subcommands:
|
||||
|
||||
-backend=Atlas Specifies the type of remote backend. Must be one
|
||||
of Atlas, Consul, or HTTP. Defaults to Atlas.
|
||||
|
||||
-backend-config="k=v" Specifies configuration for the remote storage
|
||||
backend. This can be specified multiple times.
|
||||
|
||||
-backup=path Path to backup the existing state file before
|
||||
modifying. Defaults to the "-state" path with
|
||||
".backup" extension. Set to "-" to disable backup.
|
||||
|
||||
-disable Disables remote state management and migrates the state
|
||||
to the -state path.
|
||||
|
||||
-pull=true Controls if the remote state is pulled before disabling.
|
||||
This defaults to true to ensure the latest state is cached
|
||||
before disabling.
|
||||
|
||||
-state=path Path to read state. Defaults to "terraform.tfstate"
|
||||
unless remote state is enabled.
|
||||
config Configure the remote storage settings.
|
||||
pull Sync the remote storage by downloading to local storage.
|
||||
push Sync the remote storage by uploading the local storage.
|
||||
|
||||
`
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
func (c *RemoteCommand) Synopsis() string {
|
||||
return "Configures remote state management"
|
||||
return "Configure remote state storage"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,339 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/state"
|
||||
"github.com/hashicorp/terraform/state/remote"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
// remoteCommandConfig is used to encapsulate our configuration
|
||||
type remoteCommandConfig struct {
|
||||
disableRemote bool
|
||||
pullOnDisable bool
|
||||
|
||||
statePath string
|
||||
backupPath string
|
||||
}
|
||||
|
||||
// RemoteConfigCommand is a Command implementation that is used to
|
||||
// enable and disable remote state management
|
||||
type RemoteConfigCommand struct {
|
||||
Meta
|
||||
conf remoteCommandConfig
|
||||
remoteConf terraform.RemoteState
|
||||
}
|
||||
|
||||
func (c *RemoteConfigCommand) Run(args []string) int {
|
||||
args = c.Meta.process(args, false)
|
||||
config := make(map[string]string)
|
||||
cmdFlags := flag.NewFlagSet("remote", flag.ContinueOnError)
|
||||
cmdFlags.BoolVar(&c.conf.disableRemote, "disable", false, "")
|
||||
cmdFlags.BoolVar(&c.conf.pullOnDisable, "pull", true, "")
|
||||
cmdFlags.StringVar(&c.conf.statePath, "state", DefaultStateFilename, "path")
|
||||
cmdFlags.StringVar(&c.conf.backupPath, "backup", "", "path")
|
||||
cmdFlags.StringVar(&c.remoteConf.Type, "backend", "atlas", "")
|
||||
cmdFlags.Var((*FlagKV)(&config), "backend-config", "config")
|
||||
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Show help if given no inputs
|
||||
if !c.conf.disableRemote && c.remoteConf.Type == "atlas" && len(config) == 0 {
|
||||
cmdFlags.Usage()
|
||||
return 1
|
||||
}
|
||||
|
||||
// Set the local state path
|
||||
c.statePath = c.conf.statePath
|
||||
|
||||
// Populate the various configurations
|
||||
c.remoteConf.Config = config
|
||||
|
||||
// Get the state information. We specifically request the cache only
|
||||
// for the remote state here because it is possible the remote state
|
||||
// is invalid and we don't want to error.
|
||||
stateOpts := c.StateOpts()
|
||||
stateOpts.RemoteCacheOnly = true
|
||||
if _, err := c.StateRaw(stateOpts); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error loading local state: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Get the local and remote [cached] state
|
||||
localState := c.stateResult.Local.State()
|
||||
var remoteState *terraform.State
|
||||
if remote := c.stateResult.Remote; remote != nil {
|
||||
remoteState = remote.State()
|
||||
}
|
||||
|
||||
// Check if remote state is being disabled
|
||||
if c.conf.disableRemote {
|
||||
if !remoteState.IsRemote() {
|
||||
c.Ui.Error(fmt.Sprintf("Remote state management not enabled! Aborting."))
|
||||
return 1
|
||||
}
|
||||
if !localState.Empty() {
|
||||
c.Ui.Error(fmt.Sprintf("State file already exists at '%s'. Aborting.",
|
||||
c.conf.statePath))
|
||||
return 1
|
||||
}
|
||||
|
||||
return c.disableRemoteState()
|
||||
}
|
||||
|
||||
// Ensure there is no conflict
|
||||
haveCache := !remoteState.Empty()
|
||||
haveLocal := !localState.Empty()
|
||||
switch {
|
||||
case haveCache && haveLocal:
|
||||
c.Ui.Error(fmt.Sprintf("Remote state is enabled, but non-managed state file '%s' is also present!",
|
||||
c.conf.statePath))
|
||||
return 1
|
||||
|
||||
case !haveCache && !haveLocal:
|
||||
// If we don't have either state file, initialize a blank state file
|
||||
return c.initBlankState()
|
||||
|
||||
case haveCache && !haveLocal:
|
||||
// Update the remote state target potentially
|
||||
return c.updateRemoteConfig()
|
||||
|
||||
case !haveCache && haveLocal:
|
||||
// Enable remote state management
|
||||
return c.enableRemoteState()
|
||||
}
|
||||
|
||||
panic("unhandled case")
|
||||
}
|
||||
|
||||
// disableRemoteState is used to disable remote state management,
|
||||
// and move the state file into place.
|
||||
func (c *RemoteConfigCommand) disableRemoteState() int {
|
||||
if c.stateResult == nil {
|
||||
c.Ui.Error(fmt.Sprintf(
|
||||
"Internal error. State() must be called internally before remote\n" +
|
||||
"state can be disabled. Please report this as a bug."))
|
||||
return 1
|
||||
}
|
||||
if !c.stateResult.State.State().IsRemote() {
|
||||
c.Ui.Error(fmt.Sprintf(
|
||||
"Remote state is not enabled. Can't disable remote state."))
|
||||
return 1
|
||||
}
|
||||
local := c.stateResult.Local
|
||||
remote := c.stateResult.Remote
|
||||
|
||||
// Ensure we have the latest state before disabling
|
||||
if c.conf.pullOnDisable {
|
||||
log.Printf("[INFO] Refreshing local state from remote server")
|
||||
if err := remote.RefreshState(); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf(
|
||||
"Failed to refresh from remote state: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Exit if we were unable to update
|
||||
if change := remote.RefreshResult(); !change.SuccessfulPull() {
|
||||
c.Ui.Error(fmt.Sprintf("%s", change))
|
||||
return 1
|
||||
} else {
|
||||
log.Printf("[INFO] %s", change)
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the remote management, and copy into place
|
||||
newState := remote.State()
|
||||
newState.Remote = nil
|
||||
if err := local.WriteState(newState); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to encode state file '%s': %s",
|
||||
c.conf.statePath, err))
|
||||
return 1
|
||||
}
|
||||
if err := local.PersistState(); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to encode state file '%s': %s",
|
||||
c.conf.statePath, err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Remove the old state file
|
||||
if err := os.Remove(c.stateResult.RemotePath); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to remove the local state file: %v", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// validateRemoteConfig is used to verify that the remote configuration
|
||||
// we have is valid
|
||||
func (c *RemoteConfigCommand) validateRemoteConfig() error {
|
||||
conf := c.remoteConf
|
||||
_, err := remote.NewClient(conf.Type, conf.Config)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("%s", err))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// initBlank state is used to initialize a blank state that is
|
||||
// remote enabled
|
||||
func (c *RemoteConfigCommand) initBlankState() int {
|
||||
// Validate the remote configuration
|
||||
if err := c.validateRemoteConfig(); err != nil {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Make a blank state, attach the remote configuration
|
||||
blank := terraform.NewState()
|
||||
blank.Remote = &c.remoteConf
|
||||
|
||||
// Persist the state
|
||||
remote := &state.LocalState{Path: c.stateResult.RemotePath}
|
||||
if err := remote.WriteState(blank); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to initialize state file: %v", err))
|
||||
return 1
|
||||
}
|
||||
if err := remote.PersistState(); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to initialize state file: %v", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Success!
|
||||
c.Ui.Output("Initialized blank state with remote state enabled!")
|
||||
return 0
|
||||
}
|
||||
|
||||
// updateRemoteConfig is used to update the configuration of the
|
||||
// remote state store
|
||||
func (c *RemoteConfigCommand) updateRemoteConfig() int {
|
||||
// Validate the remote configuration
|
||||
if err := c.validateRemoteConfig(); err != nil {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Read in the local state, which is just the cache of the remote state
|
||||
remote := c.stateResult.Remote.Cache
|
||||
|
||||
// Update the configuration
|
||||
state := remote.State()
|
||||
state.Remote = &c.remoteConf
|
||||
if err := remote.WriteState(state); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("%s", err))
|
||||
return 1
|
||||
}
|
||||
if err := remote.PersistState(); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("%s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Success!
|
||||
c.Ui.Output("Remote configuration updated")
|
||||
return 0
|
||||
}
|
||||
|
||||
// enableRemoteState is used to enable remote state management
|
||||
// and to move a state file into place
|
||||
func (c *RemoteConfigCommand) enableRemoteState() int {
|
||||
// Validate the remote configuration
|
||||
if err := c.validateRemoteConfig(); err != nil {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Read the local state
|
||||
local := c.stateResult.Local
|
||||
if err := local.RefreshState(); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to read local state: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Backup the state file before we modify it
|
||||
backupPath := c.conf.backupPath
|
||||
if backupPath != "-" {
|
||||
// Provide default backup path if none provided
|
||||
if backupPath == "" {
|
||||
backupPath = c.conf.statePath + DefaultBackupExtention
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Writing backup state to: %s", backupPath)
|
||||
backup := &state.LocalState{Path: backupPath}
|
||||
if err := backup.WriteState(local.State()); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error writing backup state file: %s", err))
|
||||
return 1
|
||||
}
|
||||
if err := backup.PersistState(); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error writing backup state file: %s", err))
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
// Update the local configuration, move into place
|
||||
state := local.State()
|
||||
state.Remote = &c.remoteConf
|
||||
remote := c.stateResult.Remote
|
||||
if err := remote.WriteState(state); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("%s", err))
|
||||
return 1
|
||||
}
|
||||
if err := remote.PersistState(); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("%s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Remove the original, local state file
|
||||
log.Printf("[INFO] Removing state file: %s", c.conf.statePath)
|
||||
if err := os.Remove(c.conf.statePath); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to remove state file '%s': %v",
|
||||
c.conf.statePath, err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Success!
|
||||
c.Ui.Output("Remote state management enabled")
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *RemoteConfigCommand) Help() string {
|
||||
helpText := `
|
||||
Usage: terraform remote [options]
|
||||
|
||||
Configures Terraform to use a remote state server. This allows state
|
||||
to be pulled down when necessary and then pushed to the server when
|
||||
updated. In this mode, the state file does not need to be stored durably
|
||||
since the remote server provides the durability.
|
||||
|
||||
Options:
|
||||
|
||||
-backend=Atlas Specifies the type of remote backend. Must be one
|
||||
of Atlas, Consul, or HTTP. Defaults to Atlas.
|
||||
|
||||
-backend-config="k=v" Specifies configuration for the remote storage
|
||||
backend. This can be specified multiple times.
|
||||
|
||||
-backup=path Path to backup the existing state file before
|
||||
modifying. Defaults to the "-state" path with
|
||||
".backup" extension. Set to "-" to disable backup.
|
||||
|
||||
-disable Disables remote state management and migrates the state
|
||||
to the -state path.
|
||||
|
||||
-pull=true Controls if the remote state is pulled before disabling.
|
||||
This defaults to true to ensure the latest state is cached
|
||||
before disabling.
|
||||
|
||||
-state=path Path to read state. Defaults to "terraform.tfstate"
|
||||
unless remote state is enabled.
|
||||
|
||||
`
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
func (c *RemoteConfigCommand) Synopsis() string {
|
||||
return "Configures remote state management"
|
||||
}
|
|
@ -8,11 +8,11 @@ import (
|
|||
"github.com/hashicorp/terraform/state"
|
||||
)
|
||||
|
||||
type PullCommand struct {
|
||||
type RemotePullCommand struct {
|
||||
Meta
|
||||
}
|
||||
|
||||
func (c *PullCommand) Run(args []string) int {
|
||||
func (c *RemotePullCommand) Run(args []string) int {
|
||||
args = c.Meta.process(args, false)
|
||||
cmdFlags := flag.NewFlagSet("pull", flag.ContinueOnError)
|
||||
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
|
||||
|
@ -67,7 +67,7 @@ func (c *PullCommand) Run(args []string) int {
|
|||
return 0
|
||||
}
|
||||
|
||||
func (c *PullCommand) Help() string {
|
||||
func (c *RemotePullCommand) Help() string {
|
||||
helpText := `
|
||||
Usage: terraform pull [options]
|
||||
|
||||
|
@ -77,6 +77,6 @@ Usage: terraform pull [options]
|
|||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
func (c *PullCommand) Synopsis() string {
|
||||
func (c *RemotePullCommand) Synopsis() string {
|
||||
return "Refreshes the local state copy from the remote server"
|
||||
}
|
|
@ -15,12 +15,12 @@ import (
|
|||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
func TestPull_noRemote(t *testing.T) {
|
||||
func TestRemotePull_noRemote(t *testing.T) {
|
||||
tmp, cwd := testCwd(t)
|
||||
defer testFixCwd(t, tmp, cwd)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
c := &PullCommand{
|
||||
c := &RemotePullCommand{
|
||||
Meta: Meta{
|
||||
ContextOpts: testCtxConfig(testProvider()),
|
||||
Ui: ui,
|
||||
|
@ -33,7 +33,7 @@ func TestPull_noRemote(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestPull_local(t *testing.T) {
|
||||
func TestRemotePull_local(t *testing.T) {
|
||||
tmp, cwd := testCwd(t)
|
||||
defer testFixCwd(t, tmp, cwd)
|
||||
|
||||
|
@ -62,7 +62,7 @@ func TestPull_local(t *testing.T) {
|
|||
}
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
c := &PullCommand{
|
||||
c := &RemotePullCommand{
|
||||
Meta: Meta{
|
||||
ContextOpts: testCtxConfig(testProvider()),
|
||||
Ui: ui,
|
|
@ -8,11 +8,11 @@ import (
|
|||
"github.com/hashicorp/terraform/state"
|
||||
)
|
||||
|
||||
type PushCommand struct {
|
||||
type RemotePushCommand struct {
|
||||
Meta
|
||||
}
|
||||
|
||||
func (c *PushCommand) Run(args []string) int {
|
||||
func (c *RemotePushCommand) Run(args []string) int {
|
||||
var force bool
|
||||
args = c.Meta.process(args, false)
|
||||
cmdFlags := flag.NewFlagSet("push", flag.ContinueOnError)
|
||||
|
@ -71,7 +71,7 @@ func (c *PushCommand) Run(args []string) int {
|
|||
return 0
|
||||
}
|
||||
|
||||
func (c *PushCommand) Help() string {
|
||||
func (c *RemotePushCommand) Help() string {
|
||||
helpText := `
|
||||
Usage: terraform push [options]
|
||||
|
||||
|
@ -87,6 +87,6 @@ Options:
|
|||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
func (c *PushCommand) Synopsis() string {
|
||||
func (c *RemotePushCommand) Synopsis() string {
|
||||
return "Uploads the the local state to the remote server"
|
||||
}
|
|
@ -9,12 +9,12 @@ import (
|
|||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
func TestPush_noRemote(t *testing.T) {
|
||||
func TestRemotePush_noRemote(t *testing.T) {
|
||||
tmp, cwd := testCwd(t)
|
||||
defer testFixCwd(t, tmp, cwd)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
c := &PushCommand{
|
||||
c := &RemotePushCommand{
|
||||
Meta: Meta{
|
||||
ContextOpts: testCtxConfig(testProvider()),
|
||||
Ui: ui,
|
||||
|
@ -27,7 +27,7 @@ func TestPush_noRemote(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestPush_local(t *testing.T) {
|
||||
func TestRemotePush_local(t *testing.T) {
|
||||
tmp, cwd := testCwd(t)
|
||||
defer testFixCwd(t, tmp, cwd)
|
||||
|
||||
|
@ -56,7 +56,7 @@ func TestPush_local(t *testing.T) {
|
|||
}
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
c := &PushCommand{
|
||||
c := &RemotePushCommand{
|
||||
Meta: Meta{
|
||||
ContextOpts: testCtxConfig(testProvider()),
|
||||
Ui: ui,
|
|
@ -13,7 +13,7 @@ import (
|
|||
)
|
||||
|
||||
// Test disabling remote management
|
||||
func TestRemote_disable(t *testing.T) {
|
||||
func TestRemoteConfig_disable(t *testing.T) {
|
||||
tmp, cwd := testCwd(t)
|
||||
defer testFixCwd(t, tmp, cwd)
|
||||
|
||||
|
@ -39,7 +39,7 @@ func TestRemote_disable(t *testing.T) {
|
|||
}
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
c := &RemoteCommand{
|
||||
c := &RemoteConfigCommand{
|
||||
Meta: Meta{
|
||||
ContextOpts: testCtxConfig(testProvider()),
|
||||
Ui: ui,
|
||||
|
@ -68,7 +68,7 @@ func TestRemote_disable(t *testing.T) {
|
|||
}
|
||||
|
||||
// Test disabling remote management without pulling
|
||||
func TestRemote_disable_noPull(t *testing.T) {
|
||||
func TestRemoteConfig_disable_noPull(t *testing.T) {
|
||||
tmp, cwd := testCwd(t)
|
||||
defer testFixCwd(t, tmp, cwd)
|
||||
|
||||
|
@ -94,7 +94,7 @@ func TestRemote_disable_noPull(t *testing.T) {
|
|||
}
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
c := &RemoteCommand{
|
||||
c := &RemoteConfigCommand{
|
||||
Meta: Meta{
|
||||
ContextOpts: testCtxConfig(testProvider()),
|
||||
Ui: ui,
|
||||
|
@ -122,12 +122,12 @@ func TestRemote_disable_noPull(t *testing.T) {
|
|||
}
|
||||
|
||||
// Test disabling remote management when not enabled
|
||||
func TestRemote_disable_notEnabled(t *testing.T) {
|
||||
func TestRemoteConfig_disable_notEnabled(t *testing.T) {
|
||||
tmp, cwd := testCwd(t)
|
||||
defer testFixCwd(t, tmp, cwd)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
c := &RemoteCommand{
|
||||
c := &RemoteConfigCommand{
|
||||
Meta: Meta{
|
||||
ContextOpts: testCtxConfig(testProvider()),
|
||||
Ui: ui,
|
||||
|
@ -141,7 +141,7 @@ func TestRemote_disable_notEnabled(t *testing.T) {
|
|||
}
|
||||
|
||||
// Test disabling remote management with a state file in the way
|
||||
func TestRemote_disable_otherState(t *testing.T) {
|
||||
func TestRemoteConfig_disable_otherState(t *testing.T) {
|
||||
tmp, cwd := testCwd(t)
|
||||
defer testFixCwd(t, tmp, cwd)
|
||||
|
||||
|
@ -171,7 +171,7 @@ func TestRemote_disable_otherState(t *testing.T) {
|
|||
}
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
c := &RemoteCommand{
|
||||
c := &RemoteConfigCommand{
|
||||
Meta: Meta{
|
||||
ContextOpts: testCtxConfig(testProvider()),
|
||||
Ui: ui,
|
||||
|
@ -185,7 +185,7 @@ func TestRemote_disable_otherState(t *testing.T) {
|
|||
}
|
||||
|
||||
// Test the case where both managed and non managed state present
|
||||
func TestRemote_managedAndNonManaged(t *testing.T) {
|
||||
func TestRemoteConfig_managedAndNonManaged(t *testing.T) {
|
||||
tmp, cwd := testCwd(t)
|
||||
defer testFixCwd(t, tmp, cwd)
|
||||
|
||||
|
@ -215,7 +215,7 @@ func TestRemote_managedAndNonManaged(t *testing.T) {
|
|||
}
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
c := &RemoteCommand{
|
||||
c := &RemoteConfigCommand{
|
||||
Meta: Meta{
|
||||
ContextOpts: testCtxConfig(testProvider()),
|
||||
Ui: ui,
|
||||
|
@ -229,12 +229,12 @@ func TestRemote_managedAndNonManaged(t *testing.T) {
|
|||
}
|
||||
|
||||
// Test initializing blank state
|
||||
func TestRemote_initBlank(t *testing.T) {
|
||||
func TestRemoteConfig_initBlank(t *testing.T) {
|
||||
tmp, cwd := testCwd(t)
|
||||
defer testFixCwd(t, tmp, cwd)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
c := &RemoteCommand{
|
||||
c := &RemoteConfigCommand{
|
||||
Meta: Meta{
|
||||
ContextOpts: testCtxConfig(testProvider()),
|
||||
Ui: ui,
|
||||
|
@ -269,12 +269,12 @@ func TestRemote_initBlank(t *testing.T) {
|
|||
}
|
||||
|
||||
// Test initializing without remote settings
|
||||
func TestRemote_initBlank_missingRemote(t *testing.T) {
|
||||
func TestRemoteConfig_initBlank_missingRemote(t *testing.T) {
|
||||
tmp, cwd := testCwd(t)
|
||||
defer testFixCwd(t, tmp, cwd)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
c := &RemoteCommand{
|
||||
c := &RemoteConfigCommand{
|
||||
Meta: Meta{
|
||||
ContextOpts: testCtxConfig(testProvider()),
|
||||
Ui: ui,
|
||||
|
@ -288,7 +288,7 @@ func TestRemote_initBlank_missingRemote(t *testing.T) {
|
|||
}
|
||||
|
||||
// Test updating remote config
|
||||
func TestRemote_updateRemote(t *testing.T) {
|
||||
func TestRemoteConfig_updateRemote(t *testing.T) {
|
||||
tmp, cwd := testCwd(t)
|
||||
defer testFixCwd(t, tmp, cwd)
|
||||
|
||||
|
@ -310,7 +310,7 @@ func TestRemote_updateRemote(t *testing.T) {
|
|||
}
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
c := &RemoteCommand{
|
||||
c := &RemoteConfigCommand{
|
||||
Meta: Meta{
|
||||
ContextOpts: testCtxConfig(testProvider()),
|
||||
Ui: ui,
|
||||
|
@ -345,7 +345,7 @@ func TestRemote_updateRemote(t *testing.T) {
|
|||
}
|
||||
|
||||
// Test enabling remote state
|
||||
func TestRemote_enableRemote(t *testing.T) {
|
||||
func TestRemoteConfig_enableRemote(t *testing.T) {
|
||||
tmp, cwd := testCwd(t)
|
||||
defer testFixCwd(t, tmp, cwd)
|
||||
|
||||
|
@ -365,7 +365,7 @@ func TestRemote_enableRemote(t *testing.T) {
|
|||
}
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
c := &RemoteCommand{
|
||||
c := &RemoteConfigCommand{
|
||||
Meta: Meta{
|
||||
ContextOpts: testCtxConfig(testProvider()),
|
||||
Ui: ui,
|
||||
|
|
12
commands.go
12
commands.go
|
@ -80,18 +80,6 @@ func init() {
|
|||
}, nil
|
||||
},
|
||||
|
||||
"pull": func() (cli.Command, error) {
|
||||
return &command.PullCommand{
|
||||
Meta: meta,
|
||||
}, nil
|
||||
},
|
||||
|
||||
"push": func() (cli.Command, error) {
|
||||
return &command.PushCommand{
|
||||
Meta: meta,
|
||||
}, nil
|
||||
},
|
||||
|
||||
"refresh": func() (cli.Command, error) {
|
||||
return &command.RefreshCommand{
|
||||
Meta: meta,
|
||||
|
|
|
@ -31,11 +31,10 @@ Available commands are:
|
|||
init Initializes Terraform configuration from a module
|
||||
output Read an output from a state file
|
||||
plan Generate and show an execution plan
|
||||
pull Refreshes the local state copy from the remote server
|
||||
push Uploads the the local state to the remote server
|
||||
refresh Update local state file against real resources
|
||||
remote Configures remote state management
|
||||
remote Configure remote state storage
|
||||
show Inspect Terraform state or plan
|
||||
taint Manually mark a resource for recreation
|
||||
version Prints the Terraform version
|
||||
```
|
||||
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
---
|
||||
layout: "docs"
|
||||
page_title: "Command: pull"
|
||||
sidebar_current: "docs-commands-pull"
|
||||
description: |-
|
||||
The `terraform pull` refreshes the cached state file from the
|
||||
remote server when remote state storage is enabled.
|
||||
---
|
||||
|
||||
# Command: pull
|
||||
|
||||
The `terraform pull` refreshes the cached state file from the
|
||||
remote server when remote state storage is enabled. The [`remote`
|
||||
command](/docs/commands/remote.html) should be used to enable
|
||||
remote state storage.
|
||||
|
||||
## Usage
|
||||
|
||||
Usage: `terraform pull`
|
||||
|
||||
The `pull` command is invoked without options to refresh the
|
||||
cache copy of the state.
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
---
|
||||
layout: "docs"
|
||||
page_title: "Command: push"
|
||||
sidebar_current: "docs-commands-push"
|
||||
description: |-
|
||||
The `terraform push` command is used to push a cached local copy
|
||||
of the state to a remote storage server.
|
||||
---
|
||||
|
||||
# Command: push
|
||||
|
||||
The `terraform push` uploads the cached state file to the
|
||||
remote server when remote state storage is enabled. The [`remote`
|
||||
command](/docs/commands/remote.html) should be used to enable
|
||||
remote state storage.
|
||||
|
||||
Uploading is typically done automatically when running a Terraform
|
||||
command that modifies state, but this can be used to retry uploads
|
||||
if a transient failure occurs.
|
||||
|
||||
## Usage
|
||||
|
||||
Usage: `terraform push`
|
||||
|
||||
The `push` command is invoked without options to upload the
|
||||
local cached state to the remote storage server.
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
---
|
||||
layout: "docs"
|
||||
page_title: "Command: remote config"
|
||||
sidebar_current: "docs-commands-remote-config"
|
||||
description: |-
|
||||
The `terraform remote config` command is used to configure Terraform to make
|
||||
use of remote state storage, change remote storage configuration, or
|
||||
to disable it.
|
||||
---
|
||||
|
||||
# Command: remote config
|
||||
|
||||
The `terraform remote config` command is used to configure use of remote
|
||||
state storage. By default, Terraform persists its state only to a local
|
||||
disk. When remote state storage is enabled, Terraform will automatically
|
||||
fetch the latest state from the remote server when necessary and if any
|
||||
updates are made, the newest state is persisted back to the remote server.
|
||||
In this mode, users do not need to durably store the state using version
|
||||
control or shared storaged.
|
||||
|
||||
## Usage
|
||||
|
||||
Usage: `terraform remote config [options]`
|
||||
|
||||
The `remote config` command can be used to enable remote storage, change
|
||||
configuration or disable the use of remote storage. Terraform supports multiple types
|
||||
of storage backends, specified by using the `-backend` flag. By default,
|
||||
Atlas is assumed to be the storage backend. Each backend expects different,
|
||||
configuration arguments documented below.
|
||||
|
||||
When remote storage is enabled, an existing local state file can be migrated.
|
||||
By default, `remote config` will look for the "terraform.tfstate" file, but that
|
||||
can be specified by the `-state` flag. If no state file exists, a blank
|
||||
state will be configured.
|
||||
|
||||
When remote storage is disabled, the existing remote state is migrated
|
||||
to a local file. This defaults to the `-state` path during restore.
|
||||
|
||||
The following backends are supported:
|
||||
|
||||
* Atlas - Stores the state in Atlas. Requires the `-name` and `-access-token` flag.
|
||||
The `-address` flag can optionally be provided.
|
||||
|
||||
* Consul - Stores the state in the KV store at a given path.
|
||||
Requires the `path` flag. The `-address` and `-access-token`
|
||||
flag can optionally be provided. Address is assumed to be the
|
||||
local agent if not provided.
|
||||
|
||||
* HTTP - Stores the state using a simple REST client. State will be fetched
|
||||
via GET, updated via POST, and purged with DELETE. Requires the `-address` flag.
|
||||
|
||||
The command-line flags are all optional. The list of available flags are:
|
||||
|
||||
* `-address=url` - URL of the remote storage server. Required for HTTP backend,
|
||||
optional for Atlas and Consul.
|
||||
|
||||
* `-access-token=token` - Authentication token for state storage server.
|
||||
Required for Atlas backend, optional for Consul.
|
||||
|
||||
* `-backend=Atlas` - Specifies the type of remote backend. Must be one
|
||||
of Atlas, Consul, or HTTP. Defaults to Atlas.
|
||||
|
||||
* `-backup=path` - Path to backup the existing state file before
|
||||
modifying. Defaults to the "-state" path with ".backup" extension.
|
||||
Set to "-" to disable backup.
|
||||
|
||||
* `-disable` - Disables remote state management and migrates the state
|
||||
to the `-state` path.
|
||||
|
||||
* `-name=name` - Name of the state file in the state storage server.
|
||||
Required for Atlas backend.
|
||||
|
||||
* `-path=path` - Path of the remote state in Consul. Required for the
|
||||
Consul backend.
|
||||
|
||||
* `-pull=true` - Controls if the remote state is pulled before disabling.
|
||||
This defaults to true to ensure the latest state is cached before disabling.
|
||||
|
||||
* `-state=path` - Path to read state. Defaults to "terraform.tfstate"
|
||||
unless remote state is enabled.
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
layout: "docs"
|
||||
page_title: "Command: remote pull"
|
||||
sidebar_current: "docs-commands-remote-pull"
|
||||
description: |-
|
||||
The `terraform remote pull` refreshes the cached state file from the
|
||||
remote server when remote state storage is enabled.
|
||||
---
|
||||
|
||||
# Command: remote pull
|
||||
|
||||
The `terraform remote pull` refreshes the cached state file from the
|
||||
remote server when remote state storage is enabled. The [`remote config`
|
||||
command](/docs/commands/remote-config.html) should be used to enable
|
||||
remote state storage.
|
||||
|
||||
## Usage
|
||||
|
||||
Usage: `terraform remote pull`
|
||||
|
||||
The `remote pull` command is invoked without options to refresh the
|
||||
cache copy of the state.
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
layout: "docs"
|
||||
page_title: "Command: remote push"
|
||||
sidebar_current: "docs-commands-remote-push"
|
||||
description: |-
|
||||
The `terraform remote push` command is used to push a cached local copy
|
||||
of the state to a remote storage server.
|
||||
---
|
||||
|
||||
# Command: remote push
|
||||
|
||||
The `terraform remote push` uploads the cached state file to the
|
||||
remote server when remote state storage is enabled. The [`remote config`
|
||||
command](/docs/commands/remote-config.html) should be used to enable
|
||||
remote state storage.
|
||||
|
||||
Uploading is typically done automatically when running a Terraform
|
||||
command that modifies state, but this can be used to retry uploads
|
||||
if a transient failure occurs.
|
||||
|
||||
## Usage
|
||||
|
||||
Usage: `terraform remote push`
|
||||
|
||||
The `remote push` command is invoked without options to upload the
|
||||
local cached state to the remote storage server.
|
||||
|
|
@ -10,72 +10,24 @@ description: |-
|
|||
|
||||
# Command: remote
|
||||
|
||||
The `terraform remote` command is used to configure use of remote
|
||||
state storage. By default, Terraform persists its state only to a local
|
||||
disk. When remote state storage is enabled, Terraform will automatically
|
||||
fetch the latest state from the remote server when necessary and if any
|
||||
updates are made, the newest state is persisted back to the remote server.
|
||||
The `terraform remote` command is used to configure all aspects of
|
||||
remote state storage. When remote state storage is enabled,
|
||||
Terraform will automatically fetch the latest state from the remote
|
||||
server when necessary and if any updates are made, the newest state
|
||||
is persisted back to the remote server.
|
||||
In this mode, users do not need to durably store the state using version
|
||||
control or shared storaged.
|
||||
|
||||
## Usage
|
||||
|
||||
Usage: `terraform remote [options]`
|
||||
Usage: `terraform remote SUBCOMMAND [options]`
|
||||
|
||||
The `remote` command can be used to enable remote storage, change configuration,
|
||||
or disable the use of remote storage. Terraform supports multiple types
|
||||
of storage backends, specified by using the `-backend` flag. By default,
|
||||
Atlas is assumed to be the storage backend. Each backend expects different,
|
||||
configuration arguments documented below.
|
||||
|
||||
When remote storage is enabled, an existing local state file can be migrated.
|
||||
By default, `remote` will look for the "terraform.tfstate" file, but that
|
||||
can be specified by the `-state` flag. If no state file exists, a blank
|
||||
state will be configured.
|
||||
|
||||
When remote storage is disabled, the existing remote state is migrated
|
||||
to a local file. This defaults to the `-state` path during restore.
|
||||
|
||||
The following backends are supported:
|
||||
|
||||
* Atlas - Stores the state in Atlas. Requires the `-name` and `-access-token` flag.
|
||||
The `-address` flag can optionally be provided.
|
||||
|
||||
* Consul - Stores the state in the KV store at a given path.
|
||||
Requires the `path` flag. The `-address` and `-access-token`
|
||||
flag can optionally be provided. Address is assumed to be the
|
||||
local agent if not provided.
|
||||
|
||||
* HTTP - Stores the state using a simple REST client. State will be fetched
|
||||
via GET, updated via POST, and purged with DELETE. Requires the `-address` flag.
|
||||
|
||||
The command-line flags are all optional. The list of available flags are:
|
||||
|
||||
* `-address=url` - URL of the remote storage server. Required for HTTP backend,
|
||||
optional for Atlas and Consul.
|
||||
|
||||
* `-access-token=token` - Authentication token for state storage server.
|
||||
Required for Atlas backend, optional for Consul.
|
||||
|
||||
* `-backend=Atlas` - Specifies the type of remote backend. Must be one
|
||||
of Atlas, Consul, or HTTP. Defaults to Atlas.
|
||||
|
||||
* `-backup=path` - Path to backup the existing state file before
|
||||
modifying. Defaults to the "-state" path with ".backup" extension.
|
||||
Set to "-" to disable backup.
|
||||
|
||||
* `-disable` - Disables remote state management and migrates the state
|
||||
to the `-state` path.
|
||||
|
||||
* `-name=name` - Name of the state file in the state storage server.
|
||||
Required for Atlas backend.
|
||||
|
||||
* `-path=path` - Path of the remote state in Consul. Required for the
|
||||
Consul backend.
|
||||
|
||||
* `-pull=true` - Controls if the remote state is pulled before disabling.
|
||||
This defaults to true to ensure the latest state is cached before disabling.
|
||||
|
||||
* `-state=path` - Path to read state. Defaults to "terraform.tfstate"
|
||||
unless remote state is enabled.
|
||||
The `remote` command behaves as another command that further has more
|
||||
subcommands. The subcommands available are:
|
||||
|
||||
* [config](/docs/commands/remote-config.html) - Configure the remote storage,
|
||||
including enabling/disabling it.
|
||||
* [pull](/docs/commands/remote-pull.html) - Sync the remote storage to
|
||||
the local storage (download).
|
||||
* [push](/docs/commands/remote-push.html) - Sync the local storage to
|
||||
remote storage (upload).
|
||||
|
|
|
@ -79,14 +79,6 @@
|
|||
<a href="/docs/commands/plan.html">plan</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-commands-pull") %>>
|
||||
<a href="/docs/commands/pull.html">pull</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-commands-push") %>>
|
||||
<a href="/docs/commands/push.html">push</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-commands-refresh") %>>
|
||||
<a href="/docs/commands/refresh.html">refresh</a>
|
||||
</li>
|
||||
|
|
Loading…
Reference in New Issue