github.com/cmalfait/terraform@v0.11.12-beta1/helper/resource/testing_import_state.go (about) 1 package resource 2 3 import ( 4 "fmt" 5 "log" 6 "reflect" 7 "strings" 8 9 "github.com/davecgh/go-spew/spew" 10 "github.com/hashicorp/terraform/terraform" 11 ) 12 13 // testStepImportState runs an imort state test step 14 func testStepImportState( 15 opts terraform.ContextOpts, 16 state *terraform.State, 17 step TestStep) (*terraform.State, error) { 18 // Determine the ID to import 19 var importId string 20 switch { 21 case step.ImportStateIdFunc != nil: 22 var err error 23 importId, err = step.ImportStateIdFunc(state) 24 if err != nil { 25 return state, err 26 } 27 case step.ImportStateId != "": 28 importId = step.ImportStateId 29 default: 30 resource, err := testResource(step, state) 31 if err != nil { 32 return state, err 33 } 34 importId = resource.Primary.ID 35 } 36 37 importPrefix := step.ImportStateIdPrefix 38 if importPrefix != "" { 39 importId = fmt.Sprintf("%s%s", importPrefix, importId) 40 } 41 42 // Setup the context. We initialize with an empty state. We use the 43 // full config for provider configurations. 44 mod, err := testModule(opts, step) 45 if err != nil { 46 return state, err 47 } 48 49 opts.Module = mod 50 opts.State = terraform.NewState() 51 ctx, err := terraform.NewContext(&opts) 52 if err != nil { 53 return state, err 54 } 55 56 // Do the import! 57 newState, err := ctx.Import(&terraform.ImportOpts{ 58 // Set the module so that any provider config is loaded 59 Module: mod, 60 61 Targets: []*terraform.ImportTarget{ 62 &terraform.ImportTarget{ 63 Addr: step.ResourceName, 64 ID: importId, 65 }, 66 }, 67 }) 68 if err != nil { 69 log.Printf("[ERROR] Test: ImportState failure: %s", err) 70 return state, err 71 } 72 73 // Go through the new state and verify 74 if step.ImportStateCheck != nil { 75 var states []*terraform.InstanceState 76 for _, r := range newState.RootModule().Resources { 77 if r.Primary != nil { 78 states = append(states, r.Primary) 79 } 80 } 81 if err := step.ImportStateCheck(states); err != nil { 82 return state, err 83 } 84 } 85 86 // Verify that all the states match 87 if step.ImportStateVerify { 88 new := newState.RootModule().Resources 89 old := state.RootModule().Resources 90 for _, r := range new { 91 // Find the existing resource 92 var oldR *terraform.ResourceState 93 for _, r2 := range old { 94 if r2.Primary != nil && r2.Primary.ID == r.Primary.ID && r2.Type == r.Type { 95 oldR = r2 96 break 97 } 98 } 99 if oldR == nil { 100 return state, fmt.Errorf( 101 "Failed state verification, resource with ID %s not found", 102 r.Primary.ID) 103 } 104 105 // Compare their attributes 106 actual := make(map[string]string) 107 for k, v := range r.Primary.Attributes { 108 actual[k] = v 109 } 110 expected := make(map[string]string) 111 for k, v := range oldR.Primary.Attributes { 112 expected[k] = v 113 } 114 115 // Remove fields we're ignoring 116 for _, v := range step.ImportStateVerifyIgnore { 117 for k, _ := range actual { 118 if strings.HasPrefix(k, v) { 119 delete(actual, k) 120 } 121 } 122 for k, _ := range expected { 123 if strings.HasPrefix(k, v) { 124 delete(expected, k) 125 } 126 } 127 } 128 129 if !reflect.DeepEqual(actual, expected) { 130 // Determine only the different attributes 131 for k, v := range expected { 132 if av, ok := actual[k]; ok && v == av { 133 delete(expected, k) 134 delete(actual, k) 135 } 136 } 137 138 spewConf := spew.NewDefaultConfig() 139 spewConf.SortKeys = true 140 return state, fmt.Errorf( 141 "ImportStateVerify attributes not equivalent. Difference is shown below. Top is actual, bottom is expected."+ 142 "\n\n%s\n\n%s", 143 spewConf.Sdump(actual), spewConf.Sdump(expected)) 144 } 145 } 146 } 147 148 // Return the old state (non-imported) so we don't change anything. 149 return state, nil 150 }