2016-08-23 08:31:50 +08:00
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 {
2016-12-17 04:10:27 +08:00
GetNameservers ( domain string ) ( [ ] * models . Nameserver , error )
2016-08-23 08:31:50 +08:00
GetDomainCorrections ( dc * models . DomainConfig ) ( [ ] * models . Correction , error )
}
2017-01-04 04:26:08 +08:00
//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
}
2016-08-23 08:31:50 +08:00
//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 { }
2017-04-27 20:59:18 +08:00
//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.
2016-08-23 08:31:50 +08:00
type DspInitializer func ( map [ string ] string , json . RawMessage ) ( DNSServiceProvider , error )
var dspTypes = map [ string ] DspInitializer { }
2017-04-18 05:16:29 +08:00
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.
2017-07-21 03:55:26 +08:00
// If you add something to this list, you probably want to add it to pkg/normalize/validate.go checkProviderCapabilities() or somewhere near there.
2017-04-18 05:16:29 +08:00
CanUseAlias Capability = 1 << iota
// CanUsePTR indicates the provider can handle PTR records
CanUsePTR
2017-07-20 03:53:40 +08:00
// CanUseSRV indicates the provider can handle SRV records
CanUseSRV
2017-07-26 02:59:40 +08:00
// CanUseCAA indicates the provider can handle CAA records
CanUseCAA
2017-08-12 03:43:06 +08:00
// CantUseNOPURGE indicates NO_PURGE is broken for this provider. To make it
// work would require complex emulation of an incremental update mechanism,
// so it is easier to simply mark this feature as not working for this
// provider.
CantUseNOPURGE
2017-04-18 05:16:29 +08:00
)
func ProviderHasCabability ( pType string , cap Capability ) bool {
return dspCapabilities [ pType ] & cap != 0
}
2016-08-23 08:31:50 +08:00
//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.
2017-04-18 05:16:29 +08:00
func RegisterDomainServiceProviderType ( name string , init DspInitializer , caps ... Capability ) {
2016-08-23 08:31:50 +08:00
if _ , ok := dspTypes [ name ] ; ok {
log . Fatalf ( "Cannot register registrar type %s multiple times" , name )
}
2017-04-18 05:16:29 +08:00
var abilities Capability
for _ , c := range caps {
abilities |= c
}
2016-08-23 08:31:50 +08:00
dspTypes [ name ] = init
2017-04-18 05:16:29 +08:00
dspCapabilities [ name ] = abilities
2016-08-23 08:31:50 +08:00
}
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 )
}
2017-03-17 13:42:53 +08:00
func CreateDNSProvider ( dType string , config map [ string ] string , meta json . RawMessage ) ( DNSServiceProvider , error ) {
2016-08-23 08:31:50 +08:00
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" {
2017-06-09 23:57:21 +08:00
return nil , fmt . Errorf ( "Registrar %s not listed in creds.json file." , reg . Name )
2016-08-23 08:31:50 +08:00
}
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 {
2017-03-23 00:38:08 +08:00
vals := providerConfigs [ dsp . Name ]
provider , err := CreateDNSProvider ( dsp . Type , vals , dsp . Metadata )
2016-08-23 08:31:50 +08:00
if err != nil {
return nil , err
}
dsps [ dsp . Name ] = provider
}
return dsps , nil
}
2017-04-27 20:59:18 +08:00
// None is a basic provider type that does absolutely nothing. Can be useful as a placeholder for third parties or unimplemented providers.
2016-08-23 08:31:50 +08:00
type None struct { }
func ( n None ) GetRegistrarCorrections ( dc * models . DomainConfig ) ( [ ] * models . Correction , error ) {
return nil , nil
}
2016-12-17 04:10:27 +08:00
func ( n None ) GetNameservers ( string ) ( [ ] * models . Nameserver , error ) {
return nil , nil
}
2016-08-23 08:31:50 +08:00
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
} )
}
2017-05-20 02:15:57 +08:00
type CustomRType struct {
Name string
Provider string
RealType string
}
// RegisterCustomRecordType registers a record type that is only valid for one provider.
// provider is the registered type of provider this is valid with
// name is the record type as it will appear in the js. (should be something like $PROVIDER_FOO)
// realType is the record type it will be replaced with after validation
func RegisterCustomRecordType ( name , provider , realType string ) {
customRecordTypes [ name ] = & CustomRType { Name : name , Provider : provider , RealType : realType }
}
// GetCustomRecordType returns a registered custom record type, or nil if none
func GetCustomRecordType ( rType string ) * CustomRType {
return customRecordTypes [ rType ]
}
var customRecordTypes = map [ string ] * CustomRType { }