github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/command/taint_test.go (about) 1 package command 2 3 import ( 4 "os" 5 "strings" 6 "testing" 7 8 "github.com/mitchellh/cli" 9 10 "github.com/hashicorp/terraform/addrs" 11 "github.com/hashicorp/terraform/states" 12 "github.com/hashicorp/terraform/terraform" 13 ) 14 15 func TestTaint(t *testing.T) { 16 state := states.BuildState(func(s *states.SyncState) { 17 s.SetResourceInstanceCurrent( 18 addrs.Resource{ 19 Mode: addrs.ManagedResourceMode, 20 Type: "test_instance", 21 Name: "foo", 22 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 23 &states.ResourceInstanceObjectSrc{ 24 AttrsJSON: []byte(`{"id":"bar"}`), 25 Status: states.ObjectReady, 26 }, 27 addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), 28 ) 29 }) 30 statePath := testStateFile(t, state) 31 32 ui := new(cli.MockUi) 33 c := &TaintCommand{ 34 Meta: Meta{ 35 Ui: ui, 36 }, 37 } 38 39 args := []string{ 40 "-state", statePath, 41 "test_instance.foo", 42 } 43 if code := c.Run(args); code != 0 { 44 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 45 } 46 47 testStateOutput(t, statePath, testTaintStr) 48 } 49 50 func TestTaint_lockedState(t *testing.T) { 51 state := states.BuildState(func(s *states.SyncState) { 52 s.SetResourceInstanceCurrent( 53 addrs.Resource{ 54 Mode: addrs.ManagedResourceMode, 55 Type: "test_instance", 56 Name: "foo", 57 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 58 &states.ResourceInstanceObjectSrc{ 59 AttrsJSON: []byte(`{"id":"bar"}`), 60 Status: states.ObjectReady, 61 }, 62 addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), 63 ) 64 }) 65 statePath := testStateFile(t, state) 66 67 unlock, err := testLockState(testDataDir, statePath) 68 if err != nil { 69 t.Fatal(err) 70 } 71 defer unlock() 72 ui := new(cli.MockUi) 73 c := &TaintCommand{ 74 Meta: Meta{ 75 Ui: ui, 76 }, 77 } 78 79 args := []string{ 80 "-state", statePath, 81 "test_instance.foo", 82 } 83 if code := c.Run(args); code == 0 { 84 t.Fatal("expected error") 85 } 86 87 output := ui.ErrorWriter.String() 88 if !strings.Contains(output, "lock") { 89 t.Fatal("command output does not look like a lock error:", output) 90 } 91 } 92 93 func TestTaint_backup(t *testing.T) { 94 // Get a temp cwd 95 tmp, cwd := testCwd(t) 96 defer testFixCwd(t, tmp, cwd) 97 98 // Write the temp state 99 state := &terraform.State{ 100 Modules: []*terraform.ModuleState{ 101 &terraform.ModuleState{ 102 Path: []string{"root"}, 103 Resources: map[string]*terraform.ResourceState{ 104 "test_instance.foo": &terraform.ResourceState{ 105 Type: "test_instance", 106 Primary: &terraform.InstanceState{ 107 ID: "bar", 108 }, 109 }, 110 }, 111 }, 112 }, 113 } 114 path := testStateFileDefault(t, state) 115 116 ui := new(cli.MockUi) 117 c := &TaintCommand{ 118 Meta: Meta{ 119 Ui: ui, 120 }, 121 } 122 123 args := []string{ 124 "test_instance.foo", 125 } 126 if code := c.Run(args); code != 0 { 127 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 128 } 129 130 testStateOutput(t, path+".backup", testTaintDefaultStr) 131 testStateOutput(t, path, testTaintStr) 132 } 133 134 func TestTaint_backupDisable(t *testing.T) { 135 // Get a temp cwd 136 tmp, cwd := testCwd(t) 137 defer testFixCwd(t, tmp, cwd) 138 139 // Write the temp state 140 state := &terraform.State{ 141 Modules: []*terraform.ModuleState{ 142 &terraform.ModuleState{ 143 Path: []string{"root"}, 144 Resources: map[string]*terraform.ResourceState{ 145 "test_instance.foo": &terraform.ResourceState{ 146 Type: "test_instance", 147 Primary: &terraform.InstanceState{ 148 ID: "bar", 149 }, 150 }, 151 }, 152 }, 153 }, 154 } 155 path := testStateFileDefault(t, state) 156 157 ui := new(cli.MockUi) 158 c := &TaintCommand{ 159 Meta: Meta{ 160 Ui: ui, 161 }, 162 } 163 164 args := []string{ 165 "-backup", "-", 166 "test_instance.foo", 167 } 168 if code := c.Run(args); code != 0 { 169 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 170 } 171 172 if _, err := os.Stat(path + ".backup"); err == nil { 173 t.Fatal("backup path should not exist") 174 } 175 176 testStateOutput(t, path, testTaintStr) 177 } 178 179 func TestTaint_badState(t *testing.T) { 180 ui := new(cli.MockUi) 181 c := &TaintCommand{ 182 Meta: Meta{ 183 Ui: ui, 184 }, 185 } 186 187 args := []string{ 188 "-state", "i-should-not-exist-ever", 189 "foo", 190 } 191 if code := c.Run(args); code != 1 { 192 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 193 } 194 } 195 196 func TestTaint_defaultState(t *testing.T) { 197 // Get a temp cwd 198 tmp, cwd := testCwd(t) 199 defer testFixCwd(t, tmp, cwd) 200 201 // Write the temp state 202 state := &terraform.State{ 203 Modules: []*terraform.ModuleState{ 204 &terraform.ModuleState{ 205 Path: []string{"root"}, 206 Resources: map[string]*terraform.ResourceState{ 207 "test_instance.foo": &terraform.ResourceState{ 208 Type: "test_instance", 209 Primary: &terraform.InstanceState{ 210 ID: "bar", 211 }, 212 }, 213 }, 214 }, 215 }, 216 } 217 path := testStateFileDefault(t, state) 218 219 ui := new(cli.MockUi) 220 c := &TaintCommand{ 221 Meta: Meta{ 222 Ui: ui, 223 }, 224 } 225 226 args := []string{ 227 "test_instance.foo", 228 } 229 if code := c.Run(args); code != 0 { 230 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 231 } 232 233 testStateOutput(t, path, testTaintStr) 234 } 235 236 func TestTaint_missing(t *testing.T) { 237 state := states.BuildState(func(s *states.SyncState) { 238 s.SetResourceInstanceCurrent( 239 addrs.Resource{ 240 Mode: addrs.ManagedResourceMode, 241 Type: "test_instance", 242 Name: "foo", 243 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 244 &states.ResourceInstanceObjectSrc{ 245 AttrsJSON: []byte(`{"id":"bar"}`), 246 Status: states.ObjectReady, 247 }, 248 addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), 249 ) 250 }) 251 statePath := testStateFile(t, state) 252 253 ui := new(cli.MockUi) 254 c := &TaintCommand{ 255 Meta: Meta{ 256 Ui: ui, 257 }, 258 } 259 260 args := []string{ 261 "-state", statePath, 262 "test_instance.bar", 263 } 264 if code := c.Run(args); code == 0 { 265 t.Fatalf("bad: %d\n\n%s", code, ui.OutputWriter.String()) 266 } 267 } 268 269 func TestTaint_missingAllow(t *testing.T) { 270 state := states.BuildState(func(s *states.SyncState) { 271 s.SetResourceInstanceCurrent( 272 addrs.Resource{ 273 Mode: addrs.ManagedResourceMode, 274 Type: "test_instance", 275 Name: "foo", 276 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 277 &states.ResourceInstanceObjectSrc{ 278 AttrsJSON: []byte(`{"id":"bar"}`), 279 Status: states.ObjectReady, 280 }, 281 addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), 282 ) 283 }) 284 statePath := testStateFile(t, state) 285 286 ui := new(cli.MockUi) 287 c := &TaintCommand{ 288 Meta: Meta{ 289 Ui: ui, 290 }, 291 } 292 293 args := []string{ 294 "-allow-missing", 295 "-state", statePath, 296 "test_instance.bar", 297 } 298 if code := c.Run(args); code != 0 { 299 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 300 } 301 } 302 303 func TestTaint_stateOut(t *testing.T) { 304 // Get a temp cwd 305 tmp, cwd := testCwd(t) 306 defer testFixCwd(t, tmp, cwd) 307 308 // Write the temp state 309 state := &terraform.State{ 310 Modules: []*terraform.ModuleState{ 311 &terraform.ModuleState{ 312 Path: []string{"root"}, 313 Resources: map[string]*terraform.ResourceState{ 314 "test_instance.foo": &terraform.ResourceState{ 315 Type: "test_instance", 316 Primary: &terraform.InstanceState{ 317 ID: "bar", 318 }, 319 }, 320 }, 321 }, 322 }, 323 } 324 path := testStateFileDefault(t, state) 325 326 ui := new(cli.MockUi) 327 c := &TaintCommand{ 328 Meta: Meta{ 329 Ui: ui, 330 }, 331 } 332 333 args := []string{ 334 "-state-out", "foo", 335 "test_instance.foo", 336 } 337 if code := c.Run(args); code != 0 { 338 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 339 } 340 341 testStateOutput(t, path, testTaintDefaultStr) 342 testStateOutput(t, "foo", testTaintStr) 343 } 344 345 func TestTaint_module(t *testing.T) { 346 state := states.BuildState(func(s *states.SyncState) { 347 s.SetResourceInstanceCurrent( 348 addrs.Resource{ 349 Mode: addrs.ManagedResourceMode, 350 Type: "test_instance", 351 Name: "foo", 352 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 353 &states.ResourceInstanceObjectSrc{ 354 AttrsJSON: []byte(`{"id":"bar"}`), 355 Status: states.ObjectReady, 356 }, 357 addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), 358 ) 359 s.SetResourceInstanceCurrent( 360 addrs.Resource{ 361 Mode: addrs.ManagedResourceMode, 362 Type: "test_instance", 363 Name: "blah", 364 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("child", addrs.NoKey)), 365 &states.ResourceInstanceObjectSrc{ 366 AttrsJSON: []byte(`{"id":"blah"}`), 367 Status: states.ObjectReady, 368 }, 369 addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), 370 ) 371 }) 372 statePath := testStateFile(t, state) 373 374 ui := new(cli.MockUi) 375 c := &TaintCommand{ 376 Meta: Meta{ 377 Ui: ui, 378 }, 379 } 380 381 args := []string{ 382 "-state", statePath, 383 "module.child.test_instance.blah", 384 } 385 if code := c.Run(args); code != 0 { 386 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 387 } 388 389 testStateOutput(t, statePath, testTaintModuleStr) 390 } 391 392 const testTaintStr = ` 393 test_instance.foo: (tainted) 394 ID = bar 395 provider = provider.test 396 ` 397 398 const testTaintDefaultStr = ` 399 test_instance.foo: 400 ID = bar 401 provider = provider.test 402 ` 403 404 const testTaintModuleStr = ` 405 test_instance.foo: 406 ID = bar 407 provider = provider.test 408 409 module.child: 410 test_instance.blah: (tainted) 411 ID = blah 412 provider = provider.test 413 `