github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/command/state_rm_test.go (about) 1 package command 2 3 import ( 4 "os" 5 "path/filepath" 6 "strings" 7 "testing" 8 9 "github.com/mitchellh/cli" 10 11 "github.com/hashicorp/terraform/addrs" 12 "github.com/hashicorp/terraform/helper/copy" 13 "github.com/hashicorp/terraform/states" 14 ) 15 16 func TestStateRm(t *testing.T) { 17 state := states.BuildState(func(s *states.SyncState) { 18 s.SetResourceInstanceCurrent( 19 addrs.Resource{ 20 Mode: addrs.ManagedResourceMode, 21 Type: "test_instance", 22 Name: "foo", 23 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 24 &states.ResourceInstanceObjectSrc{ 25 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 26 Status: states.ObjectReady, 27 }, 28 addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), 29 ) 30 s.SetResourceInstanceCurrent( 31 addrs.Resource{ 32 Mode: addrs.ManagedResourceMode, 33 Type: "test_instance", 34 Name: "bar", 35 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 36 &states.ResourceInstanceObjectSrc{ 37 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 38 Status: states.ObjectReady, 39 }, 40 addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), 41 ) 42 }) 43 statePath := testStateFile(t, state) 44 45 p := testProvider() 46 ui := new(cli.MockUi) 47 c := &StateRmCommand{ 48 StateMeta{ 49 Meta: Meta{ 50 testingOverrides: metaOverridesForProvider(p), 51 Ui: ui, 52 }, 53 }, 54 } 55 56 args := []string{ 57 "-state", statePath, 58 "test_instance.foo", 59 } 60 if code := c.Run(args); code != 0 { 61 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 62 } 63 64 // Test it is correct 65 testStateOutput(t, statePath, testStateRmOutput) 66 67 // Test we have backups 68 backups := testStateBackups(t, filepath.Dir(statePath)) 69 if len(backups) != 1 { 70 t.Fatalf("bad: %#v", backups) 71 } 72 testStateOutput(t, backups[0], testStateRmOutputOriginal) 73 } 74 75 func TestStateRmNotChildModule(t *testing.T) { 76 state := states.BuildState(func(s *states.SyncState) { 77 s.SetResourceInstanceCurrent( 78 addrs.Resource{ 79 Mode: addrs.ManagedResourceMode, 80 Type: "test_instance", 81 Name: "foo", 82 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 83 &states.ResourceInstanceObjectSrc{ 84 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 85 Status: states.ObjectReady, 86 }, 87 addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), 88 ) 89 // This second instance has the same local address as the first but 90 // is in a child module. Older versions of Terraform would incorrectly 91 // remove this one too, since they failed to check the module address. 92 s.SetResourceInstanceCurrent( 93 addrs.Resource{ 94 Mode: addrs.ManagedResourceMode, 95 Type: "test_instance", 96 Name: "foo", 97 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("child", addrs.NoKey)), 98 &states.ResourceInstanceObjectSrc{ 99 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 100 Status: states.ObjectReady, 101 }, 102 addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), 103 ) 104 }) 105 statePath := testStateFile(t, state) 106 107 p := testProvider() 108 ui := new(cli.MockUi) 109 c := &StateRmCommand{ 110 StateMeta{ 111 Meta: Meta{ 112 testingOverrides: metaOverridesForProvider(p), 113 Ui: ui, 114 }, 115 }, 116 } 117 118 args := []string{ 119 "-state", statePath, 120 "test_instance.foo", 121 } 122 if code := c.Run(args); code != 0 { 123 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 124 } 125 126 // Test it is correct 127 testStateOutput(t, statePath, ` 128 <no state> 129 module.child: 130 test_instance.foo: 131 ID = foo 132 provider = provider.test 133 bar = value 134 foo = value 135 `) 136 137 // Test we have backups 138 backups := testStateBackups(t, filepath.Dir(statePath)) 139 if len(backups) != 1 { 140 t.Fatalf("bad: %#v", backups) 141 } 142 testStateOutput(t, backups[0], ` 143 test_instance.foo: 144 ID = bar 145 provider = provider.test 146 bar = value 147 foo = value 148 149 module.child: 150 test_instance.foo: 151 ID = foo 152 provider = provider.test 153 bar = value 154 foo = value 155 `) 156 } 157 158 func TestStateRmNoArgs(t *testing.T) { 159 state := states.BuildState(func(s *states.SyncState) { 160 s.SetResourceInstanceCurrent( 161 addrs.Resource{ 162 Mode: addrs.ManagedResourceMode, 163 Type: "test_instance", 164 Name: "foo", 165 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 166 &states.ResourceInstanceObjectSrc{ 167 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 168 Status: states.ObjectReady, 169 }, 170 addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), 171 ) 172 s.SetResourceInstanceCurrent( 173 addrs.Resource{ 174 Mode: addrs.ManagedResourceMode, 175 Type: "test_instance", 176 Name: "bar", 177 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 178 &states.ResourceInstanceObjectSrc{ 179 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 180 Status: states.ObjectReady, 181 }, 182 addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), 183 ) 184 }) 185 statePath := testStateFile(t, state) 186 187 p := testProvider() 188 ui := new(cli.MockUi) 189 c := &StateRmCommand{ 190 StateMeta{ 191 Meta: Meta{ 192 testingOverrides: metaOverridesForProvider(p), 193 Ui: ui, 194 }, 195 }, 196 } 197 198 args := []string{ 199 "-state", statePath, 200 } 201 if code := c.Run(args); code == 0 { 202 t.Errorf("expected non-zero exit code, got: %d", code) 203 } 204 205 if msg := ui.ErrorWriter.String(); !strings.Contains(msg, "At least one address") { 206 t.Errorf("not the error we were looking for:\n%s", msg) 207 } 208 209 } 210 211 func TestStateRmNonExist(t *testing.T) { 212 state := states.BuildState(func(s *states.SyncState) { 213 s.SetResourceInstanceCurrent( 214 addrs.Resource{ 215 Mode: addrs.ManagedResourceMode, 216 Type: "test_instance", 217 Name: "foo", 218 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 219 &states.ResourceInstanceObjectSrc{ 220 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 221 Status: states.ObjectReady, 222 }, 223 addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), 224 ) 225 s.SetResourceInstanceCurrent( 226 addrs.Resource{ 227 Mode: addrs.ManagedResourceMode, 228 Type: "test_instance", 229 Name: "bar", 230 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 231 &states.ResourceInstanceObjectSrc{ 232 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 233 Status: states.ObjectReady, 234 }, 235 addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), 236 ) 237 }) 238 statePath := testStateFile(t, state) 239 240 p := testProvider() 241 ui := new(cli.MockUi) 242 c := &StateRmCommand{ 243 StateMeta{ 244 Meta: Meta{ 245 testingOverrides: metaOverridesForProvider(p), 246 Ui: ui, 247 }, 248 }, 249 } 250 251 args := []string{ 252 "-state", statePath, 253 "test_instance.baz", // doesn't exist in the state constructed above 254 } 255 if code := c.Run(args); code != 0 { 256 t.Fatalf("expected exit status %d, got: %d", 0, code) 257 } 258 259 if msg := ui.OutputWriter.String(); !strings.Contains(msg, "No matching resource instances found") { 260 t.Fatalf("unexpected output:\n%s", msg) 261 } 262 263 } 264 265 func TestStateRm_backupExplicit(t *testing.T) { 266 state := states.BuildState(func(s *states.SyncState) { 267 s.SetResourceInstanceCurrent( 268 addrs.Resource{ 269 Mode: addrs.ManagedResourceMode, 270 Type: "test_instance", 271 Name: "foo", 272 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 273 &states.ResourceInstanceObjectSrc{ 274 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 275 Status: states.ObjectReady, 276 }, 277 addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), 278 ) 279 s.SetResourceInstanceCurrent( 280 addrs.Resource{ 281 Mode: addrs.ManagedResourceMode, 282 Type: "test_instance", 283 Name: "bar", 284 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 285 &states.ResourceInstanceObjectSrc{ 286 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 287 Status: states.ObjectReady, 288 }, 289 addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), 290 ) 291 }) 292 statePath := testStateFile(t, state) 293 backupPath := statePath + ".backup.test" 294 295 p := testProvider() 296 ui := new(cli.MockUi) 297 c := &StateRmCommand{ 298 StateMeta{ 299 Meta: Meta{ 300 testingOverrides: metaOverridesForProvider(p), 301 Ui: ui, 302 }, 303 }, 304 } 305 306 args := []string{ 307 "-backup", backupPath, 308 "-state", statePath, 309 "test_instance.foo", 310 } 311 if code := c.Run(args); code != 0 { 312 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 313 } 314 315 // Test it is correct 316 testStateOutput(t, statePath, testStateRmOutput) 317 318 // Test backup 319 testStateOutput(t, backupPath, testStateRmOutputOriginal) 320 } 321 322 func TestStateRm_noState(t *testing.T) { 323 tmp, cwd := testCwd(t) 324 defer testFixCwd(t, tmp, cwd) 325 326 p := testProvider() 327 ui := new(cli.MockUi) 328 c := &StateRmCommand{ 329 StateMeta{ 330 Meta: Meta{ 331 testingOverrides: metaOverridesForProvider(p), 332 Ui: ui, 333 }, 334 }, 335 } 336 337 args := []string{"foo"} 338 if code := c.Run(args); code != 1 { 339 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 340 } 341 } 342 343 func TestStateRm_needsInit(t *testing.T) { 344 td := tempDir(t) 345 copy.CopyDir(testFixturePath("backend-change"), td) 346 defer os.RemoveAll(td) 347 defer testChdir(t, td)() 348 349 p := testProvider() 350 ui := new(cli.MockUi) 351 c := &StateRmCommand{ 352 StateMeta{ 353 Meta: Meta{ 354 testingOverrides: metaOverridesForProvider(p), 355 Ui: ui, 356 }, 357 }, 358 } 359 360 args := []string{"foo"} 361 if code := c.Run(args); code == 0 { 362 t.Fatalf("expected error output, got:\n%s", ui.OutputWriter.String()) 363 } 364 365 if !strings.Contains(ui.ErrorWriter.String(), "Initialization") { 366 t.Fatalf("expected initialization error, got:\n%s", ui.ErrorWriter.String()) 367 } 368 } 369 370 func TestStateRm_backendState(t *testing.T) { 371 td := tempDir(t) 372 copy.CopyDir(testFixturePath("backend-unchanged"), td) 373 defer os.RemoveAll(td) 374 defer testChdir(t, td)() 375 376 state := states.BuildState(func(s *states.SyncState) { 377 s.SetResourceInstanceCurrent( 378 addrs.Resource{ 379 Mode: addrs.ManagedResourceMode, 380 Type: "test_instance", 381 Name: "foo", 382 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 383 &states.ResourceInstanceObjectSrc{ 384 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 385 Status: states.ObjectReady, 386 }, 387 addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), 388 ) 389 s.SetResourceInstanceCurrent( 390 addrs.Resource{ 391 Mode: addrs.ManagedResourceMode, 392 Type: "test_instance", 393 Name: "bar", 394 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 395 &states.ResourceInstanceObjectSrc{ 396 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 397 Status: states.ObjectReady, 398 }, 399 addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), 400 ) 401 }) 402 403 statePath := "local-state.tfstate" 404 backupPath := "local-state.backup" 405 406 f, err := os.Create(statePath) 407 if err != nil { 408 t.Fatalf("failed to create state file %s: %s", statePath, err) 409 } 410 defer f.Close() 411 412 err = writeStateForTesting(state, f) 413 if err != nil { 414 t.Fatalf("failed to write state to file %s: %s", statePath, err) 415 } 416 417 p := testProvider() 418 ui := new(cli.MockUi) 419 c := &StateRmCommand{ 420 StateMeta{ 421 Meta: Meta{ 422 testingOverrides: metaOverridesForProvider(p), 423 Ui: ui, 424 }, 425 }, 426 } 427 428 args := []string{ 429 "-backup", backupPath, 430 "test_instance.foo", 431 } 432 if code := c.Run(args); code != 0 { 433 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 434 } 435 436 // Test it is correct 437 testStateOutput(t, statePath, testStateRmOutput) 438 439 // Test backup 440 testStateOutput(t, backupPath, testStateRmOutputOriginal) 441 } 442 443 const testStateRmOutputOriginal = ` 444 test_instance.bar: 445 ID = foo 446 provider = provider.test 447 bar = value 448 foo = value 449 test_instance.foo: 450 ID = bar 451 provider = provider.test 452 bar = value 453 foo = value 454 ` 455 456 const testStateRmOutput = ` 457 test_instance.bar: 458 ID = foo 459 provider = provider.test 460 bar = value 461 foo = value 462 `