helper/schema: start the Diff function
This commit is contained in:
parent
01b6b5f48e
commit
efa2335886
|
@ -2,3 +2,8 @@ package schema
|
|||
|
||||
// ResourceData is used to query and set the attributes of a resource.
|
||||
type ResourceData struct{}
|
||||
|
||||
// Get returns the data for the given key, or nil if the key doesn't exist.
|
||||
func (d *ResourceData) Get(key string) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
package schema
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
// ValueType is an enum of the type that can be represented by a schema.
|
||||
type ValueType int
|
||||
|
||||
|
@ -14,7 +21,7 @@ const (
|
|||
// Schema is used to describe the structure of a value.
|
||||
type Schema struct {
|
||||
// Type is the type of the value and must be one of the ValueType values.
|
||||
Type ValueType
|
||||
Type ValueType
|
||||
|
||||
// If one of these is set, then this item can come from the configuration.
|
||||
// Both cannot be set. If Optional is set, the value is optional. If
|
||||
|
@ -34,3 +41,95 @@ type Schema struct {
|
|||
// element type is a complex structure, potentially with its own lifecycle.
|
||||
Elem interface{}
|
||||
}
|
||||
|
||||
// schemaMap is a wrapper that adds nice functions on top of schemas.
|
||||
type schemaMap map[string]*Schema
|
||||
|
||||
// Data returns a ResourceData for the given schema, state, and diff.
|
||||
//
|
||||
// The diff is optional.
|
||||
func (m schemaMap) Data(
|
||||
s *terraform.ResourceState,
|
||||
d *terraform.ResourceDiff) (*ResourceData, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Diff returns the diff for a resource given the schema map,
|
||||
// state, and configuration.
|
||||
func (m schemaMap) Diff(
|
||||
s *terraform.ResourceState,
|
||||
c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) {
|
||||
result := new(terraform.ResourceDiff)
|
||||
result.Attributes = make(map[string]*terraform.ResourceAttrDiff)
|
||||
|
||||
for k, schema := range m {
|
||||
var attrD *terraform.ResourceAttrDiff
|
||||
var err error
|
||||
|
||||
switch schema.Type {
|
||||
case TypeString:
|
||||
attrD, err = m.diffString(k, schema, s, c)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if attrD == nil {
|
||||
// There is no diff for this attribute so just carry on.
|
||||
continue
|
||||
}
|
||||
|
||||
if schema.ForceNew {
|
||||
// We require a new one if we have a diff, which we do, so
|
||||
// set the flag to true.
|
||||
attrD.RequiresNew = true
|
||||
}
|
||||
|
||||
result.Attributes[k] = attrD
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (m schemaMap) diffString(
|
||||
k string,
|
||||
schema *Schema,
|
||||
s *terraform.ResourceState,
|
||||
c *terraform.ResourceConfig) (*terraform.ResourceAttrDiff, error) {
|
||||
var old, n string
|
||||
if s != nil {
|
||||
old = s.Attributes[k]
|
||||
}
|
||||
|
||||
computed := false
|
||||
v, ok := c.Get(k)
|
||||
if !ok {
|
||||
// We don't have a value, if it is required then it is an error
|
||||
if schema.Required {
|
||||
return nil, fmt.Errorf("%s: required field not set", k)
|
||||
}
|
||||
|
||||
// We don't have a configuration value.
|
||||
if schema.Computed {
|
||||
computed = true
|
||||
} else {
|
||||
return nil, nil
|
||||
}
|
||||
} else {
|
||||
if err := mapstructure.WeakDecode(v, &n); err != nil {
|
||||
return nil, fmt.Errorf("%s: %s", k, err)
|
||||
}
|
||||
|
||||
if old == n {
|
||||
// They're the same value
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
return &terraform.ResourceAttrDiff{
|
||||
Old: old,
|
||||
New: n,
|
||||
NewComputed: computed,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
package schema
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/config"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestSchemaMap_Diff(t *testing.T) {
|
||||
cases := []struct {
|
||||
Schema map[string]*Schema
|
||||
State *terraform.ResourceState
|
||||
Config map[string]interface{}
|
||||
Diff *terraform.ResourceDiff
|
||||
Err bool
|
||||
}{
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
Type: TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
|
||||
State: nil,
|
||||
|
||||
Config: map[string]interface{}{
|
||||
"availability_zone": "foo",
|
||||
},
|
||||
|
||||
Diff: &terraform.ResourceDiff{
|
||||
Attributes: map[string]*terraform.ResourceAttrDiff{
|
||||
"availability_zone": &terraform.ResourceAttrDiff{
|
||||
Old: "",
|
||||
New: "foo",
|
||||
RequiresNew: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Err: false,
|
||||
},
|
||||
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
Type: TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
|
||||
State: nil,
|
||||
|
||||
Config: map[string]interface{}{},
|
||||
|
||||
Diff: &terraform.ResourceDiff{
|
||||
Attributes: map[string]*terraform.ResourceAttrDiff{
|
||||
"availability_zone": &terraform.ResourceAttrDiff{
|
||||
Old: "",
|
||||
NewComputed: true,
|
||||
RequiresNew: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Err: false,
|
||||
},
|
||||
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
Type: TypeString,
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
|
||||
State: nil,
|
||||
|
||||
Config: map[string]interface{}{},
|
||||
|
||||
Diff: nil,
|
||||
|
||||
Err: true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
c, err := config.NewRawConfig(tc.Config)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
d, err := schemaMap(tc.Schema).Diff(
|
||||
tc.State, terraform.NewResourceConfig(c))
|
||||
if (err != nil) != tc.Err {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tc.Diff, d) {
|
||||
t.Fatalf("#%d: bad:\n\n%#v", i, d)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue