2014-08-17 23:45:43 +02:00
|
|
|
package schema
|
|
|
|
|
|
|
|
import (
|
2014-08-18 18:32:40 +02:00
|
|
|
"errors"
|
2014-08-17 23:45:43 +02:00
|
|
|
"fmt"
|
2014-08-18 04:32:11 +02:00
|
|
|
"sort"
|
2014-08-17 23:45:43 +02:00
|
|
|
|
|
|
|
"github.com/hashicorp/terraform/terraform"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Provider represents a Resource provider in Terraform, and properly
|
|
|
|
// implements all of the ResourceProvider API.
|
|
|
|
//
|
|
|
|
// This is a friendlier API than the core Terraform ResourceProvider API,
|
|
|
|
// and is recommended to be used over that.
|
|
|
|
type Provider struct {
|
2014-08-18 00:07:01 +02:00
|
|
|
Schema map[string]*Schema
|
|
|
|
ResourcesMap map[string]*Resource
|
2014-08-17 23:45:43 +02:00
|
|
|
|
2014-08-18 00:01:27 +02:00
|
|
|
ConfigureFunc ConfigureFunc
|
2014-08-18 04:45:26 +02:00
|
|
|
|
|
|
|
meta interface{}
|
2014-08-17 23:45:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// ConfigureFunc is the function used to configure a Provider.
|
2014-08-18 04:45:26 +02:00
|
|
|
//
|
|
|
|
// 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)
|
2014-08-17 23:45:43 +02:00
|
|
|
|
2014-08-18 18:32:40 +02:00
|
|
|
// InternalValidate should be called to validate the structure
|
|
|
|
// of the provider.
|
|
|
|
//
|
|
|
|
// This should be called in a unit test for any provider to verify
|
|
|
|
// before release that a provider is properly configured for use with
|
|
|
|
// this library.
|
|
|
|
func (p *Provider) InternalValidate() error {
|
|
|
|
if p == nil {
|
|
|
|
return errors.New("provider is nil")
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := schemaMap(p.Schema).InternalValidate(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for k, r := range p.ResourcesMap {
|
|
|
|
if err := r.InternalValidate(); err != nil {
|
|
|
|
return fmt.Errorf("%s: %s", k, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Meta returns the metadata associated with this provider that was
|
|
|
|
// returned by the Configure call. It will be nil until Configure is called.
|
|
|
|
func (p *Provider) Meta() interface{} {
|
|
|
|
return p.meta
|
|
|
|
}
|
|
|
|
|
2014-08-17 23:45:43 +02:00
|
|
|
// Validate validates the provider configuration against the schema.
|
|
|
|
func (p *Provider) Validate(c *terraform.ResourceConfig) ([]string, []error) {
|
|
|
|
return schemaMap(p.Schema).Validate(c)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ValidateResource validates the resource configuration against the
|
|
|
|
// proper schema.
|
|
|
|
func (p *Provider) ValidateResource(
|
|
|
|
t string, c *terraform.ResourceConfig) ([]string, []error) {
|
2014-08-18 00:07:01 +02:00
|
|
|
r, ok := p.ResourcesMap[t]
|
2014-08-17 23:45:43 +02:00
|
|
|
if !ok {
|
|
|
|
return nil, []error{fmt.Errorf(
|
|
|
|
"Provider doesn't support resource: %s", t)}
|
|
|
|
}
|
|
|
|
|
|
|
|
return r.Validate(c)
|
|
|
|
}
|
2014-08-18 00:01:27 +02:00
|
|
|
|
|
|
|
// Configure implementation of terraform.ResourceProvider interface.
|
|
|
|
func (p *Provider) Configure(c *terraform.ResourceConfig) error {
|
|
|
|
// No configuration
|
|
|
|
if p.ConfigureFunc == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
sm := schemaMap(p.Schema)
|
|
|
|
|
|
|
|
// Get a ResourceData for this configuration. To do this, we actually
|
|
|
|
// generate an intermediary "diff" although that is never exposed.
|
|
|
|
diff, err := sm.Diff(nil, c)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
data, err := sm.Data(nil, diff)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2014-08-18 04:45:26 +02:00
|
|
|
meta, err := p.ConfigureFunc(data)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
p.meta = meta
|
|
|
|
return nil
|
2014-08-18 00:01:27 +02:00
|
|
|
}
|
2014-08-18 00:07:01 +02:00
|
|
|
|
2014-08-18 05:23:25 +02:00
|
|
|
// Apply implementation of terraform.ResourceProvider interface.
|
|
|
|
func (p *Provider) Apply(
|
|
|
|
s *terraform.ResourceState,
|
|
|
|
d *terraform.ResourceDiff) (*terraform.ResourceState, error) {
|
|
|
|
r, ok := p.ResourcesMap[s.Type]
|
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("unknown resource type: %s", s.Type)
|
|
|
|
}
|
|
|
|
|
|
|
|
return r.Apply(s, d, p.meta)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Diff implementation of terraform.ResourceProvider interface.
|
|
|
|
func (p *Provider) Diff(
|
|
|
|
s *terraform.ResourceState,
|
|
|
|
c *terraform.ResourceConfig) (*terraform.ResourceDiff, error) {
|
|
|
|
r, ok := p.ResourcesMap[s.Type]
|
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("unknown resource type: %s", s.Type)
|
|
|
|
}
|
|
|
|
|
|
|
|
return r.Diff(s, c)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Refresh implementation of terraform.ResourceProvider interface.
|
|
|
|
func (p *Provider) Refresh(
|
|
|
|
s *terraform.ResourceState) (*terraform.ResourceState, error) {
|
|
|
|
r, ok := p.ResourcesMap[s.Type]
|
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("unknown resource type: %s", s.Type)
|
|
|
|
}
|
|
|
|
|
|
|
|
return r.Refresh(s, p.meta)
|
|
|
|
}
|
|
|
|
|
2014-08-18 00:07:01 +02:00
|
|
|
// Resources implementation of terraform.ResourceProvider interface.
|
|
|
|
func (p *Provider) Resources() []terraform.ResourceType {
|
2014-08-18 04:32:11 +02:00
|
|
|
keys := make([]string, 0, len(p.ResourcesMap))
|
2014-08-18 00:07:01 +02:00
|
|
|
for k, _ := range p.ResourcesMap {
|
2014-08-18 04:32:11 +02:00
|
|
|
keys = append(keys, k)
|
|
|
|
}
|
|
|
|
sort.Strings(keys)
|
|
|
|
|
|
|
|
result := make([]terraform.ResourceType, 0, len(keys))
|
|
|
|
for _, k := range keys {
|
2014-08-18 00:07:01 +02:00
|
|
|
result = append(result, terraform.ResourceType{
|
|
|
|
Name: k,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|