2014-08-17 23:45:43 +02:00
|
|
|
package schema
|
|
|
|
|
|
|
|
import (
|
2016-10-25 20:29:24 +02:00
|
|
|
"context"
|
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"
|
2016-10-24 03:07:17 +02:00
|
|
|
"sync"
|
2014-08-17 23:45:43 +02:00
|
|
|
|
2016-08-27 11:33:19 +02:00
|
|
|
"github.com/hashicorp/go-multierror"
|
2017-07-11 06:51:55 +02:00
|
|
|
"github.com/hashicorp/terraform/config"
|
2018-07-05 19:33:29 +02:00
|
|
|
"github.com/hashicorp/terraform/configs/configschema"
|
2014-08-17 23:45:43 +02:00
|
|
|
"github.com/hashicorp/terraform/terraform"
|
|
|
|
)
|
|
|
|
|
2014-08-27 06:52:09 +02:00
|
|
|
// Provider represents a resource provider in Terraform, and properly
|
2014-08-17 23:45:43 +02:00
|
|
|
// implements all of the ResourceProvider API.
|
|
|
|
//
|
2014-08-27 06:52:09 +02:00
|
|
|
// By defining a schema for the configuration of the provider, the
|
|
|
|
// map of supporting resources, and a configuration function, the schema
|
|
|
|
// framework takes over and handles all the provider operations for you.
|
|
|
|
//
|
|
|
|
// After defining the provider structure, it is unlikely that you'll require any
|
|
|
|
// of the methods on Provider itself.
|
2014-08-17 23:45:43 +02:00
|
|
|
type Provider struct {
|
2014-08-27 06:52:09 +02:00
|
|
|
// Schema is the schema for the configuration of this provider. If this
|
|
|
|
// provider has no configuration, this can be omitted.
|
|
|
|
//
|
|
|
|
// The keys of this map are the configuration keys, and the value is
|
|
|
|
// the schema describing the value of the configuration.
|
2014-08-31 02:03:01 +02:00
|
|
|
Schema map[string]*Schema
|
2014-08-27 06:52:09 +02:00
|
|
|
|
|
|
|
// ResourcesMap is the list of available resources that this provider
|
|
|
|
// can manage, along with their Resource structure defining their
|
|
|
|
// own schemas and CRUD operations.
|
|
|
|
//
|
|
|
|
// Provider automatically handles routing operations such as Apply,
|
|
|
|
// Diff, etc. to the proper resource.
|
2014-08-18 00:07:01 +02:00
|
|
|
ResourcesMap map[string]*Resource
|
2014-08-17 23:45:43 +02:00
|
|
|
|
core: New ResourceProvider methods for data resources
This is a breaking change to the ResourceProvider interface that adds the
new operations relating to data sources.
DataSources, ValidateDataSource, ReadDataDiff and ReadDataApply are the
data source equivalents of Resources, Validate, Diff and Apply (respectively)
for managed resources.
The diff/apply model seems at first glance a rather strange workflow for
read-only resources, but implementing data resources in this way allows them
to fit cleanly into the standard plan/apply lifecycle in cases where the
configuration contains computed arguments and thus the read must be deferred
until apply time.
Along with breaking the interface, we also fix up the plugin client/server
and helper/schema implementations of it, which are all of the callers
used when provider plugins use helper/schema. This would be a breaking
change for any provider plugin that directly implements the provider
interface, but no known plugins do this and it is not recommended.
At the helper/schema layer the implementer sees ReadDataApply as a "Read",
as opposed to "Create" or "Update" as in the managed resource Apply
implementation. The planning mechanics are handled entirely within
helper/schema, so that complexity is hidden from the provider implementation
itself.
2016-05-08 06:55:32 +02:00
|
|
|
// DataSourcesMap is the collection of available data sources that
|
|
|
|
// this provider implements, with a Resource instance defining
|
|
|
|
// the schema and Read operation of each.
|
|
|
|
//
|
|
|
|
// Resource instances for data sources must have a Read function
|
|
|
|
// and must *not* implement Create, Update or Delete.
|
|
|
|
DataSourcesMap map[string]*Resource
|
|
|
|
|
2014-08-27 06:52:09 +02:00
|
|
|
// ConfigureFunc is a function for configuring the provider. If the
|
|
|
|
// provider doesn't need to be configured, this can be omitted.
|
|
|
|
//
|
|
|
|
// See the ConfigureFunc documentation for more information.
|
2014-08-18 00:01:27 +02:00
|
|
|
ConfigureFunc ConfigureFunc
|
2014-08-18 04:45:26 +02:00
|
|
|
|
2017-03-07 15:19:02 +01:00
|
|
|
// MetaReset is called by TestReset to reset any state stored in the meta
|
|
|
|
// interface. This is especially important if the StopContext is stored by
|
|
|
|
// the provider.
|
|
|
|
MetaReset func() error
|
|
|
|
|
2014-08-18 04:45:26 +02:00
|
|
|
meta interface{}
|
2016-10-24 03:07:17 +02:00
|
|
|
|
2018-01-23 17:41:03 +01:00
|
|
|
// a mutex is required because TestReset can directly replace the stopCtx
|
2017-03-07 15:19:02 +01:00
|
|
|
stopMu sync.Mutex
|
2016-10-25 20:29:24 +02:00
|
|
|
stopCtx context.Context
|
|
|
|
stopCtxCancel context.CancelFunc
|
|
|
|
stopOnce sync.Once
|
2019-01-28 20:27:58 +01:00
|
|
|
|
|
|
|
TerraformVersion string
|
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
|
2014-08-27 06:52:09 +02:00
|
|
|
// the subsequent resources as the meta parameter. This return value is
|
|
|
|
// usually used to pass along a configured API client, a configuration
|
|
|
|
// structure, etc.
|
2014-08-18 04:45:26 +02:00
|
|
|
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")
|
|
|
|
}
|
|
|
|
|
2016-08-27 11:33:19 +02:00
|
|
|
var validationErrors error
|
2015-05-12 16:45:15 +02:00
|
|
|
sm := schemaMap(p.Schema)
|
|
|
|
if err := sm.InternalValidate(sm); err != nil {
|
2016-08-27 11:33:19 +02:00
|
|
|
validationErrors = multierror.Append(validationErrors, err)
|
2014-08-18 18:32:40 +02:00
|
|
|
}
|
|
|
|
|
2017-07-11 06:51:55 +02:00
|
|
|
// Provider-specific checks
|
|
|
|
for k, _ := range sm {
|
|
|
|
if isReservedProviderFieldName(k) {
|
|
|
|
return fmt.Errorf("%s is a reserved field name for a provider", k)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-18 18:32:40 +02:00
|
|
|
for k, r := range p.ResourcesMap {
|
2016-04-17 02:27:00 +02:00
|
|
|
if err := r.InternalValidate(nil, true); err != nil {
|
2016-08-27 11:33:19 +02:00
|
|
|
validationErrors = multierror.Append(validationErrors, fmt.Errorf("resource %s: %s", k, err))
|
core: New ResourceProvider methods for data resources
This is a breaking change to the ResourceProvider interface that adds the
new operations relating to data sources.
DataSources, ValidateDataSource, ReadDataDiff and ReadDataApply are the
data source equivalents of Resources, Validate, Diff and Apply (respectively)
for managed resources.
The diff/apply model seems at first glance a rather strange workflow for
read-only resources, but implementing data resources in this way allows them
to fit cleanly into the standard plan/apply lifecycle in cases where the
configuration contains computed arguments and thus the read must be deferred
until apply time.
Along with breaking the interface, we also fix up the plugin client/server
and helper/schema implementations of it, which are all of the callers
used when provider plugins use helper/schema. This would be a breaking
change for any provider plugin that directly implements the provider
interface, but no known plugins do this and it is not recommended.
At the helper/schema layer the implementer sees ReadDataApply as a "Read",
as opposed to "Create" or "Update" as in the managed resource Apply
implementation. The planning mechanics are handled entirely within
helper/schema, so that complexity is hidden from the provider implementation
itself.
2016-05-08 06:55:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for k, r := range p.DataSourcesMap {
|
2016-04-17 02:27:00 +02:00
|
|
|
if err := r.InternalValidate(nil, false); err != nil {
|
2016-08-27 11:33:19 +02:00
|
|
|
validationErrors = multierror.Append(validationErrors, fmt.Errorf("data source %s: %s", k, err))
|
core: New ResourceProvider methods for data resources
This is a breaking change to the ResourceProvider interface that adds the
new operations relating to data sources.
DataSources, ValidateDataSource, ReadDataDiff and ReadDataApply are the
data source equivalents of Resources, Validate, Diff and Apply (respectively)
for managed resources.
The diff/apply model seems at first glance a rather strange workflow for
read-only resources, but implementing data resources in this way allows them
to fit cleanly into the standard plan/apply lifecycle in cases where the
configuration contains computed arguments and thus the read must be deferred
until apply time.
Along with breaking the interface, we also fix up the plugin client/server
and helper/schema implementations of it, which are all of the callers
used when provider plugins use helper/schema. This would be a breaking
change for any provider plugin that directly implements the provider
interface, but no known plugins do this and it is not recommended.
At the helper/schema layer the implementer sees ReadDataApply as a "Read",
as opposed to "Create" or "Update" as in the managed resource Apply
implementation. The planning mechanics are handled entirely within
helper/schema, so that complexity is hidden from the provider implementation
itself.
2016-05-08 06:55:32 +02:00
|
|
|
}
|
2014-08-18 18:32:40 +02:00
|
|
|
}
|
|
|
|
|
2016-08-27 11:33:19 +02:00
|
|
|
return validationErrors
|
2014-08-18 18:32:40 +02:00
|
|
|
}
|
|
|
|
|
2017-07-11 06:51:55 +02:00
|
|
|
func isReservedProviderFieldName(name string) bool {
|
|
|
|
for _, reservedName := range config.ReservedProviderFields {
|
|
|
|
if name == reservedName {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2014-08-18 18:32:40 +02:00
|
|
|
// 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-20 00:26:31 +02:00
|
|
|
// SetMeta can be used to forcefully set the Meta object of the provider.
|
|
|
|
// Note that if Configure is called the return value will override anything
|
|
|
|
// set here.
|
|
|
|
func (p *Provider) SetMeta(v interface{}) {
|
|
|
|
p.meta = v
|
|
|
|
}
|
|
|
|
|
2016-10-24 03:07:17 +02:00
|
|
|
// Stopped reports whether the provider has been stopped or not.
|
|
|
|
func (p *Provider) Stopped() bool {
|
2016-10-25 20:29:24 +02:00
|
|
|
ctx := p.StopContext()
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return true
|
|
|
|
default:
|
|
|
|
return false
|
|
|
|
}
|
2016-10-24 03:07:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// StopCh returns a channel that is closed once the provider is stopped.
|
2016-10-25 20:29:24 +02:00
|
|
|
func (p *Provider) StopContext() context.Context {
|
|
|
|
p.stopOnce.Do(p.stopInit)
|
2017-03-07 15:19:02 +01:00
|
|
|
|
|
|
|
p.stopMu.Lock()
|
|
|
|
defer p.stopMu.Unlock()
|
|
|
|
|
2016-10-25 20:29:24 +02:00
|
|
|
return p.stopCtx
|
|
|
|
}
|
2016-10-24 03:07:17 +02:00
|
|
|
|
2016-10-25 20:29:24 +02:00
|
|
|
func (p *Provider) stopInit() {
|
2017-03-07 15:19:02 +01:00
|
|
|
p.stopMu.Lock()
|
|
|
|
defer p.stopMu.Unlock()
|
|
|
|
|
2016-10-25 20:29:24 +02:00
|
|
|
p.stopCtx, p.stopCtxCancel = context.WithCancel(context.Background())
|
2016-10-24 03:07:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Stop implementation of terraform.ResourceProvider interface.
|
|
|
|
func (p *Provider) Stop() error {
|
2016-10-25 20:29:24 +02:00
|
|
|
p.stopOnce.Do(p.stopInit)
|
2017-03-07 15:19:02 +01:00
|
|
|
|
|
|
|
p.stopMu.Lock()
|
|
|
|
defer p.stopMu.Unlock()
|
|
|
|
|
2016-10-25 20:29:24 +02:00
|
|
|
p.stopCtxCancel()
|
2016-10-24 03:07:17 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-03-07 15:19:02 +01:00
|
|
|
// TestReset resets any state stored in the Provider, and will call TestReset
|
|
|
|
// on Meta if it implements the TestProvider interface.
|
|
|
|
// This may be used to reset the schema.Provider at the start of a test, and is
|
|
|
|
// automatically called by resource.Test.
|
|
|
|
func (p *Provider) TestReset() error {
|
|
|
|
p.stopInit()
|
|
|
|
if p.MetaReset != nil {
|
|
|
|
return p.MetaReset()
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-10-14 03:43:08 +02:00
|
|
|
// GetSchema implementation of terraform.ResourceProvider interface
|
|
|
|
func (p *Provider) GetSchema(req *terraform.ProviderSchemaRequest) (*terraform.ProviderSchema, error) {
|
|
|
|
resourceTypes := map[string]*configschema.Block{}
|
|
|
|
dataSources := map[string]*configschema.Block{}
|
|
|
|
|
|
|
|
for _, name := range req.ResourceTypes {
|
|
|
|
if r, exists := p.ResourcesMap[name]; exists {
|
|
|
|
resourceTypes[name] = r.CoreConfigSchema()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, name := range req.DataSources {
|
|
|
|
if r, exists := p.DataSourcesMap[name]; exists {
|
|
|
|
dataSources[name] = r.CoreConfigSchema()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &terraform.ProviderSchema{
|
|
|
|
Provider: schemaMap(p.Schema).CoreConfigSchema(),
|
|
|
|
ResourceTypes: resourceTypes,
|
|
|
|
DataSources: dataSources,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2014-09-29 19:25:43 +02:00
|
|
|
// Input implementation of terraform.ResourceProvider interface.
|
|
|
|
func (p *Provider) Input(
|
|
|
|
input terraform.UIInput,
|
|
|
|
c *terraform.ResourceConfig) (*terraform.ResourceConfig, error) {
|
|
|
|
return schemaMap(p.Schema).Input(input, c)
|
|
|
|
}
|
|
|
|
|
2014-08-27 06:52:09 +02:00
|
|
|
// Validate implementation of terraform.ResourceProvider interface.
|
2014-08-17 23:45:43 +02:00
|
|
|
func (p *Provider) Validate(c *terraform.ResourceConfig) ([]string, []error) {
|
2015-06-24 01:52:04 +02:00
|
|
|
if err := p.InternalValidate(); err != nil {
|
|
|
|
return nil, []error{fmt.Errorf(
|
|
|
|
"Internal validation of the provider failed! This is always a bug\n"+
|
|
|
|
"with the provider itself, and not a user issue. Please report\n"+
|
|
|
|
"this bug:\n\n%s", err)}
|
|
|
|
}
|
|
|
|
|
2014-08-17 23:45:43 +02:00
|
|
|
return schemaMap(p.Schema).Validate(c)
|
|
|
|
}
|
|
|
|
|
2014-08-27 06:52:09 +02:00
|
|
|
// ValidateResource implementation of terraform.ResourceProvider interface.
|
2014-08-17 23:45:43 +02:00
|
|
|
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.
|
2018-10-16 01:29:37 +02:00
|
|
|
diff, err := sm.Diff(nil, c, nil, p.meta, true)
|
2014-08-18 00:01:27 +02:00
|
|
|
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(
|
2014-09-17 02:07:13 +02:00
|
|
|
info *terraform.InstanceInfo,
|
|
|
|
s *terraform.InstanceState,
|
2014-09-18 01:33:24 +02:00
|
|
|
d *terraform.InstanceDiff) (*terraform.InstanceState, error) {
|
2014-09-17 02:07:13 +02:00
|
|
|
r, ok := p.ResourcesMap[info.Type]
|
2014-08-18 05:23:25 +02:00
|
|
|
if !ok {
|
2014-09-17 02:07:13 +02:00
|
|
|
return nil, fmt.Errorf("unknown resource type: %s", info.Type)
|
2014-08-18 05:23:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return r.Apply(s, d, p.meta)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Diff implementation of terraform.ResourceProvider interface.
|
|
|
|
func (p *Provider) Diff(
|
2014-09-17 02:07:13 +02:00
|
|
|
info *terraform.InstanceInfo,
|
|
|
|
s *terraform.InstanceState,
|
2014-09-18 01:33:24 +02:00
|
|
|
c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
|
2014-09-17 02:07:13 +02:00
|
|
|
r, ok := p.ResourcesMap[info.Type]
|
2014-08-18 05:23:25 +02:00
|
|
|
if !ok {
|
2014-09-17 02:07:13 +02:00
|
|
|
return nil, fmt.Errorf("unknown resource type: %s", info.Type)
|
2014-08-18 05:23:25 +02:00
|
|
|
}
|
|
|
|
|
2017-05-28 07:58:44 +02:00
|
|
|
return r.Diff(s, c, p.meta)
|
2014-08-18 05:23:25 +02:00
|
|
|
}
|
|
|
|
|
2018-10-16 01:29:37 +02:00
|
|
|
// SimpleDiff is used by the new protocol wrappers to get a diff that doesn't
|
|
|
|
// attempt to calculate ignore_changes.
|
|
|
|
func (p *Provider) SimpleDiff(
|
|
|
|
info *terraform.InstanceInfo,
|
|
|
|
s *terraform.InstanceState,
|
|
|
|
c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
|
|
|
|
r, ok := p.ResourcesMap[info.Type]
|
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("unknown resource type: %s", info.Type)
|
|
|
|
}
|
|
|
|
|
|
|
|
return r.simpleDiff(s, c, p.meta)
|
|
|
|
}
|
|
|
|
|
2014-08-18 05:23:25 +02:00
|
|
|
// Refresh implementation of terraform.ResourceProvider interface.
|
|
|
|
func (p *Provider) Refresh(
|
2014-09-17 02:07:13 +02:00
|
|
|
info *terraform.InstanceInfo,
|
|
|
|
s *terraform.InstanceState) (*terraform.InstanceState, error) {
|
|
|
|
r, ok := p.ResourcesMap[info.Type]
|
2014-08-18 05:23:25 +02:00
|
|
|
if !ok {
|
2014-09-17 02:07:13 +02:00
|
|
|
return nil, fmt.Errorf("unknown resource type: %s", info.Type)
|
2014-08-18 05:23:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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))
|
2018-10-16 01:29:37 +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 {
|
2016-04-26 18:39:39 +02:00
|
|
|
resource := p.ResourcesMap[k]
|
|
|
|
|
|
|
|
// This isn't really possible (it'd fail InternalValidate), but
|
|
|
|
// we do it anyways to avoid a panic.
|
|
|
|
if resource == nil {
|
|
|
|
resource = &Resource{}
|
|
|
|
}
|
|
|
|
|
2014-08-18 00:07:01 +02:00
|
|
|
result = append(result, terraform.ResourceType{
|
2016-04-26 18:39:39 +02:00
|
|
|
Name: k,
|
|
|
|
Importable: resource.Importer != nil,
|
2017-10-14 03:43:08 +02:00
|
|
|
|
|
|
|
// Indicates that a provider is compiled against a new enough
|
|
|
|
// version of core to support the GetSchema method.
|
|
|
|
SchemaAvailable: true,
|
2014-08-18 00:07:01 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
2016-04-26 21:25:50 +02:00
|
|
|
|
2016-05-01 01:36:31 +02:00
|
|
|
func (p *Provider) ImportState(
|
2016-05-04 21:42:02 +02:00
|
|
|
info *terraform.InstanceInfo,
|
|
|
|
id string) ([]*terraform.InstanceState, error) {
|
2016-05-01 01:36:31 +02:00
|
|
|
// Find the resource
|
|
|
|
r, ok := p.ResourcesMap[info.Type]
|
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("unknown resource type: %s", info.Type)
|
|
|
|
}
|
|
|
|
|
|
|
|
// If it doesn't support import, error
|
|
|
|
if r.Importer == nil {
|
|
|
|
return nil, fmt.Errorf("resource %s doesn't support import", info.Type)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the data
|
|
|
|
data := r.Data(nil)
|
2016-05-04 21:42:02 +02:00
|
|
|
data.SetId(id)
|
2016-05-01 01:36:31 +02:00
|
|
|
data.SetType(info.Type)
|
|
|
|
|
|
|
|
// Call the import function
|
2016-05-04 21:56:45 +02:00
|
|
|
results := []*ResourceData{data}
|
|
|
|
if r.Importer.State != nil {
|
|
|
|
var err error
|
|
|
|
results, err = r.Importer.State(data, p.meta)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2016-05-01 01:36:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Convert the results to InstanceState values and return it
|
|
|
|
states := make([]*terraform.InstanceState, len(results))
|
|
|
|
for i, r := range results {
|
|
|
|
states[i] = r.State()
|
|
|
|
}
|
|
|
|
|
2016-05-04 20:18:45 +02:00
|
|
|
// Verify that all are non-nil. If there are any nil the error
|
|
|
|
// isn't obvious so we circumvent that with a friendlier error.
|
|
|
|
for _, s := range states {
|
|
|
|
if s == nil {
|
|
|
|
return nil, fmt.Errorf(
|
|
|
|
"nil entry in ImportState results. This is always a bug with\n" +
|
|
|
|
"the resource that is being imported. Please report this as\n" +
|
|
|
|
"a bug to Terraform.")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-01 01:36:31 +02:00
|
|
|
return states, nil
|
2016-04-26 21:25:50 +02:00
|
|
|
}
|
core: New ResourceProvider methods for data resources
This is a breaking change to the ResourceProvider interface that adds the
new operations relating to data sources.
DataSources, ValidateDataSource, ReadDataDiff and ReadDataApply are the
data source equivalents of Resources, Validate, Diff and Apply (respectively)
for managed resources.
The diff/apply model seems at first glance a rather strange workflow for
read-only resources, but implementing data resources in this way allows them
to fit cleanly into the standard plan/apply lifecycle in cases where the
configuration contains computed arguments and thus the read must be deferred
until apply time.
Along with breaking the interface, we also fix up the plugin client/server
and helper/schema implementations of it, which are all of the callers
used when provider plugins use helper/schema. This would be a breaking
change for any provider plugin that directly implements the provider
interface, but no known plugins do this and it is not recommended.
At the helper/schema layer the implementer sees ReadDataApply as a "Read",
as opposed to "Create" or "Update" as in the managed resource Apply
implementation. The planning mechanics are handled entirely within
helper/schema, so that complexity is hidden from the provider implementation
itself.
2016-05-08 06:55:32 +02:00
|
|
|
|
|
|
|
// ValidateDataSource implementation of terraform.ResourceProvider interface.
|
|
|
|
func (p *Provider) ValidateDataSource(
|
|
|
|
t string, c *terraform.ResourceConfig) ([]string, []error) {
|
|
|
|
r, ok := p.DataSourcesMap[t]
|
|
|
|
if !ok {
|
|
|
|
return nil, []error{fmt.Errorf(
|
|
|
|
"Provider doesn't support data source: %s", t)}
|
|
|
|
}
|
|
|
|
|
|
|
|
return r.Validate(c)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ReadDataDiff implementation of terraform.ResourceProvider interface.
|
|
|
|
func (p *Provider) ReadDataDiff(
|
|
|
|
info *terraform.InstanceInfo,
|
|
|
|
c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
|
|
|
|
|
|
|
|
r, ok := p.DataSourcesMap[info.Type]
|
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("unknown data source: %s", info.Type)
|
|
|
|
}
|
|
|
|
|
2017-05-28 07:58:44 +02:00
|
|
|
return r.Diff(nil, c, p.meta)
|
core: New ResourceProvider methods for data resources
This is a breaking change to the ResourceProvider interface that adds the
new operations relating to data sources.
DataSources, ValidateDataSource, ReadDataDiff and ReadDataApply are the
data source equivalents of Resources, Validate, Diff and Apply (respectively)
for managed resources.
The diff/apply model seems at first glance a rather strange workflow for
read-only resources, but implementing data resources in this way allows them
to fit cleanly into the standard plan/apply lifecycle in cases where the
configuration contains computed arguments and thus the read must be deferred
until apply time.
Along with breaking the interface, we also fix up the plugin client/server
and helper/schema implementations of it, which are all of the callers
used when provider plugins use helper/schema. This would be a breaking
change for any provider plugin that directly implements the provider
interface, but no known plugins do this and it is not recommended.
At the helper/schema layer the implementer sees ReadDataApply as a "Read",
as opposed to "Create" or "Update" as in the managed resource Apply
implementation. The planning mechanics are handled entirely within
helper/schema, so that complexity is hidden from the provider implementation
itself.
2016-05-08 06:55:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// RefreshData implementation of terraform.ResourceProvider interface.
|
|
|
|
func (p *Provider) ReadDataApply(
|
|
|
|
info *terraform.InstanceInfo,
|
|
|
|
d *terraform.InstanceDiff) (*terraform.InstanceState, error) {
|
|
|
|
|
|
|
|
r, ok := p.DataSourcesMap[info.Type]
|
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("unknown data source: %s", info.Type)
|
|
|
|
}
|
|
|
|
|
|
|
|
return r.ReadDataApply(d, p.meta)
|
|
|
|
}
|
|
|
|
|
|
|
|
// DataSources implementation of terraform.ResourceProvider interface.
|
|
|
|
func (p *Provider) DataSources() []terraform.DataSource {
|
|
|
|
keys := make([]string, 0, len(p.DataSourcesMap))
|
|
|
|
for k, _ := range p.DataSourcesMap {
|
|
|
|
keys = append(keys, k)
|
|
|
|
}
|
|
|
|
sort.Strings(keys)
|
|
|
|
|
|
|
|
result := make([]terraform.DataSource, 0, len(keys))
|
|
|
|
for _, k := range keys {
|
|
|
|
result = append(result, terraform.DataSource{
|
|
|
|
Name: k,
|
2017-10-14 03:43:08 +02:00
|
|
|
|
|
|
|
// Indicates that a provider is compiled against a new enough
|
|
|
|
// version of core to support the GetSchema method.
|
|
|
|
SchemaAvailable: true,
|
core: New ResourceProvider methods for data resources
This is a breaking change to the ResourceProvider interface that adds the
new operations relating to data sources.
DataSources, ValidateDataSource, ReadDataDiff and ReadDataApply are the
data source equivalents of Resources, Validate, Diff and Apply (respectively)
for managed resources.
The diff/apply model seems at first glance a rather strange workflow for
read-only resources, but implementing data resources in this way allows them
to fit cleanly into the standard plan/apply lifecycle in cases where the
configuration contains computed arguments and thus the read must be deferred
until apply time.
Along with breaking the interface, we also fix up the plugin client/server
and helper/schema implementations of it, which are all of the callers
used when provider plugins use helper/schema. This would be a breaking
change for any provider plugin that directly implements the provider
interface, but no known plugins do this and it is not recommended.
At the helper/schema layer the implementer sees ReadDataApply as a "Read",
as opposed to "Create" or "Update" as in the managed resource Apply
implementation. The planning mechanics are handled entirely within
helper/schema, so that complexity is hidden from the provider implementation
itself.
2016-05-08 06:55:32 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|