mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-05-11 05:55:12 +00:00
NEW PROVIDER: OctoDNS (#309)
* govendor gopkg.in/yaml.v2 * Ignore YAML and BIND test data litter. Create README.txt files to force git to create subdirectories. * Update convertzone to also read OctoDNS files
This commit is contained in:
170
providers/octodns/octodnsProvider.go
Normal file
170
providers/octodns/octodnsProvider.go
Normal file
@@ -0,0 +1,170 @@
|
||||
package octodns
|
||||
|
||||
/*
|
||||
|
||||
octodns -
|
||||
Generate zonefiles suitiable for OctoDNS.
|
||||
|
||||
The zonefiles are read and written to the directory octoconfig
|
||||
|
||||
If the old octoconfig files are readable, we read them to determine
|
||||
if an update is actually needed.
|
||||
|
||||
The YAML input and output code is extremely complicated because
|
||||
the format does not fit well with a statically typed language.
|
||||
The YAML format changes drastically if the label has single
|
||||
or multiple rtypes associated with it, and if there is a single
|
||||
or multiple rtype data.
|
||||
|
||||
*/
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/models"
|
||||
"github.com/StackExchange/dnscontrol/providers"
|
||||
"github.com/StackExchange/dnscontrol/providers/diff"
|
||||
"github.com/StackExchange/dnscontrol/providers/octodns/octoyaml"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var features = providers.DocumentationNotes{
|
||||
//providers.CanUseCAA: providers.Can(),
|
||||
providers.CanUsePTR: providers.Can(),
|
||||
providers.CanUseSRV: providers.Can(),
|
||||
//providers.CanUseTXTMulti: providers.Can(),
|
||||
providers.DocCreateDomains: providers.Cannot("Driver just maintains list of OctoDNS config files. You must manually create the master config files that refer these."),
|
||||
providers.DocDualHost: providers.Cannot("Research is needed."),
|
||||
}
|
||||
|
||||
func initProvider(config map[string]string, providermeta json.RawMessage) (providers.DNSServiceProvider, error) {
|
||||
// config -- the key/values from creds.json
|
||||
// meta -- the json blob from NewReq('name', 'TYPE', meta)
|
||||
api := &Provider{
|
||||
directory: config["directory"],
|
||||
}
|
||||
if api.directory == "" {
|
||||
api.directory = "config"
|
||||
}
|
||||
if len(providermeta) != 0 {
|
||||
err := json.Unmarshal(providermeta, api)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
//api.nameservers = models.StringsToNameservers(api.DefaultNS)
|
||||
return api, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
providers.RegisterDomainServiceProviderType("OCTODNS", initProvider, features)
|
||||
}
|
||||
|
||||
// Provider is the provider handle for the OctoDNS driver.
|
||||
type Provider struct {
|
||||
//DefaultNS []string `json:"default_ns"`
|
||||
//DefaultSoa SoaInfo `json:"default_soa"`
|
||||
//nameservers []*models.Nameserver
|
||||
directory string
|
||||
}
|
||||
|
||||
// GetNameservers returns the nameservers for a domain.
|
||||
func (c *Provider) GetNameservers(string) ([]*models.Nameserver, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns a list of corrections to update a domain.
|
||||
func (c *Provider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc.Punycode()
|
||||
// Phase 1: Copy everything to []*models.RecordConfig:
|
||||
// expectedRecords < dc.Records[i]
|
||||
// foundRecords < zonefile
|
||||
//
|
||||
// Phase 2: Do any manipulations:
|
||||
// add NS
|
||||
// manipulate SOA
|
||||
//
|
||||
// Phase 3: Convert to []diff.Records and compare:
|
||||
// expectedDiffRecords < expectedRecords
|
||||
// foundDiffRecords < foundRecords
|
||||
// diff.Inc...(foundDiffRecords, expectedDiffRecords )
|
||||
|
||||
// Read foundRecords:
|
||||
var foundRecords models.Records
|
||||
zoneFileFound := true
|
||||
zoneFileName := filepath.Join(c.directory, strings.Replace(strings.ToLower(dc.Name), "/", "_", -1)+".yaml")
|
||||
foundFH, err := os.Open(zoneFileName)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
zoneFileFound = false
|
||||
} else {
|
||||
return nil, errors.Wrapf(err, "can't open %s:", zoneFileName)
|
||||
}
|
||||
} else {
|
||||
foundRecords, err = octoyaml.ReadYaml(foundFH, dc.Name)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "can not get corrections")
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(foundRecords)
|
||||
|
||||
differ := diff.New(dc)
|
||||
_, create, del, mod := differ.IncrementalDiff(foundRecords)
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
// Print a list of changes. Generate an actual change that is the zone
|
||||
changes := false
|
||||
for _, i := range create {
|
||||
changes = true
|
||||
fmt.Fprintln(buf, i)
|
||||
}
|
||||
for _, i := range del {
|
||||
changes = true
|
||||
fmt.Fprintln(buf, i)
|
||||
}
|
||||
for _, i := range mod {
|
||||
changes = true
|
||||
fmt.Fprintln(buf, i)
|
||||
}
|
||||
msg := fmt.Sprintf("GENERATE_CONFIGFILE: %s", dc.Name)
|
||||
if zoneFileFound {
|
||||
msg += "\n"
|
||||
msg += buf.String()
|
||||
} else {
|
||||
msg += fmt.Sprintf(" (%d records)\n", len(create))
|
||||
}
|
||||
corrections := []*models.Correction{}
|
||||
if changes {
|
||||
corrections = append(corrections,
|
||||
&models.Correction{
|
||||
Msg: msg,
|
||||
F: func() error {
|
||||
fmt.Printf("CREATING CONFIGFILE: %v\n", zoneFileName)
|
||||
zf, err := os.Create(zoneFileName)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not create zonefile: %v", err)
|
||||
}
|
||||
//err = WriteZoneFile(zf, dc.Records, dc.Name)
|
||||
err = octoyaml.WriteYaml(zf, dc.Records, dc.Name)
|
||||
if err != nil {
|
||||
log.Fatalf("WriteZoneFile error: %v\n", err)
|
||||
}
|
||||
err = zf.Close()
|
||||
if err != nil {
|
||||
log.Fatalf("Closing: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return corrections, nil
|
||||
}
|
Reference in New Issue
Block a user