1 /*
2 * Copyright (c) 2015-2017 Red Hat, Inc.
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
35 #include "qdevice-config.h"
36 #include "qdevice-instance.h"
37 #include "qdevice-heuristics-exec-list.h"
38 #include "qdevice-log.h"
39 #include "qdevice-model.h"
40 #include "utils.h"
41
42 int
qdevice_instance_init(struct qdevice_instance * instance,const struct qdevice_advanced_settings * advanced_settings)43 qdevice_instance_init(struct qdevice_instance *instance,
44 const struct qdevice_advanced_settings *advanced_settings)
45 {
46
47 memset(instance, 0, sizeof(*instance));
48
49 node_list_init(&instance->config_node_list);
50
51 instance->vq_last_poll = ((time_t) -1);
52 instance->advanced_settings = advanced_settings;
53
54 return (0);
55 }
56
57 int
qdevice_instance_destroy(struct qdevice_instance * instance)58 qdevice_instance_destroy(struct qdevice_instance *instance)
59 {
60
61 node_list_free(&instance->config_node_list);
62
63 return (0);
64 }
65
66 int
qdevice_instance_configure_from_cmap_heuristics(struct qdevice_instance * instance)67 qdevice_instance_configure_from_cmap_heuristics(struct qdevice_instance *instance)
68 {
69 char *str;
70 long long int lli;
71 int i;
72 int res;
73 cs_error_t cs_err;
74 cmap_iter_handle_t iter_handle;
75 char key_name[CMAP_KEYNAME_MAXLEN + 1];
76 size_t value_len;
77 cmap_value_types_t type;
78 struct qdevice_heuristics_exec_list tmp_exec_list;
79 struct qdevice_heuristics_exec_list *exec_list;
80 char *command;
81 char exec_name[CMAP_KEYNAME_MAXLEN + 1];
82 char tmp_key[CMAP_KEYNAME_MAXLEN + 1];
83 size_t no_execs;
84 int send_exec_list;
85
86 instance->heuristics_instance.timeout = instance->heartbeat_interval / 2;
87 if (cmap_get_string(instance->cmap_handle,
88 "quorum.device.heuristics.timeout", &str) == CS_OK) {
89 if (utils_strtonum(str, instance->advanced_settings->heuristics_min_timeout,
90 instance->advanced_settings->heuristics_max_timeout, &lli) == -1) {
91 qdevice_log(LOG_ERR, "heuristics.timeout must be valid number in "
92 "range <%"PRIu32",%"PRIu32">",
93 instance->advanced_settings->heuristics_min_timeout,
94 instance->advanced_settings->heuristics_max_timeout);
95
96 free(str);
97 return (-1);
98 } else {
99 instance->heuristics_instance.timeout = lli;
100 }
101
102 free(str);
103 }
104
105 instance->heuristics_instance.sync_timeout = instance->sync_heartbeat_interval / 2;
106 if (cmap_get_string(instance->cmap_handle,
107 "quorum.device.heuristics.sync_timeout", &str) == CS_OK) {
108 if (utils_strtonum(str, instance->advanced_settings->heuristics_min_timeout,
109 instance->advanced_settings->heuristics_max_timeout, &lli) == -1) {
110 qdevice_log(LOG_ERR, "heuristics.sync_timeout must be valid number in "
111 "range <%"PRIu32",%"PRIu32">",
112 instance->advanced_settings->heuristics_min_timeout,
113 instance->advanced_settings->heuristics_max_timeout);
114
115 free(str);
116 return (-1);
117 } else {
118 instance->heuristics_instance.sync_timeout = lli;
119 }
120
121 free(str);
122 }
123
124 instance->heuristics_instance.interval = instance->heartbeat_interval * 3;
125 if (cmap_get_string(instance->cmap_handle,
126 "quorum.device.heuristics.interval", &str) == CS_OK) {
127 if (utils_strtonum(str, instance->advanced_settings->heuristics_min_interval,
128 instance->advanced_settings->heuristics_max_interval, &lli) == -1) {
129 qdevice_log(LOG_ERR, "heuristics.interval must be valid number in "
130 "range <%"PRIu32",%"PRIu32">",
131 instance->advanced_settings->heuristics_min_interval,
132 instance->advanced_settings->heuristics_max_interval);
133
134 free(str);
135 return (-1);
136 } else {
137 instance->heuristics_instance.interval = lli;
138 }
139
140 free(str);
141 }
142
143 instance->heuristics_instance.mode = QDEVICE_DEFAULT_HEURISTICS_MODE;
144
145 if (cmap_get_string(instance->cmap_handle, "quorum.device.heuristics.mode", &str) == CS_OK) {
146 if ((i = utils_parse_bool_str(str)) == -1) {
147 if (strcasecmp(str, "sync") != 0) {
148 qdevice_log(LOG_ERR, "quorum.device.heuristics.mode value is not valid.");
149
150 free(str);
151 return (-1);
152 } else {
153 instance->heuristics_instance.mode = QDEVICE_HEURISTICS_MODE_SYNC;
154 }
155 } else {
156 if (i == 1) {
157 instance->heuristics_instance.mode = QDEVICE_HEURISTICS_MODE_ENABLED;
158 } else {
159 instance->heuristics_instance.mode = QDEVICE_HEURISTICS_MODE_DISABLED;
160 }
161 }
162
163 free(str);
164 }
165
166 send_exec_list = 0;
167 exec_list = NULL;
168 qdevice_heuristics_exec_list_init(&tmp_exec_list);
169
170 if (instance->heuristics_instance.mode == QDEVICE_HEURISTICS_MODE_DISABLED) {
171 exec_list = NULL;
172 send_exec_list = 1;
173 } else if (instance->heuristics_instance.mode == QDEVICE_HEURISTICS_MODE_ENABLED ||
174 instance->heuristics_instance.mode == QDEVICE_HEURISTICS_MODE_SYNC) {
175 /*
176 * Walk thru list of commands to exec
177 */
178 cs_err = cmap_iter_init(instance->cmap_handle, "quorum.device.heuristics.exec_", &iter_handle);
179 if (cs_err != CS_OK) {
180 qdevice_log(LOG_ERR, "Can't iterate quorum.device.heuristics.exec_ keys. "
181 "Error %s", cs_strerror(cs_err));
182
183 return (-1);
184 }
185
186 while ((cs_err = cmap_iter_next(instance->cmap_handle, iter_handle, key_name,
187 &value_len, &type)) == CS_OK) {
188 if (type != CMAP_VALUETYPE_STRING) {
189 qdevice_log(LOG_WARNING, "%s key is not of string type. Ignoring");
190 continue ;
191 }
192
193 res = sscanf(key_name, "quorum.device.heuristics.exec_%[^.]%s", exec_name, tmp_key);
194 if (res != 1) {
195 qdevice_log(LOG_WARNING, "%s key is not correct heuristics exec name. Ignoring");
196 continue ;
197 }
198
199 cs_err = cmap_get_string(instance->cmap_handle, key_name, &command);
200 if (cs_err != CS_OK) {
201 qdevice_log(LOG_WARNING, "Can't get value of %s key. Ignoring");
202 continue ;
203 }
204
205 if (qdevice_heuristics_exec_list_add(&tmp_exec_list, exec_name, command) == NULL) {
206 qdevice_log(LOG_WARNING, "Can't store value of %s key into list. Ignoring");
207 }
208
209 free(command);
210 }
211
212 no_execs = qdevice_heuristics_exec_list_size(&tmp_exec_list);
213
214 if (no_execs == 0) {
215 qdevice_log(LOG_INFO, "No valid heuristics execs defined. Disabling heuristics.");
216 instance->heuristics_instance.mode = QDEVICE_HEURISTICS_MODE_DISABLED;
217 exec_list = NULL;
218 send_exec_list = 1;
219 } else if (no_execs > instance->advanced_settings->heuristics_max_execs) {
220 qdevice_log(LOG_ERR, "Too much (%zu) heuristics execs defined (max is %zu)."
221 " Disabling heuristics.", no_execs,
222 instance->advanced_settings->heuristics_max_execs);
223 instance->heuristics_instance.mode = QDEVICE_HEURISTICS_MODE_DISABLED;
224 exec_list = NULL;
225 send_exec_list = 1;
226 } else if (qdevice_heuristics_exec_list_eq(&tmp_exec_list,
227 &instance->heuristics_instance.exec_list) == 1) {
228 qdevice_log(LOG_DEBUG, "Heuristics list is unchanged");
229 send_exec_list = 0;
230 } else {
231 qdevice_log(LOG_DEBUG, "Heuristics list changed");
232 exec_list = &tmp_exec_list;
233 send_exec_list = 1;
234 }
235
236 } else {
237 qdevice_log(LOG_CRIT, "Undefined heuristics mode");
238 exit(1);
239 }
240
241 if (send_exec_list) {
242 if (qdevice_heuristics_change_exec_list(&instance->heuristics_instance,
243 exec_list, instance->sync_in_progress) != 0) {
244 return (-1);
245 }
246 }
247
248 qdevice_heuristics_exec_list_free(&tmp_exec_list);
249
250 return (0);
251 }
252
253 int
qdevice_instance_configure_from_cmap(struct qdevice_instance * instance)254 qdevice_instance_configure_from_cmap(struct qdevice_instance *instance)
255 {
256 char *str;
257
258 if (cmap_get_string(instance->cmap_handle, "quorum.device.model", &str) != CS_OK) {
259 qdevice_log(LOG_ERR, "Can't read quorum.device.model cmap key.");
260
261 return (-1);
262 }
263
264 if (qdevice_model_str_to_type(str, &instance->model_type) != 0) {
265 qdevice_log(LOG_ERR, "Configured device model %s is not supported.", str);
266 free(str);
267
268 return (-1);
269 }
270 free(str);
271
272 if (cmap_get_uint32(instance->cmap_handle, "runtime.votequorum.this_node_id",
273 &instance->node_id) != CS_OK) {
274 qdevice_log(LOG_ERR, "Unable to retrieve this node nodeid.");
275
276 return (-1);
277 }
278
279 if (cmap_get_uint32(instance->cmap_handle, "quorum.device.timeout", &instance->heartbeat_interval) != CS_OK) {
280 instance->heartbeat_interval = VOTEQUORUM_QDEVICE_DEFAULT_TIMEOUT;
281 }
282
283 if (cmap_get_uint32(instance->cmap_handle, "quorum.device.sync_timeout",
284 &instance->sync_heartbeat_interval) != CS_OK) {
285 instance->sync_heartbeat_interval = VOTEQUORUM_QDEVICE_DEFAULT_SYNC_TIMEOUT;
286 }
287
288 if (qdevice_instance_configure_from_cmap_heuristics(instance) != 0) {
289 return (-1);
290 }
291
292 return (0);
293 }
294