2019-04-09 20:56:12 +00:00
|
|
|
package sakuracloud
|
|
|
|
|
|
|
|
import (
|
2022-08-04 13:56:46 +00:00
|
|
|
"context"
|
2019-04-09 20:56:12 +00:00
|
|
|
"fmt"
|
|
|
|
"strings"
|
2022-08-04 13:56:46 +00:00
|
|
|
"sync"
|
2019-04-09 20:56:12 +00:00
|
|
|
|
2020-09-02 01:20:01 +00:00
|
|
|
"github.com/go-acme/lego/v4/challenge/dns01"
|
2022-08-04 13:56:46 +00:00
|
|
|
"github.com/sacloud/iaas-api-go"
|
|
|
|
"github.com/sacloud/iaas-api-go/search"
|
2019-04-09 20:56:12 +00:00
|
|
|
)
|
|
|
|
|
2022-08-04 13:56:46 +00:00
|
|
|
// This mutex is required for concurrent updates.
|
|
|
|
// see: https://github.com/go-acme/lego/pull/850
|
|
|
|
var mu sync.Mutex
|
2019-04-09 20:56:12 +00:00
|
|
|
|
2022-11-25 17:12:21 +00:00
|
|
|
func (d *DNSProvider) addTXTRecord(fqdn, value string, ttl int) error {
|
2022-08-04 13:56:46 +00:00
|
|
|
mu.Lock()
|
|
|
|
defer mu.Unlock()
|
2019-04-09 20:56:12 +00:00
|
|
|
|
2022-11-25 17:12:21 +00:00
|
|
|
zone, err := d.getHostedZone(fqdn)
|
2019-04-09 20:56:12 +00:00
|
|
|
if err != nil {
|
2022-08-04 13:56:46 +00:00
|
|
|
return fmt.Errorf("%w", err)
|
2019-04-09 20:56:12 +00:00
|
|
|
}
|
|
|
|
|
2020-06-27 12:28:59 +00:00
|
|
|
name := extractRecordName(fqdn, zone.Name)
|
2019-04-09 20:56:12 +00:00
|
|
|
|
2022-08-04 13:56:46 +00:00
|
|
|
records := append(zone.Records, &iaas.DNSRecord{
|
|
|
|
Name: name,
|
|
|
|
Type: "TXT",
|
|
|
|
RData: value,
|
|
|
|
TTL: ttl,
|
|
|
|
})
|
|
|
|
_, err = d.client.UpdateSettings(context.Background(), zone.ID, &iaas.DNSUpdateSettingsRequest{
|
|
|
|
Records: records,
|
|
|
|
SettingsHash: zone.SettingsHash,
|
|
|
|
})
|
2019-04-09 20:56:12 +00:00
|
|
|
if err != nil {
|
2022-08-04 13:56:46 +00:00
|
|
|
return fmt.Errorf("API call failed: %w", err)
|
2019-04-09 20:56:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-11-25 17:12:21 +00:00
|
|
|
func (d *DNSProvider) cleanupTXTRecord(fqdn, value string) error {
|
2022-08-04 13:56:46 +00:00
|
|
|
mu.Lock()
|
|
|
|
defer mu.Unlock()
|
2019-04-09 20:56:12 +00:00
|
|
|
|
2022-11-25 17:12:21 +00:00
|
|
|
zone, err := d.getHostedZone(fqdn)
|
2019-04-09 20:56:12 +00:00
|
|
|
if err != nil {
|
2022-08-04 13:56:46 +00:00
|
|
|
return err
|
2019-04-09 20:56:12 +00:00
|
|
|
}
|
|
|
|
|
2022-08-04 13:56:46 +00:00
|
|
|
recordName := extractRecordName(fqdn, zone.Name)
|
2019-04-09 20:56:12 +00:00
|
|
|
|
2022-08-04 13:56:46 +00:00
|
|
|
var updRecords iaas.DNSRecords
|
|
|
|
for _, r := range zone.Records {
|
|
|
|
if !(r.Name == recordName && r.Type == "TXT" && r.RData == value) {
|
|
|
|
updRecords = append(updRecords, r)
|
2019-04-09 20:56:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-04 13:56:46 +00:00
|
|
|
settings := &iaas.DNSUpdateSettingsRequest{
|
|
|
|
Records: updRecords,
|
|
|
|
SettingsHash: zone.SettingsHash,
|
|
|
|
}
|
|
|
|
_, err = d.client.UpdateSettings(context.Background(), zone.ID, settings)
|
2019-04-09 20:56:12 +00:00
|
|
|
if err != nil {
|
2022-08-04 13:56:46 +00:00
|
|
|
return fmt.Errorf("API call failed: %w", err)
|
2019-04-09 20:56:12 +00:00
|
|
|
}
|
2022-08-04 13:56:46 +00:00
|
|
|
|
2019-04-09 20:56:12 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-08-04 13:56:46 +00:00
|
|
|
func (d *DNSProvider) getHostedZone(domain string) (*iaas.DNS, error) {
|
2022-11-25 17:12:21 +00:00
|
|
|
authZone, err := dns01.FindZoneByFqdn(domain)
|
2019-04-09 20:56:12 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
zoneName := dns01.UnFqdn(authZone)
|
|
|
|
|
2022-08-04 13:56:46 +00:00
|
|
|
conditions := &iaas.FindCondition{
|
|
|
|
Filter: search.Filter{
|
|
|
|
search.Key("Name"): search.ExactMatch(zoneName),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
res, err := d.client.Find(context.Background(), conditions)
|
2019-04-09 20:56:12 +00:00
|
|
|
if err != nil {
|
2022-08-04 13:56:46 +00:00
|
|
|
if iaas.IsNotFoundError(err) {
|
2020-02-27 18:14:46 +00:00
|
|
|
return nil, fmt.Errorf("zone %s not found on SakuraCloud DNS: %w", zoneName, err)
|
2019-04-09 20:56:12 +00:00
|
|
|
}
|
2020-10-27 11:01:05 +00:00
|
|
|
|
2020-02-27 18:14:46 +00:00
|
|
|
return nil, fmt.Errorf("API call failed: %w", err)
|
2019-04-09 20:56:12 +00:00
|
|
|
}
|
|
|
|
|
2022-08-04 13:56:46 +00:00
|
|
|
for _, zone := range res.DNS {
|
2019-04-09 20:56:12 +00:00
|
|
|
if zone.Name == zoneName {
|
2022-08-04 13:56:46 +00:00
|
|
|
return zone, nil
|
2019-04-09 20:56:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, fmt.Errorf("zone %s not found", zoneName)
|
|
|
|
}
|
|
|
|
|
2020-06-27 12:28:59 +00:00
|
|
|
func extractRecordName(fqdn, zone string) string {
|
2019-04-09 20:56:12 +00:00
|
|
|
name := dns01.UnFqdn(fqdn)
|
2020-06-27 12:28:59 +00:00
|
|
|
if idx := strings.Index(name, "."+zone); idx != -1 {
|
2019-04-09 20:56:12 +00:00
|
|
|
return name[:idx]
|
|
|
|
}
|
|
|
|
return name
|
|
|
|
}
|