github.com/ggriffiths/terraform@v0.9.0-beta1.0.20170222213024-79c4935604cb/command/state_push.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "os" 6 "strings" 7 8 "github.com/hashicorp/terraform/terraform" 9 "github.com/mitchellh/cli" 10 ) 11 12 // StatePushCommand is a Command implementation that shows a single resource. 13 type StatePushCommand struct { 14 Meta 15 StateMeta 16 } 17 18 func (c *StatePushCommand) Run(args []string) int { 19 args = c.Meta.process(args, true) 20 21 var flagForce bool 22 cmdFlags := c.Meta.flagSet("state push") 23 cmdFlags.BoolVar(&flagForce, "force", false, "") 24 if err := cmdFlags.Parse(args); err != nil { 25 return cli.RunResultHelp 26 } 27 args = cmdFlags.Args() 28 29 if len(args) != 1 { 30 c.Ui.Error("Exactly one argument expected: path to state to push") 31 return 1 32 } 33 34 // Read the state 35 f, err := os.Open(args[0]) 36 if err != nil { 37 c.Ui.Error(err.Error()) 38 return 1 39 } 40 sourceState, err := terraform.ReadState(f) 41 f.Close() 42 if err != nil { 43 c.Ui.Error(fmt.Sprintf("Error reading source state %q: %s", args[0], err)) 44 return 1 45 } 46 47 // Load the backend 48 b, err := c.Backend(nil) 49 if err != nil { 50 c.Ui.Error(fmt.Sprintf("Failed to load backend: %s", err)) 51 return 1 52 } 53 54 // Get the state 55 state, err := b.State() 56 if err != nil { 57 c.Ui.Error(fmt.Sprintf("Failed to load destination state: %s", err)) 58 return 1 59 } 60 if err := state.RefreshState(); err != nil { 61 c.Ui.Error(fmt.Sprintf("Failed to load destination state: %s", err)) 62 return 1 63 } 64 dstState := state.State() 65 66 // If we're not forcing, then perform safety checks 67 if !flagForce && !dstState.Empty() { 68 if !dstState.SameLineage(sourceState) { 69 c.Ui.Error(strings.TrimSpace(errStatePushLineage)) 70 return 1 71 } 72 73 age, err := dstState.CompareAges(sourceState) 74 if err != nil { 75 c.Ui.Error(err.Error()) 76 return 1 77 } 78 if age == terraform.StateAgeReceiverNewer { 79 c.Ui.Error(strings.TrimSpace(errStatePushSerialNewer)) 80 return 1 81 } 82 } 83 84 // Overwrite it 85 if err := state.WriteState(sourceState); err != nil { 86 c.Ui.Error(fmt.Sprintf("Failed to write state: %s", err)) 87 return 1 88 } 89 if err := state.PersistState(); err != nil { 90 c.Ui.Error(fmt.Sprintf("Failed to write state: %s", err)) 91 return 1 92 } 93 94 return 0 95 } 96 97 func (c *StatePushCommand) Help() string { 98 helpText := ` 99 Usage: terraform state push [options] PATH 100 101 Update remote state from a local state file at PATH. 102 103 This command "pushes" a local state and overwrites remote state 104 with a local state file. The command will protect you against writing 105 an older serial or a different state file lineage unless you specify the 106 "-force" flag. 107 108 This command works with local state (it will overwrite the local 109 state), but is less useful for this use case. 110 111 Options: 112 113 -force Write the state even if lineages don't match or the 114 remote serial is higher. 115 116 ` 117 return strings.TrimSpace(helpText) 118 } 119 120 func (c *StatePushCommand) Synopsis() string { 121 return "Update remote state from a local state file" 122 } 123 124 const errStatePushLineage = ` 125 The lineages do not match! The state will not be pushed. 126 127 The "lineage" is a unique identifier given to a state on creation. It helps 128 protect Terraform from overwriting a seemingly unrelated state file since it 129 represents potentially losing real state. 130 131 Please verify you're pushing the correct state. If you're sure you are, you 132 can force the behavior with the "-force" flag. 133 ` 134 135 const errStatePushSerialNewer = ` 136 The destination state has a higher serial number! The state will not be pushed. 137 138 A higher serial could indicate that there is data in the destination state 139 that was not present when the source state was created. As a protection measure, 140 Terraform will not automatically overwrite this state. 141 142 Please verify you're pushing the correct state. If you're sure you are, you 143 can force the behavior with the "-force" flag. 144 `