dnscontrol/providers/providers.go
Craig Peterson fb14cea91e Support ALIAS records with Cloudflare (#89)
* simple facility for registering provider capabilities

* support for cloudflare. tests.

* js and docs

* docs

* generate
2017-04-19 13:13:28 -06:00

141 lines
4.9 KiB
Go

package providers
import (
"encoding/json"
"fmt"
"log"
"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.
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
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
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.
type RegistrarInitializer func(map[string]string) (Registrar, error)
var registrarTypes = map[string]RegistrarInitializer{}
//DspInitializer is a function to create a registrar. 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)
var dspTypes = map[string]DspInitializer{}
var dspCapabilities = map[string]Capability{}
//Capability is a bitmasked set of "features" that a provider supports. Only use constants from this package.
type Capability uint32
const (
// CanUseAlias indicates the provider support ALIAS records (or flattened CNAMES). Up to the provider to translate them to the appropriate record type.
CanUseAlias Capability = 1 << iota
// CanUsePTR indicates the provider can handle PTR records
CanUsePTR
)
func ProviderHasCabability(pType string, cap Capability) bool {
return dspCapabilities[pType]&cap != 0
}
//RegisterRegistrarType adds a registrar type to the registry by providing a suitable initialization function.
func RegisterRegistrarType(name string, init RegistrarInitializer) {
if _, ok := registrarTypes[name]; ok {
log.Fatalf("Cannot register registrar type %s multiple times", name)
}
registrarTypes[name] = init
}
//RegisterDomainServiceProviderType adds a dsp to the registry with the given initialization function.
func RegisterDomainServiceProviderType(name string, init DspInitializer, caps ...Capability) {
if _, ok := dspTypes[name]; ok {
log.Fatalf("Cannot register registrar type %s multiple times", name)
}
var abilities Capability
for _, c := range caps {
abilities |= c
}
dspTypes[name] = init
dspCapabilities[name] = abilities
}
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 initer(config)
}
func CreateDNSProvider(dType string, config map[string]string, meta json.RawMessage) (DNSServiceProvider, error) {
initer, ok := dspTypes[dType]
if !ok {
return nil, fmt.Errorf("DSP type %s not declared", dType)
}
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 -providers file.", reg.Name)
}
registrar, err := createRegistrar(reg.Type, rawMsg)
if err != nil {
return nil, err
}
regs[reg.Name] = registrar
}
return regs, nil
}
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, err
}
dsps[dsp.Name] = provider
}
return dsps, nil
}
// None is a basivc provider type that does absolutely nothing. Can be useful as a placeholder for third parties or unimplemented providers.
type None struct{}
func (n None) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
return nil, nil
}
func (n None) GetNameservers(string) ([]*models.Nameserver, error) {
return nil, nil
}
func (n None) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
return nil, nil
}
func init() {
RegisterRegistrarType("NONE", func(map[string]string) (Registrar, error) {
return None{}, nil
})
}