Commit 5f9757a9 authored by Daniel Salzman's avatar Daniel Salzman

Merge branch 'knotc_refactor' into 'master'

Knotc refactor

See merge request !711
parents 1a35fa57 0c6a5fbc
......@@ -69,9 +69,9 @@ Print the program version.
.INDENT 0.0
.TP
\fBstatus\fP [\fIdetail\fP]
Check if the server is running.
Moreover display either the running knotd version, numbers of worker threads,
or Knot DNS buid (configure) summary, if the parameter is specified.
Check if the server is running. Details are \fBversion\fP for the running
server version, \fBworkers\fP for the numbers of worker threads,
or \fBconfigure\fP for the configure summary.
.TP
\fBstop\fP
Stop the server if running.
......@@ -85,8 +85,8 @@ Show global statistics counter(s). To print also counters with value 0, use
force option.
.TP
\fBzone\-status\fP \fIzone\fP [\fIfilter\fP]
Show the zone status. (*)
Filters are type, serial, transaction, event\-timers, and freeze with prefix \(aq+\(aq.
Show the zone status. Filters are \fB+role\fP, \fB+serial\fP, \fB+transaction\fP,
\fB+events\fP, and \fB+freeze\fP\&.
.TP
\fBzone\-check\fP [\fIzone\fP\&...]
Test if the server can load the zone. Semantic checks are executed if enabled
......@@ -109,8 +109,10 @@ newer zone, a transfer is scheduled. This command is valid for slave zones.
Trigger a zone transfer from the zone\(aqs master. The server doesn\(aqt check the
serial of the master\(aqs zone. This command is valid for slave zones.
.TP
\fBzone\-flush\fP [\fIzone\fP\&...]
Trigger a zone journal flush into the zone file.
\fBzone\-flush\fP [\fIzone\fP\&...] [\fB+outdir\fP \fIdirectory\fP]
Trigger a zone journal flush into the zone file. If output dir is specified,
instead of flushing the zonefile, the zone is dumped to a file in the specified
directory.
.TP
\fBzone\-sign\fP [\fIzone\fP\&...]
Trigger a DNSSEC re\-sign of the zone. Existing signatures will be dropped.
......@@ -141,8 +143,10 @@ requires a ttl value specified.
\fBzone\-unset\fP \fIzone\fP \fIowner\fP [\fItype\fP [\fIrdata\fP]]
Remove zone data within the transaction.
.TP
\fBzone\-purge\fP \fIzone\fP\&...
Purge zone data, file, journal, and timers.
\fBzone\-purge\fP \fIzone\fP\&... [\fIfilter\fP\&...]
Purge zone data, file, journal, timers, and kaspdb.
Filters are \fB+expire\fP, \fB+timers\fP, \fB+zonefile\fP, \fB+journal\fP,
and \fB+kaspdb\fP\&.
.TP
\fBzone\-stats\fP \fIzone\fP [\fImodule\fP[\fB\&.\fP\fIcounter\fP]]
Show zone statistics counter(s). To print also counters with value 0, use
......@@ -204,8 +208,6 @@ Use \fB@\fP \fIowner\fP to denote the zone name.
.sp
Type \fIitem\fP parameter in the form of \fIsection\fP[\fB[\fP\fIid\fP\fB]\fP][\fB\&.\fP\fIname\fP].
.sp
The \fIdetail\fP option for \fBstatus\fP can be one of words: version, workers, configure.
.sp
(*) indicates a local operation which requires a configuration.
.SS Interactive mode
.sp
......
......@@ -46,9 +46,9 @@ Actions
.......
**status** [*detail*]
Check if the server is running.
Moreover display either the running knotd version, numbers of worker threads,
or Knot DNS buid (configure) summary, if the parameter is specified.
Check if the server is running. Details are **version** for the running
server version, **workers** for the numbers of worker threads,
or **configure** for the configure summary.
**stop**
Stop the server if running.
......@@ -62,8 +62,8 @@ Actions
force option.
**zone-status** *zone* [*filter*]
Show the zone status. (*)
Filters are type, serial, transaction, event-timers, and freeze with prefix '+'.
Show the zone status. Filters are **+role**, **+serial**, **+transaction**,
**+events**, and **+freeze**.
**zone-check** [*zone*...]
Test if the server can load the zone. Semantic checks are executed if enabled
......@@ -86,8 +86,10 @@ Actions
Trigger a zone transfer from the zone's master. The server doesn't check the
serial of the master's zone. This command is valid for slave zones.
**zone-flush** [*zone*...]
Trigger a zone journal flush into the zone file.
**zone-flush** [*zone*...] [**+outdir** *directory*]
Trigger a zone journal flush into the zone file. If output dir is specified,
instead of flushing the zonefile, the zone is dumped to a file in the specified
directory.
**zone-sign** [*zone*...]
Trigger a DNSSEC re-sign of the zone. Existing signatures will be dropped.
......@@ -118,8 +120,10 @@ Actions
**zone-unset** *zone* *owner* [*type* [*rdata*]]
Remove zone data within the transaction.
**zone-purge** *zone*...
Purge zone data, file, journal, and timers.
**zone-purge** *zone*... [*filter*...]
Purge zone data, file, journal, timers, and kaspdb.
Filters are **+expire**, **+timers**, **+zonefile**, **+journal**,
and **+kaspdb**.
**zone-stats** *zone* [*module*\ [\ **.**\ *counter*\ ]]
Show zone statistics counter(s). To print also counters with value 0, use
......@@ -182,8 +186,6 @@ Use **@** *owner* to denote the zone name.
Type *item* parameter in the form of *section*\ [**[**\ *id*\ **]**\ ][**.**\ *name*].
The *detail* option for **status** can be one of words: version, workers, configure.
(*) indicates a local operation which requires a configuration.
Interactive mode
......
......@@ -26,6 +26,7 @@
#include "knot/nameserver/query_module.h"
#include "knot/updates/zone-update.h"
#include "knot/zone/timers.h"
#include "knot/zone/zonefile.h"
#include "libknot/libknot.h"
#include "libknot/yparser/yptrafo.h"
#include "contrib/macros.h"
......@@ -34,6 +35,9 @@
#include "zscanner/scanner.h"
#include "contrib/strtonum.h"
#define MATCH_FILTER(args, code) ((args)->data[KNOT_CTL_IDX_FILTER] == NULL || \
strchr((args)->data[KNOT_CTL_IDX_FILTER], (code)) != NULL)
void ctl_log_data(knot_ctl_data_t *data)
{
if (data == NULL) {
......@@ -138,68 +142,23 @@ static int zones_apply(ctl_args_t *args, int (*fcn)(zone_t *, ctl_args_t *))
return ret;
}
typedef enum {
ZONE_STATUS_INVALID = -1,
ZONE_STATUS_NONE = 0,
ZONE_STATUS_TYPE = 1,
ZONE_STATUS_SERIAL,
ZONE_STATUS_TRANSACTION,
ZONE_STATUS_EVENT_TIMERS,
ZONE_STATUS_EVENT_STATUS,
ZONE_STATUS_FREEZE,
} zone_status_param ;
static zone_status_param zone_status_param_check(const char *param)
{
if (param == NULL) {
return ZONE_STATUS_NONE;
}
if (strcmp(param, "+type") == 0) {
return ZONE_STATUS_TYPE;
}
if (strcmp(param, "+serial") == 0) {
return ZONE_STATUS_SERIAL;
}
if (strcmp(param, "+transaction") == 0) {
return ZONE_STATUS_TRANSACTION;
}
if (strcmp(param, "+event-timers") == 0) {
return ZONE_STATUS_EVENT_TIMERS;
}
if (strcmp(param, "+freeze") == 0) {
return ZONE_STATUS_FREEZE;
}
return ZONE_STATUS_INVALID;
}
static int zone_status(zone_t *zone, ctl_args_t *args)
{
// Zone name.
char name[KNOT_DNAME_TXT_MAXLEN + 1];
if (knot_dname_to_str(name, zone->name, sizeof(name)) == NULL) {
return KNOT_EINVAL;
}
knot_ctl_data_t data = {
[KNOT_CTL_IDX_ZONE] = name
[KNOT_CTL_IDX_ZONE] = name
};
zone_status_param param = zone_status_param_check(args->data[KNOT_CTL_IDX_OWNER]);
if (param == ZONE_STATUS_INVALID) {
data[KNOT_CTL_IDX_ERROR] = "Invalid parameters.";
int ret = knot_ctl_send(args->ctl, KNOT_CTL_TYPE_DATA, &data);
if (ret != KNOT_EOK) {
return ret;
}
return KNOT_EINVAL;
}
int ret;
char buff[128];
knot_ctl_type_t type = KNOT_CTL_TYPE_DATA;
// Zone type.
if (param == ZONE_STATUS_TYPE || param == ZONE_STATUS_NONE) {
data[KNOT_CTL_IDX_TYPE] = "type";
if (MATCH_FILTER(args, CTL_FILTER_STATUS_ROLE)) {
data[KNOT_CTL_IDX_TYPE] = "role";
if (zone_is_slave(conf(), zone)) {
data[KNOT_CTL_IDX_DATA] = "slave";
......@@ -214,13 +173,13 @@ static int zone_status(zone_t *zone, ctl_args_t *args)
type = KNOT_CTL_TYPE_EXTRA;
}
}
// Zone serial.
if (param == ZONE_STATUS_SERIAL || param == ZONE_STATUS_NONE) {
if (MATCH_FILTER(args, CTL_FILTER_STATUS_SERIAL)) {
data[KNOT_CTL_IDX_TYPE] = "serial";
if (zone->contents != NULL) {
knot_rdataset_t *soa = node_rdataset(zone->contents->apex,
KNOT_RRTYPE_SOA);
KNOT_RRTYPE_SOA);
ret = snprintf(buff, sizeof(buff), "%u", knot_soa_serial(soa));
} else {
ret = snprintf(buff, sizeof(buff), "none");
......@@ -238,8 +197,8 @@ static int zone_status(zone_t *zone, ctl_args_t *args)
type = KNOT_CTL_TYPE_EXTRA;
}
}
// Zone transaction.
if (param == ZONE_STATUS_TRANSACTION || param == ZONE_STATUS_NONE) {
if (MATCH_FILTER(args, CTL_FILTER_STATUS_TRANSACTION)) {
data[KNOT_CTL_IDX_TYPE] = "transaction";
data[KNOT_CTL_IDX_DATA] = (zone->control_update != NULL) ? "open" : "none";
ret = knot_ctl_send(args->ctl, type, &data);
......@@ -249,23 +208,22 @@ static int zone_status(zone_t *zone, ctl_args_t *args)
type = KNOT_CTL_TYPE_EXTRA;
}
}
// frozen
bool ufrozen = zone->events.ufrozen;
if (param == ZONE_STATUS_FREEZE || param == ZONE_STATUS_NONE) {
time_t freeze = zone_events_get_time(zone, ZONE_EVENT_UFREEZE) - time(NULL);
time_t thaw = zone_events_get_time(zone, ZONE_EVENT_UTHAW) - time(NULL);
if (MATCH_FILTER(args, CTL_FILTER_STATUS_FREEZE)) {
data[KNOT_CTL_IDX_TYPE] = "freeze";
if (ufrozen) {
if (thaw < 0) {
if (zone_events_get_time(zone, ZONE_EVENT_UTHAW) < time(NULL)) {
data[KNOT_CTL_IDX_DATA] = "yes";
} else {
data[KNOT_CTL_IDX_DATA] = "thaw queued";
data[KNOT_CTL_IDX_DATA] = "thawing";
}
} else {
if (freeze < 0) {
if (zone_events_get_time(zone, ZONE_EVENT_UFREEZE) < time(NULL)) {
data[KNOT_CTL_IDX_DATA] = "no";
} else {
data[KNOT_CTL_IDX_DATA] = "freeze queued";
data[KNOT_CTL_IDX_DATA] = "freezing";
}
}
ret = knot_ctl_send(args->ctl, type, &data);
......@@ -273,39 +231,40 @@ static int zone_status(zone_t *zone, ctl_args_t *args)
return ret;
}
}
// list modules
if (param == ZONE_STATUS_EVENT_TIMERS || param == ZONE_STATUS_NONE) {
time_t ev_time;
if (MATCH_FILTER(args, CTL_FILTER_STATUS_EVENTS)) {
for (zone_event_type_t i = 0; i < ZONE_EVENT_COUNT; i++) {
// Events not worth showing or used elsewhere
if (!(i == ZONE_EVENT_LOAD || i == ZONE_EVENT_UFREEZE
|| i == ZONE_EVENT_UTHAW)) {
// Skip events affected by freeze
if (!ufrozen || !ufreeze_applies(i)) {
data[KNOT_CTL_IDX_TYPE] = zone_events_get_name(i);
ev_time = zone_events_get_time(zone, i);
ev_time = ev_time - time(NULL);
if (ev_time < 0) {
ret = snprintf(buff, sizeof(buff), "not scheduled");
} else {
ret = snprintf(buff, sizeof(buff), "in %lldh%lldm%llds",
(long long)(ev_time / 3600),
(long long)(ev_time % 3600) / 60,
(long long)(ev_time % 60));
}
if (ret < 0 || ret >= sizeof(buff)) {
return KNOT_ESPACE;
}
data[KNOT_CTL_IDX_DATA] = buff;
ret = knot_ctl_send(args->ctl, type,
&data);
if (ret != KNOT_EOK) {
return ret;
}
type = KNOT_CTL_TYPE_EXTRA;
}
// Events not worth showing or used elsewhere.
if (i == ZONE_EVENT_LOAD || i == ZONE_EVENT_UFREEZE ||
i == ZONE_EVENT_UTHAW) {
continue;
}
// Skip events affected by freeze.
if (ufrozen && ufreeze_applies(i)) {
continue;
}
data[KNOT_CTL_IDX_TYPE] = zone_events_get_name(i);
time_t ev_time = zone_events_get_time(zone, i);
if (ev_time < time(NULL)) {
ret = snprintf(buff, sizeof(buff), "not scheduled");
} else {
ret = snprintf(buff, sizeof(buff), "in %lldh%lldm%llds",
(long long)(ev_time / 3600),
(long long)(ev_time % 3600) / 60,
(long long)(ev_time % 60));
}
if (ret < 0 || ret >= sizeof(buff)) {
return KNOT_ESPACE;
}
data[KNOT_CTL_IDX_DATA] = buff;
ret = knot_ctl_send(args->ctl, type, &data);
if (ret != KNOT_EOK) {
return ret;
}
type = KNOT_CTL_TYPE_EXTRA;
}
}
......@@ -354,7 +313,9 @@ static int zone_retransfer(zone_t *zone, ctl_args_t *args)
static int zone_flush(zone_t *zone, ctl_args_t *args)
{
UNUSED(args);
if (MATCH_FILTER(args, CTL_FILTER_FLUSH_OUTDIR)) {
return zone_dump_to_dir(conf(), zone, args->data[KNOT_CTL_IDX_DATA]);
}
if (ctl_has_flag(args->data[KNOT_CTL_IDX_FLAGS], CTL_FLAG_FORCE)) {
zone->flags |= ZONE_FORCE_FLUSH;
......@@ -996,30 +957,40 @@ static int zone_txn_unset(zone_t *zone, ctl_args_t *args)
static int zone_purge(zone_t *zone, ctl_args_t *args)
{
UNUSED(args);
// Abort possible editing transaction.
(void)zone_txn_abort(zone, args);
if (MATCH_FILTER(args, CTL_FILTER_PURGE_EXPIRE)) {
(void)zone_txn_abort(zone, args);
}
// Purge the zone timers.
memset(&zone->timers, 0, sizeof(zone->timers));
if (MATCH_FILTER(args, CTL_FILTER_PURGE_TIMERS)) {
memset(&zone->timers, 0, sizeof(zone->timers));
}
// Expire the zone.
event_expire(conf(), zone);
if (MATCH_FILTER(args, CTL_FILTER_PURGE_EXPIRE)) {
(void)event_expire(conf(), zone);
}
// Purge the zone file.
char *zonefile = conf_zonefile(conf(), zone->name);
(void)unlink(zonefile);
free(zonefile);
if (MATCH_FILTER(args, CTL_FILTER_PURGE_ZONEFILE)) {
char *zonefile = conf_zonefile(conf(), zone->name);
(void)unlink(zonefile);
free(zonefile);
}
// Purge the zone journal.
if (journal_open(zone->journal, zone->journal_db, zone->name) == KNOT_EOK) {
(void)journal_scrape(zone->journal);
if (MATCH_FILTER(args, CTL_FILTER_PURGE_JOURNAL)) {
if (journal_open(zone->journal, zone->journal_db, zone->name) == KNOT_EOK) {
(void)journal_scrape(zone->journal);
}
}
// Purge KASP DB
if (kasp_db_open(*kaspdb()) == KNOT_EOK) {
(void)kasp_db_delete_all(*kaspdb(), zone->name);
// Purge KASP DB.
if (MATCH_FILTER(args, CTL_FILTER_PURGE_KASPDB)) {
if (kasp_db_open(*kaspdb()) == KNOT_EOK) {
(void)kasp_db_delete_all(*kaspdb(), zone->name);
}
}
return KNOT_EOK;
......
......@@ -31,6 +31,20 @@
#define CTL_FLAG_ADD "+"
#define CTL_FLAG_REM "-"
#define CTL_FILTER_FLUSH_OUTDIR 'd'
#define CTL_FILTER_STATUS_ROLE 'r'
#define CTL_FILTER_STATUS_SERIAL 's'
#define CTL_FILTER_STATUS_TRANSACTION 't'
#define CTL_FILTER_STATUS_FREEZE 'f'
#define CTL_FILTER_STATUS_EVENTS 'e'
#define CTL_FILTER_PURGE_EXPIRE 'e'
#define CTL_FILTER_PURGE_TIMERS 't'
#define CTL_FILTER_PURGE_ZONEFILE 'f'
#define CTL_FILTER_PURGE_JOURNAL 'j'
#define CTL_FILTER_PURGE_KASPDB 'k'
/*! Control commands. */
typedef enum {
CTL_NONE,
......
......@@ -615,3 +615,32 @@ size_t zone_update_dequeue(zone_t *zone, list_t *updates)
return update_count;
}
int zone_dump_to_dir(conf_t *conf, zone_t *zone, const char *dir)
{
if (zone == NULL || dir == NULL) {
return KNOT_EINVAL;
}
size_t dir_len = strlen(dir);
if (dir_len == 0) {
return KNOT_EINVAL;
}
char *zonefile = conf_zonefile(conf, zone->name);
char *zonefile_basename = strrchr(zonefile, '/');
if (zonefile_basename == NULL) {
zonefile_basename = zonefile;
}
size_t target_length = strlen(zonefile_basename) + dir_len + 2;
char target[target_length];
(void)snprintf(target, target_length, "%s/%s", dir, zonefile_basename);
if (strcmp(target, zonefile) == 0) {
free(zonefile);
return KNOT_EDENIED;
}
free(zonefile);
return zonefile_write(target, zone->contents);
}
......@@ -180,4 +180,7 @@ int zone_update_enqueue(zone_t *zone, knot_pkt_t *pkt, struct process_query_para
/*! \brief Dequeue UPDATE request. Returns number of queued updates. */
size_t zone_update_dequeue(zone_t *zone, list_t *updates);
/*! \brief Write zone contents to zonefile, but into different directory. */
int zone_dump_to_dir(conf_t *conf, zone_t *zone, const char *dir);
/*! @} */
......@@ -37,6 +37,7 @@ typedef enum {
KNOT_CTL_IDX_TTL, /*!< Zone record TTL. */
KNOT_CTL_IDX_TYPE, /*!< Zone record type name. */
KNOT_CTL_IDX_DATA, /*!< Configuration item/zone record data. */
KNOT_CTL_IDX_FILTER, /*!< An option or a filter for output data processing. */
KNOT_CTL_IDX__COUNT, /*!< The number of data items. */
} knot_ctl_idx_t;
......
This diff is collapsed.
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