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