mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-20 11:48:24 -06:00
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.
230 lines
4.7 KiB
Go
230 lines
4.7 KiB
Go
package command
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/terraform/terraform"
|
|
"github.com/mitchellh/cli"
|
|
)
|
|
|
|
func TestStateRm(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,
|
|
"test_instance.foo",
|
|
}
|
|
if code := c.Run(args); code != 0 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
// Test it is correct
|
|
testStateOutput(t, statePath, testStateRmOutput)
|
|
|
|
// Test we have backups
|
|
backups := testStateBackups(t, filepath.Dir(statePath))
|
|
if len(backups) != 1 {
|
|
t.Fatalf("bad: %#v", backups)
|
|
}
|
|
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) {
|
|
td := tempDir(t)
|
|
defer os.RemoveAll(td)
|
|
backupPath := filepath.Join(td, "backup")
|
|
|
|
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{
|
|
"-backup", backupPath,
|
|
"-state", statePath,
|
|
"test_instance.foo",
|
|
}
|
|
if code := c.Run(args); code != 0 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
// Test it is correct
|
|
testStateOutput(t, statePath, testStateRmOutput)
|
|
|
|
// Test backup
|
|
testStateOutput(t, backupPath, testStateRmOutputOriginal)
|
|
}
|
|
|
|
func TestStateRm_noState(t *testing.T) {
|
|
tmp, cwd := testCwd(t)
|
|
defer testFixCwd(t, tmp, cwd)
|
|
|
|
p := testProvider()
|
|
ui := new(cli.MockUi)
|
|
c := &StateRmCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(p),
|
|
Ui: ui,
|
|
},
|
|
}
|
|
|
|
args := []string{}
|
|
if code := c.Run(args); code != 1 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
}
|
|
|
|
const testStateRmOutputOriginal = `
|
|
test_instance.bar:
|
|
ID = foo
|
|
bar = value
|
|
foo = value
|
|
test_instance.foo:
|
|
ID = bar
|
|
bar = value
|
|
foo = value
|
|
`
|
|
|
|
const testStateRmOutput = `
|
|
test_instance.bar:
|
|
ID = foo
|
|
bar = value
|
|
foo = value
|
|
`
|