]>
Commit | Line | Data |
---|---|---|
107c1cdb ND |
1 | package providers |
2 | ||
3 | import ( | |
4 | "fmt" | |
5 | ||
6 | "github.com/hashicorp/terraform/plugin/discovery" | |
7 | ) | |
8 | ||
9 | // Resolver is an interface implemented by objects that are able to resolve | |
10 | // a given set of resource provider version constraints into Factory | |
11 | // callbacks. | |
12 | type Resolver interface { | |
13 | // Given a constraint map, return a Factory for each requested provider. | |
14 | // If some or all of the constraints cannot be satisfied, return a non-nil | |
15 | // slice of errors describing the problems. | |
16 | ResolveProviders(reqd discovery.PluginRequirements) (map[string]Factory, []error) | |
17 | } | |
18 | ||
19 | // ResolverFunc wraps a callback function and turns it into a Resolver | |
20 | // implementation, for convenience in situations where a function and its | |
21 | // associated closure are sufficient as a resolver implementation. | |
22 | type ResolverFunc func(reqd discovery.PluginRequirements) (map[string]Factory, []error) | |
23 | ||
24 | // ResolveProviders implements Resolver by calling the | |
25 | // wrapped function. | |
26 | func (f ResolverFunc) ResolveProviders(reqd discovery.PluginRequirements) (map[string]Factory, []error) { | |
27 | return f(reqd) | |
28 | } | |
29 | ||
30 | // ResolverFixed returns a Resolver that has a fixed set of provider factories | |
31 | // provided by the caller. The returned resolver ignores version constraints | |
32 | // entirely and just returns the given factory for each requested provider | |
33 | // name. | |
34 | // | |
35 | // This function is primarily used in tests, to provide mock providers or | |
36 | // in-process providers under test. | |
37 | func ResolverFixed(factories map[string]Factory) Resolver { | |
38 | return ResolverFunc(func(reqd discovery.PluginRequirements) (map[string]Factory, []error) { | |
39 | ret := make(map[string]Factory, len(reqd)) | |
40 | var errs []error | |
41 | for name := range reqd { | |
42 | if factory, exists := factories[name]; exists { | |
43 | ret[name] = factory | |
44 | } else { | |
45 | errs = append(errs, fmt.Errorf("provider %q is not available", name)) | |
46 | } | |
47 | } | |
48 | return ret, errs | |
49 | }) | |
50 | } | |
51 | ||
52 | // Factory is a function type that creates a new instance of a resource | |
53 | // provider, or returns an error if that is impossible. | |
54 | type Factory func() (Interface, error) | |
55 | ||
56 | // FactoryFixed is a helper that creates a Factory that just returns some given | |
57 | // single provider. | |
58 | // | |
59 | // Unlike usual factories, the exact same instance is returned for each call | |
60 | // to the factory and so this must be used in only specialized situations where | |
61 | // the caller can take care to either not mutate the given provider at all | |
62 | // or to mutate it in ways that will not cause unexpected behavior for others | |
63 | // holding the same reference. | |
64 | func FactoryFixed(p Interface) Factory { | |
65 | return func() (Interface, error) { | |
66 | return p, nil | |
67 | } | |
68 | } | |
69 | ||
70 | // ProviderHasResource is a helper that requests schema from the given provider | |
71 | // and checks if it has a resource type of the given name. | |
72 | // | |
73 | // This function is more expensive than it may first appear since it must | |
74 | // retrieve the entire schema from the underlying provider, and so it should | |
75 | // be used sparingly and especially not in tight loops. | |
76 | // | |
77 | // Since retrieving the provider may fail (e.g. if the provider is accessed | |
78 | // over an RPC channel that has operational problems), this function will | |
79 | // return false if the schema cannot be retrieved, under the assumption that | |
80 | // a subsequent call to do anything with the resource type would fail | |
81 | // anyway. | |
82 | func ProviderHasResource(provider Interface, typeName string) bool { | |
83 | resp := provider.GetSchema() | |
84 | if resp.Diagnostics.HasErrors() { | |
85 | return false | |
86 | } | |
87 | ||
88 | _, exists := resp.ResourceTypes[typeName] | |
89 | return exists | |
90 | } | |
91 | ||
92 | // ProviderHasDataSource is a helper that requests schema from the given | |
93 | // provider and checks if it has a data source of the given name. | |
94 | // | |
95 | // This function is more expensive than it may first appear since it must | |
96 | // retrieve the entire schema from the underlying provider, and so it should | |
97 | // be used sparingly and especially not in tight loops. | |
98 | // | |
99 | // Since retrieving the provider may fail (e.g. if the provider is accessed | |
100 | // over an RPC channel that has operational problems), this function will | |
101 | // return false if the schema cannot be retrieved, under the assumption that | |
102 | // a subsequent call to do anything with the data source would fail | |
103 | // anyway. | |
104 | func ProviderHasDataSource(provider Interface, dataSourceName string) bool { | |
105 | resp := provider.GetSchema() | |
106 | if resp.Diagnostics.HasErrors() { | |
107 | return false | |
108 | } | |
109 | ||
110 | _, exists := resp.DataSources[dataSourceName] | |
111 | return exists | |
112 | } |