2016-08-23 08:31:50 +08:00
package providers
import (
"encoding/json"
Switch to Go 1.13 error wrapping (#604)
* Replaced errors.Wrap with fmt.Errorf (#589)
* Find: errors\.Wrap\(([^,]+),\s+(["`][^"`]*)(["`])\)
Replace: fmt.Errorf($2: %w$3, $1)
* Replaced errors.Wrapf with fmt.Errorf (#589)
* Find: errors\.Wrapf\(([^,]+),\s+(["`][^"`]*)(["`])\)
Replace: fmt.Errorf($2: %w$3, $1)
* Find: errors\.Wrapf\(([^,]+),\s+(["`][^"`]*)(["`])(,[^)]+)\)
* Replace: fmt.Errorf($2: %w$3$4, $1)
* Replaced errors.Errorf with fmt.Errorf (#589)
* Find: errors\.Errorf
Replace: fmt.Errorf
* Cleaned up remaining imports
* Cleanup
* Regenerate provider support matrix
This was broken by #533 ... and it's now the third time this has been missed.
2020-01-29 00:06:56 +08:00
"fmt"
2016-08-23 08:31:50 +08:00
"log"
2023-05-21 01:21:45 +08:00
"github.com/StackExchange/dnscontrol/v4/models"
2016-08-23 08:31:50 +08:00
)
2018-07-26 00:59:04 +08:00
// Registrar is an interface for a domain registrar. It can return a list of needed corrections to be applied in the future. Implement this only if the provider is a "registrar" (i.e. can update the NS records of the parent to a domain).
2016-08-23 08:31:50 +08:00
type Registrar interface {
2018-02-02 00:45:53 +08:00
models . Registrar
2016-08-23 08:31:50 +08:00
}
2018-07-26 00:59:04 +08:00
// DNSServiceProvider is able to generate a set of corrections that need to be made to correct records for a domain. Implement this only if the provider is a DNS Service Provider (can update records in a DNS zone).
2016-08-23 08:31:50 +08:00
type DNSServiceProvider interface {
2018-02-02 00:45:53 +08:00
models . DNSProvider
2016-08-23 08:31:50 +08:00
}
2023-02-07 20:22:49 +08:00
// ZoneCreator should be implemented by providers that have the ability to create zones
// (used for automatically creating zones if they don't exist)
type ZoneCreator interface {
EnsureZoneExists ( domain string ) error
2017-01-04 04:26:08 +08:00
}
2020-03-11 04:53:17 +08:00
// ZoneLister should be implemented by providers that have the
2020-02-18 21:59:18 +08:00
// ability to list the zones they manage. This facilitates using the
// "get-zones" command for "all" zones.
type ZoneLister interface {
ListZones ( ) ( [ ] string , error )
}
2018-01-10 01:53:16 +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.
2016-08-23 08:31:50 +08:00
type RegistrarInitializer func ( map [ string ] string ) ( Registrar , error )
2018-01-10 01:53:16 +08:00
// RegistrarTypes stores initializer for each registrar.
2017-09-15 04:13:17 +08:00
var RegistrarTypes = map [ string ] RegistrarInitializer { }
2016-08-23 08:31:50 +08:00
2018-01-10 01:53:16 +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 )
2021-03-09 09:14:30 +08:00
// RecordAuditor is a function that verifies that all the records
2022-08-12 05:24:47 +08:00
// are supportable by this provider. It returns a list of errors
// detailing records that this provider can not support.
type RecordAuditor func ( [ ] * models . RecordConfig ) [ ] error
2021-03-08 02:19:22 +08:00
// DspFuncs lists functions registered with a provider.
type DspFuncs struct {
2021-05-05 02:15:31 +08:00
Initializer DspInitializer
2021-03-09 09:14:30 +08:00
RecordAuditor RecordAuditor
2021-03-08 02:19:22 +08:00
}
2018-01-10 01:53:16 +08:00
// DNSProviderTypes stores initializer for each DSP.
2021-03-08 02:19:22 +08:00
var DNSProviderTypes = map [ string ] DspFuncs { }
2016-08-23 08:31:50 +08:00
2018-01-10 01:53:16 +08:00
// RegisterRegistrarType adds a registrar type to the registry by providing a suitable initialization function.
2017-09-15 04:13:17 +08:00
func RegisterRegistrarType ( name string , init RegistrarInitializer , pm ... ProviderMetadata ) {
if _ , ok := RegistrarTypes [ name ] ; ok {
2022-05-09 02:23:45 +08:00
log . Fatalf ( "Cannot register registrar type %q multiple times" , name )
2016-08-23 08:31:50 +08:00
}
2017-09-15 04:13:17 +08:00
RegistrarTypes [ name ] = init
unwrapProviderCapabilities ( name , pm )
2016-08-23 08:31:50 +08:00
}
2018-01-10 01:53:16 +08:00
// RegisterDomainServiceProviderType adds a dsp to the registry with the given initialization function.
2021-03-08 02:19:22 +08:00
func RegisterDomainServiceProviderType ( name string , fns DspFuncs , pm ... ProviderMetadata ) {
2017-09-15 04:13:17 +08:00
if _ , ok := DNSProviderTypes [ name ] ; ok {
2022-05-09 02:23:45 +08:00
log . Fatalf ( "Cannot register registrar type %q multiple times" , name )
2016-08-23 08:31:50 +08:00
}
2021-03-08 02:19:22 +08:00
DNSProviderTypes [ name ] = fns
2017-09-15 04:13:17 +08:00
unwrapProviderCapabilities ( name , pm )
2016-08-23 08:31:50 +08:00
}
2018-02-02 00:45:53 +08:00
// CreateRegistrar initializes a registrar instance from given credentials.
func CreateRegistrar ( rType string , config map [ string ] string ) ( Registrar , error ) {
2022-05-09 02:23:45 +08:00
var err error
rType , err = beCompatible ( rType , config )
if err != nil {
return nil , err
}
2017-09-15 04:13:17 +08:00
initer , ok := RegistrarTypes [ rType ]
2016-08-23 08:31:50 +08:00
if ! ok {
2022-06-13 04:01:08 +08:00
return nil , fmt . Errorf ( "no such registrar type: %q" , rType )
2016-08-23 08:31:50 +08:00
}
return initer ( config )
}
2018-02-02 00:45:53 +08:00
// CreateDNSProvider initializes a dns provider instance from given credentials.
2022-05-09 02:23:45 +08:00
func CreateDNSProvider ( providerTypeName string , config map [ string ] string , meta json . RawMessage ) ( DNSServiceProvider , error ) {
var err error
providerTypeName , err = beCompatible ( providerTypeName , config )
if err != nil {
return nil , err
}
p , ok := DNSProviderTypes [ providerTypeName ]
2016-08-23 08:31:50 +08:00
if ! ok {
2022-06-13 04:01:08 +08:00
return nil , fmt . Errorf ( "no such DNS service provider: %q" , providerTypeName )
2016-08-23 08:31:50 +08:00
}
2021-03-08 02:19:22 +08:00
return p . Initializer ( config , meta )
}
2022-05-09 02:23:45 +08:00
// beCompatible looks up
func beCompatible ( n string , config map [ string ] string ) ( string , error ) {
// Pre 4.0: If n is a placeholder, substitute the TYPE from creds.json.
// 4.0: Require TYPE from creds.json.
ct := config [ "TYPE" ]
// If a placeholder value was specified...
if n == "" || n == "-" {
// But no TYPE exists in creds.json...
if ct == "" {
return "-" , fmt . Errorf ( "creds.json entry missing TYPE field" )
}
// Otherwise, use the value from creds.json.
return ct , nil
}
// Pre 4.0: The user specified the name manually.
// Cross check to detect user-error.
if ct != "" && n != ct {
return "" , fmt . Errorf ( "creds.json entry mismatch: specified=%q TYPE=%q" , n , ct )
}
// Seems like the user did it the right way. Return the original value.
return n , nil
// NB(tlim): My hope is that in 4.0 this entire function will simply be the
// following, but I may be wrong:
//return config["TYPE"], nil
}
2021-03-09 09:14:30 +08:00
// AuditRecords calls the RecordAudit function for a provider.
2022-08-12 05:24:47 +08:00
func AuditRecords ( dType string , rcs models . Records ) [ ] error {
2021-03-08 02:19:22 +08:00
p , ok := DNSProviderTypes [ dType ]
if ! ok {
2022-08-12 05:24:47 +08:00
return [ ] error { fmt . Errorf ( "unknown DNS service provider type: %q" , dType ) }
2021-03-08 02:19:22 +08:00
}
2021-03-09 09:14:30 +08:00
if p . RecordAuditor == nil {
2022-08-12 05:24:47 +08:00
return [ ] error { fmt . Errorf ( "DNS service provider type %q has no RecordAuditor" , dType ) }
2021-03-08 02:19:22 +08:00
}
2021-03-09 09:14:30 +08:00
return p . RecordAuditor ( rcs )
2016-08-23 08:31:50 +08:00
}
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 { }
2018-01-10 01:53:16 +08:00
// GetRegistrarCorrections returns corrections to update registrars.
2016-08-23 08:31:50 +08:00
func ( n None ) GetRegistrarCorrections ( dc * models . DomainConfig ) ( [ ] * models . Correction , error ) {
return nil , nil
}
2018-01-10 01:53:16 +08:00
// GetNameservers returns the current nameservers for a domain.
2016-12-17 04:10:27 +08:00
func ( n None ) GetNameservers ( string ) ( [ ] * models . Nameserver , error ) {
return nil , nil
}
2020-02-18 21:59:18 +08:00
// GetZoneRecords gets the records of a zone and returns them in RecordConfig format.
2023-05-03 01:04:59 +08:00
func ( n None ) GetZoneRecords ( domain string , meta map [ string ] string ) ( models . Records , error ) {
2023-04-15 03:22:23 +08:00
return nil , nil
}
// GetZoneRecordsCorrections gets the records of a zone and returns them in RecordConfig format.
func ( n None ) GetZoneRecordsCorrections ( dc * models . DomainConfig , records models . Records ) ( [ ] * models . Correction , error ) {
return nil , nil
2020-02-18 21:59:18 +08:00
}
2018-01-10 01:53:16 +08:00
// GetDomainCorrections returns corrections to update a domain.
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
2018-01-10 01:53:16 +08:00
// CustomRType stores an rtype that is only valid for this DSP.
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 { }