helper/schema: Resource can be writable or not
In the "schema" layer a Resource is just any "thing" that has a schema and supports some or all of the CRUD operations. Data sources introduce a new use of Resource to represent read-only resources, which require some different InternalValidate logic.
This commit is contained in:
parent
0e0e3d73af
commit
6a468dcd83
|
@ -75,21 +75,15 @@ func (p *Provider) InternalValidate() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, r := range p.ResourcesMap {
|
for k, r := range p.ResourcesMap {
|
||||||
if err := r.InternalValidate(nil); err != nil {
|
if err := r.InternalValidate(nil, true); err != nil {
|
||||||
return fmt.Errorf("resource %s: %s", k, err)
|
return fmt.Errorf("resource %s: %s", k, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, r := range p.DataSourcesMap {
|
for k, r := range p.DataSourcesMap {
|
||||||
if err := r.InternalValidate(nil); err != nil {
|
if err := r.InternalValidate(nil, false); err != nil {
|
||||||
return fmt.Errorf("data source %s: %s", k, err)
|
return fmt.Errorf("data source %s: %s", k, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Create != nil || r.Update != nil || r.Delete != nil {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"data source %s: must not have Create, Update or Delete", k,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -14,6 +14,10 @@ import (
|
||||||
// The Resource schema is an abstraction that allows provider writers to
|
// The Resource schema is an abstraction that allows provider writers to
|
||||||
// worry only about CRUD operations while off-loading validation, diff
|
// worry only about CRUD operations while off-loading validation, diff
|
||||||
// generation, etc. to this higher level library.
|
// generation, etc. to this higher level library.
|
||||||
|
//
|
||||||
|
// In spite of the name, this struct is not used only for terraform resources,
|
||||||
|
// but also for data sources. In the case of data sources, the Create,
|
||||||
|
// Update and Delete functions must not be provided.
|
||||||
type Resource struct {
|
type Resource struct {
|
||||||
// Schema is the schema for the configuration of this resource.
|
// Schema is the schema for the configuration of this resource.
|
||||||
//
|
//
|
||||||
|
@ -260,13 +264,20 @@ func (r *Resource) Refresh(
|
||||||
// Provider.InternalValidate() will automatically call this for all of
|
// Provider.InternalValidate() will automatically call this for all of
|
||||||
// the resources it manages, so you don't need to call this manually if it
|
// the resources it manages, so you don't need to call this manually if it
|
||||||
// is part of a Provider.
|
// is part of a Provider.
|
||||||
func (r *Resource) InternalValidate(topSchemaMap schemaMap) error {
|
func (r *Resource) InternalValidate(topSchemaMap schemaMap, writable bool) error {
|
||||||
if r == nil {
|
if r == nil {
|
||||||
return errors.New("resource is nil")
|
return errors.New("resource is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !writable {
|
||||||
|
if r.Create != nil || r.Update != nil || r.Delete != nil {
|
||||||
|
return fmt.Errorf("must not implement Create, Update or Delete")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tsm := topSchemaMap
|
tsm := topSchemaMap
|
||||||
|
|
||||||
if r.isTopLevel() {
|
if r.isTopLevel() && writable {
|
||||||
// All non-Computed attributes must be ForceNew if Update is not defined
|
// All non-Computed attributes must be ForceNew if Update is not defined
|
||||||
if r.Update == nil {
|
if r.Update == nil {
|
||||||
nonForceNewAttrs := make([]string, 0)
|
nonForceNewAttrs := make([]string, 0)
|
||||||
|
|
|
@ -395,12 +395,14 @@ func TestResourceApply_isNewResource(t *testing.T) {
|
||||||
|
|
||||||
func TestResourceInternalValidate(t *testing.T) {
|
func TestResourceInternalValidate(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
In *Resource
|
In *Resource
|
||||||
Err bool
|
Writable bool
|
||||||
|
Err bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
nil,
|
nil,
|
||||||
true,
|
true,
|
||||||
|
true,
|
||||||
},
|
},
|
||||||
|
|
||||||
// No optional and no required
|
// No optional and no required
|
||||||
|
@ -415,6 +417,7 @@ func TestResourceInternalValidate(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
|
true,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Update undefined for non-ForceNew field
|
// Update undefined for non-ForceNew field
|
||||||
|
@ -429,6 +432,7 @@ func TestResourceInternalValidate(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
|
true,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Update defined for ForceNew field
|
// Update defined for ForceNew field
|
||||||
|
@ -445,11 +449,41 @@ func TestResourceInternalValidate(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// non-writable doesn't need Update, Create or Delete
|
||||||
|
{
|
||||||
|
&Resource{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"goo": &Schema{
|
||||||
|
Type: TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// non-writable *must not* have Create
|
||||||
|
{
|
||||||
|
&Resource{
|
||||||
|
Create: func(d *ResourceData, meta interface{}) error { return nil },
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"goo": &Schema{
|
||||||
|
Type: TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tc := range cases {
|
for i, tc := range cases {
|
||||||
err := tc.In.InternalValidate(schemaMap{})
|
err := tc.In.InternalValidate(schemaMap{}, tc.Writable)
|
||||||
if err != nil != tc.Err {
|
if err != nil != tc.Err {
|
||||||
t.Fatalf("%d: bad: %s", i, err)
|
t.Fatalf("%d: bad: %s", i, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -553,7 +553,7 @@ func (m schemaMap) InternalValidate(topSchemaMap schemaMap) error {
|
||||||
|
|
||||||
switch t := v.Elem.(type) {
|
switch t := v.Elem.(type) {
|
||||||
case *Resource:
|
case *Resource:
|
||||||
if err := t.InternalValidate(topSchemaMap); err != nil {
|
if err := t.InternalValidate(topSchemaMap, true); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case *Schema:
|
case *Schema:
|
||||||
|
|
Loading…
Reference in New Issue