mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-05-11 05:55:12 +00:00
Ns1 provider (#63)
* add ns1 libs to vendor * Create shim and wire into tests * ns1 provider more working. * vendor correct files * comment diff functions * ns1 docs * making mx work with ns1 * ? * refactor tests to make capability blocks easier. fix up ns1
This commit is contained in:
145
providers/ns1/ns1provider.go
Normal file
145
providers/ns1/ns1provider.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package ns1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"fmt"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/models"
|
||||
"github.com/StackExchange/dnscontrol/providers"
|
||||
|
||||
"net/http"
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/providers/diff"
|
||||
"github.com/miekg/dns/dnsutil"
|
||||
"gopkg.in/ns1/ns1-go.v2/rest"
|
||||
"gopkg.in/ns1/ns1-go.v2/rest/model/dns"
|
||||
)
|
||||
|
||||
func init() {
|
||||
providers.RegisterDomainServiceProviderType("NS1", newProvider)
|
||||
}
|
||||
|
||||
type nsone struct {
|
||||
*rest.Client
|
||||
}
|
||||
|
||||
func newProvider(creds map[string]string, meta json.RawMessage) (providers.DNSServiceProvider, error) {
|
||||
if creds["api_token"] == "" {
|
||||
return nil, fmt.Errorf("api_token required for ns1")
|
||||
}
|
||||
return &nsone{rest.NewClient(http.DefaultClient, rest.SetAPIKey(creds["api_token"]))}, nil
|
||||
}
|
||||
|
||||
func (n *nsone) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
||||
z, _, err := n.Zones.Get(domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return models.StringsToNameservers(z.DNSServers), nil
|
||||
}
|
||||
|
||||
func (n *nsone) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc.Punycode()
|
||||
dc.CombineMXs()
|
||||
z, _, err := n.Zones.Get(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
found := models.Records{}
|
||||
for _, r := range z.Records {
|
||||
zrs, err := convert(r, dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
found = append(found, zrs...)
|
||||
}
|
||||
foundGrouped := found.Grouped()
|
||||
desiredGrouped := dc.Records.Grouped()
|
||||
|
||||
differ := diff.New(dc)
|
||||
changedGroups := differ.ChangedGroups(found)
|
||||
corrections := []*models.Correction{}
|
||||
// each name/type is given to the api as a unit.
|
||||
for k, descs := range changedGroups {
|
||||
key := k
|
||||
desc := strings.Join(descs, "\n")
|
||||
_, current := foundGrouped[k]
|
||||
recs, wanted := desiredGrouped[k]
|
||||
if wanted && !current {
|
||||
// pure addition
|
||||
corrections = append(corrections, &models.Correction{
|
||||
Msg: desc,
|
||||
F: func() error { return n.add(recs, dc.Name) },
|
||||
})
|
||||
} else if current && !wanted {
|
||||
// pure deletion
|
||||
corrections = append(corrections, &models.Correction{
|
||||
Msg: desc,
|
||||
F: func() error { return n.remove(key, dc.Name) },
|
||||
})
|
||||
} else {
|
||||
// modification
|
||||
corrections = append(corrections, &models.Correction{
|
||||
Msg: desc,
|
||||
F: func() error { return n.modify(recs, dc.Name) },
|
||||
})
|
||||
}
|
||||
}
|
||||
return corrections, nil
|
||||
}
|
||||
|
||||
func (n *nsone) add(recs models.Records, domain string) error {
|
||||
_, err := n.Records.Create(buildRecord(recs, domain, ""))
|
||||
return err
|
||||
}
|
||||
|
||||
func (n *nsone) remove(key models.RecordKey, domain string) error {
|
||||
_, err := n.Records.Delete(domain, dnsutil.AddOrigin(key.Name, domain), key.Type)
|
||||
return err
|
||||
}
|
||||
|
||||
func (n *nsone) modify(recs models.Records, domain string) error {
|
||||
_, err := n.Records.Update(buildRecord(recs, domain, ""))
|
||||
return err
|
||||
}
|
||||
|
||||
func buildRecord(recs models.Records, domain string, id string) *dns.Record {
|
||||
r := recs[0]
|
||||
rec := &dns.Record{
|
||||
Domain: r.NameFQDN,
|
||||
Type: r.Type,
|
||||
ID: id,
|
||||
TTL: int(r.TTL),
|
||||
Zone: domain,
|
||||
}
|
||||
for _, r := range recs {
|
||||
ans := &dns.Answer{
|
||||
Rdata: strings.Split(r.Target, " "),
|
||||
}
|
||||
rec.AddAnswer(ans)
|
||||
}
|
||||
return rec
|
||||
}
|
||||
|
||||
func convert(zr *dns.ZoneRecord, domain string) ([]*models.RecordConfig, error) {
|
||||
found := []*models.RecordConfig{}
|
||||
for _, ans := range zr.ShortAns {
|
||||
rec := &models.RecordConfig{
|
||||
NameFQDN: zr.Domain,
|
||||
Name: dnsutil.TrimDomainName(zr.Domain, domain),
|
||||
TTL: uint32(zr.TTL),
|
||||
Target: ans,
|
||||
Original: zr,
|
||||
Type: zr.Type,
|
||||
}
|
||||
if zr.Type == "MX" {
|
||||
rec.CombinedTarget = true
|
||||
}
|
||||
found = append(found, rec)
|
||||
}
|
||||
return found, nil
|
||||
}
|
Reference in New Issue
Block a user