]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
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 | |
15c0b25d AP |
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: | |
bae9f6d2 JC |
30 | resource, err := testResource(step, state) |
31 | if err != nil { | |
32 | return state, err | |
33 | } | |
bae9f6d2 JC |
34 | importId = resource.Primary.ID |
35 | } | |
15c0b25d | 36 | |
bae9f6d2 JC |
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 | } |