Disable zones instead of deleting them

A disabled zone stays in Jarl with its records, options and history,
still editable, but named doesn't load it; enabling it serves it as it is
then. Signed zones, and zones another view shares, can't be disabled.
jarl zone disable|enable, the zone page's Disable/Enable button.
Database schema 7.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adamandClaude Opus 5.5 committed 2026-10-10 13:45:55 +00:00
1 parent 59baccd636
commit 89663e366b
24 files changed
+264 -26

No files matched your search

+34
View File
@@ -145,6 +145,12 @@ func (x *expander) expand(req Request) ([]model.Op, error) {
if n := len(x.st.ZoneRecords(z.ID)); n > 0 {
verb += fmt.Sprintf(" (with its %d records)", n)
}
} else if d := zoneToggle(req, z); d != nil {
if *d {
x.warnings = append(x.warnings, disabledZoneEffect(x.st, z))
return []model.Op{x.versioned(req, z.Version, "disable zone "+zoneDesc(x.st, z))}, nil
}
return []model.Op{x.versioned(req, z.Version, "enable zone "+zoneDesc(x.st, z))}, nil
}
return []model.Op{x.versioned(req, z.Version, "zone "+verb+" "+zoneDesc(x.st, z))}, nil
case OpRecordCreate:
@@ -1029,3 +1035,31 @@ func RedactOps(ops []model.Op) []model.Op {
}
return out
}
// zoneToggle returns the new disabled state when a zone update only
// disables or enables the zone (nil otherwise).
func zoneToggle(req Request, z *model.Zone) *bool {
var in ZoneInput
if decode(req.Data, &in) != nil || in.Disabled == nil || *in.Disabled == z.Disabled {
return nil
}
only := ZoneInput{Disabled: in.Disabled}
if string(mustJSON(in)) != string(mustJSON(only)) {
return nil
}
return in.Disabled
}
// disabledZoneEffect says what clients get once named no longer loads a
// zone: in a view that offers recursion, answers from recursion (the
// internet's version of the zone, if it has one); elsewhere, REFUSED.
func disabledZoneEffect(st *model.State, z *model.Zone) string {
where := "this server"
if v := st.ViewName(z); v != "" {
where = "view " + v
}
if st.RecursionOn(z.ViewID) {
return fmt.Sprintf("once zone %s is disabled, clients of %s that may use recursion get its names from recursion: the internet's version of the zone, if there is one", dnsname.Display(z.Name), where)
}
return fmt.Sprintf("once zone %s is disabled, %s answers REFUSED for its names", dnsname.Display(z.Name), where)
}