Don't count diff2.REPORT (informational warnings) as a "correction" (#2361)

Co-authored-by: Tom Limoncelli <tal@whatexit.org>
This commit is contained in:
Tom Limoncelli 2023-05-16 10:42:08 -04:00 committed by GitHub
parent 84e39b4ae2
commit 66a76c44c1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 90 additions and 61 deletions

View file

@ -26,8 +26,6 @@ var commands = []*cli.Command{}
// These are set by/for goreleaser // These are set by/for goreleaser
var ( var (
version = "dev" version = "dev"
commit = "none"
date = "unknown"
) )
func cmd(cat string, c *cli.Command) bool { func cmd(cat string, c *cli.Command) bool {

View file

@ -222,13 +222,16 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI) error {
continue continue
} }
corrections, err := zonerecs.CorrectZoneRecords(provider.Driver, domain) reports, corrections, err := zonerecs.CorrectZoneRecords(provider.Driver, domain)
printReports(domain.Name, provider.Name, reports, out, push, notifier)
out.EndProvider(provider.Name, len(corrections), err) out.EndProvider(provider.Name, len(corrections), err)
if err != nil { if err != nil {
anyErrors = true anyErrors = true
return return
} }
totalCorrections += len(corrections) totalCorrections += len(corrections)
// When diff1 goes away, the call to printReports() should be moved to HERE.
//printReports(domain.Name, provider.Name, reports, out, push, notifier)
anyErrors = printOrRunCorrections(domain.Name, provider.Name, corrections, out, push, interactive, notifier) || anyErrors anyErrors = printOrRunCorrections(domain.Name, provider.Name, corrections, out, push, interactive, notifier) || anyErrors
} }
@ -543,3 +546,15 @@ func printOrRunCorrections(domain string, provider string, corrections []*models
} }
return anyErrors return anyErrors
} }
func printReports(domain string, provider string, reports []*models.Correction, out printer.CLI, push bool, notifier notifications.Notifier) (anyErrors bool) {
anyErrors = false
if len(reports) == 0 {
return false
}
for i, report := range reports {
out.PrintReport(i, report)
notifier.Notify(domain, provider, report.Msg, nil, !push)
}
return anyErrors
}

View file

@ -223,12 +223,12 @@ func makeChanges(t *testing.T, prv providers.DNSServiceProvider, dc *models.Doma
} }
// get and run corrections for first time // get and run corrections for first time
corrections, err := zonerecs.CorrectZoneRecords(prv, dom) _, corrections, err := zonerecs.CorrectZoneRecords(prv, dom)
if err != nil { if err != nil {
t.Fatal(fmt.Errorf("runTests: %w", err)) t.Fatal(fmt.Errorf("runTests: %w", err))
} }
if tst.Changeless { if tst.Changeless {
if count := zonerecs.CountActionable(corrections); count != 0 { if count := len(corrections); count != 0 {
t.Logf("Expected 0 corrections on FIRST run, but found %d.", count) t.Logf("Expected 0 corrections on FIRST run, but found %d.", count)
for i, c := range corrections { for i, c := range corrections {
t.Logf("UNEXPECTED #%d: %s", i, c.Msg) t.Logf("UNEXPECTED #%d: %s", i, c.Msg)
@ -256,11 +256,11 @@ func makeChanges(t *testing.T, prv providers.DNSServiceProvider, dc *models.Doma
} }
// run a second time and expect zero corrections // run a second time and expect zero corrections
corrections, err = zonerecs.CorrectZoneRecords(prv, dom2) _, corrections, err = zonerecs.CorrectZoneRecords(prv, dom2)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if count := zonerecs.CountActionable(corrections); count != 0 { if count := len(corrections); count != 0 {
t.Logf("Expected 0 corrections on second run, but found %d.", count) t.Logf("Expected 0 corrections on second run, but found %d.", count)
for i, c := range corrections { for i, c := range corrections {
t.Logf("UNEXPECTED #%d: %s", i, c.Msg) t.Logf("UNEXPECTED #%d: %s", i, c.Msg)
@ -351,10 +351,13 @@ func TestDualProviders(t *testing.T) {
run := func() { run := func() {
dom, _ := dc.Copy() dom, _ := dc.Copy()
cs, err := zonerecs.CorrectZoneRecords(p, dom) rs, cs, err := zonerecs.CorrectZoneRecords(p, dom)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
for i, c := range rs {
t.Logf("INFO#%d:\n%s", i+1, c.Msg)
}
for i, c := range cs { for i, c := range cs {
t.Logf("#%d:\n%s", i+1, c.Msg) t.Logf("#%d:\n%s", i+1, c.Msg)
if err = c.F(); err != nil { if err = c.F(); err != nil {
@ -373,14 +376,17 @@ func TestDualProviders(t *testing.T) {
run() run()
// run again to make sure no corrections // run again to make sure no corrections
t.Log("Running again to ensure stability") t.Log("Running again to ensure stability")
cs, err := zonerecs.CorrectZoneRecords(p, dc) rs, cs, err := zonerecs.CorrectZoneRecords(p, dc)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if count := zonerecs.CountActionable(cs); count != 0 { if count := len(cs); count != 0 {
t.Logf("Expect no corrections on second run, but found %d.", count) t.Logf("Expect no corrections on second run, but found %d.", count)
for i, c := range rs {
t.Logf("INFO#%d:\n%s", i+1, c.Msg)
}
for i, c := range cs { for i, c := range cs {
t.Logf("#%d: %s", i, c.Msg) t.Logf("#%d: %s", i+1, c.Msg)
} }
t.FailNow() t.FailNow()
} }

View file

@ -9,8 +9,10 @@ import (
) )
const ( const (
// DomainUniqueName is the full `example.com!tag` name`
DomainUniqueName = "dnscontrol_uniquename" DomainUniqueName = "dnscontrol_uniquename"
DomainTag = "dnscontrol_tag" // DomainTag is the tag part of `example.com!tag` name
DomainTag = "dnscontrol_tag"
) )
// DomainConfig describes a DNS domain (technically a DNS zone). // DomainConfig describes a DNS domain (technically a DNS zone).

View file

@ -263,7 +263,7 @@ func (c *certManager) ensureNoPendingCorrections(d *models.DomainConfig) error {
return nil return nil
} }
// IgnoredProviders is a lit of provider names that should not be used to fill challenges. // IgnoredProviders is a list of provider names that should not be used to fill challenges.
var IgnoredProviders = map[string]bool{} var IgnoredProviders = map[string]bool{}
func (c *certManager) getCorrections(d *models.DomainConfig) ([]*models.Correction, error) { func (c *certManager) getCorrections(d *models.DomainConfig) ([]*models.Correction, error) {
@ -276,10 +276,13 @@ func (c *certManager) getCorrections(d *models.DomainConfig) ([]*models.Correcti
if err != nil { if err != nil {
return nil, err return nil, err
} }
corrections, err := zonerecs.CorrectZoneRecords(p.Driver, dc) reports, corrections, err := zonerecs.CorrectZoneRecords(p.Driver, dc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, c := range reports {
c.Msg = fmt.Sprintf("INFO[%s] %s", p.Name, strings.TrimSpace(c.Msg))
}
for _, c := range corrections { for _, c := range corrections {
c.Msg = fmt.Sprintf("[%s] %s", p.Name, strings.TrimSpace(c.Msg)) c.Msg = fmt.Sprintf("[%s] %s", p.Name, strings.TrimSpace(c.Msg))
} }

View file

@ -62,7 +62,13 @@ func (d *differCompat) IncrementalDiff(existing []*models.RecordConfig) (unchang
case diff2.REPORT: case diff2.REPORT:
// Sadly the NewCompat function doesn't have an equivalent. We // Sadly the NewCompat function doesn't have an equivalent. We
// just output the messages now. // just output the messages now.
fmt.Print("INFO: ")
fmt.Println(inst.MsgsJoined) fmt.Println(inst.MsgsJoined)
// TODO(tlim): When diff1 is deleted, IncremtntalDiff should add a
// parameter to list the REPORT messages. It can also eliminate the
// first parameter (existing) since nobody uses that in the diff2
// world.
case diff2.CREATE: case diff2.CREATE:
cor.Desired = inst.New[0] cor.Desired = inst.New[0]
toCreate = append(toCreate, cor) toCreate = append(toCreate, cor)

View file

@ -119,18 +119,18 @@ func handsoff(
// Process UNMANAGE/IGNORE_* and NO_PURGE features: // Process UNMANAGE/IGNORE_* and NO_PURGE features:
ignorable, foreign := processIgnoreAndNoPurge(domain, existing, desired, absences, unmanagedConfigs, noPurge) ignorable, foreign := processIgnoreAndNoPurge(domain, existing, desired, absences, unmanagedConfigs, noPurge)
if len(foreign) != 0 { if len(foreign) != 0 {
msgs = append(msgs, fmt.Sprintf("INFO: %d records not being deleted because of NO_PURGE:", len(foreign))) msgs = append(msgs, fmt.Sprintf("%d records not being deleted because of NO_PURGE:", len(foreign)))
msgs = append(msgs, reportSkips(foreign, !printer.SkinnyReport)...) msgs = append(msgs, reportSkips(foreign, !printer.SkinnyReport)...)
} }
if len(ignorable) != 0 { if len(ignorable) != 0 {
msgs = append(msgs, fmt.Sprintf("INFO: %d records not being deleted because of IGNORE*():", len(ignorable))) msgs = append(msgs, fmt.Sprintf("%d records not being deleted because of IGNORE*():", len(ignorable)))
msgs = append(msgs, reportSkips(ignorable, !printer.SkinnyReport)...) msgs = append(msgs, reportSkips(ignorable, !printer.SkinnyReport)...)
} }
// Check for invalid use of IGNORE_*. // Check for invalid use of IGNORE_*.
conflicts := findConflicts(unmanagedConfigs, desired) conflicts := findConflicts(unmanagedConfigs, desired)
if len(conflicts) != 0 { if len(conflicts) != 0 {
msgs = append(msgs, fmt.Sprintf("INFO: %d records that are both IGNORE*()'d and not ignored:", len(conflicts))) msgs = append(msgs, fmt.Sprintf("%d records that are both IGNORE*()'d and not ignored:", len(conflicts)))
for _, r := range conflicts { for _, r := range conflicts {
msgs = append(msgs, fmt.Sprintf(" %s %s %s", r.GetLabelFQDN(), r.Type, r.GetTargetCombined())) msgs = append(msgs, fmt.Sprintf(" %s %s %s", r.GetLabelFQDN(), r.Type, r.GetTargetCombined()))
} }

View file

@ -19,6 +19,7 @@ type CLI interface {
StartRegistrar(name string, skip bool) StartRegistrar(name string, skip bool)
PrintCorrection(n int, c *models.Correction) PrintCorrection(n int, c *models.Correction)
PrintReport(n int, c *models.Correction) // Print corrections that are diff2.REPORT
EndCorrection(err error) EndCorrection(err error)
PromptToRun() bool PromptToRun() bool
} }
@ -89,6 +90,13 @@ func (c ConsolePrinter) PrintCorrection(i int, correction *models.Correction) {
fmt.Fprintf(c.Writer, "#%d: %s\n", i+1, correction.Msg) fmt.Fprintf(c.Writer, "#%d: %s\n", i+1, correction.Msg)
} }
// PrintReport is called to print/format each non-mutating correction (diff2.REPORT).
func (c ConsolePrinter) PrintReport(i int, correction *models.Correction) {
// When diff1 is eliminated:
//fmt.Fprintf(c.Writer, "INFO#%d: %s\n", i+1, correction.Msg)
fmt.Fprintf(c.Writer, "INFO: %s\n", correction.Msg)
}
// PromptToRun prompts the user to see if they want to execute a correction. // PromptToRun prompts the user to see if they want to execute a correction.
func (c ConsolePrinter) PromptToRun() bool { func (c ConsolePrinter) PromptToRun() bool {
fmt.Fprint(c.Writer, "Run? (Y/n): ") fmt.Fprint(c.Writer, "Run? (Y/n): ")

View file

@ -7,11 +7,11 @@ import (
// CorrectZoneRecords calls both GetZoneRecords, does any // CorrectZoneRecords calls both GetZoneRecords, does any
// post-processing, and then calls GetZoneRecordsCorrections. The // post-processing, and then calls GetZoneRecordsCorrections. The
// name sucks because all the good names were taken. // name sucks because all the good names were taken.
func CorrectZoneRecords(driver models.DNSProvider, dc *models.DomainConfig) ([]*models.Correction, error) { func CorrectZoneRecords(driver models.DNSProvider, dc *models.DomainConfig) ([]*models.Correction, []*models.Correction, error) {
existingRecords, err := driver.GetZoneRecords(dc.Name, dc.Metadata) existingRecords, err := driver.GetZoneRecords(dc.Name, dc.Metadata)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
// downcase // downcase
@ -23,7 +23,7 @@ func CorrectZoneRecords(driver models.DNSProvider, dc *models.DomainConfig) ([]*
// dc.Records. // dc.Records.
dc, err = dc.Copy() dc, err = dc.Copy()
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
// punycode // punycode
@ -31,18 +31,18 @@ func CorrectZoneRecords(driver models.DNSProvider, dc *models.DomainConfig) ([]*
// FIXME(tlim) It is a waste to PunyCode every iteration. // FIXME(tlim) It is a waste to PunyCode every iteration.
// This should be moved to where the JavaScript is processed. // This should be moved to where the JavaScript is processed.
return driver.GetZoneRecordsCorrections(dc, existingRecords) everything, err := driver.GetZoneRecordsCorrections(dc, existingRecords)
reports, corrections := splitReportsAndCorrections(everything)
return reports, corrections, err
} }
// CountActionable returns the number of corrections that have func splitReportsAndCorrections(everything []*models.Correction) (reports, corrections []*models.Correction) {
// actions. It is like `len(corrections)` but doesn't count any for i := range everything {
// corrections that are purely informational. (i.e. `.F` is nil) if everything[i].F == nil {
func CountActionable(corrections []*models.Correction) int { reports = append(reports, everything[i])
count := 0 } else {
for i := range corrections { corrections = append(corrections, everything[i])
if corrections[i].F != nil {
count++
} }
} }
return count return reports, corrections
} }

View file

@ -496,7 +496,9 @@ func (r *route53Provider) GetZoneRecordsCorrections(dc *models.DomainConfig, exi
return nil, err return nil, err
} }
instructions = reorderInstructions(instructions) instructions = reorderInstructions(instructions)
wasReport := false var reports []*models.Correction
//wasReport := false
for _, inst := range instructions { for _, inst := range instructions {
instNameFQDN := inst.Key.NameFQDN instNameFQDN := inst.Key.NameFQDN
instType := inst.Key.Type instType := inst.Key.Type
@ -505,8 +507,12 @@ func (r *route53Provider) GetZoneRecordsCorrections(dc *models.DomainConfig, exi
switch inst.Type { switch inst.Type {
case diff2.REPORT: case diff2.REPORT:
chg = r53Types.Change{} // REPORTs are held in a separate list so that they aren't part of the batching process.
wasReport = true reports = append(reports,
&models.Correction{
Msg: inst.MsgsJoined,
})
continue
case diff2.CREATE: case diff2.CREATE:
fallthrough fallthrough
@ -560,34 +566,19 @@ func (r *route53Provider) GetZoneRecordsCorrections(dc *models.DomainConfig, exi
} }
addCorrection := func(msg string, req *r53.ChangeResourceRecordSetsInput) { addCorrection := func(msg string, req *r53.ChangeResourceRecordSetsInput) {
corrections = append(corrections,
if wasReport { &models.Correction{
Msg: msg,
// Add a "msg only" correction. F: func() error {
corrections = append(corrections, var err error
&models.Correction{ req.HostedZoneId = zone.Id
Msg: msg, withRetry(func() error {
}) _, err = r.client.ChangeResourceRecordSets(context.Background(), req)
} else {
// Add a function to execute.
corrections = append(corrections,
&models.Correction{
Msg: msg,
F: func() error {
var err error
req.HostedZoneId = zone.Id
withRetry(func() error {
_, err = r.client.ChangeResourceRecordSets(context.Background(), req)
return err
})
return err return err
}, })
}) return err
},
} })
} }
// Send the changes in as few API calls as possible. // Send the changes in as few API calls as possible.
@ -605,7 +596,7 @@ func (r *route53Provider) GetZoneRecordsCorrections(dc *models.DomainConfig, exi
return nil, err return nil, err
} }
return corrections, nil return append(reports, corrections...), nil
} }