helper/schema: GetChange
This commit is contained in:
parent
199b72d798
commit
f1f4836c99
|
@ -9,6 +9,17 @@ import (
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// getSource represents the level we want to get for a value (internally).
|
||||||
|
// Any source less than or equal to the level will be loaded (whichever
|
||||||
|
// has a value first).
|
||||||
|
type getSource byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
getSourceState getSource = iota
|
||||||
|
getSourceDiff
|
||||||
|
getSourceSet
|
||||||
|
)
|
||||||
|
|
||||||
// ResourceData is used to query and set the attributes of a resource.
|
// ResourceData is used to query and set the attributes of a resource.
|
||||||
type ResourceData struct {
|
type ResourceData struct {
|
||||||
schema map[string]*Schema
|
schema map[string]*Schema
|
||||||
|
@ -30,7 +41,21 @@ func (d *ResourceData) Get(key string) interface{} {
|
||||||
parts = strings.Split(key, ".")
|
parts = strings.Split(key, ".")
|
||||||
}
|
}
|
||||||
|
|
||||||
return d.getObject("", parts, d.schema)
|
return d.getObject("", parts, d.schema, getSourceSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChange returns the old and new value for a given key.
|
||||||
|
//
|
||||||
|
// If there is no change, then old and new will simply be the same.
|
||||||
|
func (d *ResourceData) GetChange(key string) (interface{}, interface{}) {
|
||||||
|
var parts []string
|
||||||
|
if key != "" {
|
||||||
|
parts = strings.Split(key, ".")
|
||||||
|
}
|
||||||
|
|
||||||
|
o := d.getObject("", parts, d.schema, getSourceState)
|
||||||
|
n := d.getObject("", parts, d.schema, getSourceDiff)
|
||||||
|
return o, n
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set sets the value for the given key.
|
// Set sets the value for the given key.
|
||||||
|
@ -84,19 +109,21 @@ func (d *ResourceData) State() *terraform.ResourceState {
|
||||||
func (d *ResourceData) get(
|
func (d *ResourceData) get(
|
||||||
k string,
|
k string,
|
||||||
parts []string,
|
parts []string,
|
||||||
schema *Schema) interface{} {
|
schema *Schema,
|
||||||
|
source getSource) interface{} {
|
||||||
switch schema.Type {
|
switch schema.Type {
|
||||||
case TypeList:
|
case TypeList:
|
||||||
return d.getList(k, parts, schema)
|
return d.getList(k, parts, schema, source)
|
||||||
default:
|
default:
|
||||||
return d.getPrimitive(k, parts, schema)
|
return d.getPrimitive(k, parts, schema, source)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *ResourceData) getObject(
|
func (d *ResourceData) getObject(
|
||||||
k string,
|
k string,
|
||||||
parts []string,
|
parts []string,
|
||||||
schema map[string]*Schema) interface{} {
|
schema map[string]*Schema,
|
||||||
|
source getSource) interface{} {
|
||||||
if len(parts) > 0 {
|
if len(parts) > 0 {
|
||||||
// We're requesting a specific key in an object
|
// We're requesting a specific key in an object
|
||||||
key := parts[0]
|
key := parts[0]
|
||||||
|
@ -112,13 +139,13 @@ func (d *ResourceData) getObject(
|
||||||
key = fmt.Sprintf("%s.%s", k, key)
|
key = fmt.Sprintf("%s.%s", k, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
return d.get(key, parts, s)
|
return d.get(key, parts, s, source)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the entire object
|
// Get the entire object
|
||||||
result := make(map[string]interface{})
|
result := make(map[string]interface{})
|
||||||
for field, _ := range schema {
|
for field, _ := range schema {
|
||||||
result[field] = d.getObject(k, []string{field}, schema)
|
result[field] = d.getObject(k, []string{field}, schema, source)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
@ -127,7 +154,8 @@ func (d *ResourceData) getObject(
|
||||||
func (d *ResourceData) getList(
|
func (d *ResourceData) getList(
|
||||||
k string,
|
k string,
|
||||||
parts []string,
|
parts []string,
|
||||||
schema *Schema) interface{} {
|
schema *Schema,
|
||||||
|
source getSource) interface{} {
|
||||||
if len(parts) > 0 {
|
if len(parts) > 0 {
|
||||||
// We still have parts left over meaning we're accessing an
|
// We still have parts left over meaning we're accessing an
|
||||||
// element of this list.
|
// element of this list.
|
||||||
|
@ -137,7 +165,7 @@ func (d *ResourceData) getList(
|
||||||
// Special case if we're accessing the count of the list
|
// Special case if we're accessing the count of the list
|
||||||
if idx == "#" {
|
if idx == "#" {
|
||||||
schema := &Schema{Type: TypeInt}
|
schema := &Schema{Type: TypeInt}
|
||||||
result := d.get(k+".#", parts, schema)
|
result := d.get(k+".#", parts, schema, source)
|
||||||
if result == nil {
|
if result == nil {
|
||||||
result = 0
|
result = 0
|
||||||
}
|
}
|
||||||
|
@ -148,17 +176,19 @@ func (d *ResourceData) getList(
|
||||||
key := fmt.Sprintf("%s.%s", k, idx)
|
key := fmt.Sprintf("%s.%s", k, idx)
|
||||||
switch t := schema.Elem.(type) {
|
switch t := schema.Elem.(type) {
|
||||||
case *Resource:
|
case *Resource:
|
||||||
return d.getObject(key, parts, t.Schema)
|
return d.getObject(key, parts, t.Schema, source)
|
||||||
case *Schema:
|
case *Schema:
|
||||||
return d.get(key, parts, t)
|
return d.get(key, parts, t, source)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the entire list.
|
// Get the entire list.
|
||||||
result := make([]interface{}, d.getList(k, []string{"#"}, schema).(int))
|
result := make(
|
||||||
|
[]interface{},
|
||||||
|
d.getList(k, []string{"#"}, schema, source).(int))
|
||||||
for i, _ := range result {
|
for i, _ := range result {
|
||||||
is := strconv.FormatInt(int64(i), 10)
|
is := strconv.FormatInt(int64(i), 10)
|
||||||
result[i] = d.getList(k, []string{is}, schema)
|
result[i] = d.getList(k, []string{is}, schema, source)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
@ -167,14 +197,15 @@ func (d *ResourceData) getList(
|
||||||
func (d *ResourceData) getPrimitive(
|
func (d *ResourceData) getPrimitive(
|
||||||
k string,
|
k string,
|
||||||
parts []string,
|
parts []string,
|
||||||
schema *Schema) interface{} {
|
schema *Schema,
|
||||||
|
source getSource) interface{} {
|
||||||
var result string
|
var result string
|
||||||
var resultSet bool
|
var resultSet bool
|
||||||
if d.state != nil {
|
if d.state != nil && source >= getSourceState {
|
||||||
result, resultSet = d.state.Attributes[k]
|
result, resultSet = d.state.Attributes[k]
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.diff != nil {
|
if d.diff != nil && source >= getSourceDiff {
|
||||||
attrD, ok := d.diff.Attributes[k]
|
attrD, ok := d.diff.Attributes[k]
|
||||||
if ok {
|
if ok {
|
||||||
result = attrD.New
|
result = attrD.New
|
||||||
|
@ -182,7 +213,7 @@ func (d *ResourceData) getPrimitive(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.setMap != nil {
|
if d.setMap != nil && source >= getSourceSet {
|
||||||
if v, ok := d.setMap[k]; ok {
|
if v, ok := d.setMap[k]; ok {
|
||||||
result = v
|
result = v
|
||||||
resultSet = true
|
resultSet = true
|
||||||
|
@ -357,7 +388,7 @@ func (d *ResourceData) setPrimitive(
|
||||||
func (d *ResourceData) stateList(
|
func (d *ResourceData) stateList(
|
||||||
prefix string,
|
prefix string,
|
||||||
schema *Schema) map[string]string {
|
schema *Schema) map[string]string {
|
||||||
countRaw := d.get(prefix, []string{"#"}, schema)
|
countRaw := d.get(prefix, []string{"#"}, schema, getSourceSet)
|
||||||
if countRaw == nil {
|
if countRaw == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -405,7 +436,7 @@ func (d *ResourceData) stateObject(
|
||||||
func (d *ResourceData) statePrimitive(
|
func (d *ResourceData) statePrimitive(
|
||||||
prefix string,
|
prefix string,
|
||||||
schema *Schema) map[string]string {
|
schema *Schema) map[string]string {
|
||||||
v := d.getPrimitive(prefix, nil, schema)
|
v := d.getPrimitive(prefix, nil, schema, getSourceSet)
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -315,6 +315,92 @@ func TestResourceDataGet(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestResourceDataGetChange(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
Schema map[string]*Schema
|
||||||
|
State *terraform.ResourceState
|
||||||
|
Diff *terraform.ResourceDiff
|
||||||
|
Key string
|
||||||
|
OldValue interface{}
|
||||||
|
NewValue interface{}
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"availability_zone": &Schema{
|
||||||
|
Type: TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
State: nil,
|
||||||
|
|
||||||
|
Diff: &terraform.ResourceDiff{
|
||||||
|
Attributes: map[string]*terraform.ResourceAttrDiff{
|
||||||
|
"availability_zone": &terraform.ResourceAttrDiff{
|
||||||
|
Old: "",
|
||||||
|
New: "foo",
|
||||||
|
RequiresNew: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Key: "availability_zone",
|
||||||
|
|
||||||
|
OldValue: nil,
|
||||||
|
NewValue: "foo",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"availability_zone": &Schema{
|
||||||
|
Type: TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
State: &terraform.ResourceState{
|
||||||
|
Attributes: map[string]string{
|
||||||
|
"availability_zone": "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Diff: &terraform.ResourceDiff{
|
||||||
|
Attributes: map[string]*terraform.ResourceAttrDiff{
|
||||||
|
"availability_zone": &terraform.ResourceAttrDiff{
|
||||||
|
Old: "",
|
||||||
|
New: "foo",
|
||||||
|
RequiresNew: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Key: "availability_zone",
|
||||||
|
|
||||||
|
OldValue: "foo",
|
||||||
|
NewValue: "foo",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range cases {
|
||||||
|
d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
o, n := d.GetChange(tc.Key)
|
||||||
|
if !reflect.DeepEqual(o, tc.OldValue) {
|
||||||
|
t.Fatalf("Old Bad: %d\n\n%#v", i, o)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(n, tc.NewValue) {
|
||||||
|
t.Fatalf("New Bad: %d\n\n%#v", i, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestResourceDataSet(t *testing.T) {
|
func TestResourceDataSet(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
Schema map[string]*Schema
|
Schema map[string]*Schema
|
||||||
|
|
Loading…
Reference in New Issue