1
0
mirror of https://github.com/StackExchange/dnscontrol.git synced 2024-05-11 05:55:12 +00:00

Refactor: Prelink providers to domains (#305)

This commit is contained in:
Craig Peterson
2018-02-01 11:45:53 -05:00
committed by Tom Limoncelli
parent b7c6efaa53
commit 7a4dca5ad5
9 changed files with 181 additions and 131 deletions

View File

@ -77,7 +77,7 @@ func (args *GetDNSConfigArgs) flags() []cli.Flag {
) )
} }
// GetDNSConfig reads the json-formatted IR file. // GetDNSConfig reads the json-formatted IR file. Or executes javascript. All depending on flags provided.
func GetDNSConfig(args GetDNSConfigArgs) (*models.DNSConfig, error) { func GetDNSConfig(args GetDNSConfigArgs) (*models.DNSConfig, error) {
if args.JSONFile != "" { if args.JSONFile != "" {
f, err := os.Open(args.JSONFile) f, err := os.Open(args.JSONFile)
@ -90,9 +90,59 @@ func GetDNSConfig(args GetDNSConfigArgs) (*models.DNSConfig, error) {
if err = dec.Decode(cfg); err != nil { if err = dec.Decode(cfg); err != nil {
return nil, err return nil, err
} }
return cfg, nil return preloadProviders(cfg, nil)
} }
return ExecuteDSL(args.ExecuteDSLArgs) return preloadProviders(ExecuteDSL(args.ExecuteDSLArgs))
}
// the json only contains provider names inside domains. This denormalizes the data for more
// convenient access patterns. Does everything we need to prepare for the validation phase, but
// cannot do anything that requires the credentials file yet.
func preloadProviders(cfg *models.DNSConfig, err error) (*models.DNSConfig, error) {
if err != nil {
return cfg, err
}
//build name to type maps
cfg.RegistrarsByName = map[string]*models.RegistrarConfig{}
cfg.DNSProvidersByName = map[string]*models.DNSProviderConfig{}
for _, reg := range cfg.Registrars {
cfg.RegistrarsByName[reg.Name] = reg
}
for _, p := range cfg.DNSProviders {
cfg.DNSProvidersByName[p.Name] = p
}
// make registrar and dns provider shims. Include name, type, and other metadata, but can't inatantiate
// driver until we load creds in later
for _, d := range cfg.Domains {
reg, ok := cfg.RegistrarsByName[d.RegistrarName]
if !ok {
return nil, fmt.Errorf("Registrar named %s expected for %s, but never registered", d.RegistrarName, d.Name)
}
d.RegistrarInstance = &models.RegistrarInstance{
ProviderBase: models.ProviderBase{
Name: reg.Name,
ProviderType: reg.Type,
},
}
for pName, n := range d.DNSProviderNames {
prov, ok := cfg.DNSProvidersByName[pName]
if !ok {
return nil, fmt.Errorf("DNS Provider named %s expected for %s, but never registered", pName, d.Name)
}
d.DNSProviderInstances = append(d.DNSProviderInstances, &models.DNSProviderInstance{
ProviderBase: models.ProviderBase{
Name: pName,
ProviderType: prov.Type,
},
NumberOfNameservers: n,
})
}
// sort so everything is deterministic
sort.Slice(d.DNSProviderInstances, func(i, j int) bool {
return d.DNSProviderInstances[i].Name < d.DNSProviderInstances[j].Name
})
}
return cfg, nil
} }
// ExecuteDSLArgs are used anytime we need to read and execute dnscontrol DSL // ExecuteDSLArgs are used anytime we need to read and execute dnscontrol DSL
@ -185,20 +235,20 @@ func (args *FilterArgs) flags() []cli.Flag {
} }
} }
func (args *FilterArgs) shouldRunProvider(p string, dc *models.DomainConfig, nonDefaultProviders []string) bool { func (args *FilterArgs) shouldRunProvider(name string, dc *models.DomainConfig) bool {
if args.Providers == "all" { if args.Providers == "all" {
return true return true
} }
if args.Providers == "" { if args.Providers == "" {
for _, pr := range nonDefaultProviders { for _, pri := range dc.DNSProviderInstances {
if pr == p { if pri.Name == name {
return false return pri.IsDefault
} }
} }
return true return true
} }
for _, prov := range strings.Split(args.Providers, ",") { for _, prov := range strings.Split(args.Providers, ",") {
if prov == p { if prov == name {
return true return true
} }
} }

View File

@ -2,7 +2,6 @@ package commands
import ( import (
"fmt" "fmt"
"log"
"github.com/StackExchange/dnscontrol/providers" "github.com/StackExchange/dnscontrol/providers"
"github.com/urfave/cli" "github.com/urfave/cli"
@ -38,21 +37,15 @@ func CreateDomains(args CreateDomainsArgs) error {
if err != nil { if err != nil {
return err return err
} }
registrars, dnsProviders, _, _, err := InitializeProviders(args.CredsFile, cfg, false) _, err = InitializeProviders(args.CredsFile, cfg, false)
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("Initialized %d registrars and %d dns service providers.\n", len(registrars), len(dnsProviders))
for _, domain := range cfg.Domains { for _, domain := range cfg.Domains {
fmt.Println("*** ", domain.Name) fmt.Println("*** ", domain.Name)
for prov := range domain.DNSProviders { for _, provider := range domain.DNSProviderInstances {
dsp, ok := dnsProviders[prov] if creator, ok := provider.Driver.(providers.DomainCreator); ok {
if !ok { fmt.Println(" -", provider.Name)
log.Fatalf("DSP %s not declared.", prov)
}
if creator, ok := dsp.(providers.DomainCreator); ok {
fmt.Println(" -", prov)
// TODO: maybe return bool if it did anything.
err := creator.EnsureDomainExists(domain.Name) err := creator.EnsureDomainExists(domain.Name)
if err != nil { if err != nil {
fmt.Printf("Error creating domain: %s\n", err) fmt.Printf("Error creating domain: %s\n", err)

View File

@ -96,11 +96,11 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI) error {
if PrintValidationErrors(errs) { if PrintValidationErrors(errs) {
return fmt.Errorf("Exiting due to validation errors") return fmt.Errorf("Exiting due to validation errors")
} }
registrars, dnsProviders, nonDefaultProviders, notifier, err := InitializeProviders(args.CredsFile, cfg, args.Notify) // TODO:
notifier, err := InitializeProviders(args.CredsFile, cfg, args.Notify)
if err != nil { if err != nil {
return err return err
} }
out.Debugf("Initialized %d registrars and %d dns service providers.\n", len(registrars), len(dnsProviders))
anyErrors := false anyErrors := false
totalCorrections := 0 totalCorrections := 0
DomainLoop: DomainLoop:
@ -109,45 +109,36 @@ DomainLoop:
continue continue
} }
out.StartDomain(domain.Name) out.StartDomain(domain.Name)
nsList, err := nameservers.DetermineNameservers(domain, 0, dnsProviders) nsList, err := nameservers.DetermineNameservers(domain)
if err != nil { if err != nil {
return err return err
} }
domain.Nameservers = nsList domain.Nameservers = nsList
nameservers.AddNSRecords(domain) nameservers.AddNSRecords(domain)
for prov := range domain.DNSProviders { for _, provider := range domain.DNSProviderInstances {
dc, err := domain.Copy() dc, err := domain.Copy()
if err != nil { if err != nil {
return err return err
} }
shouldrun := args.shouldRunProvider(prov, dc, nonDefaultProviders) shouldrun := args.shouldRunProvider(provider.Name, dc)
out.StartDNSProvider(prov, !shouldrun) out.StartDNSProvider(provider.Name, !shouldrun)
if !shouldrun { if !shouldrun {
continue continue
} }
// TODO: make provider discovery like this a validate-time operation corrections, err := provider.Driver.GetDomainCorrections(dc)
dsp, ok := dnsProviders[prov]
if !ok {
log.Fatalf("DSP %s not declared.", prov)
}
corrections, err := dsp.GetDomainCorrections(dc)
out.EndProvider(len(corrections), err) out.EndProvider(len(corrections), err)
if err != nil { if err != nil {
anyErrors = true anyErrors = true
continue DomainLoop continue DomainLoop
} }
totalCorrections += len(corrections) totalCorrections += len(corrections)
anyErrors = printOrRunCorrections(domain.Name, prov, corrections, out, push, interactive, notifier) || anyErrors anyErrors = printOrRunCorrections(domain.Name, provider.Name, corrections, out, push, interactive, notifier) || anyErrors
} }
run := args.shouldRunProvider(domain.Registrar, domain, nonDefaultProviders) run := args.shouldRunProvider(domain.RegistrarName, domain)
out.StartRegistrar(domain.Registrar, !run) out.StartRegistrar(domain.RegistrarName, !run)
if !run { if !run {
continue continue
} }
reg, ok := registrars[domain.Registrar]
if !ok {
log.Fatalf("Registrar %s not declared.", reg)
}
if len(domain.Nameservers) == 0 && domain.Metadata["no_ns"] != "true" { if len(domain.Nameservers) == 0 && domain.Metadata["no_ns"] != "true" {
out.Warnf("No nameservers declared; skipping registrar. Add {no_ns:'true'} to force.\n") out.Warnf("No nameservers declared; skipping registrar. Add {no_ns:'true'} to force.\n")
continue continue
@ -156,14 +147,14 @@ DomainLoop:
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
corrections, err := reg.GetRegistrarCorrections(dc) corrections, err := domain.RegistrarInstance.Driver.GetRegistrarCorrections(dc)
out.EndProvider(len(corrections), err) out.EndProvider(len(corrections), err)
if err != nil { if err != nil {
anyErrors = true anyErrors = true
continue continue
} }
totalCorrections += len(corrections) totalCorrections += len(corrections)
anyErrors = printOrRunCorrections(domain.Name, domain.Registrar, corrections, out, push, interactive, notifier) || anyErrors anyErrors = printOrRunCorrections(domain.Name, domain.RegistrarName, corrections, out, push, interactive, notifier) || anyErrors
} }
if os.Getenv("TEAMCITY_VERSION") != "" { if os.Getenv("TEAMCITY_VERSION") != "" {
fmt.Fprintf(os.Stderr, "##teamcity[buildStatus status='SUCCESS' text='%d corrections']", totalCorrections) fmt.Fprintf(os.Stderr, "##teamcity[buildStatus status='SUCCESS' text='%d corrections']", totalCorrections)
@ -178,7 +169,7 @@ DomainLoop:
// InitializeProviders takes a creds file path and a DNSConfig object. Creates all providers with the proper types, and returns them. // InitializeProviders takes a creds file path and a DNSConfig object. Creates all providers with the proper types, and returns them.
// nonDefaultProviders is a list of providers that should not be run unless explicitly asked for by flags. // nonDefaultProviders is a list of providers that should not be run unless explicitly asked for by flags.
func InitializeProviders(credsFile string, cfg *models.DNSConfig, notifyFlag bool) (registrars map[string]providers.Registrar, dnsProviders map[string]providers.DNSServiceProvider, nonDefaultProviders []string, notify notifications.Notifier, err error) { func InitializeProviders(credsFile string, cfg *models.DNSConfig, notifyFlag bool) (notify notifications.Notifier, err error) {
var providerConfigs map[string]map[string]string var providerConfigs map[string]map[string]string
var notificationCfg map[string]string var notificationCfg map[string]string
defer func() { defer func() {
@ -191,21 +182,39 @@ func InitializeProviders(credsFile string, cfg *models.DNSConfig, notifyFlag boo
if notifyFlag { if notifyFlag {
notificationCfg = providerConfigs["notifications"] notificationCfg = providerConfigs["notifications"]
} }
nonDefaultProviders = []string{} isNonDefault := map[string]bool{}
for name, vals := range providerConfigs { for name, vals := range providerConfigs {
// add "_exclude_from_defaults":"true" to a provider to exclude it from being run unless // add "_exclude_from_defaults":"true" to a provider to exclude it from being run unless
// -providers=all or -providers=name // -providers=all or -providers=name
if vals["_exclude_from_defaults"] == "true" { if vals["_exclude_from_defaults"] == "true" {
nonDefaultProviders = append(nonDefaultProviders, name) isNonDefault[name] = true
} }
} }
registrars, err = providers.CreateRegistrars(cfg, providerConfigs) registrars := map[string]providers.Registrar{}
if err != nil { dnsProviders := map[string]providers.DNSServiceProvider{}
return for _, d := range cfg.Domains {
} if registrars[d.RegistrarName] == nil {
dnsProviders, err = providers.CreateDsps(cfg, providerConfigs) rCfg := cfg.RegistrarsByName[d.RegistrarName]
if err != nil { r, err := providers.CreateRegistrar(rCfg.Type, providerConfigs[d.RegistrarName])
return if err != nil {
return nil, err
}
registrars[d.RegistrarName] = r
}
d.RegistrarInstance.Driver = registrars[d.RegistrarName]
d.RegistrarInstance.IsDefault = !isNonDefault[d.RegistrarName]
for _, pInst := range d.DNSProviderInstances {
if dnsProviders[pInst.Name] == nil {
dCfg := cfg.DNSProvidersByName[pInst.Name]
prov, err := providers.CreateDNSProvider(dCfg.Type, providerConfigs[dCfg.Name], dCfg.Metadata)
if err != nil {
return nil, err
}
dnsProviders[pInst.Name] = prov
}
pInst.Driver = dnsProviders[pInst.Name]
pInst.IsDefault = !isNonDefault[pInst.Name]
}
} }
return return
} }

View File

@ -21,9 +21,11 @@ const DefaultTTL = uint32(300)
// DNSConfig describes the desired DNS configuration, usually loaded from dnsconfig.js. // DNSConfig describes the desired DNS configuration, usually loaded from dnsconfig.js.
type DNSConfig struct { type DNSConfig struct {
Registrars []*RegistrarConfig `json:"registrars"` Registrars []*RegistrarConfig `json:"registrars"`
DNSProviders []*DNSProviderConfig `json:"dns_providers"` DNSProviders []*DNSProviderConfig `json:"dns_providers"`
Domains []*DomainConfig `json:"domains"` Domains []*DomainConfig `json:"domains"`
RegistrarsByName map[string]*RegistrarConfig `json:"-"`
DNSProvidersByName map[string]*DNSProviderConfig `json:"-"`
} }
// FindDomain returns the *DomainConfig for domain query in config. // FindDomain returns the *DomainConfig for domain query in config.
@ -348,20 +350,41 @@ func StringsToNameservers(nss []string) []*Nameserver {
// DomainConfig describes a DNS domain (tecnically a DNS zone). // DomainConfig describes a DNS domain (tecnically a DNS zone).
type DomainConfig struct { type DomainConfig struct {
Name string `json:"name"` // NO trailing "." Name string `json:"name"` // NO trailing "."
Registrar string `json:"registrar"` RegistrarName string `json:"registrar"`
DNSProviders map[string]int `json:"dnsProviders"` DNSProviderNames map[string]int `json:"dnsProviders"`
Metadata map[string]string `json:"meta,omitempty"` Metadata map[string]string `json:"meta,omitempty"`
Records Records `json:"records"` Records Records `json:"records"`
Nameservers []*Nameserver `json:"nameservers,omitempty"` Nameservers []*Nameserver `json:"nameservers,omitempty"`
KeepUnknown bool `json:"keepunknown,omitempty"` KeepUnknown bool `json:"keepunknown,omitempty"`
IgnoredLabels []string `json:"ignored_labels,omitempty"` IgnoredLabels []string `json:"ignored_labels,omitempty"`
// These fields contain instantiated provider instances once everything is linked up.
// This linking is in two phases:
// 1. Metadata (name/type) is availible just from the dnsconfig. Validation can use that.
// 2. Final driver instances are loaded after we load credentials. Any actual provider interaction requires that.
RegistrarInstance *RegistrarInstance `json:"-"`
DNSProviderInstances []*DNSProviderInstance `json:"-"`
} }
// Copy returns a deep copy of the DomainConfig. // Copy returns a deep copy of the DomainConfig.
func (dc *DomainConfig) Copy() (*DomainConfig, error) { func (dc *DomainConfig) Copy() (*DomainConfig, error) {
newDc := &DomainConfig{} newDc := &DomainConfig{}
// provider instances are interfaces that gob hates if you don't register them.
// and the specific types are not gob encodable since nothing is exported.
// should find a better solution for this now.
//
// current strategy: remove everything, gob copy it. Then set both to stored copy.
reg := dc.RegistrarInstance
dnsps := dc.DNSProviderInstances
dc.RegistrarInstance = nil
dc.DNSProviderInstances = nil
err := copyObj(dc, newDc) err := copyObj(dc, newDc)
dc.RegistrarInstance = reg
newDc.RegistrarInstance = reg
dc.DNSProviderInstances = dnsps
newDc.DNSProviderInstances = dnsps
return newDc, err return newDc, err
} }

27
models/provider.go Normal file
View File

@ -0,0 +1,27 @@
package models
type DNSProvider interface {
GetNameservers(domain string) ([]*Nameserver, error)
GetDomainCorrections(dc *DomainConfig) ([]*Correction, error)
}
type Registrar interface {
GetRegistrarCorrections(dc *DomainConfig) ([]*Correction, error)
}
type ProviderBase struct {
Name string
IsDefault bool
ProviderType string
}
type RegistrarInstance struct {
ProviderBase
Driver Registrar
}
type DNSProviderInstance struct {
ProviderBase
Driver DNSProvider
NumberOfNameservers int
}

View File

@ -8,26 +8,22 @@ import (
"strconv" "strconv"
"github.com/StackExchange/dnscontrol/models" "github.com/StackExchange/dnscontrol/models"
"github.com/StackExchange/dnscontrol/providers"
"github.com/miekg/dns/dnsutil" "github.com/miekg/dns/dnsutil"
) )
// DetermineNameservers will find all nameservers we should use for a domain. It follows the following rules: // 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. // 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. // 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) { func DetermineNameservers(dc *models.DomainConfig) ([]*models.Nameserver, error) {
// always take explicit // always take explicit
ns := dc.Nameservers ns := dc.Nameservers
for dsp, n := range dc.DNSProviders { for _, dnsProvider := range dc.DNSProviderInstances {
n := dnsProvider.NumberOfNameservers
if n == 0 { if n == 0 {
continue continue
} }
fmt.Printf("----- Getting nameservers from: %s\n", dsp) fmt.Printf("----- Getting nameservers from: %s\n", dnsProvider.Name)
p, ok := dsps[dsp] nss, err := dnsProvider.Driver.GetNameservers(dc.Name)
if !ok {
return nil, fmt.Errorf("DNS provider %s not declared", dsp)
}
nss, err := p.GetNameservers(dc.Name)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -246,30 +246,19 @@ type Warning struct {
// NormalizeAndValidateConfig performs and normalization and/or validation of the IR. // NormalizeAndValidateConfig performs and normalization and/or validation of the IR.
func NormalizeAndValidateConfig(config *models.DNSConfig) (errs []error) { func NormalizeAndValidateConfig(config *models.DNSConfig) (errs []error) {
ptypeMap := map[string]string{}
for _, p := range config.DNSProviders {
ptypeMap[p.Name] = p.Type
}
for _, domain := range config.Domains { for _, domain := range config.Domains {
pTypes := []string{} pTypes := []string{}
txtMultiDissenters := []string{} txtMultiDissenters := []string{}
for p := range domain.DNSProviders { for _, provider := range domain.DNSProviderInstances {
pType, ok := ptypeMap[p] pType := provider.ProviderType
if !ok {
errs = append(errs, fmt.Errorf("%s uses undefined DNS provider %s", domain.Name, p))
} else {
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) { 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)) errs = append(errs, fmt.Errorf("%s uses NO_PURGE which is not supported by %s(%s)", domain.Name, provider.Name, pType))
} }
// Record if any providers do not support TXTMulti: // Record if any providers do not support TXTMulti:
if !providers.ProviderHasCabability(pType, providers.CanUseTXTMulti) { if !providers.ProviderHasCabability(pType, providers.CanUseTXTMulti) {
txtMultiDissenters = append(txtMultiDissenters, p) txtMultiDissenters = append(txtMultiDissenters, provider.Name)
} }
} }
@ -374,7 +363,7 @@ func NormalizeAndValidateConfig(config *models.DNSConfig) (errs []error) {
// 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 { for _, d := range config.Domains {
err := checkProviderCapabilities(d, config.DNSProviders) err := checkProviderCapabilities(d)
if err != nil { if err != nil {
errs = append(errs, err) errs = append(errs, err)
} }
@ -401,7 +390,7 @@ func checkCNAMEs(dc *models.DomainConfig) (errs []error) {
return return
} }
func checkProviderCapabilities(dc *models.DomainConfig, pList []*models.DNSProviderConfig) error { func checkProviderCapabilities(dc *models.DomainConfig) error {
types := []struct { types := []struct {
rType string rType string
cap providers.Capability cap providers.Capability
@ -423,14 +412,9 @@ func checkProviderCapabilities(dc *models.DomainConfig, pList []*models.DNSProvi
if !hasAny { if !hasAny {
continue continue
} }
for pName := range dc.DNSProviders { for _, provider := range dc.DNSProviderInstances {
for _, p := range pList { if !providers.ProviderHasCabability(provider.ProviderType, ty.cap) {
if p.Name == pName { return fmt.Errorf("Domain %s uses %s records, but DNS provider type %s does not support them", dc.Name, ty.rType, provider.ProviderType)
if !providers.ProviderHasCabability(p.Type, ty.cap) {
return fmt.Errorf("Domain %s uses %s records, but DNS provider type %s does not support them", dc.Name, ty.rType, p.Type)
}
break
}
} }
} }
} }

View File

@ -193,8 +193,8 @@ func TestCAAValidation(t *testing.T) {
config := &models.DNSConfig{ config := &models.DNSConfig{
Domains: []*models.DomainConfig{ Domains: []*models.DomainConfig{
{ {
Name: "example.com", Name: "example.com",
Registrar: "BIND", RegistrarName: "BIND",
Records: []*models.RecordConfig{ Records: []*models.RecordConfig{
{Name: "@", Type: "CAA", CaaTag: "invalid", Target: "example.com"}, {Name: "@", Type: "CAA", CaaTag: "invalid", Target: "example.com"},
}, },
@ -211,8 +211,8 @@ func TestTLSAValidation(t *testing.T) {
config := &models.DNSConfig{ config := &models.DNSConfig{
Domains: []*models.DomainConfig{ Domains: []*models.DomainConfig{
{ {
Name: "_443._tcp.example.com", Name: "_443._tcp.example.com",
Registrar: "BIND", RegistrarName: "BIND",
Records: []*models.RecordConfig{ Records: []*models.RecordConfig{
{Name: "_443._tcp", Type: "TLSA", TlsaUsage: 4, TlsaSelector: 1, TlsaMatchingType: 1, Target: "abcdef0"}, {Name: "_443._tcp", Type: "TLSA", TlsaUsage: 4, TlsaSelector: 1, TlsaMatchingType: 1, Target: "abcdef0"},
}, },

View File

@ -10,13 +10,12 @@ import (
// 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 { type Registrar interface {
GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) models.Registrar
} }
// 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 { type DNSServiceProvider interface {
GetNameservers(domain string) ([]*models.Nameserver, error) models.DNSProvider
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 // DomainCreator should be implemented by providers that have the ability to add domains to an account. the create-domains command
@ -55,7 +54,8 @@ func RegisterDomainServiceProviderType(name string, init DspInitializer, pm ...P
unwrapProviderCapabilities(name, pm) unwrapProviderCapabilities(name, pm)
} }
func createRegistrar(rType string, config map[string]string) (Registrar, error) { // CreateRegistrar initializes a registrar instance from given credentials.
func CreateRegistrar(rType string, config map[string]string) (Registrar, error) {
initer, ok := RegistrarTypes[rType] initer, ok := RegistrarTypes[rType]
if !ok { if !ok {
return nil, fmt.Errorf("registrar type %s not declared", rType) return nil, fmt.Errorf("registrar type %s not declared", rType)
@ -63,7 +63,7 @@ func createRegistrar(rType string, config map[string]string) (Registrar, error)
return initer(config) return initer(config)
} }
// CreateDNSProvider returnsa DSP's initializer. // CreateDNSProvider initializes a dns provider instance from given credentials.
func CreateDNSProvider(dType string, config map[string]string, meta json.RawMessage) (DNSServiceProvider, error) { func CreateDNSProvider(dType string, config map[string]string, meta json.RawMessage) (DNSServiceProvider, error) {
initer, ok := DNSProviderTypes[dType] initer, ok := DNSProviderTypes[dType]
if !ok { if !ok {
@ -72,38 +72,6 @@ func CreateDNSProvider(dType string, config map[string]string, meta json.RawMess
return initer(config, meta) 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.
func CreateRegistrars(d *models.DNSConfig, providerConfigs map[string]map[string]string) (map[string]Registrar, error) {
regs := map[string]Registrar{}
for _, reg := range d.Registrars {
rawMsg, ok := providerConfigs[reg.Name]
if !ok && reg.Type != "NONE" {
return nil, fmt.Errorf("Registrar %s not listed in creds.json file", reg.Name)
}
registrar, err := createRegistrar(reg.Type, rawMsg)
if err != nil {
return nil, fmt.Errorf("Creating %s registrar: %s", reg.Name, err)
}
regs[reg.Name] = registrar
}
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 {
vals := providerConfigs[dsp.Name]
provider, err := CreateDNSProvider(dsp.Type, vals, dsp.Metadata)
if err != nil {
return nil, fmt.Errorf("Creating %s dns provider: %s", dsp.Name, err)
}
dsps[dsp.Name] = provider
}
return dsps, nil
}
// None is a basic provider type that does absolutely nothing. Can be useful as a placeholder for third parties or unimplemented providers. // 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{} type None struct{}