]>
Commit | Line | Data |
---|---|---|
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 | ||
45 | int | |
46 | qdevice_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 | ||
61 | int | |
62 | qdevice_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 | ||
71 | int | |
72 | qdevice_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 | ||
258 | int | |
259 | qdevice_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 | } |