aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/terraform/helper/resource/testing.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/helper/resource/testing.go')
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/resource/testing.go348
1 files changed, 285 insertions, 63 deletions
diff --git a/vendor/github.com/hashicorp/terraform/helper/resource/testing.go b/vendor/github.com/hashicorp/terraform/helper/resource/testing.go
index d7de1a0..b97673f 100644
--- a/vendor/github.com/hashicorp/terraform/helper/resource/testing.go
+++ b/vendor/github.com/hashicorp/terraform/helper/resource/testing.go
@@ -11,11 +11,13 @@ import (
11 "reflect" 11 "reflect"
12 "regexp" 12 "regexp"
13 "strings" 13 "strings"
14 "syscall"
14 "testing" 15 "testing"
15 16
16 "github.com/davecgh/go-spew/spew" 17 "github.com/davecgh/go-spew/spew"
17 "github.com/hashicorp/go-getter" 18 "github.com/hashicorp/errwrap"
18 "github.com/hashicorp/go-multierror" 19 "github.com/hashicorp/go-multierror"
20 "github.com/hashicorp/logutils"
19 "github.com/hashicorp/terraform/config/module" 21 "github.com/hashicorp/terraform/config/module"
20 "github.com/hashicorp/terraform/helper/logging" 22 "github.com/hashicorp/terraform/helper/logging"
21 "github.com/hashicorp/terraform/terraform" 23 "github.com/hashicorp/terraform/terraform"
@@ -186,6 +188,10 @@ type TestCheckFunc func(*terraform.State) error
186// ImportStateCheckFunc is the check function for ImportState tests 188// ImportStateCheckFunc is the check function for ImportState tests
187type ImportStateCheckFunc func([]*terraform.InstanceState) error 189type ImportStateCheckFunc func([]*terraform.InstanceState) error
188 190
191// ImportStateIdFunc is an ID generation function to help with complex ID
192// generation for ImportState tests.
193type ImportStateIdFunc func(*terraform.State) (string, error)
194
189// TestCase is a single acceptance test case used to test the apply/destroy 195// TestCase is a single acceptance test case used to test the apply/destroy
190// lifecycle of a resource in a specific configuration. 196// lifecycle of a resource in a specific configuration.
191// 197//
@@ -260,6 +266,15 @@ type TestStep struct {
260 // below. 266 // below.
261 PreConfig func() 267 PreConfig func()
262 268
269 // Taint is a list of resource addresses to taint prior to the execution of
270 // the step. Be sure to only include this at a step where the referenced
271 // address will be present in state, as it will fail the test if the resource
272 // is missing.
273 //
274 // This option is ignored on ImportState tests, and currently only works for
275 // resources in the root module path.
276 Taint []string
277
263 //--------------------------------------------------------------- 278 //---------------------------------------------------------------
264 // Test modes. One of the following groups of settings must be 279 // Test modes. One of the following groups of settings must be
265 // set to determine what the test step will do. Ideally we would've 280 // set to determine what the test step will do. Ideally we would've
@@ -304,10 +319,19 @@ type TestStep struct {
304 // no-op plans 319 // no-op plans
305 PlanOnly bool 320 PlanOnly bool
306 321
322 // PreventDiskCleanup can be set to true for testing terraform modules which
323 // require access to disk at runtime. Note that this will leave files in the
324 // temp folder
325 PreventDiskCleanup bool
326
307 // PreventPostDestroyRefresh can be set to true for cases where data sources 327 // PreventPostDestroyRefresh can be set to true for cases where data sources
308 // are tested alongside real resources 328 // are tested alongside real resources
309 PreventPostDestroyRefresh bool 329 PreventPostDestroyRefresh bool
310 330
331 // SkipFunc is called before applying config, but after PreConfig
332 // This is useful for defining test steps with platform-dependent checks
333 SkipFunc func() (bool, error)
334
311 //--------------------------------------------------------------- 335 //---------------------------------------------------------------
312 // ImportState testing 336 // ImportState testing
313 //--------------------------------------------------------------- 337 //---------------------------------------------------------------
@@ -329,6 +353,12 @@ type TestStep struct {
329 // the unset ImportStateId field. 353 // the unset ImportStateId field.
330 ImportStateIdPrefix string 354 ImportStateIdPrefix string
331 355
356 // ImportStateIdFunc is a function that can be used to dynamically generate
357 // the ID for the ImportState tests. It is sent the state, which can be
358 // checked to derive the attributes necessary and generate the string in the
359 // desired format.
360 ImportStateIdFunc ImportStateIdFunc
361
332 // ImportStateCheck checks the results of ImportState. It should be 362 // ImportStateCheck checks the results of ImportState. It should be
333 // used to verify that the resulting value of ImportState has the 363 // used to verify that the resulting value of ImportState has the
334 // proper resources, IDs, and attributes. 364 // proper resources, IDs, and attributes.
@@ -345,6 +375,60 @@ type TestStep struct {
345 ImportStateVerifyIgnore []string 375 ImportStateVerifyIgnore []string
346} 376}
347 377
378// Set to a file mask in sprintf format where %s is test name
379const EnvLogPathMask = "TF_LOG_PATH_MASK"
380
381func LogOutput(t TestT) (logOutput io.Writer, err error) {
382 logOutput = ioutil.Discard
383
384 logLevel := logging.LogLevel()
385 if logLevel == "" {
386 return
387 }
388
389 logOutput = os.Stderr
390
391 if logPath := os.Getenv(logging.EnvLogFile); logPath != "" {
392 var err error
393 logOutput, err = os.OpenFile(logPath, syscall.O_CREAT|syscall.O_RDWR|syscall.O_APPEND, 0666)
394 if err != nil {
395 return nil, err
396 }
397 }
398
399 if logPathMask := os.Getenv(EnvLogPathMask); logPathMask != "" {
400 // Escape special characters which may appear if we have subtests
401 testName := strings.Replace(t.Name(), "/", "__", -1)
402
403 logPath := fmt.Sprintf(logPathMask, testName)
404 var err error
405 logOutput, err = os.OpenFile(logPath, syscall.O_CREAT|syscall.O_RDWR|syscall.O_APPEND, 0666)
406 if err != nil {
407 return nil, err
408 }
409 }
410
411 // This was the default since the beginning
412 logOutput = &logutils.LevelFilter{
413 Levels: logging.ValidLevels,
414 MinLevel: logutils.LogLevel(logLevel),
415 Writer: logOutput,
416 }
417
418 return
419}
420
421// ParallelTest performs an acceptance test on a resource, allowing concurrency
422// with other ParallelTest.
423//
424// Tests will fail if they do not properly handle conditions to allow multiple
425// tests to occur against the same resource or service (e.g. random naming).
426// All other requirements of the Test function also apply to this function.
427func ParallelTest(t TestT, c TestCase) {
428 t.Parallel()
429 Test(t, c)
430}
431
348// Test performs an acceptance test on a resource. 432// Test performs an acceptance test on a resource.
349// 433//
350// Tests are not run unless an environmental variable "TF_ACC" is 434// Tests are not run unless an environmental variable "TF_ACC" is
@@ -366,7 +450,7 @@ func Test(t TestT, c TestCase) {
366 return 450 return
367 } 451 }
368 452
369 logWriter, err := logging.LogOutput() 453 logWriter, err := LogOutput(t)
370 if err != nil { 454 if err != nil {
371 t.Error(fmt.Errorf("error setting up logging: %s", err)) 455 t.Error(fmt.Errorf("error setting up logging: %s", err))
372 } 456 }
@@ -398,7 +482,18 @@ func Test(t TestT, c TestCase) {
398 errored := false 482 errored := false
399 for i, step := range c.Steps { 483 for i, step := range c.Steps {
400 var err error 484 var err error
401 log.Printf("[WARN] Test: Executing step %d", i) 485 log.Printf("[DEBUG] Test: Executing step %d", i)
486
487 if step.SkipFunc != nil {
488 skip, err := step.SkipFunc()
489 if err != nil {
490 t.Fatal(err)
491 }
492 if skip {
493 log.Printf("[WARN] Skipping step %d", i)
494 continue
495 }
496 }
402 497
403 if step.Config == "" && !step.ImportState { 498 if step.Config == "" && !step.ImportState {
404 err = fmt.Errorf( 499 err = fmt.Errorf(
@@ -418,6 +513,15 @@ func Test(t TestT, c TestCase) {
418 } 513 }
419 } 514 }
420 515
516 // If we expected an error, but did not get one, fail
517 if err == nil && step.ExpectError != nil {
518 errored = true
519 t.Error(fmt.Sprintf(
520 "Step %d, no error received, but expected a match to:\n\n%s\n\n",
521 i, step.ExpectError))
522 break
523 }
524
421 // If there was an error, exit 525 // If there was an error, exit
422 if err != nil { 526 if err != nil {
423 // Perhaps we expected an error? Check if it matches 527 // Perhaps we expected an error? Check if it matches
@@ -485,6 +589,7 @@ func Test(t TestT, c TestCase) {
485 Config: lastStep.Config, 589 Config: lastStep.Config,
486 Check: c.CheckDestroy, 590 Check: c.CheckDestroy,
487 Destroy: true, 591 Destroy: true,
592 PreventDiskCleanup: lastStep.PreventDiskCleanup,
488 PreventPostDestroyRefresh: c.PreventPostDestroyRefresh, 593 PreventPostDestroyRefresh: c.PreventPostDestroyRefresh,
489 } 594 }
490 595
@@ -593,18 +698,12 @@ func testIDOnlyRefresh(c TestCase, opts terraform.ContextOpts, step TestStep, r
593 if err != nil { 698 if err != nil {
594 return err 699 return err
595 } 700 }
596 if ws, es := ctx.Validate(); len(ws) > 0 || len(es) > 0 { 701 if diags := ctx.Validate(); len(diags) > 0 {
597 if len(es) > 0 { 702 if diags.HasErrors() {
598 estrs := make([]string, len(es)) 703 return errwrap.Wrapf("config is invalid: {{err}}", diags.Err())
599 for i, e := range es {
600 estrs[i] = e.Error()
601 }
602 return fmt.Errorf(
603 "Configuration is invalid.\n\nWarnings: %#v\n\nErrors: %#v",
604 ws, estrs)
605 } 704 }
606 705
607 log.Printf("[WARN] Config warnings: %#v", ws) 706 log.Printf("[WARN] Config warnings:\n%s", diags.Err().Error())
608 } 707 }
609 708
610 // Refresh! 709 // Refresh!
@@ -657,9 +756,7 @@ func testIDOnlyRefresh(c TestCase, opts terraform.ContextOpts, step TestStep, r
657 return nil 756 return nil
658} 757}
659 758
660func testModule( 759func testModule(opts terraform.ContextOpts, step TestStep) (*module.Tree, error) {
661 opts terraform.ContextOpts,
662 step TestStep) (*module.Tree, error) {
663 if step.PreConfig != nil { 760 if step.PreConfig != nil {
664 step.PreConfig() 761 step.PreConfig()
665 } 762 }
@@ -669,7 +766,12 @@ func testModule(
669 return nil, fmt.Errorf( 766 return nil, fmt.Errorf(
670 "Error creating temporary directory for config: %s", err) 767 "Error creating temporary directory for config: %s", err)
671 } 768 }
672 defer os.RemoveAll(cfgPath) 769
770 if step.PreventDiskCleanup {
771 log.Printf("[INFO] Skipping defer os.RemoveAll call")
772 } else {
773 defer os.RemoveAll(cfgPath)
774 }
673 775
674 // Write the configuration 776 // Write the configuration
675 cfgF, err := os.Create(filepath.Join(cfgPath, "main.tf")) 777 cfgF, err := os.Create(filepath.Join(cfgPath, "main.tf"))
@@ -693,10 +795,11 @@ func testModule(
693 } 795 }
694 796
695 // Load the modules 797 // Load the modules
696 modStorage := &getter.FolderStorage{ 798 modStorage := &module.Storage{
697 StorageDir: filepath.Join(cfgPath, ".tfmodules"), 799 StorageDir: filepath.Join(cfgPath, ".tfmodules"),
800 Mode: module.GetModeGet,
698 } 801 }
699 err = mod.Load(modStorage, module.GetModeGet) 802 err = mod.Load(modStorage)
700 if err != nil { 803 if err != nil {
701 return nil, fmt.Errorf("Error downloading modules: %s", err) 804 return nil, fmt.Errorf("Error downloading modules: %s", err)
702 } 805 }
@@ -771,12 +874,29 @@ func TestCheckResourceAttrSet(name, key string) TestCheckFunc {
771 return err 874 return err
772 } 875 }
773 876
774 if val, ok := is.Attributes[key]; ok && val != "" { 877 return testCheckResourceAttrSet(is, name, key)
775 return nil 878 }
879}
880
881// TestCheckModuleResourceAttrSet - as per TestCheckResourceAttrSet but with
882// support for non-root modules
883func TestCheckModuleResourceAttrSet(mp []string, name string, key string) TestCheckFunc {
884 return func(s *terraform.State) error {
885 is, err := modulePathPrimaryInstanceState(s, mp, name)
886 if err != nil {
887 return err
776 } 888 }
777 889
890 return testCheckResourceAttrSet(is, name, key)
891 }
892}
893
894func testCheckResourceAttrSet(is *terraform.InstanceState, name string, key string) error {
895 if val, ok := is.Attributes[key]; !ok || val == "" {
778 return fmt.Errorf("%s: Attribute '%s' expected to be set", name, key) 896 return fmt.Errorf("%s: Attribute '%s' expected to be set", name, key)
779 } 897 }
898
899 return nil
780} 900}
781 901
782// TestCheckResourceAttr is a TestCheckFunc which validates 902// TestCheckResourceAttr is a TestCheckFunc which validates
@@ -788,21 +908,37 @@ func TestCheckResourceAttr(name, key, value string) TestCheckFunc {
788 return err 908 return err
789 } 909 }
790 910
791 if v, ok := is.Attributes[key]; !ok || v != value { 911 return testCheckResourceAttr(is, name, key, value)
792 if !ok { 912 }
793 return fmt.Errorf("%s: Attribute '%s' not found", name, key) 913}
794 }
795 914
796 return fmt.Errorf( 915// TestCheckModuleResourceAttr - as per TestCheckResourceAttr but with
797 "%s: Attribute '%s' expected %#v, got %#v", 916// support for non-root modules
798 name, 917func TestCheckModuleResourceAttr(mp []string, name string, key string, value string) TestCheckFunc {
799 key, 918 return func(s *terraform.State) error {
800 value, 919 is, err := modulePathPrimaryInstanceState(s, mp, name)
801 v) 920 if err != nil {
921 return err
802 } 922 }
803 923
804 return nil 924 return testCheckResourceAttr(is, name, key, value)
925 }
926}
927
928func testCheckResourceAttr(is *terraform.InstanceState, name string, key string, value string) error {
929 if v, ok := is.Attributes[key]; !ok || v != value {
930 if !ok {
931 return fmt.Errorf("%s: Attribute '%s' not found", name, key)
932 }
933
934 return fmt.Errorf(
935 "%s: Attribute '%s' expected %#v, got %#v",
936 name,
937 key,
938 value,
939 v)
805 } 940 }
941 return nil
806} 942}
807 943
808// TestCheckNoResourceAttr is a TestCheckFunc which ensures that 944// TestCheckNoResourceAttr is a TestCheckFunc which ensures that
@@ -814,14 +950,31 @@ func TestCheckNoResourceAttr(name, key string) TestCheckFunc {
814 return err 950 return err
815 } 951 }
816 952
817 if _, ok := is.Attributes[key]; ok { 953 return testCheckNoResourceAttr(is, name, key)
818 return fmt.Errorf("%s: Attribute '%s' found when not expected", name, key) 954 }
955}
956
957// TestCheckModuleNoResourceAttr - as per TestCheckNoResourceAttr but with
958// support for non-root modules
959func TestCheckModuleNoResourceAttr(mp []string, name string, key string) TestCheckFunc {
960 return func(s *terraform.State) error {
961 is, err := modulePathPrimaryInstanceState(s, mp, name)
962 if err != nil {
963 return err
819 } 964 }
820 965
821 return nil 966 return testCheckNoResourceAttr(is, name, key)
822 } 967 }
823} 968}
824 969
970func testCheckNoResourceAttr(is *terraform.InstanceState, name string, key string) error {
971 if _, ok := is.Attributes[key]; ok {
972 return fmt.Errorf("%s: Attribute '%s' found when not expected", name, key)
973 }
974
975 return nil
976}
977
825// TestMatchResourceAttr is a TestCheckFunc which checks that the value 978// TestMatchResourceAttr is a TestCheckFunc which checks that the value
826// in state for the given name/key combination matches the given regex. 979// in state for the given name/key combination matches the given regex.
827func TestMatchResourceAttr(name, key string, r *regexp.Regexp) TestCheckFunc { 980func TestMatchResourceAttr(name, key string, r *regexp.Regexp) TestCheckFunc {
@@ -831,17 +984,34 @@ func TestMatchResourceAttr(name, key string, r *regexp.Regexp) TestCheckFunc {
831 return err 984 return err
832 } 985 }
833 986
834 if !r.MatchString(is.Attributes[key]) { 987 return testMatchResourceAttr(is, name, key, r)
835 return fmt.Errorf( 988 }
836 "%s: Attribute '%s' didn't match %q, got %#v", 989}
837 name, 990
838 key, 991// TestModuleMatchResourceAttr - as per TestMatchResourceAttr but with
839 r.String(), 992// support for non-root modules
840 is.Attributes[key]) 993func TestModuleMatchResourceAttr(mp []string, name string, key string, r *regexp.Regexp) TestCheckFunc {
994 return func(s *terraform.State) error {
995 is, err := modulePathPrimaryInstanceState(s, mp, name)
996 if err != nil {
997 return err
841 } 998 }
842 999
843 return nil 1000 return testMatchResourceAttr(is, name, key, r)
1001 }
1002}
1003
1004func testMatchResourceAttr(is *terraform.InstanceState, name string, key string, r *regexp.Regexp) error {
1005 if !r.MatchString(is.Attributes[key]) {
1006 return fmt.Errorf(
1007 "%s: Attribute '%s' didn't match %q, got %#v",
1008 name,
1009 key,
1010 r.String(),
1011 is.Attributes[key])
844 } 1012 }
1013
1014 return nil
845} 1015}
846 1016
847// TestCheckResourceAttrPtr is like TestCheckResourceAttr except the 1017// TestCheckResourceAttrPtr is like TestCheckResourceAttr except the
@@ -853,6 +1023,14 @@ func TestCheckResourceAttrPtr(name string, key string, value *string) TestCheckF
853 } 1023 }
854} 1024}
855 1025
1026// TestCheckModuleResourceAttrPtr - as per TestCheckResourceAttrPtr but with
1027// support for non-root modules
1028func TestCheckModuleResourceAttrPtr(mp []string, name string, key string, value *string) TestCheckFunc {
1029 return func(s *terraform.State) error {
1030 return TestCheckModuleResourceAttr(mp, name, key, *value)(s)
1031 }
1032}
1033
856// TestCheckResourceAttrPair is a TestCheckFunc which validates that the values 1034// TestCheckResourceAttrPair is a TestCheckFunc which validates that the values
857// in state for a pair of name/key combinations are equal. 1035// in state for a pair of name/key combinations are equal.
858func TestCheckResourceAttrPair(nameFirst, keyFirst, nameSecond, keySecond string) TestCheckFunc { 1036func TestCheckResourceAttrPair(nameFirst, keyFirst, nameSecond, keySecond string) TestCheckFunc {
@@ -861,33 +1039,57 @@ func TestCheckResourceAttrPair(nameFirst, keyFirst, nameSecond, keySecond string
861 if err != nil { 1039 if err != nil {
862 return err 1040 return err
863 } 1041 }
864 vFirst, ok := isFirst.Attributes[keyFirst]
865 if !ok {
866 return fmt.Errorf("%s: Attribute '%s' not found", nameFirst, keyFirst)
867 }
868 1042
869 isSecond, err := primaryInstanceState(s, nameSecond) 1043 isSecond, err := primaryInstanceState(s, nameSecond)
870 if err != nil { 1044 if err != nil {
871 return err 1045 return err
872 } 1046 }
873 vSecond, ok := isSecond.Attributes[keySecond] 1047
874 if !ok { 1048 return testCheckResourceAttrPair(isFirst, nameFirst, keyFirst, isSecond, nameSecond, keySecond)
875 return fmt.Errorf("%s: Attribute '%s' not found", nameSecond, keySecond) 1049 }
1050}
1051
1052// TestCheckModuleResourceAttrPair - as per TestCheckResourceAttrPair but with
1053// support for non-root modules
1054func TestCheckModuleResourceAttrPair(mpFirst []string, nameFirst string, keyFirst string, mpSecond []string, nameSecond string, keySecond string) TestCheckFunc {
1055 return func(s *terraform.State) error {
1056 isFirst, err := modulePathPrimaryInstanceState(s, mpFirst, nameFirst)
1057 if err != nil {
1058 return err
876 } 1059 }
877 1060
878 if vFirst != vSecond { 1061 isSecond, err := modulePathPrimaryInstanceState(s, mpSecond, nameSecond)
879 return fmt.Errorf( 1062 if err != nil {
880 "%s: Attribute '%s' expected %#v, got %#v", 1063 return err
881 nameFirst,
882 keyFirst,
883 vSecond,
884 vFirst)
885 } 1064 }
886 1065
887 return nil 1066 return testCheckResourceAttrPair(isFirst, nameFirst, keyFirst, isSecond, nameSecond, keySecond)
888 } 1067 }
889} 1068}
890 1069
1070func testCheckResourceAttrPair(isFirst *terraform.InstanceState, nameFirst string, keyFirst string, isSecond *terraform.InstanceState, nameSecond string, keySecond string) error {
1071 vFirst, ok := isFirst.Attributes[keyFirst]
1072 if !ok {
1073 return fmt.Errorf("%s: Attribute '%s' not found", nameFirst, keyFirst)
1074 }
1075
1076 vSecond, ok := isSecond.Attributes[keySecond]
1077 if !ok {
1078 return fmt.Errorf("%s: Attribute '%s' not found", nameSecond, keySecond)
1079 }
1080
1081 if vFirst != vSecond {
1082 return fmt.Errorf(
1083 "%s: Attribute '%s' expected %#v, got %#v",
1084 nameFirst,
1085 keyFirst,
1086 vSecond,
1087 vFirst)
1088 }
1089
1090 return nil
1091}
1092
891// TestCheckOutput checks an output in the Terraform configuration 1093// TestCheckOutput checks an output in the Terraform configuration
892func TestCheckOutput(name, value string) TestCheckFunc { 1094func TestCheckOutput(name, value string) TestCheckFunc {
893 return func(s *terraform.State) error { 1095 return func(s *terraform.State) error {
@@ -936,23 +1138,43 @@ type TestT interface {
936 Error(args ...interface{}) 1138 Error(args ...interface{})
937 Fatal(args ...interface{}) 1139 Fatal(args ...interface{})
938 Skip(args ...interface{}) 1140 Skip(args ...interface{})
1141 Name() string
1142 Parallel()
939} 1143}
940 1144
941// This is set to true by unit tests to alter some behavior 1145// This is set to true by unit tests to alter some behavior
942var testTesting = false 1146var testTesting = false
943 1147
944// primaryInstanceState returns the primary instance state for the given resource name. 1148// modulePrimaryInstanceState returns the instance state for the given resource
945func primaryInstanceState(s *terraform.State, name string) (*terraform.InstanceState, error) { 1149// name in a ModuleState
946 ms := s.RootModule() 1150func modulePrimaryInstanceState(s *terraform.State, ms *terraform.ModuleState, name string) (*terraform.InstanceState, error) {
947 rs, ok := ms.Resources[name] 1151 rs, ok := ms.Resources[name]
948 if !ok { 1152 if !ok {
949 return nil, fmt.Errorf("Not found: %s", name) 1153 return nil, fmt.Errorf("Not found: %s in %s", name, ms.Path)
950 } 1154 }
951 1155
952 is := rs.Primary 1156 is := rs.Primary
953 if is == nil { 1157 if is == nil {
954 return nil, fmt.Errorf("No primary instance: %s", name) 1158 return nil, fmt.Errorf("No primary instance: %s in %s", name, ms.Path)
955 } 1159 }
956 1160
957 return is, nil 1161 return is, nil
958} 1162}
1163
1164// modulePathPrimaryInstanceState returns the primary instance state for the
1165// given resource name in a given module path.
1166func modulePathPrimaryInstanceState(s *terraform.State, mp []string, name string) (*terraform.InstanceState, error) {
1167 ms := s.ModuleByPath(mp)
1168 if ms == nil {
1169 return nil, fmt.Errorf("No module found at: %s", mp)
1170 }
1171
1172 return modulePrimaryInstanceState(s, ms, name)
1173}
1174
1175// primaryInstanceState returns the primary instance state for the given
1176// resource name in the root module.
1177func primaryInstanceState(s *terraform.State, name string) (*terraform.InstanceState, error) {
1178 ms := s.RootModule()
1179 return modulePrimaryInstanceState(s, ms, name)
1180}