2 Copyright (C) 2010-2015 Proxmox Server Solutions GmbH
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.
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.
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/>.
17 Author: Dietmar Maurer <dietmar@proxmox.com>
22 /* see "man cmap_overview" and "man cmap_keys" */
24 #define G_LOG_DOMAIN "confdb"
26 #define CLUSTER_KEY "cluster"
30 #endif /* HAVE_CONFIG_H */
38 #include <corosync/cmap.h>
40 #include "cfs-utils.h"
46 cmap_track_handle_t track_nodelist_handle
;
47 cmap_track_handle_t track_version_handle
;
52 cmap_read_clusternodes(
57 cmap_iter_handle_t iter
;
59 result
= cmap_iter_init(handle
, "nodelist.node.", &iter
);
60 if (result
!= CS_OK
) {
61 cfs_critical("cmap_iter_init failed %d", result
);
65 cmap_value_types_t type
;
66 char key_name
[CMAP_KEYNAME_MAXLEN
+ 1];
74 while ((result
= cmap_iter_next(handle
, iter
, key_name
, &value_len
, &type
)) == CS_OK
) {
76 char subkey
[CMAP_KEYNAME_MAXLEN
+ 1];
77 if (sscanf(key_name
, "nodelist.node.%d.%s", &id
, subkey
) != 2) continue;
81 cfs_clnode_t
*clnode
= cfs_clnode_new(name
, nodeid
, votes
);
82 cfs_clinfo_add_node(clinfo
, clnode
);
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
);
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
);
99 } else if (strcmp(subkey
, "ring0_addr") == 0) {
100 // prefering the 'name' subkey over 'ring0_addr', needed for RRP
101 // and when using a IP address for ring0_addr
103 (result
= cmap_get_string(handle
, key_name
, &name
)) != CS_OK
) {
104 cfs_critical("cmap_get %s failed %d", key_name
, result
);
106 } else if (strcmp(subkey
, "name") == 0) {
109 if ((result
= cmap_get_string(handle
, key_name
, &name
)) != CS_OK
) {
110 cfs_critical("cmap_get %s failed %d", key_name
, result
);
115 if (name
&& nodeid
) {
116 cfs_clnode_t
*clnode
= cfs_clnode_new(name
, nodeid
, votes
);
117 cfs_clinfo_add_node(clinfo
, clnode
);
121 result
= cmap_iter_finalize(handle
, iter
);
122 if (result
!= CS_OK
) {
123 cfs_critical("cmap_iter_finalize failed %d", result
);
131 cmap_read_config(cmap_handle_t handle
)
135 uint64_t config_version
= 0;
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
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
);
150 cfs_clinfo_t
*clinfo
= cfs_clinfo_new(clustername
, config_version
);
153 result
= cmap_read_clusternodes(handle
, clinfo
);
154 if (result
== CS_OK
) {
155 cfs_status_set_clinfo(clinfo
);
157 cfs_clinfo_destroy(clinfo
);
164 service_cmap_finalize(
165 cfs_service_t
*service
,
168 g_return_val_if_fail(service
!= NULL
, FALSE
);
169 g_return_val_if_fail(context
!= NULL
, FALSE
);
171 cs_private_t
*private = (cs_private_t
*)context
;
172 cmap_handle_t handle
= private->handle
;
175 if (private->track_nodelist_handle
) {
176 result
= cmap_track_delete(handle
, private->track_nodelist_handle
);
177 if (result
!= CS_OK
) {
178 cfs_critical("cmap_track_delete nodelist failed: %d", result
);
180 private->track_nodelist_handle
= 0;
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
);
188 private->track_version_handle
= 0;
191 result
= cmap_finalize(handle
);
193 if (result
!= CS_OK
) {
194 cfs_critical("cmap_finalize failed: %d", result
);
203 cmap_handle_t cmap_handle
,
204 cmap_track_handle_t cmap_track_handle
,
206 const char *key_name
,
207 struct cmap_notify_value new_value
,
208 struct cmap_notify_value old_value
,
211 g_return_if_fail(context
!= NULL
);
213 cs_private_t
*private = (cs_private_t
*)context
;
215 cfs_debug("track_callback %s %d\n", key_name
, event
);
217 private->changes
= TRUE
;
222 service_cmap_initialize(
223 cfs_service_t
*service
,
226 g_return_val_if_fail(service
!= NULL
, FALSE
);
227 g_return_val_if_fail(context
!= NULL
, FALSE
);
229 cs_private_t
*private = (cs_private_t
*)context
;
231 // fixme: do not copy (use pointer)
232 cmap_handle_t handle
= private->handle
;
235 if (!private->handle
) {
237 result
= cmap_initialize(&handle
);
238 if (result
!= CS_OK
) {
239 cfs_critical("cmap_initialize failed: %d", result
);
244 result
= cmap_context_set(handle
, private);
245 if (result
!= CS_OK
) {
246 cfs_critical("cmap_context_set failed: %d", result
);
247 cmap_finalize(handle
);
252 private->handle
= handle
;
256 result
= cmap_track_add(handle
, "nodelist.node.",
257 CMAP_TRACK_PREFIX
|CMAP_TRACK_ADD
|CMAP_TRACK_DELETE
|CMAP_TRACK_MODIFY
,
258 track_callback
, context
, &private->track_nodelist_handle
);
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
);
266 if (result
== CS_ERR_LIBRARY
|| result
== CS_ERR_BAD_HANDLE
) {
267 cfs_critical("cmap_track_changes failed: %d - closing handle", result
);
268 cmap_finalize(handle
);
271 } else if (result
!= CS_OK
) {
272 cfs_critical("cmap_track_changes failed: %d - trying again", result
);
277 if ((result
= cmap_fd_get(handle
, &cmap_fd
)) != CS_OK
) {
278 cfs_critical("confdb_fd_get failed %d - trying again", result
);
282 cmap_read_config(handle
);
288 service_cmap_dispatch(
289 cfs_service_t
*service
,
292 g_return_val_if_fail(service
!= NULL
, FALSE
);
293 g_return_val_if_fail(context
!= NULL
, FALSE
);
295 cs_private_t
*private = (cs_private_t
*)context
;
296 cmap_handle_t handle
= private->handle
;
300 private->changes
= FALSE
;
303 result
= cmap_dispatch(handle
, CS_DISPATCH_ALL
);
304 if (result
== CS_ERR_TRY_AGAIN
) {
307 if ((retries
% 100) == 0)
308 cfs_message("cmap_dispatch retry %d", retries
);
313 if (result
== CS_OK
|| result
== CS_ERR_TRY_AGAIN
) {
315 if (private->changes
) {
316 result
= cmap_read_config(handle
);
318 private->changes
= FALSE
;
324 cfs_critical("cmap_dispatch failed: %d", result
);
327 cmap_finalize(handle
);
332 static cfs_service_callbacks_t cfs_confdb_callbacks
= {
333 .cfs_service_initialize_fn
= service_cmap_initialize
,
334 .cfs_service_finalize_fn
= service_cmap_finalize
,
335 .cfs_service_dispatch_fn
= service_cmap_dispatch
,
339 service_confdb_new(void)
341 cfs_service_t
*service
;
343 cs_private_t
*private = g_new0(cs_private_t
, 1);
347 service
= cfs_service_new(&cfs_confdb_callbacks
, G_LOG_DOMAIN
, private);
353 service_confdb_destroy(cfs_service_t
*service
)
355 g_return_if_fail(service
!= NULL
);
357 cs_private_t
*private =
358 (cs_private_t
*)cfs_service_get_context(service
);