github.com/cycloidio/terraform@v1.1.10-0.20220513142504-76d5c768dc63/command/untaint_test.go (about) 1 package command 2 3 import ( 4 "os" 5 "strings" 6 "testing" 7 8 "github.com/google/go-cmp/cmp" 9 "github.com/cycloidio/terraform/addrs" 10 "github.com/cycloidio/terraform/states" 11 "github.com/mitchellh/cli" 12 ) 13 14 func TestUntaint(t *testing.T) { 15 state := states.BuildState(func(s *states.SyncState) { 16 s.SetResourceInstanceCurrent( 17 addrs.Resource{ 18 Mode: addrs.ManagedResourceMode, 19 Type: "test_instance", 20 Name: "foo", 21 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 22 &states.ResourceInstanceObjectSrc{ 23 AttrsJSON: []byte(`{"id":"bar"}`), 24 Status: states.ObjectTainted, 25 }, 26 addrs.AbsProviderConfig{ 27 Provider: addrs.NewDefaultProvider("test"), 28 Module: addrs.RootModule, 29 }, 30 ) 31 }) 32 statePath := testStateFile(t, state) 33 34 ui := new(cli.MockUi) 35 view, _ := testView(t) 36 c := &UntaintCommand{ 37 Meta: Meta{ 38 Ui: ui, 39 View: view, 40 }, 41 } 42 43 args := []string{ 44 "-state", statePath, 45 "test_instance.foo", 46 } 47 if code := c.Run(args); code != 0 { 48 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 49 } 50 51 expected := strings.TrimSpace(` 52 test_instance.foo: 53 ID = bar 54 provider = provider["registry.terraform.io/hashicorp/test"] 55 `) 56 testStateOutput(t, statePath, expected) 57 } 58 59 func TestUntaint_lockedState(t *testing.T) { 60 state := states.BuildState(func(s *states.SyncState) { 61 s.SetResourceInstanceCurrent( 62 addrs.Resource{ 63 Mode: addrs.ManagedResourceMode, 64 Type: "test_instance", 65 Name: "foo", 66 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 67 &states.ResourceInstanceObjectSrc{ 68 AttrsJSON: []byte(`{"id":"bar"}`), 69 Status: states.ObjectTainted, 70 }, 71 addrs.AbsProviderConfig{ 72 Provider: addrs.NewDefaultProvider("test"), 73 Module: addrs.RootModule, 74 }, 75 ) 76 }) 77 statePath := testStateFile(t, state) 78 unlock, err := testLockState(testDataDir, statePath) 79 if err != nil { 80 t.Fatal(err) 81 } 82 defer unlock() 83 84 ui := new(cli.MockUi) 85 view, _ := testView(t) 86 c := &UntaintCommand{ 87 Meta: Meta{ 88 Ui: ui, 89 View: view, 90 }, 91 } 92 93 args := []string{ 94 "-state", statePath, 95 "test_instance.foo", 96 } 97 if code := c.Run(args); code == 0 { 98 t.Fatal("expected error") 99 } 100 101 output := ui.ErrorWriter.String() 102 if !strings.Contains(output, "lock") { 103 t.Fatal("command output does not look like a lock error:", output) 104 } 105 } 106 107 func TestUntaint_backup(t *testing.T) { 108 // Get a temp cwd 109 tmp, cwd := testCwd(t) 110 defer testFixCwd(t, tmp, cwd) 111 112 // Write the temp state 113 state := states.BuildState(func(s *states.SyncState) { 114 s.SetResourceInstanceCurrent( 115 addrs.Resource{ 116 Mode: addrs.ManagedResourceMode, 117 Type: "test_instance", 118 Name: "foo", 119 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 120 &states.ResourceInstanceObjectSrc{ 121 AttrsJSON: []byte(`{"id":"bar"}`), 122 Status: states.ObjectTainted, 123 }, 124 addrs.AbsProviderConfig{ 125 Provider: addrs.NewDefaultProvider("test"), 126 Module: addrs.RootModule, 127 }, 128 ) 129 }) 130 testStateFileDefault(t, state) 131 132 ui := new(cli.MockUi) 133 view, _ := testView(t) 134 c := &UntaintCommand{ 135 Meta: Meta{ 136 Ui: ui, 137 View: view, 138 }, 139 } 140 141 args := []string{ 142 "test_instance.foo", 143 } 144 if code := c.Run(args); code != 0 { 145 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 146 } 147 148 // Backup is still tainted 149 testStateOutput(t, DefaultStateFilename+".backup", strings.TrimSpace(` 150 test_instance.foo: (tainted) 151 ID = bar 152 provider = provider["registry.terraform.io/hashicorp/test"] 153 `)) 154 155 // State is untainted 156 testStateOutput(t, DefaultStateFilename, strings.TrimSpace(` 157 test_instance.foo: 158 ID = bar 159 provider = provider["registry.terraform.io/hashicorp/test"] 160 `)) 161 } 162 163 func TestUntaint_backupDisable(t *testing.T) { 164 // Get a temp cwd 165 tmp, cwd := testCwd(t) 166 defer testFixCwd(t, tmp, cwd) 167 168 // Write the temp state 169 state := states.BuildState(func(s *states.SyncState) { 170 s.SetResourceInstanceCurrent( 171 addrs.Resource{ 172 Mode: addrs.ManagedResourceMode, 173 Type: "test_instance", 174 Name: "foo", 175 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 176 &states.ResourceInstanceObjectSrc{ 177 AttrsJSON: []byte(`{"id":"bar"}`), 178 Status: states.ObjectTainted, 179 }, 180 addrs.AbsProviderConfig{ 181 Provider: addrs.NewDefaultProvider("test"), 182 Module: addrs.RootModule, 183 }, 184 ) 185 }) 186 testStateFileDefault(t, state) 187 188 ui := new(cli.MockUi) 189 view, _ := testView(t) 190 c := &UntaintCommand{ 191 Meta: Meta{ 192 Ui: ui, 193 View: view, 194 }, 195 } 196 197 args := []string{ 198 "-backup", "-", 199 "test_instance.foo", 200 } 201 if code := c.Run(args); code != 0 { 202 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 203 } 204 205 if _, err := os.Stat(DefaultStateFilename + ".backup"); err == nil { 206 t.Fatal("backup path should not exist") 207 } 208 209 testStateOutput(t, DefaultStateFilename, strings.TrimSpace(` 210 test_instance.foo: 211 ID = bar 212 provider = provider["registry.terraform.io/hashicorp/test"] 213 `)) 214 } 215 216 func TestUntaint_badState(t *testing.T) { 217 ui := new(cli.MockUi) 218 view, _ := testView(t) 219 c := &UntaintCommand{ 220 Meta: Meta{ 221 Ui: ui, 222 View: view, 223 }, 224 } 225 226 args := []string{ 227 "-state", "i-should-not-exist-ever", 228 "foo", 229 } 230 if code := c.Run(args); code != 1 { 231 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 232 } 233 } 234 235 func TestUntaint_defaultState(t *testing.T) { 236 // Get a temp cwd 237 tmp, cwd := testCwd(t) 238 defer testFixCwd(t, tmp, cwd) 239 240 // Write the temp state 241 state := states.BuildState(func(s *states.SyncState) { 242 s.SetResourceInstanceCurrent( 243 addrs.Resource{ 244 Mode: addrs.ManagedResourceMode, 245 Type: "test_instance", 246 Name: "foo", 247 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 248 &states.ResourceInstanceObjectSrc{ 249 AttrsJSON: []byte(`{"id":"bar"}`), 250 Status: states.ObjectTainted, 251 }, 252 addrs.AbsProviderConfig{ 253 Provider: addrs.NewDefaultProvider("test"), 254 Module: addrs.RootModule, 255 }, 256 ) 257 }) 258 testStateFileDefault(t, state) 259 260 ui := new(cli.MockUi) 261 view, _ := testView(t) 262 c := &UntaintCommand{ 263 Meta: Meta{ 264 Ui: ui, 265 View: view, 266 }, 267 } 268 269 args := []string{ 270 "test_instance.foo", 271 } 272 if code := c.Run(args); code != 0 { 273 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 274 } 275 276 testStateOutput(t, DefaultStateFilename, strings.TrimSpace(` 277 test_instance.foo: 278 ID = bar 279 provider = provider["registry.terraform.io/hashicorp/test"] 280 `)) 281 } 282 283 func TestUntaint_defaultWorkspaceState(t *testing.T) { 284 // Get a temp cwd 285 tmp, cwd := testCwd(t) 286 defer testFixCwd(t, tmp, cwd) 287 288 // Write the temp state 289 state := states.BuildState(func(s *states.SyncState) { 290 s.SetResourceInstanceCurrent( 291 addrs.Resource{ 292 Mode: addrs.ManagedResourceMode, 293 Type: "test_instance", 294 Name: "foo", 295 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 296 &states.ResourceInstanceObjectSrc{ 297 AttrsJSON: []byte(`{"id":"bar"}`), 298 Status: states.ObjectTainted, 299 }, 300 addrs.AbsProviderConfig{ 301 Provider: addrs.NewDefaultProvider("test"), 302 Module: addrs.RootModule, 303 }, 304 ) 305 }) 306 testWorkspace := "development" 307 path := testStateFileWorkspaceDefault(t, testWorkspace, state) 308 309 ui := new(cli.MockUi) 310 view, _ := testView(t) 311 meta := Meta{Ui: ui, View: view} 312 meta.SetWorkspace(testWorkspace) 313 c := &UntaintCommand{ 314 Meta: meta, 315 } 316 317 args := []string{ 318 "test_instance.foo", 319 } 320 if code := c.Run(args); code != 0 { 321 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 322 } 323 324 testStateOutput(t, path, strings.TrimSpace(` 325 test_instance.foo: 326 ID = bar 327 provider = provider["registry.terraform.io/hashicorp/test"] 328 `)) 329 } 330 331 func TestUntaint_missing(t *testing.T) { 332 state := states.BuildState(func(s *states.SyncState) { 333 s.SetResourceInstanceCurrent( 334 addrs.Resource{ 335 Mode: addrs.ManagedResourceMode, 336 Type: "test_instance", 337 Name: "foo", 338 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 339 &states.ResourceInstanceObjectSrc{ 340 AttrsJSON: []byte(`{"id":"bar"}`), 341 Status: states.ObjectTainted, 342 }, 343 addrs.AbsProviderConfig{ 344 Provider: addrs.NewDefaultProvider("test"), 345 Module: addrs.RootModule, 346 }, 347 ) 348 }) 349 statePath := testStateFile(t, state) 350 351 ui := new(cli.MockUi) 352 view, _ := testView(t) 353 c := &UntaintCommand{ 354 Meta: Meta{ 355 Ui: ui, 356 View: view, 357 }, 358 } 359 360 args := []string{ 361 "-state", statePath, 362 "test_instance.bar", 363 } 364 if code := c.Run(args); code == 0 { 365 t.Fatalf("bad: %d\n\n%s", code, ui.OutputWriter.String()) 366 } 367 } 368 369 func TestUntaint_missingAllow(t *testing.T) { 370 state := states.BuildState(func(s *states.SyncState) { 371 s.SetResourceInstanceCurrent( 372 addrs.Resource{ 373 Mode: addrs.ManagedResourceMode, 374 Type: "test_instance", 375 Name: "foo", 376 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 377 &states.ResourceInstanceObjectSrc{ 378 AttrsJSON: []byte(`{"id":"bar"}`), 379 Status: states.ObjectTainted, 380 }, 381 addrs.AbsProviderConfig{ 382 Provider: addrs.NewDefaultProvider("test"), 383 Module: addrs.RootModule, 384 }, 385 ) 386 }) 387 statePath := testStateFile(t, state) 388 389 ui := new(cli.MockUi) 390 view, _ := testView(t) 391 c := &UntaintCommand{ 392 Meta: Meta{ 393 Ui: ui, 394 View: view, 395 }, 396 } 397 398 args := []string{ 399 "-allow-missing", 400 "-state", statePath, 401 "test_instance.bar", 402 } 403 if code := c.Run(args); code != 0 { 404 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 405 } 406 407 // Check for the warning 408 actual := strings.TrimSpace(ui.ErrorWriter.String()) 409 expected := strings.TrimSpace(` 410 Warning: No such resource instance 411 412 Resource instance test_instance.bar was not found, but this is not an error 413 because -allow-missing was set. 414 415 `) 416 if diff := cmp.Diff(expected, actual); diff != "" { 417 t.Fatalf("wrong output\n%s", diff) 418 } 419 } 420 421 func TestUntaint_stateOut(t *testing.T) { 422 // Get a temp cwd 423 tmp, cwd := testCwd(t) 424 defer testFixCwd(t, tmp, cwd) 425 426 // Write the temp state 427 state := states.BuildState(func(s *states.SyncState) { 428 s.SetResourceInstanceCurrent( 429 addrs.Resource{ 430 Mode: addrs.ManagedResourceMode, 431 Type: "test_instance", 432 Name: "foo", 433 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 434 &states.ResourceInstanceObjectSrc{ 435 AttrsJSON: []byte(`{"id":"bar"}`), 436 Status: states.ObjectTainted, 437 }, 438 addrs.AbsProviderConfig{ 439 Provider: addrs.NewDefaultProvider("test"), 440 Module: addrs.RootModule, 441 }, 442 ) 443 }) 444 testStateFileDefault(t, state) 445 446 ui := new(cli.MockUi) 447 view, _ := testView(t) 448 c := &UntaintCommand{ 449 Meta: Meta{ 450 Ui: ui, 451 View: view, 452 }, 453 } 454 455 args := []string{ 456 "-state-out", "foo", 457 "test_instance.foo", 458 } 459 if code := c.Run(args); code != 0 { 460 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 461 } 462 463 testStateOutput(t, DefaultStateFilename, strings.TrimSpace(` 464 test_instance.foo: (tainted) 465 ID = bar 466 provider = provider["registry.terraform.io/hashicorp/test"] 467 `)) 468 testStateOutput(t, "foo", strings.TrimSpace(` 469 test_instance.foo: 470 ID = bar 471 provider = provider["registry.terraform.io/hashicorp/test"] 472 `)) 473 } 474 475 func TestUntaint_module(t *testing.T) { 476 state := states.BuildState(func(s *states.SyncState) { 477 s.SetResourceInstanceCurrent( 478 addrs.Resource{ 479 Mode: addrs.ManagedResourceMode, 480 Type: "test_instance", 481 Name: "foo", 482 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 483 &states.ResourceInstanceObjectSrc{ 484 AttrsJSON: []byte(`{"id":"bar"}`), 485 Status: states.ObjectTainted, 486 }, 487 addrs.AbsProviderConfig{ 488 Provider: addrs.NewDefaultProvider("test"), 489 Module: addrs.RootModule, 490 }, 491 ) 492 s.SetResourceInstanceCurrent( 493 addrs.Resource{ 494 Mode: addrs.ManagedResourceMode, 495 Type: "test_instance", 496 Name: "blah", 497 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("child", addrs.NoKey)), 498 &states.ResourceInstanceObjectSrc{ 499 AttrsJSON: []byte(`{"id":"bar"}`), 500 Status: states.ObjectTainted, 501 }, 502 addrs.AbsProviderConfig{ 503 Provider: addrs.NewDefaultProvider("test"), 504 Module: addrs.RootModule, 505 }, 506 ) 507 }) 508 statePath := testStateFile(t, state) 509 510 ui := new(cli.MockUi) 511 view, _ := testView(t) 512 c := &UntaintCommand{ 513 Meta: Meta{ 514 Ui: ui, 515 View: view, 516 }, 517 } 518 519 args := []string{ 520 "-state", statePath, 521 "module.child.test_instance.blah", 522 } 523 if code := c.Run(args); code != 0 { 524 t.Fatalf("command exited with status code %d; want 0\n\n%s", code, ui.ErrorWriter.String()) 525 } 526 527 testStateOutput(t, statePath, strings.TrimSpace(` 528 test_instance.foo: (tainted) 529 ID = bar 530 provider = provider["registry.terraform.io/hashicorp/test"] 531 532 module.child: 533 test_instance.blah: 534 ID = bar 535 provider = provider["registry.terraform.io/hashicorp/test"] 536 `)) 537 }