]>
Commit | Line | Data |
---|---|---|
1 | package resource | |
2 | ||
3 | import ( | |
4 | "fmt" | |
5 | ||
6 | "github.com/hashicorp/terraform/addrs" | |
7 | "github.com/zclconf/go-cty/cty" | |
8 | ||
9 | "github.com/hashicorp/terraform/config/hcl2shim" | |
10 | "github.com/hashicorp/terraform/helper/schema" | |
11 | ||
12 | "github.com/hashicorp/terraform/states" | |
13 | "github.com/hashicorp/terraform/terraform" | |
14 | ) | |
15 | ||
16 | // shimState takes a new *states.State and reverts it to a legacy state for the provider ACC tests | |
17 | func shimNewState(newState *states.State, providers map[string]terraform.ResourceProvider) (*terraform.State, error) { | |
18 | state := terraform.NewState() | |
19 | ||
20 | // in the odd case of a nil state, let the helper packages handle it | |
21 | if newState == nil { | |
22 | return nil, nil | |
23 | } | |
24 | ||
25 | for _, newMod := range newState.Modules { | |
26 | mod := state.AddModule(newMod.Addr) | |
27 | ||
28 | for name, out := range newMod.OutputValues { | |
29 | outputType := "" | |
30 | val := hcl2shim.ConfigValueFromHCL2(out.Value) | |
31 | ty := out.Value.Type() | |
32 | switch { | |
33 | case ty == cty.String: | |
34 | outputType = "string" | |
35 | case ty.IsTupleType() || ty.IsListType(): | |
36 | outputType = "list" | |
37 | case ty.IsMapType(): | |
38 | outputType = "map" | |
39 | } | |
40 | ||
41 | mod.Outputs[name] = &terraform.OutputState{ | |
42 | Type: outputType, | |
43 | Value: val, | |
44 | Sensitive: out.Sensitive, | |
45 | } | |
46 | } | |
47 | ||
48 | for _, res := range newMod.Resources { | |
49 | resType := res.Addr.Type | |
50 | providerType := res.ProviderConfig.ProviderConfig.Type | |
51 | ||
52 | resource := getResource(providers, providerType, res.Addr) | |
53 | ||
54 | for key, i := range res.Instances { | |
55 | flatmap, err := shimmedAttributes(i.Current, resource) | |
56 | if err != nil { | |
57 | return nil, fmt.Errorf("error decoding state for %q: %s", resType, err) | |
58 | } | |
59 | ||
60 | resState := &terraform.ResourceState{ | |
61 | Type: resType, | |
62 | Primary: &terraform.InstanceState{ | |
63 | ID: flatmap["id"], | |
64 | Attributes: flatmap, | |
65 | Tainted: i.Current.Status == states.ObjectTainted, | |
66 | }, | |
67 | Provider: res.ProviderConfig.String(), | |
68 | } | |
69 | if i.Current.SchemaVersion != 0 { | |
70 | resState.Primary.Meta = map[string]interface{}{ | |
71 | "schema_version": i.Current.SchemaVersion, | |
72 | } | |
73 | } | |
74 | ||
75 | for _, dep := range i.Current.Dependencies { | |
76 | resState.Dependencies = append(resState.Dependencies, dep.String()) | |
77 | } | |
78 | ||
79 | // convert the indexes to the old style flapmap indexes | |
80 | idx := "" | |
81 | switch key.(type) { | |
82 | case addrs.IntKey: | |
83 | // don't add numeric index values to resources with a count of 0 | |
84 | if len(res.Instances) > 1 { | |
85 | idx = fmt.Sprintf(".%d", key) | |
86 | } | |
87 | case addrs.StringKey: | |
88 | idx = "." + key.String() | |
89 | } | |
90 | ||
91 | mod.Resources[res.Addr.String()+idx] = resState | |
92 | ||
93 | // add any deposed instances | |
94 | for _, dep := range i.Deposed { | |
95 | flatmap, err := shimmedAttributes(dep, resource) | |
96 | if err != nil { | |
97 | return nil, fmt.Errorf("error decoding deposed state for %q: %s", resType, err) | |
98 | } | |
99 | ||
100 | deposed := &terraform.InstanceState{ | |
101 | ID: flatmap["id"], | |
102 | Attributes: flatmap, | |
103 | Tainted: dep.Status == states.ObjectTainted, | |
104 | } | |
105 | if dep.SchemaVersion != 0 { | |
106 | deposed.Meta = map[string]interface{}{ | |
107 | "schema_version": dep.SchemaVersion, | |
108 | } | |
109 | } | |
110 | ||
111 | resState.Deposed = append(resState.Deposed, deposed) | |
112 | } | |
113 | } | |
114 | } | |
115 | } | |
116 | ||
117 | return state, nil | |
118 | } | |
119 | ||
120 | func getResource(providers map[string]terraform.ResourceProvider, providerName string, addr addrs.Resource) *schema.Resource { | |
121 | p := providers[providerName] | |
122 | if p == nil { | |
123 | panic(fmt.Sprintf("provider %q not found in test step", providerName)) | |
124 | } | |
125 | ||
126 | // this is only for tests, so should only see schema.Providers | |
127 | provider := p.(*schema.Provider) | |
128 | ||
129 | switch addr.Mode { | |
130 | case addrs.ManagedResourceMode: | |
131 | resource := provider.ResourcesMap[addr.Type] | |
132 | if resource != nil { | |
133 | return resource | |
134 | } | |
135 | case addrs.DataResourceMode: | |
136 | resource := provider.DataSourcesMap[addr.Type] | |
137 | if resource != nil { | |
138 | return resource | |
139 | } | |
140 | } | |
141 | ||
142 | panic(fmt.Sprintf("resource %s not found in test step", addr.Type)) | |
143 | } | |
144 | ||
145 | func shimmedAttributes(instance *states.ResourceInstanceObjectSrc, res *schema.Resource) (map[string]string, error) { | |
146 | flatmap := instance.AttrsFlat | |
147 | if flatmap != nil { | |
148 | return flatmap, nil | |
149 | } | |
150 | ||
151 | // if we have json attrs, they need to be decoded | |
152 | rio, err := instance.Decode(res.CoreConfigSchema().ImpliedType()) | |
153 | if err != nil { | |
154 | return nil, err | |
155 | } | |
156 | ||
157 | instanceState, err := res.ShimInstanceStateFromValue(rio.Value) | |
158 | if err != nil { | |
159 | return nil, err | |
160 | } | |
161 | ||
162 | return instanceState.Attributes, nil | |
163 | } |