package providers import ( "fmt" "github.com/hashicorp/terraform/plugin/discovery" ) // Resolver is an interface implemented by objects that are able to resolve // a given set of resource provider version constraints into Factory // callbacks. type Resolver interface { // Given a constraint map, return a Factory 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]Factory, []error) } // ResolverFunc wraps a callback function and turns it into a Resolver // implementation, for convenience in situations where a function and its // associated closure are sufficient as a resolver implementation. type ResolverFunc func(reqd discovery.PluginRequirements) (map[string]Factory, []error) // ResolveProviders implements Resolver by calling the // wrapped function. func (f ResolverFunc) ResolveProviders(reqd discovery.PluginRequirements) (map[string]Factory, []error) { return f(reqd) } // ResolverFixed returns a Resolver 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 ResolverFixed(factories map[string]Factory) Resolver { return ResolverFunc(func(reqd discovery.PluginRequirements) (map[string]Factory, []error) { ret := make(map[string]Factory, 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 }) } // Factory is a function type that creates a new instance of a resource // provider, or returns an error if that is impossible. type Factory func() (Interface, error) // FactoryFixed is a helper that creates a Factory that just returns some given // single provider. // // Unlike usual factories, the exact same instance is returned for each call // to the factory and so this must be used in only specialized situations where // the caller can take care to either not mutate the given provider at all // or to mutate it in ways that will not cause unexpected behavior for others // holding the same reference. func FactoryFixed(p Interface) Factory { return func() (Interface, error) { return p, nil } } // ProviderHasResource is a helper that requests schema from the given provider // and checks if it has a resource type of the given name. // // This function is more expensive than it may first appear since it must // retrieve the entire schema from the underlying provider, and so it should // be used sparingly and especially not in tight loops. // // Since retrieving the provider may fail (e.g. if the provider is accessed // over an RPC channel that has operational problems), this function will // return false if the schema cannot be retrieved, under the assumption that // a subsequent call to do anything with the resource type would fail // anyway. func ProviderHasResource(provider Interface, typeName string) bool { resp := provider.GetSchema() if resp.Diagnostics.HasErrors() { return false } _, exists := resp.ResourceTypes[typeName] return exists } // ProviderHasDataSource is a helper that requests schema from the given // provider and checks if it has a data source of the given name. // // This function is more expensive than it may first appear since it must // retrieve the entire schema from the underlying provider, and so it should // be used sparingly and especially not in tight loops. // // Since retrieving the provider may fail (e.g. if the provider is accessed // over an RPC channel that has operational problems), this function will // return false if the schema cannot be retrieved, under the assumption that // a subsequent call to do anything with the data source would fail // anyway. func ProviderHasDataSource(provider Interface, dataSourceName string) bool { resp := provider.GetSchema() if resp.Diagnostics.HasErrors() { return false } _, exists := resp.DataSources[dataSourceName] return exists }