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:
adamandClaude Opus 5.5 committed 2026-10-09 22:33:02 +00:00
1 parent 5f04ab523b
commit 295c549479
29 files changed
+815 -60

No files matched your search

+36
View File
@@ -22,6 +22,8 @@ changes:
- set: {zone: example.com, name: api, type: A, data: 192.0.2.5}
- set: {zone: example.com, name: gone, type: TXT}
- update: {id: 13, data: 192.0.2.9}
- disable: {zone: example.com, name: www, type: A, data: 192.0.2.1, ptr: true}
- enable: {id: 14}
- op: zone.create
data: {name: lab.example.com}
`
@@ -44,6 +46,8 @@ changes:
{"rrset.replace", 0, `{"data":["192.0.2.5"],"name":"api","type":"A","zone":"example.com"}`},
{"rrset.replace", 0, `{"data":[],"name":"gone","type":"TXT","zone":"example.com"}`},
{"record.update", 13, `{"data":"192.0.2.9"}`},
{"record.disable", 0, `{"data":"192.0.2.1","name":"www","ptr":true,"type":"A","zone":"example.com"}`},
{"record.enable", 14, `{}`},
{"zone.create", 0, `{"name":"lab.example.com"}`},
}
if len(reqs) != len(want) {
@@ -112,6 +116,38 @@ func TestListValue(t *testing.T) {
// filters they send: flags bound to variables shared between subcommands
// must not leak defaults (zone create's --type primary once hid every
// non-primary zone from 'zone list').
func TestDisableCommands(t *testing.T) {
var got string
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
got = r.Method + " " + r.URL.Path + "?" + r.URL.RawQuery
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"applied":true,"changeset_id":1}`))
}))
defer srv.Close()
t.Setenv("JARL_CLI_CONFIG", filepath.Join(t.TempDir(), "cli.yaml"))
for _, tc := range []struct {
args []string
want string
}{
{[]string{"record", "disable", "example.com", "www", "A"}, "POST /api/v1/zones/example.com/records/disable?name=www&type=A"},
{[]string{"record", "disable", "example.com", "www", "A", "192.0.2.1", "--ptr", "--view", "internal"}, "POST /api/v1/zones/example.com/records/disable?data=192.0.2.1&name=www&ptr=1&type=A&view=internal"},
{[]string{"record", "enable", "--id", "12", "--ptr"}, "POST /api/v1/records/12/enable?ptr=1"},
{[]string{"record", "enable", "example.com", "old", "CNAME", "--missing-ok"}, "POST /api/v1/zones/example.com/records/enable?missing_ok=1&name=old&type=CNAME"},
} {
got = ""
root := rootCmd()
root.SetArgs(append(tc.args, "--server", srv.URL, "--token", "jarl_test_token", "-o", "json"))
root.SetOut(io.Discard)
if err := root.Execute(); err != nil {
t.Errorf("%v: %v", tc.args, err)
continue
}
if got != tc.want {
t.Errorf("%v sent %q, want %q", tc.args, got, tc.want)
}
}
}
func TestListQueries(t *testing.T) {
var got string
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {