]>
Commit | Line | Data |
---|---|---|
fe000966 | 1 | /* |
e5257efa | 2 | Copyright (C) 2010-2015 Proxmox Server Solutions GmbH |
fe000966 DM |
3 | |
4 | This program is free software: you can redistribute it and/or modify | |
5 | it under the terms of the GNU Affero General Public License as published by | |
6 | the Free Software Foundation, either version 3 of the License, or | |
7 | (at your option) any later version. | |
8 | ||
9 | This program is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | GNU Affero General Public License for more details. | |
13 | ||
14 | You should have received a copy of the GNU Affero General Public License | |
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | ||
17 | Author: Dietmar Maurer <dietmar@proxmox.com> | |
18 | ||
19 | */ | |
20 | ||
89fde9ac DM |
21 | |
22 | /* see "man cmap_overview" and "man cmap_keys" */ | |
e5257efa | 23 | |
fe000966 DM |
24 | #define G_LOG_DOMAIN "confdb" |
25 | ||
26 | #define CLUSTER_KEY "cluster" | |
27 | ||
28 | #ifdef HAVE_CONFIG_H | |
29 | #include <config.h> | |
30 | #endif /* HAVE_CONFIG_H */ | |
31 | ||
32 | #include <stdlib.h> | |
33 | #include <stdio.h> | |
34 | #include <string.h> | |
35 | #include <unistd.h> | |
36 | #include <glib.h> | |
37 | ||
89fde9ac | 38 | #include <corosync/cmap.h> |
fe000966 DM |
39 | |
40 | #include "cfs-utils.h" | |
41 | #include "loop.h" | |
42 | #include "status.h" | |
43 | ||
44 | typedef struct { | |
89fde9ac | 45 | cmap_handle_t handle; |
feeb10d6 DM |
46 | cmap_track_handle_t track_nodelist_handle; |
47 | cmap_track_handle_t track_version_handle; | |
fe000966 DM |
48 | gboolean changes; |
49 | } cs_private_t; | |
50 | ||
e5257efa DM |
51 | static cs_error_t |
52 | cmap_read_clusternodes( | |
53 | cmap_handle_t handle, | |
54 | cfs_clinfo_t *clinfo) | |
fe000966 DM |
55 | { |
56 | cs_error_t result; | |
89fde9ac | 57 | cmap_iter_handle_t iter; |
fe000966 | 58 | |
e5257efa DM |
59 | result = cmap_iter_init(handle, "nodelist.node.", &iter); |
60 | if (result != CS_OK) { | |
89fde9ac | 61 | cfs_critical("cmap_iter_init failed %d", result); |
fe000966 DM |
62 | return result; |
63 | } | |
64 | ||
e5257efa DM |
65 | cmap_value_types_t type; |
66 | char key_name[CMAP_KEYNAME_MAXLEN + 1]; | |
67 | size_t value_len; | |
68 | ||
69 | int last_id = -1; | |
70 | uint32_t nodeid = 0; | |
71 | uint32_t votes = 0; | |
72 | char *name = NULL; | |
73 | ||
74 | while ((result = cmap_iter_next(handle, iter, key_name, &value_len, &type)) == CS_OK) { | |
75 | int id; | |
76 | char subkey[CMAP_KEYNAME_MAXLEN + 1]; | |
77 | if (sscanf(key_name, "nodelist.node.%d.%s", &id, subkey) != 2) continue; | |
78 | ||
79 | if (id != last_id) { | |
80 | if (name && nodeid) { | |
81 | cfs_clnode_t *clnode = cfs_clnode_new(name, nodeid, votes); | |
82 | cfs_clinfo_add_node(clinfo, clnode); | |
83 | } | |
84 | last_id = id; | |
58e19b27 | 85 | free(name); |
e5257efa DM |
86 | name = NULL; |
87 | nodeid = 0; | |
88 | votes = 0; | |
89 | } | |
90 | ||
91 | if (strcmp(subkey, "nodeid") == 0) { | |
92 | if ((result = cmap_get_uint32(handle, key_name, &nodeid)) != CS_OK) { | |
93 | cfs_critical("cmap_get %s failed %d", key_name, result); | |
94 | } | |
95 | } else if (strcmp(subkey, "quorum_votes") == 0) { | |
96 | if ((result = cmap_get_uint32(handle, key_name, &votes)) != CS_OK) { | |
97 | cfs_critical("cmap_get %s failed %d", key_name, result); | |
98 | } | |
99 | } else if (strcmp(subkey, "ring0_addr") == 0) { | |
3f24bfff TL |
100 | // prefering the 'name' subkey over 'ring0_addr', needed for RRP |
101 | // and when using a IP address for ring0_addr | |
102 | if (name == NULL && | |
103 | (result = cmap_get_string(handle, key_name, &name)) != CS_OK) { | |
104 | cfs_critical("cmap_get %s failed %d", key_name, result); | |
105 | } | |
106 | } else if (strcmp(subkey, "name") == 0) { | |
107 | free(name); | |
108 | name = NULL; | |
e5257efa DM |
109 | if ((result = cmap_get_string(handle, key_name, &name)) != CS_OK) { |
110 | cfs_critical("cmap_get %s failed %d", key_name, result); | |
111 | } | |
112 | } | |
113 | } | |
114 | ||
115 | if (name && nodeid) { | |
116 | cfs_clnode_t *clnode = cfs_clnode_new(name, nodeid, votes); | |
117 | cfs_clinfo_add_node(clinfo, clnode); | |
118 | } | |
58e19b27 | 119 | free(name); |
fe000966 | 120 | |
89fde9ac DM |
121 | result = cmap_iter_finalize(handle, iter); |
122 | if (result != CS_OK) { | |
123 | cfs_critical("cmap_iter_finalize failed %d", result); | |
fe000966 DM |
124 | return result; |
125 | } | |
126 | ||
fe000966 DM |
127 | return result; |
128 | } | |
129 | ||
e5257efa DM |
130 | static cs_error_t |
131 | cmap_read_config(cmap_handle_t handle) | |
132 | { | |
133 | cs_error_t result; | |
134 | ||
135 | uint64_t config_version = 0; | |
136 | ||
137 | result = cmap_get_uint64(handle, "totem.config_version", &config_version); | |
138 | if (result != CS_OK) { | |
139 | cfs_critical("cmap_get totem.config_version failed %d", result); | |
140 | // optional, do not throw error | |
141 | } | |
142 | ||
143 | char *clustername = NULL; | |
144 | result = cmap_get_string(handle, "totem.cluster_name", &clustername); | |
145 | if (result != CS_OK) { | |
146 | cfs_critical("cmap_get totem.cluster_name failed %d", result); | |
147 | return result; | |
148 | } | |
149 | ||
150 | cfs_clinfo_t *clinfo = cfs_clinfo_new(clustername, config_version); | |
151 | g_free(clustername); | |
152 | ||
153 | result = cmap_read_clusternodes(handle, clinfo); | |
154 | if (result == CS_OK) { | |
155 | cfs_status_set_clinfo(clinfo); | |
156 | } else { | |
157 | cfs_clinfo_destroy(clinfo); | |
158 | } | |
159 | ||
160 | return result; | |
161 | } | |
162 | ||
163 | static gboolean | |
89fde9ac | 164 | service_cmap_finalize( |
fe000966 DM |
165 | cfs_service_t *service, |
166 | gpointer context) | |
167 | { | |
168 | g_return_val_if_fail(service != NULL, FALSE); | |
169 | g_return_val_if_fail(context != NULL, FALSE); | |
170 | ||
171 | cs_private_t *private = (cs_private_t *)context; | |
89fde9ac | 172 | cmap_handle_t handle = private->handle; |
fe000966 DM |
173 | cs_error_t result; |
174 | ||
feeb10d6 DM |
175 | if (private->track_nodelist_handle) { |
176 | result = cmap_track_delete(handle, private->track_nodelist_handle); | |
e5257efa | 177 | if (result != CS_OK) { |
feeb10d6 | 178 | cfs_critical("cmap_track_delete nodelist failed: %d", result); |
e5257efa | 179 | } |
feeb10d6 DM |
180 | private->track_nodelist_handle = 0; |
181 | } | |
182 | ||
183 | if (private->track_version_handle) { | |
184 | result = cmap_track_delete(handle, private->track_version_handle); | |
185 | if (result != CS_OK) { | |
186 | cfs_critical("cmap_track_delete version failed: %d", result); | |
187 | } | |
188 | private->track_version_handle = 0; | |
e5257efa DM |
189 | } |
190 | ||
89fde9ac | 191 | result = cmap_finalize(handle); |
fe000966 DM |
192 | private->handle = 0; |
193 | if (result != CS_OK) { | |
89fde9ac | 194 | cfs_critical("cmap_finalize failed: %d", result); |
fe000966 DM |
195 | return FALSE; |
196 | } | |
197 | ||
198 | return TRUE; | |
199 | } | |
200 | ||
e5257efa DM |
201 | static void |
202 | track_callback( | |
203 | cmap_handle_t cmap_handle, | |
204 | cmap_track_handle_t cmap_track_handle, | |
205 | int32_t event, | |
206 | const char *key_name, | |
207 | struct cmap_notify_value new_value, | |
208 | struct cmap_notify_value old_value, | |
209 | void *context) | |
210 | { | |
07be995a | 211 | g_return_if_fail(context != NULL); |
e5257efa | 212 | |
07be995a | 213 | cs_private_t *private = (cs_private_t *)context; |
e5257efa | 214 | |
07be995a | 215 | cfs_debug("track_callback %s %d\n", key_name, event); |
e5257efa | 216 | |
07be995a | 217 | private->changes = TRUE; |
e5257efa DM |
218 | } |
219 | ||
220 | ||
221 | static int | |
89fde9ac | 222 | service_cmap_initialize( |
fe000966 DM |
223 | cfs_service_t *service, |
224 | gpointer context) | |
225 | { | |
226 | g_return_val_if_fail(service != NULL, FALSE); | |
227 | g_return_val_if_fail(context != NULL, FALSE); | |
228 | ||
229 | cs_private_t *private = (cs_private_t *)context; | |
230 | ||
89fde9ac DM |
231 | // fixme: do not copy (use pointer) |
232 | cmap_handle_t handle = private->handle; | |
fe000966 DM |
233 | cs_error_t result; |
234 | ||
235 | if (!private->handle) { | |
236 | ||
89fde9ac | 237 | result = cmap_initialize(&handle); |
fe000966 | 238 | if (result != CS_OK) { |
89fde9ac | 239 | cfs_critical("cmap_initialize failed: %d", result); |
fe000966 DM |
240 | private->handle = 0; |
241 | return -1; | |
242 | } | |
243 | ||
89fde9ac | 244 | result = cmap_context_set(handle, private); |
fe000966 | 245 | if (result != CS_OK) { |
89fde9ac DM |
246 | cfs_critical("cmap_context_set failed: %d", result); |
247 | cmap_finalize(handle); | |
fe000966 DM |
248 | private->handle = 0; |
249 | return -1; | |
250 | } | |
251 | ||
252 | private->handle = handle; | |
253 | } | |
254 | ||
feeb10d6 | 255 | |
07be995a DM |
256 | result = cmap_track_add(handle, "nodelist.node.", |
257 | CMAP_TRACK_PREFIX|CMAP_TRACK_ADD|CMAP_TRACK_DELETE|CMAP_TRACK_MODIFY, | |
feeb10d6 DM |
258 | track_callback, context, &private->track_nodelist_handle); |
259 | ||
260 | if (result == CS_OK) { | |
261 | result = cmap_track_add(handle, "totem.config_version", | |
262 | CMAP_TRACK_ADD|CMAP_TRACK_DELETE|CMAP_TRACK_MODIFY, | |
263 | track_callback, context, &private->track_version_handle); | |
264 | } | |
e5257efa | 265 | |
fe000966 | 266 | if (result == CS_ERR_LIBRARY || result == CS_ERR_BAD_HANDLE) { |
89fde9ac DM |
267 | cfs_critical("cmap_track_changes failed: %d - closing handle", result); |
268 | cmap_finalize(handle); | |
fe000966 DM |
269 | private->handle = 0; |
270 | return -1; | |
271 | } else if (result != CS_OK) { | |
89fde9ac | 272 | cfs_critical("cmap_track_changes failed: %d - trying again", result); |
fe000966 DM |
273 | return -1; |
274 | } | |
e5257efa | 275 | |
89fde9ac DM |
276 | int cmap_fd = -1; |
277 | if ((result = cmap_fd_get(handle, &cmap_fd)) != CS_OK) { | |
fe000966 DM |
278 | cfs_critical("confdb_fd_get failed %d - trying again", result); |
279 | return -1; | |
280 | } | |
281 | ||
89fde9ac | 282 | cmap_read_config(handle); |
fe000966 | 283 | |
89fde9ac | 284 | return cmap_fd; |
fe000966 DM |
285 | } |
286 | ||
e5257efa | 287 | static gboolean |
89fde9ac | 288 | service_cmap_dispatch( |
fe000966 DM |
289 | cfs_service_t *service, |
290 | gpointer context) | |
291 | { | |
292 | g_return_val_if_fail(service != NULL, FALSE); | |
293 | g_return_val_if_fail(context != NULL, FALSE); | |
294 | ||
295 | cs_private_t *private = (cs_private_t *)context; | |
89fde9ac | 296 | cmap_handle_t handle = private->handle; |
fe000966 DM |
297 | |
298 | cs_error_t result; | |
299 | ||
300 | private->changes = FALSE; | |
301 | int retries = 0; | |
302 | loop: | |
89fde9ac | 303 | result = cmap_dispatch(handle, CS_DISPATCH_ALL); |
fe000966 DM |
304 | if (result == CS_ERR_TRY_AGAIN) { |
305 | usleep(100000); | |
306 | ++retries; | |
307 | if ((retries % 100) == 0) | |
89fde9ac | 308 | cfs_message("cmap_dispatch retry %d", retries); |
fe000966 DM |
309 | goto loop; |
310 | } | |
311 | ||
312 | ||
313 | if (result == CS_OK || result == CS_ERR_TRY_AGAIN) { | |
314 | ||
315 | if (private->changes) { | |
89fde9ac | 316 | result = cmap_read_config(handle); |
17d800bb DM |
317 | |
318 | private->changes = FALSE; | |
319 | ||
fe000966 DM |
320 | if (result == CS_OK) |
321 | return TRUE; | |
322 | } | |
323 | } else { | |
89fde9ac | 324 | cfs_critical("cmap_dispatch failed: %d", result); |
fe000966 DM |
325 | } |
326 | ||
89fde9ac | 327 | cmap_finalize(handle); |
fe000966 DM |
328 | private->handle = 0; |
329 | return FALSE; | |
330 | } | |
331 | ||
332 | static cfs_service_callbacks_t cfs_confdb_callbacks = { | |
89fde9ac DM |
333 | .cfs_service_initialize_fn = service_cmap_initialize, |
334 | .cfs_service_finalize_fn = service_cmap_finalize, | |
335 | .cfs_service_dispatch_fn = service_cmap_dispatch, | |
fe000966 DM |
336 | }; |
337 | ||
338 | cfs_service_t * | |
339 | service_confdb_new(void) | |
340 | { | |
341 | cfs_service_t *service; | |
342 | ||
343 | cs_private_t *private = g_new0(cs_private_t, 1); | |
344 | if (!private) | |
345 | return NULL; | |
346 | ||
e5257efa | 347 | service = cfs_service_new(&cfs_confdb_callbacks, G_LOG_DOMAIN, private); |
fe000966 DM |
348 | |
349 | return service; | |
350 | } | |
351 | ||
e5257efa DM |
352 | void |
353 | service_confdb_destroy(cfs_service_t *service) | |
fe000966 DM |
354 | { |
355 | g_return_if_fail(service != NULL); | |
356 | ||
e5257efa | 357 | cs_private_t *private = |
fe000966 DM |
358 | (cs_private_t *)cfs_service_get_context(service); |
359 | ||
360 | g_free(private); | |
361 | g_free(service); | |
362 | } |