github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/legacy/helper/schema/shims.go (about) 1 package schema 2 3 import ( 4 "encoding/json" 5 6 "github.com/zclconf/go-cty/cty" 7 ctyjson "github.com/zclconf/go-cty/cty/json" 8 9 "github.com/hashicorp/terraform/internal/configs/configschema" 10 "github.com/hashicorp/terraform/internal/configs/hcl2shim" 11 "github.com/hashicorp/terraform/internal/legacy/terraform" 12 ) 13 14 // DiffFromValues takes the current state and desired state as cty.Values and 15 // derives a terraform.InstanceDiff to give to the legacy providers. This is 16 // used to take the states provided by the new ApplyResourceChange method and 17 // convert them to a state+diff required for the legacy Apply method. 18 func DiffFromValues(prior, planned cty.Value, res *Resource) (*terraform.InstanceDiff, error) { 19 return diffFromValues(prior, planned, res, nil) 20 } 21 22 // diffFromValues takes an additional CustomizeDiffFunc, so we can generate our 23 // test fixtures from the legacy tests. In the new provider protocol the diff 24 // only needs to be created for the apply operation, and any customizations 25 // have already been done. 26 func diffFromValues(prior, planned cty.Value, res *Resource, cust CustomizeDiffFunc) (*terraform.InstanceDiff, error) { 27 instanceState, err := res.ShimInstanceStateFromValue(prior) 28 if err != nil { 29 return nil, err 30 } 31 32 configSchema := res.CoreConfigSchema() 33 34 cfg := terraform.NewResourceConfigShimmed(planned, configSchema) 35 removeConfigUnknowns(cfg.Config) 36 removeConfigUnknowns(cfg.Raw) 37 38 diff, err := schemaMap(res.Schema).Diff(instanceState, cfg, cust, nil, false) 39 if err != nil { 40 return nil, err 41 } 42 43 return diff, err 44 } 45 46 // During apply the only unknown values are those which are to be computed by 47 // the resource itself. These may have been marked as unknown config values, and 48 // need to be removed to prevent the UnknownVariableValue from appearing the diff. 49 func removeConfigUnknowns(cfg map[string]interface{}) { 50 for k, v := range cfg { 51 switch v := v.(type) { 52 case string: 53 if v == hcl2shim.UnknownVariableValue { 54 delete(cfg, k) 55 } 56 case []interface{}: 57 for _, i := range v { 58 if m, ok := i.(map[string]interface{}); ok { 59 removeConfigUnknowns(m) 60 } 61 } 62 case map[string]interface{}: 63 removeConfigUnknowns(v) 64 } 65 } 66 } 67 68 // ApplyDiff takes a cty.Value state and applies a terraform.InstanceDiff to 69 // get a new cty.Value state. This is used to convert the diff returned from 70 // the legacy provider Diff method to the state required for the new 71 // PlanResourceChange method. 72 func ApplyDiff(base cty.Value, d *terraform.InstanceDiff, schema *configschema.Block) (cty.Value, error) { 73 return d.ApplyToValue(base, schema) 74 } 75 76 // StateValueToJSONMap converts a cty.Value to generic JSON map via the cty JSON 77 // encoding. 78 func StateValueToJSONMap(val cty.Value, ty cty.Type) (map[string]interface{}, error) { 79 js, err := ctyjson.Marshal(val, ty) 80 if err != nil { 81 return nil, err 82 } 83 84 var m map[string]interface{} 85 if err := json.Unmarshal(js, &m); err != nil { 86 return nil, err 87 } 88 89 return m, nil 90 } 91 92 // JSONMapToStateValue takes a generic json map[string]interface{} and converts it 93 // to the specific type, ensuring that the values conform to the schema. 94 func JSONMapToStateValue(m map[string]interface{}, block *configschema.Block) (cty.Value, error) { 95 var val cty.Value 96 97 js, err := json.Marshal(m) 98 if err != nil { 99 return val, err 100 } 101 102 val, err = ctyjson.Unmarshal(js, block.ImpliedType()) 103 if err != nil { 104 return val, err 105 } 106 107 return block.CoerceValue(val) 108 } 109 110 // StateValueFromInstanceState converts a terraform.InstanceState to a 111 // cty.Value as described by the provided cty.Type, and maintains the resource 112 // ID as the "id" attribute. 113 func StateValueFromInstanceState(is *terraform.InstanceState, ty cty.Type) (cty.Value, error) { 114 return is.AttrsAsObjectValue(ty) 115 }