From f0cc1706e2c605ad36d7d5e55df5de2e458f6237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Va=C5=A1ek?= Date: Tue, 25 Nov 2025 16:59:51 +0100 Subject: [PATCH] purge: start using keys purge --- doc/man_knotc.rst | 13 +++++++------ src/knot/ctl/commands.c | 21 +++++++++++++++++++-- src/knot/zone/zone.c | 10 ++++++++++ src/knot/zone/zone.h | 4 ++-- tests-extra/tests/dnssec/shared_ksk/test.py | 2 +- 5 files changed, 39 insertions(+), 11 deletions(-) diff --git a/doc/man_knotc.rst b/doc/man_knotc.rst index 6b4015221..152df0ee9 100644 --- a/doc/man_knotc.rst +++ b/doc/man_knotc.rst @@ -297,12 +297,13 @@ Actions **zone-purge** *zone*... [**+orphan**] [*filter*...] Purge zone data, zone file, journal, timers, and/or KASP data of specified zones. Available filters are **+expire**, **+zonefile**, **+journal**, **+timers**, - **+kaspdb**, and **+catalog**. If no filter is specified, all filters are enabled. - If the zone is no longer configured, add **+orphan** parameter (zone file cannot - be purged in this case). When purging orphans, always check the server log for - possible errors. For proper operation, it's necessary to prevent ongoing changes - to the zone and triggering of zone related events during purge; use of - **zone-freeze** is advisable. This command always requires the force option. (#) + **+keys**, **+kaspdb**, and **+catalog**. If no filter is specified, all filters + are enabled, except for **+keys**, which must be listed explicitly. If the zone is + no longer configured, add **+orphan** parameter (zone file cannot be purged in this + case). When purging orphans, always check the server log for possible errors. For proper + operation, it's necessary to prevent ongoing changes to the zone and triggering of zone + related events during purge; use of **zone-freeze** is advisable. This command always + requires the force option. (#) .. _knotc_zone-stats: diff --git a/src/knot/ctl/commands.c b/src/knot/ctl/commands.c index 8f6965ff6..179a4f610 100644 --- a/src/knot/ctl/commands.c +++ b/src/knot/ctl/commands.c @@ -1660,8 +1660,8 @@ static int purge_orphan_member_cb(const knot_dname_t *member, const knot_dname_t orphan->server = server; const purge_flag_t params = - PURGE_ZONE_TIMERS | PURGE_ZONE_JOURNAL | PURGE_ZONE_KASPDB | - PURGE_ZONE_BEST | PURGE_ZONE_LOG; + PURGE_ZONE_TIMERS | PURGE_ZONE_JOURNAL | PURGE_ZONE_KEYS | + PURGE_ZONE_KASPDB | PURGE_ZONE_BEST | PURGE_ZONE_LOG; int ret = selective_zone_purge(conf(), orphan, params); free(orphan); @@ -1745,6 +1745,13 @@ static int orphans_purge(ctl_args_t *args) bool failed = false; if (args->data[KNOT_CTL_IDX_ZONE] == NULL) { + // Purge keys. (It needs to be requested explicitly.) + if (MATCH_AND_FILTER(args, CTL_FILTER_PURGE_KEYS)) { + ret = kasp_db_sweep_keys(&args->server->kaspdb, + zone_exists, args->server->zone_db); + log_if_orphans_error(NULL, ret, "keys", &failed); + } + // Purge KASP DB. if (only_orphan || MATCH_AND_FILTER(args, CTL_FILTER_PURGE_KASPDB)) { ret = kasp_db_sweep(&args->server->kaspdb, @@ -1792,6 +1799,14 @@ static int orphans_purge(ctl_args_t *args) knot_dname_to_lower(zone_name); if (!zone_exists(zone_name, args->server->zone_db)) { + // Purge keys. (It needs to be requested explicitly.) + if (MATCH_AND_FILTER(args, CTL_FILTER_PURGE_KEYS)) { + if (knot_lmdb_open(&args->server->kaspdb) == KNOT_EOK) { + ret = kasp_db_delete_keys(&args->server->kaspdb, zone_name, true, false); + log_if_orphans_error(zone_name, ret, "keys", &failed); + } + } + // Purge KASP DB. if (only_orphan || MATCH_AND_FILTER(args, CTL_FILTER_PURGE_KASPDB)) { if (knot_lmdb_open(&args->server->kaspdb) == KNOT_EOK) { @@ -1852,6 +1867,8 @@ static int zone_purge(zone_t *zone, ctl_args_t *args) MATCH_OR_FILTER(args, CTL_FILTER_PURGE_KASPDB) * PURGE_ZONE_KASPDB | MATCH_OR_FILTER(args, CTL_FILTER_PURGE_CATALOG) * PURGE_ZONE_CATALOG | MATCH_OR_FILTER(args, CTL_FILTER_PURGE_EXPIRE) * PURGE_ZONE_EXPIRE | + // Keys purge must be requested explicitly. + MATCH_AND_FILTER(args, CTL_FILTER_PURGE_KEYS) * PURGE_ZONE_KEYS | PURGE_ZONE_NOSYNC; // Purge even zonefiles with disabled syncing. zone_set_flag(zone, (zone_flag_t)params); diff --git a/src/knot/zone/zone.c b/src/knot/zone/zone.c index f4c4eb8bc..a029a0954 100644 --- a/src/knot/zone/zone.c +++ b/src/knot/zone/zone.c @@ -345,6 +345,16 @@ int selective_zone_purge(conf_t *conf, zone_t *zone, purge_flag_t params) RETURN_IF_FAILED("journal", KNOT_ENOENT); } + // Purge keys and related metadata. + if (params & PURGE_ZONE_KEYS) { + ret = knot_lmdb_open(zone_kaspdb(zone)); + if (ret == KNOT_EOK) { + ret = kasp_db_delete_keys(zone_kaspdb(zone), zone->name, + false, !exit_immediately); + } + RETURN_IF_FAILED("keys", KNOT_ENOENT); + } + // Purge KASP DB. if (params & PURGE_ZONE_KASPDB) { ret = knot_lmdb_open(zone_kaspdb(zone)); diff --git a/src/knot/zone/zone.h b/src/knot/zone/zone.h index f4b7fa7f6..15f3d89d8 100644 --- a/src/knot/zone/zone.h +++ b/src/knot/zone/zone.h @@ -74,8 +74,8 @@ typedef enum { #define PURGE_ZONE_DATA (PURGE_ZONE_TIMERS | PURGE_ZONE_ZONEFILE | PURGE_ZONE_JOURNAL | \ PURGE_ZONE_KASPDB | PURGE_ZONE_CATALOG) -/*!< Standard purge (respect C_ZONEFILE_SYNC param). */ -#define PURGE_ZONE_ALL (PURGE_ZONE_DATA | PURGE_ZONE_BEST | PURGE_ZONE_LOG) +/*!< Standard purge (including keys; respect C_ZONEFILE_SYNC param). */ +#define PURGE_ZONE_ALL (PURGE_ZONE_DATA | PURGE_ZONE_KEYS | PURGE_ZONE_BEST | PURGE_ZONE_LOG) /*!< All purge-related flags. */ #define PURGE_ZONE_FLAGS (PURGE_ZONE_ALL | PURGE_ZONE_NOSYNC | PURGE_ZONE_EXPIRE) diff --git a/tests-extra/tests/dnssec/shared_ksk/test.py b/tests-extra/tests/dnssec/shared_ksk/test.py index 07fb5b872..6bc930508 100644 --- a/tests-extra/tests/dnssec/shared_ksk/test.py +++ b/tests-extra/tests/dnssec/shared_ksk/test.py @@ -61,7 +61,7 @@ check_ksks(knot, zones0 + zones_add1, zones0[1]) # now purge zones keys in order to create dangling policy_last for z in zones0: - knot.ctl("zone-purge -f +kaspdb " + z.name) + knot.ctl("zone-purge -f +keys " + z.name) zones_add2 = t.zone_rnd(5, dnssec=False, records=10) add_shared(t, knot, zones_add2, zones0[0])