}
}
+static bool same_group(zone_t *old_z, zone_t *new_z)
+{
+ if (old_z->catalog_group == NULL || new_z->catalog_group == NULL) {
+ return (old_z->catalog_group == new_z->catalog_group);
+ } else {
+ return (strcmp(old_z->catalog_group, new_z->catalog_group) == 0);
+ }
+}
+
static knot_zonedb_t *create_zonedb_commit(conf_t *conf, server_t *server)
{
knot_zonedb_t *db_old = server->zone_db; // If NULL, zonedb is beeing initialized.
}
}
knot_zonedb_insert(db_new, zone);
+ catalog_generate_add(zone, db_new, false);
reg_reverse(conf, db_new, zone);
} else if (type & CONF_IO_TUNSET) {
+ zone_t *zone = knot_zonedb_find(db_new, name);
knot_zonedb_del(db_new, name);
+ catalog_generate_rem(zone, db_new);
} else {
zone_t *zone = knot_zonedb_find(db_new, name);
+ zone_t *old = knot_zonedb_find(db_old, name);
+ if (!same_group(old, zone)) {
+ catalog_generate_add(zone, db_new, true);
+ }
reg_reverse(conf, db_new, zone);
}
}
case CAT_UPD_ADD:
zone = add_member_zone(upd, db_new, server, conf);
knot_zonedb_insert(db_new, zone);
+ catalog_generate_add(zone, db_new, false);
reg_reverse(conf, db_new, zone);
break;
case CAT_UPD_REM:
+ zone = knot_zonedb_find(db_new, upd->member);
knot_zonedb_del(db_new, upd->member);
+ catalog_generate_rem(zone, db_new);
break;
case CAT_UPD_UNIQ:
case CAT_UPD_PROP:
ptrlist_add(expired_contents, zone_expire(zone, true), NULL);
knot_sem_post(&zone->cow_lock);
}
+ zone_t *old = knot_zonedb_find(db_old, upd->member);
+ if (!same_group(old, zone)) {
+ catalog_generate_add(zone, db_new, true);
+ }
reg_reverse(conf, db_new, zone);
break;
default:
return db_new;
}
-static bool same_group(zone_t *old_z, zone_t *new_z)
-{
- if (old_z->catalog_group == NULL || new_z->catalog_group == NULL) {
- return (old_z->catalog_group == new_z->catalog_group);
- } else {
- return (strcmp(old_z->catalog_group, new_z->catalog_group) == 0);
- }
-}
-
-static void catalogs_generate(struct knot_zonedb *db_new, struct knot_zonedb *db_old)
-{
- if (db_old != NULL) {
- knot_zonedb_iter_t *it = knot_zonedb_iter_begin(db_old);
- for (; !knot_zonedb_iter_finished(it); knot_zonedb_iter_next(it)) {
- zone_t *zone = knot_zonedb_iter_val(it);
- if (knot_zonedb_find(db_new, zone->name) == NULL) {
- catalog_generate_rem(zone, db_new);
- }
- }
- knot_zonedb_iter_free(it);
- }
-
- knot_zonedb_iter_t *it = knot_zonedb_iter_begin(db_new);
- for (; !knot_zonedb_iter_finished(it); knot_zonedb_iter_next(it)) {
- zone_t *zone = knot_zonedb_iter_val(it);
- zone_t *old = knot_zonedb_find(db_old, zone->name);
- if (old == NULL) {
- catalog_generate_add(zone, db_new, false);
- } else if (!same_group(zone, old)) {
- catalog_generate_add(zone, db_new, true);
- }
- }
- knot_zonedb_iter_free(it);
-}
-
static knot_zonedb_t *create_zonedb_full(conf_t *conf, server_t *server,
list_t *expired_contents)
{
}
catalog_it_free(cat_it);
+ /* Update generated catalogs - remove members. */
+ if (db_old != NULL) {
+ knot_zonedb_iter_t *db_it = knot_zonedb_iter_begin(db_old);
+ for (; !knot_zonedb_iter_finished(db_it); knot_zonedb_iter_next(db_it)) {
+ zone_t *zone = knot_zonedb_iter_val(db_it);
+ if (knot_zonedb_find(db_new, zone->name) == NULL) {
+ catalog_generate_rem(zone, db_new);
+ }
+ }
+ knot_zonedb_iter_free(db_it);
+ }
+
+ /* Update generated catalogs - add members, updated reversed zones. */
knot_zonedb_iter_t *db_it = knot_zonedb_iter_begin(db_new);
for (; !knot_zonedb_iter_finished(db_it); knot_zonedb_iter_next(db_it)) {
zone_t *zone = knot_zonedb_iter_val(db_it);
+ zone_t *old = knot_zonedb_find(db_old, zone->name);
+ if (old == NULL) {
+ catalog_generate_add(zone, db_new, false);
+ } else if (!same_group(old, zone)) {
+ catalog_generate_add(zone, db_new, true);
+ }
reg_reverse(conf, db_new, zone);
}
knot_zonedb_iter_free(db_it);
return;
}
- // TODO: optimize within create_zonedb.
- catalogs_generate(db_new, server->zone_db);
-
/* Switch the databases. */
knot_zonedb_t **db_current = &server->zone_db;
knot_zonedb_t *db_old = rcu_xchg_pointer(db_current, db_new);
'''Test of Catalog zone generation.'''
from dnstest.test import Test
-from dnstest.utils import set_err, detail_log
+from dnstest.utils import compare, set_err, detail_log
+from dnstest.libknot import libknot
import os
import random
+import shutil
import time
+USE_CTL = random.choice([True, False, False])
+
t = Test()
-def wait_for_zonefile(server, role, zonename, max_age, timeout):
- fn = os.path.join(server.dir, role, zonename + "zone")
+def wait_for_zonefile(server, zonename, max_age, timeout):
+ fn = os.path.join(server.dir, "catalog", zonename + "zone")
while timeout > 0:
if os.path.exists(fn):
age = time.time() - os.path.getmtime(fn)
slave.dnssec(catz[0]).enable = True
slave.dnssec(catz[0]).single_type_signing = True
+def ctl_begin():
+ ctl = libknot.control.KnotCtl()
+ ctl.connect(os.path.join(master.dir, "knot.sock"))
+ ctl.send_block(cmd="conf-begin")
+ resp = ctl.receive_block()
+ return ctl
+
+def ctl_end(ctl):
+ ctl.send_block(cmd="conf-commit")
+ resp = ctl.receive_block()
+ ctl.send(libknot.control.KnotCtlType.END)
+ ctl.close()
+
+def ctl_add_zone(ctl, zone_name):
+ ctl.send_block(cmd="conf-set", section="zone", item="domain", data=zone_name)
+ resp = ctl.receive_block()
+ ctl.send_block(cmd="conf-set", section="zone", item="template", identifier=zone_name, data="catalog-default")
+ resp = ctl.receive_block()
+ ctl.send_block(cmd="conf-set", section="zone", item="catalog-zone", identifier=zone_name, data=catz[0].name)
+ resp = ctl.receive_block()
+ ctl.send_block(cmd="conf-set", section="zone", item="catalog-role", identifier=zone_name, data="member")
+ resp = ctl.receive_block()
+ ctl.send_block(cmd="conf-set", section="zone", item="file", identifier=zone_name, data=os.path.join(master.dir, "generic.zone"))
+ resp = ctl.receive_block()
+
t.start()
# testcase 1: initial catalog zone with 1 member
slave.zones_wait(zone)
-# testcase 2: adding member zones online/offline
-add_online = random.choice([True, False])
-
+# testcase 2: adding member zones dynamically/online/offline
zone_add = t.zone("flags.") + t.zone("records.")
-t.link(zone_add, master, slave)
-for z in zone_add:
- master.cat_member(z, catz)
- slave.cat_hidden(z)
-
-master.gen_confile()
-
-if add_online:
- master.reload()
+if USE_CTL:
+ shutil.copy(t.data_dir + "generic.zone", os.path.join(master.dir, "generic.zone"))
+ ctl = ctl_begin()
+ ctl_add_zone(ctl, "flags.")
+ ctl_add_zone(ctl, "records.")
+ ctl_end(ctl)
else:
- master.stop()
- t.sleep(1)
- master.start()
+ t.link(zone_add, master, slave)
+ for z in zone_add:
+ master.cat_member(z, catz)
+ slave.cat_hidden(z)
+
+ master.gen_confile()
+
+ add_online = random.choice([True, False])
+ if add_online:
+ master.reload()
+ else:
+ master.stop()
+ t.sleep(1)
+ master.start()
slave.zones_wait(zone + zone_add)
-# testcase 3: removing member zone online/offline
-rem_online = random.choice([True, False])
-
+# testcase 3: removing member zone dynamically/online/offline
serial_bef_rem = slave.zone_wait(catz, tsig=True)
master.ctl("-f zone-purge example.com")
-master.zones.pop("example.com.")
-master.gen_confile()
-
-if rem_online:
- master.reload()
+if USE_CTL:
+ ctl = ctl_begin()
+ ctl.send_block(cmd="conf-unset", section="zone", item="domain", data="example.com.")
+ resp = ctl.receive_block()
+ ctl_end(ctl)
else:
- master.stop()
- t.sleep(1)
- master.start()
+ master.zones.pop("example.com.")
+ master.gen_confile()
+
+ add_online = random.choice([True, False])
+ if add_online:
+ master.reload()
+ else:
+ master.stop()
+ t.sleep(1)
+ master.start()
slave.zone_wait(catz, serial_bef_rem, tsig=True)
t.sleep(2) # allow the member zone to actually be purged
dnskey0 = resp0.resp.answer[0].to_rdataset()
slave.stop()
-temp_rem = master.zones.pop("records.")
-master.gen_confile()
-master.reload()
-t.sleep(7)
-master.ctl("-f zone-purge +orphan records.")
-master.zones["records."] = temp_rem
-master.gen_confile()
-master.reload()
+if USE_CTL:
+ ctl = ctl_begin()
+ ctl.send_block(cmd="conf-unset", section="zone", item="domain", data="records.")
+ resp = ctl.receive_block()
+ ctl_end(ctl)
+ t.sleep(7)
+ master.ctl("-f zone-purge +orphan records.")
+ ctl = ctl_begin()
+ ctl_add_zone(ctl, "records.")
+ ctl_end(ctl)
+else:
+ temp_rem = master.zones.pop("records.")
+ master.gen_confile()
+ master.reload()
+ t.sleep(7)
+ master.ctl("-f zone-purge +orphan records.")
+ master.zones["records."] = temp_rem
+ master.gen_confile()
+ master.reload()
slave.start()
-wait_for_zonefile(slave, "master", "records.", 3, 30)
+wait_for_zonefile(slave, "records.", 3, 30)
slave.ctl("zone-refresh")
-wait_for_zonefile(slave, "master", "records.", 3, 30)
+wait_for_zonefile(slave, "records.", 3, 30)
resp1 = slave.dig("records.", "DNSKEY")
resp1.check_count(1, "DNSKEY")
dnskey1 = resp1.resp.answer[0].to_rdataset()
if dnskey0 == dnskey1:
set_err("ZONE NOT PURGED")
+#testcase 5: reload and don't reload a zone depending on the config change
+if USE_CTL:
+ shutil.copy(t.data_dir + "generic.upd", os.path.join(master.dir, "generic.zone"))
+
+ ctl = ctl_begin()
+ ctl.send_block(cmd="conf-set", section="zone", identifier="flags.", item="zone-max-size", data="10000")
+ resp = ctl.receive_block()
+ ctl.send_block(cmd="conf-set", section="zone", identifier="records.", item="comment", data="don't reload")
+ resp = ctl.receive_block()
+ ctl_end(ctl)
+
+ t.sleep(2)
+ resp = master.dig("flags.", "SOA")
+ compare(resp.soa_serial(), 10, "master zone reloaded")
+ resp = master.dig("records.", "SOA")
+ compare(resp.soa_serial(), 1, "master zone not reloaded")
+ slave.zone_wait(zone_add[0], 1)
+
t.end()