Skip to content
This repository has been archived by the owner on Mar 8, 2022. It is now read-only.

Commit

Permalink
Merge branch 'master' of github.com:alexkappa/terraform-provider-auth0
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex Kalyvitis committed Nov 9, 2021
2 parents dfecd8f + 53ffa63 commit 85e5d59
Show file tree
Hide file tree
Showing 11 changed files with 555 additions and 24 deletions.
30 changes: 30 additions & 0 deletions auth0/internal/digitalocean/provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package digitalocean

import (
"github.com/digitalocean/godo"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

// Provider returns a schema.Provider for a minimal version of the DigitalOcean
// provider used for testing.
func Provider() *schema.Provider {
return &schema.Provider{
Schema: map[string]*schema.Schema{
"token": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.MultiEnvDefaultFunc([]string{
"DIGITALOCEAN_TOKEN",
"DIGITALOCEAN_ACCESS_TOKEN",
}, nil),
Description: "The token key for API operations.",
},
},
ResourcesMap: map[string]*schema.Resource{
"digitalocean_record": resourceDigitalOceanRecord(),
},
ConfigureFunc: func(d *schema.ResourceData) (interface{}, error) {
return godo.NewFromToken(d.Get("token").(string)), nil
},
}
}
323 changes: 323 additions & 0 deletions auth0/internal/digitalocean/resource_digitalocean_record.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,323 @@
package digitalocean

import (
"context"
"fmt"
"log"
"strconv"
"strings"

"github.com/digitalocean/godo"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
)

func resourceDigitalOceanRecord() *schema.Resource {
return &schema.Resource{
Create: resourceDigitalOceanRecordCreate,
Read: resourceDigitalOceanRecordRead,
Update: resourceDigitalOceanRecordUpdate,
Delete: resourceDigitalOceanRecordDelete,
Importer: &schema.ResourceImporter{
State: resourceDigitalOceanRecordImport,
},

Schema: map[string]*schema.Schema{
"type": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{
"A",
"AAAA",
"CAA",
"CNAME",
"MX",
"NS",
"TXT",
"SRV",
}, false),
},

"domain": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.NoZeroValues,
},

"name": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.NoZeroValues,
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
domain := d.Get("domain").(string) + "."

return old+"."+domain == new
},
},

"port": {
Type: schema.TypeInt,
Optional: true,
ValidateFunc: validation.IntBetween(0, 65535),
},

"priority": {
Type: schema.TypeInt,
Optional: true,
ValidateFunc: validation.IntBetween(0, 65535),
},

"weight": {
Type: schema.TypeInt,
Optional: true,
ValidateFunc: validation.IntBetween(0, 65535),
},

"ttl": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
ValidateFunc: validation.IntAtLeast(1),
},

"value": {
Type: schema.TypeString,
Required: true,
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
domain := d.Get("domain").(string) + "."

return (old == "@" && new == domain) || (old == new+"."+domain)
},
},

"fqdn": {
Type: schema.TypeString,
Computed: true,
},

"flags": {
Type: schema.TypeInt,
Optional: true,
ValidateFunc: validation.IntBetween(0, 255),
},

"tag": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{
"issue",
"issuewild",
"iodef",
}, false),
},
},

CustomizeDiff: func(diff *schema.ResourceDiff, v interface{}) error {
recordType := diff.Get("type").(string)

_, hasPriority := diff.GetOkExists("priority")
if recordType == "MX" {
if !hasPriority {
return fmt.Errorf("`priority` is required for when type is `MX`")
}
}

_, hasPort := diff.GetOkExists("port")
_, hasWeight := diff.GetOkExists("weight")
if recordType == "SRV" {
if !hasPriority {
return fmt.Errorf("`priority` is required for when type is `SRV`")
}
if !hasPort {
return fmt.Errorf("`port` is required for when type is `SRV`")
}
if !hasWeight {
return fmt.Errorf("`weight` is required for when type is `SRV`")
}
}

_, hasFlags := diff.GetOkExists("flags")
_, hasTag := diff.GetOk("tag")
if recordType == "CAA" {
if !hasFlags {
return fmt.Errorf("`flags` is required for when type is `CAA`")
}
if !hasTag {
return fmt.Errorf("`tag` is required for when type is `CAA`")
}
}

return nil
},
}
}

func resourceDigitalOceanRecordCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*godo.Client)

newRecord, err := expandDigitalOceanRecordResource(d)
if err != nil {
return fmt.Errorf("Error in constructing record request: %s", err)
}

newRecord.Type = d.Get("type").(string)

log.Printf("[DEBUG] record create configuration: %#v", newRecord)
rec, _, err := client.Domains.CreateRecord(context.Background(), d.Get("domain").(string), newRecord)
if err != nil {
return fmt.Errorf("Failed to create record: %s", err)
}

d.SetId(strconv.Itoa(rec.ID))
log.Printf("[INFO] Record ID: %s", d.Id())

return resourceDigitalOceanRecordRead(d, meta)
}

func resourceDigitalOceanRecordRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*godo.Client)
domain := d.Get("domain").(string)
id, err := strconv.Atoi(d.Id())
if err != nil {
return fmt.Errorf("invalid record ID: %v", err)
}

rec, resp, err := client.Domains.Record(context.Background(), domain, id)
if err != nil {
// If the record is somehow already destroyed, mark as
// successfully gone
if resp != nil && resp.StatusCode == 404 {
d.SetId("")
return nil
}

return err
}

if t := rec.Type; t == "CNAME" || t == "MX" || t == "NS" || t == "SRV" || t == "CAA" {
if rec.Data != "@" && rec.Tag != "iodef" {
rec.Data += "."
}
}

d.Set("name", rec.Name)
d.Set("type", rec.Type)
d.Set("value", rec.Data)
d.Set("port", rec.Port)
d.Set("priority", rec.Priority)
d.Set("ttl", rec.TTL)
d.Set("weight", rec.Weight)
d.Set("flags", rec.Flags)
d.Set("tag", rec.Tag)

en := constructFqdn(rec.Name, d.Get("domain").(string))
log.Printf("[DEBUG] Constructed FQDN: %s", en)
d.Set("fqdn", en)

return nil
}

func resourceDigitalOceanRecordImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
if strings.Contains(d.Id(), ",") {
s := strings.Split(d.Id(), ",")
// Validate that this is an ID by making sure it can be converted into an int
_, err := strconv.Atoi(s[1])
if err != nil {
return nil, fmt.Errorf("invalid record ID: %v", err)
}

d.SetId(s[1])
d.Set("domain", s[0])
}

return []*schema.ResourceData{d}, nil
}

func resourceDigitalOceanRecordUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*godo.Client)

domain := d.Get("domain").(string)
id, err := strconv.Atoi(d.Id())
if err != nil {
return fmt.Errorf("invalid record ID: %v", err)
}

editRecord, err := expandDigitalOceanRecordResource(d)
if err != nil {
return fmt.Errorf("Error in constructing record request: %s", err)
}

log.Printf("[DEBUG] record update configuration: %#v", editRecord)
_, _, err = client.Domains.EditRecord(context.Background(), domain, id, editRecord)
if err != nil {
return fmt.Errorf("Failed to update record: %s", err)
}

return resourceDigitalOceanRecordRead(d, meta)
}

func resourceDigitalOceanRecordDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*godo.Client)

domain := d.Get("domain").(string)
id, err := strconv.Atoi(d.Id())
if err != nil {
return fmt.Errorf("invalid record ID: %v", err)
}

log.Printf("[INFO] Deleting record: %s, %d", domain, id)

resp, delErr := client.Domains.DeleteRecord(context.Background(), domain, id)
if delErr != nil {
// If the record is somehow already destroyed, mark as
// successfully gone
if resp != nil && resp.StatusCode == 404 {
return nil
}

return fmt.Errorf("Error deleting record: %s", delErr)
}

return nil
}

func expandDigitalOceanRecordResource(d *schema.ResourceData) (*godo.DomainRecordEditRequest, error) {
record := &godo.DomainRecordEditRequest{
Name: d.Get("name").(string),
Data: d.Get("value").(string),
}

if v, ok := d.GetOkExists("port"); ok {
record.Port = v.(int)
}
if v, ok := d.GetOkExists("priority"); ok {
record.Priority = v.(int)
}
if v, ok := d.GetOk("ttl"); ok {
record.TTL = v.(int)
}
if v, ok := d.GetOkExists("weight"); ok {
record.Weight = v.(int)
}
if v, ok := d.GetOkExists("flags"); ok {
record.Flags = v.(int)
}
if v, ok := d.GetOk("tag"); ok {
record.Tag = v.(string)
}

return record, nil
}

func constructFqdn(name, domain string) string {
rn := strings.ToLower(name)
domainSuffix := domain + "."
if strings.HasSuffix(rn, domainSuffix) {
rn = strings.TrimSuffix(rn, ".")
} else {
rn = strings.Join([]string{name, domain}, ".")
}
return rn
}
Loading

0 comments on commit 85e5d59

Please sign in to comment.