package diff2 import ( "fmt" "strings" "github.com/gobwas/glob" "github.com/StackExchange/dnscontrol/v3/models" "github.com/StackExchange/dnscontrol/v3/pkg/printer" ) func handsoff( existing, desired models.Records, unmanaged []*models.UnmanagedConfig, beSafe bool, ) (models.Records, error) { // What foreign items should we ignore? foreign, err := manyQueries(existing, unmanaged) if err != nil { return nil, err } if len(foreign) != 0 { printer.Printf("INFO: Foreign records being ignored: (%d)\n", len(foreign)) for i, r := range foreign { printer.Printf("- % 4d: %s %s %s\n", i, r.GetLabelFQDN(), r.Type, r.GetTargetRFC1035Quoted()) } } // What desired items might conflict? conflicts, err := manyQueries(desired, unmanaged) if err != nil { return nil, err } if len(conflicts) != 0 { level := "WARN" if beSafe { level = "ERROR" } printer.Printf("%s: dnsconfig.js records that overlap MANAGED: (%d)\n", level, len(conflicts)) for i, r := range conflicts { printer.Printf("- % 4d: %s %s %s\n", i, r.GetLabelFQDN(), r.Type, r.GetTargetRFC1035Quoted()) } if beSafe { return nil, fmt.Errorf("ERROR: Unsafe to continue. Add DISABLE_UNMANAGED_SAFETY_CHECK to D() to override") } } // Add the foreign items to the desired list. // (Rather than literally ignoring them, we just add them to the desired list // and all the diffing algorithms become more simple.) desired = append(desired, foreign...) return desired, nil } func manyQueries(rcs models.Records, queries []*models.UnmanagedConfig) (result models.Records, err error) { for _, q := range queries { lab := q.Label if lab == "" { lab = "*" } glabel, err := glob.Compile(lab) if err != nil { return nil, err } targ := q.Target if targ == "" { targ = "*" } gtarget, err := glob.Compile(targ) if err != nil { return nil, err } hasRType := compileTypeGlob(q.RType) for _, rc := range rcs { if match(rc, glabel, gtarget, hasRType) { result = append(result, rc) } } } return result, nil } func compileTypeGlob(g string) map[string]bool { m := map[string]bool{} for _, j := range strings.Split(g, ",") { m[strings.TrimSpace(j)] = true } return m } func match(rc *models.RecordConfig, glabel, gtarget glob.Glob, hasRType map[string]bool) bool { printer.Printf("DEBUG: match(%v, %v, %v, %v)\n", rc.NameFQDN, glabel, gtarget, hasRType) // _ = glabel.Match(rc.NameFQDN) // _ = matchType(rc.Type, hasRType) // x := rc.GetTargetField() // _ = gtarget.Match(x) if !glabel.Match(rc.NameFQDN) { printer.Printf("DEBUG: REJECTED LABEL: %s:%v\n", rc.NameFQDN, glabel) return false } else if !matchType(rc.Type, hasRType) { printer.Printf("DEBUG: REJECTED TYPE: %s:%v\n", rc.Type, hasRType) return false } else if gtarget == nil { return true } else if !gtarget.Match(rc.GetTargetField()) { printer.Printf("DEBUG: REJECTED TARGET: %v:%v\n", rc.GetTargetField(), gtarget) return false } return true } func matchType(s string, hasRType map[string]bool) bool { printer.Printf("DEBUG: matchType map=%v\n", hasRType) if len(hasRType) == 0 { return true } _, ok := hasRType[s] return ok }