2
2
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
4
4
* This program is free software; you can redistribute it and/or
5
5
* modify it under the terms of the GNU General Public
6
6
* License as published by the Free Software Foundation; either
7
7
* version 2 of the License, or (at your option) any later version.
9
9
* This software is distributed in the hope that it will be useful,
10
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
12
* General Public License for more details.
14
14
* You should have received a copy of the GNU General Public
15
15
* License along with this library; if not, write to the Free Software
16
16
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
58
58
extern gboolean stand_alone;
60
60
gboolean cib_shutdown_flag = FALSE;
61
enum cib_errors cib_status = cib_ok;
61
int cib_status = pcmk_ok;
63
crm_cluster_t crm_cluster;
63
65
#if SUPPORT_HEARTBEAT
64
66
oc_ev_t *cib_ev_token;
65
67
ll_cluster_t *hb_conn = NULL;
66
68
extern void oc_ev_special(const oc_ev_t *, oc_ev_class_t, int);
67
69
gboolean cib_register_ha(ll_cluster_t * hb_cluster, const char *client_name);
70
74
extern void terminate_cib(const char *caller, gboolean fast);
72
76
GMainLoop *mainloop = NULL;
73
const char *cib_root = CRM_CONFIG_DIR;
77
const char *cib_root = NULL;
74
78
char *cib_our_uname = NULL;
75
79
gboolean preserve_status = FALSE;
76
80
gboolean cib_writes_enabled = TRUE;
78
82
int remote_tls_fd = 0;
80
void usage(const char *cmd, int exit_status);
81
84
int cib_init(void);
82
85
void cib_shutdown(int nsig);
83
void cib_ha_connection_destroy(gpointer user_data);
84
86
gboolean startCib(const char *filename);
85
87
extern int write_cib_contents(gpointer p);
87
GTRIGSource *cib_writer = NULL;
88
GHashTable *client_list = NULL;
89
89
GHashTable *config_hash = NULL;
90
GHashTable *local_notify_queue = NULL;
91
92
char *channel1 = NULL;
92
93
char *channel2 = NULL;
108
cib_diskwrite_complete(gpointer userdata, int status, int signo, int exitcode)
110
if (exitcode != LSB_EXIT_OK || signo != 0 || status != 0) {
111
crm_err("Disk write failed: status=%d, signo=%d, exitcode=%d", status, signo, exitcode);
113
if (cib_writes_enabled) {
114
crm_err("Disabling disk writes after write failure");
115
cib_writes_enabled = FALSE;
119
crm_trace("Disk write passed");
124
109
log_cib_client(gpointer key, gpointer value, gpointer user_data)
126
cib_client_t *a_client = value;
128
crm_info("Client %s/%s", crm_str(a_client->name),
129
crm_str(a_client->channel_name));
111
crm_info("Client %s", crm_client_name(value));
115
static struct crm_option long_options[] = {
116
/* Top-level Options */
117
{"help", 0, 0, '?', "\tThis text"},
118
{"verbose", 0, 0, 'V', "\tIncrease debug output"},
120
{"per-action-cib", 0, 0, 'a', "\tAdvanced use only"},
121
{"stand-alone", 0, 0, 's', "\tAdvanced use only"},
122
{"disk-writes", 0, 0, 'w', "\tAdvanced use only"},
123
{"cib-root", 1, 0, 'r', "\tAdvanced use only"},
133
130
main(int argc, char **argv)
140
int option_index = 0;
142
static struct option long_options[] = {
143
{"per-action-cib", 0, 0, 'a'},
144
{"stand-alone", 0, 0, 's'},
145
{"disk-writes", 0, 0, 'w'},
147
{"cib-root", 1, 0, 'r'},
149
{"verbose", 0, 0, 'V'},
151
{"metadata", 0, 0, 'm'},
158
136
struct passwd *pwentry = NULL;
160
crm_log_init("cib", LOG_INFO, TRUE, FALSE, 0, NULL);
138
crm_log_init(NULL, LOG_INFO, TRUE, FALSE, argc, argv, FALSE);
139
crm_set_options(NULL, "[options]",
140
long_options, "Daemon for storing and replicating the cluster configuration");
161
142
mainloop_add_signal(SIGTERM, cib_shutdown);
162
143
mainloop_add_signal(SIGPIPE, cib_enable_writes);
165
G_main_add_tempproc_trigger(G_PRIORITY_LOW, write_cib_contents, "write_cib_contents", NULL,
166
NULL, NULL, cib_diskwrite_complete);
168
/* EnableProcLogging(); */
169
set_sigchld_proctrack(G_PRIORITY_HIGH, DEFAULT_MAXDISPATCHTIME);
145
cib_writer = mainloop_add_trigger(G_PRIORITY_LOW, write_cib_contents, NULL);
172
client_list = g_hash_table_new(crm_str_hash, g_str_equal);
176
flag = getopt_long(argc, argv, OPTARGS, long_options, &option_index);
178
flag = getopt(argc, argv, OPTARGS);
150
flag = crm_get_option(argc, argv, &index);
185
crm_bump_log_level();
156
crm_bump_log_level(argc, argv);
188
159
stand_alone = TRUE;
236
usage(crm_system_name, LSB_EXIT_GENERIC);
207
crm_help('?', EX_USAGE);
210
if (cib_root == NULL) {
211
char *path = g_strdup_printf("%s/cib.xml", CRM_CONFIG_DIR);
212
char *legacy = g_strdup_printf("%s/cib.xml", CRM_LEGACY_CONFIG_DIR);
214
if (g_file_test(path, G_FILE_TEST_EXISTS)) {
215
cib_root = CRM_CONFIG_DIR;
217
} else if (g_file_test(legacy, G_FILE_TEST_EXISTS)) {
218
cib_root = CRM_LEGACY_CONFIG_DIR;
219
crm_notice("Using legacy config location: %s", cib_root);
222
cib_root = CRM_CONFIG_DIR;
223
crm_notice("Using new config location: %s", cib_root);
230
crm_notice("Using custom config location: %s", cib_root);
239
233
if (crm_is_writable(cib_root, NULL, CRM_DAEMON_USER, CRM_DAEMON_GROUP, FALSE) == FALSE) {
264
259
cib_cleanup(void)
266
261
crm_peer_destroy();
262
if (local_notify_queue) {
263
g_hash_table_destroy(local_notify_queue);
265
crm_client_cleanup();
267
266
g_hash_table_destroy(config_hash);
268
g_hash_table_destroy(client_list);
269
crm_free(cib_our_uname);
280
275
unsigned long cib_num_ops = 0;
281
276
const char *cib_stat_interval = "10min";
282
277
unsigned long cib_num_local = 0, cib_num_updates = 0, cib_num_fail = 0;
283
278
unsigned long cib_bad_connects = 0, cib_num_timeouts = 0;
284
longclock_t cib_call_time = 0;
286
gboolean cib_stats(gpointer data);
289
cib_stats(gpointer data)
291
int local_log_level = LOG_DEBUG;
292
static unsigned long last_stat = 0;
293
unsigned int cib_calls_ms = 0;
294
static unsigned long cib_stat_interval_ms = 0;
296
if (cib_stat_interval_ms == 0) {
297
cib_stat_interval_ms = crm_get_msec(cib_stat_interval);
300
cib_calls_ms = longclockto_ms(cib_call_time);
302
if ((cib_num_ops - last_stat) > 0) {
303
unsigned long calls_diff = cib_num_ops - last_stat;
304
double stat_1 = (1000 * cib_calls_ms) / calls_diff;
306
local_log_level = LOG_INFO;
307
do_crm_log(local_log_level,
308
"Processed %lu operations"
309
" (%.2fus average, %lu%% utilization) in the last %s",
311
(100 * cib_calls_ms) / cib_stat_interval_ms, cib_stat_interval);
315
"\tDetail: %lu operations (%ums total)"
316
" (%lu local, %lu updates, %lu failures,"
317
" %lu timeouts, %lu bad connects)",
318
cib_num_ops, cib_calls_ms, cib_num_local, cib_num_updates,
319
cib_num_fail, cib_bad_connects, cib_num_timeouts);
321
last_stat = cib_num_ops;
326
280
#if SUPPORT_HEARTBEAT
327
281
gboolean ccm_connect(void);
348
302
int (*ccm_api_register) (oc_ev_t ** token) =
349
find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_register");
303
find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_register", 1);
351
305
int (*ccm_api_set_callback) (const oc_ev_t * token,
352
306
oc_ev_class_t class,
353
307
oc_ev_callback_t * fn,
354
308
oc_ev_callback_t ** prev_fn) =
355
find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_set_callback");
309
find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_set_callback", 1);
357
311
void (*ccm_api_special) (const oc_ev_t *, oc_ev_class_t, int) =
358
find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_special");
312
find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_special", 1);
359
313
int (*ccm_api_activate) (const oc_ev_t * token, int *fd) =
360
find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_activate");
314
find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_activate", 1);
361
315
int (*ccm_api_unregister) (oc_ev_t * token) =
362
find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_unregister");
316
find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_unregister", 1);
318
static struct mainloop_fd_callbacks ccm_fd_callbacks = {
319
.dispatch = cib_ccm_dispatch,
320
.destroy = ccm_connection_destroy,
364
323
while (did_fail) {
365
324
did_fail = FALSE;
454
cib_ais_status_callback(enum crm_status_type type, crm_node_t * node, const void *data)
411
cib_peer_update_callback(enum crm_status_type type, crm_node_t * node, const void *data)
456
if(cib_shutdown_flag && crm_active_peers(crm_proc_cib) < 2 && g_hash_table_size(client_list) == 0) {
414
/* crm_active_peers(crm_proc_cib) appears to give the wrong answer
415
* sometimes, this might help figure out why
417
if (type == crm_status_nstate) {
418
crm_info("status: %s is now %s (was %s)", node->uname, node->state, (const char *)data);
419
if (safe_str_eq(CRMD_JOINSTATE_MEMBER, node->state)) {
423
} else if (type == crm_status_processes) {
427
old = *(const uint32_t *)data;
430
if ((node->processes ^ old) & crm_proc_cib) {
431
crm_info("status: cib process on %s is now %sactive",
432
node->uname, is_set(node->processes, crm_proc_cib) ? "" : "in");
441
if (cib_shutdown_flag && crm_active_peers() < 2 && crm_hash_table_size(client_connections) == 0) {
457
442
crm_info("No more peers");
458
443
terminate_cib(__FUNCTION__, FALSE);
447
#if SUPPORT_HEARTBEAT
449
cib_ha_connection_destroy(gpointer user_data)
451
if (cib_shutdown_flag) {
452
crm_info("Heartbeat disconnection complete... exiting");
453
terminate_cib(__FUNCTION__, FALSE);
455
crm_err("Heartbeat connection lost! Exiting.");
456
terminate_cib(__FUNCTION__, TRUE);
465
gboolean was_error = FALSE;
464
if (is_openais_cluster()) {
466
crm_cluster.destroy = cib_ais_destroy;
467
crm_cluster.cs_dispatch = cib_ais_dispatch;
469
} else if (is_heartbeat_cluster()) {
470
#if SUPPORT_HEARTBEAT
471
crm_cluster.hb_dispatch = cib_ha_peer_callback;
472
crm_cluster.destroy = cib_ha_connection_destroy;
468
477
g_hash_table_new_full(crm_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str);
470
479
if (startCib("cib.xml") == FALSE) {
471
480
crm_crit("Cannot start CIB... terminating");
475
484
if (stand_alone == FALSE) {
476
void *dispatch = cib_ha_peer_callback;
477
void *destroy = cib_ha_connection_destroy;
479
if (is_openais_cluster()) {
481
destroy = cib_ais_destroy;
482
dispatch = cib_ais_dispatch;
486
if (crm_cluster_connect(&cib_our_uname, NULL, dispatch, destroy,
487
#if SUPPORT_HEARTBEAT
485
if (crm_cluster_connect(&crm_cluster) == FALSE) {
493
486
crm_crit("Cannot sign in to the cluster... terminating");
489
cib_our_uname = crm_cluster.uname;
496
490
if (is_openais_cluster()) {
497
crm_set_status_callback(&cib_ais_status_callback);
491
crm_set_status_callback(&cib_peer_update_callback);
499
493
#if SUPPORT_HEARTBEAT
500
494
if (is_heartbeat_cluster()) {
496
gboolean was_error = FALSE;
498
hb_conn = crm_cluster.hb_conn;
502
499
if (was_error == FALSE) {
504
501
hb_conn->llc_ops->set_cstatus_callback(hb_conn, cib_client_status_callback,
525
cib_our_uname = crm_strdup("localhost");
522
cib_our_uname = strdup("localhost");
528
channel1 = crm_strdup(cib_channel_callback);
529
was_error = init_server_ipc_comms(channel1, cib_client_connect, default_ipc_connection_destroy);
531
channel2 = crm_strdup(cib_channel_ro);
532
was_error = was_error || init_server_ipc_comms(channel2, cib_client_connect,
533
default_ipc_connection_destroy);
535
channel3 = crm_strdup(cib_channel_rw);
536
was_error = was_error || init_server_ipc_comms(channel3, cib_client_connect,
537
default_ipc_connection_destroy);
525
cib_ipc_servers_init(&ipcs_ro,
539
531
if (stand_alone) {
541
crm_err("Couldnt start");
544
532
cib_is_master = TRUE;
546
/* Create the mainloop and run it... */
547
mainloop = g_main_new(FALSE);
548
crm_info("Starting %s mainloop", crm_system_name);
550
g_main_run(mainloop);
554
if (was_error == FALSE) {
555
/* Create the mainloop and run it... */
556
mainloop = g_main_new(FALSE);
557
crm_info("Starting %s mainloop", crm_system_name);
559
g_timeout_add(crm_get_msec(cib_stat_interval), cib_stats, NULL);
561
g_main_run(mainloop);
564
crm_err("Couldnt start all communication channels, exiting.");
571
usage(const char *cmd, int exit_status)
575
stream = exit_status ? stderr : stdout;
577
fprintf(stream, "usage: %s [-%s]\n", cmd, OPTARGS);
578
fprintf(stream, "\t--%s (-%c)\t\tTurn on debug info."
579
" Additional instances increase verbosity\n", "verbose", 'V');
580
fprintf(stream, "\t--%s (-%c)\t\tThis help message\n", "help", '?');
581
fprintf(stream, "\t--%s (-%c)\t\tShow configurable cib options\n", "metadata", 'm');
582
fprintf(stream, "\t--%s (-%c)\tAdvanced use only\n", "per-action-cib", 'a');
583
fprintf(stream, "\t--%s (-%c)\tAdvanced use only\n", "stand-alone", 's');
584
fprintf(stream, "\t--%s (-%c)\tAdvanced use only\n", "disk-writes", 'w');
585
fprintf(stream, "\t--%s (-%c)\t\tAdvanced use only\n", "cib-root", 'r');
592
cib_ha_connection_destroy(gpointer user_data)
594
if (cib_shutdown_flag) {
595
crm_info("Heartbeat disconnection complete... exiting");
596
terminate_cib(__FUNCTION__, FALSE);
598
crm_err("Heartbeat connection lost! Exiting.");
599
terminate_cib(__FUNCTION__, TRUE);
604
disconnect_cib_client(gpointer key, gpointer value, gpointer user_data)
606
cib_client_t *a_client = value;
608
crm_trace("Processing client %s/%s... send=%d, recv=%d",
609
crm_str(a_client->name), crm_str(a_client->channel_name),
610
(int)a_client->channel->send_queue->current_qlen,
611
(int)a_client->channel->recv_queue->current_qlen);
613
if (a_client->channel->ch_status == IPC_CONNECT) {
614
a_client->channel->ops->resume_io(a_client->channel);
615
if (a_client->channel->send_queue->current_qlen != 0
616
|| a_client->channel->recv_queue->current_qlen != 0) {
617
crm_info("Flushed messages to/from %s/%s... send=%d, recv=%d",
618
crm_str(a_client->name),
619
crm_str(a_client->channel_name),
620
(int)a_client->channel->send_queue->current_qlen,
621
(int)a_client->channel->recv_queue->current_qlen);
625
if (a_client->channel->ch_status == IPC_CONNECT) {
626
crm_warn("Disconnecting %s/%s...",
627
crm_str(a_client->name), crm_str(a_client->channel_name));
628
a_client->channel->ops->disconnect(a_client->channel);
632
extern gboolean cib_process_disconnect(IPC_Channel * channel, cib_client_t * cib_client);
635
cib_shutdown(int nsig)
637
if (cib_shutdown_flag == FALSE) {
638
cib_shutdown_flag = TRUE;
639
crm_debug("Disconnecting %d clients", g_hash_table_size(client_list));
640
g_hash_table_foreach(client_list, disconnect_cib_client, NULL);
641
crm_info("Disconnected %d clients", g_hash_table_size(client_list));
642
cib_process_disconnect(NULL, NULL);
645
crm_info("Waiting for %d clients to disconnect...", g_hash_table_size(client_list));
535
/* Create the mainloop and run it... */
536
mainloop = g_main_new(FALSE);
537
crm_info("Starting %s mainloop", crm_system_name);
539
g_main_run(mainloop);
540
cib_ipc_servers_destroy(ipcs_ro, ipcs_rw, ipcs_shm);