dnscontrol/pkg/diff2/unmanaged.go

129 lines
3.1 KiB
Go

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
}