mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-12-27 10:12:16 +08:00
parent
1a91a7f536
commit
b7c251190f
64 changed files with 540 additions and 433 deletions
|
@ -48,18 +48,18 @@ func getVersion() string {
|
|||
if *sha != "" {
|
||||
return *sha
|
||||
}
|
||||
//check teamcity build version
|
||||
// check teamcity build version
|
||||
if v := os.Getenv("BUILD_VCS_NUMBER"); v != "" {
|
||||
return v
|
||||
}
|
||||
//check git
|
||||
// check git
|
||||
cmd := exec.Command("git", "rev-parse", "HEAD")
|
||||
v, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
ver := strings.TrimSpace(string(v))
|
||||
//see if dirty
|
||||
// see if dirty
|
||||
cmd = exec.Command("git", "diff-index", "--quiet", "HEAD", "--")
|
||||
err = cmd.Run()
|
||||
// exit status 1 indicates dirty tree
|
||||
|
|
|
@ -93,11 +93,15 @@ func generateFeatureMatrix() error {
|
|||
return ioutil.WriteFile("docs/_includes/matrix.html", buf.Bytes(), 0644)
|
||||
}
|
||||
|
||||
// FeatureDef describes features.
|
||||
type FeatureDef struct {
|
||||
Name, Desc string
|
||||
}
|
||||
|
||||
// FeatureMap maps provider names to compliance documentation.
|
||||
type FeatureMap map[string]*providers.DocumentationNote
|
||||
|
||||
// SetSimple configures a provider's setting in fm.
|
||||
func (fm FeatureMap) SetSimple(name string, unknownsAllowed bool, f func() bool) {
|
||||
if f() {
|
||||
fm[name] = &providers.DocumentationNote{HasFeature: true}
|
||||
|
@ -106,6 +110,7 @@ func (fm FeatureMap) SetSimple(name string, unknownsAllowed bool, f func() bool)
|
|||
}
|
||||
}
|
||||
|
||||
// FeatureMatrix describes features and which providers support it.
|
||||
type FeatureMatrix struct {
|
||||
Features []FeatureDef
|
||||
Providers map[string]FeatureMap
|
||||
|
|
|
@ -124,7 +124,7 @@ func init() {
|
|||
hc := oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(&oauth2.Token{AccessToken: string(t)}))
|
||||
client = github.NewClient(hc)
|
||||
|
||||
//get current version if in travis build
|
||||
// get current version if in travis build
|
||||
if tc := os.Getenv("TRAVIS_COMMIT"); tc != "" {
|
||||
commitish = tc
|
||||
}
|
||||
|
|
|
@ -77,6 +77,7 @@ func (args *GetDNSConfigArgs) flags() []cli.Flag {
|
|||
)
|
||||
}
|
||||
|
||||
// GetDNSConfig reads the json-formatted IR file.
|
||||
func GetDNSConfig(args GetDNSConfigArgs) (*models.DNSConfig, error) {
|
||||
if args.JSONFile != "" {
|
||||
f, err := os.Open(args.JSONFile)
|
||||
|
@ -145,6 +146,7 @@ func (args *PrintJSONArgs) flags() []cli.Flag {
|
|||
}
|
||||
}
|
||||
|
||||
// GetCredentialsArgs encapsulates the flags/args for sub-commands that use the creds.json file.
|
||||
type GetCredentialsArgs struct {
|
||||
CredsFile string
|
||||
}
|
||||
|
@ -160,6 +162,7 @@ func (args *GetCredentialsArgs) flags() []cli.Flag {
|
|||
}
|
||||
}
|
||||
|
||||
// FilterArgs encapsulates the flags/args for sub-commands that can filter by provider or domain.
|
||||
type FilterArgs struct {
|
||||
Providers string
|
||||
Domains string
|
||||
|
|
|
@ -20,6 +20,7 @@ var _ = cmd(catUtils, func() *cli.Command {
|
|||
}
|
||||
}())
|
||||
|
||||
// CreateDomainsArgs args required for the create-domain subcommand.
|
||||
type CreateDomainsArgs struct {
|
||||
GetDNSConfigArgs
|
||||
GetCredentialsArgs
|
||||
|
@ -31,6 +32,7 @@ func (args *CreateDomainsArgs) flags() []cli.Flag {
|
|||
return flags
|
||||
}
|
||||
|
||||
// CreateDomains contains all data/flags needed to run create-domains, independently of CLI.
|
||||
func CreateDomains(args CreateDomainsArgs) error {
|
||||
cfg, err := GetDNSConfig(args.GetDNSConfigArgs)
|
||||
if err != nil {
|
||||
|
|
|
@ -52,6 +52,7 @@ var _ = cmd(catMain, func() *cli.Command {
|
|||
}
|
||||
}())
|
||||
|
||||
// PushArgs contains all data/flags needed to run push, independently of CLI
|
||||
type PushArgs struct {
|
||||
PreviewArgs
|
||||
Interactive bool
|
||||
|
@ -67,10 +68,12 @@ func (args *PushArgs) flags() []cli.Flag {
|
|||
return flags
|
||||
}
|
||||
|
||||
// Preview implements the preview subcommand.
|
||||
func Preview(args PreviewArgs) error {
|
||||
return run(args, false, false, printer.ConsolePrinter{})
|
||||
}
|
||||
|
||||
// Push implements the push subcommand.
|
||||
func Push(args PushArgs) error {
|
||||
return run(args.PreviewArgs, true, args.Interactive, printer.ConsolePrinter{})
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ var _ = cmd(catDebug, func() *cli.Command {
|
|||
}
|
||||
}())
|
||||
|
||||
// PrintIRArgs encapsulates the flags/arguments for the print-ir command.
|
||||
type PrintIRArgs struct {
|
||||
GetDNSConfigArgs
|
||||
PrintJSONArgs
|
||||
|
@ -62,6 +63,7 @@ func (args *PrintIRArgs) flags() []cli.Flag {
|
|||
return flags
|
||||
}
|
||||
|
||||
// PrintIR implements the print-ir subcommand.
|
||||
func PrintIR(args PrintIRArgs) error {
|
||||
cfg, err := GetDNSConfig(args.GetDNSConfigArgs)
|
||||
if err != nil {
|
||||
|
@ -76,6 +78,7 @@ func PrintIR(args PrintIRArgs) error {
|
|||
return PrintJSON(args.PrintJSONArgs, cfg)
|
||||
}
|
||||
|
||||
// PrintValidationErrors formats and prints the validation errors and warnings.
|
||||
func PrintValidationErrors(errs []error) (fatal bool) {
|
||||
if len(errs) == 0 {
|
||||
return false
|
||||
|
@ -92,6 +95,7 @@ func PrintValidationErrors(errs []error) (fatal bool) {
|
|||
return
|
||||
}
|
||||
|
||||
// ExecuteDSL executes the dnsconfig.js contents.
|
||||
func ExecuteDSL(args ExecuteDSLArgs) (*models.DNSConfig, error) {
|
||||
if args.JSFile == "" {
|
||||
return nil, fmt.Errorf("No config specified")
|
||||
|
@ -107,6 +111,7 @@ func ExecuteDSL(args ExecuteDSLArgs) (*models.DNSConfig, error) {
|
|||
return dnsConfig, nil
|
||||
}
|
||||
|
||||
// PrintJSON outputs/prettyprints the IR data.
|
||||
func PrintJSON(args PrintJSONArgs, config *models.DNSConfig) (err error) {
|
||||
var dat []byte
|
||||
if args.Pretty {
|
||||
|
|
|
@ -22,13 +22,13 @@ Modifier arguments are processed according to type as follows:
|
|||
var REGISTRAR = NewRegistrar("name.com", "NAMEDOTCOM");
|
||||
var r53 = NewDnsProvider("R53","ROUTE53");
|
||||
|
||||
//simple domain
|
||||
// simple domain
|
||||
D("example.com", REGISTRAR, DnsProvider(r53),
|
||||
A("@","1.2.3.4"),
|
||||
CNAME("test", "foo.example2.com.")
|
||||
);
|
||||
|
||||
//"macro" for records that can be mixed into any zone
|
||||
// "macro" for records that can be mixed into any zone
|
||||
var GOOGLE_APPS_DOMAIN_MX = [
|
||||
MX('@', 1, 'aspmx.l.google.com.'),
|
||||
MX('@', 5, 'alt1.aspmx.l.google.com.'),
|
||||
|
@ -44,4 +44,4 @@ D("example.com", REGISTRAR, DnsProvider(r53),
|
|||
);
|
||||
|
||||
{%endhighlight%}
|
||||
{% include endExample.html %}
|
||||
{% include endExample.html %}
|
||||
|
|
|
@ -10,14 +10,14 @@ arguments passed as if they were the first modifiers in the argument list.
|
|||
{% include startExample.html %}
|
||||
{% highlight js %}
|
||||
var COMMON = NewDnsProvider("foo","BIND");
|
||||
//we want to create backup zone files for all domains, but not actually register them.
|
||||
//also create a default TTL
|
||||
// we want to create backup zone files for all domains, but not actually register them.
|
||||
// also create a default TTL
|
||||
DEFAULTS( DnsProvider(COMMON,0), DefaultTTL(1000));
|
||||
|
||||
D("example.com", REGISTRAR, DnsProvider("R53"), A("@","1.2.3.4")); //this domain will have the defaults set.
|
||||
D("example.com", REGISTRAR, DnsProvider("R53"), A("@","1.2.3.4")); // this domain will have the defaults set.
|
||||
|
||||
//clear defaults
|
||||
// clear defaults
|
||||
DEFAULTS();
|
||||
D("example2.com", REGISTRAR, DnsProvider("R53"), A("@","1.2.3.4")); //this domain will not have the previous defaults.
|
||||
D("example2.com", REGISTRAR, DnsProvider("R53"), A("@","1.2.3.4")); // this domain will not have the previous defaults.
|
||||
{%endhighlight%}
|
||||
{% include endExample.html %}
|
||||
{% include endExample.html %}
|
||||
|
|
|
@ -100,7 +100,7 @@ list.
|
|||
Each entry in the list is a new state. For example:
|
||||
|
||||
```
|
||||
//MX
|
||||
// MX
|
||||
tc("Empty"), <<< 1
|
||||
tc("MX record", mx("@", 5, "foo.com.")), <<< 2
|
||||
tc("Change MX pref", mx("@", 10, "foo.com.")), <<< 3
|
||||
|
|
|
@ -46,8 +46,8 @@ D('example.com', registrar,
|
|||
var addrA = IP('1.2.3.4')
|
||||
|
||||
D('example.com', REG, DnsProvider('R53'),
|
||||
A('@', addrA), //1.2.3.4
|
||||
A('www', addrA + 1), //1.2.3.5
|
||||
A('@', addrA), // 1.2.3.4
|
||||
A('www', addrA + 1), // 1.2.3.5
|
||||
)
|
||||
{% endhighlight %}
|
||||
|
||||
|
|
|
@ -64,13 +64,13 @@ If you are using other providers, you will likely need to make a `creds.json` fi
|
|||
|
||||
{% highlight js %}
|
||||
{
|
||||
"cloudflare":{ //provider name to be used in dnsconfig.js
|
||||
"apikey": "key", //API key
|
||||
"apiuser": "username" //username for cloudflare
|
||||
"cloudflare":{ // provider name to be used in dnsconfig.js
|
||||
"apikey": "key", // API key
|
||||
"apiuser": "username" // username for cloudflare
|
||||
},
|
||||
"namecom":{ //provider name to be used in dnsconfig.js
|
||||
"apikey": "key", //API Key
|
||||
"apiuser": "username" //username for name.com
|
||||
"namecom":{ // provider name to be used in dnsconfig.js
|
||||
"apikey": "key", // API Key
|
||||
"apiuser": "username" // username for name.com
|
||||
}
|
||||
}
|
||||
{%endhighlight%}
|
||||
|
|
|
@ -136,7 +136,7 @@ func runTests(t *testing.T, prv providers.DNSServiceProvider, domainName string,
|
|||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
//run a second time and expect zero corrections
|
||||
// run a second time and expect zero corrections
|
||||
corrections, err = prv.GetDomainCorrections(dom2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -296,7 +296,7 @@ func manyA(namePattern, target string, n int) []*rec {
|
|||
}
|
||||
|
||||
func makeTests(t *testing.T) []*TestCase {
|
||||
//ALWAYS ADD TO BOTTOM OF LIST. Order and indexes matter.
|
||||
// ALWAYS ADD TO BOTTOM OF LIST. Order and indexes matter.
|
||||
tests := []*TestCase{
|
||||
// A
|
||||
tc("Empty"),
|
||||
|
@ -319,20 +319,20 @@ func makeTests(t *testing.T) []*TestCase {
|
|||
tc("Change back to CNAME", cname("foo", "google.com.")),
|
||||
tc("Record pointing to @", cname("foo", "**current-domain**")),
|
||||
|
||||
//NS
|
||||
// NS
|
||||
tc("Empty"),
|
||||
tc("NS for subdomain", ns("xyz", "ns2.foo.com.")),
|
||||
tc("Dual NS for subdomain", ns("xyz", "ns2.foo.com."), ns("xyz", "ns1.foo.com.")),
|
||||
tc("NS Record pointing to @", ns("foo", "**current-domain**")),
|
||||
|
||||
//IDNAs
|
||||
// IDNAs
|
||||
tc("Empty"),
|
||||
tc("Internationalized name", a("ööö", "1.2.3.4")),
|
||||
tc("Change IDN", a("ööö", "2.2.2.2")),
|
||||
tc("Internationalized CNAME Target", cname("a", "ööö.com.")),
|
||||
tc("IDN CNAME AND Target", cname("öoö", "ööö.企业.")),
|
||||
|
||||
//MX
|
||||
// MX
|
||||
tc("Empty"),
|
||||
tc("MX record", mx("@", 5, "foo.com.")),
|
||||
tc("Second MX record, same prio", mx("@", 5, "foo.com."), mx("@", 5, "foo2.com.")),
|
||||
|
@ -394,7 +394,7 @@ func makeTests(t *testing.T) []*TestCase {
|
|||
)
|
||||
}
|
||||
|
||||
//TLSA
|
||||
// TLSA
|
||||
if !providers.ProviderHasCabability(*providerToRun, providers.CanUseTLSA) {
|
||||
t.Log("Skipping TLSA Tests because provider does not support them")
|
||||
} else {
|
||||
|
@ -425,7 +425,7 @@ func makeTests(t *testing.T) []*TestCase {
|
|||
// Known page sizes:
|
||||
// - gandi: 100
|
||||
skip := map[string]bool{
|
||||
"NS1": true, //ns1 free acct only allows 50 records
|
||||
"NS1": true, // ns1 free acct only allows 50 records
|
||||
}
|
||||
if skip[*providerToRun] {
|
||||
t.Log("Skipping Large record count Tests because provider does not support them")
|
||||
|
|
2
main.go
2
main.go
|
@ -34,7 +34,7 @@ func versionString() string {
|
|||
if SHA != "" {
|
||||
version = fmt.Sprintf("%s (%s)", Version, SHA)
|
||||
} else {
|
||||
version = fmt.Sprintf("%s-dev", Version) //no SHA. '0.x.y-dev' indicates it is run from source without build script.
|
||||
version = fmt.Sprintf("%s-dev", Version) // no SHA. '0.x.y-dev' indicates it is run from source without build script.
|
||||
}
|
||||
if BuildTime != "" {
|
||||
i, err := strconv.ParseInt(BuildTime, 10, 64)
|
||||
|
|
120
models/dns.go
120
models/dns.go
|
@ -16,14 +16,17 @@ import (
|
|||
"golang.org/x/net/idna"
|
||||
)
|
||||
|
||||
// DefaultTTL is applied to any DNS record without an explicit TTL.
|
||||
const DefaultTTL = uint32(300)
|
||||
|
||||
// DNSConfig describes the desired DNS configuration, usually loaded from dnsconfig.js.
|
||||
type DNSConfig struct {
|
||||
Registrars []*RegistrarConfig `json:"registrars"`
|
||||
DNSProviders []*DNSProviderConfig `json:"dns_providers"`
|
||||
Domains []*DomainConfig `json:"domains"`
|
||||
}
|
||||
|
||||
// FindDomain returns the *DomainConfig for domain query in config.
|
||||
func (config *DNSConfig) FindDomain(query string) *DomainConfig {
|
||||
for _, b := range config.Domains {
|
||||
if b.Name == query {
|
||||
|
@ -33,12 +36,14 @@ func (config *DNSConfig) FindDomain(query string) *DomainConfig {
|
|||
return nil
|
||||
}
|
||||
|
||||
// RegistrarConfig describes a registrar.
|
||||
type RegistrarConfig struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Metadata json.RawMessage `json:"meta,omitempty"`
|
||||
}
|
||||
|
||||
// DNSProviderConfig describes a DNS service provider.
|
||||
type DNSProviderConfig struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
|
@ -108,53 +113,53 @@ type RecordConfig struct {
|
|||
Original interface{} `json:"-"` // Store pointer to provider-specific record object. Used in diffing.
|
||||
}
|
||||
|
||||
func (r *RecordConfig) String() (content string) {
|
||||
if r.CombinedTarget {
|
||||
return r.Target
|
||||
func (rc *RecordConfig) String() (content string) {
|
||||
if rc.CombinedTarget {
|
||||
return rc.Target
|
||||
}
|
||||
|
||||
content = fmt.Sprintf("%s %s %s %d", r.Type, r.NameFQDN, r.Target, r.TTL)
|
||||
switch r.Type { // #rtype_variations
|
||||
content = fmt.Sprintf("%s %s %s %d", rc.Type, rc.NameFQDN, rc.Target, rc.TTL)
|
||||
switch rc.Type { // #rtype_variations
|
||||
case "A", "AAAA", "CNAME", "NS", "PTR", "TXT":
|
||||
// Nothing special.
|
||||
case "MX":
|
||||
content += fmt.Sprintf(" pref=%d", r.MxPreference)
|
||||
content += fmt.Sprintf(" pref=%d", rc.MxPreference)
|
||||
case "SOA":
|
||||
content = fmt.Sprintf("%s %s %s %d", r.Type, r.Name, r.Target, r.TTL)
|
||||
content = fmt.Sprintf("%s %s %s %d", rc.Type, rc.Name, rc.Target, rc.TTL)
|
||||
case "SRV":
|
||||
content += fmt.Sprintf(" srvpriority=%d srvweight=%d srvport=%d", r.SrvPriority, r.SrvWeight, r.SrvPort)
|
||||
content += fmt.Sprintf(" srvpriority=%d srvweight=%d srvport=%d", rc.SrvPriority, rc.SrvWeight, rc.SrvPort)
|
||||
case "TLSA":
|
||||
content += fmt.Sprintf(" tlsausage=%d tlsaselector=%d tlsamatchingtype=%d", r.TlsaUsage, r.TlsaSelector, r.TlsaMatchingType)
|
||||
content += fmt.Sprintf(" tlsausage=%d tlsaselector=%d tlsamatchingtype=%d", rc.TlsaUsage, rc.TlsaSelector, rc.TlsaMatchingType)
|
||||
case "CAA":
|
||||
content += fmt.Sprintf(" caatag=%s caaflag=%d", r.CaaTag, r.CaaFlag)
|
||||
content += fmt.Sprintf(" caatag=%s caaflag=%d", rc.CaaTag, rc.CaaFlag)
|
||||
default:
|
||||
msg := fmt.Sprintf("rc.String rtype %v unimplemented", r.Type)
|
||||
msg := fmt.Sprintf("rc.String rtype %v unimplemented", rc.Type)
|
||||
panic(msg)
|
||||
// We panic so that we quickly find any switch statements
|
||||
// that have not been updated for a new RR type.
|
||||
}
|
||||
for k, v := range r.Metadata {
|
||||
for k, v := range rc.Metadata {
|
||||
content += fmt.Sprintf(" %s=%s", k, v)
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
// Content combines Target and other fields into one string.
|
||||
func (r *RecordConfig) Content() string {
|
||||
if r.CombinedTarget {
|
||||
return r.Target
|
||||
func (rc *RecordConfig) Content() string {
|
||||
if rc.CombinedTarget {
|
||||
return rc.Target
|
||||
}
|
||||
|
||||
// If this is a pseudo record, just return the target.
|
||||
if _, ok := dns.StringToType[r.Type]; !ok {
|
||||
return r.Target
|
||||
if _, ok := dns.StringToType[rc.Type]; !ok {
|
||||
return rc.Target
|
||||
}
|
||||
|
||||
// We cheat by converting to a dns.RR and use the String() function.
|
||||
// Sadly that function always includes a header, which we must strip out.
|
||||
// TODO(tlim): Request the dns project add a function that returns
|
||||
// the string without the header.
|
||||
rr := r.ToRR()
|
||||
rr := rc.ToRR()
|
||||
header := rr.Header().String()
|
||||
full := rr.String()
|
||||
if !strings.HasPrefix(full, header) {
|
||||
|
@ -164,30 +169,30 @@ func (r *RecordConfig) Content() string {
|
|||
}
|
||||
|
||||
// MergeToTarget combines "extra" fields into .Target, and zeros the merged fields.
|
||||
func (r *RecordConfig) MergeToTarget() {
|
||||
if r.CombinedTarget {
|
||||
pm := strings.Join([]string{"MergeToTarget: Already collapsed: ", r.Name, r.Target}, " ")
|
||||
func (rc *RecordConfig) MergeToTarget() {
|
||||
if rc.CombinedTarget {
|
||||
pm := strings.Join([]string{"MergeToTarget: Already collapsed: ", rc.Name, rc.Target}, " ")
|
||||
panic(pm)
|
||||
}
|
||||
|
||||
// Merge "extra" fields into the Target.
|
||||
r.Target = r.Content()
|
||||
rc.Target = rc.Content()
|
||||
|
||||
// Zap any fields that may have been merged.
|
||||
r.MxPreference = 0
|
||||
r.SrvPriority = 0
|
||||
r.SrvWeight = 0
|
||||
r.SrvPort = 0
|
||||
r.CaaFlag = 0
|
||||
r.CaaTag = ""
|
||||
r.TlsaUsage = 0
|
||||
r.TlsaMatchingType = 0
|
||||
r.TlsaSelector = 0
|
||||
rc.MxPreference = 0
|
||||
rc.SrvPriority = 0
|
||||
rc.SrvWeight = 0
|
||||
rc.SrvPort = 0
|
||||
rc.CaaFlag = 0
|
||||
rc.CaaTag = ""
|
||||
rc.TlsaUsage = 0
|
||||
rc.TlsaMatchingType = 0
|
||||
rc.TlsaSelector = 0
|
||||
|
||||
r.CombinedTarget = true
|
||||
rc.CombinedTarget = true
|
||||
}
|
||||
|
||||
/// Convert RecordConfig -> dns.RR.
|
||||
// ToRR converts a RecordConfig to a dns.RR.
|
||||
func (rc *RecordConfig) ToRR() dns.RR {
|
||||
|
||||
// Don't call this on fake types.
|
||||
|
@ -266,8 +271,10 @@ func atou32(s string) uint32 {
|
|||
return uint32(i64)
|
||||
}
|
||||
|
||||
// Records is a list of *RecordConfig.
|
||||
type Records []*RecordConfig
|
||||
|
||||
// Grouped returns a map of keys to records.
|
||||
func (r Records) Grouped() map[RecordKey]Records {
|
||||
groups := map[RecordKey]Records{}
|
||||
for _, rec := range r {
|
||||
|
@ -310,20 +317,24 @@ func fixTxt(recs []*RecordConfig) {
|
|||
}
|
||||
}
|
||||
|
||||
// RecordKey represents a resource record in a format used by some systems.
|
||||
type RecordKey struct {
|
||||
Name string
|
||||
Type string
|
||||
}
|
||||
|
||||
func (r *RecordConfig) Key() RecordKey {
|
||||
return RecordKey{r.Name, r.Type}
|
||||
// Key converts a RecordConfig into a RecordKey.
|
||||
func (rc *RecordConfig) Key() RecordKey {
|
||||
return RecordKey{rc.Name, rc.Type}
|
||||
}
|
||||
|
||||
// Nameserver describes a nameserver.
|
||||
type Nameserver struct {
|
||||
Name string `json:"name"` // Normalized to a FQDN with NO trailing "."
|
||||
Target string `json:"target"`
|
||||
}
|
||||
|
||||
// StringsToNameservers constructs a list of *Nameserver structs using a list of FQDNs.
|
||||
func StringsToNameservers(nss []string) []*Nameserver {
|
||||
nservers := []*Nameserver{}
|
||||
for _, ns := range nss {
|
||||
|
@ -332,6 +343,7 @@ func StringsToNameservers(nss []string) []*Nameserver {
|
|||
return nservers
|
||||
}
|
||||
|
||||
// DomainConfig describes a DNS domain (tecnically a DNS zone).
|
||||
type DomainConfig struct {
|
||||
Name string `json:"name"` // NO trailing "."
|
||||
Registrar string `json:"registrar"`
|
||||
|
@ -342,23 +354,25 @@ type DomainConfig struct {
|
|||
KeepUnknown bool `json:"keepunknown,omitempty"`
|
||||
}
|
||||
|
||||
// Copy returns a deep copy of the DomainConfig.
|
||||
func (dc *DomainConfig) Copy() (*DomainConfig, error) {
|
||||
newDc := &DomainConfig{}
|
||||
err := copyObj(dc, newDc)
|
||||
return newDc, err
|
||||
}
|
||||
|
||||
func (r *RecordConfig) Copy() (*RecordConfig, error) {
|
||||
// Copy returns a deep copy of a RecordConfig.
|
||||
func (rc *RecordConfig) Copy() (*RecordConfig, error) {
|
||||
newR := &RecordConfig{}
|
||||
err := copyObj(r, newR)
|
||||
err := copyObj(rc, newR)
|
||||
return newR, err
|
||||
}
|
||||
|
||||
//Punycode will convert all records to punycode format.
|
||||
//It will encode:
|
||||
//- Name
|
||||
//- NameFQDN
|
||||
//- Target (CNAME and MX only)
|
||||
// Punycode will convert all records to punycode format.
|
||||
// It will encode:
|
||||
// - Name
|
||||
// - NameFQDN
|
||||
// - Target (CNAME and MX only)
|
||||
func (dc *DomainConfig) Punycode() error {
|
||||
var err error
|
||||
for _, rec := range dc.Records {
|
||||
|
@ -436,9 +450,9 @@ func (dc *DomainConfig) CombineSRVs() {
|
|||
}
|
||||
}
|
||||
|
||||
//SplitCombinedSrvValue splits a combined SRV priority, weight, port and target into
|
||||
//separate entities, some DNS providers want "5" "10" 15" and "foo.com.",
|
||||
//while other providers want "5 10 15 foo.com.".
|
||||
// SplitCombinedSrvValue splits a combined SRV priority, weight, port and target into
|
||||
// separate entities, some DNS providers want "5" "10" 15" and "foo.com.",
|
||||
// while other providers want "5 10 15 foo.com.".
|
||||
func SplitCombinedSrvValue(s string) (priority, weight, port uint16, target string, err error) {
|
||||
parts := strings.Fields(s)
|
||||
|
||||
|
@ -476,6 +490,7 @@ func (dc *DomainConfig) CombineCAAs() {
|
|||
}
|
||||
}
|
||||
|
||||
// SplitCombinedCaaValue parses a string listing the parts of a CAA record into its components.
|
||||
func SplitCombinedCaaValue(s string) (tag string, flag uint8, value string, err error) {
|
||||
|
||||
splitData := strings.SplitN(s, " ", 3)
|
||||
|
@ -509,12 +524,10 @@ func copyObj(input interface{}, output interface{}) error {
|
|||
if err := enc.Encode(input); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := dec.Decode(output); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return dec.Decode(output)
|
||||
}
|
||||
|
||||
// HasRecordTypeName returns True if there is a record with this rtype and name.
|
||||
func (dc *DomainConfig) HasRecordTypeName(rtype, name string) bool {
|
||||
for _, r := range dc.Records {
|
||||
if r.Type == rtype && r.Name == name {
|
||||
|
@ -524,6 +537,7 @@ func (dc *DomainConfig) HasRecordTypeName(rtype, name string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// Filter removes all records that don't match the filter f.
|
||||
func (dc *DomainConfig) Filter(f func(r *RecordConfig) bool) {
|
||||
recs := []*RecordConfig{}
|
||||
for _, r := range dc.Records {
|
||||
|
@ -534,6 +548,10 @@ func (dc *DomainConfig) Filter(f func(r *RecordConfig) bool) {
|
|||
dc.Records = recs
|
||||
}
|
||||
|
||||
// InterfaceToIP returns an IP address when given a 32-bit value or a string. That is,
|
||||
// dnsconfig.js output may represent IP addresses as either a string ("1.2.3.4")
|
||||
// or as an numeric value (the integer representation of the 32-bit value). This function
|
||||
// converts either to a net.IP.
|
||||
func InterfaceToIP(i interface{}) (net.IP, error) {
|
||||
switch v := i.(type) {
|
||||
case float64:
|
||||
|
@ -545,11 +563,11 @@ func InterfaceToIP(i interface{}) (net.IP, error) {
|
|||
}
|
||||
return nil, fmt.Errorf("%s is not a valid ip address", v)
|
||||
default:
|
||||
return nil, fmt.Errorf("Cannot convert type %s to ip.", reflect.TypeOf(i))
|
||||
return nil, fmt.Errorf("cannot convert type %s to ip", reflect.TypeOf(i))
|
||||
}
|
||||
}
|
||||
|
||||
//Correction is anything that can be run. Implementation is up to the specific provider.
|
||||
// Correction is anything that can be run. Implementation is up to the specific provider.
|
||||
type Correction struct {
|
||||
F func() error `json:"-"`
|
||||
Msg string
|
||||
|
|
|
@ -209,7 +209,7 @@ var TLSA = recordBuilder('TLSA', {
|
|||
['usage', _.isNumber],
|
||||
['selector', _.isNumber],
|
||||
['matchingtype', _.isNumber],
|
||||
['target', _.isString], //recordBuilder needs a "target" argument
|
||||
['target', _.isString], // recordBuilder needs a "target" argument
|
||||
],
|
||||
transform: function(record, args, modifiers) {
|
||||
record.name = args.name;
|
||||
|
@ -474,7 +474,7 @@ function addRecord(d, type, name, target, mods) {
|
|||
if (_.isFunction(m)) {
|
||||
m(rec);
|
||||
} else if (_.isObject(m)) {
|
||||
//convert transforms to strings
|
||||
// convert transforms to strings
|
||||
if (m.transform && _.isArray(m.transform)) {
|
||||
m.transform = format_tt(m.transform);
|
||||
}
|
||||
|
@ -493,7 +493,7 @@ function addRecord(d, type, name, target, mods) {
|
|||
return rec;
|
||||
}
|
||||
|
||||
//ip conversion functions from http://stackoverflow.com/a/8105740/121660
|
||||
// ip conversion functions from http://stackoverflow.com/a/8105740/121660
|
||||
// via http://javascript.about.com/library/blipconvert.htm
|
||||
function IP(dot) {
|
||||
var d = dot.split('.');
|
||||
|
|
|
@ -9,12 +9,12 @@ import (
|
|||
"github.com/StackExchange/dnscontrol/pkg/transform"
|
||||
|
||||
"github.com/robertkrimen/otto"
|
||||
//load underscore js into vm by default
|
||||
// load underscore js into vm by default
|
||||
|
||||
_ "github.com/robertkrimen/otto/underscore"
|
||||
_ "github.com/robertkrimen/otto/underscore" // required by otto
|
||||
)
|
||||
|
||||
//ExecuteJavascript accepts a javascript string and runs it, returning the resulting dnsConfig.
|
||||
// ExecuteJavascript accepts a javascript string and runs it, returning the resulting dnsConfig.
|
||||
func ExecuteJavascript(script string, devMode bool) (*models.DNSConfig, error) {
|
||||
vm := otto.New()
|
||||
|
||||
|
@ -48,6 +48,7 @@ func ExecuteJavascript(script string, devMode bool) (*models.DNSConfig, error) {
|
|||
return conf, nil
|
||||
}
|
||||
|
||||
// GetHelpers returns the filename of helpers.js, or the esc'ed version.
|
||||
func GetHelpers(devMode bool) string {
|
||||
return _escFSMustString(devMode, "/helpers.js")
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ func TestParsedFiles(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
for _, f := range files {
|
||||
//run all js files that start with a number. Skip others.
|
||||
// run all js files that start with a number. Skip others.
|
||||
if filepath.Ext(f.Name()) != ".js" || !unicode.IsNumber(rune(f.Name()[0])) {
|
||||
continue
|
||||
}
|
||||
|
|
162
pkg/js/static.go
162
pkg/js/static.go
|
@ -192,89 +192,89 @@ var _escData = map[string]*_escFile{
|
|||
|
||||
"/helpers.js": {
|
||||
local: "pkg/js/helpers.js",
|
||||
size: 17431,
|
||||
size: 17434,
|
||||
modtime: 0,
|
||||
compressed: `
|
||||
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
|
||||
`,
|
||||
},
|
||||
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
//Package nameservers provides logic for dynamically finding nameservers for a domain, and configuring NS records for them.
|
||||
// Package nameservers provides logic for dynamically finding nameservers for a domain, and configuring NS records for them.
|
||||
package nameservers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"strconv"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/models"
|
||||
"github.com/StackExchange/dnscontrol/providers"
|
||||
"github.com/miekg/dns/dnsutil"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
//DetermineNameservers will find all nameservers we should use for a domain. It follows the following rules:
|
||||
//1. All explicitly defined NAMESERVER records will be used.
|
||||
//2. Each DSP declares how many nameservers to use. Default is all. 0 indicates to use none.
|
||||
// DetermineNameservers will find all nameservers we should use for a domain. It follows the following rules:
|
||||
// 1. All explicitly defined NAMESERVER records will be used.
|
||||
// 2. Each DSP declares how many nameservers to use. Default is all. 0 indicates to use none.
|
||||
func DetermineNameservers(dc *models.DomainConfig, maxNS int, dsps map[string]providers.DNSServiceProvider) ([]*models.Nameserver, error) {
|
||||
//always take explicit
|
||||
// always take explicit
|
||||
ns := dc.Nameservers
|
||||
for dsp, n := range dc.DNSProviders {
|
||||
if n == 0 {
|
||||
|
@ -41,7 +42,7 @@ func DetermineNameservers(dc *models.DomainConfig, maxNS int, dsps map[string]pr
|
|||
return ns, nil
|
||||
}
|
||||
|
||||
//AddNSRecords creates NS records on a domain corresponding to the nameservers specified.
|
||||
// AddNSRecords creates NS records on a domain corresponding to the nameservers specified.
|
||||
func AddNSRecords(dc *models.DomainConfig) {
|
||||
ttl := uint32(300)
|
||||
if ttls, ok := dc.Metadata["ns_ttl"]; ok {
|
||||
|
|
|
@ -71,7 +71,7 @@ func flattenSPFs(cfg *models.DNSConfig) []error {
|
|||
if err := cache.Save("spfcache.updated.json"); err != nil {
|
||||
errs = append(errs, err)
|
||||
} else {
|
||||
errs = append(errs, Warning{fmt.Errorf("%d spf record lookups are out of date with cache (%s).\nWrote changes to spfcache.updated.json. Please rename and commit:\n $ mv spfcache.updated.json spfcache.json\n $ git commit spfcache.json\n", len(changed), strings.Join(changed, ","))})
|
||||
errs = append(errs, Warning{fmt.Errorf("%d spf record lookups are out of date with cache (%s).\nWrote changes to spfcache.updated.json. Please rename and commit:\n $ mv spfcache.updated.json spfcache.json\n $ git commit spfcache.json", len(changed), strings.Join(changed, ","))})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ func validateRecordTypes(rec *models.RecordConfig, domain string, pTypes []strin
|
|||
return fmt.Errorf("Custom record type %s is not compatible with provider type %s", rec.Type, providerType)
|
||||
}
|
||||
}
|
||||
//it is ok. Lets replace the type with real type and add metadata to say we checked it
|
||||
// it is ok. Lets replace the type with real type and add metadata to say we checked it
|
||||
rec.Metadata["orig_custom_type"] = rec.Type
|
||||
if cType.RealType != "" {
|
||||
rec.Type = cType.RealType
|
||||
|
@ -87,7 +87,7 @@ func validateRecordTypes(rec *models.RecordConfig, domain string, pTypes []strin
|
|||
// here we list common records expected to have underscores. Anything else containing an underscore will print a warning.
|
||||
var labelUnderscores = []string{"_domainkey", "_dmarc", "_amazonses", "_acme-challenge"}
|
||||
|
||||
//these record types may contain underscores
|
||||
// these record types may contain underscores
|
||||
var rTypeUnderscores = []string{"SRV", "TLSA", "TXT"}
|
||||
|
||||
func checkLabel(label string, rType string, domain string, meta map[string]string) error {
|
||||
|
@ -116,7 +116,7 @@ func checkLabel(label string, rType string, domain string, meta map[string]strin
|
|||
return nil
|
||||
}
|
||||
}
|
||||
//underscores are warnings
|
||||
// underscores are warnings
|
||||
if strings.ContainsRune(label, '_') {
|
||||
return Warning{fmt.Errorf("label %s.%s contains an underscore", label, domain)}
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ func checkTargets(rec *models.RecordConfig, domain string) (errs []error) {
|
|||
case "TXT", "IMPORT_TRANSFORM", "CAA", "TLSA":
|
||||
default:
|
||||
if rec.Metadata["orig_custom_type"] != "" {
|
||||
//it is a valid custom type. We perform no validation on target
|
||||
// it is a valid custom type. We perform no validation on target
|
||||
return
|
||||
}
|
||||
errs = append(errs, fmt.Errorf("checkTargets: Unimplemented record type (%v) domain=%v name=%v",
|
||||
|
@ -244,6 +244,7 @@ type Warning struct {
|
|||
error
|
||||
}
|
||||
|
||||
// NormalizeAndValidateConfig performs and normalization and/or validation of the IR.
|
||||
func NormalizeAndValidateConfig(config *models.DNSConfig) (errs []error) {
|
||||
ptypeMap := map[string]string{}
|
||||
for _, p := range config.DNSProviders {
|
||||
|
@ -261,7 +262,7 @@ func NormalizeAndValidateConfig(config *models.DNSConfig) (errs []error) {
|
|||
pTypes = append(pTypes, pType)
|
||||
}
|
||||
|
||||
//If NO_PURGE is in use, make sure this *isn't* a provider that *doesn't* support NO_PURGE.
|
||||
// If NO_PURGE is in use, make sure this *isn't* a provider that *doesn't* support NO_PURGE.
|
||||
if domain.KeepUnknown && providers.ProviderHasCabability(pType, providers.CantUseNOPURGE) {
|
||||
errs = append(errs, fmt.Errorf("%s uses NO_PURGE which is not supported by %s(%s)", domain.Name, p, pType))
|
||||
}
|
||||
|
@ -366,12 +367,12 @@ func NormalizeAndValidateConfig(config *models.DNSConfig) (errs []error) {
|
|||
}
|
||||
}
|
||||
|
||||
//Check that CNAMES don't have to co-exist with any other records
|
||||
// Check that CNAMES don't have to co-exist with any other records
|
||||
for _, d := range config.Domains {
|
||||
errs = append(errs, checkCNAMEs(d)...)
|
||||
}
|
||||
|
||||
//Check that if any aliases / ptr / etc.. are used in a domain, every provider for that domain supports them
|
||||
// Check that if any aliases / ptr / etc.. are used in a domain, every provider for that domain supports them
|
||||
for _, d := range config.Domains {
|
||||
err := checkProviderCapabilities(d, config.DNSProviders)
|
||||
if err != nil {
|
||||
|
@ -449,14 +450,14 @@ func applyRecordTransforms(domain *models.DomainConfig) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ip := net.ParseIP(rec.Target) //ip already validated above
|
||||
ip := net.ParseIP(rec.Target) // ip already validated above
|
||||
newIPs, err := transform.TransformIPToList(net.ParseIP(rec.Target), table)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i, newIP := range newIPs {
|
||||
if i == 0 && !newIP.Equal(ip) {
|
||||
rec.Target = newIP.String() //replace target of first record if different
|
||||
rec.Target = newIP.String() // replace target of first record if different
|
||||
} else if i > 0 {
|
||||
// any additional ips need identical records with the alternate ip added to the domain
|
||||
copy, err := rec.Copy()
|
||||
|
|
|
@ -112,7 +112,7 @@ func Test_transform_cname(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNSAtRoot(t *testing.T) {
|
||||
//do not allow ns records for @
|
||||
// do not allow ns records for @
|
||||
rec := &models.RecordConfig{Name: "test", Type: "NS", Target: "ns1.name.com."}
|
||||
errs := checkTargets(rec, "foo.com")
|
||||
if len(errs) > 0 {
|
||||
|
|
|
@ -22,7 +22,7 @@ type CLI interface {
|
|||
PromptToRun() bool
|
||||
}
|
||||
|
||||
// Printer is a simple acstraction for printing data. Can be passed to providers to give simple output capabilities.
|
||||
// Printer is a simple abstraction for printing data. Can be passed to providers to give simple output capabilities.
|
||||
type Printer interface {
|
||||
Debugf(fmt string, args ...interface{})
|
||||
Warnf(fmt string, args ...interface{})
|
||||
|
@ -30,16 +30,20 @@ type Printer interface {
|
|||
|
||||
var reader = bufio.NewReader(os.Stdin)
|
||||
|
||||
// ConsolePrinter is a handle for the console printer.
|
||||
type ConsolePrinter struct{}
|
||||
|
||||
// StartDomain is called at the start of each domain.
|
||||
func (c ConsolePrinter) StartDomain(domain string) {
|
||||
fmt.Printf("******************** Domain: %s\n", domain)
|
||||
}
|
||||
|
||||
// PrintCorrection is called to print/format each correction.
|
||||
func (c ConsolePrinter) PrintCorrection(i int, correction *models.Correction) {
|
||||
fmt.Printf("#%d: %s\n", i+1, correction.Msg)
|
||||
}
|
||||
|
||||
// PromptToRun prompts the user to see if they want to execute a correction.
|
||||
func (c ConsolePrinter) PromptToRun() bool {
|
||||
fmt.Print("Run? (Y/n): ")
|
||||
txt, err := reader.ReadString('\n')
|
||||
|
@ -57,6 +61,7 @@ func (c ConsolePrinter) PromptToRun() bool {
|
|||
return run
|
||||
}
|
||||
|
||||
// EndCorrection is called at the end of each correction.
|
||||
func (c ConsolePrinter) EndCorrection(err error) {
|
||||
if err != nil {
|
||||
fmt.Println("FAILURE!", err)
|
||||
|
@ -65,6 +70,7 @@ func (c ConsolePrinter) EndCorrection(err error) {
|
|||
}
|
||||
}
|
||||
|
||||
// StartDNSProvider is called at the start of each new provider.
|
||||
func (c ConsolePrinter) StartDNSProvider(provider string, skip bool) {
|
||||
lbl := ""
|
||||
if skip {
|
||||
|
@ -73,6 +79,7 @@ func (c ConsolePrinter) StartDNSProvider(provider string, skip bool) {
|
|||
fmt.Printf("----- DNS Provider: %s...%s", provider, lbl)
|
||||
}
|
||||
|
||||
// StartRegistrar is called at the start of each new registrar.
|
||||
func (c ConsolePrinter) StartRegistrar(provider string, skip bool) {
|
||||
lbl := ""
|
||||
if skip {
|
||||
|
@ -81,6 +88,7 @@ func (c ConsolePrinter) StartRegistrar(provider string, skip bool) {
|
|||
fmt.Printf("----- Registrar: %s...%s", provider, lbl)
|
||||
}
|
||||
|
||||
// EndProvider is called at the end of each provider.
|
||||
func (c ConsolePrinter) EndProvider(numCorrections int, err error) {
|
||||
if err != nil {
|
||||
fmt.Println("ERROR")
|
||||
|
@ -94,10 +102,12 @@ func (c ConsolePrinter) EndProvider(numCorrections int, err error) {
|
|||
}
|
||||
}
|
||||
|
||||
// Debugf is called to print/format debug information.
|
||||
func (c ConsolePrinter) Debugf(format string, args ...interface{}) {
|
||||
fmt.Printf(format, args...)
|
||||
}
|
||||
|
||||
// Warnf is called to print/format a warning.
|
||||
func (c ConsolePrinter) Warnf(format string, args ...interface{}) {
|
||||
fmt.Printf("WARNING: "+format, args...)
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// TXT outputs s as a TXT record.
|
||||
func (s *SPFRecord) TXT() string {
|
||||
text := "v=spf1"
|
||||
for _, p := range s.Parts {
|
||||
|
@ -15,12 +16,12 @@ func (s *SPFRecord) TXT() string {
|
|||
|
||||
const maxLen = 255
|
||||
|
||||
//TXTSplit returns a set of txt records to use for SPF.
|
||||
//pattern given is used to name all chained spf records.
|
||||
//patern should include %d, which will be replaced by a counter.
|
||||
//should result in fqdn after replacement
|
||||
//returned map will have keys with fqdn of resulting records.
|
||||
//root record will be under key "@"
|
||||
// TXTSplit returns a set of txt records to use for SPF.
|
||||
// pattern given is used to name all chained spf records.
|
||||
// patern should include %d, which will be replaced by a counter.
|
||||
// should result in fqdn after replacement
|
||||
// returned map will have keys with fqdn of resulting records.
|
||||
// root record will be under key "@"
|
||||
func (s *SPFRecord) TXTSplit(pattern string) map[string]string {
|
||||
m := map[string]string{}
|
||||
s.split("@", pattern, 1, m)
|
||||
|
@ -54,7 +55,7 @@ func (s *SPFRecord) split(thisfqdn string, pattern string, nextIdx int, m map[st
|
|||
} else {
|
||||
over = true
|
||||
if addedCount == 0 {
|
||||
//the first part is too big to include. We kinda have to give up here.
|
||||
// the first part is too big to include. We kinda have to give up here.
|
||||
m[thisfqdn] = base
|
||||
return
|
||||
}
|
||||
|
@ -68,6 +69,7 @@ func (s *SPFRecord) split(thisfqdn string, pattern string, nextIdx int, m map[st
|
|||
newRec.split(nextFQDN, pattern, nextIdx+1, m)
|
||||
}
|
||||
|
||||
// Flatten optimizes s.
|
||||
func (s *SPFRecord) Flatten(spec string) *SPFRecord {
|
||||
newRec := &SPFRecord{}
|
||||
for _, p := range s.Parts {
|
||||
|
@ -75,10 +77,10 @@ func (s *SPFRecord) Flatten(spec string) *SPFRecord {
|
|||
// non-includes copy straight over
|
||||
newRec.Parts = append(newRec.Parts, p)
|
||||
} else if !matchesFlatSpec(spec, p.IncludeDomain) {
|
||||
//includes that don't match get copied straight across
|
||||
// includes that don't match get copied straight across
|
||||
newRec.Parts = append(newRec.Parts, p)
|
||||
} else {
|
||||
//flatten child recursively
|
||||
// flatten child recursively
|
||||
flattenedChild := p.IncludeRecord.Flatten(spec)
|
||||
// include their parts (skipping final all term)
|
||||
for _, childPart := range flattenedChild.Parts[:len(flattenedChild.Parts)-1] {
|
||||
|
|
|
@ -9,10 +9,12 @@ import (
|
|||
"io"
|
||||
)
|
||||
|
||||
// SPFRecord stores the parts of an SPF record.
|
||||
type SPFRecord struct {
|
||||
Parts []*SPFPart
|
||||
}
|
||||
|
||||
// Lookups returns the number of DNS lookups required by s.
|
||||
func (s *SPFRecord) Lookups() int {
|
||||
count := 0
|
||||
for _, p := range s.Parts {
|
||||
|
@ -26,6 +28,7 @@ func (s *SPFRecord) Lookups() int {
|
|||
return count
|
||||
}
|
||||
|
||||
// SPFPart stores a part of an SPF record, with attributes.
|
||||
type SPFPart struct {
|
||||
Text string
|
||||
IsLookup bool
|
||||
|
@ -40,6 +43,7 @@ var qualifiers = map[byte]bool{
|
|||
'+': true,
|
||||
}
|
||||
|
||||
// Parse parses a raw SPF record.
|
||||
func Parse(text string, dnsres Resolver) (*SPFRecord, error) {
|
||||
if !strings.HasPrefix(text, "v=spf1 ") {
|
||||
return nil, fmt.Errorf("Not an spf record")
|
||||
|
@ -53,12 +57,12 @@ func Parse(text string, dnsres Resolver) (*SPFRecord, error) {
|
|||
}
|
||||
rec.Parts = append(rec.Parts, p)
|
||||
if part == "all" {
|
||||
//all. nothing else matters.
|
||||
// all. nothing else matters.
|
||||
break
|
||||
} else if strings.HasPrefix(part, "a") || strings.HasPrefix(part, "mx") {
|
||||
p.IsLookup = true
|
||||
} else if strings.HasPrefix(part, "ip4:") || strings.HasPrefix(part, "ip6:") {
|
||||
//ip address, 0 lookups
|
||||
// ip address, 0 lookups
|
||||
continue
|
||||
} else if strings.HasPrefix(part, "include:") {
|
||||
p.IsLookup = true
|
||||
|
@ -100,8 +104,9 @@ func dump(rec *SPFRecord, indent string, w io.Writer) {
|
|||
}
|
||||
}
|
||||
|
||||
func (rec *SPFRecord) Print() string {
|
||||
// Print prints an SPFRecord.
|
||||
func (s *SPFRecord) Print() string {
|
||||
w := &bytes.Buffer{}
|
||||
dump(rec, "", w)
|
||||
dump(s, "", w)
|
||||
return w.String()
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ type Resolver interface {
|
|||
// LiveResolver simply queries DNS to resolve SPF records.
|
||||
type LiveResolver struct{}
|
||||
|
||||
// GetSPF looks up the SPF record named "name".
|
||||
func (l LiveResolver) GetSPF(name string) (string, error) {
|
||||
vals, err := net.LookupTXT(name)
|
||||
if err != nil {
|
||||
|
@ -66,6 +67,7 @@ type cache struct {
|
|||
inner Resolver
|
||||
}
|
||||
|
||||
// NewCache creates a new cache file named filename.
|
||||
func NewCache(filename string) (CachingResolver, error) {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ReverseDomainName turns a CIDR block into a reversed (in-addr) name.
|
||||
func ReverseDomainName(cidr string) (string, error) {
|
||||
a, c, err := net.ParseCIDR(cidr)
|
||||
if err != nil {
|
||||
|
|
|
@ -71,7 +71,7 @@ func TestReverse(t *testing.T) {
|
|||
{"174.1.0.0/31", false, "0/31.0.1.174.in-addr.arpa"},
|
||||
{"174.1.0.2/31", false, "2/31.0.1.174.in-addr.arpa"},
|
||||
|
||||
//Errror Cases:
|
||||
// Error Cases:
|
||||
{"0.0.0.0/0", true, ""},
|
||||
{"2001::/0", true, ""},
|
||||
{"4.5/16", true, ""},
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// PtrNameMagic implements the PTR magic.
|
||||
func PtrNameMagic(name, domain string) (string, error) {
|
||||
// Implement the PTR name magic. If the name is a properly formed
|
||||
// IPv4 or IPv6 address, we replace it with the right string (i.e
|
||||
|
@ -20,9 +21,8 @@ func PtrNameMagic(name, domain string) (string, error) {
|
|||
if strings.HasSuffix(name, ".in-addr.arpa.") || strings.HasSuffix(name, ".ip6.arpa.") {
|
||||
if strings.HasSuffix(name, "."+domain+".") {
|
||||
return strings.TrimSuffix(name, "."+domain+"."), nil
|
||||
} else {
|
||||
return name, errors.Errorf("PTR record %v in wrong domain (%v)", name, domain)
|
||||
}
|
||||
return name, errors.Errorf("PTR record %v in wrong domain (%v)", name, domain)
|
||||
}
|
||||
|
||||
// If the domain is .arpa, we do magic.
|
||||
|
|
|
@ -66,8 +66,8 @@ func TestPtrMagic(t *testing.T) {
|
|||
{"2001:db8::1", "9.9.ip6.arpa", "", true},
|
||||
|
||||
// These should be errors but we don't check for them at this time:
|
||||
//{"blurg", "3.4.in-addr.arpa", "blurg", true},
|
||||
//{"1", "3.4.in-addr.arpa", "1", true},
|
||||
// {"blurg", "3.4.in-addr.arpa", "blurg", true},
|
||||
// {"1", "3.4.in-addr.arpa", "1", true},
|
||||
}
|
||||
for _, tst := range tests {
|
||||
t.Run(fmt.Sprintf("%s %s", tst.name, tst.domain), func(t *testing.T) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// IpConversion describes an IP conversion.
|
||||
type IpConversion struct {
|
||||
Low, High net.IP
|
||||
NewBases []net.IP
|
||||
|
@ -21,6 +22,7 @@ func ipToUint(i net.IP) (uint32, error) {
|
|||
return r, nil
|
||||
}
|
||||
|
||||
// UintToIP convert a 32-bit into into a net.IP.
|
||||
func UintToIP(u uint32) net.IP {
|
||||
return net.IPv4(
|
||||
byte((u>>24)&255),
|
||||
|
@ -36,7 +38,7 @@ func DecodeTransformTable(transforms string) ([]IpConversion, error) {
|
|||
for ri, row := range rows {
|
||||
items := strings.Split(row, "~")
|
||||
if len(items) != 4 {
|
||||
return nil, fmt.Errorf("transform_table rows should have 4 elements. (%v) found in row (%v) of %#v\n", len(items), ri, transforms)
|
||||
return nil, fmt.Errorf("transform_table rows should have 4 elements. (%v) found in row (%v) of %#v", len(items), ri, transforms)
|
||||
}
|
||||
for i, item := range items {
|
||||
items[i] = strings.TrimSpace(item)
|
||||
|
@ -72,7 +74,7 @@ func DecodeTransformTable(transforms string) ([]IpConversion, error) {
|
|||
low, _ := ipToUint(con.Low)
|
||||
high, _ := ipToUint(con.High)
|
||||
if low > high {
|
||||
return nil, fmt.Errorf("transform_table Low should be less than High. row (%v) %v>%v (%v)\n", ri, con.Low, con.High, transforms)
|
||||
return nil, fmt.Errorf("transform_table Low should be less than High. row (%v) %v>%v (%v)", ri, con.Low, con.High, transforms)
|
||||
}
|
||||
if len(con.NewBases) > 0 && len(con.NewIPs) > 0 {
|
||||
return nil, fmt.Errorf("transform_table_rows should only specify one of NewBases or NewIPs, Not both")
|
||||
|
|
|
@ -21,7 +21,7 @@ func TestIPToUint(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func Test_DecodeTransformTable_failures(t *testing.T) {
|
||||
func TestDecodeTransformTableFailures(t *testing.T) {
|
||||
result, err := DecodeTransformTable("1.2.3.4 ~ 3.4.5.6")
|
||||
if result != nil {
|
||||
t.Errorf("expected nil, got (%v)\n", result)
|
||||
|
@ -31,7 +31,7 @@ func Test_DecodeTransformTable_failures(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func test_ip(t *testing.T, test string, expected string, actual net.IP) {
|
||||
func testIP(t *testing.T, test string, expected string, actual net.IP) {
|
||||
if !net.ParseIP(expected).Equal(actual) {
|
||||
t.Errorf("Test %v: expected Low (%v), got (%v)\n", test, actual, expected)
|
||||
}
|
||||
|
@ -45,10 +45,10 @@ func Test_DecodeTransformTable_0(t *testing.T) {
|
|||
if len(result) != 1 {
|
||||
t.Errorf("Test %v: expected col length (%v), got (%v)\n", 1, 1, len(result))
|
||||
}
|
||||
test_ip(t, "low", "1.2.3.4", result[0].Low)
|
||||
test_ip(t, "high", "2.3.4.5", result[0].High)
|
||||
test_ip(t, "newBase", "3.4.5.6", result[0].NewBases[0])
|
||||
//test_ip(t, "newIP", "", result[0].NewIPs)
|
||||
testIP(t, "low", "1.2.3.4", result[0].Low)
|
||||
testIP(t, "high", "2.3.4.5", result[0].High)
|
||||
testIP(t, "newBase", "3.4.5.6", result[0].NewBases[0])
|
||||
// test_ip(t, "newIP", "", result[0].NewIPs)
|
||||
}
|
||||
|
||||
func Test_DecodeTransformTable_1(t *testing.T) {
|
||||
|
@ -59,14 +59,14 @@ func Test_DecodeTransformTable_1(t *testing.T) {
|
|||
if len(result) != 2 {
|
||||
t.Errorf("Test %v: expected col length (%v), got (%v)\n", 1, 2, len(result))
|
||||
}
|
||||
test_ip(t, "Low[0]", "1.2.3.4", result[0].Low)
|
||||
test_ip(t, "High[0]", "2.3.4.5", result[0].High)
|
||||
test_ip(t, "NewBase[0]", "3.4.5.6", result[0].NewBases[0])
|
||||
//test_ip(t, "newIP[0]", "", result[0].NewIP)
|
||||
test_ip(t, "Low[1]", "8.7.6.5", result[1].Low)
|
||||
test_ip(t, "High[1]", "9.8.7.6", result[1].High)
|
||||
test_ip(t, "NewBase[1]", "7.6.5.4", result[1].NewBases[0])
|
||||
//test_ip(t, "newIP[1]", "", result[0].NewIP)
|
||||
testIP(t, "Low[0]", "1.2.3.4", result[0].Low)
|
||||
testIP(t, "High[0]", "2.3.4.5", result[0].High)
|
||||
testIP(t, "NewBase[0]", "3.4.5.6", result[0].NewBases[0])
|
||||
// test_ip(t, "newIP[0]", "", result[0].NewIP)
|
||||
testIP(t, "Low[1]", "8.7.6.5", result[1].Low)
|
||||
testIP(t, "High[1]", "9.8.7.6", result[1].High)
|
||||
testIP(t, "NewBase[1]", "7.6.5.4", result[1].NewBases[0])
|
||||
// test_ip(t, "newIP[1]", "", result[0].NewIP)
|
||||
}
|
||||
func Test_DecodeTransformTable_NewIP(t *testing.T) {
|
||||
result, err := DecodeTransformTable("1.2.3.4 ~ 2.3.4.5 ~ ~ 3.4.5.6 ")
|
||||
|
@ -76,9 +76,9 @@ func Test_DecodeTransformTable_NewIP(t *testing.T) {
|
|||
if len(result) != 1 {
|
||||
t.Errorf("Test %v: expected col length (%v), got (%v)\n", 1, 1, len(result))
|
||||
}
|
||||
test_ip(t, "low", "1.2.3.4", result[0].Low)
|
||||
test_ip(t, "high", "2.3.4.5", result[0].High)
|
||||
test_ip(t, "newIP", "3.4.5.6", result[0].NewIPs[0])
|
||||
testIP(t, "low", "1.2.3.4", result[0].Low)
|
||||
testIP(t, "high", "2.3.4.5", result[0].High)
|
||||
testIP(t, "newIP", "3.4.5.6", result[0].NewIPs[0])
|
||||
}
|
||||
|
||||
func Test_DecodeTransformTable_order(t *testing.T) {
|
||||
|
@ -126,7 +126,7 @@ func Test_TransformIP(t *testing.T) {
|
|||
High: net.ParseIP("55.255.0.0"),
|
||||
NewBases: []net.IP{net.ParseIP("66.0.0.0"), net.ParseIP("77.0.0.0")},
|
||||
}}
|
||||
//NO TRANSFORMS ON 99.x.x.x PLZ
|
||||
// NO TRANSFORMS ON 99.x.x.x PLZ
|
||||
|
||||
var tests = []struct {
|
||||
experiment string
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
//Package all is simply a container to reference all known provider implementations for easy import into other packages
|
||||
// Package all is simply a container to reference all known provider implementations for easy import into other packages
|
||||
package all
|
||||
|
||||
import (
|
||||
//Define all known providers here. They should each register themselves with the providers package via init function.
|
||||
// Define all known providers here. They should each register themselves with the providers package via init function.
|
||||
_ "github.com/StackExchange/dnscontrol/providers/activedir"
|
||||
_ "github.com/StackExchange/dnscontrol/providers/bind"
|
||||
_ "github.com/StackExchange/dnscontrol/providers/cloudflare"
|
||||
|
|
|
@ -37,7 +37,7 @@ D('ds.stackexchange.com', REG_NONE,
|
|||
)
|
||||
|
||||
|
||||
//records handled by another provider...
|
||||
// records handled by another provider...
|
||||
);
|
||||
```
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
|
||||
const zoneDumpFilenamePrefix = "adzonedump"
|
||||
|
||||
// RecordConfigJson RecordConfig, reconfigured for JSON input/output.
|
||||
type RecordConfigJson struct {
|
||||
Name string `json:"hostname"`
|
||||
Type string `json:"recordtype"`
|
||||
|
@ -25,7 +26,7 @@ type RecordConfigJson struct {
|
|||
}
|
||||
|
||||
func (c *adProvider) GetNameservers(string) ([]*models.Nameserver, error) {
|
||||
//TODO: If using AD for publicly hosted zones, probably pull these from config.
|
||||
// TODO: If using AD for publicly hosted zones, probably pull these from config.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
@ -99,11 +100,11 @@ func (c *adProvider) logOutput(s string) error {
|
|||
|
||||
// powerShellLogErr logs that a PowerShell command had an error.
|
||||
func (c *adProvider) logErr(e error) error {
|
||||
err := c.logHelper(fmt.Sprintf("ERROR: %v\r\r", e)) //Log error to powershell.log
|
||||
err := c.logHelper(fmt.Sprintf("ERROR: %v\r\r", e)) // Log error to powershell.log
|
||||
if err != nil {
|
||||
return err //Bubble up error created in logHelper
|
||||
return err // Bubble up error created in logHelper
|
||||
}
|
||||
return e //Bubble up original error
|
||||
return e // Bubble up original error
|
||||
}
|
||||
|
||||
func (c *adProvider) logHelper(s string) error {
|
||||
|
@ -125,17 +126,17 @@ func (c *adProvider) logHelper(s string) error {
|
|||
func (c *adProvider) powerShellRecord(command string) error {
|
||||
recordfile, err := os.OpenFile(c.psOut, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0660)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Can not create/append to %#v: %v\n", c.psOut, err)
|
||||
return fmt.Errorf("can not create/append to %#v: %v", c.psOut, err)
|
||||
}
|
||||
_, err = recordfile.WriteString(command)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Append to %#v failed: %v\n", c.psOut, err)
|
||||
return fmt.Errorf("append to %#v failed: %v", c.psOut, err)
|
||||
}
|
||||
return recordfile.Close()
|
||||
}
|
||||
|
||||
func (c *adProvider) getExistingRecords(domainname string) ([]*models.RecordConfig, error) {
|
||||
//log.Printf("getExistingRecords(%s)\n", domainname)
|
||||
// log.Printf("getExistingRecords(%s)\n", domainname)
|
||||
|
||||
// Get the JSON either from adzonedump or by running a PowerShell script.
|
||||
data, err := c.getRecords(domainname)
|
||||
|
@ -211,7 +212,7 @@ func (c *adProvider) generatePowerShellCreate(domainname string, rec *models.Rec
|
|||
case "NS":
|
||||
text = fmt.Sprintf("\r\n"+`echo "Skipping NS update (%v %v)"`+"\r\n", rec.Name, rec.Target)
|
||||
default:
|
||||
panic(fmt.Errorf("ERROR: generatePowerShellCreate() does not yet handle recType=%s recName=%#v content=%#v)\n", rec.Type, rec.Name, content))
|
||||
panic(fmt.Errorf("generatePowerShellCreate() does not yet handle recType=%s recName=%#v content=%#v)", rec.Type, rec.Name, content))
|
||||
// We panic so that we quickly find any switch statements
|
||||
// that have not been updated for a new RR type.
|
||||
}
|
||||
|
@ -233,7 +234,7 @@ func (c *adProvider) generatePowerShellModify(domainname, recName, recType, oldC
|
|||
queryField = "HostNameAlias"
|
||||
queryContent = `"` + oldContent + `"`
|
||||
default:
|
||||
panic(fmt.Errorf("ERROR: generatePowerShellModify() does not yet handle recType=%s recName=%#v content=(%#v, %#v)\n", recType, recName, oldContent, newContent))
|
||||
panic(fmt.Errorf("generatePowerShellModify() does not yet handle recType=%s recName=%#v content=(%#v, %#v)", recType, recName, oldContent, newContent))
|
||||
// We panic so that we quickly find any switch statements
|
||||
// that have not been updated for a new RR type.
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ func init() {
|
|||
providers.RegisterDomainServiceProviderType("BIND", initBind, features)
|
||||
}
|
||||
|
||||
// SoaInfo contains the parts of a SOA rtype.
|
||||
type SoaInfo struct {
|
||||
Ns string `json:"master"`
|
||||
Mbox string `json:"mbox"`
|
||||
|
@ -79,6 +80,7 @@ func (s SoaInfo) String() string {
|
|||
return fmt.Sprintf("%s %s %d %d %d %d %d", s.Ns, s.Mbox, s.Serial, s.Refresh, s.Retry, s.Expire, s.Minttl)
|
||||
}
|
||||
|
||||
// Bind is the provider handle for the Bind driver.
|
||||
type Bind struct {
|
||||
DefaultNS []string `json:"default_ns"`
|
||||
DefaultSoa SoaInfo `json:"default_soa"`
|
||||
|
@ -86,7 +88,7 @@ type Bind struct {
|
|||
directory string
|
||||
}
|
||||
|
||||
//var bindSkeletin = flag.String("bind_skeletin", "skeletin/master/var/named/chroot/var/named/master", "")
|
||||
// var bindSkeletin = flag.String("bind_skeletin", "skeletin/master/var/named/chroot/var/named/master", "")
|
||||
|
||||
func rrToRecord(rr dns.RR, origin string, replaceSerial uint32) (models.RecordConfig, uint32) {
|
||||
// Convert's dns.RR into our native data type (models.RecordConfig).
|
||||
|
@ -95,7 +97,7 @@ func rrToRecord(rr dns.RR, origin string, replaceSerial uint32) (models.RecordCo
|
|||
// replaceSerial != 0, change the serial to replaceSerial.
|
||||
// WARNING(tlim): This assumes SOAs do not have serial=0.
|
||||
// If one is found, we replace it with serial=1.
|
||||
var old_serial, new_serial uint32
|
||||
var oldSerial, newSerial uint32
|
||||
header := rr.Header()
|
||||
rc := models.RecordConfig{}
|
||||
rc.Type = dns.TypeToString[header.Rrtype]
|
||||
|
@ -121,17 +123,17 @@ func rrToRecord(rr dns.RR, origin string, replaceSerial uint32) (models.RecordCo
|
|||
case *dns.PTR:
|
||||
rc.Target = v.Ptr
|
||||
case *dns.SOA:
|
||||
old_serial = v.Serial
|
||||
if old_serial == 0 {
|
||||
oldSerial = v.Serial
|
||||
if oldSerial == 0 {
|
||||
// For SOA records, we never return a 0 serial number.
|
||||
old_serial = 1
|
||||
oldSerial = 1
|
||||
}
|
||||
new_serial = v.Serial
|
||||
newSerial = v.Serial
|
||||
if (dnsutil.TrimDomainName(rc.Name, origin+".") == "@") && replaceSerial != 0 {
|
||||
new_serial = replaceSerial
|
||||
newSerial = replaceSerial
|
||||
}
|
||||
rc.Target = fmt.Sprintf("%v %v %v %v %v %v %v",
|
||||
v.Ns, v.Mbox, new_serial, v.Refresh, v.Retry, v.Expire, v.Minttl)
|
||||
v.Ns, v.Mbox, newSerial, v.Refresh, v.Retry, v.Expire, v.Minttl)
|
||||
case *dns.SRV:
|
||||
rc.Target = v.Target
|
||||
rc.SrvPort = v.Port
|
||||
|
@ -148,7 +150,7 @@ func rrToRecord(rr dns.RR, origin string, replaceSerial uint32) (models.RecordCo
|
|||
default:
|
||||
log.Fatalf("rrToRecord: Unimplemented zone record type=%s (%v)\n", rc.Type, rr)
|
||||
}
|
||||
return rc, old_serial
|
||||
return rc, oldSerial
|
||||
}
|
||||
|
||||
func makeDefaultSOA(info SoaInfo, origin string) *models.RecordConfig {
|
||||
|
@ -184,10 +186,12 @@ func makeDefaultSOA(info SoaInfo, origin string) *models.RecordConfig {
|
|||
return &soaRec
|
||||
}
|
||||
|
||||
// GetNameservers returns the nameservers for a domain.
|
||||
func (c *Bind) GetNameservers(string) ([]*models.Nameserver, error) {
|
||||
return c.nameservers, nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns a list of corrections to update a domain.
|
||||
func (c *Bind) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc.Punycode()
|
||||
// Phase 1: Copy everything to []*models.RecordConfig:
|
||||
|
@ -228,7 +232,7 @@ func (c *Bind) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correcti
|
|||
if serial != 0 {
|
||||
// This was an SOA record. Update the serial.
|
||||
oldSerial = serial
|
||||
newSerial = generate_serial(oldSerial)
|
||||
newSerial = generateSerial(oldSerial)
|
||||
// Regenerate with new serial:
|
||||
*soaRec, _ = rrToRecord(x.RR, dc.Name, newSerial)
|
||||
rec = *soaRec
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package bind
|
||||
|
||||
// Generate zonefiles.
|
||||
// This generates a zonefile that prioritizes beauty over efficiency.
|
||||
package bind
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
@ -98,10 +99,10 @@ func (z *zoneGenData) Less(i, j int) bool {
|
|||
return a.String() < b.String()
|
||||
}
|
||||
|
||||
// mostCommonTtl returns the most common TTL in a set of records. If there is
|
||||
// mostCommonTTL returns the most common TTL in a set of records. If there is
|
||||
// a tie, the highest TTL is selected. This makes the results consistent.
|
||||
// NS records are not included in the analysis because Tom said so.
|
||||
func mostCommonTtl(records []dns.RR) uint32 {
|
||||
func mostCommonTTL(records []dns.RR) uint32 {
|
||||
// Index the TTLs in use:
|
||||
d := make(map[uint32]int)
|
||||
for _, r := range records {
|
||||
|
@ -141,11 +142,11 @@ func WriteZoneFile(w io.Writer, records []dns.RR, origin string) error {
|
|||
// * $TTL is used to eliminate clutter. The most common TTL value is used.
|
||||
// * "@" is used instead of the apex domain name.
|
||||
|
||||
defaultTtl := mostCommonTtl(records)
|
||||
defaultTTL := mostCommonTTL(records)
|
||||
|
||||
z := &zoneGenData{
|
||||
Origin: dnsutil.AddOrigin(origin, "."),
|
||||
DefaultTtl: defaultTtl,
|
||||
DefaultTtl: defaultTTL,
|
||||
}
|
||||
z.Records = nil
|
||||
for _, r := range records {
|
||||
|
@ -200,9 +201,6 @@ func (z *zoneGenData) generateZoneFileHelper(w io.Writer) error {
|
|||
|
||||
// items[4]: the remaining line
|
||||
target := items[4]
|
||||
//if typeStr == "TXT" {
|
||||
// fmt.Printf("generateZoneFileHelper.go: target=%#v\n", target)
|
||||
//}
|
||||
|
||||
fmt.Fprintln(w, formatLine([]int{10, 5, 2, 5, 0}, []string{name, ttl, "IN", typeStr, target}))
|
||||
}
|
||||
|
@ -291,10 +289,9 @@ func zoneLabelLess(a, b string) bool {
|
|||
bu, berr := strconv.ParseUint(bs[j], 10, 64)
|
||||
if aerr == nil && berr == nil {
|
||||
return au < bu
|
||||
} else {
|
||||
// otherwise, compare as strings:
|
||||
return as[i] < bs[j]
|
||||
}
|
||||
// otherwise, compare as strings:
|
||||
return as[i] < bs[j]
|
||||
}
|
||||
}
|
||||
// The min top elements were equal, so the shorter name is less.
|
||||
|
|
|
@ -47,7 +47,7 @@ func TestMostCommonTtl(t *testing.T) {
|
|||
// All records are TTL=100
|
||||
records = nil
|
||||
records, e = append(records, r1, r1, r1), 100
|
||||
g = mostCommonTtl(records)
|
||||
g = mostCommonTTL(records)
|
||||
if e != g {
|
||||
t.Fatalf("expected %d; got %d\n", e, g)
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ func TestMostCommonTtl(t *testing.T) {
|
|||
// Mixture of TTLs with an obvious winner.
|
||||
records = nil
|
||||
records, e = append(records, r1, r2, r2), 200
|
||||
g = mostCommonTtl(records)
|
||||
g = mostCommonTTL(records)
|
||||
if e != g {
|
||||
t.Fatalf("expected %d; got %d\n", e, g)
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ func TestMostCommonTtl(t *testing.T) {
|
|||
// 3-way tie. Largest TTL should be used.
|
||||
records = nil
|
||||
records, e = append(records, r1, r2, r3), 300
|
||||
g = mostCommonTtl(records)
|
||||
g = mostCommonTTL(records)
|
||||
if e != g {
|
||||
t.Fatalf("expected %d; got %d\n", e, g)
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ func TestMostCommonTtl(t *testing.T) {
|
|||
// NS records are ignored.
|
||||
records = nil
|
||||
records, e = append(records, r1, r4, r5), 100
|
||||
g = mostCommonTtl(records)
|
||||
g = mostCommonTTL(records)
|
||||
if e != g {
|
||||
t.Fatalf("expected %d; got %d\n", e, g)
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ www 300 IN CNAME bosun.org.
|
|||
}
|
||||
|
||||
func TestWriteZoneFileMx(t *testing.T) {
|
||||
//exhibits explicit ttls and long name
|
||||
// exhibits explicit ttls and long name
|
||||
r1, _ := dns.NewRR(`bosun.org. 300 IN TXT "aaa"`)
|
||||
r2, _ := dns.NewRR(`bosun.org. 300 IN TXT "bbb"`)
|
||||
r2.(*dns.TXT).Txt[0] = `b"bb`
|
||||
|
@ -157,7 +157,7 @@ google._domainkey IN TXT "\"foo\""
|
|||
`
|
||||
|
||||
func TestWriteZoneFileSrv(t *testing.T) {
|
||||
//exhibits explicit ttls and long name
|
||||
// exhibits explicit ttls and long name
|
||||
r1, _ := dns.NewRR(`bosun.org. 300 IN SRV 10 10 9999 foo.com.`)
|
||||
r2, _ := dns.NewRR(`bosun.org. 300 IN SRV 10 20 5050 foo.com.`)
|
||||
r3, _ := dns.NewRR(`bosun.org. 300 IN SRV 10 10 5050 foo.com.`)
|
||||
|
@ -182,7 +182,7 @@ var testdataZFSRV = `$TTL 300
|
|||
`
|
||||
|
||||
func TestWriteZoneFilePtr(t *testing.T) {
|
||||
//exhibits explicit ttls and long name
|
||||
// exhibits explicit ttls and long name
|
||||
r1, _ := dns.NewRR(`bosun.org. 300 IN PTR chell.bosun.org`)
|
||||
r2, _ := dns.NewRR(`bosun.org. 300 IN PTR barney.bosun.org.`)
|
||||
r3, _ := dns.NewRR(`bosun.org. 300 IN PTR alex.bosun.org.`)
|
||||
|
@ -203,7 +203,7 @@ var testdataZFPTR = `$TTL 300
|
|||
`
|
||||
|
||||
func TestWriteZoneFileCaa(t *testing.T) {
|
||||
//exhibits explicit ttls and long name
|
||||
// exhibits explicit ttls and long name
|
||||
r1, _ := dns.NewRR(`bosun.org. 300 IN CAA 0 issuewild ";"`)
|
||||
r2, _ := dns.NewRR(`bosun.org. 300 IN CAA 0 issue "letsencrypt.org"`)
|
||||
r3, _ := dns.NewRR(`bosun.org. 300 IN CAA 1 iodef "http://example.com"`)
|
||||
|
|
|
@ -7,10 +7,10 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
var nowFunc func() time.Time = time.Now
|
||||
var nowFunc = time.Now
|
||||
|
||||
// generate_serial takes an old SOA serial number and increments it.
|
||||
func generate_serial(old_serial uint32) uint32 {
|
||||
// generateSerial takes an old SOA serial number and increments it.
|
||||
func generateSerial(oldSerial uint32) uint32 {
|
||||
// Serial numbers are in the format yyyymmddvv
|
||||
// where vv is a version count that starts at 01 each day.
|
||||
// Multiple serial numbers generated on the same day increase vv.
|
||||
|
@ -19,9 +19,9 @@ func generate_serial(old_serial uint32) uint32 {
|
|||
// that is smaller than the old one, we punt and increment the old number.
|
||||
// At no time will a serial number == 0 be returned.
|
||||
|
||||
original := old_serial
|
||||
old_serialStr := strconv.FormatUint(uint64(old_serial), 10)
|
||||
var new_serial uint32
|
||||
original := oldSerial
|
||||
oldSerialStr := strconv.FormatUint(uint64(oldSerial), 10)
|
||||
var newSerial uint32
|
||||
|
||||
// Make draft new serial number:
|
||||
today := nowFunc().UTC()
|
||||
|
@ -34,38 +34,38 @@ func generate_serial(old_serial uint32) uint32 {
|
|||
draft := uint32(todayNum)*100 + version
|
||||
|
||||
method := "none" // Used only in debugging.
|
||||
if old_serial > draft {
|
||||
if oldSerial > draft {
|
||||
// If old_serial was really slow, upgrade to new yyyymmddvv standard:
|
||||
method = "o>d"
|
||||
new_serial = old_serial + 1
|
||||
new_serial = old_serial + 1
|
||||
} else if old_serial == draft {
|
||||
newSerial = oldSerial + 1
|
||||
newSerial = oldSerial + 1
|
||||
} else if oldSerial == draft {
|
||||
// Edge case: increment old serial:
|
||||
method = "o=d"
|
||||
new_serial = draft + 1
|
||||
} else if len(old_serialStr) != 10 {
|
||||
newSerial = draft + 1
|
||||
} else if len(oldSerialStr) != 10 {
|
||||
// If old_serial is wrong number of digits, upgrade to yyyymmddvv standard:
|
||||
method = "len!=10"
|
||||
new_serial = draft
|
||||
} else if strings.HasPrefix(old_serialStr, todayStr) {
|
||||
newSerial = draft
|
||||
} else if strings.HasPrefix(oldSerialStr, todayStr) {
|
||||
// If old_serial just needs to be incremented:
|
||||
method = "prefix"
|
||||
new_serial = old_serial + 1
|
||||
newSerial = oldSerial + 1
|
||||
} else {
|
||||
// First serial number to be requested today:
|
||||
method = "default"
|
||||
new_serial = draft
|
||||
newSerial = draft
|
||||
}
|
||||
|
||||
if new_serial == 0 {
|
||||
if newSerial == 0 {
|
||||
// We never return 0 as the serial number.
|
||||
new_serial = 1
|
||||
newSerial = 1
|
||||
}
|
||||
if old_serial == new_serial {
|
||||
log.Fatalf("%v: old_serial == new_serial (%v == %v) draft=%v method=%v", original, old_serial, new_serial, draft, method)
|
||||
if oldSerial == newSerial {
|
||||
log.Fatalf("%v: old_serial == new_serial (%v == %v) draft=%v method=%v", original, oldSerial, newSerial, draft, method)
|
||||
}
|
||||
if old_serial > new_serial {
|
||||
log.Fatalf("%v: old_serial > new_serial (%v > %v) draft=%v method=%v", original, old_serial, new_serial, draft, method)
|
||||
if oldSerial > newSerial {
|
||||
log.Fatalf("%v: old_serial > new_serial (%v > %v) draft=%v method=%v", original, oldSerial, newSerial, draft, method)
|
||||
}
|
||||
return new_serial
|
||||
return newSerial
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ func Test_generate_serial_1(t *testing.T) {
|
|||
nowFunc = func() time.Time {
|
||||
return tst.Today
|
||||
}
|
||||
found := generate_serial(tst.Given)
|
||||
found := generateSerial(tst.Given)
|
||||
if expected != found {
|
||||
t.Fatalf("Test:%d/%v: Expected (%d) got (%d)\n", i, tst.Given, expected, found)
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"log"
|
||||
)
|
||||
|
||||
//Capability is a bitmasked set of "features" that a provider supports. Only use constants from this package.
|
||||
// Capability is a bitmasked set of "features" that a provider supports. Only use constants from this package.
|
||||
type Capability uint32
|
||||
|
||||
const (
|
||||
|
@ -44,6 +44,7 @@ const (
|
|||
|
||||
var providerCapabilities = map[string]map[Capability]bool{}
|
||||
|
||||
// ProviderHasCabability returns true if provider has capability.
|
||||
func ProviderHasCabability(pType string, cap Capability) bool {
|
||||
if providerCapabilities[pType] == nil {
|
||||
return false
|
||||
|
|
|
@ -48,6 +48,7 @@ func init() {
|
|||
providers.RegisterCustomRecordType("CF_TEMP_REDIRECT", "CLOUDFLAREAPI", "")
|
||||
}
|
||||
|
||||
// CloudflareApi is the handle for API calls.
|
||||
type CloudflareApi struct {
|
||||
ApiKey string `json:"apikey"`
|
||||
ApiUser string `json:"apiuser"`
|
||||
|
@ -59,7 +60,7 @@ type CloudflareApi struct {
|
|||
}
|
||||
|
||||
func labelMatches(label string, matches []string) bool {
|
||||
//log.Printf("DEBUG: labelMatches(%#v, %#v)\n", label, matches)
|
||||
// log.Printf("DEBUG: labelMatches(%#v, %#v)\n", label, matches)
|
||||
for _, tst := range matches {
|
||||
if label == tst {
|
||||
return true
|
||||
|
@ -68,6 +69,7 @@ func labelMatches(label string, matches []string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// GetNameservers returns the nameservers for a domain.
|
||||
func (c *CloudflareApi) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
||||
if c.domainIndex == nil {
|
||||
if err := c.fetchDomainList(); err != nil {
|
||||
|
@ -81,6 +83,7 @@ func (c *CloudflareApi) GetNameservers(domain string) ([]*models.Nameserver, err
|
|||
return models.StringsToNameservers(ns), nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns a list of corrections to update a domain.
|
||||
func (c *CloudflareApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
if c.domainIndex == nil {
|
||||
if err := c.fetchDomainList(); err != nil {
|
||||
|
@ -275,7 +278,7 @@ func (c *CloudflareApi) preprocessConfig(dc *models.DomainConfig) error {
|
|||
if rec.Type != "A" {
|
||||
continue
|
||||
}
|
||||
//only transform "full"
|
||||
// only transform "full"
|
||||
if rec.Metadata[metaProxy] != "full" {
|
||||
continue
|
||||
}
|
||||
|
@ -365,7 +368,7 @@ type cfRecord struct {
|
|||
}
|
||||
|
||||
func (c *cfRecord) toRecord(domain string) *models.RecordConfig {
|
||||
//normalize cname,mx,ns records with dots to be consistent with our config format.
|
||||
// normalize cname,mx,ns records with dots to be consistent with our config format.
|
||||
if c.Type == "CNAME" || c.Type == "MX" || c.Type == "NS" || c.Type == "SRV" {
|
||||
c.Content = dnsutil.AddOrigin(c.Content+".", domain)
|
||||
}
|
||||
|
@ -417,6 +420,7 @@ func getProxyMetadata(r *models.RecordConfig) map[string]string {
|
|||
}
|
||||
}
|
||||
|
||||
// EnsureDomainExists returns an error of domain does not exist.
|
||||
func (c *CloudflareApi) EnsureDomainExists(domain string) error {
|
||||
if _, ok := c.domainIndex[domain]; ok {
|
||||
return nil
|
||||
|
|
|
@ -81,12 +81,12 @@ func TestIpRewriting(t *testing.T) {
|
|||
Given, Expected string
|
||||
Proxy string
|
||||
}{
|
||||
//outside of range
|
||||
// outside of range
|
||||
{"5.5.5.5", "5.5.5.5", "full"},
|
||||
{"5.5.5.5", "5.5.5.5", "on"},
|
||||
// inside range, but not proxied
|
||||
{"1.2.3.4", "1.2.3.4", "on"},
|
||||
//inside range and proxied
|
||||
// inside range and proxied
|
||||
{"1.2.3.4", "255.255.255.4", "full"},
|
||||
}
|
||||
cf := &CloudflareApi{}
|
||||
|
|
|
@ -67,7 +67,7 @@ func (c *CloudflareApi) getRecordsForDomain(id string, domain string) ([]*models
|
|||
return nil, fmt.Errorf("Error fetching record list cloudflare: %s", stringifyErrors(data.Errors))
|
||||
}
|
||||
for _, rec := range data.Result {
|
||||
//fmt.Printf("REC: %+v\n", rec)
|
||||
// fmt.Printf("REC: %+v\n", rec)
|
||||
records = append(records, rec.toRecord(domain))
|
||||
}
|
||||
ri := data.ResultInfo
|
||||
|
@ -76,7 +76,7 @@ func (c *CloudflareApi) getRecordsForDomain(id string, domain string) ([]*models
|
|||
}
|
||||
page++
|
||||
}
|
||||
//fmt.Printf("DEBUG REORDS=%v\n", records)
|
||||
// fmt.Printf("DEBUG REORDS=%v\n", records)
|
||||
return records, nil
|
||||
}
|
||||
|
||||
|
@ -202,7 +202,7 @@ func (c *CloudflareApi) createRec(rec *models.RecordConfig, domainID string) []*
|
|||
|
||||
func (c *CloudflareApi) modifyRecord(domainID, recID string, proxied bool, rec *models.RecordConfig) error {
|
||||
if domainID == "" || recID == "" {
|
||||
return fmt.Errorf("Cannot modify record if domain or record id are empty.")
|
||||
return fmt.Errorf("cannot modify record if domain or record id are empty")
|
||||
}
|
||||
type record struct {
|
||||
ID string `json:"id"`
|
||||
|
@ -273,7 +273,7 @@ func (c *CloudflareApi) get(endpoint string, target interface{}) error {
|
|||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != 200 {
|
||||
return fmt.Errorf("Bad status code from cloudflare: %d not 200.", resp.StatusCode)
|
||||
return fmt.Errorf("bad status code from cloudflare: %d not 200", resp.StatusCode)
|
||||
}
|
||||
decoder := json.NewDecoder(resp.Body)
|
||||
return decoder.Decode(target)
|
||||
|
@ -306,7 +306,7 @@ func (c *CloudflareApi) getPageRules(id string, domain string) ([]*models.Record
|
|||
Name: "@",
|
||||
NameFQDN: domain,
|
||||
Type: "PAGE_RULE",
|
||||
//$FROM,$TO,$PRIO,$CODE
|
||||
// $FROM,$TO,$PRIO,$CODE
|
||||
Target: fmt.Sprintf("%s,%s,%d,%d", pr.Targets[0].Constraint.Value, pr.ForwardingInfo.URL, pr.Priority, pr.ForwardingInfo.StatusCode),
|
||||
Original: thisPr,
|
||||
TTL: 1,
|
||||
|
@ -339,7 +339,7 @@ func (c *CloudflareApi) createPageRule(domainID string, target string) error {
|
|||
}
|
||||
|
||||
func (c *CloudflareApi) sendPageRule(endpoint, method string, data string) error {
|
||||
//from to priority code
|
||||
// from to priority code
|
||||
parts := strings.Split(data, ",")
|
||||
priority, _ := strconv.Atoi(parts[2])
|
||||
code, _ := strconv.Atoi(parts[3])
|
||||
|
|
|
@ -19,7 +19,7 @@ func LoadProviderConfigs(fname string) (map[string]map[string]string, error) {
|
|||
var results = map[string]map[string]string{}
|
||||
dat, err := utfutil.ReadFile(fname, utfutil.POSIX)
|
||||
if err != nil {
|
||||
//no creds file is ok. Bind requires nothing for example. Individual providers will error if things not found.
|
||||
// no creds file is ok. Bind requires nothing for example. Individual providers will error if things not found.
|
||||
if os.IsNotExist(err) {
|
||||
return results, nil
|
||||
}
|
||||
|
|
|
@ -8,21 +8,26 @@ import (
|
|||
"github.com/StackExchange/dnscontrol/models"
|
||||
)
|
||||
|
||||
// Correlation stores a difference between two domains.
|
||||
type Correlation struct {
|
||||
d *differ
|
||||
Existing *models.RecordConfig
|
||||
Desired *models.RecordConfig
|
||||
}
|
||||
|
||||
// Changeset stores many Correlation.
|
||||
type Changeset []Correlation
|
||||
|
||||
// Differ is an interface for computing the difference between two zones.
|
||||
type Differ interface {
|
||||
//IncrementalDiff performs a diff on a record-by-record basis, and returns a sets for which records need to be created, deleted, or modified.
|
||||
// IncrementalDiff performs a diff on a record-by-record basis, and returns a sets for which records need to be created, deleted, or modified.
|
||||
IncrementalDiff(existing []*models.RecordConfig) (unchanged, create, toDelete, modify Changeset)
|
||||
// ChangedGroups performs a diff more appropriate for providers with a "RecordSet" model, where all records with the same name and type are grouped.
|
||||
// Individual record changes are often not useful in such scenarios. Instead we return a map of record keys to a list of change descriptions within that group.
|
||||
ChangedGroups(existing []*models.RecordConfig) map[models.RecordKey][]string
|
||||
}
|
||||
|
||||
// New is a constructor for a Differ.
|
||||
func New(dc *models.DomainConfig, extraValues ...func(*models.RecordConfig) map[string]string) Differ {
|
||||
return &differ{
|
||||
dc: dc,
|
||||
|
@ -53,7 +58,7 @@ func (d *differ) IncrementalDiff(existing []*models.RecordConfig) (unchanged, cr
|
|||
modify = Changeset{}
|
||||
desired := d.dc.Records
|
||||
|
||||
//sort existing and desired by name
|
||||
// sort existing and desired by name
|
||||
type key struct {
|
||||
name, rType string
|
||||
}
|
||||
|
@ -67,7 +72,7 @@ func (d *differ) IncrementalDiff(existing []*models.RecordConfig) (unchanged, cr
|
|||
k := key{d.NameFQDN, d.Type}
|
||||
desiredByNameAndType[k] = append(desiredByNameAndType[k], d)
|
||||
}
|
||||
//if NO_PURGE is set, just remove anything that is only in existing.
|
||||
// if NO_PURGE is set, just remove anything that is only in existing.
|
||||
if d.dc.KeepUnknown {
|
||||
for k := range existingByNameAndType {
|
||||
if _, ok := desiredByNameAndType[k]; !ok {
|
||||
|
@ -80,12 +85,12 @@ func (d *differ) IncrementalDiff(existing []*models.RecordConfig) (unchanged, cr
|
|||
// Each iteration is only for a single type/name record set
|
||||
for key, existingRecords := range existingByNameAndType {
|
||||
desiredRecords := desiredByNameAndType[key]
|
||||
//first look through records that are the same target on both sides. Those are either modifications or unchanged
|
||||
// first look through records that are the same target on both sides. Those are either modifications or unchanged
|
||||
for i := len(existingRecords) - 1; i >= 0; i-- {
|
||||
ex := existingRecords[i]
|
||||
for j, de := range desiredRecords {
|
||||
if de.Target == ex.Target {
|
||||
//they're either identical or should be a modification of each other (ttl or metadata changes)
|
||||
// they're either identical or should be a modification of each other (ttl or metadata changes)
|
||||
if d.content(de) == d.content(ex) {
|
||||
unchanged = append(unchanged, Correlation{d, ex, de})
|
||||
} else {
|
||||
|
@ -124,7 +129,7 @@ func (d *differ) IncrementalDiff(existing []*models.RecordConfig) (unchanged, cr
|
|||
delete(desiredLookup, norm)
|
||||
}
|
||||
}
|
||||
//sort records by normalized text. Keeps behaviour deterministic
|
||||
// sort records by normalized text. Keeps behaviour deterministic
|
||||
existingStrings, desiredStrings := sortedKeys(existingLookup), sortedKeys(desiredLookup)
|
||||
// Modifications. Take 1 from each side.
|
||||
for len(desiredStrings) > 0 && len(existingStrings) > 0 {
|
||||
|
@ -146,7 +151,7 @@ func (d *differ) IncrementalDiff(existing []*models.RecordConfig) (unchanged, cr
|
|||
delete(desiredByNameAndType, key)
|
||||
}
|
||||
|
||||
//any name/type sets not already processed are pure additions
|
||||
// any name/type sets not already processed are pure additions
|
||||
for name := range existingByNameAndType {
|
||||
delete(desiredByNameAndType, name)
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ Info required in `creds.json`:
|
|||
|
||||
*/
|
||||
|
||||
// DoApi is the handle for operations.
|
||||
type DoApi struct {
|
||||
client *godo.Client
|
||||
}
|
||||
|
@ -34,9 +35,10 @@ var defaultNameServerNames = []string{
|
|||
"ns3.digitalocean.com",
|
||||
}
|
||||
|
||||
// NewDo creates a DO-specific DNS provider.
|
||||
func NewDo(m map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
|
||||
if m["token"] == "" {
|
||||
return nil, fmt.Errorf("Digitalocean Token must be provided.")
|
||||
return nil, fmt.Errorf("no Digitalocean token provided")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
@ -54,7 +56,7 @@ func NewDo(m map[string]string, metadata json.RawMessage) (providers.DNSServiceP
|
|||
return nil, err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("Digitalocean Token is not valid.")
|
||||
return nil, fmt.Errorf("token for digitalocean is not valid")
|
||||
}
|
||||
|
||||
return api, nil
|
||||
|
@ -70,6 +72,7 @@ func init() {
|
|||
providers.RegisterDomainServiceProviderType("DIGITALOCEAN", NewDo, features)
|
||||
}
|
||||
|
||||
// EnsureDomainExists returns an error if domain doesn't exist.
|
||||
func (api *DoApi) EnsureDomainExists(domain string) error {
|
||||
ctx := context.Background()
|
||||
_, resp, err := api.client.Domains.Get(ctx, domain)
|
||||
|
@ -79,15 +82,16 @@ func (api *DoApi) EnsureDomainExists(domain string) error {
|
|||
IPAddress: "",
|
||||
})
|
||||
return err
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// GetNameservers returns the nameservers for domain.
|
||||
func (api *DoApi) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
||||
return models.StringsToNameservers(defaultNameServerNames), nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns a list of corretions for the domain.
|
||||
func (api *DoApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
ctx := context.Background()
|
||||
dc.Punycode()
|
||||
|
|
|
@ -40,16 +40,19 @@ var defaultNameServerNames = []string{
|
|||
"ns4.dnsimple.com",
|
||||
}
|
||||
|
||||
// DnsimpleApi is the handle for this provider.
|
||||
type DnsimpleApi struct {
|
||||
AccountToken string // The account access token
|
||||
BaseURL string // An alternate base URI
|
||||
accountId string // Account id cache
|
||||
accountID string // Account id cache
|
||||
}
|
||||
|
||||
// GetNameservers returns the name servers for a domain.
|
||||
func (c *DnsimpleApi) GetNameservers(domainName string) ([]*models.Nameserver, error) {
|
||||
return models.StringsToNameservers(defaultNameServerNames), nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns corrections that update a domain.
|
||||
func (c *DnsimpleApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
corrections := []*models.Correction{}
|
||||
dc.Punycode()
|
||||
|
@ -129,6 +132,7 @@ func (c *DnsimpleApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models.C
|
|||
return corrections, nil
|
||||
}
|
||||
|
||||
// GetRegistrarCorrections returns corrections that update a domain's registrar.
|
||||
func (c *DnsimpleApi) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
corrections := []*models.Correction{}
|
||||
|
||||
|
@ -168,8 +172,8 @@ func (c *DnsimpleApi) getClient() *dnsimpleapi.Client {
|
|||
return client
|
||||
}
|
||||
|
||||
func (c *DnsimpleApi) getAccountId() (string, error) {
|
||||
if c.accountId == "" {
|
||||
func (c *DnsimpleApi) getAccountID() (string, error) {
|
||||
if c.accountID == "" {
|
||||
client := c.getClient()
|
||||
whoamiResponse, err := client.Identity.Whoami()
|
||||
if err != nil {
|
||||
|
@ -178,15 +182,15 @@ func (c *DnsimpleApi) getAccountId() (string, error) {
|
|||
if whoamiResponse.Data.User != nil && whoamiResponse.Data.Account == nil {
|
||||
return "", fmt.Errorf("DNSimple token appears to be a user token. Please supply an account token")
|
||||
}
|
||||
c.accountId = strconv.Itoa(whoamiResponse.Data.Account.ID)
|
||||
c.accountID = strconv.Itoa(whoamiResponse.Data.Account.ID)
|
||||
}
|
||||
return c.accountId, nil
|
||||
return c.accountID, nil
|
||||
}
|
||||
|
||||
func (c *DnsimpleApi) getRecords(domainName string) ([]dnsimpleapi.ZoneRecord, error) {
|
||||
client := c.getClient()
|
||||
|
||||
accountId, err := c.getAccountId()
|
||||
accountID, err := c.getAccountID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -195,7 +199,7 @@ func (c *DnsimpleApi) getRecords(domainName string) ([]dnsimpleapi.ZoneRecord, e
|
|||
recs := []dnsimpleapi.ZoneRecord{}
|
||||
opts.Page = 1
|
||||
for {
|
||||
recordsResponse, err := client.Zones.ListRecords(accountId, domainName, opts)
|
||||
recordsResponse, err := client.Zones.ListRecords(accountID, domainName, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -216,27 +220,26 @@ func (c *DnsimpleApi) getRecords(domainName string) ([]dnsimpleapi.ZoneRecord, e
|
|||
func (c *DnsimpleApi) getNameservers(domainName string) ([]string, error) {
|
||||
client := c.getClient()
|
||||
|
||||
accountId, err := c.getAccountId()
|
||||
accountID, err := c.getAccountID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
domainResponse, err := client.Domains.GetDomain(accountId, domainName)
|
||||
domainResponse, err := client.Domains.GetDomain(accountID, domainName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if domainResponse.Data.State == stateRegistered {
|
||||
|
||||
delegationResponse, err := client.Registrar.GetDomainDelegation(accountId, domainName)
|
||||
delegationResponse, err := client.Registrar.GetDomainDelegation(accountID, domainName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return *delegationResponse.Data, nil
|
||||
} else {
|
||||
return defaultNameServerNames, nil
|
||||
}
|
||||
return defaultNameServerNames, nil
|
||||
}
|
||||
|
||||
// Returns a function that can be invoked to change the delegation of the domain to the given name server names.
|
||||
|
@ -244,14 +247,14 @@ func (c *DnsimpleApi) updateNameserversFunc(nameServerNames []string, domainName
|
|||
return func() error {
|
||||
client := c.getClient()
|
||||
|
||||
accountId, err := c.getAccountId()
|
||||
accountID, err := c.getAccountID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nameServers := dnsimpleapi.Delegation(nameServerNames)
|
||||
|
||||
_, err = client.Registrar.ChangeDomainDelegation(accountId, domainName, &nameServers)
|
||||
_, err = client.Registrar.ChangeDomainDelegation(accountID, domainName, &nameServers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -265,7 +268,7 @@ func (c *DnsimpleApi) createRecordFunc(rc *models.RecordConfig, domainName strin
|
|||
return func() error {
|
||||
client := c.getClient()
|
||||
|
||||
accountId, err := c.getAccountId()
|
||||
accountID, err := c.getAccountID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -276,7 +279,7 @@ func (c *DnsimpleApi) createRecordFunc(rc *models.RecordConfig, domainName strin
|
|||
TTL: int(rc.TTL),
|
||||
Priority: int(rc.MxPreference),
|
||||
}
|
||||
_, err = client.Zones.CreateRecord(accountId, domainName, record)
|
||||
_, err = client.Zones.CreateRecord(accountID, domainName, record)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -286,16 +289,16 @@ func (c *DnsimpleApi) createRecordFunc(rc *models.RecordConfig, domainName strin
|
|||
}
|
||||
|
||||
// Returns a function that can be invoked to delete a record in a zone.
|
||||
func (c *DnsimpleApi) deleteRecordFunc(recordId int, domainName string) func() error {
|
||||
func (c *DnsimpleApi) deleteRecordFunc(recordID int, domainName string) func() error {
|
||||
return func() error {
|
||||
client := c.getClient()
|
||||
|
||||
accountId, err := c.getAccountId()
|
||||
accountID, err := c.getAccountID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = client.Zones.DeleteRecord(accountId, domainName, recordId)
|
||||
_, err = client.Zones.DeleteRecord(accountID, domainName, recordID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -310,7 +313,7 @@ func (c *DnsimpleApi) updateRecordFunc(old *dnsimpleapi.ZoneRecord, rc *models.R
|
|||
return func() error {
|
||||
client := c.getClient()
|
||||
|
||||
accountId, err := c.getAccountId()
|
||||
accountID, err := c.getAccountID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -323,7 +326,7 @@ func (c *DnsimpleApi) updateRecordFunc(old *dnsimpleapi.ZoneRecord, rc *models.R
|
|||
Priority: int(rc.MxPreference),
|
||||
}
|
||||
|
||||
_, err = client.Zones.UpdateRecord(accountId, domainName, old.ID, record)
|
||||
_, err = client.Zones.UpdateRecord(accountID, domainName, old.ID, record)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -346,7 +349,7 @@ func newProvider(m map[string]string, metadata json.RawMessage) (*DnsimpleApi, e
|
|||
api := &DnsimpleApi{}
|
||||
api.AccountToken = m["token"]
|
||||
if api.AccountToken == "" {
|
||||
return nil, fmt.Errorf("DNSimple token must be provided.")
|
||||
return nil, fmt.Errorf("missing DNSimple token")
|
||||
}
|
||||
|
||||
if m["baseurl"] != "" {
|
||||
|
|
|
@ -40,6 +40,7 @@ func init() {
|
|||
providers.RegisterRegistrarType("GANDI", newReg)
|
||||
}
|
||||
|
||||
// GandiApi is the API handle for this module.
|
||||
type GandiApi struct {
|
||||
ApiKey string
|
||||
domainIndex map[string]int64 // Map of domainname to index
|
||||
|
@ -62,6 +63,7 @@ func (c *GandiApi) getDomainInfo(domain string) (*gandidomain.DomainInfo, error)
|
|||
return c.fetchDomainInfo(domain)
|
||||
}
|
||||
|
||||
// GetNameservers returns the nameservers for domain.
|
||||
func (c *GandiApi) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
||||
domaininfo, err := c.getDomainInfo(domain)
|
||||
if err != nil {
|
||||
|
@ -74,6 +76,7 @@ func (c *GandiApi) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
|||
return ns, nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns a list of corrections recommended for this domain.
|
||||
func (c *GandiApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc.Punycode()
|
||||
dc.CombineSRVs()
|
||||
|
@ -168,12 +171,13 @@ func newGandi(m map[string]string, metadata json.RawMessage) (*GandiApi, error)
|
|||
api := &GandiApi{}
|
||||
api.ApiKey = m["apikey"]
|
||||
if api.ApiKey == "" {
|
||||
return nil, fmt.Errorf("Gandi apikey must be provided.")
|
||||
return nil, fmt.Errorf("missing Gandi apikey")
|
||||
}
|
||||
|
||||
return api, nil
|
||||
}
|
||||
|
||||
// GetRegistrarCorrections returns a list of corrections for this registrar.
|
||||
func (c *GandiApi) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
domaininfo, err := c.getDomainInfo(dc.Name)
|
||||
if err != nil {
|
||||
|
|
|
@ -25,7 +25,7 @@ func (c *GandiApi) fetchDomainList() error {
|
|||
domain := gandidomain.New(gc)
|
||||
domains, err := domain.List()
|
||||
if err != nil {
|
||||
// fmt.Println(err)
|
||||
// fmt.Println(err)
|
||||
return err
|
||||
}
|
||||
for _, d := range domains {
|
||||
|
@ -71,10 +71,10 @@ func (c *GandiApi) listZones() ([]*gandizone.ZoneInfoBase, error) {
|
|||
}
|
||||
|
||||
// setZone assigns a particular zone to a domain.
|
||||
func (c *GandiApi) setZones(domainname string, zone_id int64) (*gandidomain.DomainInfo, error) {
|
||||
func (c *GandiApi) setZones(domainname string, zoneID int64) (*gandidomain.DomainInfo, error) {
|
||||
gc := gandiclient.New(c.ApiKey, gandiclient.Production)
|
||||
zone := gandizone.New(gc)
|
||||
return zone.Set(domainname, zone_id)
|
||||
return zone.Set(domainname, zoneID)
|
||||
}
|
||||
|
||||
// getZoneInfo gets ZoneInfo about a zone.
|
||||
|
@ -92,12 +92,12 @@ func (c *GandiApi) createZone(name string) (*gandizone.ZoneInfo, error) {
|
|||
}
|
||||
|
||||
func (c *GandiApi) getEditableZone(domainname string, zoneinfo *gandizone.ZoneInfo) (int64, error) {
|
||||
var zone_id int64
|
||||
var zoneID int64
|
||||
if zoneinfo.Domains < 2 {
|
||||
// If there is only on{ domain linked to this zone, use it.
|
||||
zone_id = zoneinfo.Id
|
||||
fmt.Printf("Using zone id=%d named %#v\n", zone_id, zoneinfo.Name)
|
||||
return zone_id, nil
|
||||
zoneID = zoneinfo.Id
|
||||
fmt.Printf("Using zone id=%d named %#v\n", zoneID, zoneinfo.Name)
|
||||
return zoneID, nil
|
||||
}
|
||||
|
||||
// We can't use the zone_id given to us. Let's make/find a new one.
|
||||
|
@ -108,39 +108,39 @@ func (c *GandiApi) getEditableZone(domainname string, zoneinfo *gandizone.ZoneIn
|
|||
zonename := fmt.Sprintf("%s dnscontrol", domainname)
|
||||
for _, z := range zones {
|
||||
if z.Name == zonename {
|
||||
zone_id = z.Id
|
||||
fmt.Printf("Recycling zone id=%d named %#v\n", zone_id, z.Name)
|
||||
return zone_id, nil
|
||||
zoneID = z.Id
|
||||
fmt.Printf("Recycling zone id=%d named %#v\n", zoneID, z.Name)
|
||||
return zoneID, nil
|
||||
}
|
||||
}
|
||||
zoneinfo, err = c.createZone(zonename)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
zone_id = zoneinfo.Id
|
||||
fmt.Printf("Created zone id=%d named %#v\n", zone_id, zoneinfo.Name)
|
||||
return zone_id, nil
|
||||
zoneID = zoneinfo.Id
|
||||
fmt.Printf("Created zone id=%d named %#v\n", zoneID, zoneinfo.Name)
|
||||
return zoneID, nil
|
||||
}
|
||||
|
||||
// makeEditableZone
|
||||
func (c *GandiApi) makeEditableZone(zone_id int64) (int64, error) {
|
||||
func (c *GandiApi) makeEditableZone(zoneID int64) (int64, error) {
|
||||
gc := gandiclient.New(c.ApiKey, gandiclient.Production)
|
||||
version := gandiversion.New(gc)
|
||||
return version.New(zone_id, 0)
|
||||
return version.New(zoneID, 0)
|
||||
}
|
||||
|
||||
// setZoneRecords
|
||||
func (c *GandiApi) setZoneRecords(zone_id, version_id int64, records []gandirecord.RecordSet) ([]*gandirecord.RecordInfo, error) {
|
||||
func (c *GandiApi) setZoneRecords(zoneID, versionID int64, records []gandirecord.RecordSet) ([]*gandirecord.RecordInfo, error) {
|
||||
gc := gandiclient.New(c.ApiKey, gandiclient.Production)
|
||||
record := gandirecord.New(gc)
|
||||
return record.SetRecords(zone_id, version_id, records)
|
||||
return record.SetRecords(zoneID, versionID, records)
|
||||
}
|
||||
|
||||
// activateVersion
|
||||
func (c *GandiApi) activateVersion(zone_id, version_id int64) (bool, error) {
|
||||
func (c *GandiApi) activateVersion(zoneID, versionID int64) (bool, error) {
|
||||
gc := gandiclient.New(c.ApiKey, gandiclient.Production)
|
||||
version := gandiversion.New(gc)
|
||||
return version.Set(zone_id, version_id)
|
||||
return version.Set(zoneID, versionID)
|
||||
}
|
||||
|
||||
func (c *GandiApi) createGandiZone(domainname string, zoneID int64, records []gandirecord.RecordSet) error {
|
||||
|
@ -150,7 +150,7 @@ func (c *GandiApi) createGandiZone(domainname string, zoneID int64, records []ga
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//fmt.Println("ZONEINFO:", zoneinfo)
|
||||
// fmt.Println("ZONEINFO:", zoneinfo)
|
||||
zoneID, err = c.getEditableZone(domainname, zoneinfo)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -114,7 +114,7 @@ func (g *gcloud) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correc
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//convert to dnscontrol RecordConfig format
|
||||
// convert to dnscontrol RecordConfig format
|
||||
existingRecords := []*models.RecordConfig{}
|
||||
oldRRs := map[key]*dns.ResourceRecordSet{}
|
||||
for _, set := range rrs {
|
||||
|
@ -168,7 +168,7 @@ func (g *gcloud) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correc
|
|||
if old, ok := oldRRs[ck]; ok {
|
||||
chg.Deletions = append(chg.Deletions, old)
|
||||
}
|
||||
//collect records to replace with
|
||||
// collect records to replace with
|
||||
newRRs := &dns.ResourceRecordSet{
|
||||
Name: ck.Name,
|
||||
Type: ck.Type,
|
||||
|
@ -240,7 +240,7 @@ func (g *gcloud) EnsureDomainExists(domain string) error {
|
|||
Name: strings.Replace(domain, ".", "-", -1),
|
||||
Description: "zone added by dnscontrol",
|
||||
}
|
||||
g.zones = nil //reset cache
|
||||
g.zones = nil // reset cache
|
||||
_, err = g.client.ManagedZones.Create(g.project, mz).Do()
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -173,10 +173,10 @@ func (c *LinodeApi) handleErrors(resp *http.Response) error {
|
|||
errs := &errorResponse{}
|
||||
|
||||
if err := decoder.Decode(errs); err != nil {
|
||||
return fmt.Errorf("Bad status code from Linode: %d not 200. Failed to decode response.", resp.StatusCode)
|
||||
return fmt.Errorf("bad status code from Linode: %d not 200. Failed to decode response", resp.StatusCode)
|
||||
}
|
||||
|
||||
buf := bytes.NewBufferString(fmt.Sprintf("Bad status code from Linode: %d not 200.", resp.StatusCode))
|
||||
buf := bytes.NewBufferString(fmt.Sprintf("bad status code from Linode: %d not 200", resp.StatusCode))
|
||||
|
||||
for _, err := range errs.Errors {
|
||||
buf.WriteString("\n- ")
|
||||
|
|
|
@ -45,6 +45,7 @@ var allowedTTLValues = []uint32{
|
|||
|
||||
var srvRegexp = regexp.MustCompile(`^_(?P<Service>\w+)\.\_(?P<Protocol>\w+)$`)
|
||||
|
||||
// LinodeApi is the handle for this provider.
|
||||
type LinodeApi struct {
|
||||
client *http.Client
|
||||
baseURL *url.URL
|
||||
|
@ -59,9 +60,10 @@ var defaultNameServerNames = []string{
|
|||
"ns5.linode.com",
|
||||
}
|
||||
|
||||
// NewLinode creates the provider.
|
||||
func NewLinode(m map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
|
||||
if m["token"] == "" {
|
||||
return nil, fmt.Errorf("Linode Token must be provided.")
|
||||
return nil, fmt.Errorf("Missing Linode token")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
@ -95,10 +97,12 @@ func init() {
|
|||
providers.RegisterDomainServiceProviderType("LINODE", NewLinode, features)
|
||||
}
|
||||
|
||||
// GetNameservers returns the nameservers for a domain.
|
||||
func (api *LinodeApi) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
||||
return models.StringsToNameservers(defaultNameServerNames), nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns the corrections for a domain.
|
||||
func (api *LinodeApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc, err := dc.Copy()
|
||||
if err != nil {
|
||||
|
@ -293,9 +297,8 @@ func fixTarget(target, domain string) string {
|
|||
// Linode always wants a fully qualified target name
|
||||
if target[len(target)-1] == '.' {
|
||||
return target[:len(target)-1]
|
||||
} else {
|
||||
return fmt.Sprintf("%s.%s", target, domain)
|
||||
}
|
||||
return fmt.Sprintf("%s.%s", target, domain)
|
||||
}
|
||||
|
||||
func fixTTL(ttl uint32) uint32 {
|
||||
|
|
|
@ -17,8 +17,10 @@ import (
|
|||
"github.com/miekg/dns/dnsutil"
|
||||
)
|
||||
|
||||
// NamecheapDefaultNs lists the default nameservers for this provider.
|
||||
var NamecheapDefaultNs = []string{"dns1.registrar-servers.com", "dns2.registrar-servers.com"}
|
||||
|
||||
// Namecheap is the handle for this provider.
|
||||
type Namecheap struct {
|
||||
ApiKey string
|
||||
ApiUser string
|
||||
|
@ -57,7 +59,7 @@ func newProvider(m map[string]string, metadata json.RawMessage) (*Namecheap, err
|
|||
api := &Namecheap{}
|
||||
api.ApiUser, api.ApiKey = m["apiuser"], m["apikey"]
|
||||
if api.ApiKey == "" || api.ApiUser == "" {
|
||||
return nil, fmt.Errorf("Namecheap apikey and apiuser must be provided.")
|
||||
return nil, fmt.Errorf("missing Namecheap apikey and apiuser")
|
||||
}
|
||||
api.client = nc.NewClient(api.ApiUser, api.ApiKey, api.ApiUser)
|
||||
// if BaseURL is specified in creds, use that url
|
||||
|
@ -104,6 +106,7 @@ func doWithRetry(f func() error) {
|
|||
}
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns the corrections for the domain.
|
||||
func (n *Namecheap) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc.Punycode()
|
||||
sld, tld := splitDomain(dc.Name)
|
||||
|
@ -221,6 +224,7 @@ func (n *Namecheap) generateRecords(dc *models.DomainConfig) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// GetNameservers returns the nameservers for a domain.
|
||||
func (n *Namecheap) GetNameservers(domainName string) ([]*models.Nameserver, error) {
|
||||
// return default namecheap nameservers
|
||||
ns := NamecheapDefaultNs
|
||||
|
@ -228,6 +232,7 @@ func (n *Namecheap) GetNameservers(domainName string) ([]*models.Nameserver, err
|
|||
return models.StringsToNameservers(ns), nil
|
||||
}
|
||||
|
||||
// GetRegistrarCorrections returns corrections to update nameservers.
|
||||
func (n *Namecheap) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
var info *nc.DomainInfo
|
||||
var err error
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//Package namedotcom implements a registrar that uses the name.com api to set name servers. It will self register it's providers when imported.
|
||||
// Package namedotcom implements a registrar that uses the name.com api to set name servers. It will self register it's providers when imported.
|
||||
package namedotcom
|
||||
|
||||
import (
|
||||
|
@ -11,7 +11,7 @@ import (
|
|||
"github.com/StackExchange/dnscontrol/providers"
|
||||
)
|
||||
|
||||
const defaultApiBase = "https://api.name.com/api"
|
||||
const defaultAPIBase = "https://api.name.com/api"
|
||||
|
||||
type nameDotCom struct {
|
||||
APIUrl string `json:"apiurl"`
|
||||
|
@ -40,10 +40,10 @@ func newProvider(conf map[string]string) (*nameDotCom, error) {
|
|||
api := &nameDotCom{}
|
||||
api.APIUser, api.APIKey, api.APIUrl = conf["apiuser"], conf["apikey"], conf["apiurl"]
|
||||
if api.APIKey == "" || api.APIUser == "" {
|
||||
return nil, fmt.Errorf("Name.com apikey and apiuser must be provided.")
|
||||
return nil, fmt.Errorf("missing Name.com apikey or apiuser")
|
||||
}
|
||||
if api.APIUrl == "" {
|
||||
api.APIUrl = defaultApiBase
|
||||
api.APIUrl = defaultAPIBase
|
||||
}
|
||||
return api, nil
|
||||
}
|
||||
|
@ -53,9 +53,7 @@ func init() {
|
|||
providers.RegisterDomainServiceProviderType("NAMEDOTCOM", newDsp, features)
|
||||
}
|
||||
|
||||
///
|
||||
//various http helpers for interacting with api
|
||||
///
|
||||
// various http helpers for interacting with api
|
||||
|
||||
func (n *nameDotCom) addAuth(r *http.Request) {
|
||||
r.Header.Add("Api-Username", n.APIUser)
|
||||
|
@ -82,7 +80,7 @@ func (r *apiResult) getErr() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
//perform http GET and unmarshal response json into target struct
|
||||
// perform http GET and unmarshal response json into target struct
|
||||
func (n *nameDotCom) get(url string, target interface{}) error {
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
|
|
|
@ -12,9 +12,9 @@ import (
|
|||
var nsRegex = regexp.MustCompile(`ns([1-4])[a-z]{3}\.name\.com`)
|
||||
|
||||
func (n *nameDotCom) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
||||
//This is an interesting edge case. Name.com expects you to SET the nameservers to ns[1-4].name.com,
|
||||
//but it will internally set it to ns1xyz.name.com, where xyz is a uniqueish 3 letters.
|
||||
//In order to avoid endless loops, we will use the unique nameservers if present, or else the generic ones if not.
|
||||
// This is an interesting edge case. Name.com expects you to SET the nameservers to ns[1-4].name.com,
|
||||
// but it will internally set it to ns1xyz.name.com, where xyz is a uniqueish 3 letters.
|
||||
// In order to avoid endless loops, we will use the unique nameservers if present, or else the generic ones if not.
|
||||
nss, err := n.getNameserversRaw(domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -22,7 +22,7 @@ func (n *nameDotCom) GetNameservers(domain string) ([]*models.Nameserver, error)
|
|||
toUse := []string{"ns1.name.com", "ns2.name.com", "ns3.name.com", "ns4.name.com"}
|
||||
for _, ns := range nss {
|
||||
if matches := nsRegex.FindStringSubmatch(ns); len(matches) == 2 && len(matches[1]) == 1 {
|
||||
idx := matches[1][0] - '1' //regex ensures proper range
|
||||
idx := matches[1][0] - '1' // regex ensures proper range
|
||||
toUse[idx] = matches[0]
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ func (n *nameDotCom) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
//even if you provide them "ns1.name.com", they will set it to "ns1qrt.name.com". This will match that pattern to see if defaults are in use.
|
||||
// even if you provide them "ns1.name.com", they will set it to "ns1qrt.name.com". This will match that pattern to see if defaults are in use.
|
||||
var defaultNsRegexp = regexp.MustCompile(`ns1[a-z]{0,3}\.name\.com,ns2[a-z]{0,3}\.name\.com,ns3[a-z]{0,3}\.name\.com,ns4[a-z]{0,3}\.name\.com`)
|
||||
|
||||
func (n *nameDotCom) apiGetDomain(domain string) string {
|
||||
|
@ -91,9 +91,6 @@ func (n *nameDotCom) updateNameservers(ns []string, domain string) func() error
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = resp.getErr(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return resp.getErr()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ func TestGetCorrections(t *testing.T) {
|
|||
{`"bar.ns.tld","foo.ns.tld"`, 0},
|
||||
{`"foo.ns.tld"`, 1},
|
||||
{`"1.ns.aaa","2.ns.www"`, 1},
|
||||
{"ERR", -1}, //-1 means we expect an error
|
||||
{"ERR", -1}, // -1 means we expect an error
|
||||
{"MSGERR", -1},
|
||||
} {
|
||||
setup()
|
||||
|
@ -155,12 +155,12 @@ func TestGetNameservers(t *testing.T) {
|
|||
for i, test := range []struct {
|
||||
givenNs, expected string
|
||||
}{
|
||||
//empty or external dsp, use ns1-4.name.com
|
||||
// empty or external dsp, use ns1-4.name.com
|
||||
{"", d},
|
||||
{`"foo.ns.tld","bar.ns.tld"`, d},
|
||||
//if already on name.com, use the existing nameservers
|
||||
// if already on name.com, use the existing nameservers
|
||||
{`"ns1aaa.name.com","ns2bbb.name.com","ns3ccc.name.com","ns4ddd.name.com"`, "ns1aaa.name.com,ns2bbb.name.com,ns3ccc.name.com,ns4ddd.name.com"},
|
||||
//also handle half and half
|
||||
// also handle half and half
|
||||
{`"ns1aaa.name.com","ns2bbb.name.com","ns3ccc.aws.net","ns4ddd.awsdns.org"`, "ns1aaa.name.com,ns2bbb.name.com,ns3.name.com,ns4.name.com"},
|
||||
{`"nsa.azuredns.com","ns2b.gandhi.net","ns3ccc.name.com","ns4ddd.name.com"`, "ns1.name.com,ns2.name.com,ns3ccc.name.com,ns4ddd.name.com"},
|
||||
} {
|
||||
|
|
|
@ -160,7 +160,7 @@ func (n *nameDotCom) createRecord(rc *models.RecordConfig, domain string) error
|
|||
if target[len(target)-1] == '.' {
|
||||
target = target[:len(target)-1]
|
||||
} else {
|
||||
return fmt.Errorf("Unexpected. CNAME/MX/NS target did not end with dot.\n")
|
||||
return fmt.Errorf("unexpected: CNAME/MX/NS target did not end with dot")
|
||||
}
|
||||
}
|
||||
dat := struct {
|
||||
|
|
|
@ -137,7 +137,7 @@ func (c *ovhProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.C
|
|||
rec := del.Existing.Original.(*Record)
|
||||
corrections = append(corrections, &models.Correction{
|
||||
Msg: del.String(),
|
||||
F: c.deleteRecordFunc(rec.Id, dc.Name),
|
||||
F: c.deleteRecordFunc(rec.ID, dc.Name),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -2,10 +2,12 @@ package ovh
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/models"
|
||||
"github.com/miekg/dns/dnsutil"
|
||||
)
|
||||
|
||||
// Void an empty structure.
|
||||
type Void struct {
|
||||
}
|
||||
|
||||
|
@ -30,6 +32,7 @@ func (c *ovhProvider) fetchZones() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Zone describes the attributes of a DNS zone.
|
||||
type Zone struct {
|
||||
LastUpdate string `json:"lastUpdate,omitempty"`
|
||||
HasDNSAnycast bool `json:"hasDNSAnycast,omitempty"`
|
||||
|
@ -49,17 +52,18 @@ func (c *ovhProvider) fetchZone(fqdn string) (*Zone, error) {
|
|||
return &response, nil
|
||||
}
|
||||
|
||||
// Record describes a DNS record.
|
||||
type Record struct {
|
||||
Target string `json:"target,omitempty"`
|
||||
Zone string `json:"zone,omitempty"`
|
||||
TTL uint32 `json:"ttl,omitempty"`
|
||||
FieldType string `json:"fieldType,omitempty"`
|
||||
Id int64 `json:"id,omitempty"`
|
||||
ID int64 `json:"id,omitempty"`
|
||||
SubDomain string `json:"subDomain,omitempty"`
|
||||
}
|
||||
|
||||
type records struct {
|
||||
recordsId []int
|
||||
recordsID []int
|
||||
}
|
||||
|
||||
func (c *ovhProvider) fetchRecords(fqdn string) ([]*Record, error) {
|
||||
|
@ -130,13 +134,13 @@ func (c *ovhProvider) updateRecordFunc(old *Record, rc *models.RecordConfig, fqd
|
|||
Target: rc.Content(),
|
||||
TTL: rc.TTL,
|
||||
Zone: fqdn,
|
||||
Id: old.Id,
|
||||
ID: old.ID,
|
||||
}
|
||||
if record.SubDomain == "@" {
|
||||
record.SubDomain = ""
|
||||
}
|
||||
|
||||
return c.client.Call("PUT", fmt.Sprintf("/domain/zone/%s/record/%d", fqdn, old.Id), &record, &Void{})
|
||||
return c.client.Call("PUT", fmt.Sprintf("/domain/zone/%s/record/%d", fqdn, old.ID), &record, &Void{})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,24 +159,25 @@ func (c *ovhProvider) fetchNS(fqdn string) ([]string, error) {
|
|||
return zone.NameServers, nil
|
||||
}
|
||||
|
||||
// CurrentNameServer stores information about nameservers.
|
||||
type CurrentNameServer struct {
|
||||
ToDelete bool `json:"toDelete,omitempty"`
|
||||
Ip string `json:"ip,omitempty"`
|
||||
IP string `json:"ip,omitempty"`
|
||||
IsUsed bool `json:"isUsed,omitempty"`
|
||||
Id int `json:"id,omitempty"`
|
||||
ID int `json:"id,omitempty"`
|
||||
Host string `json:"host,omitempty"`
|
||||
}
|
||||
|
||||
// Retrieve the NS currently being deployed to the registrar
|
||||
func (c *ovhProvider) fetchRegistrarNS(fqdn string) ([]string, error) {
|
||||
var nameServersId []int
|
||||
err := c.client.Call("GET", "/domain/"+fqdn+"/nameServer", nil, &nameServersId)
|
||||
var nameServersID []int
|
||||
err := c.client.Call("GET", "/domain/"+fqdn+"/nameServer", nil, &nameServersID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var nameServers []string
|
||||
for _, id := range nameServersId {
|
||||
for _, id := range nameServersID {
|
||||
var ns CurrentNameServer
|
||||
err = c.client.Call("GET", fmt.Sprintf("/domain/%s/nameServer/%d", fqdn, id), nil, &ns)
|
||||
if err != nil {
|
||||
|
@ -189,15 +194,18 @@ func (c *ovhProvider) fetchRegistrarNS(fqdn string) ([]string, error) {
|
|||
return nameServers, nil
|
||||
}
|
||||
|
||||
// DomainNS describes a domain's NS in ovh's protocol.
|
||||
type DomainNS struct {
|
||||
Host string `json:"host,omitempty"`
|
||||
Ip string `json:"ip,omitempty"`
|
||||
IP string `json:"ip,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateNS describes a list of nameservers in ovh's protocol.
|
||||
type UpdateNS struct {
|
||||
NameServers []DomainNS `json:"nameServers"`
|
||||
}
|
||||
|
||||
// Task describes a task in ovh's protocol.
|
||||
type Task struct {
|
||||
Function string `json:"function,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
|
@ -206,12 +214,13 @@ type Task struct {
|
|||
CreationDate string `json:"creationDate,omitempty"`
|
||||
Comment string `json:"comment,omitempty"`
|
||||
TodoDate string `json:"todoDate,omitempty"`
|
||||
Id int64 `json:"id,omitempty"`
|
||||
ID int64 `json:"id,omitempty"`
|
||||
CanCancel bool `json:"canCancel,omitempty"`
|
||||
DoneDate string `json:"doneDate,omitempty"`
|
||||
CanRelaunch bool `json:"canRelaunch,omitempty"`
|
||||
}
|
||||
|
||||
// Domain describes a domain in ovh's protocol.
|
||||
type Domain struct {
|
||||
NameServerType string `json:"nameServerType,omitempty"`
|
||||
TransferLockStatus string `json:"transferLockStatus,omitempty"`
|
||||
|
|
|
@ -8,34 +8,36 @@ import (
|
|||
"github.com/StackExchange/dnscontrol/models"
|
||||
)
|
||||
|
||||
//Registrar is an interface for a domain registrar. It can return a list of needed corrections to be applied in the future.
|
||||
// Registrar is an interface for a domain registrar. It can return a list of needed corrections to be applied in the future.
|
||||
type Registrar interface {
|
||||
GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error)
|
||||
}
|
||||
|
||||
//DNSServiceProvider is able to generate a set of corrections that need to be made to correct records for a domain
|
||||
// DNSServiceProvider is able to generate a set of corrections that need to be made to correct records for a domain
|
||||
type DNSServiceProvider interface {
|
||||
GetNameservers(domain string) ([]*models.Nameserver, error)
|
||||
GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error)
|
||||
}
|
||||
|
||||
//DomainCreator should be implemented by providers that have the ability to add domains to an account. the create-domains command
|
||||
//can be run to ensure all domains are present before running preview/push
|
||||
// DomainCreator should be implemented by providers that have the ability to add domains to an account. the create-domains command
|
||||
// can be run to ensure all domains are present before running preview/push
|
||||
type DomainCreator interface {
|
||||
EnsureDomainExists(domain string) error
|
||||
}
|
||||
|
||||
//RegistrarInitializer is a function to create a registrar. Function will be passed the unprocessed json payload from the configuration file for the given provider.
|
||||
// RegistrarInitializer is a function to create a registrar. Function will be passed the unprocessed json payload from the configuration file for the given provider.
|
||||
type RegistrarInitializer func(map[string]string) (Registrar, error)
|
||||
|
||||
// RegistrarTypes stores initializer for each registrar.
|
||||
var RegistrarTypes = map[string]RegistrarInitializer{}
|
||||
|
||||
//DspInitializer is a function to create a DNS service provider. Function will be passed the unprocessed json payload from the configuration file for the given provider.
|
||||
// DspInitializer is a function to create a DNS service provider. Function will be passed the unprocessed json payload from the configuration file for the given provider.
|
||||
type DspInitializer func(map[string]string, json.RawMessage) (DNSServiceProvider, error)
|
||||
|
||||
// DNSProviderTypes stores initializer for each DSP.
|
||||
var DNSProviderTypes = map[string]DspInitializer{}
|
||||
|
||||
//RegisterRegistrarType adds a registrar type to the registry by providing a suitable initialization function.
|
||||
// RegisterRegistrarType adds a registrar type to the registry by providing a suitable initialization function.
|
||||
func RegisterRegistrarType(name string, init RegistrarInitializer, pm ...ProviderMetadata) {
|
||||
if _, ok := RegistrarTypes[name]; ok {
|
||||
log.Fatalf("Cannot register registrar type %s multiple times", name)
|
||||
|
@ -44,7 +46,7 @@ func RegisterRegistrarType(name string, init RegistrarInitializer, pm ...Provide
|
|||
unwrapProviderCapabilities(name, pm)
|
||||
}
|
||||
|
||||
//RegisterDomainServiceProviderType adds a dsp to the registry with the given initialization function.
|
||||
// RegisterDomainServiceProviderType adds a dsp to the registry with the given initialization function.
|
||||
func RegisterDomainServiceProviderType(name string, init DspInitializer, pm ...ProviderMetadata) {
|
||||
if _, ok := DNSProviderTypes[name]; ok {
|
||||
log.Fatalf("Cannot register registrar type %s multiple times", name)
|
||||
|
@ -56,11 +58,12 @@ func RegisterDomainServiceProviderType(name string, init DspInitializer, pm ...P
|
|||
func createRegistrar(rType string, config map[string]string) (Registrar, error) {
|
||||
initer, ok := RegistrarTypes[rType]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Registrar type %s not declared.", rType)
|
||||
return nil, fmt.Errorf("registrar type %s not declared", rType)
|
||||
}
|
||||
return initer(config)
|
||||
}
|
||||
|
||||
// CreateDNSProvider returnsa DSP's initializer.
|
||||
func CreateDNSProvider(dType string, config map[string]string, meta json.RawMessage) (DNSServiceProvider, error) {
|
||||
initer, ok := DNSProviderTypes[dType]
|
||||
if !ok {
|
||||
|
@ -69,8 +72,8 @@ func CreateDNSProvider(dType string, config map[string]string, meta json.RawMess
|
|||
return initer(config, meta)
|
||||
}
|
||||
|
||||
//CreateRegistrars will load all registrars from the dns config, and create instances of the correct type using data from
|
||||
//the provider config to load relevant keys and options.
|
||||
// CreateRegistrars will load all registrars from the dns config, and create instances of the correct type using data from
|
||||
// the provider config to load relevant keys and options.
|
||||
func CreateRegistrars(d *models.DNSConfig, providerConfigs map[string]map[string]string) (map[string]Registrar, error) {
|
||||
regs := map[string]Registrar{}
|
||||
for _, reg := range d.Registrars {
|
||||
|
@ -87,6 +90,7 @@ func CreateRegistrars(d *models.DNSConfig, providerConfigs map[string]map[string
|
|||
return regs, nil
|
||||
}
|
||||
|
||||
// CreateDsps creates a DSP.
|
||||
func CreateDsps(d *models.DNSConfig, providerConfigs map[string]map[string]string) (map[string]DNSServiceProvider, error) {
|
||||
dsps := map[string]DNSServiceProvider{}
|
||||
for _, dsp := range d.DNSProviders {
|
||||
|
@ -103,14 +107,17 @@ func CreateDsps(d *models.DNSConfig, providerConfigs map[string]map[string]strin
|
|||
// None is a basic provider type that does absolutely nothing. Can be useful as a placeholder for third parties or unimplemented providers.
|
||||
type None struct{}
|
||||
|
||||
// GetRegistrarCorrections returns corrections to update registrars.
|
||||
func (n None) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetNameservers returns the current nameservers for a domain.
|
||||
func (n None) GetNameservers(string) ([]*models.Nameserver, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns corrections to update a domain.
|
||||
func (n None) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -121,6 +128,7 @@ func init() {
|
|||
})
|
||||
}
|
||||
|
||||
// CustomRType stores an rtype that is only valid for this DSP.
|
||||
type CustomRType struct {
|
||||
Name string
|
||||
Provider string
|
||||
|
|
|
@ -33,7 +33,7 @@ func newRoute53Dsp(conf map[string]string, metadata json.RawMessage) (providers.
|
|||
}
|
||||
|
||||
func newRoute53(m map[string]string, metadata json.RawMessage) (*route53Provider, error) {
|
||||
keyId, secretKey := m["KeyId"], m["SecretKey"]
|
||||
keyID, secretKey := m["KeyId"], m["SecretKey"]
|
||||
|
||||
// Route53 uses a global endpoint and route53domains
|
||||
// currently only has a single regional endpoint in us-east-1
|
||||
|
@ -42,8 +42,8 @@ func newRoute53(m map[string]string, metadata json.RawMessage) (*route53Provider
|
|||
Region: aws.String("us-east-1"),
|
||||
}
|
||||
|
||||
if keyId != "" || secretKey != "" {
|
||||
config.Credentials = credentials.NewStaticCredentials(keyId, secretKey, "")
|
||||
if keyID != "" || secretKey != "" {
|
||||
config.Credentials = credentials.NewStaticCredentials(keyID, secretKey, "")
|
||||
}
|
||||
sess := session.New(config)
|
||||
|
||||
|
@ -102,7 +102,7 @@ func (r *route53Provider) getZones() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
//map key for grouping records
|
||||
// map key for grouping records
|
||||
type key struct {
|
||||
Name, Type string
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ func (r *route53Provider) GetDomainCorrections(dc *models.DomainConfig) ([]*mode
|
|||
// Normalize
|
||||
models.PostProcessRecords(existingRecords)
|
||||
|
||||
//diff
|
||||
// diff
|
||||
differ := diff.New(dc)
|
||||
_, create, delete, modify := differ.IncrementalDiff(existingRecords)
|
||||
|
||||
|
@ -196,7 +196,7 @@ func (r *route53Provider) GetDomainCorrections(dc *models.DomainConfig) ([]*mode
|
|||
}
|
||||
|
||||
updates := map[key][]*models.RecordConfig{}
|
||||
//for each name we need to update, collect relevant records from dc
|
||||
// for each name we need to update, collect relevant records from dc
|
||||
for k := range namesToUpdate {
|
||||
updates[k] = nil
|
||||
for _, rc := range dc.Records {
|
||||
|
@ -227,7 +227,7 @@ func (r *route53Provider) GetDomainCorrections(dc *models.DomainConfig) ([]*mode
|
|||
} else {
|
||||
changes = append(changes, chg)
|
||||
changeDesc += strings.Join(namesToUpdate[k], "\n") + "\n"
|
||||
//on change or create, just build a new record set from our desired state
|
||||
// on change or create, just build a new record set from our desired state
|
||||
chg.Action = sPtr("UPSERT")
|
||||
rrset = &r53.ResourceRecordSet{
|
||||
Name: sPtr(k.Name),
|
||||
|
@ -241,7 +241,7 @@ func (r *route53Provider) GetDomainCorrections(dc *models.DomainConfig) ([]*mode
|
|||
}
|
||||
rrset.ResourceRecords = append(rrset.ResourceRecords, rr)
|
||||
i := int64(r.TTL)
|
||||
rrset.TTL = &i //TODO: make sure that ttls are consistent within a set
|
||||
rrset.TTL = &i // TODO: make sure that ttls are consistent within a set
|
||||
}
|
||||
}
|
||||
chg.ResourceRecordSet = rrset
|
||||
|
@ -367,13 +367,13 @@ func (r *route53Provider) fetchRecordSets(zoneID *string) ([]*r53.ResourceRecord
|
|||
return records, nil
|
||||
}
|
||||
|
||||
//we have to process names from route53 to match what we expect and to remove their odd octal encoding
|
||||
// we have to process names from route53 to match what we expect and to remove their odd octal encoding
|
||||
func unescape(s *string) string {
|
||||
if s == nil {
|
||||
return ""
|
||||
}
|
||||
name := strings.TrimSuffix(*s, ".")
|
||||
name = strings.Replace(name, `\052`, "*", -1) //TODO: escape all octal sequences
|
||||
name = strings.Replace(name, `\052`, "*", -1) // TODO: escape all octal sequences
|
||||
return name
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"github.com/softlayer/softlayer-go/session"
|
||||
)
|
||||
|
||||
// SoftLayer is the protocol handle for this provider.
|
||||
type SoftLayer struct {
|
||||
Session *session.Session
|
||||
}
|
||||
|
@ -36,7 +37,7 @@ func newReg(conf map[string]string, _ json.RawMessage) (providers.DNSServiceProv
|
|||
return nil, fmt.Errorf("SoftLayer UserName and APIKey must be provided")
|
||||
}
|
||||
|
||||
//s.Debug = true
|
||||
// s.Debug = true
|
||||
|
||||
api := &SoftLayer{
|
||||
Session: s,
|
||||
|
@ -45,12 +46,14 @@ func newReg(conf map[string]string, _ json.RawMessage) (providers.DNSServiceProv
|
|||
return api, nil
|
||||
}
|
||||
|
||||
// GetNameservers returns the nameservers for a domain.
|
||||
func (s *SoftLayer) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
||||
// Always use the same nameservers for softlayer
|
||||
nservers := []string{"ns1.softlayer.com", "ns2.softlayer.com"}
|
||||
return models.StringsToNameservers(nservers), nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns corrections to update a domain.
|
||||
func (s *SoftLayer) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
corrections := []*models.Correction{}
|
||||
|
||||
|
@ -174,16 +177,16 @@ func (s *SoftLayer) getExistingRecords(domain *datatypes.Dns_Domain) ([]*models.
|
|||
}
|
||||
|
||||
func (s *SoftLayer) createRecordFunc(desired *models.RecordConfig, domain *datatypes.Dns_Domain) func() error {
|
||||
var ttl, preference, domainId int = int(desired.TTL), int(desired.MxPreference), *domain.Id
|
||||
var ttl, preference, domainID int = int(desired.TTL), int(desired.MxPreference), *domain.Id
|
||||
var weight, priority, port int = int(desired.SrvWeight), int(desired.SrvPriority), int(desired.SrvPort)
|
||||
var host, data, newType string = desired.Name, desired.Target, desired.Type
|
||||
var err error = nil
|
||||
var err error
|
||||
|
||||
srvRegexp := regexp.MustCompile(`^_(?P<Service>\w+)\.\_(?P<Protocol>\w+)$`)
|
||||
|
||||
return func() error {
|
||||
newRecord := datatypes.Dns_Domain_ResourceRecord{
|
||||
DomainId: &domainId,
|
||||
DomainId: &domainID,
|
||||
Ttl: &ttl,
|
||||
Type: &newType,
|
||||
Data: &data,
|
||||
|
@ -232,11 +235,11 @@ func (s *SoftLayer) createRecordFunc(desired *models.RecordConfig, domain *datat
|
|||
}
|
||||
}
|
||||
|
||||
func (s *SoftLayer) deleteRecordFunc(resId int) func() error {
|
||||
func (s *SoftLayer) deleteRecordFunc(resID int) func() error {
|
||||
// seems to be no problem deleting MX and SRV records via common interface
|
||||
return func() error {
|
||||
_, err := services.GetDnsDomainResourceRecordService(s.Session).
|
||||
Id(resId).
|
||||
Id(resID).
|
||||
DeleteObject()
|
||||
|
||||
return err
|
||||
|
@ -248,8 +251,8 @@ func (s *SoftLayer) updateRecordFunc(existing *datatypes.Dns_Domain_ResourceReco
|
|||
var priority, weight, port int = int(desired.SrvPriority), int(desired.SrvWeight), int(desired.SrvPort)
|
||||
|
||||
return func() error {
|
||||
var changes bool = false
|
||||
var err error = nil
|
||||
var changes = false
|
||||
var err error
|
||||
|
||||
switch desired.Type {
|
||||
case "MX":
|
||||
|
@ -277,7 +280,7 @@ func (s *SoftLayer) updateRecordFunc(existing *datatypes.Dns_Domain_ResourceReco
|
|||
}
|
||||
|
||||
if !changes {
|
||||
return fmt.Errorf("Error: Didn't find changes when I expect some.")
|
||||
return fmt.Errorf("didn't find changes when I expect some")
|
||||
}
|
||||
|
||||
_, err = service.Id(*existing.Id).EditObject(&updated)
|
||||
|
@ -320,7 +323,7 @@ func (s *SoftLayer) updateRecordFunc(existing *datatypes.Dns_Domain_ResourceReco
|
|||
// delete and recreate?
|
||||
|
||||
if !changes {
|
||||
return fmt.Errorf("Error: Didn't find changes when I expect some.")
|
||||
return fmt.Errorf("didn't find changes when I expect some")
|
||||
}
|
||||
|
||||
_, err = service.Id(*existing.Id).EditObject(&updated)
|
||||
|
@ -345,7 +348,7 @@ func (s *SoftLayer) updateRecordFunc(existing *datatypes.Dns_Domain_ResourceReco
|
|||
}
|
||||
|
||||
if !changes {
|
||||
return fmt.Errorf("Error: Didn't find changes when I expect some.")
|
||||
return fmt.Errorf("didn't find changes when I expect some")
|
||||
}
|
||||
|
||||
_, err = service.Id(*existing.Id).EditObject(&updated)
|
||||
|
|
Loading…
Reference in a new issue