command: terraform state rm to require at least one argument
Due to how the state filter machinery works, passing no arguments is valid and matches _all_ resources. It is very unlikely that someone wants to remove everything from state, so this ends up being a very dangerous default for the "terraform state rm" command, and surprising for someone who perhaps runs it looking for the usage information. So we'll be pragmatic here and reject the no-arguments case for this command, accepting that it makes the unlikely case of intentionally deleting all resources harder in order to make it less likely that it will happen _unintentionally_. If someone does really want to remove all resources from the state, they can provide an explicit empty string argument, but this isn't documented because it's a weird case that doesn't seem worth mentioning. This fixes #15283.
This commit is contained in:
parent
d5ebad33a4
commit
fee1197cf9
|
@ -24,6 +24,11 @@ func (c *StateRmCommand) Run(args []string) int {
|
||||||
}
|
}
|
||||||
args = cmdFlags.Args()
|
args = cmdFlags.Args()
|
||||||
|
|
||||||
|
if len(args) < 1 {
|
||||||
|
c.Ui.Error("At least one resource address is required.")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
state, err := c.StateMeta.State(&c.Meta)
|
state, err := c.StateMeta.State(&c.Meta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf(errStateLoadingState, err))
|
c.Ui.Error(fmt.Sprintf(errStateLoadingState, err))
|
||||||
|
|
|
@ -3,6 +3,7 @@ package command
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
@ -71,6 +72,62 @@ func TestStateRm(t *testing.T) {
|
||||||
testStateOutput(t, backups[0], testStateRmOutputOriginal)
|
testStateOutput(t, backups[0], testStateRmOutputOriginal)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStateRmNoArgs(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",
|
||||||
|
Attributes: map[string]string{
|
||||||
|
"foo": "value",
|
||||||
|
"bar": "value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"test_instance.bar": &terraform.ResourceState{
|
||||||
|
Type: "test_instance",
|
||||||
|
Primary: &terraform.InstanceState{
|
||||||
|
ID: "foo",
|
||||||
|
Attributes: map[string]string{
|
||||||
|
"foo": "value",
|
||||||
|
"bar": "value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
statePath := testStateFile(t, state)
|
||||||
|
|
||||||
|
p := testProvider()
|
||||||
|
ui := new(cli.MockUi)
|
||||||
|
c := &StateRmCommand{
|
||||||
|
Meta: Meta{
|
||||||
|
testingOverrides: metaOverridesForProvider(p),
|
||||||
|
Ui: ui,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []string{
|
||||||
|
"-state", statePath,
|
||||||
|
}
|
||||||
|
if code := c.Run(args); code != 1 {
|
||||||
|
t.Errorf("wrong exit status %d; want %d", code, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg := ui.ErrorWriter.String(); !strings.Contains(msg, "At least one resource address") {
|
||||||
|
t.Errorf("not the error we were looking for:\n%s", msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func TestStateRm_backupExplicit(t *testing.T) {
|
func TestStateRm_backupExplicit(t *testing.T) {
|
||||||
td := tempDir(t)
|
td := tempDir(t)
|
||||||
defer os.RemoveAll(td)
|
defer os.RemoveAll(td)
|
||||||
|
|
Loading…
Reference in New Issue