package diff import "github.com/vasyakrg/dns-autoresolver/internal/model" type ChangeKind string const ( InSync ChangeKind = "in_sync" Add ChangeKind = "add" Update ChangeKind = "update" Delete ChangeKind = "delete" ) // RecordDiff describes one RRset's deviation between template and zone. type RecordDiff struct { Kind ChangeKind Type model.RecordType Name string Desired *model.Record // nil for Delete Actual *model.Record // nil for Add ReadOnly bool // NS/SOA — shown but never applied } type Changeset struct { Diffs []RecordDiff } // Actionable returns managed diffs that are not in sync. func (c Changeset) Actionable() []RecordDiff { var out []RecordDiff for _, d := range c.Diffs { if d.ReadOnly || d.Kind == InSync { continue } out = append(out, d) } return out } // Diff compares a template against the actual zone records. // Records present in the zone but absent from the template yield Delete. func Diff(template, actual []model.Record) Changeset { current := index(actual) seen := make(map[string]bool, len(template)) var diffs []RecordDiff for _, t := range template { tt := t key := tt.Key() seen[key] = true ro := !tt.Type.Managed() if a, ok := current[key]; ok { ac := a kind := Update if tt.Equal(ac) { kind = InSync } diffs = append(diffs, RecordDiff{Kind: kind, Type: tt.Type, Name: tt.Name, Desired: &tt, Actual: &ac, ReadOnly: ro}) } else { diffs = append(diffs, RecordDiff{Kind: Add, Type: tt.Type, Name: tt.Name, Desired: &tt, ReadOnly: ro}) } } for _, a := range actual { ac := a if seen[ac.Key()] { continue } diffs = append(diffs, RecordDiff{Kind: Delete, Type: ac.Type, Name: ac.Name, Actual: &ac, ReadOnly: !ac.Type.Managed()}) } return Changeset{Diffs: diffs} } func index(recs []model.Record) map[string]model.Record { m := make(map[string]model.Record, len(recs)) for _, r := range recs { m[r.Key()] = r } return m }