Commit 465caf49 authored by Libor Peltan's avatar Libor Peltan Committed by Daniel Salzman

events+ctl: freeze-thaw events implemented

parent 66b0f287
......@@ -256,6 +256,7 @@ src/knot/events/handlers.h
src/knot/events/handlers/dnssec.c
src/knot/events/handlers/expire.c
src/knot/events/handlers/flush.c
src/knot/events/handlers/freeze_thaw.c
src/knot/events/handlers/load.c
src/knot/events/handlers/notify.c
src/knot/events/handlers/refresh.c
......
......@@ -145,6 +145,13 @@ Purge zone data, file, journal, and timers.
Show zone statistics counter(s). To print also counters with value 0, use
force option.
.TP
\fBzone\-freeze\fP [\fIzone\fP\&...]
Temporarily postpone zone\-changing events (load, refresh, update, flush, and
DNSSEC signing).
.TP
\fBzone\-thaw\fP [\fIzone\fP\&...]
Dismiss zone freeze.
.TP
\fBconf\-init\fP
Initialize the configuration database. (*)
.TP
......
......@@ -122,6 +122,13 @@ Actions
Show zone statistics counter(s). To print also counters with value 0, use
force option.
**zone-freeze** [*zone*...]
Temporarily postpone zone-changing events (load, refresh, update, flush, and
DNSSEC signing).
**zone-thaw** [*zone*...]
Dismiss zone freeze.
**conf-init**
Initialize the configuration database. (*)
......
......@@ -269,6 +269,7 @@ libknotd_la_SOURCES = \
knot/events/handlers/dnssec.c \
knot/events/handlers/expire.c \
knot/events/handlers/flush.c \
knot/events/handlers/freeze_thaw.c \
knot/events/handlers/load.c \
knot/events/handlers/notify.c \
knot/events/handlers/refresh.c \
......
/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -258,7 +258,7 @@ static int zone_reload(zone_t *zone, ctl_args_t *args)
return KNOT_ENOTSUP;
}
zone_events_schedule_now(zone, ZONE_EVENT_LOAD);
zone_events_schedule_user(zone, ZONE_EVENT_LOAD);
return KNOT_EOK;
}
......@@ -271,7 +271,7 @@ static int zone_refresh(zone_t *zone, ctl_args_t *args)
return KNOT_ENOTSUP;
}
zone_events_schedule_now(zone, ZONE_EVENT_REFRESH);
zone_events_schedule_user(zone, ZONE_EVENT_REFRESH);
return KNOT_EOK;
}
......@@ -285,7 +285,7 @@ static int zone_retransfer(zone_t *zone, ctl_args_t *args)
}
zone->flags |= ZONE_FORCE_AXFR;
zone_events_schedule_now(zone, ZONE_EVENT_REFRESH);
zone_events_schedule_user(zone, ZONE_EVENT_REFRESH);
return KNOT_EOK;
}
......@@ -298,7 +298,7 @@ static int zone_flush(zone_t *zone, ctl_args_t *args)
zone->flags |= ZONE_FORCE_FLUSH;
}
zone_events_schedule_now(zone, ZONE_EVENT_FLUSH);
zone_events_schedule_user(zone, ZONE_EVENT_FLUSH);
return KNOT_EOK;
}
......@@ -313,7 +313,25 @@ static int zone_sign(zone_t *zone, ctl_args_t *args)
}
zone->flags |= ZONE_FORCE_RESIGN;
zone_events_schedule_now(zone, ZONE_EVENT_DNSSEC);
zone_events_schedule_user(zone, ZONE_EVENT_DNSSEC);
return KNOT_EOK;
}
static int zone_freeze(zone_t *zone, ctl_args_t *args)
{
UNUSED(args);
zone_events_schedule_now(zone, ZONE_EVENT_UFREEZE);
return KNOT_EOK;
}
static int zone_thaw(zone_t *zone, ctl_args_t *args)
{
UNUSED(args);
zone_events_schedule_now(zone, ZONE_EVENT_UTHAW);
return KNOT_EOK;
}
......@@ -1099,6 +1117,10 @@ static int ctl_zone(ctl_args_t *args, ctl_cmd_t cmd)
return zones_apply(args, zone_flush);
case CTL_ZONE_SIGN:
return zones_apply(args, zone_sign);
case CTL_ZONE_FREEZE:
return zones_apply(args, zone_freeze);
case CTL_ZONE_THAW:
return zones_apply(args, zone_thaw);
case CTL_ZONE_READ:
return zones_apply(args, zone_read);
case CTL_ZONE_BEGIN:
......@@ -1485,6 +1507,8 @@ static const desc_t cmd_table[] = {
[CTL_ZONE_RETRANSFER] = { "zone-retransfer", ctl_zone },
[CTL_ZONE_FLUSH] = { "zone-flush", ctl_zone },
[CTL_ZONE_SIGN] = { "zone-sign", ctl_zone },
[CTL_ZONE_FREEZE] = { "zone-freeze", ctl_zone },
[CTL_ZONE_THAW] = { "zone-thaw", ctl_zone },
[CTL_ZONE_READ] = { "zone-read", ctl_zone },
[CTL_ZONE_BEGIN] = { "zone-begin", ctl_zone },
......
/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -46,7 +46,8 @@ typedef enum {
CTL_ZONE_RETRANSFER,
CTL_ZONE_FLUSH,
CTL_ZONE_SIGN,
CTL_ZONE_STATS,
CTL_ZONE_FREEZE,
CTL_ZONE_THAW,
CTL_ZONE_READ,
CTL_ZONE_BEGIN,
......@@ -57,6 +58,7 @@ typedef enum {
CTL_ZONE_SET,
CTL_ZONE_UNSET,
CTL_ZONE_PURGE,
CTL_ZONE_STATS,
CTL_CONF_LIST,
CTL_CONF_READ,
......
/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -44,6 +44,8 @@ static const event_info_t EVENT_INFO[] = {
{ ZONE_EVENT_FLUSH, event_flush, "journal flush" },
{ ZONE_EVENT_NOTIFY, event_notify, "notify" },
{ ZONE_EVENT_DNSSEC, event_dnssec, "DNSSEC resign" },
{ ZONE_EVENT_UFREEZE, event_ufreeze, "update freeze" },
{ ZONE_EVENT_UTHAW, event_uthaw, "update thaw" },
{ 0 }
};
......@@ -65,6 +67,20 @@ static bool valid_event(zone_event_type_t type)
return (type > ZONE_EVENT_INVALID && type < ZONE_EVENT_COUNT);
}
static bool ufreeze_applies(zone_event_type_t type)
{
switch (type) {
case ZONE_EVENT_LOAD:
case ZONE_EVENT_REFRESH:
case ZONE_EVENT_UPDATE:
case ZONE_EVENT_FLUSH:
case ZONE_EVENT_DNSSEC:
return true;
default:
return false;
}
}
/*! \brief Return remaining time to planned event (seconds). */
static time_t time_until(time_t planned)
{
......@@ -97,6 +113,10 @@ static time_t event_get_time(zone_events_t *events, zone_event_type_t type)
/*!
* \brief Find next scheduled zone event.
*
* \note Afer the UTHAW event, get_next_event() is also invoked. In that situation,
* all the events are suddenly allowed, and those which were planned into
* the ufrozen interval, start to be performed one-by-one sorted by their times.
*
* \param events Zone events.
*
* \return Zone event type, or ZONE_EVENT_INVALID if no event is scheduled.
......@@ -112,11 +132,9 @@ static zone_event_type_t get_next_event(zone_events_t *events)
for (int i = 0; i < ZONE_EVENT_COUNT; i++) {
time_t current = events->time[i];
if (current == 0) {
continue;
}
if (next == 0 || current < next) {
if ((next == 0 || current < next) && (current != 0) &&
(events->forced[i] || !events->ufrozen || !ufreeze_applies(i))) {
next = current;
next_type = i;
}
......@@ -162,7 +180,7 @@ static void reschedule(zone_events_t *events)
* \brief Zone event wrapper, expected to be called from a worker thread.
*
* 1. Takes the next planned event.
* 2. Resets the event's scheduled time.
* 2. Resets the event's scheduled time (and forced flag).
* 3. Perform the event's callback.
* 4. Schedule next event planned event.
*/
......@@ -182,6 +200,7 @@ static void event_wrap(task_t *task)
return;
}
event_set_time(events, type, 0);
events->forced[type] = false;
pthread_mutex_unlock(&events->mx);
const event_info_t *info = get_event_info(type);
......@@ -310,6 +329,25 @@ void _zone_events_schedule_at(zone_t *zone, ...)
va_end(args);
}
void zone_events_schedule_user(zone_t *zone, zone_event_type_t type)
{
if (!zone || !valid_event(type)) {
return;
}
zone_events_t *events = &zone->events;
pthread_mutex_lock(&events->mx);
events->forced[type] = true;
pthread_mutex_unlock(&events->mx);
zone_events_schedule_now(zone, type);
pthread_mutex_lock(&events->mx);
// reschedule because get_next_event result changed outside of _zone_events_schedule_at
reschedule(events);
pthread_mutex_unlock(&events->mx);
}
void zone_events_enqueue(zone_t *zone, zone_event_type_t type)
{
if (!zone || !valid_event(type)) {
......@@ -321,7 +359,8 @@ void zone_events_enqueue(zone_t *zone, zone_event_type_t type)
pthread_mutex_lock(&events->mx);
/* Bypass scheduler if no event is running. */
if (!events->running && !events->frozen) {
if (!events->running && !events->frozen &&
(!events->ufrozen || !ufreeze_applies(type))) {
events->running = true;
event_set_time(events, type, ZONE_EVENT_IMMEDIATE);
worker_pool_assign(events->pool, &events->task);
......
/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -37,6 +37,8 @@ typedef enum zone_event_type {
ZONE_EVENT_FLUSH,
ZONE_EVENT_NOTIFY,
ZONE_EVENT_DNSSEC,
ZONE_EVENT_UFREEZE,
ZONE_EVENT_UTHAW,
// terminator
ZONE_EVENT_COUNT,
} zone_event_type_t;
......@@ -45,6 +47,7 @@ typedef struct zone_events {
pthread_mutex_t mx; //!< Mutex protecting the struct.
bool running; //!< Some zone event is being run.
bool frozen; //!< Terminated, don't schedule new events.
bool ufrozen; //!< Updates to the zone temporarily frozen by user.
event_t *event; //!< Scheduler event.
worker_pool_t *pool; //!< Server worker pool.
......@@ -52,6 +55,7 @@ typedef struct zone_events {
task_t task; //!< Event execution context.
time_t time[ZONE_EVENT_COUNT]; //!< Event execution times.
bool forced[ZONE_EVENT_COUNT]; //!< Flag that the event was invoked by user ctl.
} zone_events_t;
/*!
......@@ -124,6 +128,11 @@ void _zone_events_schedule_at(struct zone *zone, ...);
#define zone_events_schedule_now(zone, type) \
zone_events_schedule_at(zone, type, time(NULL))
/*!
* \brief Schedule zone event to now, with forced flag.
*/
void zone_events_schedule_user(struct zone *zone, zone_event_type_t type);
/*!
* \brief Freeze all zone events and prevent new events from running.
*
......
/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -33,3 +33,7 @@ int event_flush(conf_t *conf, zone_t *zone);
int event_notify(conf_t *conf, zone_t *zone);
/*! \brief Signs the zone using its DNSSEC keys. */
int event_dnssec(conf_t *conf, zone_t *zone);
/*! \brief Freeze those events causing zone contents change. */
int event_ufreeze(conf_t *conf, zone_t *zone);
/*! \brief Unfreeze zone updates. */
int event_uthaw(conf_t *conf, zone_t *zone);
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "contrib/macros.h"
#include "knot/events/events.h"
#include "knot/conf/conf.h"
#include "knot/zone/zone.h"
#include "knot/common/log.h"
int event_ufreeze(conf_t *conf, zone_t *zone)
{
UNUSED(conf);
assert(zone);
pthread_mutex_lock(&zone->events.mx);
zone->events.ufrozen = true;
pthread_mutex_unlock(&zone->events.mx);
log_zone_info(zone->name, "zone updates frozen");
return KNOT_EOK;
}
int event_uthaw(conf_t *conf, zone_t *zone)
{
UNUSED(conf);
assert(zone);
pthread_mutex_lock(&zone->events.mx);
zone->events.ufrozen = false;
pthread_mutex_unlock(&zone->events.mx);
log_zone_info(zone->name, "zone updates unfrozen");
return KNOT_EOK;
}
/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -46,6 +46,8 @@
#define CMD_ZONE_RETRANSFER "zone-retransfer"
#define CMD_ZONE_FLUSH "zone-flush"
#define CMD_ZONE_SIGN "zone-sign"
#define CMD_ZONE_FREEZE "zone-freeze"
#define CMD_ZONE_THAW "zone-thaw"
#define CMD_ZONE_READ "zone-read"
#define CMD_ZONE_BEGIN "zone-begin"
......@@ -337,6 +339,8 @@ static void format_block(ctl_cmd_t cmd, bool failed, bool empty)
case CTL_ZONE_RETRANSFER:
case CTL_ZONE_FLUSH:
case CTL_ZONE_SIGN:
case CTL_ZONE_FREEZE:
case CTL_ZONE_THAW:
case CTL_ZONE_BEGIN:
case CTL_ZONE_COMMIT:
case CTL_ZONE_ABORT:
......@@ -970,6 +974,8 @@ const cmd_desc_t cmd_table[] = {
{ CMD_ZONE_RETRANSFER, cmd_zone_ctl, CTL_ZONE_RETRANSFER, CMD_FOPT_ZONE },
{ CMD_ZONE_FLUSH, cmd_zone_ctl, CTL_ZONE_FLUSH, CMD_FOPT_ZONE },
{ CMD_ZONE_SIGN, cmd_zone_ctl, CTL_ZONE_SIGN, CMD_FOPT_ZONE },
{ CMD_ZONE_FREEZE, cmd_zone_ctl, CTL_ZONE_FREEZE, CMD_FOPT_ZONE },
{ CMD_ZONE_THAW, cmd_zone_ctl, CTL_ZONE_THAW, CMD_FOPT_ZONE },
{ CMD_ZONE_READ, cmd_zone_node_ctl, CTL_ZONE_READ, CMD_FREQ_ZONE },
{ CMD_ZONE_BEGIN, cmd_zone_ctl, CTL_ZONE_BEGIN, CMD_FREQ_ZONE | CMD_FOPT_ZONE },
......@@ -1014,6 +1020,8 @@ static const cmd_help_t cmd_help_table[] = {
{ CMD_ZONE_RETRANSFER, "[<zone>...]", "Force slave zone retransfer (no serial check)." },
{ CMD_ZONE_FLUSH, "[<zone>...]", "Flush zone journal into the zone file." },
{ CMD_ZONE_SIGN, "[<zone>...]", "Re-sign the automatically signed zone." },
{ CMD_ZONE_FREEZE, "[<zone>...]", "Temporarily postpone automatic zone-changing events." },
{ CMD_ZONE_THAW, "[<zone>...]", "Dismiss zone freeze." },
{ "", "", "" },
{ CMD_ZONE_READ, "<zone> [<owner> [<type>]]", "Get zone data that are currently being presented." },
{ CMD_ZONE_BEGIN, "<zone>...", "Begin a zone transaction." },
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment