github.com/loicalbertin/terraform@v0.6.15-0.20170626182346-8e2583055467/terraform/resource_provider.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  
     6  	multierror "github.com/hashicorp/go-multierror"
     7  	"github.com/hashicorp/terraform/plugin/discovery"
     8  )
     9  
    10  // ResourceProvider is an interface that must be implemented by any
    11  // resource provider: the thing that creates and manages the resources in
    12  // a Terraform configuration.
    13  //
    14  // Important implementation note: All returned pointers, such as
    15  // *ResourceConfig, *InstanceState, *InstanceDiff, etc. must not point to
    16  // shared data. Terraform is highly parallel and assumes that this data is safe
    17  // to read/write in parallel so it must be unique references. Note that it is
    18  // safe to return arguments as results, however.
    19  type ResourceProvider interface {
    20  	/*********************************************************************
    21  	* Functions related to the provider
    22  	*********************************************************************/
    23  
    24  	// Input is called to ask the provider to ask the user for input
    25  	// for completing the configuration if necesarry.
    26  	//
    27  	// This may or may not be called, so resource provider writers shouldn't
    28  	// rely on this being available to set some default values for validate
    29  	// later. Example of a situation where this wouldn't be called is if
    30  	// the user is not using a TTY.
    31  	Input(UIInput, *ResourceConfig) (*ResourceConfig, error)
    32  
    33  	// Validate is called once at the beginning with the raw configuration
    34  	// (no interpolation done) and can return a list of warnings and/or
    35  	// errors.
    36  	//
    37  	// This is called once with the provider configuration only. It may not
    38  	// be called at all if no provider configuration is given.
    39  	//
    40  	// This should not assume that any values of the configurations are valid.
    41  	// The primary use case of this call is to check that required keys are
    42  	// set.
    43  	Validate(*ResourceConfig) ([]string, []error)
    44  
    45  	// Configure configures the provider itself with the configuration
    46  	// given. This is useful for setting things like access keys.
    47  	//
    48  	// This won't be called at all if no provider configuration is given.
    49  	//
    50  	// Configure returns an error if it occurred.
    51  	Configure(*ResourceConfig) error
    52  
    53  	// Resources returns all the available resource types that this provider
    54  	// knows how to manage.
    55  	Resources() []ResourceType
    56  
    57  	// Stop is called when the provider should halt any in-flight actions.
    58  	//
    59  	// This can be used to make a nicer Ctrl-C experience for Terraform.
    60  	// Even if this isn't implemented to do anything (just returns nil),
    61  	// Terraform will still cleanly stop after the currently executing
    62  	// graph node is complete. However, this API can be used to make more
    63  	// efficient halts.
    64  	//
    65  	// Stop doesn't have to and shouldn't block waiting for in-flight actions
    66  	// to complete. It should take any action it wants and return immediately
    67  	// acknowledging it has received the stop request. Terraform core will
    68  	// automatically not make any further API calls to the provider soon
    69  	// after Stop is called (technically exactly once the currently executing
    70  	// graph nodes are complete).
    71  	//
    72  	// The error returned, if non-nil, is assumed to mean that signaling the
    73  	// stop somehow failed and that the user should expect potentially waiting
    74  	// a longer period of time.
    75  	Stop() error
    76  
    77  	/*********************************************************************
    78  	* Functions related to individual resources
    79  	*********************************************************************/
    80  
    81  	// ValidateResource is called once at the beginning with the raw
    82  	// configuration (no interpolation done) and can return a list of warnings
    83  	// and/or errors.
    84  	//
    85  	// This is called once per resource.
    86  	//
    87  	// This should not assume any of the values in the resource configuration
    88  	// are valid since it is possible they have to be interpolated still.
    89  	// The primary use case of this call is to check that the required keys
    90  	// are set and that the general structure is correct.
    91  	ValidateResource(string, *ResourceConfig) ([]string, []error)
    92  
    93  	// Apply applies a diff to a specific resource and returns the new
    94  	// resource state along with an error.
    95  	//
    96  	// If the resource state given has an empty ID, then a new resource
    97  	// is expected to be created.
    98  	Apply(
    99  		*InstanceInfo,
   100  		*InstanceState,
   101  		*InstanceDiff) (*InstanceState, error)
   102  
   103  	// Diff diffs a resource versus a desired state and returns
   104  	// a diff.
   105  	Diff(
   106  		*InstanceInfo,
   107  		*InstanceState,
   108  		*ResourceConfig) (*InstanceDiff, error)
   109  
   110  	// Refresh refreshes a resource and updates all of its attributes
   111  	// with the latest information.
   112  	Refresh(*InstanceInfo, *InstanceState) (*InstanceState, error)
   113  
   114  	/*********************************************************************
   115  	* Functions related to importing
   116  	*********************************************************************/
   117  
   118  	// ImportState requests that the given resource be imported.
   119  	//
   120  	// The returned InstanceState only requires ID be set. Importing
   121  	// will always call Refresh after the state to complete it.
   122  	//
   123  	// IMPORTANT: InstanceState doesn't have the resource type attached
   124  	// to it. A type must be specified on the state via the Ephemeral
   125  	// field on the state.
   126  	//
   127  	// This function can return multiple states. Normally, an import
   128  	// will map 1:1 to a physical resource. However, some resources map
   129  	// to multiple. For example, an AWS security group may contain many rules.
   130  	// Each rule is represented by a separate resource in Terraform,
   131  	// therefore multiple states are returned.
   132  	ImportState(*InstanceInfo, string) ([]*InstanceState, error)
   133  
   134  	/*********************************************************************
   135  	* Functions related to data resources
   136  	*********************************************************************/
   137  
   138  	// ValidateDataSource is called once at the beginning with the raw
   139  	// configuration (no interpolation done) and can return a list of warnings
   140  	// and/or errors.
   141  	//
   142  	// This is called once per data source instance.
   143  	//
   144  	// This should not assume any of the values in the resource configuration
   145  	// are valid since it is possible they have to be interpolated still.
   146  	// The primary use case of this call is to check that the required keys
   147  	// are set and that the general structure is correct.
   148  	ValidateDataSource(string, *ResourceConfig) ([]string, []error)
   149  
   150  	// DataSources returns all of the available data sources that this
   151  	// provider implements.
   152  	DataSources() []DataSource
   153  
   154  	// ReadDataDiff produces a diff that represents the state that will
   155  	// be produced when the given data source is read using a later call
   156  	// to ReadDataApply.
   157  	ReadDataDiff(*InstanceInfo, *ResourceConfig) (*InstanceDiff, error)
   158  
   159  	// ReadDataApply initializes a data instance using the configuration
   160  	// in a diff produced by ReadDataDiff.
   161  	ReadDataApply(*InstanceInfo, *InstanceDiff) (*InstanceState, error)
   162  }
   163  
   164  // ResourceProviderError may be returned when creating a Context if the
   165  // required providers cannot be satisfied. This error can then be used to
   166  // format a more useful message for the user.
   167  type ResourceProviderError struct {
   168  	Errors []error
   169  }
   170  
   171  func (e *ResourceProviderError) Error() string {
   172  	// use multierror to format the default output
   173  	return multierror.Append(nil, e.Errors...).Error()
   174  }
   175  
   176  // ResourceProviderCloser is an interface that providers that can close
   177  // connections that aren't needed anymore must implement.
   178  type ResourceProviderCloser interface {
   179  	Close() error
   180  }
   181  
   182  // ResourceType is a type of resource that a resource provider can manage.
   183  type ResourceType struct {
   184  	Name       string // Name of the resource, example "instance" (no provider prefix)
   185  	Importable bool   // Whether this resource supports importing
   186  }
   187  
   188  // DataSource is a data source that a resource provider implements.
   189  type DataSource struct {
   190  	Name string
   191  }
   192  
   193  // ResourceProviderResolver is an interface implemented by objects that are
   194  // able to resolve a given set of resource provider version constraints
   195  // into ResourceProviderFactory callbacks.
   196  type ResourceProviderResolver interface {
   197  	// Given a constraint map, return a ResourceProviderFactory for each
   198  	// requested provider. If some or all of the constraints cannot be
   199  	// satisfied, return a non-nil slice of errors describing the problems.
   200  	ResolveProviders(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error)
   201  }
   202  
   203  // ResourceProviderResolverFunc wraps a callback function and turns it into
   204  // a ResourceProviderResolver implementation, for convenience in situations
   205  // where a function and its associated closure are sufficient as a resolver
   206  // implementation.
   207  type ResourceProviderResolverFunc func(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error)
   208  
   209  // ResolveProviders implements ResourceProviderResolver by calling the
   210  // wrapped function.
   211  func (f ResourceProviderResolverFunc) ResolveProviders(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error) {
   212  	return f(reqd)
   213  }
   214  
   215  // ResourceProviderResolverFixed returns a ResourceProviderResolver that
   216  // has a fixed set of provider factories provided by the caller. The returned
   217  // resolver ignores version constraints entirely and just returns the given
   218  // factory for each requested provider name.
   219  //
   220  // This function is primarily used in tests, to provide mock providers or
   221  // in-process providers under test.
   222  func ResourceProviderResolverFixed(factories map[string]ResourceProviderFactory) ResourceProviderResolver {
   223  	return ResourceProviderResolverFunc(func(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error) {
   224  		ret := make(map[string]ResourceProviderFactory, len(reqd))
   225  		var errs []error
   226  		for name := range reqd {
   227  			if factory, exists := factories[name]; exists {
   228  				ret[name] = factory
   229  			} else {
   230  				errs = append(errs, fmt.Errorf("provider %q is not available", name))
   231  			}
   232  		}
   233  		return ret, errs
   234  	})
   235  }
   236  
   237  // ResourceProviderFactory is a function type that creates a new instance
   238  // of a resource provider.
   239  type ResourceProviderFactory func() (ResourceProvider, error)
   240  
   241  // ResourceProviderFactoryFixed is a helper that creates a
   242  // ResourceProviderFactory that just returns some fixed provider.
   243  func ResourceProviderFactoryFixed(p ResourceProvider) ResourceProviderFactory {
   244  	return func() (ResourceProvider, error) {
   245  		return p, nil
   246  	}
   247  }
   248  
   249  func ProviderHasResource(p ResourceProvider, n string) bool {
   250  	for _, rt := range p.Resources() {
   251  		if rt.Name == n {
   252  			return true
   253  		}
   254  	}
   255  
   256  	return false
   257  }
   258  
   259  func ProviderHasDataSource(p ResourceProvider, n string) bool {
   260  	for _, rt := range p.DataSources() {
   261  		if rt.Name == n {
   262  			return true
   263  		}
   264  	}
   265  
   266  	return false
   267  }
   268  
   269  // resourceProviderFactories matches available plugins to the given version
   270  // requirements to produce a map of compatible provider plugins if possible,
   271  // or an error if the currently-available plugins are insufficient.
   272  //
   273  // This should be called only with configurations that have passed calls
   274  // to config.Validate(), which ensures that all of the given version
   275  // constraints are valid. It will panic if any invalid constraints are present.
   276  func resourceProviderFactories(resolver ResourceProviderResolver, reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, error) {
   277  	ret, errs := resolver.ResolveProviders(reqd)
   278  	if errs != nil {
   279  		return nil, &ResourceProviderError{
   280  			Errors: errs,
   281  		}
   282  	}
   283  
   284  	return ret, nil
   285  }