mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2025-10-09 21:36:22 +08:00
Adding gandi to integration suite. Fixing bugs. (#57)
* Adding gandi to integration suite. Fixing bugs. Fixes #35 Fixes #36 * small fixes * gandi docs
This commit is contained in:
parent
efb8e9bbf4
commit
d205c8b4ed
6 changed files with 104 additions and 27 deletions
|
@ -26,7 +26,8 @@ This provider does not recognize any special metadata fields unique to DNSimple.
|
||||||
Example javascript:
|
Example javascript:
|
||||||
|
|
||||||
{% highlight js %}
|
{% highlight js %}
|
||||||
var DNSIMPLE = NewDnsProvider("dnsimple", DNSIMPLE);
|
var REG_DNSIMPLE = NewRegistrar("dnsimple", "DNSIMPLE");
|
||||||
|
var DNSIMPLE = NewDnsProvider("dnsimple", "DNSIMPLE");
|
||||||
|
|
||||||
D("example.tld", REG_DNSIMPLE, DnsProvider(DNSIMPLE),
|
D("example.tld", REG_DNSIMPLE, DnsProvider(DNSIMPLE),
|
||||||
A("test","1.2.3.4")
|
A("test","1.2.3.4")
|
||||||
|
|
38
docs/_providers/gandi.md
Normal file
38
docs/_providers/gandi.md
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
---
|
||||||
|
name: Gandi
|
||||||
|
layout: default
|
||||||
|
jsId: GANDI
|
||||||
|
---
|
||||||
|
# Gandi Provider
|
||||||
|
|
||||||
|
Gandi provides bot a registrar and a dns provider implementation.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
In your providers config json file you must provide your Gandi.net api key:
|
||||||
|
|
||||||
|
{% highlight json %}
|
||||||
|
{
|
||||||
|
"gandi":{
|
||||||
|
"apikey": "your-gandi-key"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{% endhighlight %}
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
|
||||||
|
This provider does not recognize any special metadata fields unique to DNSimple.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Example javascript:
|
||||||
|
|
||||||
|
{% highlight js %}
|
||||||
|
var REG_GANDI = NewRegistrar("gandi", "GANDI");
|
||||||
|
var GANDI = NewDnsProvider("gandi", "GANDI");
|
||||||
|
|
||||||
|
D("example.tld", REG_GANDI, DnsProvider(GANDI),
|
||||||
|
A("test","1.2.3.4")
|
||||||
|
);
|
||||||
|
{% endhighlight %}
|
||||||
|
|
|
@ -3,11 +3,18 @@
|
||||||
"domain": "example.com"
|
"domain": "example.com"
|
||||||
},
|
},
|
||||||
"DNSIMPLE": {
|
"DNSIMPLE": {
|
||||||
|
//16/17: no ns records managable. Not even for subdomains.
|
||||||
"knownFailures": "16,17",
|
"knownFailures": "16,17",
|
||||||
"domain": "$DNSIMPLE_DOMAIN",
|
"domain": "$DNSIMPLE_DOMAIN",
|
||||||
"token": "$DNSIMPLE_TOKEN",
|
"token": "$DNSIMPLE_TOKEN",
|
||||||
"baseurl": "https://api.sandbox.dnsimple.com"
|
"baseurl": "https://api.sandbox.dnsimple.com"
|
||||||
},
|
},
|
||||||
|
"GANDI":{
|
||||||
|
//5: gandi does not accept ttls less than 300
|
||||||
|
"knownFailures": "5",
|
||||||
|
"domain": "$GANDI_DOMAIN",
|
||||||
|
"apikey": "$GANDI_KEY"
|
||||||
|
},
|
||||||
"GCLOUD": {
|
"GCLOUD": {
|
||||||
"domain": "$GCLOUD_DOMAIN",
|
"domain": "$GCLOUD_DOMAIN",
|
||||||
"project_id": "$GCLOUD_PROJECT",
|
"project_id": "$GCLOUD_PROJECT",
|
||||||
|
|
|
@ -191,6 +191,17 @@ func (dc *DomainConfig) Punycode() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CombineMXs will merge the priority into the target field for all mx records.
|
||||||
|
// Useful for providers that desire them as one field.
|
||||||
|
func (dc *DomainConfig) CombineMXs() {
|
||||||
|
for _, rec := range dc.Records {
|
||||||
|
if rec.Type == "MX" {
|
||||||
|
rec.Target = fmt.Sprintf("%d %s", rec.Priority, rec.Target)
|
||||||
|
rec.Priority = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func copyObj(input interface{}, output interface{}) error {
|
func copyObj(input interface{}, output interface{}) error {
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
enc := gob.NewEncoder(buf)
|
enc := gob.NewEncoder(buf)
|
||||||
|
|
|
@ -3,11 +3,14 @@ package gandi
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
"github.com/StackExchange/dnscontrol/models"
|
"github.com/StackExchange/dnscontrol/models"
|
||||||
"github.com/StackExchange/dnscontrol/providers"
|
"github.com/StackExchange/dnscontrol/providers"
|
||||||
"github.com/StackExchange/dnscontrol/providers/diff"
|
"github.com/StackExchange/dnscontrol/providers/diff"
|
||||||
|
|
||||||
|
"strings"
|
||||||
|
|
||||||
gandidomain "github.com/prasmussen/gandi-api/domain"
|
gandidomain "github.com/prasmussen/gandi-api/domain"
|
||||||
gandirecord "github.com/prasmussen/gandi-api/domain/zone/record"
|
gandirecord "github.com/prasmussen/gandi-api/domain/zone/record"
|
||||||
)
|
)
|
||||||
|
@ -56,48 +59,63 @@ func (c *GandiApi) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *GandiApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
func (c *GandiApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||||
|
dc.Punycode()
|
||||||
|
dc.CombineMXs()
|
||||||
domaininfo, err := c.getDomainInfo(dc.Name)
|
domaininfo, err := c.getDomainInfo(dc.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
foundRecords, err := c.getZoneRecords(domaininfo.ZoneId)
|
foundRecords, err := c.getZoneRecords(domaininfo.ZoneId, dc.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedRecordSets := make([]gandirecord.RecordSet, len(dc.Records))
|
expectedRecordSets := make([]gandirecord.RecordSet, 0, len(dc.Records))
|
||||||
for i, rec := range dc.Records {
|
recordsToKeep := make([]*models.RecordConfig, 0, len(dc.Records))
|
||||||
if rec.Type == "MX" {
|
for _, rec := range dc.Records {
|
||||||
rec.Target = fmt.Sprintf("%d %s", rec.Priority, rec.Target)
|
if rec.TTL < 300 {
|
||||||
|
log.Printf("WARNING: Gandi does not support ttls < 300. %s will not be set to %d.", rec.NameFQDN, rec.TTL)
|
||||||
|
rec.TTL = 300
|
||||||
}
|
}
|
||||||
if rec.Type == "TXT" {
|
if rec.Type == "TXT" {
|
||||||
rec.Target = "\"" + rec.Target + "\"" // FIXME(tlim): Should do proper quoting.
|
rec.Target = "\"" + rec.Target + "\"" // FIXME(tlim): Should do proper quoting.
|
||||||
}
|
}
|
||||||
expectedRecordSets[i] = gandirecord.RecordSet{}
|
if rec.Type == "NS" && rec.Name == "@" {
|
||||||
expectedRecordSets[i]["type"] = rec.Type
|
if !strings.HasSuffix(rec.Target, ".gandi.net.") {
|
||||||
expectedRecordSets[i]["name"] = rec.Name
|
log.Printf("WARNING: Gandi does not support changing apex NS records. %s will not be added.", rec.Target)
|
||||||
expectedRecordSets[i]["value"] = rec.Target
|
|
||||||
expectedRecordSets[i]["ttl"] = rec.TTL
|
|
||||||
}
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
rs := gandirecord.RecordSet{
|
||||||
|
"type": rec.Type,
|
||||||
|
"name": rec.Name,
|
||||||
|
"value": rec.Target,
|
||||||
|
"ttl": rec.TTL,
|
||||||
|
}
|
||||||
|
expectedRecordSets = append(expectedRecordSets, rs)
|
||||||
|
recordsToKeep = append(recordsToKeep, rec)
|
||||||
|
}
|
||||||
|
dc.Records = recordsToKeep
|
||||||
differ := diff.New(dc)
|
differ := diff.New(dc)
|
||||||
_, create, del, mod := differ.IncrementalDiff(foundRecords)
|
_, create, del, mod := differ.IncrementalDiff(foundRecords)
|
||||||
|
|
||||||
// Print a list of changes. Generate an actual change that is the zone
|
// Print a list of changes. Generate an actual change that is the zone
|
||||||
changes := false
|
changes := false
|
||||||
|
desc := ""
|
||||||
for _, i := range create {
|
for _, i := range create {
|
||||||
changes = true
|
changes = true
|
||||||
fmt.Println(i)
|
desc += "\n" + i.String()
|
||||||
}
|
}
|
||||||
for _, i := range del {
|
for _, i := range del {
|
||||||
changes = true
|
changes = true
|
||||||
fmt.Println(i)
|
desc += "\n" + i.String()
|
||||||
}
|
}
|
||||||
for _, i := range mod {
|
for _, i := range mod {
|
||||||
changes = true
|
changes = true
|
||||||
fmt.Println(i)
|
desc += "\n" + i.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := fmt.Sprintf("GENERATE_ZONE: %s (%d records)", dc.Name, len(dc.Records))
|
msg := fmt.Sprintf("GENERATE_ZONE: %s (%d records)%s", dc.Name, len(dc.Records), desc)
|
||||||
corrections := []*models.Correction{}
|
corrections := []*models.Correction{}
|
||||||
if changes {
|
if changes {
|
||||||
corrections = append(corrections,
|
corrections = append(corrections,
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
gandiversion "github.com/prasmussen/gandi-api/domain/zone/version"
|
gandiversion "github.com/prasmussen/gandi-api/domain/zone/version"
|
||||||
|
|
||||||
"github.com/StackExchange/dnscontrol/models"
|
"github.com/StackExchange/dnscontrol/models"
|
||||||
|
"github.com/miekg/dns/dnsutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// fetchDomainList gets list of domains for account. Cache ids for easy lookup.
|
// fetchDomainList gets list of domains for account. Cache ids for easy lookup.
|
||||||
|
@ -39,7 +40,7 @@ func (c *GandiApi) fetchDomainInfo(fqdn string) (*gandidomain.DomainInfo, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getRecordsForDomain returns a list of records for a zone.
|
// getRecordsForDomain returns a list of records for a zone.
|
||||||
func (c *GandiApi) getZoneRecords(zoneid int64) ([]*models.RecordConfig, error) {
|
func (c *GandiApi) getZoneRecords(zoneid int64, origin string) ([]*models.RecordConfig, error) {
|
||||||
gc := gandiclient.New(c.ApiKey, gandiclient.Production)
|
gc := gandiclient.New(c.ApiKey, gandiclient.Production)
|
||||||
record := gandirecord.New(gc)
|
record := gandirecord.New(gc)
|
||||||
recs, err := record.List(zoneid, 0)
|
recs, err := record.List(zoneid, 0)
|
||||||
|
@ -48,7 +49,7 @@ func (c *GandiApi) getZoneRecords(zoneid int64) ([]*models.RecordConfig, error)
|
||||||
}
|
}
|
||||||
rcs := make([]*models.RecordConfig, 0, len(recs))
|
rcs := make([]*models.RecordConfig, 0, len(recs))
|
||||||
for _, r := range recs {
|
for _, r := range recs {
|
||||||
rcs = append(rcs, convert(r))
|
rcs = append(rcs, convert(r, origin))
|
||||||
}
|
}
|
||||||
return rcs, nil
|
return rcs, nil
|
||||||
}
|
}
|
||||||
|
@ -133,37 +134,37 @@ func (c *GandiApi) activateVersion(zone_id, version_id int64) (bool, error) {
|
||||||
return version.Set(zone_id, version_id)
|
return version.Set(zone_id, version_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *GandiApi) createGandiZone(domainname string, zone_id int64, records []gandirecord.RecordSet) error {
|
func (c *GandiApi) createGandiZone(domainname string, zoneID int64, records []gandirecord.RecordSet) error {
|
||||||
|
|
||||||
// Get the zone_id of the zone we'll be updating.
|
// Get the zone_id of the zone we'll be updating.
|
||||||
zoneinfo, err := c.getZoneInfo(zone_id)
|
zoneinfo, err := c.getZoneInfo(zoneID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
//fmt.Println("ZONEINFO:", zoneinfo)
|
//fmt.Println("ZONEINFO:", zoneinfo)
|
||||||
zone_id, err = c.getEditableZone(domainname, zoneinfo)
|
zoneID, err = c.getEditableZone(domainname, zoneinfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the version_id of the zone we're updating.
|
// Get the versionID of the zone we're updating.
|
||||||
version_id, err := c.makeEditableZone(zone_id)
|
versionID, err := c.makeEditableZone(zoneID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the new version.
|
// Update the new version.
|
||||||
_, err = c.setZoneRecords(zone_id, version_id, records)
|
_, err = c.setZoneRecords(zoneID, versionID, records)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Activate zone version
|
// Activate zone version
|
||||||
_, err = c.activateVersion(zone_id, version_id)
|
_, err = c.activateVersion(zoneID, versionID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = c.setZones(domainname, zone_id)
|
_, err = c.setZones(domainname, zoneID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -171,9 +172,10 @@ func (c *GandiApi) createGandiZone(domainname string, zone_id int64, records []g
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func convert(r *gandirecord.RecordInfo) *models.RecordConfig {
|
func convert(r *gandirecord.RecordInfo, origin string) *models.RecordConfig {
|
||||||
return &models.RecordConfig{
|
return &models.RecordConfig{
|
||||||
NameFQDN: r.Name,
|
NameFQDN: dnsutil.AddOrigin(r.Name, origin),
|
||||||
|
Name: r.Name,
|
||||||
Type: r.Type,
|
Type: r.Type,
|
||||||
Original: r,
|
Original: r,
|
||||||
Target: r.Value,
|
Target: r.Value,
|
||||||
|
|
Loading…
Add table
Reference in a new issue