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