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