diff options
-rw-r--r-- | mailgun/provider.go | 4 | ||||
-rw-r--r-- | mailgun/resource_mailgun_domain.go | 469 |
2 files changed, 472 insertions, 1 deletions
diff --git a/mailgun/provider.go b/mailgun/provider.go index 8771c48..32ec890 100644 --- a/mailgun/provider.go +++ b/mailgun/provider.go | |||
@@ -23,7 +23,9 @@ func Provider() terraform.ResourceProvider { | |||
23 | }, | 23 | }, |
24 | }, | 24 | }, |
25 | 25 | ||
26 | ResourcesMap: map[string]*schema.Resource{}, | 26 | ResourcesMap: map[string]*schema.Resource{ |
27 | "mailgun_domain": resourceMailgunDomain(), | ||
28 | }, | ||
27 | 29 | ||
28 | ConfigureFunc: providerConfigure, | 30 | ConfigureFunc: providerConfigure, |
29 | } | 31 | } |
diff --git a/mailgun/resource_mailgun_domain.go b/mailgun/resource_mailgun_domain.go new file mode 100644 index 0000000..028c99f --- /dev/null +++ b/mailgun/resource_mailgun_domain.go | |||
@@ -0,0 +1,469 @@ | |||
1 | package mailgun | ||
2 | |||
3 | import ( | ||
4 | "context" | ||
5 | "fmt" | ||
6 | "github.com/hashicorp/terraform/helper/schema" | ||
7 | "github.com/mailgun/mailgun-go" | ||
8 | "log" | ||
9 | "time" | ||
10 | ) | ||
11 | |||
12 | func resourceMailgunDomain() *schema.Resource { | ||
13 | return &schema.Resource{ | ||
14 | Create: CreateDomain, | ||
15 | Update: UpdateDomain, | ||
16 | Delete: DeleteDomain, | ||
17 | Read: ReadDomain, | ||
18 | Importer: &schema.ResourceImporter{ | ||
19 | State: schema.ImportStatePassthrough, | ||
20 | }, | ||
21 | |||
22 | Schema: map[string]*schema.Schema{ | ||
23 | "name": &schema.Schema{ | ||
24 | Type: schema.TypeString, | ||
25 | Required: true, | ||
26 | ForceNew: true, | ||
27 | }, | ||
28 | |||
29 | "spam_action": &schema.Schema{ | ||
30 | Type: schema.TypeString, | ||
31 | Default: "disabled", | ||
32 | ForceNew: true, | ||
33 | Optional: true, | ||
34 | }, | ||
35 | |||
36 | "smtp_password": &schema.Schema{ | ||
37 | Type: schema.TypeString, | ||
38 | ForceNew: true, | ||
39 | Optional: true, | ||
40 | }, | ||
41 | |||
42 | "smtp_login": &schema.Schema{ | ||
43 | Type: schema.TypeString, | ||
44 | Computed: true, | ||
45 | }, | ||
46 | |||
47 | "wildcard": &schema.Schema{ | ||
48 | Type: schema.TypeBool, | ||
49 | Default: false, | ||
50 | ForceNew: true, | ||
51 | Optional: true, | ||
52 | }, | ||
53 | |||
54 | "created_at": &schema.Schema{ | ||
55 | Type: schema.TypeString, | ||
56 | Computed: true, | ||
57 | ForceNew: true, | ||
58 | }, | ||
59 | |||
60 | "state": &schema.Schema{ | ||
61 | Type: schema.TypeString, | ||
62 | Computed: true, | ||
63 | }, | ||
64 | |||
65 | "force_dkim_authority": &schema.Schema{ | ||
66 | Type: schema.TypeBool, | ||
67 | Default: false, | ||
68 | Optional: true, | ||
69 | }, | ||
70 | |||
71 | "dkim_key_size": &schema.Schema{ | ||
72 | Type: schema.TypeInt, | ||
73 | Default: 1024, | ||
74 | ForceNew: true, | ||
75 | Optional: true, | ||
76 | }, | ||
77 | |||
78 | "ips": &schema.Schema{ | ||
79 | Type: schema.TypeList, | ||
80 | Computed: true, | ||
81 | ForceNew: true, | ||
82 | Optional: true, | ||
83 | Elem: &schema.Schema{Type: schema.TypeString}, | ||
84 | }, | ||
85 | |||
86 | "credentials": &schema.Schema{ | ||
87 | Type: schema.TypeList, | ||
88 | Optional: true, | ||
89 | Elem: &schema.Resource{ | ||
90 | Schema: map[string]*schema.Schema{ | ||
91 | "created_at": &schema.Schema{ | ||
92 | Type: schema.TypeString, | ||
93 | Computed: true, | ||
94 | }, | ||
95 | "login": &schema.Schema{ | ||
96 | Type: schema.TypeString, | ||
97 | Required: true, | ||
98 | }, | ||
99 | "password": &schema.Schema{ | ||
100 | Type: schema.TypeString, | ||
101 | Required: true, | ||
102 | }, | ||
103 | }, | ||
104 | }, | ||
105 | }, | ||
106 | |||
107 | "open_tracking_settings_active": &schema.Schema{ | ||
108 | Type: schema.TypeBool, | ||
109 | Optional: true, | ||
110 | Computed: true, | ||
111 | }, | ||
112 | |||
113 | "click_tracking_settings_active": &schema.Schema{ | ||
114 | Type: schema.TypeBool, | ||
115 | Optional: true, | ||
116 | Computed: true, | ||
117 | }, | ||
118 | |||
119 | "unsubscribe_tracking_settings_active": &schema.Schema{ | ||
120 | Type: schema.TypeBool, | ||
121 | Optional: true, | ||
122 | Computed: true, | ||
123 | }, | ||
124 | "unsubscribe_tracking_settings_html_footer": &schema.Schema{ | ||
125 | Type: schema.TypeString, | ||
126 | Optional: true, | ||
127 | Computed: true, | ||
128 | }, | ||
129 | "unsubscribe_tracking_settings_text_footer": &schema.Schema{ | ||
130 | Type: schema.TypeString, | ||
131 | Optional: true, | ||
132 | Computed: true, | ||
133 | }, | ||
134 | |||
135 | "require_tls": &schema.Schema{ | ||
136 | Type: schema.TypeBool, | ||
137 | Default: false, | ||
138 | Optional: true, | ||
139 | }, | ||
140 | |||
141 | "skip_verification": &schema.Schema{ | ||
142 | Type: schema.TypeBool, | ||
143 | Default: false, | ||
144 | Optional: true, | ||
145 | }, | ||
146 | |||
147 | "receiving_records": &schema.Schema{ | ||
148 | Type: schema.TypeList, | ||
149 | Computed: true, | ||
150 | Elem: &schema.Resource{ | ||
151 | Schema: map[string]*schema.Schema{ | ||
152 | "name": &schema.Schema{ | ||
153 | Type: schema.TypeString, | ||
154 | Computed: true, | ||
155 | }, | ||
156 | "priority": &schema.Schema{ | ||
157 | Type: schema.TypeString, | ||
158 | Computed: true, | ||
159 | }, | ||
160 | "record_type": &schema.Schema{ | ||
161 | Type: schema.TypeString, | ||
162 | Computed: true, | ||
163 | }, | ||
164 | "valid": &schema.Schema{ | ||
165 | Type: schema.TypeString, | ||
166 | Computed: true, | ||
167 | }, | ||
168 | "value": &schema.Schema{ | ||
169 | Type: schema.TypeString, | ||
170 | Computed: true, | ||
171 | }, | ||
172 | }, | ||
173 | }, | ||
174 | }, | ||
175 | |||
176 | "sending_records": &schema.Schema{ | ||
177 | Type: schema.TypeList, | ||
178 | Computed: true, | ||
179 | Elem: &schema.Resource{ | ||
180 | Schema: map[string]*schema.Schema{ | ||
181 | "name": &schema.Schema{ | ||
182 | Type: schema.TypeString, | ||
183 | Computed: true, | ||
184 | }, | ||
185 | "priority": &schema.Schema{ | ||
186 | Type: schema.TypeString, | ||
187 | Computed: true, | ||
188 | }, | ||
189 | "record_type": &schema.Schema{ | ||
190 | Type: schema.TypeString, | ||
191 | Computed: true, | ||
192 | }, | ||
193 | "valid": &schema.Schema{ | ||
194 | Type: schema.TypeString, | ||
195 | Computed: true, | ||
196 | }, | ||
197 | "value": &schema.Schema{ | ||
198 | Type: schema.TypeString, | ||
199 | Computed: true, | ||
200 | }, | ||
201 | }, | ||
202 | }, | ||
203 | }, | ||
204 | }, | ||
205 | } | ||
206 | } | ||
207 | |||
208 | func CreateDomain(d *schema.ResourceData, meta interface{}) error { | ||
209 | mg := meta.(*mailgun.MailgunImpl) | ||
210 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*30) | ||
211 | defer cancel() | ||
212 | |||
213 | log.Printf("[DEBUG] creating mailgun domain: %s", d.Id()) | ||
214 | |||
215 | creationResponse, err := mg.CreateDomain(ctx, d.Get("name").(string), &mailgun.CreateDomainOptions{ | ||
216 | Password: d.Get("smtp_password").(string), | ||
217 | SpamAction: mailgun.SpamAction(d.Get("spam_action").(string)), | ||
218 | Wildcard: d.Get("wildcard").(bool), | ||
219 | ForceDKIMAuthority: d.Get("force_dkim_authority").(bool), | ||
220 | DKIMKeySize: d.Get("dkim_key_size").(int), | ||
221 | IPS: d.Get("ips").([]string), | ||
222 | }) | ||
223 | |||
224 | if err != nil { | ||
225 | return fmt.Errorf("Error creating mailgun domain: %s", err.Error()) | ||
226 | } | ||
227 | |||
228 | mg = mailgun.NewMailgun(creationResponse.Domain.Name, mg.APIKey()) | ||
229 | |||
230 | for _, i := range d.Get("credentials").([]interface{}) { | ||
231 | credential := i.(map[string]interface{}) | ||
232 | err = mg.CreateCredential(ctx, credential["login"].(string), credential["password"].(string)) | ||
233 | if err != nil { | ||
234 | return fmt.Errorf("Error creating mailgun credential: %s", err.Error()) | ||
235 | } | ||
236 | } | ||
237 | |||
238 | err = mg.UpdateUnsubscribeTracking(ctx, creationResponse.Domain.Name, boolToString(d.Get("unsubscribe_tracking_settings_active").(bool)), d.Get("unsubscribe_tracking_settings_html_footer").(string), d.Get("unsubscribe_tracking_settings_text_footer").(string)) | ||
239 | if err != nil { | ||
240 | return fmt.Errorf("Error updating mailgun unsubscribe tracking settings: %s", err.Error()) | ||
241 | } | ||
242 | |||
243 | err = mg.UpdateOpenTracking(ctx, creationResponse.Domain.Name, boolToString(d.Get("open_tracking_settings_active").(bool))) | ||
244 | if err != nil { | ||
245 | return fmt.Errorf("Error updating mailgun open tracking settings: %s", err.Error()) | ||
246 | } | ||
247 | |||
248 | err = mg.UpdateClickTracking(ctx, creationResponse.Domain.Name, boolToString(d.Get("click_tracking_settings_active").(bool))) | ||
249 | if err != nil { | ||
250 | return fmt.Errorf("Error updating mailgun click tracking settings: %s", err.Error()) | ||
251 | } | ||
252 | |||
253 | err = mg.UpdateDomainConnection(ctx, creationResponse.Domain.Name, mailgun.DomainConnection{RequireTLS: d.Get("require_tls").(bool), SkipVerification: d.Get("skip_verification").(bool)}) | ||
254 | if err != nil { | ||
255 | return fmt.Errorf("Error updating mailgun connexion settings: %s", err.Error()) | ||
256 | } | ||
257 | |||
258 | d.SetId(creationResponse.Domain.Name) | ||
259 | |||
260 | return ReadDomain(d, meta) | ||
261 | } | ||
262 | |||
263 | func UpdateDomain(d *schema.ResourceData, meta interface{}) error { | ||
264 | mg := meta.(*mailgun.MailgunImpl) | ||
265 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*30) | ||
266 | defer cancel() | ||
267 | domainName := d.Get("name").(string) | ||
268 | mg = mailgun.NewMailgun(domainName, mg.APIKey()) | ||
269 | |||
270 | log.Printf("[DEBUG] updating mailgun domain: %s", d.Id()) | ||
271 | |||
272 | if d.HasChange("unsubscribe_tracking_settings_active") || d.HasChange("unsubscribe_tracking_settings_html_footer") || d.HasChange("unsubscribe_tracking_settings_text_footer") { | ||
273 | err := mg.UpdateUnsubscribeTracking(ctx, domainName, boolToString(d.Get("unsubscribe_tracking_settings_active").(bool)), d.Get("unsubscribe_tracking_settings_html_footer").(string), d.Get("unsubscribe_tracking_settings_text_footer").(string)) | ||
274 | if err != nil { | ||
275 | return fmt.Errorf("Error updating mailgun unsubscribe tracking settings: %s", err.Error()) | ||
276 | } | ||
277 | } | ||
278 | if d.HasChange("open_tracking_settings_active") { | ||
279 | err := mg.UpdateOpenTracking(ctx, domainName, boolToString(d.Get("open_tracking_settings_active").(bool))) | ||
280 | if err != nil { | ||
281 | return fmt.Errorf("Error updating mailgun open tracking settings: %s", err.Error()) | ||
282 | } | ||
283 | } | ||
284 | |||
285 | if d.HasChange("click_tracking_settings_active") { | ||
286 | err := mg.UpdateClickTracking(ctx, domainName, boolToString(d.Get("click_tracking_settings_active").(bool))) | ||
287 | if err != nil { | ||
288 | return fmt.Errorf("Error updating mailgun click tracking settings: %s", err.Error()) | ||
289 | } | ||
290 | } | ||
291 | |||
292 | if d.HasChange("require_tls") || d.HasChange("skip_verification") { | ||
293 | err := mg.UpdateDomainConnection(ctx, domainName, mailgun.DomainConnection{RequireTLS: d.Get("require_tls").(bool), SkipVerification: d.Get("skip_verification").(bool)}) | ||
294 | if err != nil { | ||
295 | return fmt.Errorf("Error updating mailgun connexion settings: %s", err.Error()) | ||
296 | } | ||
297 | } | ||
298 | |||
299 | if d.HasChange("credentials") { | ||
300 | old, new := d.GetChange("credentials") | ||
301 | for _, i := range old.([]interface{}) { | ||
302 | oldCredential := i.(map[string]interface{}) | ||
303 | found := false | ||
304 | for _, j := range new.([]interface{}) { | ||
305 | newCredential := j.(map[string]interface{}) | ||
306 | if oldCredential["login"] == newCredential["login"] { | ||
307 | found = true | ||
308 | if oldCredential["password"] != newCredential["password"] { | ||
309 | err := mg.ChangeCredentialPassword(ctx, oldCredential["login"].(string), newCredential["password"].(string)) | ||
310 | if err != nil { | ||
311 | return fmt.Errorf("Error updating mailgun credential password: %s", err.Error()) | ||
312 | } | ||
313 | } | ||
314 | break | ||
315 | } | ||
316 | } | ||
317 | if !found { | ||
318 | err := mg.DeleteCredential(ctx, oldCredential["login"].(string)) | ||
319 | if err != nil { | ||
320 | return fmt.Errorf("Error deleting mailgun credential : %s", err.Error()) | ||
321 | } | ||
322 | } | ||
323 | } | ||
324 | |||
325 | for _, i := range new.([]interface{}) { | ||
326 | newCredential := i.(map[string]interface{}) | ||
327 | found := false | ||
328 | for _, j := range old.([]interface{}) { | ||
329 | oldCredential := j.(map[string]interface{}) | ||
330 | if oldCredential["login"] == newCredential["login"] { | ||
331 | found = true | ||
332 | break | ||
333 | } | ||
334 | } | ||
335 | if !found { | ||
336 | err := mg.CreateCredential(ctx, newCredential["login"].(string), newCredential["password"].(string)) | ||
337 | if err != nil { | ||
338 | return fmt.Errorf("Error creating mailgun credential : %s", err.Error()) | ||
339 | } | ||
340 | } | ||
341 | } | ||
342 | } | ||
343 | |||
344 | return ReadDomain(d, meta) | ||
345 | } | ||
346 | |||
347 | func DeleteDomain(d *schema.ResourceData, meta interface{}) error { | ||
348 | mg := meta.(*mailgun.MailgunImpl) | ||
349 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*30) | ||
350 | defer cancel() | ||
351 | |||
352 | log.Printf("[DEBUG] Deleting mailgun domain: %s", d.Id()) | ||
353 | |||
354 | err := mg.DeleteDomain(ctx, d.Get("name").(string)) | ||
355 | |||
356 | return err | ||
357 | } | ||
358 | |||
359 | func ReadDomain(d *schema.ResourceData, meta interface{}) error { | ||
360 | mg := meta.(*mailgun.MailgunImpl) | ||
361 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*30) | ||
362 | defer cancel() | ||
363 | |||
364 | domainName := d.Get("name").(string) | ||
365 | |||
366 | domainResponse, err := mg.GetDomain(ctx, domainName) | ||
367 | if err != nil { | ||
368 | return fmt.Errorf("Error Getting mailgun domain Details for %s: Error: %s", d.Id(), err) | ||
369 | } | ||
370 | |||
371 | d.Set("created_at", domainResponse.Domain.CreatedAt) | ||
372 | d.Set("smtd_login", domainResponse.Domain.SMTPLogin) | ||
373 | d.Set("name", domainResponse.Domain.Name) | ||
374 | d.Set("smtd_password", domainResponse.Domain.SMTPPassword) | ||
375 | d.Set("wildcard", domainResponse.Domain.Wildcard) | ||
376 | d.Set("spam_action", domainResponse.Domain.SpamAction) | ||
377 | d.Set("state", domainResponse.Domain.State) | ||
378 | |||
379 | simpleReceivingRecords := make([]map[string]interface{}, len(domainResponse.ReceivingDNSRecords)) | ||
380 | for i, r := range domainResponse.ReceivingDNSRecords { | ||
381 | simpleReceivingRecords[i] = make(map[string]interface{}) | ||
382 | simpleReceivingRecords[i]["priority"] = r.Priority | ||
383 | simpleReceivingRecords[i]["name"] = r.Name | ||
384 | simpleReceivingRecords[i]["valid"] = r.Valid | ||
385 | simpleReceivingRecords[i]["value"] = r.Value | ||
386 | simpleReceivingRecords[i]["record_type"] = r.RecordType | ||
387 | } | ||
388 | d.Set("receiving_records", simpleReceivingRecords) | ||
389 | |||
390 | simpleSendingRecords := make([]map[string]interface{}, len(domainResponse.SendingDNSRecords)) | ||
391 | for i, r := range domainResponse.SendingDNSRecords { | ||
392 | simpleSendingRecords[i] = make(map[string]interface{}) | ||
393 | simpleSendingRecords[i]["name"] = r.Name | ||
394 | simpleSendingRecords[i]["priority"] = r.Priority | ||
395 | simpleSendingRecords[i]["valid"] = r.Valid | ||
396 | simpleSendingRecords[i]["value"] = r.Value | ||
397 | simpleSendingRecords[i]["record_type"] = r.RecordType | ||
398 | } | ||
399 | d.Set("sending_records", simpleSendingRecords) | ||
400 | |||
401 | domainConnection, err := mg.GetDomainConnection(ctx, domainName) | ||
402 | if err != nil { | ||
403 | return fmt.Errorf("Error Getting mailgun domain connection Details for %s: Error: %s", d.Id(), err) | ||
404 | } | ||
405 | d.Set("require_tls", domainConnection.RequireTLS) | ||
406 | d.Set("skip_verification", domainConnection.SkipVerification) | ||
407 | |||
408 | domainTracking, err := mg.GetDomainTracking(ctx, domainName) | ||
409 | if err != nil { | ||
410 | return fmt.Errorf("Error Getting mailgun domain tracking Details for %s: Error: %s", d.Id(), err) | ||
411 | } | ||
412 | |||
413 | d.Set("open_tracking_settings_active", domainTracking.Open.Active) | ||
414 | |||
415 | d.Set("click_tracking_settings_active", domainTracking.Click.Active) | ||
416 | d.Set("unsubscribe_tracking_settings_active", domainTracking.Unsubscribe.Active) | ||
417 | d.Set("unsubscribe_tracking_settings_html_footer", domainTracking.Unsubscribe.HTMLFooter) | ||
418 | d.Set("unsubscribe_tracking_settings_text_footer", domainTracking.Unsubscribe.TextFooter) | ||
419 | |||
420 | ipAddress, err := mg.ListDomainIPS(ctx) | ||
421 | if err != nil { | ||
422 | return fmt.Errorf("Error Getting mailgun domain ips for %s: Error: %s", d.Id(), err) | ||
423 | } | ||
424 | ips := make([]string, len(ipAddress)) | ||
425 | for i, r := range ipAddress { | ||
426 | ips[i] = r.IP | ||
427 | |||
428 | } | ||
429 | d.Set("ips", ips) | ||
430 | |||
431 | credentialsResponse, err := ListCredentials(domainName, mg.APIKey()) | ||
432 | credentials := make([]map[string]interface{}, len(credentialsResponse)) | ||
433 | for i, r := range credentialsResponse { | ||
434 | credentials[i] = make(map[string]interface{}) | ||
435 | credentials[i]["created_at"] = r.CreatedAt | ||
436 | credentials[i]["login"] = r.Login | ||
437 | credentials[i]["password"] = r.Password | ||
438 | } | ||
439 | d.Set("credentials", credentials) | ||
440 | |||
441 | d.SetId(domainName) | ||
442 | |||
443 | return nil | ||
444 | } | ||
445 | |||
446 | func boolToString(b bool) string { | ||
447 | if b { | ||
448 | return "true" | ||
449 | } | ||
450 | return "false" | ||
451 | } | ||
452 | |||
453 | func ListCredentials(domain, apiKey string) ([]mailgun.Credential, error) { | ||
454 | mg := mailgun.NewMailgun(domain, apiKey) | ||
455 | it := mg.ListCredentials(nil) | ||
456 | |||
457 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*30) | ||
458 | defer cancel() | ||
459 | |||
460 | var page, result []mailgun.Credential | ||
461 | for it.Next(ctx, &page) { | ||
462 | result = append(result, page...) | ||
463 | } | ||
464 | |||
465 | if it.Err() != nil { | ||
466 | return nil, it.Err() | ||
467 | } | ||
468 | return result, nil | ||
469 | } | ||