1package resource 2 3import ( 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 17func 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 120func 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 145func 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} 164