package terraform
+import (
+ "fmt"
+
+ "github.com/hashicorp/terraform/tfdiags"
+
+ "github.com/hashicorp/terraform/plugin/discovery"
+ "github.com/hashicorp/terraform/providers"
+)
+
// ResourceProvider is an interface that must be implemented by any
// resource provider: the thing that creates and manages the resources in
// a Terraform configuration.
* Functions related to the provider
*********************************************************************/
- // Input is called to ask the provider to ask the user for input
- // for completing the configuration if necesarry.
+ // ProviderSchema returns the config schema for the main provider
+ // configuration, as would appear in a "provider" block in the
+ // configuration files.
//
- // 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.
+ // Currently not all providers support schema. Callers must therefore
+ // first call Resources and DataSources and ensure that at least one
+ // resource or data source has the SchemaAvailable flag set.
+ GetSchema(*ProviderSchemaRequest) (*ProviderSchema, error)
+
+ // Input was used prior to v0.12 to ask the provider to prompt the user
+ // for input to complete the configuration.
+ //
+ // From v0.12 onwards this method is never called because Terraform Core
+ // is able to handle the necessary input logic itself based on the
+ // schema returned from GetSchema.
Input(UIInput, *ResourceConfig) (*ResourceConfig, error)
// Validate is called once at the beginning with the raw configuration
type ResourceType struct {
Name string // Name of the resource, example "instance" (no provider prefix)
Importable bool // Whether this resource supports importing
+
+ // SchemaAvailable is set if the provider supports the ProviderSchema,
+ // ResourceTypeSchema and DataSourceSchema methods. Although it is
+ // included on each resource type, it's actually a provider-wide setting
+ // that's smuggled here only because that avoids a breaking change to
+ // the plugin protocol.
+ SchemaAvailable bool
}
// DataSource is a data source that a resource provider implements.
type DataSource struct {
Name string
+
+ // SchemaAvailable is set if the provider supports the ProviderSchema,
+ // ResourceTypeSchema and DataSourceSchema methods. Although it is
+ // included on each resource type, it's actually a provider-wide setting
+ // that's smuggled here only because that avoids a breaking change to
+ // the plugin protocol.
+ SchemaAvailable bool
+}
+
+// ResourceProviderResolver is an interface implemented by objects that are
+// able to resolve a given set of resource provider version constraints
+// into ResourceProviderFactory callbacks.
+type ResourceProviderResolver interface {
+ // Given a constraint map, return a ResourceProviderFactory for each
+ // requested provider. If some or all of the constraints cannot be
+ // satisfied, return a non-nil slice of errors describing the problems.
+ ResolveProviders(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error)
+}
+
+// ResourceProviderResolverFunc wraps a callback function and turns it into
+// a ResourceProviderResolver implementation, for convenience in situations
+// where a function and its associated closure are sufficient as a resolver
+// implementation.
+type ResourceProviderResolverFunc func(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error)
+
+// ResolveProviders implements ResourceProviderResolver by calling the
+// wrapped function.
+func (f ResourceProviderResolverFunc) ResolveProviders(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error) {
+ return f(reqd)
+}
+
+// ResourceProviderResolverFixed returns a ResourceProviderResolver that
+// has a fixed set of provider factories provided by the caller. The returned
+// resolver ignores version constraints entirely and just returns the given
+// factory for each requested provider name.
+//
+// This function is primarily used in tests, to provide mock providers or
+// in-process providers under test.
+func ResourceProviderResolverFixed(factories map[string]ResourceProviderFactory) ResourceProviderResolver {
+ return ResourceProviderResolverFunc(func(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error) {
+ ret := make(map[string]ResourceProviderFactory, len(reqd))
+ var errs []error
+ for name := range reqd {
+ if factory, exists := factories[name]; exists {
+ ret[name] = factory
+ } else {
+ errs = append(errs, fmt.Errorf("provider %q is not available", name))
+ }
+ }
+ return ret, errs
+ })
}
// ResourceProviderFactory is a function type that creates a new instance
return false
}
+
+// resourceProviderFactories matches available plugins to the given version
+// requirements to produce a map of compatible provider plugins if possible,
+// or an error if the currently-available plugins are insufficient.
+//
+// This should be called only with configurations that have passed calls
+// to config.Validate(), which ensures that all of the given version
+// constraints are valid. It will panic if any invalid constraints are present.
+func resourceProviderFactories(resolver providers.Resolver, reqd discovery.PluginRequirements) (map[string]providers.Factory, tfdiags.Diagnostics) {
+ var diags tfdiags.Diagnostics
+ ret, errs := resolver.ResolveProviders(reqd)
+ if errs != nil {
+ diags = diags.Append(
+ tfdiags.Sourceless(tfdiags.Error,
+ "Could not satisfy plugin requirements",
+ errPluginInit,
+ ),
+ )
+
+ for _, err := range errs {
+ diags = diags.Append(err)
+ }
+
+ return nil, diags
+ }
+
+ return ret, nil
+}
+
+const errPluginInit = `
+Plugin reinitialization required. Please run "terraform init".
+
+Plugins are external binaries that Terraform uses to access and manipulate
+resources. The configuration provided requires plugins which can't be located,
+don't satisfy the version constraints, or are otherwise incompatible.
+
+Terraform automatically discovers provider requirements from your
+configuration, including providers used in child modules. To see the
+requirements and constraints from each module, run "terraform providers".
+`