github.com/LorbusChris/terraform@v0.11.12-beta1/terraform/context_input_test.go (about) 1 package terraform 2 3 import ( 4 "errors" 5 "reflect" 6 "strings" 7 "sync" 8 "testing" 9 ) 10 11 func TestContext2Input(t *testing.T) { 12 input := new(MockUIInput) 13 m := testModule(t, "input-vars") 14 p := testProvider("aws") 15 p.ApplyFn = testApplyFn 16 p.DiffFn = testDiffFn 17 ctx := testContext2(t, &ContextOpts{ 18 Module: m, 19 ProviderResolver: ResourceProviderResolverFixed( 20 map[string]ResourceProviderFactory{ 21 "aws": testProviderFuncFixed(p), 22 }, 23 ), 24 Variables: map[string]interface{}{ 25 "foo": "us-west-2", 26 "amis": []map[string]interface{}{ 27 map[string]interface{}{ 28 "us-east-1": "override", 29 }, 30 }, 31 }, 32 UIInput: input, 33 }) 34 35 input.InputReturnMap = map[string]string{ 36 "var.foo": "us-east-1", 37 } 38 39 if err := ctx.Input(InputModeStd); err != nil { 40 t.Fatalf("err: %s", err) 41 } 42 43 if _, err := ctx.Plan(); err != nil { 44 t.Fatalf("err: %s", err) 45 } 46 47 state, err := ctx.Apply() 48 if err != nil { 49 t.Fatalf("err: %s", err) 50 } 51 52 actual := strings.TrimSpace(state.String()) 53 expected := strings.TrimSpace(testTerraformInputVarsStr) 54 if actual != expected { 55 t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual) 56 } 57 } 58 59 func TestContext2Input_moduleComputedOutputElement(t *testing.T) { 60 m := testModule(t, "input-module-computed-output-element") 61 p := testProvider("aws") 62 p.ApplyFn = testApplyFn 63 p.DiffFn = testDiffFn 64 ctx := testContext2(t, &ContextOpts{ 65 Module: m, 66 ProviderResolver: ResourceProviderResolverFixed( 67 map[string]ResourceProviderFactory{ 68 "aws": testProviderFuncFixed(p), 69 }, 70 ), 71 }) 72 73 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 74 return c, nil 75 } 76 77 if err := ctx.Input(InputModeStd); err != nil { 78 t.Fatalf("err: %s", err) 79 } 80 } 81 82 func TestContext2Input_badVarDefault(t *testing.T) { 83 m := testModule(t, "input-bad-var-default") 84 p := testProvider("aws") 85 p.ApplyFn = testApplyFn 86 p.DiffFn = testDiffFn 87 ctx := testContext2(t, &ContextOpts{ 88 Module: m, 89 ProviderResolver: ResourceProviderResolverFixed( 90 map[string]ResourceProviderFactory{ 91 "aws": testProviderFuncFixed(p), 92 }, 93 ), 94 }) 95 96 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 97 c.Config["foo"] = "bar" 98 return c, nil 99 } 100 101 if err := ctx.Input(InputModeStd); err != nil { 102 t.Fatalf("err: %s", err) 103 } 104 } 105 106 func TestContext2Input_provider(t *testing.T) { 107 m := testModule(t, "input-provider") 108 p := testProvider("aws") 109 p.ApplyFn = testApplyFn 110 p.DiffFn = testDiffFn 111 ctx := testContext2(t, &ContextOpts{ 112 Module: m, 113 ProviderResolver: ResourceProviderResolverFixed( 114 map[string]ResourceProviderFactory{ 115 "aws": testProviderFuncFixed(p), 116 }, 117 ), 118 }) 119 120 var actual interface{} 121 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 122 c.Config["foo"] = "bar" 123 return c, nil 124 } 125 p.ConfigureFn = func(c *ResourceConfig) error { 126 actual = c.Config["foo"] 127 return nil 128 } 129 p.ValidateFn = func(c *ResourceConfig) ([]string, []error) { 130 return nil, c.CheckSet([]string{"foo"}) 131 } 132 133 if err := ctx.Input(InputModeStd); err != nil { 134 t.Fatalf("err: %s", err) 135 } 136 137 if _, err := ctx.Plan(); err != nil { 138 t.Fatalf("err: %s", err) 139 } 140 141 if _, err := ctx.Apply(); err != nil { 142 t.Fatalf("err: %s", err) 143 } 144 145 if !reflect.DeepEqual(actual, "bar") { 146 t.Fatalf("bad: %#v", actual) 147 } 148 } 149 150 func TestContext2Input_providerMulti(t *testing.T) { 151 m := testModule(t, "input-provider-multi") 152 p := testProvider("aws") 153 p.ApplyFn = testApplyFn 154 p.DiffFn = testDiffFn 155 ctx := testContext2(t, &ContextOpts{ 156 Module: m, 157 ProviderResolver: ResourceProviderResolverFixed( 158 map[string]ResourceProviderFactory{ 159 "aws": testProviderFuncFixed(p), 160 }, 161 ), 162 }) 163 164 var actual []interface{} 165 var lock sync.Mutex 166 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 167 c.Config["foo"] = "bar" 168 return c, nil 169 } 170 p.ConfigureFn = func(c *ResourceConfig) error { 171 lock.Lock() 172 defer lock.Unlock() 173 actual = append(actual, c.Config["foo"]) 174 return nil 175 } 176 p.ValidateFn = func(c *ResourceConfig) ([]string, []error) { 177 return nil, c.CheckSet([]string{"foo"}) 178 } 179 180 if err := ctx.Input(InputModeStd); err != nil { 181 t.Fatalf("err: %s", err) 182 } 183 184 if _, err := ctx.Plan(); err != nil { 185 t.Fatalf("err: %s", err) 186 } 187 188 if _, err := ctx.Apply(); err != nil { 189 t.Fatalf("err: %s", err) 190 } 191 192 expected := []interface{}{"bar", "bar"} 193 if !reflect.DeepEqual(actual, expected) { 194 t.Fatalf("bad: %#v", actual) 195 } 196 } 197 198 func TestContext2Input_providerOnce(t *testing.T) { 199 m := testModule(t, "input-provider-once") 200 p := testProvider("aws") 201 p.ApplyFn = testApplyFn 202 p.DiffFn = testDiffFn 203 ctx := testContext2(t, &ContextOpts{ 204 Module: m, 205 ProviderResolver: ResourceProviderResolverFixed( 206 map[string]ResourceProviderFactory{ 207 "aws": testProviderFuncFixed(p), 208 }, 209 ), 210 }) 211 212 count := 0 213 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 214 count++ 215 _, set := c.Config["from_input"] 216 217 if count == 1 { 218 if set { 219 return nil, errors.New("from_input should not be set") 220 } 221 c.Config["from_input"] = "x" 222 } 223 224 if count > 1 && !set { 225 return nil, errors.New("from_input should be set") 226 } 227 228 return c, nil 229 } 230 231 if err := ctx.Input(InputModeStd); err != nil { 232 t.Fatalf("err: %s", err) 233 } 234 } 235 236 func TestContext2Input_providerId(t *testing.T) { 237 input := new(MockUIInput) 238 m := testModule(t, "input-provider") 239 p := testProvider("aws") 240 p.ApplyFn = testApplyFn 241 p.DiffFn = testDiffFn 242 ctx := testContext2(t, &ContextOpts{ 243 Module: m, 244 ProviderResolver: ResourceProviderResolverFixed( 245 map[string]ResourceProviderFactory{ 246 "aws": testProviderFuncFixed(p), 247 }, 248 ), 249 UIInput: input, 250 }) 251 252 var actual interface{} 253 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 254 v, err := i.Input(&InputOpts{Id: "foo"}) 255 if err != nil { 256 return nil, err 257 } 258 259 c.Config["foo"] = v 260 return c, nil 261 } 262 p.ConfigureFn = func(c *ResourceConfig) error { 263 actual = c.Config["foo"] 264 return nil 265 } 266 267 input.InputReturnMap = map[string]string{ 268 "provider.aws.foo": "bar", 269 } 270 271 if err := ctx.Input(InputModeStd); err != nil { 272 t.Fatalf("err: %s", err) 273 } 274 275 if _, err := ctx.Plan(); err != nil { 276 t.Fatalf("err: %s", err) 277 } 278 279 if _, err := ctx.Apply(); err != nil { 280 t.Fatalf("err: %s", err) 281 } 282 283 if !reflect.DeepEqual(actual, "bar") { 284 t.Fatalf("bad: %#v", actual) 285 } 286 } 287 288 func TestContext2Input_providerOnly(t *testing.T) { 289 input := new(MockUIInput) 290 m := testModule(t, "input-provider-vars") 291 p := testProvider("aws") 292 p.ApplyFn = testApplyFn 293 p.DiffFn = testDiffFn 294 ctx := testContext2(t, &ContextOpts{ 295 Module: m, 296 ProviderResolver: ResourceProviderResolverFixed( 297 map[string]ResourceProviderFactory{ 298 "aws": testProviderFuncFixed(p), 299 }, 300 ), 301 Variables: map[string]interface{}{ 302 "foo": "us-west-2", 303 }, 304 UIInput: input, 305 }) 306 307 input.InputReturnMap = map[string]string{ 308 "var.foo": "us-east-1", 309 } 310 311 var actual interface{} 312 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 313 c.Config["foo"] = "bar" 314 return c, nil 315 } 316 p.ConfigureFn = func(c *ResourceConfig) error { 317 actual = c.Config["foo"] 318 return nil 319 } 320 321 if err := ctx.Input(InputModeProvider); err != nil { 322 t.Fatalf("err: %s", err) 323 } 324 325 if _, err := ctx.Plan(); err != nil { 326 t.Fatalf("err: %s", err) 327 } 328 329 state, err := ctx.Apply() 330 if err != nil { 331 t.Fatalf("err: %s", err) 332 } 333 334 if !reflect.DeepEqual(actual, "bar") { 335 t.Fatalf("bad: %#v", actual) 336 } 337 338 actualStr := strings.TrimSpace(state.String()) 339 expectedStr := strings.TrimSpace(testTerraformInputProviderOnlyStr) 340 if actualStr != expectedStr { 341 t.Fatalf("bad: \n%s", actualStr) 342 } 343 } 344 345 func TestContext2Input_providerVars(t *testing.T) { 346 input := new(MockUIInput) 347 m := testModule(t, "input-provider-with-vars") 348 p := testProvider("aws") 349 p.ApplyFn = testApplyFn 350 p.DiffFn = testDiffFn 351 ctx := testContext2(t, &ContextOpts{ 352 Module: m, 353 ProviderResolver: ResourceProviderResolverFixed( 354 map[string]ResourceProviderFactory{ 355 "aws": testProviderFuncFixed(p), 356 }, 357 ), 358 Variables: map[string]interface{}{ 359 "foo": "bar", 360 }, 361 UIInput: input, 362 }) 363 364 input.InputReturnMap = map[string]string{ 365 "var.foo": "bar", 366 } 367 368 var actual interface{} 369 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 370 c.Config["bar"] = "baz" 371 return c, nil 372 } 373 p.ConfigureFn = func(c *ResourceConfig) error { 374 actual, _ = c.Get("foo") 375 return nil 376 } 377 378 if err := ctx.Input(InputModeStd); err != nil { 379 t.Fatalf("err: %s", err) 380 } 381 382 if _, err := ctx.Plan(); err != nil { 383 t.Fatalf("err: %s", err) 384 } 385 386 if _, err := ctx.Apply(); err != nil { 387 t.Fatalf("err: %s", err) 388 } 389 390 if !reflect.DeepEqual(actual, "bar") { 391 t.Fatalf("bad: %#v", actual) 392 } 393 } 394 395 func TestContext2Input_providerVarsModuleInherit(t *testing.T) { 396 input := new(MockUIInput) 397 m := testModule(t, "input-provider-with-vars-and-module") 398 p := testProvider("aws") 399 p.ApplyFn = testApplyFn 400 p.DiffFn = testDiffFn 401 ctx := testContext2(t, &ContextOpts{ 402 Module: m, 403 ProviderResolver: ResourceProviderResolverFixed( 404 map[string]ResourceProviderFactory{ 405 "aws": testProviderFuncFixed(p), 406 }, 407 ), 408 UIInput: input, 409 }) 410 411 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 412 if errs := c.CheckSet([]string{"access_key"}); len(errs) > 0 { 413 return c, errs[0] 414 } 415 return c, nil 416 } 417 p.ConfigureFn = func(c *ResourceConfig) error { 418 return nil 419 } 420 421 if err := ctx.Input(InputModeStd); err != nil { 422 t.Fatalf("err: %s", err) 423 } 424 } 425 426 func TestContext2Input_varOnly(t *testing.T) { 427 input := new(MockUIInput) 428 m := testModule(t, "input-provider-vars") 429 p := testProvider("aws") 430 p.ApplyFn = testApplyFn 431 p.DiffFn = testDiffFn 432 ctx := testContext2(t, &ContextOpts{ 433 Module: m, 434 ProviderResolver: ResourceProviderResolverFixed( 435 map[string]ResourceProviderFactory{ 436 "aws": testProviderFuncFixed(p), 437 }, 438 ), 439 Variables: map[string]interface{}{ 440 "foo": "us-west-2", 441 }, 442 UIInput: input, 443 }) 444 445 input.InputReturnMap = map[string]string{ 446 "var.foo": "us-east-1", 447 } 448 449 var actual interface{} 450 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 451 c.Raw["foo"] = "bar" 452 return c, nil 453 } 454 p.ConfigureFn = func(c *ResourceConfig) error { 455 actual = c.Raw["foo"] 456 return nil 457 } 458 459 if err := ctx.Input(InputModeVar); err != nil { 460 t.Fatalf("err: %s", err) 461 } 462 463 if _, err := ctx.Plan(); err != nil { 464 t.Fatalf("err: %s", err) 465 } 466 467 state, err := ctx.Apply() 468 if err != nil { 469 t.Fatalf("err: %s", err) 470 } 471 472 if reflect.DeepEqual(actual, "bar") { 473 t.Fatalf("bad: %#v", actual) 474 } 475 476 actualStr := strings.TrimSpace(state.String()) 477 expectedStr := strings.TrimSpace(testTerraformInputVarOnlyStr) 478 if actualStr != expectedStr { 479 t.Fatalf("bad: \n%s", actualStr) 480 } 481 } 482 483 func TestContext2Input_varOnlyUnset(t *testing.T) { 484 input := new(MockUIInput) 485 m := testModule(t, "input-vars-unset") 486 p := testProvider("aws") 487 p.ApplyFn = testApplyFn 488 p.DiffFn = testDiffFn 489 ctx := testContext2(t, &ContextOpts{ 490 Module: m, 491 ProviderResolver: ResourceProviderResolverFixed( 492 map[string]ResourceProviderFactory{ 493 "aws": testProviderFuncFixed(p), 494 }, 495 ), 496 Variables: map[string]interface{}{ 497 "foo": "foovalue", 498 }, 499 UIInput: input, 500 }) 501 502 input.InputReturnMap = map[string]string{ 503 "var.foo": "nope", 504 "var.bar": "baz", 505 } 506 507 if err := ctx.Input(InputModeVar | InputModeVarUnset); err != nil { 508 t.Fatalf("err: %s", err) 509 } 510 511 if _, err := ctx.Plan(); err != nil { 512 t.Fatalf("err: %s", err) 513 } 514 515 state, err := ctx.Apply() 516 if err != nil { 517 t.Fatalf("err: %s", err) 518 } 519 520 actualStr := strings.TrimSpace(state.String()) 521 expectedStr := strings.TrimSpace(testTerraformInputVarOnlyUnsetStr) 522 if actualStr != expectedStr { 523 t.Fatalf("bad: \n%s", actualStr) 524 } 525 } 526 527 func TestContext2Input_varWithDefault(t *testing.T) { 528 input := new(MockUIInput) 529 m := testModule(t, "input-var-default") 530 p := testProvider("aws") 531 p.ApplyFn = testApplyFn 532 p.DiffFn = testDiffFn 533 ctx := testContext2(t, &ContextOpts{ 534 Module: m, 535 ProviderResolver: ResourceProviderResolverFixed( 536 map[string]ResourceProviderFactory{ 537 "aws": testProviderFuncFixed(p), 538 }, 539 ), 540 Variables: map[string]interface{}{}, 541 UIInput: input, 542 }) 543 544 input.InputFn = func(opts *InputOpts) (string, error) { 545 t.Fatalf( 546 "Input should never be called because variable has a default: %#v", opts) 547 return "", nil 548 } 549 550 if err := ctx.Input(InputModeVar | InputModeVarUnset); err != nil { 551 t.Fatalf("err: %s", err) 552 } 553 554 if _, err := ctx.Plan(); err != nil { 555 t.Fatalf("err: %s", err) 556 } 557 558 state, err := ctx.Apply() 559 if err != nil { 560 t.Fatalf("err: %s", err) 561 } 562 563 actualStr := strings.TrimSpace(state.String()) 564 expectedStr := strings.TrimSpace(` 565 aws_instance.foo: 566 ID = foo 567 provider = provider.aws 568 foo = 123 569 type = aws_instance 570 `) 571 if actualStr != expectedStr { 572 t.Fatalf("expected: \n%s\ngot: \n%s\n", expectedStr, actualStr) 573 } 574 } 575 576 func TestContext2Input_varPartiallyComputed(t *testing.T) { 577 input := new(MockUIInput) 578 m := testModule(t, "input-var-partially-computed") 579 p := testProvider("aws") 580 p.ApplyFn = testApplyFn 581 p.DiffFn = testDiffFn 582 ctx := testContext2(t, &ContextOpts{ 583 Module: m, 584 ProviderResolver: ResourceProviderResolverFixed( 585 map[string]ResourceProviderFactory{ 586 "aws": testProviderFuncFixed(p), 587 }, 588 ), 589 Variables: map[string]interface{}{ 590 "foo": "foovalue", 591 }, 592 UIInput: input, 593 State: &State{ 594 Modules: []*ModuleState{ 595 &ModuleState{ 596 Path: rootModulePath, 597 Resources: map[string]*ResourceState{ 598 "aws_instance.foo": &ResourceState{ 599 Type: "aws_instance", 600 Primary: &InstanceState{ 601 ID: "i-abc123", 602 Attributes: map[string]string{ 603 "id": "i-abc123", 604 }, 605 }, 606 }, 607 }, 608 }, 609 &ModuleState{ 610 Path: append(rootModulePath, "child"), 611 Resources: map[string]*ResourceState{ 612 "aws_instance.mod": &ResourceState{ 613 Type: "aws_instance", 614 Primary: &InstanceState{ 615 ID: "i-bcd345", 616 Attributes: map[string]string{ 617 "id": "i-bcd345", 618 "value": "one,i-abc123", 619 }, 620 }, 621 }, 622 }, 623 }, 624 }, 625 }, 626 }) 627 628 if err := ctx.Input(InputModeStd); err != nil { 629 t.Fatalf("err: %s", err) 630 } 631 632 if _, err := ctx.Plan(); err != nil { 633 t.Fatalf("err: %s", err) 634 } 635 } 636 637 // Module variables weren't being interpolated during the Input walk. 638 // https://github.com/hashicorp/terraform/issues/5322 639 func TestContext2Input_interpolateVar(t *testing.T) { 640 input := new(MockUIInput) 641 642 m := testModule(t, "input-interpolate-var") 643 p := testProvider("null") 644 p.ApplyFn = testApplyFn 645 p.DiffFn = testDiffFn 646 647 ctx := testContext2(t, &ContextOpts{ 648 Module: m, 649 ProviderResolver: ResourceProviderResolverFixed( 650 map[string]ResourceProviderFactory{ 651 "template": testProviderFuncFixed(p), 652 }, 653 ), 654 UIInput: input, 655 }) 656 657 if err := ctx.Input(InputModeStd); err != nil { 658 t.Fatalf("err: %s", err) 659 } 660 } 661 662 func TestContext2Input_hcl(t *testing.T) { 663 input := new(MockUIInput) 664 m := testModule(t, "input-hcl") 665 p := testProvider("hcl") 666 p.ApplyFn = testApplyFn 667 p.DiffFn = testDiffFn 668 ctx := testContext2(t, &ContextOpts{ 669 Module: m, 670 ProviderResolver: ResourceProviderResolverFixed( 671 map[string]ResourceProviderFactory{ 672 "hcl": testProviderFuncFixed(p), 673 }, 674 ), 675 Variables: map[string]interface{}{}, 676 UIInput: input, 677 }) 678 679 input.InputReturnMap = map[string]string{ 680 "var.listed": `["a", "b"]`, 681 "var.mapped": `{x = "y", w = "z"}`, 682 } 683 684 if err := ctx.Input(InputModeVar | InputModeVarUnset); err != nil { 685 t.Fatalf("err: %s", err) 686 } 687 688 if _, err := ctx.Plan(); err != nil { 689 t.Fatalf("err: %s", err) 690 } 691 692 state, err := ctx.Apply() 693 if err != nil { 694 t.Fatalf("err: %s", err) 695 } 696 697 actualStr := strings.TrimSpace(state.String()) 698 expectedStr := strings.TrimSpace(testTerraformInputHCL) 699 if actualStr != expectedStr { 700 t.Logf("expected: \n%s", expectedStr) 701 t.Fatalf("bad: \n%s", actualStr) 702 } 703 } 704 705 // adding a list interpolation in fails to interpolate the count variable 706 func TestContext2Input_submoduleTriggersInvalidCount(t *testing.T) { 707 input := new(MockUIInput) 708 m := testModule(t, "input-submodule-count") 709 p := testProvider("aws") 710 p.ApplyFn = testApplyFn 711 p.DiffFn = testDiffFn 712 ctx := testContext2(t, &ContextOpts{ 713 Module: m, 714 ProviderResolver: ResourceProviderResolverFixed( 715 map[string]ResourceProviderFactory{ 716 "aws": testProviderFuncFixed(p), 717 }, 718 ), 719 UIInput: input, 720 }) 721 722 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 723 return c, nil 724 } 725 p.ConfigureFn = func(c *ResourceConfig) error { 726 return nil 727 } 728 729 if err := ctx.Input(InputModeStd); err != nil { 730 t.Fatalf("err: %s", err) 731 } 732 } 733 734 // In this case, a module variable can't be resolved from a data source until 735 // it's refreshed, but it can't be refreshed during Input. 736 func TestContext2Input_dataSourceRequiresRefresh(t *testing.T) { 737 input := new(MockUIInput) 738 p := testProvider("null") 739 m := testModule(t, "input-module-data-vars") 740 741 p.ReadDataDiffFn = testDataDiffFn 742 743 state := &State{ 744 Modules: []*ModuleState{ 745 &ModuleState{ 746 Path: rootModulePath, 747 Resources: map[string]*ResourceState{ 748 "data.null_data_source.bar": &ResourceState{ 749 Type: "null_data_source", 750 Primary: &InstanceState{ 751 ID: "-", 752 Attributes: map[string]string{ 753 "foo.#": "1", 754 "foo.0": "a", 755 // foo.1 exists in the data source, but needs to be refreshed. 756 }, 757 }, 758 }, 759 }, 760 }, 761 }, 762 } 763 764 ctx := testContext2(t, &ContextOpts{ 765 Module: m, 766 ProviderResolver: ResourceProviderResolverFixed( 767 map[string]ResourceProviderFactory{ 768 "null": testProviderFuncFixed(p), 769 }, 770 ), 771 State: state, 772 UIInput: input, 773 }) 774 775 if err := ctx.Input(InputModeStd); err != nil { 776 t.Fatalf("err: %s", err) 777 } 778 779 // ensure that plan works after Refresh 780 if _, err := ctx.Refresh(); err != nil { 781 t.Fatalf("err: %s", err) 782 } 783 if _, err := ctx.Plan(); err != nil { 784 t.Fatalf("err: %s", err) 785 } 786 }