command/taint: -allow-missing

This commit is contained in:
Mitchell Hashimoto 2015-02-26 10:56:45 -08:00
parent d43c88f5f3
commit d411e2939f
3 changed files with 108 additions and 5 deletions

View File

@ -15,8 +15,10 @@ type TaintCommand struct {
func (c *TaintCommand) Run(args []string) int {
args = c.Meta.process(args, false)
var allowMissing bool
var module string
cmdFlags := c.Meta.flagSet("taint")
cmdFlags.BoolVar(&allowMissing, "allow-missing", false, "module")
cmdFlags.StringVar(&module, "module", "", "module")
cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "path")
cmdFlags.StringVar(&c.Meta.stateOutPath, "state-out", "", "path")
@ -33,7 +35,13 @@ func (c *TaintCommand) Run(args []string) int {
cmdFlags.Usage()
return 1
}
name := args[0]
if module == "" {
module = "root"
} else {
module = "root." + module
}
// Get the state that we'll be modifying
state, err := c.State()
@ -45,6 +53,10 @@ func (c *TaintCommand) Run(args []string) int {
// Get the actual state structure
s := state.State()
if s.Empty() {
if allowMissing {
return c.allowMissingExit(name, module)
}
c.Ui.Error(fmt.Sprintf(
"The state is empty. The most common reason for this is that\n" +
"an invalid state file path was given or Terraform has never\n " +
@ -54,14 +66,13 @@ func (c *TaintCommand) Run(args []string) int {
}
// Get the proper module we want to taint
if module == "" {
module = "root"
} else {
module = "root." + module
}
modPath := strings.Split(module, ".")
mod := s.ModuleByPath(modPath)
if mod == nil {
if allowMissing {
return c.allowMissingExit(name, module)
}
c.Ui.Error(fmt.Sprintf(
"The module %s could not be found. There is nothing to taint.",
module))
@ -70,6 +81,10 @@ func (c *TaintCommand) Run(args []string) int {
// If there are no resources in this module, it is an error
if len(mod.Resources) == 0 {
if allowMissing {
return c.allowMissingExit(name, module)
}
c.Ui.Error(fmt.Sprintf(
"The module %s has no resources. There is nothing to taint.",
module))
@ -79,6 +94,10 @@ func (c *TaintCommand) Run(args []string) int {
// Get the resource we're looking for
rs, ok := mod.Resources[name]
if !ok {
if allowMissing {
return c.allowMissingExit(name, module)
}
c.Ui.Error(fmt.Sprintf(
"The resource %s couldn't be found in the module %s.",
name,
@ -116,6 +135,9 @@ Usage: terraform taint [options] name
Options:
-allow-missing If specified, the command will succeed (exit code 0)
even if the resource is missing.
-backup=path Path to backup the existing state file before
modifying. Defaults to the "-state-out" path with
".backup" extension. Set to "-" to disable backup.
@ -139,3 +161,11 @@ Options:
func (c *TaintCommand) Synopsis() string {
return "Manually mark a resource for recreation"
}
func (c *TaintCommand) allowMissingExit(name, module string) int {
c.Ui.Output(fmt.Sprintf(
"The resource %s in the module %s was not found, but\n"+
"-allow-missing is set, so we're exiting successfully.",
name, module))
return 0
}

View File

@ -187,6 +187,75 @@ func TestTaint_defaultState(t *testing.T) {
testStateOutput(t, path, testTaintStr)
}
func TestTaint_missing(t *testing.T) {
state := &terraform.State{
Modules: []*terraform.ModuleState{
&terraform.ModuleState{
Path: []string{"root"},
Resources: map[string]*terraform.ResourceState{
"test_instance.foo": &terraform.ResourceState{
Type: "test_instance",
Primary: &terraform.InstanceState{
ID: "bar",
},
},
},
},
},
}
statePath := testStateFile(t, state)
ui := new(cli.MockUi)
c := &TaintCommand{
Meta: Meta{
Ui: ui,
},
}
args := []string{
"-state", statePath,
"test_instance.bar",
}
if code := c.Run(args); code == 0 {
t.Fatalf("bad: %d\n\n%s", code, ui.OutputWriter.String())
}
}
func TestTaint_missingAllow(t *testing.T) {
state := &terraform.State{
Modules: []*terraform.ModuleState{
&terraform.ModuleState{
Path: []string{"root"},
Resources: map[string]*terraform.ResourceState{
"test_instance.foo": &terraform.ResourceState{
Type: "test_instance",
Primary: &terraform.InstanceState{
ID: "bar",
},
},
},
},
},
}
statePath := testStateFile(t, state)
ui := new(cli.MockUi)
c := &TaintCommand{
Meta: Meta{
Ui: ui,
},
}
args := []string{
"-allow-missing",
"-state", statePath,
"test_instance.bar",
}
if code := c.Run(args); code != 0 {
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
}
}
func TestTaint_stateOut(t *testing.T) {
// Get a temp cwd
tmp, cwd := testCwd(t)

View File

@ -40,6 +40,10 @@ The format of this argument is `TYPE.NAME`, such as `aws_instance.foo`.
The command-line flags are all optional. The list of available flags are:
* `-allow-missing` - If specified, the command will succeed (exit code 0)
even if the resource is missing. The command can still error, but only
in critically erroneous cases.
* `-backup=path` - Path to the backup file. Defaults to `-state-out` with
the ".backup" extension. Disabled by setting to "-".