helper/schema: initial work

This commit is contained in:
Mitchell Hashimoto 2014-08-13 14:23:22 -07:00
parent 3e3be5e2a3
commit 01b6b5f48e
4 changed files with 173 additions and 0 deletions

56
helper/schema/resource.go Normal file
View File

@ -0,0 +1,56 @@
package schema
import (
"errors"
"fmt"
)
// The functions below are the CRUD function types for a Resource.
type CreateFunc func(*ResourceData) error
type ReadFunc func(*ResourceData) error
type UpdateFunc func(*ResourceData) error
type DeleteFunc func(*ResourceData) error
// Resource represents a thing in Terraform that has a set of configurable
// attributes and generally also has a lifecycle (create, read, update,
// delete).
//
// The Resource schema is an abstraction that allows provider writers to
// worry only about CRUD operations while off-loading validation, diff
// generation, etc. to this higher level library.
type Resource struct {
Schema map[string]*Schema
Create CreateFunc
Read ReadFunc
Update UpdateFunc
Delete DeleteFunc
}
// InternalValidate should be called to validate the structure
// of the resource.
//
// This should be called in a unit test for any resource to verify
// before release that a resource is properly configured for use with
// this library.
func (r *Resource) InternalValidate() error {
if r == nil {
return errors.New("resource is nil")
}
for k, v := range r.Schema {
if v.Type == TypeInvalid {
return fmt.Errorf("%s: Type must be specified", k)
}
if v.Optional && v.Required {
return fmt.Errorf("%s: Optional or Required must be set, not both", k)
}
if v.Required && v.Computed {
return fmt.Errorf("%s: Cannot be both Required and Computed", k)
}
}
return nil
}

View File

@ -0,0 +1,4 @@
package schema
// ResourceData is used to query and set the attributes of a resource.
type ResourceData struct{}

View File

@ -0,0 +1,77 @@
package schema
import (
"testing"
)
func TestResourceInternalValidate(t *testing.T) {
cases := []struct {
In *Resource
Err bool
}{
{
nil,
true,
},
// No optional and no required
{
&Resource{
Schema: map[string]*Schema{
"foo": &Schema{
Type: TypeInt,
Optional: true,
Required: true,
},
},
},
true,
},
// Missing Type
{
&Resource{
Schema: map[string]*Schema{
"foo": &Schema{
Required: true,
},
},
},
true,
},
// Required but computed
{
&Resource{
Schema: map[string]*Schema{
"foo": &Schema{
Type: TypeInt,
Required: true,
Computed: true,
},
},
},
true,
},
// Looks good
{
&Resource{
Schema: map[string]*Schema{
"foo": &Schema{
Type: TypeString,
Required: true,
},
},
},
false,
},
}
for i, tc := range cases {
err := tc.In.InternalValidate()
if (err != nil) != tc.Err {
t.Fatalf("%d: bad: %s", i, err)
}
}
}

36
helper/schema/schema.go Normal file
View File

@ -0,0 +1,36 @@
package schema
// ValueType is an enum of the type that can be represented by a schema.
type ValueType int
const (
TypeInvalid ValueType = iota
TypeBoolean
TypeInt
TypeString
TypeList
)
// 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
// 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
// Required is set, the value is required.
Optional bool
Required bool
// The fields below relate to diffs: if Computed is true, then the
// result of this value is computed (unless specified by config).
// If ForceNew is true
Computed bool
ForceNew bool
// Elem must be either a *Schema or a *Resource only if the Type is
// TypeList, and represents what the element type is. If it is *Schema,
// the element type is just a simple value. If it is *Resource, the
// element type is a complex structure, potentially with its own lifecycle.
Elem interface{}
}