github.com/xsb/terraform@v0.6.13-0.20160314145438-fe415c2f09d7/command/untaint.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strings"
     7  )
     8  
     9  // UntaintCommand is a cli.Command implementation that manually untaints
    10  // a resource, marking it as primary and ready for service.
    11  type UntaintCommand struct {
    12  	Meta
    13  }
    14  
    15  func (c *UntaintCommand) Run(args []string) int {
    16  	args = c.Meta.process(args, false)
    17  
    18  	var allowMissing bool
    19  	var module string
    20  	var index int
    21  	cmdFlags := c.Meta.flagSet("untaint")
    22  	cmdFlags.BoolVar(&allowMissing, "allow-missing", false, "module")
    23  	cmdFlags.StringVar(&module, "module", "", "module")
    24  	cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "path")
    25  	cmdFlags.StringVar(&c.Meta.stateOutPath, "state-out", "", "path")
    26  	cmdFlags.StringVar(&c.Meta.backupPath, "backup", "", "path")
    27  	cmdFlags.IntVar(&index, "index", -1, "index")
    28  	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
    29  	if err := cmdFlags.Parse(args); err != nil {
    30  		return 1
    31  	}
    32  
    33  	// Require the one argument for the resource to untaint
    34  	args = cmdFlags.Args()
    35  	if len(args) != 1 {
    36  		c.Ui.Error("The untaint command expects exactly one argument.")
    37  		cmdFlags.Usage()
    38  		return 1
    39  	}
    40  
    41  	name := args[0]
    42  	if module == "" {
    43  		module = "root"
    44  	} else {
    45  		module = "root." + module
    46  	}
    47  
    48  	// Get the state that we'll be modifying
    49  	state, err := c.State()
    50  	if err != nil {
    51  		c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
    52  		return 1
    53  	}
    54  
    55  	// Get the actual state structure
    56  	s := state.State()
    57  	if s.Empty() {
    58  		if allowMissing {
    59  			return c.allowMissingExit(name, module)
    60  		}
    61  
    62  		c.Ui.Error(fmt.Sprintf(
    63  			"The state is empty. The most common reason for this is that\n" +
    64  				"an invalid state file path was given or Terraform has never\n " +
    65  				"been run for this infrastructure. Infrastructure must exist\n" +
    66  				"for it to be untainted."))
    67  		return 1
    68  	}
    69  
    70  	// Get the proper module holding the resource we want to untaint
    71  	modPath := strings.Split(module, ".")
    72  	mod := s.ModuleByPath(modPath)
    73  	if mod == nil {
    74  		if allowMissing {
    75  			return c.allowMissingExit(name, module)
    76  		}
    77  
    78  		c.Ui.Error(fmt.Sprintf(
    79  			"The module %s could not be found. There is nothing to untaint.",
    80  			module))
    81  		return 1
    82  	}
    83  
    84  	// If there are no resources in this module, it is an error
    85  	if len(mod.Resources) == 0 {
    86  		if allowMissing {
    87  			return c.allowMissingExit(name, module)
    88  		}
    89  
    90  		c.Ui.Error(fmt.Sprintf(
    91  			"The module %s has no resources. There is nothing to untaint.",
    92  			module))
    93  		return 1
    94  	}
    95  
    96  	// Get the resource we're looking for
    97  	rs, ok := mod.Resources[name]
    98  	if !ok {
    99  		if allowMissing {
   100  			return c.allowMissingExit(name, module)
   101  		}
   102  
   103  		c.Ui.Error(fmt.Sprintf(
   104  			"The resource %s couldn't be found in the module %s.",
   105  			name,
   106  			module))
   107  		return 1
   108  	}
   109  
   110  	// Untaint the resource
   111  	if err := rs.Untaint(index); err != nil {
   112  		c.Ui.Error(fmt.Sprintf("Error untainting %s: %s", name, err))
   113  		c.Ui.Error("You can use `terraform show` to inspect the current state.")
   114  		return 1
   115  	}
   116  
   117  	log.Printf("[INFO] Writing state output to: %s", c.Meta.StateOutPath())
   118  	if err := c.Meta.PersistState(s); err != nil {
   119  		c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
   120  		return 1
   121  	}
   122  
   123  	c.Ui.Output(fmt.Sprintf(
   124  		"The resource %s in the module %s has been successfully untainted!",
   125  		name, module))
   126  	return 0
   127  }
   128  
   129  func (c *UntaintCommand) Help() string {
   130  	helpText := `
   131  Usage: terraform untaint [options] name
   132  
   133    Manually unmark a resource as tainted, restoring it as the primary
   134    instance in the state.  This reverses either a manual 'terraform taint'
   135    or the result of provisioners failing on a resource.
   136  
   137    This will not modify your infrastructure. This command changes your
   138    state to unmark a resource as tainted.  This command can be undone by
   139    reverting the state backup file that is created, or by running
   140    'terraform taint' on the resource.
   141  
   142  Options:
   143  
   144    -allow-missing      If specified, the command will succeed (exit code 0)
   145                        even if the resource is missing.
   146  
   147    -backup=path        Path to backup the existing state file before
   148                        modifying. Defaults to the "-state-out" path with
   149                        ".backup" extension. Set to "-" to disable backup.
   150  
   151    -index=n            Selects a single tainted instance when there are more
   152                        than one tainted instances present in the state for a
   153                        given resource. This flag is required when multiple
   154                        tainted instances are present. The vast majority of the
   155                        time, there is a maxiumum of one tainted instance per
   156                        resource, so this flag can be safely omitted.
   157  
   158    -module=path        The module path where the resource lives. By
   159                        default this will be root. Child modules can be specified
   160                        by names. Ex. "consul" or "consul.vpc" (nested modules).
   161  
   162    -no-color           If specified, output won't contain any color.
   163  
   164    -state=path         Path to read and save state (unless state-out
   165                        is specified). Defaults to "terraform.tfstate".
   166  
   167    -state-out=path     Path to write updated state file. By default, the
   168                        "-state" path will be used.
   169  
   170  `
   171  	return strings.TrimSpace(helpText)
   172  }
   173  
   174  func (c *UntaintCommand) Synopsis() string {
   175  	return "Manually unmark a resource as tainted"
   176  }
   177  
   178  func (c *UntaintCommand) allowMissingExit(name, module string) int {
   179  	c.Ui.Output(fmt.Sprintf(
   180  		"The resource %s in the module %s was not found, but\n"+
   181  			"-allow-missing is set, so we're exiting successfully.",
   182  		name, module))
   183  	return 0
   184  }