From 6bf4c373f56109267c9177e99d0ac4e5aaa7b2c5 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Mon, 9 Jun 2025 16:26:53 -0400 Subject: [PATCH 1/2] chore(none) Move provider "none" to its own directory --- providers/msdns/msdnsProvider.go | 2 +- providers/none/api.go | 21 +++++++++++++++++ providers/none/convert.go | 19 +++++++++++++++ providers/none/convert_test.go | 3 +++ providers/none/dnsprovider.go | 13 +++++++++++ providers/none/noneProvider.go | 24 +++++++++++++++++++ providers/none/protocol.go | 8 +++++++ providers/none/registrar.go | 15 ++++++++++++ providers/none/zonecreator.go | 5 ++++ providers/none/zonelister.go | 5 ++++ providers/providers.go | 40 -------------------------------- 11 files changed, 114 insertions(+), 41 deletions(-) create mode 100644 providers/none/api.go create mode 100644 providers/none/convert.go create mode 100644 providers/none/convert_test.go create mode 100644 providers/none/dnsprovider.go create mode 100644 providers/none/noneProvider.go create mode 100644 providers/none/protocol.go create mode 100644 providers/none/registrar.go create mode 100644 providers/none/zonecreator.go create mode 100644 providers/none/zonelister.go diff --git a/providers/msdns/msdnsProvider.go b/providers/msdns/msdnsProvider.go index 57cbd33ebc..ebc675924d 100644 --- a/providers/msdns/msdnsProvider.go +++ b/providers/msdns/msdnsProvider.go @@ -53,7 +53,7 @@ func init() { func newDNS(config map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) { if runtime.GOOS != "windows" { printer.Println("INFO: MSDNS deactivated. Required OS not detected.") - return providers.None{}, nil + return &msdnsProvider{}, nil } var err error diff --git a/providers/none/api.go b/providers/none/api.go new file mode 100644 index 0000000000..585ef1ebaf --- /dev/null +++ b/providers/none/api.go @@ -0,0 +1,21 @@ +package none + +/* + +A front-end to the SDK. + +Use the Facade Pattern to create +a simplified interface to the SDK. + +This isn't needed if the SDK offers the functions you want. + +Rate-limiting and re-try logic should be here. This is the module that should +implement re-trying if the provider replies with a 429 or other "you're going +too fast" or "temporary error, please re-try later) erros. + +Pagination logic. This is the module that should implement any any pagination +logic. The vendor's SDK might return data in pages (typically each reply +includes the next 100 records and you must request additional "pages" of +records. This file is typically where logic to get all pages is implemented. + +*/ diff --git a/providers/none/convert.go b/providers/none/convert.go new file mode 100644 index 0000000000..fb37458c1b --- /dev/null +++ b/providers/none/convert.go @@ -0,0 +1,19 @@ +package none + +//// toRc converts a native record (what is received from the API) to a RecordConfig. +//func toRc(domain string, r theSdkModule.NativeRecordType) (*models.RecordConfig, error) { +//} + +//// toRc converts a RecordConfig to a native record (what is received from the API). +//func toNative(rc *models.RecordConfig) theSdkModule.NativeRecordType { +//} + +/* Or... + +If your provider stores all records at the same label (or label+type) in one type (often called a RecordSet). + +func toRcs(n theSdkModule.NativeRecordSet, origin string) (rcs []*models.RecordConfig, err error) {} + +func toNative(rcs []*models.RecordConfig, origin string) []theSdkModule.NativeRecordSet {} + +*/ diff --git a/providers/none/convert_test.go b/providers/none/convert_test.go new file mode 100644 index 0000000000..0763b44075 --- /dev/null +++ b/providers/none/convert_test.go @@ -0,0 +1,3 @@ +package none + +/* add test cases here */ diff --git a/providers/none/dnsprovider.go b/providers/none/dnsprovider.go new file mode 100644 index 0000000000..ba6dd70896 --- /dev/null +++ b/providers/none/dnsprovider.go @@ -0,0 +1,13 @@ +package none + +import "github.com/StackExchange/dnscontrol/v4/models" + +// 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 +} diff --git a/providers/none/noneProvider.go b/providers/none/noneProvider.go new file mode 100644 index 0000000000..af81f39679 --- /dev/null +++ b/providers/none/noneProvider.go @@ -0,0 +1,24 @@ +package none + +import "github.com/StackExchange/dnscontrol/v4/providers" + +/* +Provider: None + +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{} + +var featuresNone = providers.DocumentationNotes{ + // The default for unlisted capabilities is 'Cannot'. + // See providers/capabilities.go for the entire list of capabilities. + providers.CanConcur: providers.Can(), +} + +func init() { + providers.RegisterRegistrarType("NONE", func(map[string]string) (providers.Registrar, error) { + return None{}, nil + }, featuresNone) +} diff --git a/providers/none/protocol.go b/providers/none/protocol.go new file mode 100644 index 0000000000..3d73c48adb --- /dev/null +++ b/providers/none/protocol.go @@ -0,0 +1,8 @@ +package none + +/* This implements the low-level protocol used for speaking to the API. +You can delete this file if it isn't needed. + +For example if Go didn't include native support for HTTP+REST, we'd implement it here. + +*/ diff --git a/providers/none/registrar.go b/providers/none/registrar.go new file mode 100644 index 0000000000..0f3adf4377 --- /dev/null +++ b/providers/none/registrar.go @@ -0,0 +1,15 @@ +package none + +import "github.com/StackExchange/dnscontrol/v4/models" + +// This file completes the "Registrar" interface. + +// GetNameservers returns the current nameservers for a domain. +func (n None) GetNameservers(string) ([]*models.Nameserver, error) { + return nil, nil +} + +// GetRegistrarCorrections returns corrections to update registrars. +func (n None) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { + return nil, nil +} diff --git a/providers/none/zonecreator.go b/providers/none/zonecreator.go new file mode 100644 index 0000000000..ccd607263d --- /dev/null +++ b/providers/none/zonecreator.go @@ -0,0 +1,5 @@ +package none + +func (n None) EnsureZoneExists(domain string) error { + return nil +} diff --git a/providers/none/zonelister.go b/providers/none/zonelister.go new file mode 100644 index 0000000000..3906c387b0 --- /dev/null +++ b/providers/none/zonelister.go @@ -0,0 +1,5 @@ +package none + +func (n None) ListZones() ([]string, error) { + return nil, nil +} diff --git a/providers/providers.go b/providers/providers.go index b3a4f7ed1b..c653028381 100644 --- a/providers/providers.go +++ b/providers/providers.go @@ -153,46 +153,6 @@ func AuditRecords(dType string, rcs models.Records) []error { 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 From 5d49cdbd527f41f3fe228f2ca822a474a22a616f Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Mon, 9 Jun 2025 17:42:59 -0400 Subject: [PATCH 2/2] wip! --- providers/none/api.go | 7 +++-- providers/none/convert.go | 4 +-- providers/none/dnsprovider.go | 49 ++++++++++++++++++++++++++++++---- providers/none/noneProvider.go | 5 ++++ providers/none/zonecreator.go | 2 ++ providers/none/zonelister.go | 2 ++ 6 files changed, 58 insertions(+), 11 deletions(-) diff --git a/providers/none/api.go b/providers/none/api.go index 585ef1ebaf..8ee2e64f9c 100644 --- a/providers/none/api.go +++ b/providers/none/api.go @@ -4,14 +4,13 @@ package none A front-end to the SDK. -Use the Facade Pattern to create -a simplified interface to the SDK. +Use the Facade Pattern to create a simplified interface to the SDK. -This isn't needed if the SDK offers the functions you want. +This isn't needed if the SDK offers the functions you want. Feel free to delete this file. Rate-limiting and re-try logic should be here. This is the module that should implement re-trying if the provider replies with a 429 or other "you're going -too fast" or "temporary error, please re-try later) erros. +too fast" or "temporary error, please re-try later) errors. Pagination logic. This is the module that should implement any any pagination logic. The vendor's SDK might return data in pages (typically each reply diff --git a/providers/none/convert.go b/providers/none/convert.go index fb37458c1b..c841261d5b 100644 --- a/providers/none/convert.go +++ b/providers/none/convert.go @@ -1,10 +1,10 @@ package none -//// toRc converts a native record (what is received from the API) to a RecordConfig. +// toRc converts a native record (what is received from the API) to a RecordConfig. //func toRc(domain string, r theSdkModule.NativeRecordType) (*models.RecordConfig, error) { //} -//// toRc converts a RecordConfig to a native record (what is received from the API). +// toRc converts a RecordConfig to a native record (what is received from the API). //func toNative(rc *models.RecordConfig) theSdkModule.NativeRecordType { //} diff --git a/providers/none/dnsprovider.go b/providers/none/dnsprovider.go index ba6dd70896..051cf51037 100644 --- a/providers/none/dnsprovider.go +++ b/providers/none/dnsprovider.go @@ -1,13 +1,52 @@ package none -import "github.com/StackExchange/dnscontrol/v4/models" +import ( + "github.com/StackExchange/dnscontrol/v4/models" +) // 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) { + + /* + // if your provider does updates one record at a time... + changes, err := diff2.ByRecord(existing, dc, nil) + + // if your provider does updates on all the records at a set (label+type) at once... + changes, err := diff2.ByRecordSet(existing, dc, nil) + + // if your provider does updates on all the records at a label at once... + changes, err := diff2.ByLabel(existing, dc, nil) + + if err != nil { + return nil, err + } + + var corrections []*models.Correction + + for _, change := range changes { + switch change.Type { + case diff2.REPORT: + corr = change.CreateMessage() + case diff2.CREATE: + corr = change.CreateCorrection(func() error { return c.createRecord(FILL_IN) }) + case diff2.CHANGE: + corr = change.CreateCorrection(func() error { return c.modifyRecord(FILL_IN) }) + case diff2.DELETE: + corr = change.CreateCorrection(func() error { return c.deleteRecord(FILL_IN) }) + default: + panic("unhandled change.TYPE %s", change.Type) + } + + corrections = append(corrections, corr) + } + + return corrections, nil + */ + return nil, 0, nil } -// GetDomainCorrections returns corrections to update a domain. -func (n None) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { - return nil, nil -} +//// GetDomainCorrections returns corrections to update a domain. +//func (n None) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { +//return nil, nil +//} diff --git a/providers/none/noneProvider.go b/providers/none/noneProvider.go index af81f39679..14351f7cef 100644 --- a/providers/none/noneProvider.go +++ b/providers/none/noneProvider.go @@ -9,6 +9,11 @@ None is a basic provider type that does absolutely nothing. Can be useful as a p */ +// None is the struct that is used to hold state for the provider. +// +// This same struct is used for all domains that use this provider. Thus +// per-domain data should be stored as a map[domain]thing and be protected by +// mutexes. type None struct{} var featuresNone = providers.DocumentationNotes{ diff --git a/providers/none/zonecreator.go b/providers/none/zonecreator.go index ccd607263d..26068897ae 100644 --- a/providers/none/zonecreator.go +++ b/providers/none/zonecreator.go @@ -1,5 +1,7 @@ package none +// EnsureZoneExists ensures that the zone exists on the DNS server. It will create it if it does not. +// This is a no-op for the None provider; it pretends that all zones already exist. func (n None) EnsureZoneExists(domain string) error { return nil } diff --git a/providers/none/zonelister.go b/providers/none/zonelister.go index 3906c387b0..a9a2e67673 100644 --- a/providers/none/zonelister.go +++ b/providers/none/zonelister.go @@ -1,5 +1,7 @@ package none +// ListZones returns a list of zones that the None provider manages. +// Since the None provider does not manage any zones, it returns an empty list. func (n None) ListZones() ([]string, error) { return nil, nil }