github.com/ricardclau/terraform@v0.6.17-0.20160519222547-283e3ae6b5a9/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 }