github.com/nevins-b/terraform@v0.3.8-0.20170215184714-bbae22007d5a/command/unlock.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/hashicorp/terraform/state" 8 "github.com/hashicorp/terraform/terraform" 9 ) 10 11 // UnlockCommand is a cli.Command implementation that manually unlocks 12 // the state. 13 type UnlockCommand struct { 14 Meta 15 } 16 17 func (c *UnlockCommand) Run(args []string) int { 18 args = c.Meta.process(args, false) 19 20 force := false 21 cmdFlags := c.Meta.flagSet("force-unlock") 22 cmdFlags.BoolVar(&force, "force", false, "force") 23 cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } 24 if err := cmdFlags.Parse(args); err != nil { 25 return 1 26 } 27 28 // assume everything is initialized. The user can manually init if this is 29 // required. 30 configPath, err := ModulePath(cmdFlags.Args()) 31 if err != nil { 32 c.Ui.Error(err.Error()) 33 return 1 34 } 35 36 // Load the backend 37 b, err := c.Backend(&BackendOpts{ 38 ConfigPath: configPath, 39 }) 40 if err != nil { 41 c.Ui.Error(fmt.Sprintf("Failed to load backend: %s", err)) 42 return 1 43 } 44 45 st, err := b.State() 46 if err != nil { 47 c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err)) 48 return 1 49 } 50 51 s, ok := st.(state.Locker) 52 if !ok { 53 c.Ui.Error("The remote state backend in use does not support locking, and therefor\n" + 54 "cannot be unlocked.") 55 return 1 56 } 57 58 isLocal := false 59 switch s := st.(type) { 60 case *state.BackupState: 61 if _, ok := s.Real.(*state.LocalState); ok { 62 isLocal = true 63 } 64 case *state.LocalState: 65 isLocal = true 66 } 67 68 if !force { 69 // Forcing this doesn't do anything, but doesn't break anything either, 70 // and allows us to run the basic command test too. 71 if isLocal { 72 c.Ui.Error("Local state cannot be unlocked by another process") 73 return 1 74 } 75 76 desc := "Terraform will remove the lock on the remote state.\n" + 77 "This will allow local Terraform commands to modify this state, even though it\n" + 78 "may be still be in use. Only 'yes' will be accepted to confirm." 79 80 v, err := c.UIInput().Input(&terraform.InputOpts{ 81 Id: "force-unlock", 82 Query: "Do you really want to force-unlock?", 83 Description: desc, 84 }) 85 if err != nil { 86 c.Ui.Error(fmt.Sprintf("Error asking for confirmation: %s", err)) 87 return 1 88 } 89 if v != "yes" { 90 c.Ui.Output("force-unlock cancelled.") 91 return 1 92 } 93 } 94 95 if err := s.Unlock(); err != nil { 96 c.Ui.Error(fmt.Sprintf("Failed to unlock state: %s", err)) 97 return 1 98 } 99 100 c.Ui.Output(c.Colorize().Color(strings.TrimSpace(outputUnlockSuccess))) 101 return 0 102 } 103 104 func (c *UnlockCommand) Help() string { 105 helpText := ` 106 Usage: terraform force-unlock [DIR] 107 108 Manually unlock the state for the defined configuration. 109 110 This will not modify your infrastructure. This command removes the lock on the 111 state for the current configuration. The behavior of this lock is dependent 112 on the backend being used. Local state files cannot be unlocked by another 113 process. 114 115 Options: 116 117 -force Don't ask for input for unlock confirmation. 118 ` 119 return strings.TrimSpace(helpText) 120 } 121 122 func (c *UnlockCommand) Synopsis() string { 123 return "Manually unlock the terraform state" 124 } 125 126 const outputUnlockSuccess = ` 127 [reset][bold][green]Terraform state has been successfully unlocked![reset][green] 128 129 The state has been unlocked, and Terraform commands should now be able to 130 obtain a new lock on the remote state. 131 `