Disable records instead of deleting them
A disabled record stays in Jarl with its ID, TTL and comment but is left out of the zone; the zone file lists it as a comment. Web UI toggle, jarl record disable|enable, record.disable|enable operations and API endpoints. Database schema 5. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5f04ab523b
commit
295c549479
29 files changed
+815
-60
No files matched your search
@@ -103,6 +103,31 @@ func (c *checker) zoneLimit(z *model.Zone, name string, def int) int {
|
||||
return n
|
||||
}
|
||||
|
||||
// checkDisabledRecords warns about disabled records that couldn't be
|
||||
// enabled again as the zone is now: the CNAME rules are the usual way a
|
||||
// name changes while one of its records is disabled.
|
||||
func (c *checker) checkDisabledRecords(z *model.Zone) {
|
||||
served := map[string]map[string]bool{}
|
||||
for _, r := range c.zoneRecords[z.ID] {
|
||||
if served[r.Name] == nil {
|
||||
served[r.Name] = map[string]bool{}
|
||||
}
|
||||
served[r.Name][r.Type] = true
|
||||
}
|
||||
for _, r := range c.allRecords[z.ID] {
|
||||
if !r.Disabled {
|
||||
continue
|
||||
}
|
||||
types := served[r.Name]
|
||||
switch {
|
||||
case r.Type != "CNAME" && types["CNAME"]:
|
||||
c.recProblem(z, r, Warning, "disabled_conflict", "the disabled record %s %s %s can't be enabled again while %s has a CNAME (a CNAME must be the only record at its name)", disp(r.Name), r.Type, r.Data, disp(r.Name))
|
||||
case r.Type == "CNAME" && len(types) > 0:
|
||||
c.recProblem(z, r, Warning, "disabled_conflict", "the disabled CNAME %s → %s can't be enabled again while %s has other records (a CNAME must be the only record at its name)", disp(r.Name), r.Data, disp(r.Name))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *checker) checkZoneRecords(z *model.Zone) {
|
||||
ix := &zoneIndex{
|
||||
z: z,
|
||||
|
||||
@@ -115,13 +115,14 @@ type checker struct {
|
||||
opts Options
|
||||
problems []Problem
|
||||
// indexes
|
||||
zoneRecords map[int64][]*model.Record
|
||||
zoneRecords map[int64][]*model.Record // served records (not disabled)
|
||||
allRecords map[int64][]*model.Record
|
||||
keyNames map[string]bool
|
||||
}
|
||||
|
||||
// State validates the complete state.
|
||||
func State(s *model.State, opts Options) []Problem {
|
||||
c := &checker{s: s, opts: opts, zoneRecords: s.RecordsByZone(), keyNames: map[string]bool{}}
|
||||
c := &checker{s: s, opts: opts, zoneRecords: s.ServedRecordsByZone(), allRecords: s.RecordsByZone(), keyNames: map[string]bool{}}
|
||||
for _, k := range s.Keys {
|
||||
c.keyNames[k.Name] = true
|
||||
}
|
||||
|
||||
@@ -105,8 +105,8 @@ func (c *checker) checkZones() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if !z.HasRecords() && len(c.zoneRecords[z.ID]) > 0 {
|
||||
c.zoneProblem(z, Error, "zone_records_unmanaged", "%s zones can't have records managed by Jarl (they get their data from elsewhere); delete the %d records or change the type to primary", z.Type, len(c.zoneRecords[z.ID]))
|
||||
if !z.HasRecords() && len(c.allRecords[z.ID]) > 0 {
|
||||
c.zoneProblem(z, Error, "zone_records_unmanaged", "%s zones can't have records managed by Jarl (they get their data from elsewhere); delete the %d records or change the type to primary", z.Type, len(c.allRecords[z.ID]))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -188,6 +188,7 @@ func (c *checker) checkPrimary(z *model.Zone) {
|
||||
c.zoneProblem(z, Info, "zone_name_slash", "zone names with '/' (RFC 2317) are supported, but the file name is escaped")
|
||||
}
|
||||
c.checkZoneRecords(z)
|
||||
c.checkDisabledRecords(z)
|
||||
}
|
||||
|
||||
// humanSeconds formats a duration in seconds as e.g. "1 day" or "12 hours".
|
||||
|
||||
Reference in new issue
Block a user