2018-10-16 03:15:08 +02:00
|
|
|
package resource
|
|
|
|
|
|
|
|
import (
|
2019-06-05 17:11:04 +02:00
|
|
|
"encoding/json"
|
2018-10-16 03:15:08 +02:00
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/hashicorp/terraform/addrs"
|
2019-04-08 21:43:32 +02:00
|
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
|
2019-08-07 01:58:58 +02:00
|
|
|
"github.com/hashicorp/terraform/configs/hcl2shim"
|
2019-01-10 18:20:03 +01:00
|
|
|
"github.com/hashicorp/terraform/helper/schema"
|
2019-04-08 21:43:32 +02:00
|
|
|
|
2018-10-16 03:15:08 +02:00
|
|
|
"github.com/hashicorp/terraform/states"
|
|
|
|
"github.com/hashicorp/terraform/terraform"
|
|
|
|
)
|
|
|
|
|
|
|
|
// shimState takes a new *states.State and reverts it to a legacy state for the provider ACC tests
|
2019-01-10 18:20:03 +01:00
|
|
|
func shimNewState(newState *states.State, providers map[string]terraform.ResourceProvider) (*terraform.State, error) {
|
2018-10-16 03:15:08 +02:00
|
|
|
state := terraform.NewState()
|
|
|
|
|
2018-10-16 01:33:33 +02:00
|
|
|
// in the odd case of a nil state, let the helper packages handle it
|
|
|
|
if newState == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2018-10-16 03:15:08 +02:00
|
|
|
for _, newMod := range newState.Modules {
|
|
|
|
mod := state.AddModule(newMod.Addr)
|
|
|
|
|
|
|
|
for name, out := range newMod.OutputValues {
|
|
|
|
outputType := ""
|
|
|
|
val := hcl2shim.ConfigValueFromHCL2(out.Value)
|
|
|
|
ty := out.Value.Type()
|
|
|
|
switch {
|
|
|
|
case ty == cty.String:
|
|
|
|
outputType = "string"
|
|
|
|
case ty.IsTupleType() || ty.IsListType():
|
|
|
|
outputType = "list"
|
|
|
|
case ty.IsMapType():
|
|
|
|
outputType = "map"
|
|
|
|
}
|
|
|
|
|
|
|
|
mod.Outputs[name] = &terraform.OutputState{
|
|
|
|
Type: outputType,
|
|
|
|
Value: val,
|
|
|
|
Sensitive: out.Sensitive,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range newMod.Resources {
|
|
|
|
resType := res.Addr.Type
|
2020-02-13 21:32:58 +01:00
|
|
|
providerType := res.ProviderConfig.Provider.Type
|
2018-10-16 03:15:08 +02:00
|
|
|
|
2020-01-28 14:13:30 +01:00
|
|
|
resource := getResource(providers, providerType, res.Addr)
|
2018-10-16 03:15:08 +02:00
|
|
|
|
|
|
|
for key, i := range res.Instances {
|
2019-06-05 17:11:04 +02:00
|
|
|
resState := &terraform.ResourceState{
|
|
|
|
Type: resType,
|
2020-02-13 21:32:58 +01:00
|
|
|
Provider: res.ProviderConfig.LegacyString(),
|
2018-10-16 03:15:08 +02:00
|
|
|
}
|
|
|
|
|
2019-06-05 17:11:04 +02:00
|
|
|
// We should always have a Current instance here, but be safe about checking.
|
|
|
|
if i.Current != nil {
|
|
|
|
flatmap, err := shimmedAttributes(i.Current, resource)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error decoding state for %q: %s", resType, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var meta map[string]interface{}
|
|
|
|
if i.Current.Private != nil {
|
|
|
|
err := json.Unmarshal(i.Current.Private, &meta)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
resState.Primary = &terraform.InstanceState{
|
2018-10-16 03:15:08 +02:00
|
|
|
ID: flatmap["id"],
|
|
|
|
Attributes: flatmap,
|
|
|
|
Tainted: i.Current.Status == states.ObjectTainted,
|
2019-06-05 17:11:04 +02:00
|
|
|
Meta: meta,
|
2019-01-05 04:22:42 +01:00
|
|
|
}
|
2018-10-16 03:15:08 +02:00
|
|
|
|
2019-06-05 17:11:04 +02:00
|
|
|
if i.Current.SchemaVersion != 0 {
|
2019-09-18 19:59:12 +02:00
|
|
|
if resState.Primary.Meta == nil {
|
|
|
|
resState.Primary.Meta = map[string]interface{}{}
|
2019-06-05 17:11:04 +02:00
|
|
|
}
|
2019-09-18 19:59:12 +02:00
|
|
|
resState.Primary.Meta["schema_version"] = i.Current.SchemaVersion
|
2019-06-05 17:11:04 +02:00
|
|
|
}
|
2018-10-16 03:15:08 +02:00
|
|
|
|
2019-10-21 20:42:40 +02:00
|
|
|
for _, dep := range i.Current.DependsOn {
|
2019-06-05 17:11:04 +02:00
|
|
|
resState.Dependencies = append(resState.Dependencies, dep.String())
|
2018-12-05 19:41:53 +01:00
|
|
|
}
|
2018-10-16 03:15:08 +02:00
|
|
|
|
2019-06-05 17:11:04 +02:00
|
|
|
// convert the indexes to the old style flapmap indexes
|
|
|
|
idx := ""
|
|
|
|
switch key.(type) {
|
|
|
|
case addrs.IntKey:
|
|
|
|
// don't add numeric index values to resources with a count of 0
|
|
|
|
if len(res.Instances) > 1 {
|
|
|
|
idx = fmt.Sprintf(".%d", key)
|
|
|
|
}
|
|
|
|
case addrs.StringKey:
|
|
|
|
idx = "." + key.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
mod.Resources[res.Addr.String()+idx] = resState
|
|
|
|
}
|
2018-10-16 03:15:08 +02:00
|
|
|
|
2018-12-05 19:41:53 +01:00
|
|
|
// add any deposed instances
|
2018-10-16 03:15:08 +02:00
|
|
|
for _, dep := range i.Deposed {
|
2019-01-10 18:20:03 +01:00
|
|
|
flatmap, err := shimmedAttributes(dep, resource)
|
2018-10-16 03:15:08 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error decoding deposed state for %q: %s", resType, err)
|
|
|
|
}
|
|
|
|
|
2019-06-05 17:11:04 +02:00
|
|
|
var meta map[string]interface{}
|
|
|
|
if dep.Private != nil {
|
|
|
|
err := json.Unmarshal(dep.Private, &meta)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-16 03:15:08 +02:00
|
|
|
deposed := &terraform.InstanceState{
|
|
|
|
ID: flatmap["id"],
|
|
|
|
Attributes: flatmap,
|
|
|
|
Tainted: dep.Status == states.ObjectTainted,
|
2019-06-05 17:11:04 +02:00
|
|
|
Meta: meta,
|
2018-10-16 03:15:08 +02:00
|
|
|
}
|
2019-01-05 04:22:42 +01:00
|
|
|
if dep.SchemaVersion != 0 {
|
|
|
|
deposed.Meta = map[string]interface{}{
|
|
|
|
"schema_version": dep.SchemaVersion,
|
|
|
|
}
|
|
|
|
}
|
2018-10-16 03:15:08 +02:00
|
|
|
|
|
|
|
resState.Deposed = append(resState.Deposed, deposed)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return state, nil
|
|
|
|
}
|
|
|
|
|
2019-01-12 17:43:48 +01:00
|
|
|
func getResource(providers map[string]terraform.ResourceProvider, providerName string, addr addrs.Resource) *schema.Resource {
|
2019-01-10 18:20:03 +01:00
|
|
|
p := providers[providerName]
|
|
|
|
if p == nil {
|
|
|
|
panic(fmt.Sprintf("provider %q not found in test step", providerName))
|
|
|
|
}
|
|
|
|
|
|
|
|
// this is only for tests, so should only see schema.Providers
|
|
|
|
provider := p.(*schema.Provider)
|
|
|
|
|
2019-01-12 17:43:48 +01:00
|
|
|
switch addr.Mode {
|
|
|
|
case addrs.ManagedResourceMode:
|
|
|
|
resource := provider.ResourcesMap[addr.Type]
|
|
|
|
if resource != nil {
|
|
|
|
return resource
|
|
|
|
}
|
|
|
|
case addrs.DataResourceMode:
|
|
|
|
resource := provider.DataSourcesMap[addr.Type]
|
|
|
|
if resource != nil {
|
|
|
|
return resource
|
|
|
|
}
|
2019-01-10 18:20:03 +01:00
|
|
|
}
|
|
|
|
|
2019-01-12 17:43:48 +01:00
|
|
|
panic(fmt.Sprintf("resource %s not found in test step", addr.Type))
|
2019-01-10 18:20:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func shimmedAttributes(instance *states.ResourceInstanceObjectSrc, res *schema.Resource) (map[string]string, error) {
|
2018-10-16 03:15:08 +02:00
|
|
|
flatmap := instance.AttrsFlat
|
2019-01-10 18:20:03 +01:00
|
|
|
if flatmap != nil {
|
|
|
|
return flatmap, nil
|
|
|
|
}
|
|
|
|
|
2018-10-16 03:15:08 +02:00
|
|
|
// if we have json attrs, they need to be decoded
|
2019-01-10 18:20:03 +01:00
|
|
|
rio, err := instance.Decode(res.CoreConfigSchema().ImpliedType())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-10-16 03:15:08 +02:00
|
|
|
|
2019-01-10 18:20:03 +01:00
|
|
|
instanceState, err := res.ShimInstanceStateFromValue(rio.Value)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2018-10-16 03:15:08 +02:00
|
|
|
}
|
2019-01-10 18:20:03 +01:00
|
|
|
|
|
|
|
return instanceState.Attributes, nil
|
2018-10-16 03:15:08 +02:00
|
|
|
}
|