This source file includes following definitions.
- cib_enable_writes
- log_cib_client
- main
- cib_cleanup
- ccm_connection_destroy
- ccm_connect
- cib_cs_dispatch
- cib_cs_destroy
- cib_peer_update_callback
- cib_ha_connection_destroy
- cib_init
- startCib
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <crm_internal.h>
20
21 #include <sys/param.h>
22 #include <stdio.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #include <sys/utsname.h>
27
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <fcntl.h>
31
32 #include <crm/crm.h>
33 #include <crm/cib/internal.h>
34 #include <crm/msg_xml.h>
35 #include <crm/cluster/internal.h>
36
37 #include <crm/common/xml.h>
38
39 #include <crm/common/mainloop.h>
40
41 #include <cibio.h>
42 #include <callbacks.h>
43 #include <pwd.h>
44 #include <grp.h>
45 #include "common.h"
46
47 #if HAVE_LIBXML2
48 # include <libxml/parser.h>
49 #endif
50
51 #ifdef HAVE_GETOPT_H
52 # include <getopt.h>
53 #endif
54
55 #if HAVE_BZLIB_H
56 # include <bzlib.h>
57 #endif
58
59 extern int init_remote_listener(int port, gboolean encrypted);
60 gboolean cib_shutdown_flag = FALSE;
61 int cib_status = pcmk_ok;
62
63 crm_cluster_t crm_cluster;
64
65 #if SUPPORT_HEARTBEAT
66 oc_ev_t *cib_ev_token;
67 ll_cluster_t *hb_conn = NULL;
68 extern void oc_ev_special(const oc_ev_t *, oc_ev_class_t, int);
69 gboolean cib_register_ha(ll_cluster_t * hb_cluster, const char *client_name);
70 #else
71 void *hb_conn = NULL;
72 #endif
73
74 GMainLoop *mainloop = NULL;
75 const char *cib_root = NULL;
76 char *cib_our_uname = NULL;
77 gboolean preserve_status = FALSE;
78
79
80 volatile gboolean cib_writes_enabled = TRUE;
81
82 int remote_fd = 0;
83 int remote_tls_fd = 0;
84
85 int cib_init(void);
86 void cib_shutdown(int nsig);
87 gboolean startCib(const char *filename);
88 extern int write_cib_contents(gpointer p);
89
90 GHashTable *config_hash = NULL;
91 GHashTable *local_notify_queue = NULL;
92
93 char *channel1 = NULL;
94 char *channel2 = NULL;
95 char *channel3 = NULL;
96 char *channel4 = NULL;
97 char *channel5 = NULL;
98
99 #define OPTARGS "maswr:V?"
100 void cib_cleanup(void);
101
102 static void
103 cib_enable_writes(int nsig)
104 {
105 crm_info("(Re)enabling disk writes");
106 cib_writes_enabled = TRUE;
107 }
108
109 static void
110 log_cib_client(gpointer key, gpointer value, gpointer user_data)
111 {
112 crm_info("Client %s", crm_client_name(value));
113 }
114
115
116 static struct crm_option long_options[] = {
117
118 {"help", 0, 0, '?', "\tThis text"},
119 {"verbose", 0, 0, 'V', "\tIncrease debug output"},
120
121 {"per-action-cib", 0, 0, 'a', "\tAdvanced use only"},
122 {"stand-alone", 0, 0, 's', "\tAdvanced use only"},
123 {"disk-writes", 0, 0, 'w', "\tAdvanced use only"},
124 {"cib-root", 1, 0, 'r', "\tAdvanced use only"},
125
126 {0, 0, 0, 0}
127 };
128
129
130 int
131 main(int argc, char **argv)
132 {
133 int flag;
134 int rc = 0;
135 int index = 0;
136 int argerr = 0;
137 struct passwd *pwentry = NULL;
138
139 crm_log_preinit(NULL, argc, argv);
140 crm_set_options(NULL, "[options]",
141 long_options, "Daemon for storing and replicating the cluster configuration");
142
143 crm_peer_init();
144
145 mainloop_add_signal(SIGTERM, cib_shutdown);
146 mainloop_add_signal(SIGPIPE, cib_enable_writes);
147
148 cib_writer = mainloop_add_trigger(G_PRIORITY_LOW, write_cib_contents, NULL);
149
150 while (1) {
151 flag = crm_get_option(argc, argv, &index);
152 if (flag == -1)
153 break;
154
155 switch (flag) {
156 case 'V':
157 crm_bump_log_level(argc, argv);
158 break;
159 case 's':
160 stand_alone = TRUE;
161 preserve_status = TRUE;
162 cib_writes_enabled = FALSE;
163
164 pwentry = getpwnam(CRM_DAEMON_USER);
165 CRM_CHECK(pwentry != NULL,
166 crm_perror(LOG_ERR, "Invalid uid (%s) specified", CRM_DAEMON_USER);
167 return 100);
168
169 rc = setgid(pwentry->pw_gid);
170 if (rc < 0) {
171 crm_perror(LOG_ERR, "Could not set group to %d", pwentry->pw_gid);
172 return 100;
173 }
174
175 rc = initgroups(CRM_DAEMON_GROUP, pwentry->pw_gid);
176 if (rc < 0) {
177 crm_perror(LOG_ERR, "Could not setup groups for user %d", pwentry->pw_uid);
178 return 100;
179 }
180
181 rc = setuid(pwentry->pw_uid);
182 if (rc < 0) {
183 crm_perror(LOG_ERR, "Could not set user to %d", pwentry->pw_uid);
184 return 100;
185 }
186 break;
187 case '?':
188 crm_help(flag, EX_OK);
189 break;
190 case 'w':
191 cib_writes_enabled = TRUE;
192 break;
193 case 'r':
194 cib_root = optarg;
195 break;
196 case 'm':
197 cib_metadata();
198 return 0;
199 default:
200 ++argerr;
201 break;
202 }
203 }
204 if (argc - optind == 1 && safe_str_eq("metadata", argv[optind])) {
205 cib_metadata();
206 return 0;
207 }
208
209 if (optind > argc) {
210 ++argerr;
211 }
212
213 if (argerr) {
214 crm_help('?', EX_USAGE);
215 }
216
217 crm_log_init(NULL, LOG_INFO, TRUE, FALSE, argc, argv, FALSE);
218
219 if (cib_root == NULL) {
220 if ((g_file_test(CRM_CONFIG_DIR "/cib.xml", G_FILE_TEST_EXISTS) == FALSE)
221 && (g_file_test(CRM_LEGACY_CONFIG_DIR "/cib.xml", G_FILE_TEST_EXISTS) == TRUE)) {
222
223 crm_notice("Using legacy config location: " CRM_LEGACY_CONFIG_DIR);
224 cib_root = CRM_LEGACY_CONFIG_DIR;
225
226 } else {
227 cib_root = CRM_CONFIG_DIR;
228 }
229 } else {
230 crm_notice("Using custom config location: %s", cib_root);
231 }
232
233 if (crm_is_writable(cib_root, NULL, CRM_DAEMON_USER, CRM_DAEMON_GROUP, FALSE) == FALSE) {
234 crm_err("Bad permissions on %s. Terminating", cib_root);
235 fprintf(stderr, "ERROR: Bad permissions on %s. See logs for details\n", cib_root);
236 fflush(stderr);
237 return 100;
238 }
239
240
241 rc = cib_init();
242
243 CRM_CHECK(crm_hash_table_size(client_connections) == 0,
244 crm_warn("Not all clients gone at exit"));
245 g_hash_table_foreach(client_connections, log_cib_client, NULL);
246 cib_cleanup();
247
248 #if SUPPORT_HEARTBEAT
249 if (hb_conn) {
250 hb_conn->llc_ops->delete(hb_conn);
251 }
252 #endif
253
254 crm_info("Done");
255 return rc;
256 }
257
258 void
259 cib_cleanup(void)
260 {
261 crm_peer_destroy();
262 if (local_notify_queue) {
263 g_hash_table_destroy(local_notify_queue);
264 }
265 crm_client_cleanup();
266 g_hash_table_destroy(config_hash);
267 free(cib_our_uname);
268 free(channel1);
269 free(channel2);
270 free(channel3);
271 free(channel4);
272 free(channel5);
273 }
274
275 unsigned long cib_num_ops = 0;
276 const char *cib_stat_interval = "10min";
277 unsigned long cib_num_local = 0, cib_num_updates = 0, cib_num_fail = 0;
278 unsigned long cib_bad_connects = 0, cib_num_timeouts = 0;
279
280 #if SUPPORT_HEARTBEAT
281 gboolean ccm_connect(void);
282
283 static void
284 ccm_connection_destroy(gpointer user_data)
285 {
286 crm_err("CCM connection failed... blocking while we reconnect");
287 CRM_ASSERT(ccm_connect());
288 return;
289 }
290
291 static void *ccm_library = NULL;
292
293 gboolean
294 ccm_connect(void)
295 {
296 gboolean did_fail = TRUE;
297 int num_ccm_fails = 0;
298 int max_ccm_fails = 30;
299 int ret;
300 int cib_ev_fd;
301
302 int (*ccm_api_register) (oc_ev_t ** token) =
303 find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_register", 1);
304
305 int (*ccm_api_set_callback) (const oc_ev_t * token,
306 oc_ev_class_t class,
307 oc_ev_callback_t * fn,
308 oc_ev_callback_t ** prev_fn) =
309 find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_set_callback", 1);
310
311 void (*ccm_api_special) (const oc_ev_t *, oc_ev_class_t, int) =
312 find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_special", 1);
313 int (*ccm_api_activate) (const oc_ev_t * token, int *fd) =
314 find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_activate", 1);
315 int (*ccm_api_unregister) (oc_ev_t * token) =
316 find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_unregister", 1);
317
318 static struct mainloop_fd_callbacks ccm_fd_callbacks = {
319 .dispatch = cib_ccm_dispatch,
320 .destroy = ccm_connection_destroy,
321 };
322
323 while (did_fail) {
324 did_fail = FALSE;
325 crm_info("Registering with CCM...");
326 ret = (*ccm_api_register) (&cib_ev_token);
327 if (ret != 0) {
328 did_fail = TRUE;
329 }
330
331 if (did_fail == FALSE) {
332 crm_trace("Setting up CCM callbacks");
333 ret = (*ccm_api_set_callback) (cib_ev_token, OC_EV_MEMB_CLASS,
334 cib_ccm_msg_callback, NULL);
335 if (ret != 0) {
336 crm_warn("CCM callback not set");
337 did_fail = TRUE;
338 }
339 }
340 if (did_fail == FALSE) {
341 (*ccm_api_special) (cib_ev_token, OC_EV_MEMB_CLASS, 0);
342
343 crm_trace("Activating CCM token");
344 ret = (*ccm_api_activate) (cib_ev_token, &cib_ev_fd);
345 if (ret != 0) {
346 crm_warn("CCM Activation failed");
347 did_fail = TRUE;
348 }
349 }
350
351 if (did_fail) {
352 num_ccm_fails++;
353 (*ccm_api_unregister) (cib_ev_token);
354
355 if (num_ccm_fails < max_ccm_fails) {
356 crm_warn("CCM Connection failed %d times (%d max)", num_ccm_fails, max_ccm_fails);
357 sleep(3);
358
359 } else {
360 crm_err("CCM Activation failed %d (max) times", num_ccm_fails);
361 return FALSE;
362 }
363 }
364 }
365
366 crm_debug("CCM Activation passed... all set to go!");
367 mainloop_add_fd("heartbeat-ccm", G_PRIORITY_MEDIUM, cib_ev_fd, cib_ev_token, &ccm_fd_callbacks);
368
369 return TRUE;
370 }
371 #endif
372
373 #if SUPPORT_COROSYNC
374 static void
375 cib_cs_dispatch(cpg_handle_t handle,
376 const struct cpg_name *groupName,
377 uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
378 {
379 uint32_t kind = 0;
380 xmlNode *xml = NULL;
381 const char *from = NULL;
382 char *data = pcmk_message_common_cs(handle, nodeid, pid, msg, &kind, &from);
383
384 if(data == NULL) {
385 return;
386 }
387 if (kind == crm_class_cluster) {
388 xml = string2xml(data);
389 if (xml == NULL) {
390 crm_err("Invalid XML: '%.120s'", data);
391 free(data);
392 return;
393 }
394 crm_xml_add(xml, F_ORIG, from);
395
396 cib_peer_callback(xml, NULL);
397 }
398
399 free_xml(xml);
400 free(data);
401 }
402
403 static void
404 cib_cs_destroy(gpointer user_data)
405 {
406 if (cib_shutdown_flag) {
407 crm_info("Corosync disconnection complete");
408 } else {
409 crm_err("Corosync connection lost! Exiting.");
410 terminate_cib(__FUNCTION__, -1);
411 }
412 }
413 #endif
414
415 static void
416 cib_peer_update_callback(enum crm_status_type type, crm_node_t * node, const void *data)
417 {
418 switch (type) {
419 case crm_status_processes:
420 #if !SUPPORT_PLUGIN
421 if (cib_legacy_mode()
422 && is_not_set(node->processes, crm_get_cluster_proc())) {
423
424 uint32_t old = data? *(const uint32_t *)data : 0;
425
426 if ((node->processes ^ old) & crm_proc_cpg) {
427 crm_info("Attempting to disable legacy mode after %s left the cluster",
428 node->uname);
429 legacy_mode = FALSE;
430 }
431 }
432 #endif
433 break;
434
435 case crm_status_uname:
436 case crm_status_rstate:
437 case crm_status_nstate:
438 if (cib_shutdown_flag && (crm_active_peers() < 2)
439 && crm_hash_table_size(client_connections) == 0) {
440
441 crm_info("No more peers");
442 terminate_cib(__FUNCTION__, 1);
443 }
444 break;
445 }
446 }
447
448 #if SUPPORT_HEARTBEAT
449 static void
450 cib_ha_connection_destroy(gpointer user_data)
451 {
452 if (cib_shutdown_flag) {
453 crm_info("Heartbeat disconnection complete... exiting");
454 terminate_cib(__FUNCTION__, 0);
455 } else {
456 crm_err("Heartbeat connection lost! Exiting.");
457 terminate_cib(__FUNCTION__, -1);
458 }
459 }
460 #endif
461
462 int
463 cib_init(void)
464 {
465 if (is_openais_cluster()) {
466 #if SUPPORT_COROSYNC
467 crm_cluster.destroy = cib_cs_destroy;
468 crm_cluster.cpg.cpg_deliver_fn = cib_cs_dispatch;
469 crm_cluster.cpg.cpg_confchg_fn = pcmk_cpg_membership;
470 #endif
471 } else if (is_heartbeat_cluster()) {
472 #if SUPPORT_HEARTBEAT
473 crm_cluster.hb_dispatch = cib_ha_peer_callback;
474 crm_cluster.destroy = cib_ha_connection_destroy;
475 #endif
476 }
477
478 config_hash = crm_str_table_new();
479
480 if (startCib("cib.xml") == FALSE) {
481 crm_crit("Cannot start CIB... terminating");
482 crm_exit(ENODATA);
483 }
484
485 if (stand_alone == FALSE) {
486 if (is_openais_cluster()) {
487 crm_set_status_callback(&cib_peer_update_callback);
488 }
489
490 if (crm_cluster_connect(&crm_cluster) == FALSE) {
491 crm_crit("Cannot sign in to the cluster... terminating");
492 crm_exit(DAEMON_RESPAWN_STOP);
493 }
494 cib_our_uname = crm_cluster.uname;
495
496 #if SUPPORT_HEARTBEAT
497 if (is_heartbeat_cluster()) {
498
499 gboolean was_error = FALSE;
500
501 hb_conn = crm_cluster.hb_conn;
502 if (was_error == FALSE) {
503 if (HA_OK !=
504 hb_conn->llc_ops->set_cstatus_callback(hb_conn, cib_client_status_callback,
505 hb_conn)) {
506
507 crm_err("Cannot set cstatus callback: %s", hb_conn->llc_ops->errmsg(hb_conn));
508 was_error = TRUE;
509 }
510 }
511
512 if (was_error == FALSE) {
513 was_error = (ccm_connect() == FALSE);
514 }
515
516 if (was_error == FALSE) {
517
518 crm_info("Requesting the list of configured nodes");
519 hb_conn->llc_ops->client_status(hb_conn, NULL, CRM_SYSTEM_CIB, -1);
520 }
521 }
522 #endif
523
524 } else {
525 cib_our_uname = strdup("localhost");
526 }
527
528 cib_ipc_servers_init(&ipcs_ro,
529 &ipcs_rw,
530 &ipcs_shm,
531 &ipc_ro_callbacks,
532 &ipc_rw_callbacks);
533
534 if (stand_alone) {
535 cib_is_master = TRUE;
536 }
537
538
539 mainloop = g_main_new(FALSE);
540 crm_info("Starting %s mainloop", crm_system_name);
541 g_main_run(mainloop);
542
543
544
545
546 crm_cluster_disconnect(&crm_cluster);
547 cib_ipc_servers_destroy(ipcs_ro, ipcs_rw, ipcs_shm);
548
549 return crm_exit(pcmk_ok);
550 }
551
552 gboolean
553 startCib(const char *filename)
554 {
555 gboolean active = FALSE;
556 xmlNode *cib = readCibXmlFile(cib_root, filename, !preserve_status);
557
558 CRM_ASSERT(cib != NULL);
559
560 if (activateCibXml(cib, TRUE, "start") == 0) {
561 int port = 0;
562 const char *port_s = NULL;
563
564 active = TRUE;
565
566 cib_read_config(config_hash, cib);
567
568 port_s = crm_element_value(cib, "remote-tls-port");
569 if (port_s) {
570 port = crm_parse_int(port_s, "0");
571 remote_tls_fd = init_remote_listener(port, TRUE);
572 }
573
574 port_s = crm_element_value(cib, "remote-clear-port");
575 if (port_s) {
576 port = crm_parse_int(port_s, "0");
577 remote_fd = init_remote_listener(port, FALSE);
578 }
579
580 crm_info("CIB Initialization completed successfully");
581 }
582
583 return active;
584 }