]> git.proxmox.com Git - mirror_corosync-qdevice.git/blame - qdevices/qdevice-instance.c
qdevice: Initial port to use pr-poll-loop
[mirror_corosync-qdevice.git] / qdevices / qdevice-instance.c
CommitLineData
9a1955a7 1/*
406b689d 2 * Copyright (c) 2015-2020 Red Hat, Inc.
9a1955a7
JF
3 *
4 * All rights reserved.
5 *
6 * Author: Jan Friesse (jfriesse@redhat.com)
7 *
8 * This software licensed under BSD license, the text of which follows:
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 *
13 * - Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * - Neither the name of the Red Hat, Inc. nor the names of its
19 * contributors may be used to endorse or promote products derived from this
20 * software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
c8d19612
JF
35#include <string.h>
36#include <stdio.h>
37
313d42d1 38#include "log.h"
9a1955a7
JF
39#include "qdevice-config.h"
40#include "qdevice-instance.h"
41#include "qdevice-heuristics-exec-list.h"
9a1955a7
JF
42#include "qdevice-model.h"
43#include "utils.h"
44
45int
46qdevice_instance_init(struct qdevice_instance *instance,
47 const struct qdevice_advanced_settings *advanced_settings)
48{
49
50 memset(instance, 0, sizeof(*instance));
51
52 node_list_init(&instance->config_node_list);
53
54 instance->vq_last_poll = ((time_t) -1);
55 instance->advanced_settings = advanced_settings;
7a4e9c59 56 pr_poll_loop_init(&instance->main_poll_loop);
9a1955a7
JF
57
58 return (0);
59}
60
61int
62qdevice_instance_destroy(struct qdevice_instance *instance)
63{
64
65 node_list_free(&instance->config_node_list);
7a4e9c59 66 pr_poll_loop_destroy(&instance->main_poll_loop);
9a1955a7
JF
67
68 return (0);
69}
70
71int
72qdevice_instance_configure_from_cmap_heuristics(struct qdevice_instance *instance)
73{
74 char *str;
c5081836 75 long long int lli;
9a1955a7
JF
76 int i;
77 int res;
78 cs_error_t cs_err;
79 cmap_iter_handle_t iter_handle;
80 char key_name[CMAP_KEYNAME_MAXLEN + 1];
81 size_t value_len;
82 cmap_value_types_t type;
83 struct qdevice_heuristics_exec_list tmp_exec_list;
84 struct qdevice_heuristics_exec_list *exec_list;
85 char *command;
86 char exec_name[CMAP_KEYNAME_MAXLEN + 1];
87 char tmp_key[CMAP_KEYNAME_MAXLEN + 1];
88 size_t no_execs;
89 int send_exec_list;
90
91 instance->heuristics_instance.timeout = instance->heartbeat_interval / 2;
92 if (cmap_get_string(instance->cmap_handle,
93 "quorum.device.heuristics.timeout", &str) == CS_OK) {
c5081836
JF
94 if (utils_strtonum(str, instance->advanced_settings->heuristics_min_timeout,
95 instance->advanced_settings->heuristics_max_timeout, &lli) == -1) {
c8d19612 96 log(LOG_ERR, "heuristics.timeout must be valid number in "
9a1955a7
JF
97 "range <%"PRIu32",%"PRIu32">",
98 instance->advanced_settings->heuristics_min_timeout,
99 instance->advanced_settings->heuristics_max_timeout);
100
101 free(str);
102 return (-1);
103 } else {
c5081836 104 instance->heuristics_instance.timeout = lli;
9a1955a7
JF
105 }
106
107 free(str);
108 }
109
110 instance->heuristics_instance.sync_timeout = instance->sync_heartbeat_interval / 2;
111 if (cmap_get_string(instance->cmap_handle,
112 "quorum.device.heuristics.sync_timeout", &str) == CS_OK) {
c5081836
JF
113 if (utils_strtonum(str, instance->advanced_settings->heuristics_min_timeout,
114 instance->advanced_settings->heuristics_max_timeout, &lli) == -1) {
c8d19612 115 log(LOG_ERR, "heuristics.sync_timeout must be valid number in "
9a1955a7
JF
116 "range <%"PRIu32",%"PRIu32">",
117 instance->advanced_settings->heuristics_min_timeout,
118 instance->advanced_settings->heuristics_max_timeout);
119
120 free(str);
121 return (-1);
122 } else {
c5081836 123 instance->heuristics_instance.sync_timeout = lli;
9a1955a7
JF
124 }
125
126 free(str);
127 }
128
129 instance->heuristics_instance.interval = instance->heartbeat_interval * 3;
130 if (cmap_get_string(instance->cmap_handle,
131 "quorum.device.heuristics.interval", &str) == CS_OK) {
c5081836
JF
132 if (utils_strtonum(str, instance->advanced_settings->heuristics_min_interval,
133 instance->advanced_settings->heuristics_max_interval, &lli) == -1) {
c8d19612 134 log(LOG_ERR, "heuristics.interval must be valid number in "
9a1955a7
JF
135 "range <%"PRIu32",%"PRIu32">",
136 instance->advanced_settings->heuristics_min_interval,
137 instance->advanced_settings->heuristics_max_interval);
138
139 free(str);
140 return (-1);
141 } else {
c5081836 142 instance->heuristics_instance.interval = lli;
9a1955a7
JF
143 }
144
145 free(str);
146 }
147
148 instance->heuristics_instance.mode = QDEVICE_DEFAULT_HEURISTICS_MODE;
149
150 if (cmap_get_string(instance->cmap_handle, "quorum.device.heuristics.mode", &str) == CS_OK) {
151 if ((i = utils_parse_bool_str(str)) == -1) {
152 if (strcasecmp(str, "sync") != 0) {
c8d19612 153 log(LOG_ERR, "quorum.device.heuristics.mode value is not valid.");
9a1955a7
JF
154
155 free(str);
156 return (-1);
157 } else {
158 instance->heuristics_instance.mode = QDEVICE_HEURISTICS_MODE_SYNC;
159 }
160 } else {
161 if (i == 1) {
162 instance->heuristics_instance.mode = QDEVICE_HEURISTICS_MODE_ENABLED;
163 } else {
164 instance->heuristics_instance.mode = QDEVICE_HEURISTICS_MODE_DISABLED;
165 }
166 }
167
168 free(str);
169 }
170
171 send_exec_list = 0;
172 exec_list = NULL;
173 qdevice_heuristics_exec_list_init(&tmp_exec_list);
174
175 if (instance->heuristics_instance.mode == QDEVICE_HEURISTICS_MODE_DISABLED) {
176 exec_list = NULL;
177 send_exec_list = 1;
178 } else if (instance->heuristics_instance.mode == QDEVICE_HEURISTICS_MODE_ENABLED ||
179 instance->heuristics_instance.mode == QDEVICE_HEURISTICS_MODE_SYNC) {
180 /*
181 * Walk thru list of commands to exec
182 */
183 cs_err = cmap_iter_init(instance->cmap_handle, "quorum.device.heuristics.exec_", &iter_handle);
184 if (cs_err != CS_OK) {
c8d19612 185 log(LOG_ERR, "Can't iterate quorum.device.heuristics.exec_ keys. "
9a1955a7
JF
186 "Error %s", cs_strerror(cs_err));
187
188 return (-1);
189 }
190
191 while ((cs_err = cmap_iter_next(instance->cmap_handle, iter_handle, key_name,
192 &value_len, &type)) == CS_OK) {
193 if (type != CMAP_VALUETYPE_STRING) {
c8d19612 194 log(LOG_WARNING, "%s key is not of string type. Ignoring", key_name);
9a1955a7
JF
195 continue ;
196 }
197
198 res = sscanf(key_name, "quorum.device.heuristics.exec_%[^.]%s", exec_name, tmp_key);
199 if (res != 1) {
c8d19612 200 log(LOG_WARNING, "%s key is not correct heuristics exec name. Ignoring", key_name);
9a1955a7
JF
201 continue ;
202 }
203
204 cs_err = cmap_get_string(instance->cmap_handle, key_name, &command);
205 if (cs_err != CS_OK) {
c8d19612 206 log(LOG_WARNING, "Can't get value of %s key. Ignoring", key_name);
9a1955a7
JF
207 continue ;
208 }
209
210 if (qdevice_heuristics_exec_list_add(&tmp_exec_list, exec_name, command) == NULL) {
c8d19612 211 log(LOG_WARNING, "Can't store value of %s key into list. Ignoring", key_name);
9a1955a7
JF
212 }
213
214 free(command);
215 }
216
217 no_execs = qdevice_heuristics_exec_list_size(&tmp_exec_list);
218
219 if (no_execs == 0) {
c8d19612 220 log(LOG_INFO, "No valid heuristics execs defined. Disabling heuristics.");
9a1955a7
JF
221 instance->heuristics_instance.mode = QDEVICE_HEURISTICS_MODE_DISABLED;
222 exec_list = NULL;
223 send_exec_list = 1;
224 } else if (no_execs > instance->advanced_settings->heuristics_max_execs) {
c8d19612 225 log(LOG_ERR, "Too much (%zu) heuristics execs defined (max is %zu)."
9a1955a7
JF
226 " Disabling heuristics.", no_execs,
227 instance->advanced_settings->heuristics_max_execs);
228 instance->heuristics_instance.mode = QDEVICE_HEURISTICS_MODE_DISABLED;
229 exec_list = NULL;
230 send_exec_list = 1;
231 } else if (qdevice_heuristics_exec_list_eq(&tmp_exec_list,
232 &instance->heuristics_instance.exec_list) == 1) {
c8d19612 233 log(LOG_DEBUG, "Heuristics list is unchanged");
9a1955a7
JF
234 send_exec_list = 0;
235 } else {
c8d19612 236 log(LOG_DEBUG, "Heuristics list changed");
9a1955a7
JF
237 exec_list = &tmp_exec_list;
238 send_exec_list = 1;
239 }
240
241 } else {
c8d19612 242 log(LOG_CRIT, "Undefined heuristics mode");
406b689d 243 exit(EXIT_FAILURE);
9a1955a7
JF
244 }
245
246 if (send_exec_list) {
247 if (qdevice_heuristics_change_exec_list(&instance->heuristics_instance,
248 exec_list, instance->sync_in_progress) != 0) {
249 return (-1);
250 }
251 }
252
253 qdevice_heuristics_exec_list_free(&tmp_exec_list);
254
255 return (0);
256}
257
258int
259qdevice_instance_configure_from_cmap(struct qdevice_instance *instance)
260{
261 char *str;
262
263 if (cmap_get_string(instance->cmap_handle, "quorum.device.model", &str) != CS_OK) {
c8d19612 264 log(LOG_ERR, "Can't read quorum.device.model cmap key.");
9a1955a7
JF
265
266 return (-1);
267 }
268
269 if (qdevice_model_str_to_type(str, &instance->model_type) != 0) {
c8d19612 270 log(LOG_ERR, "Configured device model %s is not supported.", str);
9a1955a7
JF
271 free(str);
272
273 return (-1);
274 }
275 free(str);
276
277 if (cmap_get_uint32(instance->cmap_handle, "runtime.votequorum.this_node_id",
278 &instance->node_id) != CS_OK) {
c8d19612 279 log(LOG_ERR, "Unable to retrieve this node nodeid.");
9a1955a7
JF
280
281 return (-1);
282 }
283
284 if (cmap_get_uint32(instance->cmap_handle, "quorum.device.timeout", &instance->heartbeat_interval) != CS_OK) {
285 instance->heartbeat_interval = VOTEQUORUM_QDEVICE_DEFAULT_TIMEOUT;
286 }
287
288 if (cmap_get_uint32(instance->cmap_handle, "quorum.device.sync_timeout",
289 &instance->sync_heartbeat_interval) != CS_OK) {
290 instance->sync_heartbeat_interval = VOTEQUORUM_QDEVICE_DEFAULT_SYNC_TIMEOUT;
291 }
292
293 if (qdevice_instance_configure_from_cmap_heuristics(instance) != 0) {
294 return (-1);
295 }
296
297 return (0);
298}