-
Notifications
You must be signed in to change notification settings - Fork 136
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add ds records and name servers resources for domains #818
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package ovh | ||
|
||
import ( | ||
"fmt" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" | ||
"github.com/ovh/go-ovh/ovh" | ||
"log" | ||
"net/url" | ||
"time" | ||
) | ||
|
||
func waitDomainTask(client *ovh.Client, domainName string, taskId int) error { | ||
endpoint := fmt.Sprintf("/domain/%s/task/%d", url.PathEscape(domainName), taskId) | ||
|
||
stateConf := &retry.StateChangeConf{ | ||
Pending: []string{"todo", "doing"}, | ||
Target: []string{"done"}, | ||
Refresh: func() (result interface{}, state string, err error) { | ||
var task DomainTask | ||
|
||
if err := client.Get(endpoint, &task); err != nil { | ||
log.Printf("[ERROR] couldn't fetch task %d for domain %s:\n\t%s\n", taskId, domainName, err.Error()) | ||
return nil, "error", err | ||
} | ||
|
||
return task, task.Status, nil | ||
}, | ||
Timeout: 10 * time.Minute, | ||
Delay: 30 * time.Second, | ||
MinTimeout: 5 * time.Second, | ||
} | ||
|
||
_, err := stateConf.WaitForState() | ||
|
||
if err != nil { | ||
return fmt.Errorf("error waiting for domain: %s task: %d to complete:\n\t%s\n", domainName, taskId, err.Error()) | ||
} | ||
|
||
return err | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,188 @@ | ||||||||||||||||||||||||||||||||||
package ovh | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
import ( | ||||||||||||||||||||||||||||||||||
"fmt" | ||||||||||||||||||||||||||||||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||||||||||||||||||||||||||||||||||
"github.com/ovh/terraform-provider-ovh/ovh/helpers" | ||||||||||||||||||||||||||||||||||
"log" | ||||||||||||||||||||||||||||||||||
"net/url" | ||||||||||||||||||||||||||||||||||
"time" | ||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
func resourceDomainDsRecords() *schema.Resource { | ||||||||||||||||||||||||||||||||||
return &schema.Resource{ | ||||||||||||||||||||||||||||||||||
Description: "Resource to manage a domain name DS records", | ||||||||||||||||||||||||||||||||||
Schema: resourceDomainDsRecordsSchema(), | ||||||||||||||||||||||||||||||||||
Create: resourceDomainDsRecordsUpdate, | ||||||||||||||||||||||||||||||||||
Read: resourceDomainDsRecordsRead, | ||||||||||||||||||||||||||||||||||
Update: resourceDomainDsRecordsUpdate, | ||||||||||||||||||||||||||||||||||
Delete: resourceDomainDsRecordsDelete, | ||||||||||||||||||||||||||||||||||
Importer: &schema.ResourceImporter{ | ||||||||||||||||||||||||||||||||||
State: func(resourceData *schema.ResourceData, meta any) ([]*schema.ResourceData, error) { | ||||||||||||||||||||||||||||||||||
resourceData.Set("domain", resourceData.Id()) | ||||||||||||||||||||||||||||||||||
return []*schema.ResourceData{resourceData}, nil | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
Timeouts: &schema.ResourceTimeout{ | ||||||||||||||||||||||||||||||||||
Default: schema.DefaultTimeout(10 * time.Minute), | ||||||||||||||||||||||||||||||||||
Read: schema.DefaultTimeout(30 * time.Second), | ||||||||||||||||||||||||||||||||||
Create: schema.DefaultTimeout(10 * time.Minute), | ||||||||||||||||||||||||||||||||||
Update: schema.DefaultTimeout(10 * time.Minute), | ||||||||||||||||||||||||||||||||||
Delete: schema.DefaultTimeout(10 * time.Minute), | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
func resourceDomainDsRecordsSchema() map[string]*schema.Schema { | ||||||||||||||||||||||||||||||||||
resourceSchema := map[string]*schema.Schema{ | ||||||||||||||||||||||||||||||||||
"domain": { | ||||||||||||||||||||||||||||||||||
Type: schema.TypeString, | ||||||||||||||||||||||||||||||||||
Description: "Domain name", | ||||||||||||||||||||||||||||||||||
Required: true, | ||||||||||||||||||||||||||||||||||
ForceNew: true, | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
"ds_records": { | ||||||||||||||||||||||||||||||||||
Type: schema.TypeList, | ||||||||||||||||||||||||||||||||||
Description: "DS Records for the domain", | ||||||||||||||||||||||||||||||||||
Elem: &schema.Resource{ | ||||||||||||||||||||||||||||||||||
Schema: map[string]*schema.Schema{ | ||||||||||||||||||||||||||||||||||
"algorithm": { | ||||||||||||||||||||||||||||||||||
Type: schema.TypeString, | ||||||||||||||||||||||||||||||||||
Description: "Algorithm name of the DNSSEC key", | ||||||||||||||||||||||||||||||||||
Required: true, | ||||||||||||||||||||||||||||||||||
ValidateFunc: helpers.ValidateEnum([]string{"RSASHA1", "RSASHA1_NSEC3_SHA1", "RSASHA256", "RSASHA512", "ECDSAP256SHA256", "ECDSAP384SHA384", "ED25519"}), | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
"flags": { | ||||||||||||||||||||||||||||||||||
Type: schema.TypeString, | ||||||||||||||||||||||||||||||||||
Description: "Flag name of the DNSSEC key", | ||||||||||||||||||||||||||||||||||
Required: true, | ||||||||||||||||||||||||||||||||||
ValidateFunc: helpers.ValidateEnum([]string{"ZONE_SIGNING_KEY", "KEY_SIGNING_KEY"}), | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
"public_key": { | ||||||||||||||||||||||||||||||||||
Type: schema.TypeString, | ||||||||||||||||||||||||||||||||||
Description: "Public key", | ||||||||||||||||||||||||||||||||||
Required: true, | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
"tag": { | ||||||||||||||||||||||||||||||||||
Type: schema.TypeInt, | ||||||||||||||||||||||||||||||||||
Description: "Tag of the DNSSEC key", | ||||||||||||||||||||||||||||||||||
Required: true, | ||||||||||||||||||||||||||||||||||
ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { | ||||||||||||||||||||||||||||||||||
if v.(int) <= 0 || v.(int) >= 65536 { | ||||||||||||||||||||||||||||||||||
errors = append(errors, fmt.Errorf(`Field "tag" must be larger than 0 and smaller than 65536.`)) | ||||||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
Required: true, | ||||||||||||||||||||||||||||||||||
MinItems: 1, | ||||||||||||||||||||||||||||||||||
MaxItems: 4, | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
return resourceSchema | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
func resourceDomainDsRecordsRead(resourceData *schema.ResourceData, meta interface{}) error { | ||||||||||||||||||||||||||||||||||
config := meta.(*Config) | ||||||||||||||||||||||||||||||||||
domainName := resourceData.Id() | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
domainDsRecords := &DomainDsRecords{ | ||||||||||||||||||||||||||||||||||
Domain: domainName, | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
log.Printf("[DEBUG] Will read domain name DS records: %s\n", domainName) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
responseData := &[]int{} | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||
endpoint := fmt.Sprintf("/domain/%s/dsRecord", url.PathEscape(domainName)) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
if err := config.OVHClient.Get(endpoint, &responseData); err != nil { | ||||||||||||||||||||||||||||||||||
return fmt.Errorf("calling GET %s:\n\t %s", endpoint, err.Error()) | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
for _, dsRecordId := range *responseData { | ||||||||||||||||||||||||||||||||||
responseData := &DomainDsRecord{} | ||||||||||||||||||||||||||||||||||
endpoint := fmt.Sprintf("/domain/%s/dsRecord/%d", url.PathEscape(domainName), dsRecordId) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
if err := config.OVHClient.Get(endpoint, &responseData); err != nil { | ||||||||||||||||||||||||||||||||||
return helpers.CheckDeleted(resourceData, err, endpoint) | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
domainDsRecords.DsRecords = append(domainDsRecords.DsRecords, *responseData) | ||||||||||||||||||||||||||||||||||
Comment on lines
+109
to
+116
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
resourceData.SetId(domainName) | ||||||||||||||||||||||||||||||||||
for k, v := range domainDsRecords.ToMap() { | ||||||||||||||||||||||||||||||||||
resourceData.Set(k, v) | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
return nil | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
func resourceDomainDsRecordsUpdate(resourceData *schema.ResourceData, meta interface{}) error { | ||||||||||||||||||||||||||||||||||
config := meta.(*Config) | ||||||||||||||||||||||||||||||||||
domainName := resourceData.Get("domain").(string) | ||||||||||||||||||||||||||||||||||
task := &DomainTask{} | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
dsRecordsUpdate := &DomainDsRecordsUpdateOpts{ | ||||||||||||||||||||||||||||||||||
DsRecords: make([]DomainDsRecord, 0), | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
for _, dsRecord := range resourceData.Get("ds_records").([]interface{}) { | ||||||||||||||||||||||||||||||||||
record := dsRecord.(map[string]interface{}) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
dsRecordsUpdate.DsRecords = append(dsRecordsUpdate.DsRecords, DomainDsRecord{ | ||||||||||||||||||||||||||||||||||
Algorithm: DsRecordAlgorithmValuesMap[record["algorithm"].(string)], | ||||||||||||||||||||||||||||||||||
Flags: DsRecordFlagValuesMap[record["flags"].(string)], | ||||||||||||||||||||||||||||||||||
PublicKey: record["public_key"].(string), | ||||||||||||||||||||||||||||||||||
Tag: record["tag"].(int), | ||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
log.Printf("[DEBUG] Will update domain name DS records: %s\n", domainName) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
endpoint := fmt.Sprintf("/domain/%s/dsRecord", url.PathEscape(domainName)) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
if err := config.OVHClient.Post(endpoint, dsRecordsUpdate, &task); err != nil { | ||||||||||||||||||||||||||||||||||
return fmt.Errorf("calling POST %s :\n\t %s", endpoint, err.Error()) | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
if err := waitDomainTask(config.OVHClient, domainName, task.TaskId); err != nil { | ||||||||||||||||||||||||||||||||||
return fmt.Errorf("waiting for %s DS records to be updated: %s", domainName, err.Error()) | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
resourceData.SetId(domainName) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
return resourceDomainDsRecordsRead(resourceData, meta) | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
func resourceDomainDsRecordsDelete(resourceData *schema.ResourceData, meta interface{}) error { | ||||||||||||||||||||||||||||||||||
config := meta.(*Config) | ||||||||||||||||||||||||||||||||||
domainName := resourceData.Get("domain").(string) | ||||||||||||||||||||||||||||||||||
task := &DomainTask{} | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
domainDsRecordsUpdateOpts := &DomainDsRecordsUpdateOpts{ | ||||||||||||||||||||||||||||||||||
DsRecords: make([]DomainDsRecord, 0), | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
log.Printf("[DEBUG] Will remove all domain name DS records: %s\n", domainName) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
endpoint := fmt.Sprintf("/domain/%s/dsRecord", url.PathEscape(domainName)) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
if err := config.OVHClient.Post(endpoint, domainDsRecordsUpdateOpts, &task); err != nil { | ||||||||||||||||||||||||||||||||||
return fmt.Errorf("calling POST %s :\n\t %s", endpoint, err.Error()) | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
if err := waitDomainTask(config.OVHClient, domainName, task.TaskId); err != nil { | ||||||||||||||||||||||||||||||||||
return fmt.Errorf("waiting for %s DS records to be deleted: %s", domainName, err.Error()) | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
resourceData.SetId("") | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
return nil | ||||||||||||||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should move this in
types_domain.go
to keep consistency with the existing code