]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/github.com/hashicorp/terraform/terraform/schemas.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / terraform / schemas.go
CommitLineData
15c0b25d
AP
1package terraform
2
3import (
107c1cdb
ND
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"
15c0b25d
AP
13)
14
107c1cdb
ND
15// Schemas is a container for various kinds of schema that Terraform needs
16// during processing.
15c0b25d 17type Schemas struct {
107c1cdb
ND
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.
27func (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.
36func (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.
53func (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.
63func (ss *Schemas) ProvisionerConfig(name string) *configschema.Block {
64 return ss.Provisioners[name]
15c0b25d
AP
65}
66
107c1cdb
ND
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.
15c0b25d 71//
107c1cdb
ND
72// If an error is returned, it may be a wrapped tfdiags.Diagnostics describing
73// errors across multiple separate objects. Errors here will usually indicate
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.
77func 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
92func 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
182func 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}
15c0b25d
AP
237
238// ProviderSchema represents the schema for a provider's own configuration
239// and the configuration for some or all of its resources and data sources.
240//
241// The completeness of this structure depends on how it was constructed.
242// When constructed for a configuration, it will generally include only
243// resource types and data sources used by that configuration.
244type ProviderSchema struct {
245 Provider *configschema.Block
246 ResourceTypes map[string]*configschema.Block
247 DataSources map[string]*configschema.Block
107c1cdb
ND
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.
254func (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.
269func (ps *ProviderSchema) SchemaForResourceAddr(addr addrs.Resource) (schema *configschema.Block, version uint64) {
270 return ps.SchemaForResourceType(addr.Mode, addr.Type)
15c0b25d
AP
271}
272
273// ProviderSchemaRequest is used to describe to a ResourceProvider which
274// aspects of schema are required, when calling the GetSchema method.
275type ProviderSchemaRequest struct {
276 ResourceTypes []string
277 DataSources []string
278}