OpenDNSSEC-enforcer 2.1.13
time_leap_cmd.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2014 NLNet Labs
3 * Copyright (c) 2014 OpenDNSSEC AB (svb)
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
29#include "config.h"
30#include <getopt.h>
31
32#include "file.h"
33#include "duration.h"
34#include "log.h"
35#include "str.h"
36#include "cmdhandler.h"
38#include "daemon/engine.h"
39#include "clientpipe.h"
41#include "longgetopt.h"
42
44
45#define MAX_ARGS 5
46
47static const char *module_str = "time_leap_cmd";
48
49static void
50usage(int sockfd)
51{
52 client_printf(sockfd,
53 "time leap\n"
54 " --time <time> aka -t \n"
55 " --attach aka -a\n"
56 );
57}
58
59static void
60help(int sockfd)
61{
62 client_printf(sockfd,
63 "*WARNING* time leap is a debugging/testing tool, it should NEVER be used\n"
64 "in production! Without arguments the daemon inspects the first task in the\n"
65 "schedule and sets its internal time to the time of the task. This allows for\n"
66 "a quick replay of a test scenario. With the --time or -t switch the daemon\n"
67 "sets its time to the argument given as: \"YYYY-MM-DD-HH:MM:SS\"."
68 "\n"
69 "\nOptions:\n"
70 "time leap to this exact time\n"
71 "attach Perform 1 task and stay attached, use only when workerthreads=0\n\n"
72 );
73}
74
75static int
76run(cmdhandler_ctx_type* context, int argc, char* argv[])
77{
78 int sockfd = context->sockfd;
79 struct longgetopt optctx;
80 db_connection_t* dbconn;
81 struct tm strtime_struct;
82 char strtime[64]; /* at least 26 according to docs plus a long integer */
83 time_t now = time_now();
84 const char *time = NULL;
85 time_t time_leap = 0;
86 struct tm tm;
87 int taskcount;
88 int attach = 0;
89 int long_index = 0, opt = 0;
90 int processed_enforce;
91 task_type* task = NULL;
92 engine_type* engine = getglobalcontext(context);
93
94 static struct option long_options[] = {
95 {"time", required_argument, 0, 't'},
96 {"attach", no_argument, 0, 'a'},
97 {0, 0, 0, 0}
98 };
99
100 for (opt = longgetopt(argc, argv, "t:a", long_options, &long_index, &optctx); opt != -1;
101 opt = longgetopt(argc, argv, NULL, long_options, &long_index, &optctx)) {
102 switch (opt) {
103 case 't':
104 time = optctx.optarg;
105 break;
106 case 'a':
107 attach = 1;
108 break;
109 default:
110 client_printf_err(sockfd, "unknown arguments\n");
111 ods_log_error("[%s] unknown arguments for time leap command", module_str);
112 return -1;
113 }
114 }
115
116 if (time) {
117 if (strptime(time, "%Y-%m-%d-%H:%M:%S", &tm)) {
118 tm.tm_isdst = -1;
119 time_leap = mktime(&tm);
120 client_printf(sockfd,
121 "Using %s parameter value as time to leap to\n", time);
122 } else {
123 client_printf_err(sockfd,
124 "Time leap: Error - could not convert '%s' to a time. "
125 "Format is YYYY-MM-DD-HH:MM:SS \n", time);
126 return -1;
127 }
128 }
129
130 ods_log_assert(engine);
131 if (!engine->taskq || !engine->taskq->tasks) {
132 client_printf(sockfd, "There are no tasks scheduled.\n");
133 return 1;
134 }
135
136 schedule_info(engine->taskq, &time_leap, NULL, &taskcount);
137 now = time_now();
138 strftime(strtime, sizeof(strtime), "%c", localtime_r(&now, &strtime_struct));
139 client_printf(sockfd,
140 "There are %i tasks scheduled.\nIt is now %s (%ld seconds since epoch)\n",
141 taskcount, strtime, (long)now);
142
143 if (!time) schedule_info(engine->taskq, &time_leap, NULL, NULL);
144 if (time_leap == -1) {
145 client_printf(sockfd, "No tasks in queue. Not able to leap.\n");
146 return 0;
147 }
148
149 if (!attach) {
150 set_time_now(time_leap);
151 strftime(strtime, sizeof(strtime), "%c", localtime_r(&time_leap, &strtime_struct));
152 client_printf(sockfd, "Leaping to time %s (%ld seconds since epoch)\n",
153 (strtime[0]?strtime:"(null)"), (long)time_leap);
154 ods_log_info("Time leap: Leaping to time %s\n", strtime);
155 /* Wake up all workers and let them reevaluate wether their
156 tasks need to be executed */
157 client_printf(sockfd, "Waking up workers\n");
158 engine_wakeup_workers(engine);
159 return 0;
160 }
161
162 if (!(dbconn = get_database_connection(engine))) {
163 client_printf_err(sockfd, "Failed to open DB connection.\n");
164 client_exit(sockfd, 1);
165 return -1;
166 }
167 /* Keep looping until an enforce task is found, then loop but don't advance time */
168 processed_enforce = 0;
169 while (1) {
170 /*if time is set never advance time but only consume all task <= time*/
171 if (!time) {
172 schedule_info(engine->taskq, &time_leap, NULL, NULL);
173 if (processed_enforce && time_leap > time_now()) break;
174 }
175 if (time_leap == -1) {
176 client_printf(sockfd, "No tasks in queue. Not able to leap.\n");
177 break;
178 }
179
180 set_time_now(time_leap);
181 strftime(strtime, sizeof(strtime), "%c", localtime_r(&time_leap, &strtime_struct));
182 client_printf(sockfd, "Leaping to time %s (%ld seconds since epoch)\n",
183 (strtime[0]?strtime:"(null)"), (long)time_leap);
184 ods_log_info("Time leap: Leaping to time %s\n", strtime);
185 if (!(task = schedule_pop_first_task(engine->taskq)))
186 break;
187 if (schedule_task_istype(task, TASK_TYPE_ENFORCE))
188 processed_enforce = 1;
189 task_perform(engine->taskq, task, dbconn);
190 ods_log_debug("[timeleap] finished working");
191 }
192 db_connection_free(dbconn);
193 return 0;
194}
195
196
197struct cmd_func_block time_leap_funcblock = {
198 "time leap", &usage, &help, NULL, NULL, &run, NULL
199};
void db_connection_free(db_connection_t *connection)
engine_type * getglobalcontext(cmdhandler_ctx_type *context)
void engine_wakeup_workers(engine_type *engine)
Definition engine.c:218
db_connection_t * get_database_connection(engine_type *engine)
Definition engine.c:226
schedule_type * taskq
Definition engine.h:60
struct cmd_func_block time_leap_funcblock