]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/github.com/hashicorp/terraform/helper/schema/provisioner.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / helper / schema / provisioner.go
CommitLineData
bae9f6d2
JC
1package schema
2
3import (
4 "context"
5 "errors"
6 "fmt"
7 "sync"
8
9 "github.com/hashicorp/go-multierror"
10 "github.com/hashicorp/terraform/config"
107c1cdb 11 "github.com/hashicorp/terraform/configs/configschema"
bae9f6d2
JC
12 "github.com/hashicorp/terraform/terraform"
13)
14
15// Provisioner represents a resource provisioner in Terraform and properly
16// implements all of the ResourceProvisioner API.
17//
18// This higher level structure makes it much easier to implement a new or
19// custom provisioner for Terraform.
20//
21// The function callbacks for this structure are all passed a context object.
22// This context object has a number of pre-defined values that can be accessed
23// via the global functions defined in context.go.
24type Provisioner struct {
25 // ConnSchema is the schema for the connection settings for this
26 // provisioner.
27 //
28 // The keys of this map are the configuration keys, and the value is
29 // the schema describing the value of the configuration.
30 //
31 // NOTE: The value of connection keys can only be strings for now.
32 ConnSchema map[string]*Schema
33
34 // Schema is the schema for the usage of this provisioner.
35 //
36 // The keys of this map are the configuration keys, and the value is
37 // the schema describing the value of the configuration.
38 Schema map[string]*Schema
39
40 // ApplyFunc is the function for executing the provisioner. This is required.
41 // It is given a context. See the Provisioner struct docs for more
42 // information.
43 ApplyFunc func(ctx context.Context) error
44
9b12e4fe
JC
45 // ValidateFunc is a function for extended validation. This is optional
46 // and should be used when individual field validation is not enough.
c680a8e1 47 ValidateFunc func(*terraform.ResourceConfig) ([]string, []error)
9b12e4fe 48
bae9f6d2
JC
49 stopCtx context.Context
50 stopCtxCancel context.CancelFunc
51 stopOnce sync.Once
52}
53
54// Keys that can be used to access data in the context parameters for
55// Provisioners.
56var (
57 connDataInvalid = contextKey("data invalid")
58
59 // This returns a *ResourceData for the connection information.
60 // Guaranteed to never be nil.
61 ProvConnDataKey = contextKey("provider conn data")
62
63 // This returns a *ResourceData for the config information.
64 // Guaranteed to never be nil.
65 ProvConfigDataKey = contextKey("provider config data")
66
67 // This returns a terraform.UIOutput. Guaranteed to never be nil.
68 ProvOutputKey = contextKey("provider output")
69
70 // This returns the raw InstanceState passed to Apply. Guaranteed to
71 // be set, but may be nil.
72 ProvRawStateKey = contextKey("provider raw state")
73)
74
75// InternalValidate should be called to validate the structure
76// of the provisioner.
77//
78// This should be called in a unit test to verify before release that this
79// structure is properly configured for use.
80func (p *Provisioner) InternalValidate() error {
81 if p == nil {
82 return errors.New("provisioner is nil")
83 }
84
85 var validationErrors error
86 {
87 sm := schemaMap(p.ConnSchema)
88 if err := sm.InternalValidate(sm); err != nil {
89 validationErrors = multierror.Append(validationErrors, err)
90 }
91 }
92
93 {
94 sm := schemaMap(p.Schema)
95 if err := sm.InternalValidate(sm); err != nil {
96 validationErrors = multierror.Append(validationErrors, err)
97 }
98 }
99
100 if p.ApplyFunc == nil {
101 validationErrors = multierror.Append(validationErrors, fmt.Errorf(
102 "ApplyFunc must not be nil"))
103 }
104
105 return validationErrors
106}
107
108// StopContext returns a context that checks whether a provisioner is stopped.
109func (p *Provisioner) StopContext() context.Context {
110 p.stopOnce.Do(p.stopInit)
111 return p.stopCtx
112}
113
114func (p *Provisioner) stopInit() {
115 p.stopCtx, p.stopCtxCancel = context.WithCancel(context.Background())
116}
117
118// Stop implementation of terraform.ResourceProvisioner interface.
119func (p *Provisioner) Stop() error {
120 p.stopOnce.Do(p.stopInit)
121 p.stopCtxCancel()
122 return nil
123}
124
107c1cdb
ND
125// GetConfigSchema implementation of terraform.ResourceProvisioner interface.
126func (p *Provisioner) GetConfigSchema() (*configschema.Block, error) {
127 return schemaMap(p.Schema).CoreConfigSchema(), nil
128}
129
bae9f6d2
JC
130// Apply implementation of terraform.ResourceProvisioner interface.
131func (p *Provisioner) Apply(
132 o terraform.UIOutput,
133 s *terraform.InstanceState,
134 c *terraform.ResourceConfig) error {
135 var connData, configData *ResourceData
136
137 {
138 // We first need to turn the connection information into a
139 // terraform.ResourceConfig so that we can use that type to more
140 // easily build a ResourceData structure. We do this by simply treating
141 // the conn info as configuration input.
142 raw := make(map[string]interface{})
143 if s != nil {
144 for k, v := range s.Ephemeral.ConnInfo {
145 raw[k] = v
146 }
147 }
148
149 c, err := config.NewRawConfig(raw)
150 if err != nil {
151 return err
152 }
153
154 sm := schemaMap(p.ConnSchema)
107c1cdb 155 diff, err := sm.Diff(nil, terraform.NewResourceConfig(c), nil, nil, true)
bae9f6d2
JC
156 if err != nil {
157 return err
158 }
159 connData, err = sm.Data(nil, diff)
160 if err != nil {
161 return err
162 }
163 }
164
165 {
166 // Build the configuration data. Doing this requires making a "diff"
167 // even though that's never used. We use that just to get the correct types.
168 configMap := schemaMap(p.Schema)
107c1cdb 169 diff, err := configMap.Diff(nil, c, nil, nil, true)
bae9f6d2
JC
170 if err != nil {
171 return err
172 }
173 configData, err = configMap.Data(nil, diff)
174 if err != nil {
175 return err
176 }
177 }
178
179 // Build the context and call the function
180 ctx := p.StopContext()
181 ctx = context.WithValue(ctx, ProvConnDataKey, connData)
182 ctx = context.WithValue(ctx, ProvConfigDataKey, configData)
183 ctx = context.WithValue(ctx, ProvOutputKey, o)
184 ctx = context.WithValue(ctx, ProvRawStateKey, s)
185 return p.ApplyFunc(ctx)
186}
c680a8e1
RS
187
188// Validate implements the terraform.ResourceProvisioner interface.
189func (p *Provisioner) Validate(c *terraform.ResourceConfig) (ws []string, es []error) {
190 if err := p.InternalValidate(); err != nil {
191 return nil, []error{fmt.Errorf(
192 "Internal validation of the provisioner failed! This is always a bug\n"+
193 "with the provisioner itself, and not a user issue. Please report\n"+
194 "this bug:\n\n%s", err)}
195 }
196
197 if p.Schema != nil {
198 w, e := schemaMap(p.Schema).Validate(c)
199 ws = append(ws, w...)
200 es = append(es, e...)
201 }
202
203 if p.ValidateFunc != nil {
204 w, e := p.ValidateFunc(c)
205 ws = append(ws, w...)
206 es = append(es, e...)
207 }
208
209 return ws, es
210}