github.com/paybyphone/terraform@v0.9.5-0.20170613192930-9706042ddd51/terraform/resource_provider.go (about)

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