mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-11-10 09:12:47 +08:00
215 lines
7.5 KiB
Go
215 lines
7.5 KiB
Go
package providers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
|
|
"github.com/StackExchange/dnscontrol/v4/models"
|
|
)
|
|
|
|
// 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).
|
|
type Registrar interface {
|
|
models.Registrar
|
|
}
|
|
|
|
// 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).
|
|
type DNSServiceProvider interface {
|
|
models.DNSProvider
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// ZoneLister should be implemented by providers that have the
|
|
// ability to list the zones they manage. This facilitates using the
|
|
// "get-zones" command for "all" zones.
|
|
type ZoneLister interface {
|
|
ListZones() ([]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)
|
|
|
|
// 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.
|
|
type DspInitializer func(map[string]string, json.RawMessage) (DNSServiceProvider, error)
|
|
|
|
// RecordAuditor is a function that verifies that all the records
|
|
// 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
|
|
|
|
// DspFuncs lists functions registered with a provider.
|
|
type DspFuncs struct {
|
|
Initializer DspInitializer
|
|
RecordAuditor RecordAuditor
|
|
}
|
|
|
|
// DNSProviderTypes stores initializer for each DSP.
|
|
var DNSProviderTypes = map[string]DspFuncs{}
|
|
|
|
// 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 %q multiple times", name)
|
|
}
|
|
RegistrarTypes[name] = init
|
|
unwrapProviderCapabilities(name, pm)
|
|
}
|
|
|
|
// RegisterDomainServiceProviderType adds a dsp to the registry with the given initialization function.
|
|
func RegisterDomainServiceProviderType(name string, fns DspFuncs, pm ...ProviderMetadata) {
|
|
if _, ok := DNSProviderTypes[name]; ok {
|
|
log.Fatalf("Cannot register registrar type %q multiple times", name)
|
|
}
|
|
DNSProviderTypes[name] = fns
|
|
unwrapProviderCapabilities(name, pm)
|
|
}
|
|
|
|
var ProviderMaintainers = map[string]string{}
|
|
|
|
func RegisterMaintainer(
|
|
providerName string,
|
|
gitHubUsername string,
|
|
) {
|
|
ProviderMaintainers[providerName] = gitHubUsername
|
|
}
|
|
|
|
// CreateRegistrar initializes a registrar instance from given credentials.
|
|
func CreateRegistrar(rType string, config map[string]string) (Registrar, error) {
|
|
var err error
|
|
rType, err = beCompatible(rType, config)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
initer, ok := RegistrarTypes[rType]
|
|
if !ok {
|
|
return nil, fmt.Errorf("no such registrar type: %q", rType)
|
|
}
|
|
return initer(config)
|
|
}
|
|
|
|
// CreateDNSProvider initializes a dns provider instance from given credentials.
|
|
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]
|
|
if !ok {
|
|
return nil, fmt.Errorf("no such DNS service provider: %q", providerTypeName)
|
|
}
|
|
return p.Initializer(config, meta)
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// AuditRecords calls the RecordAudit function for a provider.
|
|
func AuditRecords(dType string, rcs models.Records) []error {
|
|
p, ok := DNSProviderTypes[dType]
|
|
if !ok {
|
|
return []error{fmt.Errorf("unknown DNS service provider type: %q", dType)}
|
|
}
|
|
if p.RecordAuditor == nil {
|
|
return []error{fmt.Errorf("DNS service provider type %q has no RecordAuditor", dType)}
|
|
}
|
|
return p.RecordAuditor(rcs)
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// GetZoneRecords gets the records of a zone and returns them in RecordConfig format.
|
|
func (n None) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) {
|
|
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, int, error) {
|
|
return nil, 0, nil
|
|
}
|
|
|
|
// GetDomainCorrections returns corrections to update a domain.
|
|
func (n None) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
var featuresNone = DocumentationNotes{
|
|
// The default for unlisted capabilities is 'Cannot'.
|
|
// See providers/capabilities.go for the entire list of capabilities.
|
|
CanConcur: Can(),
|
|
}
|
|
|
|
func init() {
|
|
RegisterRegistrarType("NONE", func(map[string]string) (Registrar, error) {
|
|
return None{}, nil
|
|
}, featuresNone)
|
|
}
|
|
|
|
// CustomRType stores an rtype that is only valid for this DSP.
|
|
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{}
|