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