diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/terraform/schemas.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/terraform/schemas.go | 256 |
1 files changed, 250 insertions, 6 deletions
diff --git a/vendor/github.com/hashicorp/terraform/terraform/schemas.go b/vendor/github.com/hashicorp/terraform/terraform/schemas.go index ec46efc..62991c8 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/schemas.go +++ b/vendor/github.com/hashicorp/terraform/terraform/schemas.go | |||
@@ -1,18 +1,239 @@ | |||
1 | package terraform | 1 | package terraform |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "github.com/hashicorp/terraform/config/configschema" | 4 | "fmt" |
5 | "log" | ||
6 | |||
7 | "github.com/hashicorp/terraform/addrs" | ||
8 | "github.com/hashicorp/terraform/configs" | ||
9 | "github.com/hashicorp/terraform/configs/configschema" | ||
10 | "github.com/hashicorp/terraform/providers" | ||
11 | "github.com/hashicorp/terraform/states" | ||
12 | "github.com/hashicorp/terraform/tfdiags" | ||
5 | ) | 13 | ) |
6 | 14 | ||
15 | // Schemas is a container for various kinds of schema that Terraform needs | ||
16 | // during processing. | ||
7 | type Schemas struct { | 17 | type Schemas struct { |
8 | Providers ProviderSchemas | 18 | Providers map[string]*ProviderSchema |
19 | Provisioners map[string]*configschema.Block | ||
20 | } | ||
21 | |||
22 | // ProviderSchema returns the entire ProviderSchema object that was produced | ||
23 | // by the plugin for the given provider, or nil if no such schema is available. | ||
24 | // | ||
25 | // It's usually better to go use the more precise methods offered by type | ||
26 | // Schemas to handle this detail automatically. | ||
27 | func (ss *Schemas) ProviderSchema(typeName string) *ProviderSchema { | ||
28 | if ss.Providers == nil { | ||
29 | return nil | ||
30 | } | ||
31 | return ss.Providers[typeName] | ||
32 | } | ||
33 | |||
34 | // ProviderConfig returns the schema for the provider configuration of the | ||
35 | // given provider type, or nil if no such schema is available. | ||
36 | func (ss *Schemas) ProviderConfig(typeName string) *configschema.Block { | ||
37 | ps := ss.ProviderSchema(typeName) | ||
38 | if ps == nil { | ||
39 | return nil | ||
40 | } | ||
41 | return ps.Provider | ||
42 | } | ||
43 | |||
44 | // ResourceTypeConfig returns the schema for the configuration of a given | ||
45 | // resource type belonging to a given provider type, or nil of no such | ||
46 | // schema is available. | ||
47 | // | ||
48 | // In many cases the provider type is inferrable from the resource type name, | ||
49 | // but this is not always true because users can override the provider for | ||
50 | // a resource using the "provider" meta-argument. Therefore it's important to | ||
51 | // always pass the correct provider name, even though it many cases it feels | ||
52 | // redundant. | ||
53 | func (ss *Schemas) ResourceTypeConfig(providerType string, resourceMode addrs.ResourceMode, resourceType string) (block *configschema.Block, schemaVersion uint64) { | ||
54 | ps := ss.ProviderSchema(providerType) | ||
55 | if ps == nil || ps.ResourceTypes == nil { | ||
56 | return nil, 0 | ||
57 | } | ||
58 | return ps.SchemaForResourceType(resourceMode, resourceType) | ||
59 | } | ||
60 | |||
61 | // ProvisionerConfig returns the schema for the configuration of a given | ||
62 | // provisioner, or nil of no such schema is available. | ||
63 | func (ss *Schemas) ProvisionerConfig(name string) *configschema.Block { | ||
64 | return ss.Provisioners[name] | ||
9 | } | 65 | } |
10 | 66 | ||
11 | // ProviderSchemas is a map from provider names to provider schemas. | 67 | // LoadSchemas searches the given configuration, state and plan (any of which |
68 | // may be nil) for constructs that have an associated schema, requests the | ||
69 | // necessary schemas from the given component factory (which must _not_ be nil), | ||
70 | // and returns a single object representing all of the necessary schemas. | ||
12 | // | 71 | // |
13 | // The names in this map are the direct plugin name (e.g. "aws") rather than | 72 | // If an error is returned, it may be a wrapped tfdiags.Diagnostics describing |
14 | // any alias name (e.g. "aws.foo"), since. | 73 | // errors across multiple separate objects. Errors here will usually indicate |
15 | type ProviderSchemas map[string]*ProviderSchema | 74 | // either misbehavior on the part of one of the providers or of the provider |
75 | // protocol itself. When returned with errors, the returned schemas object is | ||
76 | // still valid but may be incomplete. | ||
77 | func LoadSchemas(config *configs.Config, state *states.State, components contextComponentFactory) (*Schemas, error) { | ||
78 | schemas := &Schemas{ | ||
79 | Providers: map[string]*ProviderSchema{}, | ||
80 | Provisioners: map[string]*configschema.Block{}, | ||
81 | } | ||
82 | var diags tfdiags.Diagnostics | ||
83 | |||
84 | newDiags := loadProviderSchemas(schemas.Providers, config, state, components) | ||
85 | diags = diags.Append(newDiags) | ||
86 | newDiags = loadProvisionerSchemas(schemas.Provisioners, config, components) | ||
87 | diags = diags.Append(newDiags) | ||
88 | |||
89 | return schemas, diags.Err() | ||
90 | } | ||
91 | |||
92 | func loadProviderSchemas(schemas map[string]*ProviderSchema, config *configs.Config, state *states.State, components contextComponentFactory) tfdiags.Diagnostics { | ||
93 | var diags tfdiags.Diagnostics | ||
94 | |||
95 | ensure := func(typeName string) { | ||
96 | if _, exists := schemas[typeName]; exists { | ||
97 | return | ||
98 | } | ||
99 | |||
100 | log.Printf("[TRACE] LoadSchemas: retrieving schema for provider type %q", typeName) | ||
101 | provider, err := components.ResourceProvider(typeName, "early/"+typeName) | ||
102 | if err != nil { | ||
103 | // We'll put a stub in the map so we won't re-attempt this on | ||
104 | // future calls. | ||
105 | schemas[typeName] = &ProviderSchema{} | ||
106 | diags = diags.Append( | ||
107 | fmt.Errorf("Failed to instantiate provider %q to obtain schema: %s", typeName, err), | ||
108 | ) | ||
109 | return | ||
110 | } | ||
111 | defer func() { | ||
112 | provider.Close() | ||
113 | }() | ||
114 | |||
115 | resp := provider.GetSchema() | ||
116 | if resp.Diagnostics.HasErrors() { | ||
117 | // We'll put a stub in the map so we won't re-attempt this on | ||
118 | // future calls. | ||
119 | schemas[typeName] = &ProviderSchema{} | ||
120 | diags = diags.Append( | ||
121 | fmt.Errorf("Failed to retrieve schema from provider %q: %s", typeName, resp.Diagnostics.Err()), | ||
122 | ) | ||
123 | return | ||
124 | } | ||
125 | |||
126 | s := &ProviderSchema{ | ||
127 | Provider: resp.Provider.Block, | ||
128 | ResourceTypes: make(map[string]*configschema.Block), | ||
129 | DataSources: make(map[string]*configschema.Block), | ||
130 | |||
131 | ResourceTypeSchemaVersions: make(map[string]uint64), | ||
132 | } | ||
133 | |||
134 | if resp.Provider.Version < 0 { | ||
135 | // We're not using the version numbers here yet, but we'll check | ||
136 | // for validity anyway in case we start using them in future. | ||
137 | diags = diags.Append( | ||
138 | fmt.Errorf("invalid negative schema version provider configuration for provider %q", typeName), | ||
139 | ) | ||
140 | } | ||
141 | |||
142 | for t, r := range resp.ResourceTypes { | ||
143 | s.ResourceTypes[t] = r.Block | ||
144 | s.ResourceTypeSchemaVersions[t] = uint64(r.Version) | ||
145 | if r.Version < 0 { | ||
146 | diags = diags.Append( | ||
147 | fmt.Errorf("invalid negative schema version for resource type %s in provider %q", t, typeName), | ||
148 | ) | ||
149 | } | ||
150 | } | ||
151 | |||
152 | for t, d := range resp.DataSources { | ||
153 | s.DataSources[t] = d.Block | ||
154 | if d.Version < 0 { | ||
155 | // We're not using the version numbers here yet, but we'll check | ||
156 | // for validity anyway in case we start using them in future. | ||
157 | diags = diags.Append( | ||
158 | fmt.Errorf("invalid negative schema version for data source %s in provider %q", t, typeName), | ||
159 | ) | ||
160 | } | ||
161 | } | ||
162 | |||
163 | schemas[typeName] = s | ||
164 | } | ||
165 | |||
166 | if config != nil { | ||
167 | for _, typeName := range config.ProviderTypes() { | ||
168 | ensure(typeName) | ||
169 | } | ||
170 | } | ||
171 | |||
172 | if state != nil { | ||
173 | needed := providers.AddressedTypesAbs(state.ProviderAddrs()) | ||
174 | for _, typeName := range needed { | ||
175 | ensure(typeName) | ||
176 | } | ||
177 | } | ||
178 | |||
179 | return diags | ||
180 | } | ||
181 | |||
182 | func loadProvisionerSchemas(schemas map[string]*configschema.Block, config *configs.Config, components contextComponentFactory) tfdiags.Diagnostics { | ||
183 | var diags tfdiags.Diagnostics | ||
184 | |||
185 | ensure := func(name string) { | ||
186 | if _, exists := schemas[name]; exists { | ||
187 | return | ||
188 | } | ||
189 | |||
190 | log.Printf("[TRACE] LoadSchemas: retrieving schema for provisioner %q", name) | ||
191 | provisioner, err := components.ResourceProvisioner(name, "early/"+name) | ||
192 | if err != nil { | ||
193 | // We'll put a stub in the map so we won't re-attempt this on | ||
194 | // future calls. | ||
195 | schemas[name] = &configschema.Block{} | ||
196 | diags = diags.Append( | ||
197 | fmt.Errorf("Failed to instantiate provisioner %q to obtain schema: %s", name, err), | ||
198 | ) | ||
199 | return | ||
200 | } | ||
201 | defer func() { | ||
202 | if closer, ok := provisioner.(ResourceProvisionerCloser); ok { | ||
203 | closer.Close() | ||
204 | } | ||
205 | }() | ||
206 | |||
207 | resp := provisioner.GetSchema() | ||
208 | if resp.Diagnostics.HasErrors() { | ||
209 | // We'll put a stub in the map so we won't re-attempt this on | ||
210 | // future calls. | ||
211 | schemas[name] = &configschema.Block{} | ||
212 | diags = diags.Append( | ||
213 | fmt.Errorf("Failed to retrieve schema from provisioner %q: %s", name, resp.Diagnostics.Err()), | ||
214 | ) | ||
215 | return | ||
216 | } | ||
217 | |||
218 | schemas[name] = resp.Provisioner | ||
219 | } | ||
220 | |||
221 | if config != nil { | ||
222 | for _, rc := range config.Module.ManagedResources { | ||
223 | for _, pc := range rc.Managed.Provisioners { | ||
224 | ensure(pc.Type) | ||
225 | } | ||
226 | } | ||
227 | |||
228 | // Must also visit our child modules, recursively. | ||
229 | for _, cc := range config.Children { | ||
230 | childDiags := loadProvisionerSchemas(schemas, cc, components) | ||
231 | diags = diags.Append(childDiags) | ||
232 | } | ||
233 | } | ||
234 | |||
235 | return diags | ||
236 | } | ||
16 | 237 | ||
17 | // ProviderSchema represents the schema for a provider's own configuration | 238 | // ProviderSchema represents the schema for a provider's own configuration |
18 | // and the configuration for some or all of its resources and data sources. | 239 | // and the configuration for some or all of its resources and data sources. |
@@ -24,6 +245,29 @@ type ProviderSchema struct { | |||
24 | Provider *configschema.Block | 245 | Provider *configschema.Block |
25 | ResourceTypes map[string]*configschema.Block | 246 | ResourceTypes map[string]*configschema.Block |
26 | DataSources map[string]*configschema.Block | 247 | DataSources map[string]*configschema.Block |
248 | |||
249 | ResourceTypeSchemaVersions map[string]uint64 | ||
250 | } | ||
251 | |||
252 | // SchemaForResourceType attempts to find a schema for the given mode and type. | ||
253 | // Returns nil if no such schema is available. | ||
254 | func (ps *ProviderSchema) SchemaForResourceType(mode addrs.ResourceMode, typeName string) (schema *configschema.Block, version uint64) { | ||
255 | switch mode { | ||
256 | case addrs.ManagedResourceMode: | ||
257 | return ps.ResourceTypes[typeName], ps.ResourceTypeSchemaVersions[typeName] | ||
258 | case addrs.DataResourceMode: | ||
259 | // Data resources don't have schema versions right now, since state is discarded for each refresh | ||
260 | return ps.DataSources[typeName], 0 | ||
261 | default: | ||
262 | // Shouldn't happen, because the above cases are comprehensive. | ||
263 | return nil, 0 | ||
264 | } | ||
265 | } | ||
266 | |||
267 | // SchemaForResourceAddr attempts to find a schema for the mode and type from | ||
268 | // the given resource address. Returns nil if no such schema is available. | ||
269 | func (ps *ProviderSchema) SchemaForResourceAddr(addr addrs.Resource) (schema *configschema.Block, version uint64) { | ||
270 | return ps.SchemaForResourceType(addr.Mode, addr.Type) | ||
27 | } | 271 | } |
28 | 272 | ||
29 | // ProviderSchemaRequest is used to describe to a ResourceProvider which | 273 | // ProviderSchemaRequest is used to describe to a ResourceProvider which |