]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/helper/schema/resource_timeout.go
Initial transfer of provider code
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / helper / schema / resource_timeout.go
1 package schema
2
3 import (
4 "fmt"
5 "log"
6 "time"
7
8 "github.com/hashicorp/terraform/terraform"
9 "github.com/mitchellh/copystructure"
10 )
11
12 const TimeoutKey = "e2bfb730-ecaa-11e6-8f88-34363bc7c4c0"
13 const TimeoutsConfigKey = "timeouts"
14
15 const (
16 TimeoutCreate = "create"
17 TimeoutRead = "read"
18 TimeoutUpdate = "update"
19 TimeoutDelete = "delete"
20 TimeoutDefault = "default"
21 )
22
23 func timeoutKeys() []string {
24 return []string{
25 TimeoutCreate,
26 TimeoutRead,
27 TimeoutUpdate,
28 TimeoutDelete,
29 TimeoutDefault,
30 }
31 }
32
33 // could be time.Duration, int64 or float64
34 func DefaultTimeout(tx interface{}) *time.Duration {
35 var td time.Duration
36 switch raw := tx.(type) {
37 case time.Duration:
38 return &raw
39 case int64:
40 td = time.Duration(raw)
41 case float64:
42 td = time.Duration(int64(raw))
43 default:
44 log.Printf("[WARN] Unknown type in DefaultTimeout: %#v", tx)
45 }
46 return &td
47 }
48
49 type ResourceTimeout struct {
50 Create, Read, Update, Delete, Default *time.Duration
51 }
52
53 // ConfigDecode takes a schema and the configuration (available in Diff) and
54 // validates, parses the timeouts into `t`
55 func (t *ResourceTimeout) ConfigDecode(s *Resource, c *terraform.ResourceConfig) error {
56 if s.Timeouts != nil {
57 raw, err := copystructure.Copy(s.Timeouts)
58 if err != nil {
59 log.Printf("[DEBUG] Error with deep copy: %s", err)
60 }
61 *t = *raw.(*ResourceTimeout)
62 }
63
64 if raw, ok := c.Config[TimeoutsConfigKey]; ok {
65 if configTimeouts, ok := raw.([]map[string]interface{}); ok {
66 for _, timeoutValues := range configTimeouts {
67 // loop through each Timeout given in the configuration and validate they
68 // the Timeout defined in the resource
69 for timeKey, timeValue := range timeoutValues {
70 // validate that we're dealing with the normal CRUD actions
71 var found bool
72 for _, key := range timeoutKeys() {
73 if timeKey == key {
74 found = true
75 break
76 }
77 }
78
79 if !found {
80 return fmt.Errorf("Unsupported Timeout configuration key found (%s)", timeKey)
81 }
82
83 // Get timeout
84 rt, err := time.ParseDuration(timeValue.(string))
85 if err != nil {
86 return fmt.Errorf("Error parsing Timeout for (%s): %s", timeKey, err)
87 }
88
89 var timeout *time.Duration
90 switch timeKey {
91 case TimeoutCreate:
92 timeout = t.Create
93 case TimeoutUpdate:
94 timeout = t.Update
95 case TimeoutRead:
96 timeout = t.Read
97 case TimeoutDelete:
98 timeout = t.Delete
99 case TimeoutDefault:
100 timeout = t.Default
101 }
102
103 // If the resource has not delcared this in the definition, then error
104 // with an unsupported message
105 if timeout == nil {
106 return unsupportedTimeoutKeyError(timeKey)
107 }
108
109 *timeout = rt
110 }
111 }
112 } else {
113 log.Printf("[WARN] Invalid Timeout structure found, skipping timeouts")
114 }
115 }
116
117 return nil
118 }
119
120 func unsupportedTimeoutKeyError(key string) error {
121 return fmt.Errorf("Timeout Key (%s) is not supported", key)
122 }
123
124 // DiffEncode, StateEncode, and MetaDecode are analogous to the Go stdlib JSONEncoder
125 // interface: they encode/decode a timeouts struct from an instance diff, which is
126 // where the timeout data is stored after a diff to pass into Apply.
127 //
128 // StateEncode encodes the timeout into the ResourceData's InstanceState for
129 // saving to state
130 //
131 func (t *ResourceTimeout) DiffEncode(id *terraform.InstanceDiff) error {
132 return t.metaEncode(id)
133 }
134
135 func (t *ResourceTimeout) StateEncode(is *terraform.InstanceState) error {
136 return t.metaEncode(is)
137 }
138
139 // metaEncode encodes the ResourceTimeout into a map[string]interface{} format
140 // and stores it in the Meta field of the interface it's given.
141 // Assumes the interface is either *terraform.InstanceState or
142 // *terraform.InstanceDiff, returns an error otherwise
143 func (t *ResourceTimeout) metaEncode(ids interface{}) error {
144 m := make(map[string]interface{})
145
146 if t.Create != nil {
147 m[TimeoutCreate] = t.Create.Nanoseconds()
148 }
149 if t.Read != nil {
150 m[TimeoutRead] = t.Read.Nanoseconds()
151 }
152 if t.Update != nil {
153 m[TimeoutUpdate] = t.Update.Nanoseconds()
154 }
155 if t.Delete != nil {
156 m[TimeoutDelete] = t.Delete.Nanoseconds()
157 }
158 if t.Default != nil {
159 m[TimeoutDefault] = t.Default.Nanoseconds()
160 // for any key above that is nil, if default is specified, we need to
161 // populate it with the default
162 for _, k := range timeoutKeys() {
163 if _, ok := m[k]; !ok {
164 m[k] = t.Default.Nanoseconds()
165 }
166 }
167 }
168
169 // only add the Timeout to the Meta if we have values
170 if len(m) > 0 {
171 switch instance := ids.(type) {
172 case *terraform.InstanceDiff:
173 if instance.Meta == nil {
174 instance.Meta = make(map[string]interface{})
175 }
176 instance.Meta[TimeoutKey] = m
177 case *terraform.InstanceState:
178 if instance.Meta == nil {
179 instance.Meta = make(map[string]interface{})
180 }
181 instance.Meta[TimeoutKey] = m
182 default:
183 return fmt.Errorf("Error matching type for Diff Encode")
184 }
185 }
186
187 return nil
188 }
189
190 func (t *ResourceTimeout) StateDecode(id *terraform.InstanceState) error {
191 return t.metaDecode(id)
192 }
193 func (t *ResourceTimeout) DiffDecode(is *terraform.InstanceDiff) error {
194 return t.metaDecode(is)
195 }
196
197 func (t *ResourceTimeout) metaDecode(ids interface{}) error {
198 var rawMeta interface{}
199 var ok bool
200 switch rawInstance := ids.(type) {
201 case *terraform.InstanceDiff:
202 rawMeta, ok = rawInstance.Meta[TimeoutKey]
203 if !ok {
204 return nil
205 }
206 case *terraform.InstanceState:
207 rawMeta, ok = rawInstance.Meta[TimeoutKey]
208 if !ok {
209 return nil
210 }
211 default:
212 return fmt.Errorf("Unknown or unsupported type in metaDecode: %#v", ids)
213 }
214
215 times := rawMeta.(map[string]interface{})
216 if len(times) == 0 {
217 return nil
218 }
219
220 if v, ok := times[TimeoutCreate]; ok {
221 t.Create = DefaultTimeout(v)
222 }
223 if v, ok := times[TimeoutRead]; ok {
224 t.Read = DefaultTimeout(v)
225 }
226 if v, ok := times[TimeoutUpdate]; ok {
227 t.Update = DefaultTimeout(v)
228 }
229 if v, ok := times[TimeoutDelete]; ok {
230 t.Delete = DefaultTimeout(v)
231 }
232 if v, ok := times[TimeoutDefault]; ok {
233 t.Default = DefaultTimeout(v)
234 }
235
236 return nil
237 }