mirror of
https://gitlab.nic.cz/knot/knot-dns.git
synced 2026-06-08 16:12:37 -04:00
external-validation: implemented configurable timeout
This commit is contained in:
parent
965f9e1ecf
commit
3900b8cbd7
7 changed files with 94 additions and 4 deletions
|
|
@ -2559,6 +2559,7 @@ External zone validation configuration.
|
|||
|
||||
external:
|
||||
- id: STR
|
||||
timeout: TIME
|
||||
dump-new-zone: STR
|
||||
dump-removals: STR
|
||||
dump-additions: STR
|
||||
|
|
@ -2570,6 +2571,16 @@ id
|
|||
|
||||
An external section identifier.
|
||||
|
||||
.. _external_timeout:
|
||||
|
||||
timeout
|
||||
-------
|
||||
|
||||
If the validation is not confirmed within this time interval in seconds,
|
||||
it is considered failed.
|
||||
|
||||
*Default:* ``300``
|
||||
|
||||
.. _external_dump-new-zone:
|
||||
|
||||
dump-new-zone
|
||||
|
|
|
|||
|
|
@ -6,8 +6,11 @@
|
|||
#include "semaphore.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
|
|
@ -66,6 +69,52 @@ void knot_sem_wait(knot_sem_t *sem)
|
|||
}
|
||||
}
|
||||
|
||||
static void timespec_now_shift(struct timespec *ts, unsigned long shift_ms)
|
||||
{
|
||||
clock_gettime(CLOCK_REALTIME, ts);
|
||||
uint64_t nsec = ts->tv_nsec + shift_ms * 1000000LU;
|
||||
ts->tv_sec += nsec / 1000000000LU;
|
||||
ts->tv_nsec = nsec % 1000000000LU;
|
||||
}
|
||||
|
||||
static bool timespec_past(const struct timespec *ts)
|
||||
{
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
return ts->tv_sec == now.tv_sec ? ts->tv_nsec <= now.tv_nsec : ts->tv_sec < now.tv_sec;
|
||||
}
|
||||
|
||||
bool knot_sem_timedwait(knot_sem_t *sem, unsigned long ms)
|
||||
{
|
||||
assert(sem != NULL);
|
||||
if (ms == 0) {
|
||||
knot_sem_wait(sem);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct timespec end;
|
||||
timespec_now_shift(&end, ms);
|
||||
if (sem->status == SEM_STATUS_POSIX) {
|
||||
int semret;
|
||||
do {
|
||||
semret = sem_timedwait(&sem->semaphore, &end);
|
||||
} while (semret != 0 && errno != ETIMEDOUT); // repeat wait as it might be interrupted by a signal
|
||||
return (semret == 0);
|
||||
} else {
|
||||
pthread_mutex_lock(&sem->status_lock->mutex);
|
||||
while (sem->status <= 0 && !timespec_past(&end)) {
|
||||
pthread_cond_timedwait(&sem->status_lock->cond, &sem->status_lock->mutex, &end);
|
||||
}
|
||||
if (sem->status <= 0) {
|
||||
pthread_mutex_unlock(&sem->status_lock->mutex);
|
||||
return false;
|
||||
}
|
||||
sem->status--;
|
||||
pthread_mutex_unlock(&sem->status_lock->mutex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void knot_sem_wait_post(knot_sem_t *sem)
|
||||
{
|
||||
assert((sem != NULL) && (sem->status != SEM_STATUS_POSIX));
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
pthread_mutex_t mutex;
|
||||
|
|
@ -42,6 +43,16 @@ void knot_sem_reset(knot_sem_t *sem, int value);
|
|||
*/
|
||||
void knot_sem_wait(knot_sem_t *sem);
|
||||
|
||||
/*!
|
||||
* \brief Lock the semaphore (decrement), block until it's non-negative but only for specified timeout.
|
||||
*
|
||||
* \param sem Semapthore.
|
||||
* \param ms Timeout in milliseconds or 0 for infinity (same as knot_sem_wait).
|
||||
*
|
||||
* \return True if semaphore acquired, false if timeout passed.
|
||||
*/
|
||||
bool knot_sem_timedwait(knot_sem_t *sem, unsigned long ms);
|
||||
|
||||
/*!
|
||||
* \brief Block until the semaphore could decrement, but keep the value unchanged.
|
||||
* \note This can be only used with nonposix semaphore.
|
||||
|
|
|
|||
|
|
@ -457,6 +457,7 @@ static const yp_item_t desc_policy[] = {
|
|||
|
||||
static const yp_item_t desc_external[] = {
|
||||
{ C_ID, YP_TSTR, YP_VNONE, CONF_IO_FREF },
|
||||
{ C_TIMEOUT, YP_TINT, YP_VINT = { 0, UINT32_MAX, 300, YP_STIME } },
|
||||
{ C_DUMP_NEW, YP_TSTR, YP_VSTR = { "" } },
|
||||
{ C_DUMP_REM, YP_TSTR, YP_VSTR = { "" } },
|
||||
{ C_DUMP_ADD, YP_TSTR, YP_VSTR = { "" } },
|
||||
|
|
|
|||
|
|
@ -1005,7 +1005,8 @@ int zone_update_external(conf_t *conf, zone_update_t *update, conf_val_t *ev_id)
|
|||
dbus_emit_external_verify(update->zone->name);
|
||||
}
|
||||
|
||||
knot_sem_wait(&update->external);
|
||||
val = conf_id_get(conf, C_EXTERNAL, C_TIMEOUT, ev_id);
|
||||
knot_sem_timedwait(&update->external, conf_int(&val) * 1000);
|
||||
|
||||
pthread_mutex_lock(&update->zone->cu_lock);
|
||||
update->zone->control_update = NULL;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,10 @@ ZONE = zone[0].name
|
|||
LOG = "for external validation"
|
||||
|
||||
slave.async_start = True
|
||||
slave.zones[ZONE].external = { "new": dump_file(slave, "new"), "rem": dump_file(slave, "diff"), "add": dump_file(slave, "diff") }
|
||||
slave.zones[ZONE].external = { "timeout": "10",
|
||||
"new": dump_file(slave, "new"),
|
||||
"rem": dump_file(slave, "diff"),
|
||||
"add": dump_file(slave, "diff") }
|
||||
|
||||
def check_diff_types(types):
|
||||
check_zf_types(slave.zones[ZONE].external["add"], types)
|
||||
|
|
@ -83,20 +86,33 @@ resp = ctl.receive_block()
|
|||
t.sleep(2)
|
||||
resp = slave.dig(ZONE, "SOA")
|
||||
resp.check_soa_serial(serial - 1)
|
||||
ctl.close()
|
||||
|
||||
up = master.update(zone)
|
||||
up.add("snail", 3600, "AAAA", "1::1")
|
||||
up.send()
|
||||
serial = master.zone_wait(zone, serial)
|
||||
t.sleep(2)
|
||||
log_count_expect(slave, LOG, 3)
|
||||
t.sleep(int(slave.zones[ZONE].external["timeout"]))
|
||||
resp = slave.dig(ZONE, "SOA")
|
||||
resp.check_soa_serial(serial - 2)
|
||||
|
||||
up = master.update(zone)
|
||||
up.add("shark", 3600, "AAAA", "1::1")
|
||||
up.send()
|
||||
serial = master.zone_wait(zone, serial)
|
||||
|
||||
ctl.connect(os.path.join(slave.dir, sockname))
|
||||
t.sleep(2)
|
||||
log_count_expect(slave, LOG, 3)
|
||||
log_count_expect(slave, LOG, 4)
|
||||
ctl.send_block(cmd="zone-diff", zone=ZONE)
|
||||
resp = ctl.receive_block()
|
||||
isset("AAAA" in resp[ZONE]["horse."+ZONE], "ZONE-DIFF 2")
|
||||
isset("AAAA" in resp[ZONE]["shark."+ZONE], "ZONE-DIFF 3")
|
||||
isset("AAAA" in resp[ZONE]["snail."+ZONE], "ZONE-DIFF 3.5")
|
||||
isset("AAAA" in resp[ZONE]["tiger."+ZONE], "ZONE-DIFF 4")
|
||||
check_diff_types(["SOA", "SOA", "AAAA", "AAAA", "AAAA"])
|
||||
check_diff_types(["SOA", "SOA", "AAAA", "AAAA", "AAAA", "AAAA"])
|
||||
ctl.send_block(cmd="zone-commit", zone=ZONE)
|
||||
resp = ctl.receive_block()
|
||||
t.sleep(2)
|
||||
|
|
|
|||
|
|
@ -1799,6 +1799,7 @@ class Knot(Server):
|
|||
s.begin("external")
|
||||
have_external = True
|
||||
s.id_item("id", z.name)
|
||||
self._str(s, "timeout", z.external["timeout"])
|
||||
self._str(s, "dump-new-zone", z.external["new"])
|
||||
self._str(s, "dump-removals", z.external["rem"])
|
||||
self._str(s, "dump-additions", z.external["add"])
|
||||
|
|
|
|||
Loading…
Reference in a new issue