From 01b6b5f48e02a1113d628c039bc607c67c27f9f2 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 13 Aug 2014 14:23:22 -0700 Subject: [PATCH] helper/schema: initial work --- helper/schema/resource.go | 56 +++++++++++++++++++++++++ helper/schema/resource_data.go | 4 ++ helper/schema/resource_test.go | 77 ++++++++++++++++++++++++++++++++++ helper/schema/schema.go | 36 ++++++++++++++++ 4 files changed, 173 insertions(+) create mode 100644 helper/schema/resource.go create mode 100644 helper/schema/resource_data.go create mode 100644 helper/schema/resource_test.go create mode 100644 helper/schema/schema.go diff --git a/helper/schema/resource.go b/helper/schema/resource.go new file mode 100644 index 000000000..63c2b1392 --- /dev/null +++ b/helper/schema/resource.go @@ -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 +} diff --git a/helper/schema/resource_data.go b/helper/schema/resource_data.go new file mode 100644 index 000000000..ed4348e23 --- /dev/null +++ b/helper/schema/resource_data.go @@ -0,0 +1,4 @@ +package schema + +// ResourceData is used to query and set the attributes of a resource. +type ResourceData struct{} diff --git a/helper/schema/resource_test.go b/helper/schema/resource_test.go new file mode 100644 index 000000000..b73ab71d7 --- /dev/null +++ b/helper/schema/resource_test.go @@ -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) + } + } +} diff --git a/helper/schema/schema.go b/helper/schema/schema.go new file mode 100644 index 000000000..415a3e613 --- /dev/null +++ b/helper/schema/schema.go @@ -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{} +}