mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-28 01:41:48 -06:00
0e0e3d73af
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.
179 lines
6.5 KiB
Go
179 lines
6.5 KiB
Go
package terraform
|
|
|
|
// ResourceProvider is an interface that must be implemented by any
|
|
// resource provider: the thing that creates and manages the resources in
|
|
// a Terraform configuration.
|
|
type ResourceProvider interface {
|
|
/*********************************************************************
|
|
* Functions related to the provider
|
|
*********************************************************************/
|
|
|
|
// Input is called to ask the provider to ask the user for input
|
|
// for completing the configuration if necesarry.
|
|
//
|
|
// This may or may not be called, so resource provider writers shouldn't
|
|
// rely on this being available to set some default values for validate
|
|
// later. Example of a situation where this wouldn't be called is if
|
|
// the user is not using a TTY.
|
|
Input(UIInput, *ResourceConfig) (*ResourceConfig, error)
|
|
|
|
// Validate is called once at the beginning with the raw configuration
|
|
// (no interpolation done) and can return a list of warnings and/or
|
|
// errors.
|
|
//
|
|
// This is called once with the provider configuration only. It may not
|
|
// be called at all if no provider configuration is given.
|
|
//
|
|
// This should not assume that any values of the configurations are valid.
|
|
// The primary use case of this call is to check that required keys are
|
|
// set.
|
|
Validate(*ResourceConfig) ([]string, []error)
|
|
|
|
// Configure configures the provider itself with the configuration
|
|
// given. This is useful for setting things like access keys.
|
|
//
|
|
// This won't be called at all if no provider configuration is given.
|
|
//
|
|
// Configure returns an error if it occurred.
|
|
Configure(*ResourceConfig) error
|
|
|
|
// Resources returns all the available resource types that this provider
|
|
// knows how to manage.
|
|
Resources() []ResourceType
|
|
|
|
/*********************************************************************
|
|
* Functions related to individual resources
|
|
*********************************************************************/
|
|
|
|
// ValidateResource is called once at the beginning with the raw
|
|
// configuration (no interpolation done) and can return a list of warnings
|
|
// and/or errors.
|
|
//
|
|
// This is called once per resource.
|
|
//
|
|
// This should not assume any of the values in the resource configuration
|
|
// are valid since it is possible they have to be interpolated still.
|
|
// The primary use case of this call is to check that the required keys
|
|
// are set and that the general structure is correct.
|
|
ValidateResource(string, *ResourceConfig) ([]string, []error)
|
|
|
|
// Apply applies a diff to a specific resource and returns the new
|
|
// resource state along with an error.
|
|
//
|
|
// If the resource state given has an empty ID, then a new resource
|
|
// is expected to be created.
|
|
Apply(
|
|
*InstanceInfo,
|
|
*InstanceState,
|
|
*InstanceDiff) (*InstanceState, error)
|
|
|
|
// Diff diffs a resource versus a desired state and returns
|
|
// a diff.
|
|
Diff(
|
|
*InstanceInfo,
|
|
*InstanceState,
|
|
*ResourceConfig) (*InstanceDiff, error)
|
|
|
|
// Refresh refreshes a resource and updates all of its attributes
|
|
// with the latest information.
|
|
Refresh(*InstanceInfo, *InstanceState) (*InstanceState, error)
|
|
|
|
/*********************************************************************
|
|
* Functions related to importing
|
|
*********************************************************************/
|
|
|
|
// ImportState requests that the given resource be imported.
|
|
//
|
|
// The returned InstanceState only requires ID be set. Importing
|
|
// will always call Refresh after the state to complete it.
|
|
//
|
|
// IMPORTANT: InstanceState doesn't have the resource type attached
|
|
// to it. A type must be specified on the state via the Ephemeral
|
|
// field on the state.
|
|
//
|
|
// This function can return multiple states. Normally, an import
|
|
// will map 1:1 to a physical resource. However, some resources map
|
|
// to multiple. For example, an AWS security group may contain many rules.
|
|
// Each rule is represented by a separate resource in Terraform,
|
|
// therefore multiple states are returned.
|
|
ImportState(*InstanceInfo, string) ([]*InstanceState, error)
|
|
|
|
/*********************************************************************
|
|
* Functions related to data resources
|
|
*********************************************************************/
|
|
|
|
// ValidateDataSource is called once at the beginning with the raw
|
|
// configuration (no interpolation done) and can return a list of warnings
|
|
// and/or errors.
|
|
//
|
|
// This is called once per data source instance.
|
|
//
|
|
// This should not assume any of the values in the resource configuration
|
|
// are valid since it is possible they have to be interpolated still.
|
|
// The primary use case of this call is to check that the required keys
|
|
// are set and that the general structure is correct.
|
|
ValidateDataSource(string, *ResourceConfig) ([]string, []error)
|
|
|
|
// DataSources returns all of the available data sources that this
|
|
// provider implements.
|
|
DataSources() []DataSource
|
|
|
|
// ReadDataDiff produces a diff that represents the state that will
|
|
// be produced when the given data source is read using a later call
|
|
// to ReadDataApply.
|
|
ReadDataDiff(*InstanceInfo, *ResourceConfig) (*InstanceDiff, error)
|
|
|
|
// ReadDataApply initializes a data instance using the configuration
|
|
// in a diff produced by ReadDataDiff.
|
|
ReadDataApply(*InstanceInfo, *InstanceDiff) (*InstanceState, error)
|
|
}
|
|
|
|
// ResourceProviderCloser is an interface that providers that can close
|
|
// connections that aren't needed anymore must implement.
|
|
type ResourceProviderCloser interface {
|
|
Close() error
|
|
}
|
|
|
|
// ResourceType is a type of resource that a resource provider can manage.
|
|
type ResourceType struct {
|
|
Name string // Name of the resource, example "instance" (no provider prefix)
|
|
Importable bool // Whether this resource supports importing
|
|
}
|
|
|
|
// DataSource is a data source that a resource provider implements.
|
|
type DataSource struct {
|
|
Name string
|
|
}
|
|
|
|
// ResourceProviderFactory is a function type that creates a new instance
|
|
// of a resource provider.
|
|
type ResourceProviderFactory func() (ResourceProvider, error)
|
|
|
|
// ResourceProviderFactoryFixed is a helper that creates a
|
|
// ResourceProviderFactory that just returns some fixed provider.
|
|
func ResourceProviderFactoryFixed(p ResourceProvider) ResourceProviderFactory {
|
|
return func() (ResourceProvider, error) {
|
|
return p, nil
|
|
}
|
|
}
|
|
|
|
func ProviderHasResource(p ResourceProvider, n string) bool {
|
|
for _, rt := range p.Resources() {
|
|
if rt.Name == n {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func ProviderHasDataSource(p ResourceProvider, n string) bool {
|
|
for _, rt := range p.DataSources() {
|
|
if rt.Name == n {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|