This source file includes following definitions.
- cib_legacy_mode
- cib_ipc_accept
- cib_ipc_dispatch_rw
- cib_ipc_dispatch_ro
- cib_ipc_closed
- cib_ipc_destroy
- cib_common_callback_worker
- cib_common_callback
- cib_digester_cb
- process_ping_reply
- do_local_notify
- local_notify_destroy_callback
- check_local_notify
- queue_local_notify
- parse_local_options_v1
- parse_local_options_v2
- parse_local_options
- parse_peer_options_v1
- parse_peer_options_v2
- parse_peer_options
- forward_request
- send_peer_reply
- cib_process_request
- calculate_section_digest
- contains_config_change
- cib_process_command
- cib_peer_callback
- cib_force_exit
- disconnect_remote_client
- initiate_exit
- cib_shutdown
- terminate_cib
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <sys/param.h>
13 #include <stdio.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16
17 #include <stdlib.h>
18 #include <stdint.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <inttypes.h>
22
23 #include <crm/crm.h>
24 #include <crm/cib.h>
25 #include <crm/msg_xml.h>
26 #include <crm/cluster/internal.h>
27
28 #include <crm/common/xml.h>
29 #include <crm/common/remote_internal.h>
30
31 #include <pacemaker-based.h>
32
33 #define EXIT_ESCALATION_MS 10000
34 #define OUR_NODENAME (stand_alone? "localhost" : crm_cluster->uname)
35
36 static unsigned long cib_local_bcast_num = 0;
37
38 typedef struct cib_local_notify_s {
39 xmlNode *notify_src;
40 char *client_id;
41 gboolean from_peer;
42 gboolean sync_reply;
43 } cib_local_notify_t;
44
45 int next_client_id = 0;
46
47 gboolean legacy_mode = FALSE;
48
49 qb_ipcs_service_t *ipcs_ro = NULL;
50 qb_ipcs_service_t *ipcs_rw = NULL;
51 qb_ipcs_service_t *ipcs_shm = NULL;
52
53 static void cib_process_request(xmlNode *request, gboolean privileged,
54 const pcmk__client_t *cib_client);
55
56 static int cib_process_command(xmlNode *request, xmlNode **reply,
57 xmlNode **cib_diff, gboolean privileged);
58
59 static gboolean cib_common_callback(qb_ipcs_connection_t *c, void *data,
60 size_t size, gboolean privileged);
61
62 gboolean
63 cib_legacy_mode(void)
64 {
65 return legacy_mode;
66 }
67
68 static int32_t
69 cib_ipc_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
70 {
71 if (cib_shutdown_flag) {
72 crm_info("Ignoring new IPC client [%d] during shutdown",
73 pcmk__client_pid(c));
74 return -EPERM;
75 }
76
77 if (pcmk__new_client(c, uid, gid) == NULL) {
78 return -EIO;
79 }
80 return 0;
81 }
82
83 static int32_t
84 cib_ipc_dispatch_rw(qb_ipcs_connection_t * c, void *data, size_t size)
85 {
86 pcmk__client_t *client = pcmk__find_client(c);
87
88 crm_trace("%p message from %s", c, client->id);
89 return cib_common_callback(c, data, size, TRUE);
90 }
91
92 static int32_t
93 cib_ipc_dispatch_ro(qb_ipcs_connection_t * c, void *data, size_t size)
94 {
95 pcmk__client_t *client = pcmk__find_client(c);
96
97 crm_trace("%p message from %s", c, client->id);
98 return cib_common_callback(c, data, size, FALSE);
99 }
100
101
102 static int32_t
103 cib_ipc_closed(qb_ipcs_connection_t * c)
104 {
105 pcmk__client_t *client = pcmk__find_client(c);
106
107 if (client == NULL) {
108 return 0;
109 }
110 crm_trace("Connection %p", c);
111 pcmk__free_client(client);
112 return 0;
113 }
114
115 static void
116 cib_ipc_destroy(qb_ipcs_connection_t * c)
117 {
118 crm_trace("Connection %p", c);
119 cib_ipc_closed(c);
120 if (cib_shutdown_flag) {
121 cib_shutdown(0);
122 }
123 }
124
125 struct qb_ipcs_service_handlers ipc_ro_callbacks = {
126 .connection_accept = cib_ipc_accept,
127 .connection_created = NULL,
128 .msg_process = cib_ipc_dispatch_ro,
129 .connection_closed = cib_ipc_closed,
130 .connection_destroyed = cib_ipc_destroy
131 };
132
133 struct qb_ipcs_service_handlers ipc_rw_callbacks = {
134 .connection_accept = cib_ipc_accept,
135 .connection_created = NULL,
136 .msg_process = cib_ipc_dispatch_rw,
137 .connection_closed = cib_ipc_closed,
138 .connection_destroyed = cib_ipc_destroy
139 };
140
141 void
142 cib_common_callback_worker(uint32_t id, uint32_t flags, xmlNode * op_request,
143 pcmk__client_t *cib_client, gboolean privileged)
144 {
145 const char *op = crm_element_value(op_request, F_CIB_OPERATION);
146
147 if (pcmk__str_eq(op, CRM_OP_REGISTER, pcmk__str_none)) {
148 if (flags & crm_ipc_client_response) {
149 xmlNode *ack = create_xml_node(NULL, __func__);
150
151 crm_xml_add(ack, F_CIB_OPERATION, CRM_OP_REGISTER);
152 crm_xml_add(ack, F_CIB_CLIENTID, cib_client->id);
153 pcmk__ipc_send_xml(cib_client, id, ack, flags);
154 cib_client->request_id = 0;
155 free_xml(ack);
156 }
157 return;
158
159 } else if (pcmk__str_eq(op, T_CIB_NOTIFY, pcmk__str_none)) {
160
161 int on_off = 0;
162 crm_exit_t status = CRM_EX_OK;
163 uint64_t bit = UINT64_C(0);
164 const char *type = crm_element_value(op_request, F_CIB_NOTIFY_TYPE);
165
166 crm_element_value_int(op_request, F_CIB_NOTIFY_ACTIVATE, &on_off);
167
168 crm_debug("Setting %s callbacks %s for client %s",
169 type, (on_off? "on" : "off"), pcmk__client_name(cib_client));
170
171 if (pcmk__str_eq(type, T_CIB_POST_NOTIFY, pcmk__str_casei)) {
172 bit = cib_notify_post;
173
174 } else if (pcmk__str_eq(type, T_CIB_PRE_NOTIFY, pcmk__str_casei)) {
175 bit = cib_notify_pre;
176
177 } else if (pcmk__str_eq(type, T_CIB_UPDATE_CONFIRM, pcmk__str_casei)) {
178 bit = cib_notify_confirm;
179
180 } else if (pcmk__str_eq(type, T_CIB_DIFF_NOTIFY, pcmk__str_casei)) {
181 bit = cib_notify_diff;
182
183 } else if (pcmk__str_eq(type, T_CIB_REPLACE_NOTIFY, pcmk__str_casei)) {
184 bit = cib_notify_replace;
185
186 } else {
187 status = CRM_EX_INVALID_PARAM;
188 }
189
190 if (bit != 0) {
191 if (on_off) {
192 pcmk__set_client_flags(cib_client, bit);
193 } else {
194 pcmk__clear_client_flags(cib_client, bit);
195 }
196 }
197
198 pcmk__ipc_send_ack(cib_client, id, flags, "ack", NULL, status);
199 return;
200 }
201
202 cib_process_request(op_request, privileged, cib_client);
203 }
204
205 int32_t
206 cib_common_callback(qb_ipcs_connection_t * c, void *data, size_t size, gboolean privileged)
207 {
208 uint32_t id = 0;
209 uint32_t flags = 0;
210 int call_options = 0;
211 pcmk__client_t *cib_client = pcmk__find_client(c);
212 xmlNode *op_request = pcmk__client_data2xml(cib_client, data, &id, &flags);
213
214 if (op_request) {
215 crm_element_value_int(op_request, F_CIB_CALLOPTS, &call_options);
216 }
217
218 if (op_request == NULL) {
219 crm_trace("Invalid message from %p", c);
220 pcmk__ipc_send_ack(cib_client, id, flags, "nack", NULL, CRM_EX_PROTOCOL);
221 return 0;
222
223 } else if(cib_client == NULL) {
224 crm_trace("Invalid client %p", c);
225 return 0;
226 }
227
228 if (pcmk_is_set(call_options, cib_sync_call)) {
229 CRM_LOG_ASSERT(flags & crm_ipc_client_response);
230 CRM_LOG_ASSERT(cib_client->request_id == 0);
231 cib_client->request_id = id;
232 }
233
234 if (cib_client->name == NULL) {
235 const char *value = crm_element_value(op_request, F_CIB_CLIENTNAME);
236
237 if (value == NULL) {
238 cib_client->name = pcmk__itoa(cib_client->pid);
239 } else {
240 cib_client->name = strdup(value);
241 if (crm_is_daemon_name(value)) {
242 pcmk__set_client_flags(cib_client, cib_is_daemon);
243 }
244 }
245 }
246
247
248 if (pcmk_is_set(cib_client->flags, cib_is_daemon)) {
249 const char *qmax = cib_config_lookup("cluster-ipc-limit");
250
251 if (pcmk__set_client_queue_max(cib_client, qmax)) {
252 crm_trace("IPC threshold for client %s[%u] is now %u",
253 pcmk__client_name(cib_client), cib_client->pid,
254 cib_client->queue_max);
255 }
256 }
257
258 crm_xml_add(op_request, F_CIB_CLIENTID, cib_client->id);
259 crm_xml_add(op_request, F_CIB_CLIENTNAME, cib_client->name);
260
261 CRM_LOG_ASSERT(cib_client->user != NULL);
262 pcmk__update_acl_user(op_request, F_CIB_USER, cib_client->user);
263
264 cib_common_callback_worker(id, flags, op_request, cib_client, privileged);
265 free_xml(op_request);
266
267 return 0;
268 }
269
270 static uint64_t ping_seq = 0;
271 static char *ping_digest = NULL;
272 static bool ping_modified_since = FALSE;
273
274 static gboolean
275 cib_digester_cb(gpointer data)
276 {
277 if (based_is_primary) {
278 char buffer[32];
279 xmlNode *ping = create_xml_node(NULL, "ping");
280
281 ping_seq++;
282 free(ping_digest);
283 ping_digest = NULL;
284 ping_modified_since = FALSE;
285 snprintf(buffer, 32, "%" PRIu64, ping_seq);
286 crm_trace("Requesting peer digests (%s)", buffer);
287
288 crm_xml_add(ping, F_TYPE, "cib");
289 crm_xml_add(ping, F_CIB_OPERATION, CRM_OP_PING);
290 crm_xml_add(ping, F_CIB_PING_ID, buffer);
291
292 crm_xml_add(ping, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
293 send_cluster_message(NULL, crm_msg_cib, ping, TRUE);
294
295 free_xml(ping);
296 }
297 return FALSE;
298 }
299
300 static void
301 process_ping_reply(xmlNode *reply)
302 {
303 uint64_t seq = 0;
304 const char *host = crm_element_value(reply, F_ORIG);
305
306 xmlNode *pong = get_message_xml(reply, F_CIB_CALLDATA);
307 const char *seq_s = crm_element_value(pong, F_CIB_PING_ID);
308 const char *digest = crm_element_value(pong, XML_ATTR_DIGEST);
309
310 if (seq_s == NULL) {
311 crm_debug("Ignoring ping reply with no " F_CIB_PING_ID);
312 return;
313
314 } else {
315 long long seq_ll;
316
317 if (pcmk__scan_ll(seq_s, &seq_ll, 0LL) != pcmk_rc_ok) {
318 return;
319 }
320 seq = (uint64_t) seq_ll;
321 }
322
323 if(digest == NULL) {
324 crm_trace("Ignoring ping reply %s from %s with no digest", seq_s, host);
325
326 } else if(seq != ping_seq) {
327 crm_trace("Ignoring out of sequence ping reply %s from %s", seq_s, host);
328
329 } else if(ping_modified_since) {
330 crm_trace("Ignoring ping reply %s from %s: cib updated since", seq_s, host);
331
332 } else {
333 const char *version = crm_element_value(pong, XML_ATTR_CRM_VERSION);
334
335 if(ping_digest == NULL) {
336 crm_trace("Calculating new digest");
337 ping_digest = calculate_xml_versioned_digest(the_cib, FALSE, TRUE, version);
338 }
339
340 crm_trace("Processing ping reply %s from %s (%s)", seq_s, host, digest);
341 if (!pcmk__str_eq(ping_digest, digest, pcmk__str_casei)) {
342 xmlNode *remote_cib = get_message_xml(pong, F_CIB_CALLDATA);
343
344 crm_notice("Local CIB %s.%s.%s.%s differs from %s: %s.%s.%s.%s %p",
345 crm_element_value(the_cib, XML_ATTR_GENERATION_ADMIN),
346 crm_element_value(the_cib, XML_ATTR_GENERATION),
347 crm_element_value(the_cib, XML_ATTR_NUMUPDATES),
348 ping_digest, host,
349 remote_cib?crm_element_value(remote_cib, XML_ATTR_GENERATION_ADMIN):"_",
350 remote_cib?crm_element_value(remote_cib, XML_ATTR_GENERATION):"_",
351 remote_cib?crm_element_value(remote_cib, XML_ATTR_NUMUPDATES):"_",
352 digest, remote_cib);
353
354 if(remote_cib && remote_cib->children) {
355
356 xml_calculate_changes(the_cib, remote_cib);
357
358 pcmk__output_set_log_level(logger_out, LOG_INFO);
359 pcmk__xml_show_changes(logger_out, remote_cib);
360 crm_trace("End of differences");
361 }
362
363 free_xml(remote_cib);
364 sync_our_cib(reply, FALSE);
365 }
366 }
367 }
368
369 static void
370 do_local_notify(xmlNode * notify_src, const char *client_id,
371 gboolean sync_reply, gboolean from_peer)
372 {
373 int rid = 0;
374 int call_id = 0;
375 pcmk__client_t *client_obj = NULL;
376
377 CRM_ASSERT(notify_src && client_id);
378
379 crm_element_value_int(notify_src, F_CIB_CALLID, &call_id);
380
381 client_obj = pcmk__find_client_by_id(client_id);
382 if (client_obj == NULL) {
383 crm_debug("Could not send response %d: client %s not found",
384 call_id, client_id);
385 return;
386 }
387
388 if (sync_reply) {
389 if (client_obj->ipcs) {
390 CRM_LOG_ASSERT(client_obj->request_id);
391
392 rid = client_obj->request_id;
393 client_obj->request_id = 0;
394
395 crm_trace("Sending response %d to client %s%s",
396 rid, pcmk__client_name(client_obj),
397 (from_peer? " (originator of delegated request)" : ""));
398 } else {
399 crm_trace("Sending response (call %d) to client %s%s",
400 call_id, pcmk__client_name(client_obj),
401 (from_peer? " (originator of delegated request)" : ""));
402 }
403
404 } else {
405 crm_trace("Sending event %d to client %s%s",
406 call_id, pcmk__client_name(client_obj),
407 (from_peer? " (originator of delegated request)" : ""));
408 }
409
410 switch (PCMK__CLIENT_TYPE(client_obj)) {
411 case pcmk__client_ipc:
412 {
413 int rc = pcmk__ipc_send_xml(client_obj, rid, notify_src,
414 (sync_reply? crm_ipc_flags_none
415 : crm_ipc_server_event));
416
417 if (rc != pcmk_rc_ok) {
418 crm_warn("%s reply to client %s failed: %s " CRM_XS " rc=%d",
419 (sync_reply? "Synchronous" : "Asynchronous"),
420 pcmk__client_name(client_obj), pcmk_rc_str(rc),
421 rc);
422 }
423 }
424 break;
425 #ifdef HAVE_GNUTLS_GNUTLS_H
426 case pcmk__client_tls:
427 #endif
428 case pcmk__client_tcp:
429 pcmk__remote_send_xml(client_obj->remote, notify_src);
430 break;
431 default:
432 crm_err("Unknown transport for client %s "
433 CRM_XS " flags=%#016" PRIx64,
434 pcmk__client_name(client_obj), client_obj->flags);
435 }
436 }
437
438 static void
439 local_notify_destroy_callback(gpointer data)
440 {
441 cib_local_notify_t *notify = data;
442
443 free_xml(notify->notify_src);
444 free(notify->client_id);
445 free(notify);
446 }
447
448 static void
449 check_local_notify(int bcast_id)
450 {
451 cib_local_notify_t *notify = NULL;
452
453 if (!local_notify_queue) {
454 return;
455 }
456
457 notify = pcmk__intkey_table_lookup(local_notify_queue, bcast_id);
458
459 if (notify) {
460 do_local_notify(notify->notify_src, notify->client_id, notify->sync_reply,
461 notify->from_peer);
462 pcmk__intkey_table_remove(local_notify_queue, bcast_id);
463 }
464 }
465
466 static void
467 queue_local_notify(xmlNode * notify_src, const char *client_id, gboolean sync_reply,
468 gboolean from_peer)
469 {
470 cib_local_notify_t *notify = calloc(1, sizeof(cib_local_notify_t));
471
472 notify->notify_src = notify_src;
473 notify->client_id = strdup(client_id);
474 notify->sync_reply = sync_reply;
475 notify->from_peer = from_peer;
476
477 if (!local_notify_queue) {
478 local_notify_queue = pcmk__intkey_table(local_notify_destroy_callback);
479 }
480 pcmk__intkey_table_insert(local_notify_queue, cib_local_bcast_num, notify);
481
482
483 }
484
485 static void
486 parse_local_options_v1(const pcmk__client_t *cib_client, int call_type,
487 int call_options, const char *host, const char *op,
488 gboolean *local_notify, gboolean *needs_reply,
489 gboolean *process, gboolean *needs_forward)
490 {
491 if (cib_op_modifies(call_type)
492 && !(call_options & cib_inhibit_bcast)) {
493
494 *needs_reply = TRUE;
495 } else {
496 *needs_reply = FALSE;
497 }
498
499 if (host == NULL && (call_options & cib_scope_local)) {
500 crm_trace("Processing locally scoped %s op from client %s",
501 op, pcmk__client_name(cib_client));
502 *local_notify = TRUE;
503
504 } else if ((host == NULL) && based_is_primary) {
505 crm_trace("Processing %s op locally from client %s as primary",
506 op, pcmk__client_name(cib_client));
507 *local_notify = TRUE;
508
509 } else if (pcmk__str_eq(host, OUR_NODENAME, pcmk__str_casei)) {
510 crm_trace("Processing locally addressed %s op from client %s",
511 op, pcmk__client_name(cib_client));
512 *local_notify = TRUE;
513
514 } else if (stand_alone) {
515 *needs_forward = FALSE;
516 *local_notify = TRUE;
517 *process = TRUE;
518
519 } else {
520 crm_trace("%s op from %s needs to be forwarded to client %s",
521 op, pcmk__client_name(cib_client),
522 pcmk__s(host, "the primary instance"));
523 *needs_forward = TRUE;
524 *process = FALSE;
525 }
526 }
527
528 static void
529 parse_local_options_v2(const pcmk__client_t *cib_client, int call_type,
530 int call_options, const char *host, const char *op,
531 gboolean *local_notify, gboolean *needs_reply,
532 gboolean *process, gboolean *needs_forward)
533 {
534 if (cib_op_modifies(call_type)) {
535 if (pcmk__str_any_of(op, PCMK__CIB_REQUEST_PRIMARY,
536 PCMK__CIB_REQUEST_SECONDARY, NULL)) {
537
538 *process = TRUE;
539 *needs_reply = FALSE;
540 *local_notify = TRUE;
541 *needs_forward = FALSE;
542 return;
543
544 } else {
545
546 *needs_reply = TRUE;
547 *needs_forward = TRUE;
548 *process = FALSE;
549 crm_trace("%s op from %s needs to be forwarded to client %s",
550 op, pcmk__client_name(cib_client),
551 pcmk__s(host, "the primary instance"));
552 return;
553 }
554 }
555
556
557 *process = TRUE;
558 *needs_reply = FALSE;
559 *local_notify = TRUE;
560 *needs_forward = FALSE;
561
562 if (stand_alone) {
563 crm_trace("Processing %s op from client %s (stand-alone)",
564 op, pcmk__client_name(cib_client));
565
566 } else if (host == NULL) {
567 crm_trace("Processing unaddressed %s op from client %s",
568 op, pcmk__client_name(cib_client));
569
570 } else if (pcmk__str_eq(host, OUR_NODENAME, pcmk__str_casei)) {
571 crm_trace("Processing locally addressed %s op from client %s",
572 op, pcmk__client_name(cib_client));
573
574 } else {
575 crm_trace("%s op from %s needs to be forwarded to client %s",
576 op, pcmk__client_name(cib_client), host);
577 *needs_forward = TRUE;
578 *process = FALSE;
579 }
580 }
581
582 static void
583 parse_local_options(const pcmk__client_t *cib_client, int call_type,
584 int call_options, const char *host, const char *op,
585 gboolean *local_notify, gboolean *needs_reply,
586 gboolean *process, gboolean *needs_forward)
587 {
588 if(cib_legacy_mode()) {
589 parse_local_options_v1(cib_client, call_type, call_options, host,
590 op, local_notify, needs_reply, process, needs_forward);
591 } else {
592 parse_local_options_v2(cib_client, call_type, call_options, host,
593 op, local_notify, needs_reply, process, needs_forward);
594 }
595 }
596
597 static gboolean
598 parse_peer_options_v1(int call_type, xmlNode * request,
599 gboolean * local_notify, gboolean * needs_reply, gboolean * process,
600 gboolean * needs_forward)
601 {
602 const char *op = NULL;
603 const char *host = NULL;
604 const char *delegated = NULL;
605 const char *originator = crm_element_value(request, F_ORIG);
606 const char *reply_to = crm_element_value(request, F_CIB_ISREPLY);
607
608 gboolean is_reply = pcmk__str_eq(reply_to, OUR_NODENAME, pcmk__str_casei);
609
610 if (pcmk__xe_attr_is_true(request, F_CIB_GLOBAL_UPDATE)) {
611 *needs_reply = FALSE;
612 if (is_reply) {
613 *local_notify = TRUE;
614 crm_trace("Processing global/peer update from %s"
615 " that originated from us", originator);
616 } else {
617 crm_trace("Processing global/peer update from %s", originator);
618 }
619 return TRUE;
620 }
621
622 op = crm_element_value(request, F_CIB_OPERATION);
623 crm_trace("Processing %s request sent by %s", op, originator);
624 if (pcmk__str_eq(op, PCMK__CIB_REQUEST_SHUTDOWN, pcmk__str_none)) {
625
626 *local_notify = FALSE;
627 if (reply_to == NULL || is_reply) {
628 *process = TRUE;
629 }
630 if (is_reply) {
631 *needs_reply = FALSE;
632 }
633 return *process;
634 }
635
636 if (is_reply && pcmk__str_eq(op, CRM_OP_PING, pcmk__str_casei)) {
637 process_ping_reply(request);
638 return FALSE;
639 }
640
641 if (is_reply) {
642 crm_trace("Forward reply sent from %s to local clients", originator);
643 *process = FALSE;
644 *needs_reply = FALSE;
645 *local_notify = TRUE;
646 return TRUE;
647 }
648
649 host = crm_element_value(request, F_CIB_HOST);
650 if (pcmk__str_eq(host, OUR_NODENAME, pcmk__str_casei)) {
651 crm_trace("Processing %s request sent to us from %s", op, originator);
652 return TRUE;
653
654 } else if(is_reply == FALSE && pcmk__str_eq(op, CRM_OP_PING, pcmk__str_casei)) {
655 crm_trace("Processing %s request sent to %s by %s", op, host?host:"everyone", originator);
656 *needs_reply = TRUE;
657 return TRUE;
658
659 } else if ((host == NULL) && based_is_primary) {
660 crm_trace("Processing %s request sent to primary instance from %s",
661 op, originator);
662 return TRUE;
663 }
664
665 delegated = crm_element_value(request, F_CIB_DELEGATED);
666 if (delegated != NULL) {
667 crm_trace("Ignoring message for primary instance");
668
669 } else if (host != NULL) {
670
671 crm_trace("Ignoring msg for instance on %s", host);
672
673 } else if ((reply_to == NULL) && !based_is_primary) {
674
675 crm_trace("Ignoring reply for primary instance");
676
677 } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_SHUTDOWN, pcmk__str_none)) {
678 if (reply_to != NULL) {
679 crm_debug("Processing %s from %s", op, originator);
680 *needs_reply = FALSE;
681
682 } else {
683 crm_debug("Processing %s reply from %s", op, originator);
684 }
685 return TRUE;
686
687 } else {
688 crm_err("Nothing for us to do?");
689 crm_log_xml_err(request, "Peer[inbound]");
690 }
691
692 return FALSE;
693 }
694
695 static gboolean
696 parse_peer_options_v2(int call_type, xmlNode * request,
697 gboolean * local_notify, gboolean * needs_reply, gboolean * process,
698 gboolean * needs_forward)
699 {
700 const char *host = NULL;
701 const char *delegated = crm_element_value(request, F_CIB_DELEGATED);
702 const char *op = crm_element_value(request, F_CIB_OPERATION);
703 const char *originator = crm_element_value(request, F_ORIG);
704 const char *reply_to = crm_element_value(request, F_CIB_ISREPLY);
705
706 gboolean is_reply = pcmk__str_eq(reply_to, OUR_NODENAME, pcmk__str_casei);
707
708 if (pcmk__str_eq(op, PCMK__CIB_REQUEST_REPLACE, pcmk__str_none)) {
709
710 if (reply_to) {
711 delegated = reply_to;
712 }
713 goto skip_is_reply;
714
715 } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_SYNC_TO_ALL,
716 pcmk__str_none)) {
717
718
719 } else if (is_reply && pcmk__str_eq(op, CRM_OP_PING, pcmk__str_casei)) {
720 process_ping_reply(request);
721 return FALSE;
722
723 } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_UPGRADE, pcmk__str_none)) {
724
725
726
727
728
729
730
731
732
733
734 const char *max = crm_element_value(request, F_CIB_SCHEMA_MAX);
735 const char *upgrade_rc = crm_element_value(request, F_CIB_UPGRADE_RC);
736
737 crm_trace("Parsing %s operation%s for %s with max=%s and upgrade_rc=%s",
738 op, (is_reply? " reply" : ""),
739 (based_is_primary? "primary" : "secondary"),
740 (max? max : "none"), (upgrade_rc? upgrade_rc : "none"));
741
742 if (upgrade_rc != NULL) {
743
744 crm_xml_add(request, F_CIB_RC, upgrade_rc);
745
746 } else if ((max == NULL) && based_is_primary) {
747
748 goto skip_is_reply;
749
750 } else if(max) {
751
752 goto skip_is_reply;
753
754 } else {
755
756 return FALSE;
757 }
758
759 } else if (pcmk__xe_attr_is_true(request, F_CIB_GLOBAL_UPDATE)) {
760 crm_info("Detected legacy %s global update from %s", op, originator);
761 send_sync_request(NULL);
762 legacy_mode = TRUE;
763 return FALSE;
764
765 } else if (is_reply && cib_op_modifies(call_type)) {
766 crm_trace("Ignoring legacy %s reply sent from %s to local clients", op, originator);
767 return FALSE;
768
769 } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_SHUTDOWN, pcmk__str_none)) {
770
771 crm_debug("Legacy handling of %s message from %s", op, originator);
772 *local_notify = FALSE;
773 if (reply_to == NULL) {
774 *process = TRUE;
775 }
776 return *process;
777 }
778
779 if(is_reply) {
780 crm_trace("Handling %s reply sent from %s to local clients", op, originator);
781 *process = FALSE;
782 *needs_reply = FALSE;
783 *local_notify = TRUE;
784 return TRUE;
785 }
786
787 skip_is_reply:
788 *process = TRUE;
789 *needs_reply = FALSE;
790
791 *local_notify = pcmk__str_eq(delegated, OUR_NODENAME, pcmk__str_casei);
792
793 host = crm_element_value(request, F_CIB_HOST);
794 if (pcmk__str_eq(host, OUR_NODENAME, pcmk__str_casei)) {
795 crm_trace("Processing %s request sent to us from %s", op, originator);
796 *needs_reply = TRUE;
797 return TRUE;
798
799 } else if (host != NULL) {
800
801 crm_trace("Ignoring %s operation for instance on %s", op, host);
802 return FALSE;
803
804 } else if(is_reply == FALSE && pcmk__str_eq(op, CRM_OP_PING, pcmk__str_casei)) {
805 *needs_reply = TRUE;
806 }
807
808 crm_trace("Processing %s request sent to everyone by %s/%s on %s %s", op,
809 crm_element_value(request, F_CIB_CLIENTNAME),
810 crm_element_value(request, F_CIB_CALLID),
811 originator, (*local_notify)?"(notify)":"");
812 return TRUE;
813 }
814
815 static gboolean
816 parse_peer_options(int call_type, xmlNode * request,
817 gboolean * local_notify, gboolean * needs_reply, gboolean * process,
818 gboolean * needs_forward)
819 {
820
821
822
823
824 if(cib_legacy_mode()) {
825 return parse_peer_options_v1(
826 call_type, request, local_notify, needs_reply, process, needs_forward);
827 } else {
828 return parse_peer_options_v2(
829 call_type, request, local_notify, needs_reply, process, needs_forward);
830 }
831 }
832
833 static void
834 forward_request(xmlNode *request, int call_options)
835 {
836 const char *op = crm_element_value(request, F_CIB_OPERATION);
837 const char *host = crm_element_value(request, F_CIB_HOST);
838
839 crm_xml_add(request, F_CIB_DELEGATED, OUR_NODENAME);
840
841 if (host != NULL) {
842 crm_trace("Forwarding %s op to %s", op, host);
843 send_cluster_message(crm_get_peer(0, host), crm_msg_cib, request, FALSE);
844
845 } else {
846 crm_trace("Forwarding %s op to primary instance", op);
847 send_cluster_message(NULL, crm_msg_cib, request, FALSE);
848 }
849
850
851 xml_remove_prop(request, F_CIB_DELEGATED);
852
853 if (call_options & cib_discard_reply) {
854 crm_trace("Client not interested in reply");
855 }
856 }
857
858 static gboolean
859 send_peer_reply(xmlNode * msg, xmlNode * result_diff, const char *originator, gboolean broadcast)
860 {
861 CRM_ASSERT(msg != NULL);
862
863 if (broadcast) {
864
865
866
867
868 int diff_add_updates = 0;
869 int diff_add_epoch = 0;
870 int diff_add_admin_epoch = 0;
871
872 int diff_del_updates = 0;
873 int diff_del_epoch = 0;
874 int diff_del_admin_epoch = 0;
875
876 const char *digest = NULL;
877 int format = 1;
878
879 CRM_LOG_ASSERT(result_diff != NULL);
880 digest = crm_element_value(result_diff, XML_ATTR_DIGEST);
881 crm_element_value_int(result_diff, "format", &format);
882
883 cib_diff_version_details(result_diff,
884 &diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates,
885 &diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);
886
887 crm_trace("Sending update diff %d.%d.%d -> %d.%d.%d %s",
888 diff_del_admin_epoch, diff_del_epoch, diff_del_updates,
889 diff_add_admin_epoch, diff_add_epoch, diff_add_updates, digest);
890
891 crm_xml_add(msg, F_CIB_ISREPLY, originator);
892 pcmk__xe_set_bool_attr(msg, F_CIB_GLOBAL_UPDATE, true);
893 crm_xml_add(msg, F_CIB_OPERATION, PCMK__CIB_REQUEST_APPLY_PATCH);
894 crm_xml_add(msg, F_CIB_USER, CRM_DAEMON_USER);
895
896 if (format == 1) {
897 CRM_ASSERT(digest != NULL);
898 }
899
900 add_message_xml(msg, F_CIB_UPDATE_DIFF, result_diff);
901 crm_log_xml_explicit(msg, "copy");
902 return send_cluster_message(NULL, crm_msg_cib, msg, TRUE);
903
904 } else if (originator != NULL) {
905
906 crm_trace("Sending request result to %s only", originator);
907 crm_xml_add(msg, F_CIB_ISREPLY, originator);
908 return send_cluster_message(crm_get_peer(0, originator), crm_msg_cib, msg, FALSE);
909 }
910
911 return FALSE;
912 }
913
914
915
916
917
918
919
920
921
922
923 static void
924 cib_process_request(xmlNode *request, gboolean privileged,
925 const pcmk__client_t *cib_client)
926 {
927 int call_type = 0;
928 int call_options = 0;
929
930 gboolean process = TRUE;
931 gboolean is_update = TRUE;
932 gboolean needs_reply = TRUE;
933 gboolean local_notify = FALSE;
934 gboolean needs_forward = FALSE;
935
936 xmlNode *op_reply = NULL;
937 xmlNode *result_diff = NULL;
938
939 int rc = pcmk_ok;
940 const char *op = crm_element_value(request, F_CIB_OPERATION);
941 const char *originator = crm_element_value(request, F_ORIG);
942 const char *host = crm_element_value(request, F_CIB_HOST);
943 const char *target = NULL;
944 const char *call_id = crm_element_value(request, F_CIB_CALLID);
945 const char *client_id = crm_element_value(request, F_CIB_CLIENTID);
946 const char *client_name = crm_element_value(request, F_CIB_CLIENTNAME);
947 const char *reply_to = crm_element_value(request, F_CIB_ISREPLY);
948
949 crm_element_value_int(request, F_CIB_CALLOPTS, &call_options);
950
951 if ((host != NULL) && (*host == '\0')) {
952 host = NULL;
953 }
954
955 if (host) {
956 target = host;
957
958 } else if (call_options & cib_scope_local) {
959 target = "local host";
960
961 } else {
962 target = "primary";
963 }
964
965 if (cib_client == NULL) {
966 crm_trace("Processing peer %s operation from %s/%s on %s intended for %s (reply=%s)",
967 op, client_name, call_id, originator, target, reply_to);
968 } else {
969 crm_xml_add(request, F_ORIG, OUR_NODENAME);
970 crm_trace("Processing local %s operation from %s/%s intended for %s", op, client_name, call_id, target);
971 }
972
973 rc = cib_get_operation_id(op, &call_type);
974 if (rc != pcmk_ok) {
975
976 crm_err("Pre-processing of command failed: %s", pcmk_strerror(rc));
977 return;
978 }
979
980 if (cib_client != NULL) {
981 parse_local_options(cib_client, call_type, call_options, host, op,
982 &local_notify, &needs_reply, &process, &needs_forward);
983
984 } else if (parse_peer_options(call_type, request, &local_notify,
985 &needs_reply, &process, &needs_forward) == FALSE) {
986 return;
987 }
988
989 is_update = cib_op_modifies(call_type);
990
991 if (call_options & cib_discard_reply) {
992
993
994
995
996 needs_reply = is_update && cib_legacy_mode();
997 local_notify = FALSE;
998 }
999
1000 if (needs_forward) {
1001 const char *section = crm_element_value(request, F_CIB_SECTION);
1002 int log_level = LOG_INFO;
1003
1004 if (pcmk__str_eq(op, PCMK__CIB_REQUEST_NOOP, pcmk__str_none)) {
1005 log_level = LOG_DEBUG;
1006 }
1007
1008 do_crm_log(log_level,
1009 "Forwarding %s operation for section %s to %s (origin=%s/%s/%s)",
1010 op,
1011 section ? section : "'all'",
1012 pcmk__s(host, (cib_legacy_mode() ? "primary" : "all")),
1013 originator ? originator : "local",
1014 client_name, call_id);
1015
1016 forward_request(request, call_options);
1017 return;
1018 }
1019
1020 if (cib_status != pcmk_ok) {
1021 const char *call = crm_element_value(request, F_CIB_CALLID);
1022
1023 rc = cib_status;
1024 crm_err("Operation ignored, cluster configuration is invalid."
1025 " Please repair and restart: %s", pcmk_strerror(cib_status));
1026
1027 op_reply = create_xml_node(NULL, "cib-reply");
1028 crm_xml_add(op_reply, F_TYPE, T_CIB);
1029 crm_xml_add(op_reply, F_CIB_OPERATION, op);
1030 crm_xml_add(op_reply, F_CIB_CALLID, call);
1031 crm_xml_add(op_reply, F_CIB_CLIENTID, client_id);
1032 crm_xml_add_int(op_reply, F_CIB_CALLOPTS, call_options);
1033 crm_xml_add_int(op_reply, F_CIB_RC, rc);
1034
1035 crm_trace("Attaching reply output");
1036 add_message_xml(op_reply, F_CIB_CALLDATA, the_cib);
1037
1038 crm_log_xml_explicit(op_reply, "cib:reply");
1039
1040 } else if (process) {
1041 time_t finished = 0;
1042 time_t now = time(NULL);
1043 int level = LOG_INFO;
1044 const char *section = crm_element_value(request, F_CIB_SECTION);
1045
1046 rc = cib_process_command(request, &op_reply, &result_diff, privileged);
1047
1048 if (!is_update) {
1049 level = LOG_TRACE;
1050
1051 } else if (pcmk__xe_attr_is_true(request, F_CIB_GLOBAL_UPDATE)) {
1052 switch (rc) {
1053 case pcmk_ok:
1054 level = LOG_INFO;
1055 break;
1056 case -pcmk_err_old_data:
1057 case -pcmk_err_diff_resync:
1058 case -pcmk_err_diff_failed:
1059 level = LOG_TRACE;
1060 break;
1061 default:
1062 level = LOG_ERR;
1063 }
1064
1065 } else if (rc != pcmk_ok) {
1066 level = LOG_WARNING;
1067 }
1068
1069 do_crm_log(level,
1070 "Completed %s operation for section %s: %s (rc=%d, origin=%s/%s/%s, version=%s.%s.%s)",
1071 op, section ? section : "'all'", pcmk_strerror(rc), rc,
1072 originator ? originator : "local", client_name, call_id,
1073 the_cib ? crm_element_value(the_cib, XML_ATTR_GENERATION_ADMIN) : "0",
1074 the_cib ? crm_element_value(the_cib, XML_ATTR_GENERATION) : "0",
1075 the_cib ? crm_element_value(the_cib, XML_ATTR_NUMUPDATES) : "0");
1076
1077 finished = time(NULL);
1078 if ((finished - now) > 3) {
1079 crm_trace("%s operation took %lds to complete", op, (long)(finished - now));
1080 crm_write_blackbox(0, NULL);
1081 }
1082
1083 if (op_reply == NULL && (needs_reply || local_notify)) {
1084 crm_err("Unexpected NULL reply to message");
1085 crm_log_xml_err(request, "null reply");
1086 needs_reply = FALSE;
1087 local_notify = FALSE;
1088 }
1089 }
1090
1091 if (is_update && !cib_legacy_mode()) {
1092 crm_trace("Completed pre-sync update from %s/%s/%s%s",
1093 originator ? originator : "local", client_name, call_id,
1094 local_notify?" with local notification":"");
1095
1096 } else if (!needs_reply || stand_alone) {
1097
1098 crm_trace("Completed update as secondary");
1099
1100 } else if (cib_legacy_mode() &&
1101 rc == pcmk_ok && result_diff != NULL && !(call_options & cib_inhibit_bcast)) {
1102 gboolean broadcast = FALSE;
1103
1104 cib_local_bcast_num++;
1105 crm_xml_add_int(request, F_CIB_LOCAL_NOTIFY_ID, cib_local_bcast_num);
1106 broadcast = send_peer_reply(request, result_diff, originator, TRUE);
1107
1108 if (broadcast && client_id && local_notify && op_reply) {
1109
1110
1111
1112
1113 local_notify = FALSE;
1114 crm_trace("Queuing local %ssync notification for %s",
1115 (call_options & cib_sync_call) ? "" : "a-", client_id);
1116
1117 queue_local_notify(op_reply, client_id,
1118 pcmk_is_set(call_options, cib_sync_call),
1119 (cib_client == NULL));
1120 op_reply = NULL;
1121 }
1122
1123 } else if (call_options & cib_discard_reply) {
1124 crm_trace("Caller isn't interested in reply");
1125
1126 } else if (cib_client == NULL) {
1127 if (is_update == FALSE || result_diff == NULL) {
1128 crm_trace("Request not broadcast: R/O call");
1129
1130 } else if (call_options & cib_inhibit_bcast) {
1131 crm_trace("Request not broadcast: inhibited");
1132
1133 } else if (rc != pcmk_ok) {
1134 crm_trace("Request not broadcast: call failed: %s", pcmk_strerror(rc));
1135
1136 } else {
1137 crm_trace("Directing reply to %s", originator);
1138 }
1139
1140 send_peer_reply(op_reply, result_diff, originator, FALSE);
1141 }
1142
1143 if (local_notify && client_id) {
1144 crm_trace("Performing local %ssync notification for %s",
1145 (pcmk_is_set(call_options, cib_sync_call)? "" : "a"),
1146 client_id);
1147 if (process == FALSE) {
1148 do_local_notify(request, client_id,
1149 pcmk_is_set(call_options, cib_sync_call),
1150 (cib_client == NULL));
1151 } else {
1152 do_local_notify(op_reply, client_id,
1153 pcmk_is_set(call_options, cib_sync_call),
1154 (cib_client == NULL));
1155 }
1156 }
1157
1158 free_xml(op_reply);
1159 free_xml(result_diff);
1160
1161 return;
1162 }
1163
1164 static char *
1165 calculate_section_digest(const char *xpath, xmlNode * xml_obj)
1166 {
1167 xmlNode *xml_section = NULL;
1168
1169 if (xml_obj == NULL) {
1170 return NULL;
1171 }
1172
1173 xml_section = get_xpath_object(xpath, xml_obj, LOG_TRACE);
1174 if (xml_section == NULL) {
1175 return NULL;
1176 }
1177 return calculate_xml_versioned_digest(xml_section, FALSE, TRUE, CRM_FEATURE_SET);
1178
1179 }
1180
1181
1182 #define XPATH_CONFIG_CHANGE \
1183 "//" XML_CIB_TAG_CRMCONFIG " | " \
1184 "//" XML_DIFF_CHANGE \
1185 "[contains(@" XML_DIFF_PATH ",'/" XML_CIB_TAG_CRMCONFIG "/')]"
1186
1187 static bool
1188 contains_config_change(xmlNode *diff)
1189 {
1190 bool changed = false;
1191
1192 if (diff) {
1193 xmlXPathObject *xpathObj = xpath_search(diff, XPATH_CONFIG_CHANGE);
1194
1195 if (numXpathResults(xpathObj) > 0) {
1196 changed = true;
1197 }
1198 freeXpathObject(xpathObj);
1199 }
1200 return changed;
1201 }
1202
1203 static int
1204 cib_process_command(xmlNode * request, xmlNode ** reply, xmlNode ** cib_diff, gboolean privileged)
1205 {
1206 xmlNode *input = NULL;
1207 xmlNode *output = NULL;
1208 xmlNode *result_cib = NULL;
1209 xmlNode *current_cib = NULL;
1210
1211 int call_type = 0;
1212 int call_options = 0;
1213
1214 const char *op = NULL;
1215 const char *section = NULL;
1216 const char *call_id = crm_element_value(request, F_CIB_CALLID);
1217 const char *client_id = crm_element_value(request, F_CIB_CLIENTID);
1218 const char *client_name = crm_element_value(request, F_CIB_CLIENTNAME);
1219 const char *origin = crm_element_value(request, F_ORIG);
1220
1221 int rc = pcmk_ok;
1222 int rc2 = pcmk_ok;
1223
1224 gboolean send_r_notify = FALSE;
1225 gboolean config_changed = FALSE;
1226 gboolean manage_counters = TRUE;
1227
1228 static mainloop_timer_t *digest_timer = NULL;
1229
1230 char *current_nodes_digest = NULL;
1231 char *current_alerts_digest = NULL;
1232 char *current_status_digest = NULL;
1233 uint32_t change_section = cib_change_section_nodes
1234 |cib_change_section_alerts
1235 |cib_change_section_status;
1236
1237 CRM_ASSERT(cib_status == pcmk_ok);
1238
1239 if(digest_timer == NULL) {
1240 digest_timer = mainloop_timer_add("digester", 5000, FALSE, cib_digester_cb, NULL);
1241 }
1242
1243 *reply = NULL;
1244 *cib_diff = NULL;
1245 current_cib = the_cib;
1246
1247
1248 op = crm_element_value(request, F_CIB_OPERATION);
1249 crm_element_value_int(request, F_CIB_CALLOPTS, &call_options);
1250 rc = cib_get_operation_id(op, &call_type);
1251
1252 if (rc == pcmk_ok && privileged == FALSE) {
1253 rc = cib_op_can_run(call_type, call_options, privileged);
1254 }
1255
1256 rc2 = cib_op_prepare(call_type, request, &input, §ion);
1257 if (rc == pcmk_ok) {
1258 rc = rc2;
1259 }
1260
1261 if (rc != pcmk_ok) {
1262 crm_trace("Call setup failed: %s", pcmk_strerror(rc));
1263 goto done;
1264
1265 } else if (cib_op_modifies(call_type) == FALSE) {
1266 rc = cib_perform_op(op, call_options, cib_op_func(call_type), TRUE,
1267 section, request, input, FALSE, &config_changed,
1268 current_cib, &result_cib, NULL, &output);
1269
1270 CRM_CHECK(result_cib == NULL, free_xml(result_cib));
1271 goto done;
1272 }
1273
1274
1275 if (pcmk__xe_attr_is_true(request, F_CIB_GLOBAL_UPDATE)) {
1276
1277 manage_counters = FALSE;
1278 cib__set_call_options(call_options, "call", cib_force_diff);
1279 crm_trace("Global update detected");
1280
1281 CRM_CHECK(call_type == 3 || call_type == 4, crm_err("Call type: %d", call_type);
1282 crm_log_xml_err(request, "bad op"));
1283 }
1284
1285 ping_modified_since = TRUE;
1286 if (pcmk_is_set(call_options, cib_inhibit_bcast)) {
1287 crm_trace("Skipping update: inhibit broadcast");
1288 manage_counters = FALSE;
1289 }
1290
1291 if (!pcmk_is_set(call_options, cib_dryrun)
1292 && pcmk__str_eq(section, XML_CIB_TAG_STATUS, pcmk__str_casei)) {
1293
1294 cib__set_call_options(call_options, "call", cib_zero_copy);
1295 } else {
1296 cib__clear_call_options(call_options, "call", cib_zero_copy);
1297 }
1298
1299 #define XPATH_CONFIG "//" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION
1300 #define XPATH_NODES XPATH_CONFIG "/" XML_CIB_TAG_NODES
1301 #define XPATH_ALERTS XPATH_CONFIG "/" XML_CIB_TAG_ALERTS
1302 #define XPATH_STATUS "//" XML_TAG_CIB "/" XML_CIB_TAG_STATUS
1303
1304
1305 if (pcmk__str_eq(PCMK__CIB_REQUEST_REPLACE, op, pcmk__str_none)) {
1306 current_nodes_digest = calculate_section_digest(XPATH_NODES,
1307 current_cib);
1308 current_alerts_digest = calculate_section_digest(XPATH_ALERTS,
1309 current_cib);
1310 current_status_digest = calculate_section_digest(XPATH_STATUS,
1311 current_cib);
1312 crm_trace("current-digest %s:%s:%s", current_nodes_digest,
1313 current_alerts_digest, current_status_digest);
1314 }
1315
1316
1317 rc = cib_perform_op(op, call_options, cib_op_func(call_type), FALSE,
1318 section, request, input, manage_counters,
1319 &config_changed, current_cib, &result_cib, cib_diff,
1320 &output);
1321
1322 if (!manage_counters) {
1323 int format = 1;
1324
1325
1326
1327
1328 if (*cib_diff != NULL) {
1329 crm_element_value_int(*cib_diff, "format", &format);
1330 }
1331
1332 if (format == 1) {
1333 config_changed = cib__config_changed_v1(NULL, NULL, cib_diff);
1334 }
1335 }
1336
1337
1338
1339
1340 if ((rc == pcmk_ok)
1341 && pcmk__str_any_of(op,
1342 PCMK__CIB_REQUEST_REPLACE,
1343 PCMK__CIB_REQUEST_UPGRADE,
1344 NULL)) {
1345 config_changed = TRUE;
1346 }
1347
1348 if (rc == pcmk_ok && !pcmk_is_set(call_options, cib_dryrun)) {
1349 crm_trace("Activating %s->%s%s%s",
1350 crm_element_value(current_cib, XML_ATTR_NUMUPDATES),
1351 crm_element_value(result_cib, XML_ATTR_NUMUPDATES),
1352 (pcmk_is_set(call_options, cib_zero_copy)? " zero-copy" : ""),
1353 (config_changed? " changed" : ""));
1354 if (!pcmk_is_set(call_options, cib_zero_copy)) {
1355 rc = activateCibXml(result_cib, config_changed, op);
1356 crm_trace("Activated %s (%d)",
1357 crm_element_value(current_cib, XML_ATTR_NUMUPDATES), rc);
1358 }
1359
1360 if ((rc == pcmk_ok) && contains_config_change(*cib_diff)) {
1361 cib_read_config(config_hash, result_cib);
1362 }
1363
1364 if (pcmk__str_eq(PCMK__CIB_REQUEST_REPLACE, op, pcmk__str_none)) {
1365 char *result_nodes_digest = NULL;
1366 char *result_alerts_digest = NULL;
1367 char *result_status_digest = NULL;
1368
1369
1370 result_nodes_digest = calculate_section_digest(XPATH_NODES,
1371 result_cib);
1372 result_alerts_digest = calculate_section_digest(XPATH_ALERTS,
1373 result_cib);
1374 result_status_digest = calculate_section_digest(XPATH_STATUS,
1375 result_cib);
1376 crm_trace("result-digest %s:%s:%s", result_nodes_digest,
1377 result_alerts_digest, result_status_digest);
1378
1379 if (pcmk__str_eq(current_nodes_digest, result_nodes_digest,
1380 pcmk__str_none)) {
1381 change_section =
1382 pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE,
1383 "CIB change section",
1384 "change_section", change_section,
1385 cib_change_section_nodes, "nodes");
1386 }
1387
1388 if (pcmk__str_eq(current_alerts_digest, result_alerts_digest,
1389 pcmk__str_none)) {
1390 change_section =
1391 pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE,
1392 "CIB change section",
1393 "change_section", change_section,
1394 cib_change_section_alerts, "alerts");
1395 }
1396
1397 if (pcmk__str_eq(current_status_digest, result_status_digest,
1398 pcmk__str_none)) {
1399 change_section =
1400 pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE,
1401 "CIB change section",
1402 "change_section", change_section,
1403 cib_change_section_status, "status");
1404 }
1405
1406 if (change_section != cib_change_section_none) {
1407 send_r_notify = TRUE;
1408 }
1409
1410 free(result_nodes_digest);
1411 free(result_alerts_digest);
1412 free(result_status_digest);
1413
1414 } else if (pcmk__str_eq(PCMK__CIB_REQUEST_ERASE, op, pcmk__str_none)) {
1415 send_r_notify = TRUE;
1416 }
1417
1418 mainloop_timer_stop(digest_timer);
1419 mainloop_timer_start(digest_timer);
1420
1421 } else if (rc == -pcmk_err_schema_validation) {
1422 CRM_ASSERT(!pcmk_is_set(call_options, cib_zero_copy));
1423
1424 if (output != NULL) {
1425 crm_log_xml_info(output, "cib:output");
1426 free_xml(output);
1427 }
1428
1429 output = result_cib;
1430
1431 } else {
1432 crm_trace("Not activating %d %d %s", rc,
1433 pcmk_is_set(call_options, cib_dryrun),
1434 crm_element_value(result_cib, XML_ATTR_NUMUPDATES));
1435 if (!pcmk_is_set(call_options, cib_zero_copy)) {
1436 free_xml(result_cib);
1437 }
1438 }
1439
1440 if ((call_options & (cib_inhibit_notify|cib_dryrun)) == 0) {
1441 crm_trace("Sending notifications %d",
1442 pcmk_is_set(call_options, cib_dryrun));
1443 cib_diff_notify(op, rc, call_id, client_id, client_name, origin, input,
1444 *cib_diff);
1445 }
1446
1447 if (send_r_notify) {
1448 cib_replace_notify(op, rc, call_id, client_id, client_name, origin,
1449 the_cib, *cib_diff, change_section);
1450 }
1451
1452 pcmk__output_set_log_level(logger_out, LOG_TRACE);
1453 logger_out->message(logger_out, "xml-patchset", *cib_diff);
1454
1455 done:
1456 if (!pcmk_is_set(call_options, cib_discard_reply) || cib_legacy_mode()) {
1457 const char *caller = crm_element_value(request, F_CIB_CLIENTID);
1458
1459 *reply = create_xml_node(NULL, "cib-reply");
1460 crm_xml_add(*reply, F_TYPE, T_CIB);
1461 crm_xml_add(*reply, F_CIB_OPERATION, op);
1462 crm_xml_add(*reply, F_CIB_CALLID, call_id);
1463 crm_xml_add(*reply, F_CIB_CLIENTID, caller);
1464 crm_xml_add_int(*reply, F_CIB_CALLOPTS, call_options);
1465 crm_xml_add_int(*reply, F_CIB_RC, rc);
1466
1467 if (output != NULL) {
1468 crm_trace("Attaching reply output");
1469 add_message_xml(*reply, F_CIB_CALLDATA, output);
1470 }
1471
1472 crm_log_xml_explicit(*reply, "cib:reply");
1473 }
1474
1475 crm_trace("cleanup");
1476
1477 if (cib_op_modifies(call_type) == FALSE && output != current_cib) {
1478 free_xml(output);
1479 output = NULL;
1480 }
1481
1482 if (call_type >= 0) {
1483 cib_op_cleanup(call_type, call_options, &input, &output);
1484 }
1485
1486 free(current_nodes_digest);
1487 free(current_alerts_digest);
1488 free(current_status_digest);
1489
1490 crm_trace("done");
1491 return rc;
1492 }
1493
1494 void
1495 cib_peer_callback(xmlNode * msg, void *private_data)
1496 {
1497 const char *reason = NULL;
1498 const char *originator = crm_element_value(msg, F_ORIG);
1499
1500 if (cib_legacy_mode()
1501 && pcmk__str_eq(originator, OUR_NODENAME,
1502 pcmk__str_casei|pcmk__str_null_matches)) {
1503
1504 int bcast_id = 0;
1505
1506 if (!(crm_element_value_int(msg, F_CIB_LOCAL_NOTIFY_ID, &bcast_id))) {
1507 check_local_notify(bcast_id);
1508 }
1509 return;
1510
1511 } else if (crm_peer_cache == NULL) {
1512 reason = "membership not established";
1513 goto bail;
1514 }
1515
1516 if (crm_element_value(msg, F_CIB_CLIENTNAME) == NULL) {
1517 crm_xml_add(msg, F_CIB_CLIENTNAME, originator);
1518 }
1519
1520
1521 cib_process_request(msg, TRUE, NULL);
1522 return;
1523
1524 bail:
1525 if (reason) {
1526 const char *seq = crm_element_value(msg, F_SEQ);
1527 const char *op = crm_element_value(msg, F_CIB_OPERATION);
1528
1529 crm_warn("Discarding %s message (%s) from %s: %s", op, seq, originator, reason);
1530 }
1531 }
1532
1533 static gboolean
1534 cib_force_exit(gpointer data)
1535 {
1536 crm_notice("Forcing exit!");
1537 terminate_cib(__func__, CRM_EX_ERROR);
1538 return FALSE;
1539 }
1540
1541 static void
1542 disconnect_remote_client(gpointer key, gpointer value, gpointer user_data)
1543 {
1544 pcmk__client_t *a_client = value;
1545
1546 crm_err("Can't disconnect client %s: Not implemented",
1547 pcmk__client_name(a_client));
1548 }
1549
1550 static void
1551 initiate_exit(void)
1552 {
1553 int active = 0;
1554 xmlNode *leaving = NULL;
1555
1556 active = crm_active_peers();
1557 if (active < 2) {
1558 terminate_cib(__func__, 0);
1559 return;
1560 }
1561
1562 crm_info("Sending disconnect notification to %d peers...", active);
1563
1564 leaving = create_xml_node(NULL, "exit-notification");
1565 crm_xml_add(leaving, F_TYPE, "cib");
1566 crm_xml_add(leaving, F_CIB_OPERATION, PCMK__CIB_REQUEST_SHUTDOWN);
1567
1568 send_cluster_message(NULL, crm_msg_cib, leaving, TRUE);
1569 free_xml(leaving);
1570
1571 g_timeout_add(EXIT_ESCALATION_MS, cib_force_exit, NULL);
1572 }
1573
1574 void
1575 cib_shutdown(int nsig)
1576 {
1577 struct qb_ipcs_stats srv_stats;
1578
1579 if (cib_shutdown_flag == FALSE) {
1580 int disconnects = 0;
1581 qb_ipcs_connection_t *c = NULL;
1582
1583 cib_shutdown_flag = TRUE;
1584
1585 c = qb_ipcs_connection_first_get(ipcs_rw);
1586 while (c != NULL) {
1587 qb_ipcs_connection_t *last = c;
1588
1589 c = qb_ipcs_connection_next_get(ipcs_rw, last);
1590
1591 crm_debug("Disconnecting r/w client %p...", last);
1592 qb_ipcs_disconnect(last);
1593 qb_ipcs_connection_unref(last);
1594 disconnects++;
1595 }
1596
1597 c = qb_ipcs_connection_first_get(ipcs_ro);
1598 while (c != NULL) {
1599 qb_ipcs_connection_t *last = c;
1600
1601 c = qb_ipcs_connection_next_get(ipcs_ro, last);
1602
1603 crm_debug("Disconnecting r/o client %p...", last);
1604 qb_ipcs_disconnect(last);
1605 qb_ipcs_connection_unref(last);
1606 disconnects++;
1607 }
1608
1609 c = qb_ipcs_connection_first_get(ipcs_shm);
1610 while (c != NULL) {
1611 qb_ipcs_connection_t *last = c;
1612
1613 c = qb_ipcs_connection_next_get(ipcs_shm, last);
1614
1615 crm_debug("Disconnecting non-blocking r/w client %p...", last);
1616 qb_ipcs_disconnect(last);
1617 qb_ipcs_connection_unref(last);
1618 disconnects++;
1619 }
1620
1621 disconnects += pcmk__ipc_client_count();
1622
1623 crm_debug("Disconnecting %d remote clients", pcmk__ipc_client_count());
1624 pcmk__foreach_ipc_client(disconnect_remote_client, NULL);
1625 crm_info("Disconnected %d clients", disconnects);
1626 }
1627
1628 qb_ipcs_stats_get(ipcs_rw, &srv_stats, QB_FALSE);
1629
1630 if (pcmk__ipc_client_count() == 0) {
1631 crm_info("All clients disconnected (%d)", srv_stats.active_connections);
1632 initiate_exit();
1633
1634 } else {
1635 crm_info("Waiting on %d clients to disconnect (%d)",
1636 pcmk__ipc_client_count(), srv_stats.active_connections);
1637 }
1638 }
1639
1640 extern int remote_fd;
1641 extern int remote_tls_fd;
1642
1643
1644
1645
1646
1647
1648
1649
1650 void
1651 terminate_cib(const char *caller, int fast)
1652 {
1653 crm_info("%s: Exiting%s...", caller,
1654 (fast > 0)? " fast" : mainloop ? " from mainloop" : "");
1655
1656 if (remote_fd > 0) {
1657 close(remote_fd);
1658 remote_fd = 0;
1659 }
1660 if (remote_tls_fd > 0) {
1661 close(remote_tls_fd);
1662 remote_tls_fd = 0;
1663 }
1664
1665 uninitializeCib();
1666
1667 if (logger_out != NULL) {
1668 logger_out->finish(logger_out, CRM_EX_OK, true, NULL);
1669 pcmk__output_free(logger_out);
1670 logger_out = NULL;
1671 }
1672
1673 if (fast > 0) {
1674
1675 pcmk__stop_based_ipc(ipcs_ro, ipcs_rw, ipcs_shm);
1676 crm_exit(fast);
1677
1678 } else if ((mainloop != NULL) && g_main_loop_is_running(mainloop)) {
1679
1680
1681
1682
1683
1684 if (fast == 0) {
1685 crm_cluster_disconnect(crm_cluster);
1686 }
1687 g_main_loop_quit(mainloop);
1688
1689 } else {
1690
1691
1692 crm_cluster_disconnect(crm_cluster);
1693 pcmk__stop_based_ipc(ipcs_ro, ipcs_rw, ipcs_shm);
1694 crm_exit(CRM_EX_OK);
1695 }
1696 }