Merge pull request #766 from hashicorp/f-exists-api
helper/schema: Exists API
This commit is contained in:
commit
466a54cfe4
|
@ -41,10 +41,17 @@ type Resource struct {
|
||||||
// If any errors occur during each of the operation, an error should be
|
// If any errors occur during each of the operation, an error should be
|
||||||
// returned. If a resource was partially updated, be careful to enable
|
// returned. If a resource was partially updated, be careful to enable
|
||||||
// partial state mode for ResourceData and use it accordingly.
|
// partial state mode for ResourceData and use it accordingly.
|
||||||
|
//
|
||||||
|
// Exists is a function that is called to check if a resource still
|
||||||
|
// exists. If this returns false, then this will affect the diff
|
||||||
|
// accordingly. If this function isn't set, it will not be called. It
|
||||||
|
// is highly recommended to set it. The *ResourceData passed to Exists
|
||||||
|
// should _not_ be modified.
|
||||||
Create CreateFunc
|
Create CreateFunc
|
||||||
Read ReadFunc
|
Read ReadFunc
|
||||||
Update UpdateFunc
|
Update UpdateFunc
|
||||||
Delete DeleteFunc
|
Delete DeleteFunc
|
||||||
|
Exists ExistsFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
// See Resource documentation.
|
// See Resource documentation.
|
||||||
|
@ -59,6 +66,9 @@ type UpdateFunc func(*ResourceData, interface{}) error
|
||||||
// See Resource documentation.
|
// See Resource documentation.
|
||||||
type DeleteFunc func(*ResourceData, interface{}) error
|
type DeleteFunc func(*ResourceData, interface{}) error
|
||||||
|
|
||||||
|
// See Resource documentation.
|
||||||
|
type ExistsFunc func(*ResourceData, interface{}) (bool, error)
|
||||||
|
|
||||||
// Apply creates, updates, and/or deletes a resource.
|
// Apply creates, updates, and/or deletes a resource.
|
||||||
func (r *Resource) Apply(
|
func (r *Resource) Apply(
|
||||||
s *terraform.InstanceState,
|
s *terraform.InstanceState,
|
||||||
|
@ -131,6 +141,23 @@ func (r *Resource) Validate(c *terraform.ResourceConfig) ([]string, []error) {
|
||||||
func (r *Resource) Refresh(
|
func (r *Resource) Refresh(
|
||||||
s *terraform.InstanceState,
|
s *terraform.InstanceState,
|
||||||
meta interface{}) (*terraform.InstanceState, error) {
|
meta interface{}) (*terraform.InstanceState, error) {
|
||||||
|
if r.Exists != nil {
|
||||||
|
// Make a copy of data so that if it is modified it doesn't
|
||||||
|
// affect our Read later.
|
||||||
|
data, err := schemaMap(r.Schema).Data(s, nil)
|
||||||
|
if err != nil {
|
||||||
|
return s, err
|
||||||
|
}
|
||||||
|
|
||||||
|
exists, err := r.Exists(data, meta)
|
||||||
|
if err != nil {
|
||||||
|
return s, err
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data, err := schemaMap(r.Schema).Data(s, nil)
|
data, err := schemaMap(r.Schema).Data(s, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return s, err
|
return s, err
|
||||||
|
|
|
@ -410,3 +410,71 @@ func TestResourceRefresh_delete(t *testing.T) {
|
||||||
t.Fatalf("bad: %#v", actual)
|
t.Fatalf("bad: %#v", actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestResourceRefresh_existsError(t *testing.T) {
|
||||||
|
r := &Resource{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"foo": &Schema{
|
||||||
|
Type: TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Exists = func(*ResourceData, interface{}) (bool, error) {
|
||||||
|
return false, fmt.Errorf("error")
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Read = func(d *ResourceData, m interface{}) error {
|
||||||
|
panic("shouldn't be called")
|
||||||
|
}
|
||||||
|
|
||||||
|
s := &terraform.InstanceState{
|
||||||
|
ID: "bar",
|
||||||
|
Attributes: map[string]string{
|
||||||
|
"foo": "12",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
actual, err := r.Refresh(s, 42)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("should error")
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(actual, s) {
|
||||||
|
t.Fatalf("bad: %#v", actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResourceRefresh_noExists(t *testing.T) {
|
||||||
|
r := &Resource{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"foo": &Schema{
|
||||||
|
Type: TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Exists = func(*ResourceData, interface{}) (bool, error) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Read = func(d *ResourceData, m interface{}) error {
|
||||||
|
panic("shouldn't be called")
|
||||||
|
}
|
||||||
|
|
||||||
|
s := &terraform.InstanceState{
|
||||||
|
ID: "bar",
|
||||||
|
Attributes: map[string]string{
|
||||||
|
"foo": "12",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
actual, err := r.Refresh(s, 42)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
if actual != nil {
|
||||||
|
t.Fatalf("should have no state")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -158,6 +158,10 @@ The CRUD operations in more detail, along with their contracts:
|
||||||
* `Delete` - This is called to delete the resource. Terraform guarantees
|
* `Delete` - This is called to delete the resource. Terraform guarantees
|
||||||
an existing ID will be set.
|
an existing ID will be set.
|
||||||
|
|
||||||
|
* `Exists` - This is called to verify a resource still exists. It is
|
||||||
|
called prior to `Read`, and lowers the burden of `Read` to be able
|
||||||
|
to assume the resource exists.
|
||||||
|
|
||||||
## Schemas
|
## Schemas
|
||||||
|
|
||||||
Both providers and resources require a schema to be specified. The schema
|
Both providers and resources require a schema to be specified. The schema
|
||||||
|
|
Loading…
Reference in New Issue