helper/schema: Resource.Refresh

This commit is contained in:
Mitchell Hashimoto 2014-08-17 19:45:26 -07:00
parent 7db585c257
commit 894187ec18
5 changed files with 98 additions and 14 deletions

View File

@ -17,10 +17,15 @@ type Provider struct {
ResourcesMap map[string]*Resource ResourcesMap map[string]*Resource
ConfigureFunc ConfigureFunc ConfigureFunc ConfigureFunc
meta interface{}
} }
// ConfigureFunc is the function used to configure a Provider. // ConfigureFunc is the function used to configure a Provider.
type ConfigureFunc func(*ResourceData) error //
// The interface{} value returned by this function is stored and passed into
// the subsequent resources as the meta parameter.
type ConfigureFunc func(*ResourceData) (interface{}, error)
// Validate validates the provider configuration against the schema. // Validate validates the provider configuration against the schema.
func (p *Provider) Validate(c *terraform.ResourceConfig) ([]string, []error) { func (p *Provider) Validate(c *terraform.ResourceConfig) ([]string, []error) {
@ -61,7 +66,13 @@ func (p *Provider) Configure(c *terraform.ResourceConfig) error {
return err return err
} }
return p.ConfigureFunc(data) meta, err := p.ConfigureFunc(data)
if err != nil {
return err
}
p.meta = meta
return nil
} }
// Resources implementation of terraform.ResourceProvider interface. // Resources implementation of terraform.ResourceProvider interface.

View File

@ -30,12 +30,12 @@ func TestProviderConfigure(t *testing.T) {
}, },
}, },
ConfigureFunc: func(d *ResourceData) error { ConfigureFunc: func(d *ResourceData) (interface{}, error) {
if d.Get("foo").(int) == 42 { if d.Get("foo").(int) == 42 {
return nil return nil, nil
} }
return fmt.Errorf("nope") return nil, fmt.Errorf("nope")
}, },
}, },
Config: map[string]interface{}{ Config: map[string]interface{}{
@ -53,12 +53,12 @@ func TestProviderConfigure(t *testing.T) {
}, },
}, },
ConfigureFunc: func(d *ResourceData) error { ConfigureFunc: func(d *ResourceData) (interface{}, error) {
if d.Get("foo").(int) == 42 { if d.Get("foo").(int) == 42 {
return nil return nil, nil
} }
return fmt.Errorf("nope") return nil, fmt.Errorf("nope")
}, },
}, },
Config: map[string]interface{}{ Config: map[string]interface{}{

View File

@ -7,10 +7,13 @@ import (
) )
// The functions below are the CRUD function types for a Resource. // The functions below are the CRUD function types for a Resource.
type CreateFunc func(*ResourceData) error //
type ReadFunc func(*ResourceData) error // The second parameter is the meta value sent to the resource when
type UpdateFunc func(*ResourceData) error // different operations are called.
type DeleteFunc func(*ResourceData) error type CreateFunc func(*ResourceData, interface{}) error
type ReadFunc func(*ResourceData, interface{}) error
type UpdateFunc func(*ResourceData, interface{}) error
type DeleteFunc func(*ResourceData, interface{}) error
// Resource represents a thing in Terraform that has a set of configurable // Resource represents a thing in Terraform that has a set of configurable
// attributes and generally also has a lifecycle (create, read, update, // attributes and generally also has a lifecycle (create, read, update,
@ -41,6 +44,19 @@ func (r *Resource) Validate(c *terraform.ResourceConfig) ([]string, []error) {
return schemaMap(r.Schema).Validate(c) return schemaMap(r.Schema).Validate(c)
} }
// Refresh refreshes the state of the resource.
func (r *Resource) Refresh(
s *terraform.ResourceState,
meta interface{}) (*terraform.ResourceState, error) {
data, err := schemaMap(r.Schema).Data(s, nil)
if err != nil {
return nil, err
}
err = r.Read(data, meta)
return data.State(), err
}
// InternalValidate should be called to validate the structure // InternalValidate should be called to validate the structure
// of the resource. // of the resource.
// //

View File

@ -14,7 +14,9 @@ type ResourceData struct {
schema map[string]*Schema schema map[string]*Schema
state *terraform.ResourceState state *terraform.ResourceState
diff *terraform.ResourceDiff diff *terraform.ResourceDiff
setMap map[string]string
setMap map[string]string
newState *terraform.ResourceState
} }
// Get returns the data for the given key, or nil if the key doesn't exist. // Get returns the data for the given key, or nil if the key doesn't exist.
@ -49,6 +51,15 @@ func (d *ResourceData) Set(key string, value interface{}) error {
func (d *ResourceData) State() *terraform.ResourceState { func (d *ResourceData) State() *terraform.ResourceState {
var result terraform.ResourceState var result terraform.ResourceState
result.Attributes = d.stateObject("", d.schema) result.Attributes = d.stateObject("", d.schema)
if d.state != nil {
result.ID = d.state.ID
}
if d.newState != nil {
result.ID = d.newState.ID
}
return &result return &result
} }
@ -335,7 +346,7 @@ func (d *ResourceData) stateList(
count := countRaw.(int) count := countRaw.(int)
result := make(map[string]string) result := make(map[string]string)
result[prefix + ".#"] = strconv.FormatInt(int64(count), 10) result[prefix+".#"] = strconv.FormatInt(int64(count), 10)
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
key := fmt.Sprintf("%s.%d", prefix, i) key := fmt.Sprintf("%s.%d", prefix, i)

View File

@ -1,7 +1,11 @@
package schema package schema
import ( import (
"fmt"
"reflect"
"testing" "testing"
"github.com/hashicorp/terraform/terraform"
) )
func TestResourceInternalValidate(t *testing.T) { func TestResourceInternalValidate(t *testing.T) {
@ -36,3 +40,45 @@ func TestResourceInternalValidate(t *testing.T) {
} }
} }
} }
func TestResourceRefresh(t *testing.T) {
r := &Resource{
Schema: map[string]*Schema{
"foo": &Schema{
Type: TypeInt,
Optional: true,
},
},
}
r.Read = func(d *ResourceData, m interface{}) error {
if m != 42 {
return fmt.Errorf("meta not passed")
}
return d.Set("foo", d.Get("foo").(int)+1)
}
s := &terraform.ResourceState{
ID: "bar",
Attributes: map[string]string{
"foo": "12",
},
}
expected := &terraform.ResourceState{
ID: "bar",
Attributes: map[string]string{
"foo": "13",
},
}
actual, err := r.Refresh(s, 42)
if err != nil {
t.Fatalf("err: %s", err)
}
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %#v", actual)
}
}