Merge branch 'main' into tlim_puny

This commit is contained in:
Tom Limoncelli 2024-03-28 07:55:29 -04:00
commit 2689cd88bd
23 changed files with 1119 additions and 149 deletions

View file

@ -96,7 +96,7 @@ jobs:
if: github.ref != 'refs/heads/master' && github.ref != 'refs/heads/main'
runs-on: ubuntu-latest
container:
image: golang:1.21
image: golang:1.22
needs:
- integration-test-providers
env:

View file

@ -42,7 +42,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ^1.21
go-version: ^1.22
# Stringer is needed because .goreleaser includes "go generate ./..."
- name: Install stringer

View file

@ -159,9 +159,9 @@ release:
## Deprecation warnings
> [!WARNING]
> - **32-bit binaries will no longer be distributed after September 10, 2023.** There is a proposal to stop shipping 32-bit binaries (packages and containers). If no objections are raised by Sept 10, 2023, new releases will not include them. See https://github.com/StackExchange/dnscontrol/issues/2461 for details.
> - **MSDNS maintainer needed!** Without a new volunteer, this DNS provider will lose support after April 2025. See https://github.com/StackExchange/dnscontrol/issues/2878
> - **Call for new volunteer maintainers for NAMEDOTCOM and SOFTLAYER.** These providers have no maintainer. Maintainers respond to PRs and fix bugs in a timely manner, and try to stay on top of protocol changes.
> - **ACME/Let's Encrypt support is frozen and will be removed after December 31, 2022.** The `get-certs` command (renews certs via Let's Encrypt) has no maintainer. There are other projects that do a better job. If you don't use this feature, please do not start. If you do use this feature, please plan on migrating to something else. See discussion in [issues/1400](https://github.com/StackExchange/dnscontrol/issues/1400)
> - **ACME/Let's Encrypt support is frozen and will be removed without notice between now and April 2025.** It has been unsupported since December 2022. If you don't use this feature, do not start. If you do use this feature, migrate ASAP. See discussion in [issues/1400](https://github.com/StackExchange/dnscontrol/issues/1400)
## Install

View file

@ -158,11 +158,11 @@ DNSControl can be installed via packages for macOS, Linux and Windows, or from s
See [dnscontrol-action](https://github.com/koenrh/dnscontrol-action) or [gacts/install-dnscontrol](https://github.com/gacts/install-dnscontrol).
## Deprecation warnings (updated 2024-02-24)
## Deprecation warnings (updated 2024-03-25)
- **32-bit binaries will no longer be distributed after September 10, 2023.** There is a proposal to stop shipping 32-bit binaries (packages and containers). If no objections are raised by Sept 10, 2023, new releases will not include them. See https://github.com/StackExchange/dnscontrol/issues/2461 for details.
- **MSDNS maintainer needed!** Without a new volunteer, this DNS provider will lose support after April 2025. See https://github.com/StackExchange/dnscontrol/issues/2878
- **Call for new volunteer maintainers for NAMEDOTCOM and SOFTLAYER.** These providers have no maintainer. Maintainers respond to PRs and fix bugs in a timely manner, and try to stay on top of protocol changes.
- **ACME/Let's Encrypt support is frozen and will be removed after December 31, 2022.** The `get-certs` command (renews certs via Let's Encrypt) has no maintainer. There are other projects that do a better job. If you don't use this feature, please do not start. If you do use this feature, please plan on migrating to something else. See discussion in [issues/1400](https://github.com/StackExchange/dnscontrol/issues/1400)
- **ACME/Let's Encrypt support is frozen and will be removed without notice between now and April 2025.** It has been unsupported since December 2022. If you don't use this feature, do not start. If you do use this feature, migrate ASAP. See discussion in [issues/1400](https://github.com/StackExchange/dnscontrol/issues/1400)
## More info at our website

783
commands/ppreviewPush.go Normal file
View file

@ -0,0 +1,783 @@
package commands
import (
"cmp"
"encoding/json"
"fmt"
"os"
"strings"
"sync"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/bindserial"
"github.com/StackExchange/dnscontrol/v4/pkg/credsfile"
"github.com/StackExchange/dnscontrol/v4/pkg/nameservers"
"github.com/StackExchange/dnscontrol/v4/pkg/normalize"
"github.com/StackExchange/dnscontrol/v4/pkg/notifications"
"github.com/StackExchange/dnscontrol/v4/pkg/printer"
"github.com/StackExchange/dnscontrol/v4/pkg/zonerecs"
"github.com/StackExchange/dnscontrol/v4/providers"
"github.com/urfave/cli/v2"
"golang.org/x/exp/slices"
"golang.org/x/net/idna"
)
type zoneCache struct {
cache map[string]*[]string
sync.Mutex
}
var _ = cmd(catMain, func() *cli.Command {
var args PPreviewArgs
return &cli.Command{
Name: "ppreview",
Usage: "read live configuration and identify changes to be made, without applying them",
Action: func(ctx *cli.Context) error {
return exit(PPreview(args))
},
Flags: args.flags(),
}
}())
// PPreviewArgs contains all data/flags needed to run preview, independently of CLI
type PPreviewArgs struct {
GetDNSConfigArgs
GetCredentialsArgs
FilterArgs
Notify bool
WarnChanges bool
ConcurMode string
NoPopulate bool
DePopulate bool
Full bool
}
// ReportItem is a record of corrections for a particular domain/provider/registrar.
//type ReportItem struct {
// Domain string `json:"domain"`
// Corrections int `json:"corrections"`
// Provider string `json:"provider,omitempty"`
// Registrar string `json:"registrar,omitempty"`
//}
func (args *PPreviewArgs) flags() []cli.Flag {
flags := args.GetDNSConfigArgs.flags()
flags = append(flags, args.GetCredentialsArgs.flags()...)
flags = append(flags, args.FilterArgs.flags()...)
flags = append(flags, &cli.BoolFlag{
Name: "notify",
Destination: &args.Notify,
Usage: `set to true to send notifications to configured destinations`,
})
flags = append(flags, &cli.BoolFlag{
Name: "expect-no-changes",
Destination: &args.WarnChanges,
Usage: `set to true for non-zero return code if there are changes`,
})
flags = append(flags, &cli.StringFlag{
Name: "cmode",
Destination: &args.ConcurMode,
Value: "default",
Usage: `Which providers to run concurrently: all, default, none`,
Action: func(c *cli.Context, s string) error {
if !slices.Contains([]string{"all", "default", "none"}, s) {
fmt.Printf("%q is not a valid option for --cmode. Valie are: all, default, none", s)
}
return nil
},
})
flags = append(flags, &cli.BoolFlag{
Name: "no-populate",
Destination: &args.NoPopulate,
Usage: `Do not auto-create zones at the provider`,
})
flags = append(flags, &cli.BoolFlag{
Name: "depopulate",
Destination: &args.NoPopulate,
Usage: `Delete unknown zones at provider (dangerous!)`,
})
flags = append(flags, &cli.BoolFlag{
Name: "full",
Destination: &args.Full,
Usage: `Add headings, providers names, notifications of no changes, etc`,
})
flags = append(flags, &cli.IntFlag{
Name: "reportmax",
Hidden: true,
Usage: `Limit the IGNORE/NO_PURGE report to this many lines (Expermental. Will change in the future.)`,
Action: func(ctx *cli.Context, max int) error {
printer.MaxReport = max
return nil
},
})
flags = append(flags, &cli.Int64Flag{
Name: "bindserial",
Destination: &bindserial.ForcedValue,
Usage: `Force BIND serial numbers to this value (for reproducibility)`,
})
return flags
}
var _ = cmd(catMain, func() *cli.Command {
var args PPushArgs
return &cli.Command{
Name: "ppush",
Usage: "identify changes to be made, and perform them",
Action: func(ctx *cli.Context) error {
return exit(PPush(args))
},
Flags: args.flags(),
}
}())
// PPushArgs contains all data/flags needed to run push, independently of CLI
type PPushArgs struct {
PPreviewArgs
Interactive bool
Report string
}
func (args *PPushArgs) flags() []cli.Flag {
flags := args.PPreviewArgs.flags()
flags = append(flags, &cli.BoolFlag{
Name: "i",
Destination: &args.Interactive,
Usage: "Interactive. Confirm or Exclude each correction before they run",
})
flags = append(flags, &cli.StringFlag{
Name: "report",
Destination: &args.Report,
Usage: `Generate a machine-parseable report of performed corrections.`,
})
return flags
}
// PPreview implements the preview subcommand.
func PPreview(args PPreviewArgs) error {
return prun(args, false, false, printer.DefaultPrinter, "")
}
// PPush implements the push subcommand.
func PPush(args PPushArgs) error {
return prun(args.PPreviewArgs, true, args.Interactive, printer.DefaultPrinter, args.Report)
}
var pobsoleteDiff2FlagUsed = false
// run is the main routine common to preview/push
func prun(args PPreviewArgs, push bool, interactive bool, out printer.CLI, report string) error {
// This is a hack until we have the new printer replacement.
printer.SkinnyReport = !args.Full
fullMode := args.Full
if pobsoleteDiff2FlagUsed {
printer.Println("WARNING: Please remove obsolete --diff2 flag. This will be an error in v5 or later. See https://github.com/StackExchange/dnscontrol/issues/2262")
}
out.PrintfIf(fullMode, "Reading dnsconfig.js or equiv.\n")
cfg, err := GetDNSConfig(args.GetDNSConfigArgs)
if err != nil {
return err
}
out.PrintfIf(fullMode, "Reading creds.json or equiv.\n")
providerConfigs, err := credsfile.LoadProviderConfigs(args.CredsFile)
if err != nil {
return err
}
out.PrintfIf(fullMode, "Creating an in-memory model of 'desired'...\n")
notifier, err := PInitializeProviders(cfg, providerConfigs, args.Notify)
if err != nil {
return err
}
out.PrintfIf(fullMode, "Normalizing and validating 'desired'..\n")
errs := normalize.ValidateAndNormalizeConfig(cfg)
if PrintValidationErrors(errs) {
return fmt.Errorf("exiting due to validation errors")
}
zcache := NewZoneCache()
// Loop over all (or some) zones:
zonesToProcess := whichZonesToProcess(cfg.Domains, args.Domains)
zonesSerial, zonesConcurrent := splitConcurrent(zonesToProcess, args.ConcurMode)
out.PrintfIf(fullMode, "PHASE 1: GATHERING data\n")
var wg sync.WaitGroup
wg.Add(len(zonesConcurrent))
out.Printf("CONCURRENTLY gathering %d zone(s)\n", len(zonesConcurrent))
for _, zone := range optimizeOrder(zonesConcurrent) {
out.PrintfIf(fullMode, "Concurrently gathering: %q\n", zone.Name)
go func(zone *models.DomainConfig, args PPreviewArgs, zcache *zoneCache) {
defer wg.Done()
oneZone(zone, args, zcache)
}(zone, args, zcache)
}
out.Printf("SERIALLY gathering %d zone(s)\n", len(zonesSerial))
for _, zone := range zonesSerial {
out.Printf("Serially Gathering: %q\n", zone.Name)
oneZone(zone, args, zcache)
}
out.PrintfIf(len(zonesConcurrent) > 0, "Waiting for concurrent gathering(s) to complete...")
wg.Wait()
out.PrintfIf(len(zonesConcurrent) > 0, "DONE\n")
// Now we know what to do, print or do the tasks.
out.PrintfIf(fullMode, "PHASE 2: CORRECTIONS\n")
var totalCorrections int
var reportItems []*ReportItem
var anyErrors bool
for _, zone := range zonesToProcess {
out.StartDomain(zone.GetUniqueName())
providersToProcess := whichProvidersToProcess(zone.DNSProviderInstances, args.Providers)
for _, provider := range zone.DNSProviderInstances {
skip := skipProvider(provider.Name, providersToProcess)
out.StartDNSProvider(provider.Name, skip)
if !skip {
corrections := zone.GetCorrections(provider.Name)
totalCorrections += len(corrections)
reportItems = append(reportItems, genReportItem(zone.Name, corrections, provider.Name))
anyErrors = cmp.Or(anyErrors, pprintOrRunCorrections(zone.Name, provider.Name, corrections, out, push, interactive, notifier, report))
out.EndProvider(provider.Name, len(corrections), nil)
}
}
skip := skipProvider(zone.RegistrarInstance.Name, providersToProcess)
out.StartRegistrar(zone.RegistrarName, !skip)
if skip {
corrections := zone.GetCorrections(zone.RegistrarInstance.Name)
totalCorrections += len(corrections)
reportItems = append(reportItems, genReportItem(zone.Name, corrections, zone.RegistrarName))
anyErrors = cmp.Or(anyErrors, pprintOrRunCorrections(zone.Name, zone.RegistrarInstance.Name, corrections, out, push, interactive, notifier, report))
out.EndProvider(zone.RegistrarName, len(corrections), nil)
}
}
if os.Getenv("TEAMCITY_VERSION") != "" {
fmt.Fprintf(os.Stderr, "##teamcity[buildStatus status='SUCCESS' text='%d corrections']", totalCorrections)
}
notifier.Done()
out.Printf("Done. %d corrections.\n", totalCorrections)
err = writeReport(report, reportItems)
if err != nil {
return fmt.Errorf("could not write report")
}
if anyErrors {
return fmt.Errorf("completed with errors")
}
if totalCorrections != 0 && args.WarnChanges {
return fmt.Errorf("there are pending changes")
}
return nil
}
func whichZonesToProcess(domains []*models.DomainConfig, filter string) []*models.DomainConfig {
if filter == "" || filter == "all" {
return domains
}
permitList := strings.Split(filter, ",")
var picked []*models.DomainConfig
for _, domain := range domains {
if domainInList(domain.Name, permitList) {
picked = append(picked, domain)
}
}
return picked
}
// splitConcurrent takes a list of DomainConfigs and returns two lists. The
// first list is the items that do NOT support concurrency. The second is list
// the items that DO support concurrency.
func splitConcurrent(domains []*models.DomainConfig, filter string) (serial []*models.DomainConfig, concurrent []*models.DomainConfig) {
if filter == "none" {
return domains, nil
} else if filter == "all" {
return nil, domains
}
for _, dc := range domains {
if allConcur(dc) {
concurrent = append(concurrent, dc)
} else {
serial = append(serial, dc)
}
}
return
}
// allConcur returns true if its registrar and all DNS providers support
// concurrency. Otherwise false is returned.
func allConcur(dc *models.DomainConfig) bool {
if !providers.ProviderHasCapability(dc.RegistrarInstance.ProviderType, providers.CanConcur) {
//fmt.Printf("WHY? %q: %+v\n", dc.Name, dc.RegistrarInstance)
return false
}
for _, p := range dc.DNSProviderInstances {
if !providers.ProviderHasCapability(p.ProviderType, providers.CanConcur) {
//fmt.Printf("WHY? %q: %+v\n", dc.Name, p)
return false
}
}
return true
}
// optimizeOrder returns a list of DomainConfigs so that they gather fastest.
//
// The current algorithm is based on the heuistic that larger zones (zones with
// the most records) need the most time to be processed. Therefore, the largest
// zones are moved to the front of the list.
// This isn't perfect but it is good enough.
func optimizeOrder(zones []*models.DomainConfig) []*models.DomainConfig {
slices.SortFunc(zones, func(a, b *models.DomainConfig) int {
return len(b.Records) - len(a.Records) // Biggest to smallest.
})
// // For benchmarking. Randomize the list. If you aren't better
// // than random, you might as well not play.
// rand.Shuffle(len(zones), func(i, j int) {
// zones[i], zones[j] = zones[j], zones[i]
// })
return zones
}
func oneZone(zone *models.DomainConfig, args PPreviewArgs, zc *zoneCache) {
// Fix the parent zone's delegation: (if able/needed)
//zone.NameserversMutex.Lock()
delegationCorrections := generateDelegationCorrections(zone, zone.DNSProviderInstances, zone.RegistrarInstance)
//zone.NameserversMutex.Unlock()
// Loop over the (selected) providers configured for that zone:
providersToProcess := whichProvidersToProcess(zone.DNSProviderInstances, args.Providers)
for _, provider := range providersToProcess {
// Populate the zones at the provider (if desired/needed/able):
if !args.NoPopulate {
populateCorrections := generatePopulateCorrections(provider, zone.Name, zc)
zone.StoreCorrections(provider.Name, populateCorrections)
}
// Update the zone's records at the provider:
zoneCor, rep := generateZoneCorrections(zone, provider)
zone.StoreCorrections(provider.Name, rep)
zone.StoreCorrections(provider.Name, zoneCor)
}
// Do the delegation corrections after the zones are updated.
zone.StoreCorrections(zone.RegistrarInstance.Name, delegationCorrections)
}
func whichProvidersToProcess(providers []*models.DNSProviderInstance, filter string) []*models.DNSProviderInstance {
if filter == "all" { // all
return providers
}
permitList := strings.Split(filter, ",")
var picked []*models.DNSProviderInstance
// Just the default providers:
if filter == "" {
for _, provider := range providers {
if provider.IsDefault {
picked = append(picked, provider)
}
}
return picked
}
// Just the exact matches:
for _, provider := range providers {
for _, filterItem := range permitList {
if provider.Name == filterItem {
picked = append(picked, provider)
}
}
}
return picked
}
func skipProvider(name string, providers []*models.DNSProviderInstance) bool {
return !slices.ContainsFunc(providers, func(p *models.DNSProviderInstance) bool {
return p.Name == name
})
}
func genReportItem(zname string, corrections []*models.Correction, pname string) *ReportItem {
// Only count the actions, not the messages.
cnt := 0
for _, cor := range corrections {
if cor.F != nil {
cnt++
}
}
r := ReportItem{
Domain: zname,
Corrections: cnt,
Provider: pname,
}
return &r
}
func pprintOrRunCorrections(zoneName string, providerName string, corrections []*models.Correction, out printer.CLI, push bool, interactive bool, notifier notifications.Notifier, report string) bool {
if len(corrections) == 0 {
return false
}
var anyErrors bool
for i, correction := range corrections {
out.PrintCorrection(i, correction)
var err error
if push {
if interactive && !out.PromptToRun() {
continue
}
if correction.F != nil {
err = correction.F()
if err != nil {
anyErrors = true
}
}
out.EndCorrection(err)
}
notifier.Notify(zoneName, providerName, correction.Msg, err, !push)
}
_ = report // File name to write report to.
return anyErrors
}
func writeReport(report string, reportItems []*ReportItem) error {
// No filename? No report.
if report == "" {
return nil
}
f, err := os.OpenFile(report, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
if err != nil {
return err
}
defer f.Close()
b, err := json.MarshalIndent(reportItems, "", " ")
if err != nil {
return err
}
if _, err := f.Write(b); err != nil {
return err
}
return nil
}
func generatePopulateCorrections(provider *models.DNSProviderInstance, zoneName string, zcache *zoneCache) []*models.Correction {
lister, ok := provider.Driver.(providers.ZoneLister)
if !ok {
return nil // We can't generate a list. No corrections are possible.
}
z, err := zcache.zoneList(provider.Name, lister)
if err != nil {
return []*models.Correction{{Msg: fmt.Sprintf("zoneList failed for %q: %s", provider.Name, err)}}
}
zones := *z
aceZoneName, _ := idna.ToASCII(zoneName)
if slices.Contains(zones, aceZoneName) {
return nil // zone exists. Nothing to do.
}
creator, ok := provider.Driver.(providers.ZoneCreator)
if !ok {
return []*models.Correction{{Msg: fmt.Sprintf("Zone %q does not exist. Can not create because %q does not implement ZoneCreator", aceZoneName, provider.Name)}}
}
return []*models.Correction{{
Msg: fmt.Sprintf("Create zone '%s' in the '%s' profile", aceZoneName, provider.Name),
F: func() error { return creator.EnsureZoneExists(aceZoneName) },
}}
}
func generateZoneCorrections(zone *models.DomainConfig, provider *models.DNSProviderInstance) ([]*models.Correction, []*models.Correction) {
reports, zoneCorrections, err := zonerecs.CorrectZoneRecords(provider.Driver, zone)
if err != nil {
return []*models.Correction{{Msg: fmt.Sprintf("Domain %q provider %s Error: %s", zone.Name, provider.Name, err)}}, nil
}
return zoneCorrections, reports
}
func generateDelegationCorrections(zone *models.DomainConfig, providers []*models.DNSProviderInstance, _ *models.RegistrarInstance) []*models.Correction {
//fmt.Printf("DEBUG: generateDelegationCorrections start zone=%q nsList = %v\n", zone.Name, zone.Nameservers)
nsList, err := nameservers.DetermineNameserversForProviders(zone, providers, true)
if err != nil {
return msg(fmt.Sprintf("DtermineNS: zone %q; Error: %s", zone.Name, err))
}
zone.Nameservers = nsList
nameservers.AddNSRecords(zone)
if len(zone.Nameservers) == 0 && zone.Metadata["no_ns"] != "true" {
return []*models.Correction{{Msg: fmt.Sprintf("No nameservers declared for domain %q; skipping registrar. Add {no_ns:'true'} to force", zone.Name)}}
}
corrections, err := zone.RegistrarInstance.Driver.GetRegistrarCorrections(zone)
if err != nil {
return msg(fmt.Sprintf("zone %q; Rprovider %q; Error: %s", zone.Name, zone.RegistrarInstance.Name, err))
}
return corrections
}
func msg(s string) []*models.Correction {
return []*models.Correction{{Msg: s}}
}
// PInitializeProviders takes (fully processed) configuration and instantiates all providers and returns them.
func PInitializeProviders(cfg *models.DNSConfig, providerConfigs map[string]map[string]string, notifyFlag bool) (notify notifications.Notifier, err error) {
var notificationCfg map[string]string
defer func() {
notify = notifications.Init(notificationCfg)
}()
if notifyFlag {
notificationCfg = providerConfigs["notifications"]
}
isNonDefault := map[string]bool{}
for name, vals := range providerConfigs {
// add "_exclude_from_defaults":"true" to a provider to exclude it from being run unless
// -providers=all or -providers=name
if vals["_exclude_from_defaults"] == "true" {
isNonDefault[name] = true
}
}
// Populate provider type ids based on values from creds.json:
msgs, err := ppopulateProviderTypes(cfg, providerConfigs)
if len(msgs) != 0 {
fmt.Fprintln(os.Stderr, strings.Join(msgs, "\n"))
}
if err != nil {
return
}
registrars := map[string]providers.Registrar{}
dnsProviders := map[string]providers.DNSServiceProvider{}
for _, d := range cfg.Domains {
if registrars[d.RegistrarName] == nil {
rCfg := cfg.RegistrarsByName[d.RegistrarName]
r, err := providers.CreateRegistrar(rCfg.Type, providerConfigs[d.RegistrarName])
if err != nil {
return nil, err
}
registrars[d.RegistrarName] = r
}
d.RegistrarInstance.Driver = registrars[d.RegistrarName]
d.RegistrarInstance.IsDefault = !isNonDefault[d.RegistrarName]
for _, pInst := range d.DNSProviderInstances {
if dnsProviders[pInst.Name] == nil {
dCfg := cfg.DNSProvidersByName[pInst.Name]
prov, err := providers.CreateDNSProvider(dCfg.Type, providerConfigs[dCfg.Name], dCfg.Metadata)
if err != nil {
return nil, err
}
dnsProviders[pInst.Name] = prov
}
pInst.Driver = dnsProviders[pInst.Name]
pInst.IsDefault = !isNonDefault[pInst.Name]
}
}
return
}
// pproviderTypeFieldName is the name of the field in creds.json that specifies the provider type id.
const pproviderTypeFieldName = "TYPE"
// ppurl is the documentation URL to list in the warnings related to missing provider type ids.
const purl = "https://docs.dnscontrol.org/commands/creds-json"
// ppopulateProviderTypes scans a DNSConfig for blank provider types and fills them in based on providerConfigs.
// That is, if the provider type is "-" or "", we take that as an flag
// that means this value should be replaced by the type found in creds.json.
func ppopulateProviderTypes(cfg *models.DNSConfig, providerConfigs map[string]map[string]string) ([]string, error) {
var msgs []string
for i := range cfg.Registrars {
pType := cfg.Registrars[i].Type
pName := cfg.Registrars[i].Name
nt, warnMsg, err := prefineProviderType(pName, pType, providerConfigs[pName], "NewRegistrar")
cfg.Registrars[i].Type = nt
if warnMsg != "" {
msgs = append(msgs, warnMsg)
}
if err != nil {
return msgs, err
}
}
for i := range cfg.DNSProviders {
pName := cfg.DNSProviders[i].Name
pType := cfg.DNSProviders[i].Type
nt, warnMsg, err := prefineProviderType(pName, pType, providerConfigs[pName], "NewDnsProvider")
cfg.DNSProviders[i].Type = nt
if warnMsg != "" {
msgs = append(msgs, warnMsg)
}
if err != nil {
return msgs, err
}
}
// Update these fields set by
// commands/commands.go:preloadProviders().
// This is probably a layering violation. That said, the
// fundamental problem here is that we're storing the provider
// instances by string name, not by a pointer to a struct. We
// should clean that up someday.
for _, domain := range cfg.Domains { // For each domain..
for _, provider := range domain.DNSProviderInstances { // For each provider...
pName := provider.ProviderBase.Name
pType := provider.ProviderBase.ProviderType
nt, warnMsg, err := prefineProviderType(pName, pType, providerConfigs[pName], "NewDnsProvider")
provider.ProviderBase.ProviderType = nt
if warnMsg != "" {
msgs = append(msgs, warnMsg)
}
if err != nil {
return msgs, err
}
}
p := domain.RegistrarInstance
pName := p.Name
pType := p.ProviderType
nt, warnMsg, err := prefineProviderType(pName, pType, providerConfigs[pName], "NewRegistrar")
p.ProviderType = nt
if warnMsg != "" {
msgs = append(msgs, warnMsg)
}
if err != nil {
return msgs, err
}
}
return puniqueStrings(msgs), nil
}
// puniqueStrings takes an unsorted slice of strings and returns the
// unique strings, in the order they first appeared in the list.
func puniqueStrings(stringSlice []string) []string {
keys := make(map[string]bool)
list := []string{}
for _, entry := range stringSlice {
if _, ok := keys[entry]; !ok {
keys[entry] = true
list = append(list, entry)
}
}
return list
}
func prefineProviderType(credEntryName string, t string, credFields map[string]string, source string) (replacementType string, warnMsg string, err error) {
// t="" and t="-" are processed the same. Standardize on "-" to reduce the number of cases to check.
if t == "" {
t = "-"
}
// Use cases:
//
// type credsType
// ---- ---------
// - or "" GANDI lookup worked. Nothing to say.
// - or "" - or "" ERROR "creds.json has invalid or missing data"
// GANDI "" WARNING "Working but.... Please fix as follows..."
// GANDI GANDI INFO "working but unneeded: clean up as follows..."
// GANDI NAMEDOT ERROR "error mismatched: please fix as follows..."
// ERROR: Invalid.
// WARNING: Required change to remain compatible with 4.0
// INFO: Post-4.0 cleanups or other non-required changes.
if t != "-" {
// Old-style, dnsconfig.js specifies the type explicitly.
// This is supported but we suggest updates for future compatibility.
// If credFields is nil, that means there was no entry in creds.json:
if credFields == nil {
// Warn the user to update creds.json in preparation for 4.0:
// In 4.0 this should be an error. We could default to a
// provider such as "NONE" but I suspect it would be confusing
// to users to see references to a provider name that they did
// not specify.
return t, fmt.Sprintf(`WARNING: For future compatibility, add this entry creds.json: %q: { %q: %q }, (See %s#missing)`,
credEntryName, pproviderTypeFieldName, t,
purl,
), nil
}
switch ct := credFields[pproviderTypeFieldName]; ct {
case "":
// Warn the user to update creds.json in preparation for 4.0:
// In 4.0 this should be an error.
return t, fmt.Sprintf(`WARNING: For future compatibility, update the %q entry in creds.json by adding: %q: %q, (See %s#missing)`,
credEntryName,
pproviderTypeFieldName, t,
purl,
), nil
case "-":
// This should never happen. The user is specifying "-" in a place that it shouldn't be used.
return "-", "", fmt.Errorf(`ERROR: creds.json entry %q has invalid %q value %q (See %s#hyphen)`,
credEntryName, pproviderTypeFieldName, ct,
purl,
)
case t:
// creds.json file is compatible with and dnsconfig.js can be updated.
return ct, fmt.Sprintf(`INFO: In dnsconfig.js %s(%q, %q) can be simplified to %s(%q) (See %s#cleanup)`,
source, credEntryName, t,
source, credEntryName,
purl,
), nil
default:
// creds.json lists a TYPE but it doesn't match what's in dnsconfig.js!
return t, "", fmt.Errorf(`ERROR: Mismatch found! creds.json entry %q has %q set to %q but dnsconfig.js specifies %s(%q, %q) (See %s#mismatch)`,
credEntryName,
pproviderTypeFieldName, ct,
source, credEntryName, t,
purl,
)
}
}
// t == "-"
// New-style, dnsconfig.js does not specify the type (t == "") or a
// command line tool accepted "-" as a positional argument for
// backwards compatibility.
// If credFields is nil, that means there was no entry in creds.json:
if credFields == nil {
return "", "", fmt.Errorf(`ERROR: creds.json is missing an entry called %q. Suggestion: %q: { %q: %q }, (See %s#missing)`,
credEntryName,
credEntryName, pproviderTypeFieldName, "FILL_IN_PROVIDER_TYPE",
purl,
)
}
// New-style, dnsconfig.js doesn't specifies the type. It will be
// looked up in creds.json.
switch ct := credFields[pproviderTypeFieldName]; ct {
case "":
return ct, "", fmt.Errorf(`ERROR: creds.json entry %q is missing: %q: %q, (See %s#fixcreds)`,
credEntryName,
pproviderTypeFieldName, "FILL_IN_PROVIDER_TYPE",
purl,
)
case "-":
// This should never happen. The user is confused and specified "-" in the wrong place!
return "-", "", fmt.Errorf(`ERROR: creds.json entry %q has invalid %q value %q (See %s#hyphen)`,
credEntryName,
pproviderTypeFieldName, ct,
purl,
)
default:
// use the value in creds.json (this should be the normal case)
return ct, "", nil
}
}

View file

@ -230,7 +230,7 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI, report
// Correct the registrar...
nsList, err := nameservers.DetermineNameserversForProviders(domain, providersWithExistingZone)
nsList, err := nameservers.DetermineNameserversForProviders(domain, providersWithExistingZone, false)
if err != nil {
out.Errorf("ERROR: %s\n", err.Error())
return

27
commands/zonecache.go Normal file
View file

@ -0,0 +1,27 @@
package commands
import "github.com/StackExchange/dnscontrol/v4/providers"
func NewZoneCache() *zoneCache {
return &zoneCache{}
}
func (zc *zoneCache) zoneList(name string, lister providers.ZoneLister) (*[]string, error) {
zc.Lock()
defer zc.Unlock()
if zc.cache == nil {
zc.cache = map[string]*[]string{}
}
if v, ok := zc.cache[name]; ok {
return v, nil
}
zones, err := lister.ListZones()
if err != nil {
return nil, err
}
zc.cache[name] = &zones
return &zones, nil
}

View file

@ -8,7 +8,6 @@
* [Examples](examples.md)
* [Migrating zones to DNSControl](migrating.md)
* [TypeScript autocomplete and type checking](typescript.md)
* [Disabling Colors](colors.md)
## Language Reference
@ -150,10 +149,14 @@
## Commands
* [creds.json](creds-json.md)
* [preview/push](preview-push.md)
* [check-creds](check-creds.md)
* [get-certs](get-certs.md)
* [get-zones](get-zones.md)
* [get-certs](get-certs.md)
* [fmt](fmt.md)
* [creds.json](creds-json.md)
* [Global Flag](globalflags.md)
* [Disabling Colors](colors.md)
## Advanced features

View file

@ -0,0 +1,100 @@
# preview/push
`preview` reads the dnsconfig.js file (or equivalent), determines what changes are to be made, and
prints them. `push` is the same but executes the changes.
```shell
NAME:
dnscontrol preview - read live configuration and identify changes to be made, without applying them
USAGE:
dnscontrol preview [command options] [arguments...]
CATEGORY:
main
OPTIONS:
--config value File containing dns config in javascript DSL (default: "dnsconfig.js")
--dev Use helpers.js from disk instead of embedded copy (default: false)
--variable value, -v value [ --variable value, -v value ] Add variable that is passed to JS
--ir value Read IR (json) directly from this file. Do not process DSL at all
--creds value Provider credentials JSON file (or !program to execute program that outputs json) (default: "creds.json")
--providers value Providers to enable (comma separated list); default is all. Can exclude individual providers from default by adding '"_exclude_from_defaults": "true"' to the credentials file for a provider
--domains value Comma separated list of domain names to include
--notify set to true to send notifications to configured destinations (default: false)
--expect-no-changes set to true for non-zero return code if there are changes (default: false)
--no-populate Use this flag to not auto-create non-existing zones at the provider (default: false)
--full Add headings, providers names, notifications of no changes, etc (default: false)
--bindserial value Force BIND serial numbers to this value (for reproducibility) (default: 0)
--report value (push) Generate a JSON-formatted report of the number of changes made.
--help, -h show help
```
`--config name` -- Specifies the name of the main configuration file, normally
`dnsconfig.js`.
`--dev` -- Developer mode. Normally `helpers.js` is embedded in the dnscontrol
executable. With this flag, the local file `helpers.js` is read instead.
`--v foo=bar` -- Sets the variable `foo` to the value `bar` prior to
interpreting the configuration file. Multiple `-v` options can be used.
`--creds name` -- Specifies the name of the credentials file, normally
`creds.json`. Typically the file is read. If the executable bit is set, the
file is executed and the output is used as the configuration. (That feature may
or may not work on Windows.) If the filename begins with a `|` (for example:
`|runme.sh`) the `|` is removed and the remaining string is used as the name of
the program.
`--providers name,name2` -- Specifies a comma-separated list of providers to
enable. The default is all providers. A provider can opt out of being in the
default list by `"_exclude_from_defaults": "true"` to the credentials entry for
that provider. In that case, the provider will only be activated if it is
included in `--providers`.
`--domains value` -- Specifies a comma-separated list of domains to include.
Typically all domains are included in `preview`/`push`. Wildcards are not
permitted except `*` at the start of the entry. For example, `--domains
example.com,*.in-addr.arpa` would include `example.com` plus all reverse lookup
domains.
`--notify` -- Enables sending notifications to the destinations configured in
`creds.json`.
`--expect-no-changes` -- If set, a non-zero exit code is returned if there are
changes. Normally DNSControl sets the exit code based on whether or not there
were protocol errors or other reasons the program can not continue. With this
flag set, the exit code indicates if any changes were required. This is
typically used with `preview` to allow scripts to determine if changes would
happen if `push` was used. For example, one might want to run `dnscontrol
preview --expect-no-changes` daily to determine if changes have been made to
a domain outside of DNSControl.
`--no-populate` -- Do not auto-create non-existing zones at the provider.
Normally non-existent zones are automatically created at a provider (unless the
provider does not implement zone creation). This flag disables that feature.
`--full` -- Add headings, providers names, notifications of no changes, etc. to
the output. Normally the output of `preview`/`push` is extremely brief. This
makes the output more verbose. Useful for debugging.
`--bindserial value` -- Force BIND serial numbers to this value. Normally the
BIND provider generates SOA serial numbers automatically. This flag forces the
serial number generator to output the value specified for all domains. This is
generally used for reproducibility in testing pipelines.
`--report name` -- (`push` only!) Generate a machine-parseable report of
performed corrections in the file named `name`. If no name is specified, no
report is generated.
## Experimental
The `ppreview`/`ppush` subcommands are a preview of a future feature where zone
data is gathered concurrently. The commands will go away when
they replace the existing `preview`/`push` commands.
`--cmode value` -- Concurrency mode. Specifies what kind of providers should be run concurrently. This flag onl
* `default` -- Providers are run sequentially or concurrently depending on whether the provider is marked as having been tested to run concurrently.
* `none` -- All providers are run sequentially. This is the safest mode. It can be used if a concurrency bug is discovered.
* `all` -- This is unsafe. It runs all providers concurrently, even the ones that have not be validated to run concurrently. It is generally only used for demonstrating bugs.

View file

@ -17,13 +17,13 @@ If a feature is definitively not supported for whatever reason, we would also li
| [`AKAMAIEDGEDNS`](providers/akamaiedgedns.md) | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❔ | ✅ | ✅ | ✅ |
| [`AUTODNS`](providers/autodns.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ✅ | ❔ | ❔ | ❔ | ❌ | ❔ | ✅ | ❌ | ❌ | ❌ | ❔ | ❌ | ❌ | ✅ |
| [`AXFRDDNS`](providers/axfrddns.md) | ❌ | ✅ | ❌ | ❌ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ✅ | ❌ | ❌ | ❌ |
| [`AZURE_DNS`](providers/azure_dns.md) | ✅ | ✅ | ❌ | | ❌ | ✅ | ❔ | ❌ | ❌ | ✅ | ❔ | ✅ | ❌ | ❌ | ❔ | ❔ | ✅ | ✅ | ✅ |
| [`AZURE_DNS`](providers/azure_dns.md) | ✅ | ✅ | ❌ | | ❌ | ✅ | ❔ | ❌ | ❌ | ✅ | ❔ | ✅ | ❌ | ❌ | ❔ | ❔ | ✅ | ✅ | ✅ |
| [`AZURE_PRIVATE_DNS`](providers/azure_private_dns.md) | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❔ | ❌ | ❌ | ✅ | ❔ | ✅ | ❌ | ❌ | ❔ | ❔ | ✅ | ✅ | ✅ |
| [`BIND`](providers/bind.md) | ✅ | ✅ | ❌ | ❌ | ❔ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| [`BUNNY_DNS`](providers/bunny_dns.md) | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ |
| [`CLOUDFLAREAPI`](providers/cloudflareapi.md) | ✅ | ✅ | ❌ | | ✅ | ✅ | ❔ | ❌ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ❔ | ❌ | ✅ | ✅ |
| [`CLOUDFLAREAPI`](providers/cloudflareapi.md) | ✅ | ✅ | ❌ | | ✅ | ✅ | ❔ | ❌ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ❔ | ❌ | ✅ | ✅ |
| [`CLOUDNS`](providers/cloudns.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ❔ | ❔ | ✅ | ✅ |
| [`CSCGLOBAL`](providers/cscglobal.md) | ✅ | ✅ | ✅ | | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ❔ | ❌ | ✅ |
| [`CSCGLOBAL`](providers/cscglobal.md) | ✅ | ✅ | ✅ | | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ❔ | ❌ | ✅ |
| [`DESEC`](providers/desec.md) | ❌ | ✅ | ❌ | ❌ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | ✅ | ✅ |
| [`DIGITALOCEAN`](providers/digitalocean.md) | ❌ | ✅ | ❌ | ❌ | ❔ | ✅ | ❔ | ❌ | ❔ | ❔ | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ❔ | ✅ | ✅ |
| [`DNSIMPLE`](providers/dnsimple.md) | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❔ | ✅ | ✅ | ❌ | ❌ | ❔ | ❌ | ❌ | ✅ |
@ -34,7 +34,7 @@ If a feature is definitively not supported for whatever reason, we would also li
| [`EASYNAME`](providers/easyname.md) | ❌ | ❌ | ✅ | ❌ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❌ | ❔ |
| [`EXOSCALE`](providers/exoscale.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ❔ | ❌ | ❔ | ❔ | ❌ | ❌ | ❔ |
| [`GANDI_V5`](providers/gandi_v5.md) | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ✅ | ✅ | ❌ | ❔ | ❔ | ❌ | ✅ |
| [`GCLOUD`](providers/gcloud.md) | ✅ | ✅ | ❌ | | ✅ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ❔ | ✅ | ✅ | ✅ |
| [`GCLOUD`](providers/gcloud.md) | ✅ | ✅ | ❌ | | ✅ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ❔ | ✅ | ✅ | ✅ |
| [`GCORE`](providers/gcore.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❔ | ✅ | ❌ | ❌ | ❌ | ❔ | ✅ | ✅ | ✅ |
| [`HEDNS`](providers/hedns.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❔ | ✅ | ✅ | ✅ |
| [`HETZNER`](providers/hetzner.md) | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ |
@ -59,7 +59,7 @@ If a feature is definitively not supported for whatever reason, we would also li
| [`PORKBUN`](providers/porkbun.md) | ❌ | ✅ | ✅ | ❌ | ✅ | ❔ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ❔ | ❌ | ❌ | ✅ |
| [`POWERDNS`](providers/powerdns.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ |
| [`REALTIMEREGISTER`](providers/realtimeregister.md) | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ |
| [`ROUTE53`](providers/route53.md) | ✅ | ✅ | ✅ | | ❌ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ✅ | ✅ | ✅ |
| [`ROUTE53`](providers/route53.md) | ✅ | ✅ | ✅ | | ❌ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ✅ | ✅ | ✅ |
| [`RWTH`](providers/rwth.md) | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ❔ | ❌ | ❌ | ✅ | ❔ | ✅ | ✅ | ❌ | ❔ | ❔ | ❌ | ❌ | ✅ |
| [`SOFTLAYER`](providers/softlayer.md) | ❌ | ✅ | ❌ | ❌ | ❔ | ❔ | ❔ | ❌ | ❔ | ❔ | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ❔ | ❌ | ❔ |
| [`TRANSIP`](providers/transip.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ | ❔ | ❔ | ✅ | ✅ | ✅ | ❌ | ❔ | ❔ | ❌ | ✅ |

50
go.mod
View file

@ -1,8 +1,6 @@
module github.com/StackExchange/dnscontrol/v4
go 1.21
toolchain go1.21.1
go 1.22.1
retract v4.8.0
@ -20,16 +18,16 @@ require (
github.com/TomOnTime/utfutil v0.0.0-20230223141146-125e65197b36
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883
github.com/aws/aws-sdk-go-v2 v1.25.3
github.com/aws/aws-sdk-go-v2/config v1.27.7
github.com/aws/aws-sdk-go-v2/credentials v1.17.7
github.com/aws/aws-sdk-go-v2/service/route53 v1.40.2
github.com/aws/aws-sdk-go-v2/service/route53domains v1.23.2
github.com/aws/aws-sdk-go-v2 v1.26.0
github.com/aws/aws-sdk-go-v2/config v1.27.9
github.com/aws/aws-sdk-go-v2/credentials v1.17.9
github.com/aws/aws-sdk-go-v2/service/route53 v1.40.3
github.com/aws/aws-sdk-go-v2/service/route53domains v1.23.3
github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6
github.com/billputer/go-namecheap v0.0.0-20210108011502-994a912fb7f9
github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.6
github.com/cloudflare/cloudflare-go v0.89.0
github.com/digitalocean/godo v1.109.0
github.com/cloudflare/cloudflare-go v0.91.0
github.com/digitalocean/godo v1.110.0
github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c
github.com/dnsimple/dnsimple-go v1.5.1
github.com/exoscale/egoscale v0.90.2
@ -37,7 +35,7 @@ require (
github.com/go-gandi/go-gandi v0.7.0
github.com/gobwas/glob v0.2.4-0.20181002190808-e7a84e9525fe
github.com/gopherjs/jquery v0.0.0-20191017083323-73f4c7416038
github.com/hashicorp/vault/api v1.12.0
github.com/hashicorp/vault/api v1.12.2
github.com/jinzhu/copier v0.4.0
github.com/miekg/dns v1.1.58
github.com/mittwald/go-powerdns v0.6.2
@ -58,7 +56,7 @@ require (
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/net v0.22.0
golang.org/x/oauth2 v0.18.0
google.golang.org/api v0.169.0
google.golang.org/api v0.171.0
gopkg.in/ns1/ns1-go.v2 v2.7.11
)
@ -73,7 +71,7 @@ require (
github.com/kylelemons/godebug v1.1.0
github.com/mattn/go-isatty v0.0.20
github.com/vultr/govultr/v2 v2.17.2
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225
golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81
golang.org/x/text v0.14.0
gopkg.in/yaml.v3 v3.0.1
)
@ -85,15 +83,15 @@ require (
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 // indirect
github.com/andybalholm/cascadia v1.3.2 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.3 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.20.2 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.28.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.20.3 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.28.5 // indirect
github.com/aws/smithy-go v1.20.1 // indirect
github.com/boombuler/barcode v1.0.1 // indirect
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
@ -115,7 +113,7 @@ require (
github.com/google/s2a-go v0.1.7 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.3 // indirect
github.com/gopherjs/gopherjs v1.17.2 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
@ -128,6 +126,7 @@ require (
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
@ -140,6 +139,7 @@ require (
github.com/sergi/go-diff v1.2.0 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/smartystreets/assertions v1.2.0 // indirect
github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
@ -148,14 +148,14 @@ require (
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
golang.org/x/mod v0.15.0 // indirect
golang.org/x/mod v0.16.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.18.0 // indirect
golang.org/x/tools v0.19.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78 // indirect
google.golang.org/grpc v1.62.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect
google.golang.org/grpc v1.62.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/sourcemap.v1 v1.0.5 // indirect
gopkg.in/square/go-jose.v2 v2.5.1 // indirect

105
go.sum
View file

@ -39,34 +39,34 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo
github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aws/aws-sdk-go-v2 v1.25.3 h1:xYiLpZTQs1mzvz5PaI6uR0Wh57ippuEthxS4iK5v0n0=
github.com/aws/aws-sdk-go-v2 v1.25.3/go.mod h1:35hUlJVYd+M++iLI3ALmVwMOyRYMmRqUXpTtRGW+K9I=
github.com/aws/aws-sdk-go-v2/config v1.27.7 h1:JSfb5nOQF01iOgxFI5OIKWwDiEXWTyTgg1Mm1mHi0A4=
github.com/aws/aws-sdk-go-v2/config v1.27.7/go.mod h1:PH0/cNpoMO+B04qET699o5W92Ca79fVtbUnvMIZro4I=
github.com/aws/aws-sdk-go-v2/credentials v1.17.7 h1:WJd+ubWKoBeRh7A5iNMnxEOs982SyVKOJD+K8HIezu4=
github.com/aws/aws-sdk-go-v2/credentials v1.17.7/go.mod h1:UQi7LMR0Vhvs+44w5ec8Q+VS+cd10cjwgHwiVkE0YGU=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.3 h1:p+y7FvkK2dxS+FEwRIDHDe//ZX+jDhP8HHE50ppj4iI=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.3/go.mod h1:/fYB+FZbDlwlAiynK9KDXlzZl3ANI9JkD0Uhz5FjNT4=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.3 h1:ifbIbHZyGl1alsAhPIYsHOg5MuApgqOvVeI8wIugXfs=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.3/go.mod h1:oQZXg3c6SNeY6OZrDY+xHcF4VGIEoNotX2B4PrDeoJI=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.3 h1:Qvodo9gHG9F3E8SfYOspPeBt0bjSbsevK8WhRAUHcoY=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.3/go.mod h1:vCKrdLXtybdf/uQd/YfVR2r5pcbNuEYKzMQpcxmeSJw=
github.com/aws/aws-sdk-go-v2 v1.26.0 h1:/Ce4OCiM3EkpW7Y+xUnfAFpchU78K7/Ug01sZni9PgA=
github.com/aws/aws-sdk-go-v2 v1.26.0/go.mod h1:35hUlJVYd+M++iLI3ALmVwMOyRYMmRqUXpTtRGW+K9I=
github.com/aws/aws-sdk-go-v2/config v1.27.9 h1:gRx/NwpNEFSk+yQlgmk1bmxxvQ5TyJ76CWXs9XScTqg=
github.com/aws/aws-sdk-go-v2/config v1.27.9/go.mod h1:dK1FQfpwpql83kbD873E9vz4FyAxuJtR22wzoXn3qq0=
github.com/aws/aws-sdk-go-v2/credentials v1.17.9 h1:N8s0/7yW+h8qR8WaRlPQeJ6czVMNQVNtNdUqf6cItao=
github.com/aws/aws-sdk-go-v2/credentials v1.17.9/go.mod h1:446YhIdmSV0Jf/SLafGZalQo+xr2iw7/fzXGDPTU1yQ=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.0 h1:af5YzcLf80tv4Em4jWVD75lpnOHSBkPUZxZfGkrI3HI=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.0/go.mod h1:nQ3how7DMnFMWiU1SpECohgC82fpn4cKZ875NDMmwtA=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4 h1:0ScVK/4qZ8CIW0k8jOeFVsyS/sAiXpYxRBLolMkuLQM=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4/go.mod h1:84KyjNZdHC6QZW08nfHI6yZgPd+qRgaWcYsyLUo3QY8=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4 h1:sHmMWWX5E7guWEFQ9SVo6A3S4xpPrWnd77a6y4WM6PU=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4/go.mod h1:WjpDrhWisWOIoS9n3nk67A3Ll1vfULJ9Kq6h29HTD48=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 h1:EyBZibRTVAs6ECHZOw5/wlylS9OcTzwyjeQMudmREjE=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1/go.mod h1:JKpmtYhhPs7D97NL/ltqz7yCkERFW5dOlHyVl66ZYF8=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.5 h1:K/NXvIftOlX+oGgWGIa3jDyYLDNsdVhsjHmsBH2GLAQ=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.5/go.mod h1:cl9HGLV66EnCmMNzq4sYOti+/xo8w34CsgzVtm2GgsY=
github.com/aws/aws-sdk-go-v2/service/route53 v1.40.2 h1:YXQQJm3KnxabBHGNU8iC0GSvKRLtUSNUfP2R7L+Z/Tg=
github.com/aws/aws-sdk-go-v2/service/route53 v1.40.2/go.mod h1:ORinaAeDvAI7L7zPyE2RmG0RpwHKZDaQ7ALO8/dXFtY=
github.com/aws/aws-sdk-go-v2/service/route53domains v1.23.2 h1:TypWfzHKes0zADvTyJEwGsb0BAscUE8Ty0xs/jQM4Dk=
github.com/aws/aws-sdk-go-v2/service/route53domains v1.23.2/go.mod h1:jVbk98+jKo/JiX+qt028oGR6yApccx4ij5FaFUjiIAg=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.2 h1:XOPfar83RIRPEzfihnp+U6udOveKZJvPQ76SKWrLRHc=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.2/go.mod h1:Vv9Xyk1KMHXrR3vNQe8W5LMFdTjSeWk0gBZBzvf3Qa0=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.2 h1:pi0Skl6mNl2w8qWZXcdOyg197Zsf4G97U7Sso9JXGZE=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.2/go.mod h1:JYzLoEVeLXk+L4tn1+rrkfhkxl6mLDEVaDSvGq9og90=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.4 h1:Ppup1nVNAOWbBOrcoOxaxPeEnSFB2RnnQdguhXpmeQk=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.4/go.mod h1:+K1rNPVyGxkRuv9NNiaZ4YhBFuyw2MMA9SlIJ1Zlpz8=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6 h1:b+E7zIUHMmcB4Dckjpkapoy47W6C9QBv/zoUP+Hn8Kc=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6/go.mod h1:S2fNV0rxrP78NhPbCZeQgY8H9jdDMeGtwcfZIRxzBqU=
github.com/aws/aws-sdk-go-v2/service/route53 v1.40.3 h1:wr5gulbwbb8PSRMWjCROoP0TIMccpF8x5A7hEk2SjpA=
github.com/aws/aws-sdk-go-v2/service/route53 v1.40.3/go.mod h1:/Gyl9xjGcjIVe80ar75YlmA8m6oFh0A4XfLciBmdS8s=
github.com/aws/aws-sdk-go-v2/service/route53domains v1.23.3 h1:iuBYHWv0+2pF2qbM+UmnSwvcdOknXRi4yE9KBHhAItQ=
github.com/aws/aws-sdk-go-v2/service/route53domains v1.23.3/go.mod h1:Ijqatnvuyx5IE/FmFJWJyWTcUY5XrlXgc6G7z1Fqk6o=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.3 h1:mnbuWHOcM70/OFUlZZ5rcdfA8PflGXXiefU/O+1S3+8=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.3/go.mod h1:5HFu51Elk+4oRBZVxmHrSds5jFXmFj8C3w7DVF2gnrs=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3 h1:uLq0BKatTmDzWa/Nu4WO0M1AaQDaPpwTKAeByEc6WFM=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3/go.mod h1:b+qdhjnxj8GSR6t5YfphOffeoQSQ1KmpoVVuBn+PWxs=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.5 h1:J/PpTf/hllOjx8Xu9DMflff3FajfLxqM5+tepvVXmxg=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.5/go.mod h1:0ih0Z83YDH/QeQ6Ori2yGE2XvWYv/Xm+cZc01LC6oK0=
github.com/aws/smithy-go v1.20.1 h1:4SZlSlMr36UEqC7XOyRVb27XMeZubNcBNN+9IgEPIQw=
github.com/aws/smithy-go v1.20.1/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0=
@ -87,8 +87,8 @@ github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.6/go.mod
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/cloudflare-go v0.89.0 h1:3zoVntC8xmUR/weFEcNE1RizdW4LRZdQnJ/AN8DDa1U=
github.com/cloudflare/cloudflare-go v0.89.0/go.mod h1:eyuehb1i6BNRc+ZwaTZAiRHeE+4jbKvHAns19oGeakg=
github.com/cloudflare/cloudflare-go v0.91.0 h1:L7IR+86qrZuEMSjGFg4cwRwtHqC8uCPmMUkP7BD4CPw=
github.com/cloudflare/cloudflare-go v0.91.0/go.mod h1:nUqvBUUDRxNzsDSQjbqUNWHEIYAoUlgRmcAzMKlFdKs=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
@ -101,8 +101,8 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE=
github.com/deepmap/oapi-codegen v1.9.1 h1:yHmEnA7jSTUMQgV+uN02WpZtwHnz2CBW3mZRIxr1vtI=
github.com/deepmap/oapi-codegen v1.9.1/go.mod h1:PLqNAhdedP8ttRpBBkzLKU3bp+Fpy+tTgeAMlztR2cw=
github.com/digitalocean/godo v1.109.0 h1:4W97RJLJSUQ3veRZDNbp1Ol3Rbn6Lmt9bKGvfqYI5SU=
github.com/digitalocean/godo v1.109.0/go.mod h1:R6EmmWI8CT1+fCtjWY9UCB+L5uufuZH13wk3YhxycCs=
github.com/digitalocean/godo v1.110.0 h1:EY+rewWCYrUNOPbk9wI2Ytf0TBSRTJcZ6BINCb5dfmQ=
github.com/digitalocean/godo v1.110.0/go.mod h1:R6EmmWI8CT1+fCtjWY9UCB+L5uufuZH13wk3YhxycCs=
github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c h1:+Zo5Ca9GH0RoeVZQKzFJcTLoAixx5s5Gq3pTIS+n354=
github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c/go.mod h1:HJGU9ULdREjOcVGZVPB5s6zYmHi1RxzT71l2wQyLmnE=
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
@ -206,8 +206,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go/v2 v2.12.2 h1:mhN09QQW1jEWeMF74zGR81R30z4VJzjZsfkUhuHF+DA=
github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc=
github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA=
github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
@ -240,8 +240,8 @@ github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0S
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/vault/api v1.12.0 h1:meCpJSesvzQyao8FCOgk2fGdoADAnbDu2WPJN1lDLJ4=
github.com/hashicorp/vault/api v1.12.0/go.mod h1:si+lJCYO7oGkIoNPAN8j3azBLTn9SjMGS+jFaHd1Cck=
github.com/hashicorp/vault/api v1.12.2 h1:7YkCTE5Ni90TcmYHDBExdt4WGJxhpzaHqR6uGbQb/rE=
github.com/hashicorp/vault/api v1.12.2/go.mod h1:LSGf1NGT1BnvFFnKVtnvcaLBM2Lz+gJdpL6HUYed8KE=
github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc=
github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
@ -261,8 +261,9 @@ github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZ
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@ -344,8 +345,8 @@ github.com/robertkrimen/otto v0.3.0 h1:5RI+8860NSxvXywDY9ddF5HcPw0puRsd8EgbXV0oq
github.com/robertkrimen/otto v0.3.0/go.mod h1:uW9yN1CYflmUQYvAMS0m+ZiNo3dMzRUDQJX0jWbzgxw=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
@ -358,8 +359,9 @@ github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFR
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
@ -426,8 +428,8 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81 h1:6R2FC06FonbXQ8pK11/PDFY6N6LWlf9KlzibaCapmqc=
golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@ -435,8 +437,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -526,14 +528,14 @@ golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4X
golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.169.0 h1:QwWPy71FgMWqJN/l6jVlFHUa29a7dcUy02I8o799nPY=
google.golang.org/api v0.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg=
google.golang.org/api v0.171.0 h1:w174hnBPqut76FzW5Qaupt7zY8Kql6fiVjgys4f58sU=
google.golang.org/api v0.171.0/go.mod h1:Hnq5AHm4OTMt2BUVjael2CWZFD6vksJdWCWiUAmjC9o=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
@ -541,19 +543,18 @@ google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJ
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 h1:g/4bk7P6TPMkAUbUhquq98xey1slwvuVJPosdBqYJlU=
google.golang.org/genproto v0.0.0-20240205150955-31a09d347014/go.mod h1:xEgQu1e4stdSSsxPDK8Azkrk/ECl5HvdPf6nbZrTS5M=
google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 h1:x9PwdEgd11LgK+orcck69WVRo7DezSO4VUMPI4xpc8A=
google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014/go.mod h1:rbHMSEDyoYX62nRVLOCc4Qt1HbsdytAYoVwgjiOhF3I=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78 h1:Xs9lu+tLXxLIfuci70nG4cpwaRC+mRQPUL7LoIeDJC4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs=
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ=
google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 h1:rIo7ocm2roD9DcFIX67Ym8icoGCKSARAiPljFhh5suQ=
google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c h1:lfpJ/2rWPa/kJgxyyXM8PrNnfCzcmxJ265mADgwmvLI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk=
google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk=
google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=

View file

@ -3,6 +3,7 @@ package models
import (
"fmt"
"strings"
"sync"
"github.com/qdm12/reprint"
"golang.org/x/net/idna"
@ -23,9 +24,10 @@ type DomainConfig struct {
// Metadata[DomainUniqueName] // .Name + "!" + .Tag
// Metadata[DomainTag] // split horizon tag
Metadata map[string]string `json:"meta,omitempty"`
Records Records `json:"records"`
Nameservers []*Nameserver `json:"nameservers,omitempty"`
Metadata map[string]string `json:"meta,omitempty"`
Records Records `json:"records"`
Nameservers []*Nameserver `json:"nameservers,omitempty"`
NameserversMutex sync.Mutex `json:"-"`
EnsureAbsent Records `json:"recordsabsent,omitempty"` // ENSURE_ABSENT
KeepUnknown bool `json:"keepunknown,omitempty"` // NO_PURGE
@ -42,6 +44,12 @@ type DomainConfig struct {
// 2. Final driver instances are loaded after we load credentials. Any actual provider interaction requires that.
RegistrarInstance *RegistrarInstance `json:"-"`
DNSProviderInstances []*DNSProviderInstance `json:"-"`
// Pending work to do for each provider. Provider may be a registrar or DSP.
// pendingCorrectionsMutex sync.Mutex
pendingCorrections map[string]([]*Correction) // Work to be done for each provider
pendingCorrectionsOrder []string // Call the providers in this order
pendingCorrectionsMutex sync.Mutex // Protect pendingCorrections*
}
// GetSplitHorizonNames returns the domain's name, uniquename, and tag.
@ -141,3 +149,38 @@ func (dc *DomainConfig) Punycode() error {
}
return nil
}
func (dc *DomainConfig) StoreCorrections(providerName string, corrections []*Correction) {
dc.pendingCorrectionsMutex.Lock()
defer dc.pendingCorrectionsMutex.Unlock()
if dc.pendingCorrections == nil {
// First time storing anything.
dc.pendingCorrections = make(map[string]([]*Correction))
dc.pendingCorrections[providerName] = corrections
dc.pendingCorrectionsOrder = []string{providerName}
} else if c, ok := dc.pendingCorrections[providerName]; !ok {
// First time key used
dc.pendingCorrections[providerName] = corrections
dc.pendingCorrectionsOrder = []string{providerName}
} else {
// Add to existing.
dc.pendingCorrections[providerName] = append(c, corrections...)
dc.pendingCorrectionsOrder = append(dc.pendingCorrectionsOrder, providerName)
}
}
func (dc *DomainConfig) GetCorrections(providerName string) []*Correction {
dc.pendingCorrectionsMutex.Lock()
defer dc.pendingCorrectionsMutex.Unlock()
if dc.pendingCorrections == nil {
// First time storing anything.
return nil
}
if c, ok := dc.pendingCorrections[providerName]; ok {
return c
}
return nil
}

View file

@ -14,24 +14,26 @@ import (
// 1. All explicitly defined NAMESERVER records will be used.
// 2. Each DSP declares how many nameservers to use. Default is all. 0 indicates to use none.
func DetermineNameservers(dc *models.DomainConfig) ([]*models.Nameserver, error) {
return DetermineNameserversForProviders(dc, dc.DNSProviderInstances)
return DetermineNameserversForProviders(dc, dc.DNSProviderInstances, false)
}
// DetermineNameserversForProviders is like DetermineNameservers, for a subset of providers.
func DetermineNameserversForProviders(dc *models.DomainConfig, providers []*models.DNSProviderInstance) ([]*models.Nameserver, error) {
// always take explicit
func DetermineNameserversForProviders(dc *models.DomainConfig, providers []*models.DNSProviderInstance, silent bool) ([]*models.Nameserver, error) {
// start with the nameservers that have been explicitly added:
ns := dc.Nameservers
for _, dnsProvider := range providers {
n := dnsProvider.NumberOfNameservers
if n == 0 {
continue
}
if !printer.SkinnyReport {
if !silent && !printer.SkinnyReport {
fmt.Printf("----- Getting nameservers from: %s\n", dnsProvider.Name)
}
nss, err := dnsProvider.Driver.GetNameservers(dc.Name)
if err != nil {
return nil, err
return nil, fmt.Errorf("error while getting Nameservers for zone=%q with provider=%q: %w", dc.Name, dnsProvider.Name, err)
}
// Clean up the nameservers due to
// https://github.com/StackExchange/dnscontrol/issues/491

View file

@ -31,6 +31,7 @@ type Printer interface {
Println(lines ...string)
Warnf(fmt string, args ...interface{})
Errorf(fmt string, args ...interface{})
PrintfIf(print bool, fmt string, args ...interface{})
}
// Debugf is called to print/format debug information.
@ -58,6 +59,11 @@ func Warnf(fmt string, args ...interface{}) {
// DefaultPrinter.Errorf(fmt, args...)
// }
// PrintfIf is called to optionally print something.
func PrintfIf(print bool, fmt string, args ...interface{}) {
DefaultPrinter.PrintfIf(print, fmt, args...)
}
var (
// DefaultPrinter is the default Printer, used by Debugf, Printf, and Warnf.
DefaultPrinter = &ConsolePrinter{
@ -190,3 +196,10 @@ func (c ConsolePrinter) Warnf(format string, args ...interface{}) {
func (c ConsolePrinter) Errorf(format string, args ...interface{}) {
fmt.Fprintf(c.Writer, "ERROR: "+format, args...)
}
// Errorf is called to optionally print/format a message.
func (c ConsolePrinter) PrintfIf(print bool, format string, args ...interface{}) {
if print {
fmt.Fprintf(c.Writer, format, args...)
}
}

View file

@ -23,15 +23,13 @@ type azurednsProvider struct {
zones map[string]*adns.Zone
resourceGroup *string
subscriptionID *string
rawRecords map[string][]*adns.RecordSet
zoneName map[string]string
}
func newAzureDNSDsp(conf map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
return newAzureDNS(conf, metadata)
}
func newAzureDNS(m map[string]string, metadata json.RawMessage) (*azurednsProvider, error) {
func newAzureDNS(m map[string]string, _ json.RawMessage) (*azurednsProvider, error) {
subID, rg := m["SubscriptionID"], m["ResourceGroup"]
clientID, clientSecret, tenantID := m["ClientID"], m["ClientSecret"], m["TenantID"]
credential, authErr := aauth.NewClientSecretCredential(tenantID, clientID, clientSecret, nil)
@ -52,8 +50,6 @@ func newAzureDNS(m map[string]string, metadata json.RawMessage) (*azurednsProvid
recordsClient: recordsClient,
resourceGroup: to.StringPtr(rg),
subscriptionID: to.StringPtr(subID),
rawRecords: map[string][]*adns.RecordSet{},
zoneName: map[string]string{},
}
err := api.getZones()
if err != nil {
@ -66,7 +62,7 @@ var features = providers.DocumentationNotes{
// The default for unlisted capabilities is 'Cannot'.
// See providers/capabilities.go for the entire list of capabilities.
providers.CanGetZones: providers.Can(),
providers.CanConcur: providers.Cannot(),
providers.CanConcur: providers.Can(),
providers.CanUseAlias: providers.Cannot("Azure DNS does not provide a generic ALIAS functionality. Use AZURE_ALIAS instead."),
providers.CanUseAzureAlias: providers.Can(),
providers.CanUseCAA: providers.Can(),
@ -187,9 +183,6 @@ func (a *azurednsProvider) getExistingRecords(domain string) (models.Records, []
existingRecords = append(existingRecords, nativeToRecords(set, zoneName)...)
}
a.rawRecords[domain] = rawRecords
a.zoneName[domain] = zoneName
return existingRecords, rawRecords, zoneName, nil
}

View file

@ -2,7 +2,9 @@
package providers
import "log"
import (
"log"
)
// Capability is a bitmasked set of "features" that a provider supports. Only use constants from this package.
type Capability uint32

View file

@ -8,6 +8,7 @@ import (
"os"
"strconv"
"strings"
"sync"
"golang.org/x/net/idna"
@ -43,7 +44,7 @@ var features = providers.DocumentationNotes{
// The default for unlisted capabilities is 'Cannot'.
// See providers/capabilities.go for the entire list of capabilities.
providers.CanGetZones: providers.Can(),
providers.CanConcur: providers.Cannot(),
providers.CanConcur: providers.Can(),
providers.CanUseAlias: providers.Can("CF automatically flattens CNAME records into A records dynamically"),
providers.CanUseCAA: providers.Can(),
providers.CanUseDSForChildren: providers.Can(),
@ -79,6 +80,7 @@ type cloudflareProvider struct {
manageWorkers bool
accountID string
cfClient *cloudflare.API
sync.Mutex
}
// TODO(dlemenkov): remove this function after deleting all commented code referecing it
@ -94,27 +96,29 @@ type cloudflareProvider struct {
// GetNameservers returns the nameservers for a domain.
func (c *cloudflareProvider) GetNameservers(domain string) ([]*models.Nameserver, error) {
if c.domainIndex == nil {
if err := c.fetchDomainList(); err != nil {
return nil, err
}
if err := c.cacheDomainList(); err != nil {
return nil, err
}
c.Lock()
ns, ok := c.nameservers[domain]
c.Unlock()
if !ok {
return nil, fmt.Errorf("nameservers for %s not found in cloudflare account", domain)
return nil, fmt.Errorf("nameservers for %s not found in cloudflare cache(%q)", domain, c.accountID)
}
return models.ToNameservers(ns)
}
// ListZones returns a list of the DNS zones.
func (c *cloudflareProvider) ListZones() ([]string, error) {
if err := c.fetchDomainList(); err != nil {
if err := c.cacheDomainList(); err != nil {
return nil, err
}
c.Lock()
zones := make([]string, 0, len(c.domainIndex))
for d := range c.domainIndex {
zones = append(zones, d)
}
c.Unlock()
return zones, nil
}
@ -178,12 +182,12 @@ func (c *cloudflareProvider) GetZoneRecords(domain string, meta map[string]strin
}
func (c *cloudflareProvider) getDomainID(name string) (string, error) {
if c.domainIndex == nil {
if err := c.fetchDomainList(); err != nil {
return "", err
}
if err := c.cacheDomainList(); err != nil {
return "", err
}
c.Lock()
id, ok := c.domainIndex[name]
c.Unlock()
if !ok {
return "", fmt.Errorf("'%s' not a zone in cloudflare account", name)
}
@ -196,14 +200,6 @@ func (c *cloudflareProvider) GetZoneRecordsCorrections(dc *models.DomainConfig,
if err := c.preprocessConfig(dc); err != nil {
return nil, err
}
// for i := len(records) - 1; i >= 0; i-- {
// rec := records[i]
// // Delete ignore labels
// if labelMatches(dnsutil.TrimDomainName(rec.Original.(cloudflare.DNSRecord).Name, dc.Name), c.ignoredLabels) {
// printer.Debugf("ignored_label: %s\n", rec.Original.(cloudflare.DNSRecord).Name)
// records = append(records[:i], records[i+1:]...)
// }
// }
checkNSModifications(dc)
@ -222,9 +218,6 @@ func (c *cloudflareProvider) GetZoneRecordsCorrections(dc *models.DomainConfig,
if rec.Metadata[metaProxy] != "off" {
rec.TTL = 1
}
// if labelMatches(rec.GetLabel(), c.ignoredLabels) {
// log.Fatalf("FATAL: dnsconfig contains label that matches ignored_labels: %#v is in %v)\n", rec.GetLabel(), c.ignoredLabels)
// }
}
checkNSModifications(dc)
@ -815,11 +808,14 @@ func getProxyMetadata(r *models.RecordConfig) map[string]string {
// EnsureZoneExists creates a zone if it does not exist
func (c *cloudflareProvider) EnsureZoneExists(domain string) error {
if c.domainIndex == nil {
if err := c.fetchDomainList(); err != nil {
return err
}
if err := c.cacheDomainList(); err != nil {
return err
}
// if c.domainIndex == nil {
// if err := c.fetchDomainList(); err != nil {
// return err
// }
// }
if _, ok := c.domainIndex[domain]; ok {
return nil
}

View file

@ -13,7 +13,10 @@ import (
)
// get list of domains for account. Cache so the ids can be looked up from domain name
func (c *cloudflareProvider) fetchDomainList() error {
func (c *cloudflareProvider) cacheDomainList() error {
c.Lock()
defer c.Unlock()
c.domainIndex = map[string]string{}
c.nameservers = map[string][]string{}
zones, err := c.cfClient.ListZones(context.Background())

View file

@ -28,7 +28,7 @@ var features = providers.DocumentationNotes{
// The default for unlisted capabilities is 'Cannot'.
// See providers/capabilities.go for the entire list of capabilities.
providers.CanGetZones: providers.Can(),
providers.CanConcur: providers.Cannot(),
providers.CanConcur: providers.Can(),
providers.CanUseCAA: providers.Can(),
providers.CanUseSRV: providers.Can(),
providers.DocOfficiallySupported: providers.Can(),

View file

@ -26,7 +26,7 @@ var features = providers.DocumentationNotes{
// The default for unlisted capabilities is 'Cannot'.
// See providers/capabilities.go for the entire list of capabilities.
providers.CanGetZones: providers.Can(),
providers.CanConcur: providers.Cannot(),
providers.CanConcur: providers.Can(),
providers.CanUseAlias: providers.Can(),
providers.CanUseCAA: providers.Can(),
providers.CanUseDSForChildren: providers.Can(),

View file

@ -171,10 +171,16 @@ func (n None) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correctio
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.

View file

@ -27,12 +27,11 @@ import (
)
type route53Provider struct {
client *r53.Client
registrar *r53d.Client
delegationSet *string
zonesByID map[string]r53Types.HostedZone
zonesByDomain map[string]r53Types.HostedZone
originalRecords []r53Types.ResourceRecordSet
client *r53.Client
registrar *r53d.Client
delegationSet *string
zonesByID map[string]r53Types.HostedZone
zonesByDomain map[string]r53Types.HostedZone
}
func newRoute53Reg(conf map[string]string) (providers.Registrar, error) {
@ -79,7 +78,7 @@ var features = providers.DocumentationNotes{
// The default for unlisted capabilities is 'Cannot'.
// See providers/capabilities.go for the entire list of capabilities.
providers.CanGetZones: providers.Can(),
providers.CanConcur: providers.Cannot(),
providers.CanConcur: providers.Can(),
providers.CanUseAlias: providers.Cannot("R53 does not provide a generic ALIAS functionality. Use R53_ALIAS instead."),
providers.CanUseCAA: providers.Can(),
providers.CanUseLOC: providers.Cannot(),
@ -267,7 +266,6 @@ func (r *route53Provider) getZoneRecords(zone r53Types.HostedZone) (models.Recor
if err != nil {
return nil, err
}
r.originalRecords = records
var existingRecords = []*models.RecordConfig{}
for _, set := range records {