This source file includes following definitions.
- cib_process_shutdown_req
- cib_process_noop
- cib_process_readwrite
- send_sync_request
- cib_process_ping
- cib_process_sync
- cib_process_upgrade_server
- cib_process_sync_one
- cib_server_process_diff
- cib_process_replace_svr
- cib_process_delete_absolute
- cib_msg_copy
- sync_our_cib
- cib_process_commit_transaction
- cib_process_schemas
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <stdio.h>
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <errno.h>
16 #include <fcntl.h>
17 #include <time.h>
18
19 #include <sys/param.h>
20 #include <sys/types.h>
21
22 #include <glib.h>
23 #include <libxml/tree.h>
24
25 #include <crm/crm.h>
26 #include <crm/cib/internal.h>
27
28 #include <crm/common/xml.h>
29 #include <crm/common/ipc_internal.h>
30 #include <crm/common/xml_internal.h>
31 #include <crm/cluster/internal.h>
32
33 #include <pacemaker-based.h>
34
35
36 #define MAX_DIFF_RETRY 5
37
38 bool based_is_primary = false;
39
40 xmlNode *the_cib = NULL;
41
42 int
43 cib_process_shutdown_req(const char *op, int options, const char *section, xmlNode * req,
44 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
45 xmlNode ** answer)
46 {
47 const char *host = crm_element_value(req, PCMK__XA_SRC);
48
49 *answer = NULL;
50
51 if (crm_element_value(req, PCMK__XA_CIB_ISREPLYTO) == NULL) {
52 crm_info("Peer %s is requesting to shut down", host);
53 return pcmk_ok;
54 }
55
56 if (cib_shutdown_flag == FALSE) {
57 crm_err("Peer %s mistakenly thinks we wanted to shut down", host);
58 return -EINVAL;
59 }
60
61 crm_info("Peer %s has acknowledged our shutdown request", host);
62 terminate_cib(__func__, 0);
63 return pcmk_ok;
64 }
65
66
67 int
68 cib_process_noop(const char *op, int options, const char *section, xmlNode *req,
69 xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib,
70 xmlNode **answer)
71 {
72 crm_trace("Processing \"%s\" event", op);
73 *answer = NULL;
74 return pcmk_ok;
75 }
76
77 int
78 cib_process_readwrite(const char *op, int options, const char *section, xmlNode * req,
79 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
80 xmlNode ** answer)
81 {
82 int result = pcmk_ok;
83
84 crm_trace("Processing \"%s\" event", op);
85
86 if (pcmk__str_eq(op, PCMK__CIB_REQUEST_IS_PRIMARY, pcmk__str_none)) {
87 if (based_is_primary) {
88 result = pcmk_ok;
89 } else {
90 result = -EPERM;
91 }
92 return result;
93 }
94
95 if (pcmk__str_eq(op, PCMK__CIB_REQUEST_PRIMARY, pcmk__str_none)) {
96 if (!based_is_primary) {
97 crm_info("We are now in R/W mode");
98 based_is_primary = true;
99 } else {
100 crm_debug("We are still in R/W mode");
101 }
102
103 } else if (based_is_primary) {
104 crm_info("We are now in R/O mode");
105 based_is_primary = false;
106 }
107
108 return result;
109 }
110
111
112
113
114 static int sync_in_progress = 0;
115
116 void
117 send_sync_request(const char *host)
118 {
119 xmlNode *sync_me = pcmk__xe_create(NULL, "sync-me");
120 crm_node_t *peer = NULL;
121
122 crm_info("Requesting re-sync from %s", (host? host : "all peers"));
123 sync_in_progress = 1;
124
125 crm_xml_add(sync_me, PCMK__XA_T, PCMK__VALUE_CIB);
126 crm_xml_add(sync_me, PCMK__XA_CIB_OP, PCMK__CIB_REQUEST_SYNC_TO_ONE);
127 crm_xml_add(sync_me, PCMK__XA_CIB_DELEGATED_FROM,
128 stand_alone? "localhost" : crm_cluster->uname);
129
130 if (host != NULL) {
131 peer = pcmk__get_node(0, host, NULL, pcmk__node_search_cluster_member);
132 }
133 pcmk__cluster_send_message(peer, crm_msg_cib, sync_me);
134 free_xml(sync_me);
135 }
136
137 int
138 cib_process_ping(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
139 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
140 {
141 const char *host = crm_element_value(req, PCMK__XA_SRC);
142 const char *seq = crm_element_value(req, PCMK__XA_CIB_PING_ID);
143 char *digest = calculate_xml_versioned_digest(the_cib, FALSE, TRUE, CRM_FEATURE_SET);
144
145 xmlNode *wrapper = NULL;
146
147 crm_trace("Processing \"%s\" event %s from %s", op, seq, host);
148 *answer = pcmk__xe_create(NULL, PCMK__XE_PING_RESPONSE);
149
150 crm_xml_add(*answer, PCMK_XA_CRM_FEATURE_SET, CRM_FEATURE_SET);
151 crm_xml_add(*answer, PCMK__XA_DIGEST, digest);
152 crm_xml_add(*answer, PCMK__XA_CIB_PING_ID, seq);
153
154 wrapper = pcmk__xe_create(*answer, PCMK__XE_CIB_CALLDATA);
155
156 if (the_cib != NULL) {
157 pcmk__if_tracing(
158 {
159
160
161
162 pcmk__xml_copy(wrapper, the_cib);
163 },
164 {
165
166 const char *name = (const char *) the_cib->name;
167 xmlNode *shallow = pcmk__xe_create(wrapper, name);
168
169 pcmk__xe_copy_attrs(shallow, the_cib, pcmk__xaf_none);
170 }
171 );
172 }
173
174 crm_info("Reporting our current digest to %s: %s for %s.%s.%s",
175 host, digest,
176 crm_element_value(existing_cib, PCMK_XA_ADMIN_EPOCH),
177 crm_element_value(existing_cib, PCMK_XA_EPOCH),
178 crm_element_value(existing_cib, PCMK_XA_NUM_UPDATES));
179
180 free(digest);
181
182 return pcmk_ok;
183 }
184
185 int
186 cib_process_sync(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
187 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
188 {
189 return sync_our_cib(req, TRUE);
190 }
191
192 int
193 cib_process_upgrade_server(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
194 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
195 {
196 int rc = pcmk_ok;
197
198 *answer = NULL;
199
200 if (crm_element_value(req, PCMK__XA_CIB_SCHEMA_MAX) != NULL) {
201
202
203
204
205
206 return cib_process_upgrade(
207 op, options, section, req, input, existing_cib, result_cib, answer);
208
209 } else {
210 xmlNode *scratch = pcmk__xml_copy(NULL, existing_cib);
211 const char *host = crm_element_value(req, PCMK__XA_SRC);
212 const char *original_schema = NULL;
213 const char *new_schema = NULL;
214 const char *client_id = crm_element_value(req, PCMK__XA_CIB_CLIENTID);
215 const char *call_opts = crm_element_value(req, PCMK__XA_CIB_CALLOPT);
216 const char *call_id = crm_element_value(req, PCMK__XA_CIB_CALLID);
217
218 crm_trace("Processing \"%s\" event", op);
219 original_schema = crm_element_value(existing_cib,
220 PCMK_XA_VALIDATE_WITH);
221 rc = pcmk__update_schema(&scratch, NULL, true, true);
222 rc = pcmk_rc2legacy(rc);
223 new_schema = crm_element_value(scratch, PCMK_XA_VALIDATE_WITH);
224
225 if (pcmk__cmp_schemas_by_name(new_schema, original_schema) > 0) {
226 xmlNode *up = pcmk__xe_create(NULL, __func__);
227
228 rc = pcmk_ok;
229 crm_notice("Upgrade request from %s verified", host);
230
231 crm_xml_add(up, PCMK__XA_T, PCMK__VALUE_CIB);
232 crm_xml_add(up, PCMK__XA_CIB_OP, PCMK__CIB_REQUEST_UPGRADE);
233 crm_xml_add(up, PCMK__XA_CIB_SCHEMA_MAX, new_schema);
234 crm_xml_add(up, PCMK__XA_CIB_DELEGATED_FROM, host);
235 crm_xml_add(up, PCMK__XA_CIB_CLIENTID, client_id);
236 crm_xml_add(up, PCMK__XA_CIB_CALLOPT, call_opts);
237 crm_xml_add(up, PCMK__XA_CIB_CALLID, call_id);
238
239 if (cib_legacy_mode() && based_is_primary) {
240 rc = cib_process_upgrade(
241 op, options, section, up, input, existing_cib, result_cib, answer);
242
243 } else {
244 pcmk__cluster_send_message(NULL, crm_msg_cib, up);
245 }
246
247 free_xml(up);
248
249 } else if(rc == pcmk_ok) {
250 rc = -pcmk_err_schema_unchanged;
251 }
252
253 if (rc != pcmk_ok) {
254
255 crm_node_t *origin = NULL;
256
257 origin = pcmk__search_node_caches(0, host,
258 pcmk__node_search_cluster_member);
259
260 crm_info("Rejecting upgrade request from %s: %s "
261 CRM_XS " rc=%d peer=%s", host, pcmk_strerror(rc), rc,
262 (origin? origin->uname : "lost"));
263
264 if (origin) {
265 xmlNode *up = pcmk__xe_create(NULL, __func__);
266
267 crm_xml_add(up, PCMK__XA_T, PCMK__VALUE_CIB);
268 crm_xml_add(up, PCMK__XA_CIB_OP, PCMK__CIB_REQUEST_UPGRADE);
269 crm_xml_add(up, PCMK__XA_CIB_DELEGATED_FROM, host);
270 crm_xml_add(up, PCMK__XA_CIB_ISREPLYTO, host);
271 crm_xml_add(up, PCMK__XA_CIB_CLIENTID, client_id);
272 crm_xml_add(up, PCMK__XA_CIB_CALLOPT, call_opts);
273 crm_xml_add(up, PCMK__XA_CIB_CALLID, call_id);
274 crm_xml_add_int(up, PCMK__XA_CIB_UPGRADE_RC, rc);
275 if (!pcmk__cluster_send_message(origin, crm_msg_cib, up)) {
276 crm_warn("Could not send CIB upgrade result to %s", host);
277 }
278 free_xml(up);
279 }
280 }
281 free_xml(scratch);
282 }
283 return rc;
284 }
285
286 int
287 cib_process_sync_one(const char *op, int options, const char *section, xmlNode * req,
288 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
289 xmlNode ** answer)
290 {
291 return sync_our_cib(req, FALSE);
292 }
293
294 int
295 cib_server_process_diff(const char *op, int options, const char *section, xmlNode * req,
296 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
297 xmlNode ** answer)
298 {
299 int rc = pcmk_ok;
300
301 if (sync_in_progress > MAX_DIFF_RETRY) {
302
303
304
305 sync_in_progress = 0;
306 }
307
308
309 if (sync_in_progress && !based_is_primary) {
310 int diff_add_updates = 0;
311 int diff_add_epoch = 0;
312 int diff_add_admin_epoch = 0;
313
314 int diff_del_updates = 0;
315 int diff_del_epoch = 0;
316 int diff_del_admin_epoch = 0;
317
318 cib_diff_version_details(input,
319 &diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates,
320 &diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);
321
322 sync_in_progress++;
323 crm_notice("Not applying diff %d.%d.%d -> %d.%d.%d (sync in progress)",
324 diff_del_admin_epoch, diff_del_epoch, diff_del_updates,
325 diff_add_admin_epoch, diff_add_epoch, diff_add_updates);
326 return -pcmk_err_diff_resync;
327 }
328
329 rc = cib_process_diff(op, options, section, req, input, existing_cib, result_cib, answer);
330 crm_trace("result: %s (%d), %s", pcmk_strerror(rc), rc,
331 (based_is_primary? "primary": "secondary"));
332
333 if ((rc == -pcmk_err_diff_resync) && !based_is_primary) {
334 free_xml(*result_cib);
335 *result_cib = NULL;
336 send_sync_request(NULL);
337
338 } else if (rc == -pcmk_err_diff_resync) {
339 rc = -pcmk_err_diff_failed;
340 if (options & cib_force_diff) {
341 crm_warn("Not requesting full refresh in R/W mode");
342 }
343
344 } else if ((rc != pcmk_ok) && !based_is_primary && cib_legacy_mode()) {
345 crm_warn("Requesting full CIB refresh because update failed: %s"
346 CRM_XS " rc=%d", pcmk_strerror(rc), rc);
347
348 pcmk__log_xml_patchset(LOG_INFO, input);
349 free_xml(*result_cib);
350 *result_cib = NULL;
351 send_sync_request(NULL);
352 }
353
354 return rc;
355 }
356
357 int
358 cib_process_replace_svr(const char *op, int options, const char *section, xmlNode * req,
359 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
360 xmlNode ** answer)
361 {
362 int rc =
363 cib_process_replace(op, options, section, req, input, existing_cib, result_cib, answer);
364
365 if ((rc == pcmk_ok) && pcmk__xe_is(input, PCMK_XE_CIB)) {
366 sync_in_progress = 0;
367 }
368 return rc;
369 }
370
371
372 int
373 cib_process_delete_absolute(const char *op, int options, const char *section, xmlNode * req,
374 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
375 xmlNode ** answer)
376 {
377 return -EINVAL;
378 }
379
380 static xmlNode *
381 cib_msg_copy(xmlNode *msg)
382 {
383 static const char *field_list[] = {
384 PCMK__XA_T,
385 PCMK__XA_CIB_CLIENTID,
386 PCMK__XA_CIB_CALLOPT,
387 PCMK__XA_CIB_CALLID,
388 PCMK__XA_CIB_OP,
389 PCMK__XA_CIB_ISREPLYTO,
390 PCMK__XA_CIB_SECTION,
391 PCMK__XA_CIB_HOST,
392 PCMK__XA_CIB_RC,
393 PCMK__XA_CIB_DELEGATED_FROM,
394 PCMK__XA_CIB_OBJECT,
395 PCMK__XA_CIB_OBJECT_TYPE,
396 PCMK__XA_CIB_UPDATE,
397 PCMK__XA_CIB_CLIENTNAME,
398 PCMK__XA_CIB_USER,
399 PCMK__XA_CIB_NOTIFY_TYPE,
400 PCMK__XA_CIB_NOTIFY_ACTIVATE,
401 };
402
403 xmlNode *copy = pcmk__xe_create(NULL, PCMK__XE_COPY);
404
405 for (int lpc = 0; lpc < PCMK__NELEM(field_list); lpc++) {
406 const char *field = field_list[lpc];
407 const char *value = crm_element_value(msg, field);
408
409 if (value != NULL) {
410 crm_xml_add(copy, field, value);
411 }
412 }
413
414 return copy;
415 }
416
417 int
418 sync_our_cib(xmlNode * request, gboolean all)
419 {
420 int result = pcmk_ok;
421 char *digest = NULL;
422 const char *host = crm_element_value(request, PCMK__XA_SRC);
423 const char *op = crm_element_value(request, PCMK__XA_CIB_OP);
424 crm_node_t *peer = NULL;
425 xmlNode *replace_request = NULL;
426 xmlNode *wrapper = NULL;
427
428 CRM_CHECK(the_cib != NULL, return -EINVAL);
429 CRM_CHECK(all || (host != NULL), return -EINVAL);
430
431 crm_debug("Syncing CIB to %s", all ? "all peers" : host);
432
433 replace_request = cib_msg_copy(request);
434
435 if (host != NULL) {
436 crm_xml_add(replace_request, PCMK__XA_CIB_ISREPLYTO, host);
437 }
438 if (all) {
439 pcmk__xe_remove_attr(replace_request, PCMK__XA_CIB_HOST);
440 }
441
442 crm_xml_add(replace_request, PCMK__XA_CIB_OP, PCMK__CIB_REQUEST_REPLACE);
443
444
445 crm_xml_add(replace_request, PCMK__XA_ORIGINAL_CIB_OP, op);
446
447 pcmk__xe_set_bool_attr(replace_request, PCMK__XA_CIB_UPDATE, true);
448
449 crm_xml_add(replace_request, PCMK_XA_CRM_FEATURE_SET, CRM_FEATURE_SET);
450 digest = calculate_xml_versioned_digest(the_cib, FALSE, TRUE, CRM_FEATURE_SET);
451 crm_xml_add(replace_request, PCMK__XA_DIGEST, digest);
452
453 wrapper = pcmk__xe_create(replace_request, PCMK__XE_CIB_CALLDATA);
454 pcmk__xml_copy(wrapper, the_cib);
455
456 if (!all) {
457 peer = pcmk__get_node(0, host, NULL, pcmk__node_search_cluster_member);
458 }
459 if (!pcmk__cluster_send_message(peer, crm_msg_cib, replace_request)) {
460 result = -ENOTCONN;
461 }
462 free_xml(replace_request);
463 free(digest);
464 return result;
465 }
466
467 int
468 cib_process_commit_transaction(const char *op, int options, const char *section,
469 xmlNode *req, xmlNode *input,
470 xmlNode *existing_cib, xmlNode **result_cib,
471 xmlNode **answer)
472 {
473
474
475
476
477 int rc = pcmk_rc_ok;
478 const char *client_id = crm_element_value(req, PCMK__XA_CIB_CLIENTID);
479 const char *origin = crm_element_value(req, PCMK__XA_SRC);
480 pcmk__client_t *client = pcmk__find_client_by_id(client_id);
481
482 rc = based_commit_transaction(input, client, origin, result_cib);
483
484 if (rc != pcmk_rc_ok) {
485 char *source = based_transaction_source_str(client, origin);
486
487 crm_err("Could not commit transaction for %s: %s",
488 source, pcmk_rc_str(rc));
489 free(source);
490 }
491 return pcmk_rc2legacy(rc);
492 }
493
494 int
495 cib_process_schemas(const char *op, int options, const char *section, xmlNode *req,
496 xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib,
497 xmlNode **answer)
498 {
499 xmlNode *wrapper = NULL;
500 xmlNode *data = NULL;
501
502 const char *after_ver = NULL;
503 GList *schemas = NULL;
504 GList *already_included = NULL;
505
506 *answer = pcmk__xe_create(NULL, PCMK__XA_SCHEMAS);
507
508 wrapper = pcmk__xe_first_child(req, PCMK__XE_CIB_CALLDATA, NULL, NULL);
509 data = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
510 if (data == NULL) {
511 crm_warn("No data specified in request");
512 return -EPROTO;
513 }
514
515 after_ver = crm_element_value(data, PCMK_XA_VERSION);
516 if (after_ver == NULL) {
517 crm_warn("No version specified in request");
518 return -EPROTO;
519 }
520
521
522
523
524
525 if (pcmk__str_eq(after_ver, pcmk__highest_schema_name(), pcmk__str_none)) {
526 return pcmk_ok;
527 }
528
529 schemas = pcmk__schema_files_later_than(after_ver);
530
531 for (GList *iter = schemas; iter != NULL; iter = iter->next) {
532 pcmk__build_schema_xml_node(*answer, iter->data, &already_included);
533 }
534
535 g_list_free_full(schemas, free);
536 g_list_free_full(already_included, free);
537 return pcmk_ok;
538 }