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
87 if (pcmk__str_eq(op, PCMK__CIB_REQUEST_IS_PRIMARY, pcmk__str_none)) {
88 if (based_is_primary) {
89 result = pcmk_ok;
90 } else {
91 result = -EPERM;
92 }
93 return result;
94 }
95
96 if (pcmk__str_eq(op, PCMK__CIB_REQUEST_PRIMARY, pcmk__str_none)) {
97 if (!based_is_primary) {
98 crm_info("We are now in R/W mode");
99 based_is_primary = true;
100 } else {
101 crm_debug("We are still in R/W mode");
102 }
103
104 } else if (based_is_primary) {
105 crm_info("We are now in R/O mode");
106 based_is_primary = false;
107 }
108
109 return result;
110 }
111
112
113
114
115 static int sync_in_progress = 0;
116
117 void
118 send_sync_request(const char *host)
119 {
120 xmlNode *sync_me = pcmk__xe_create(NULL, "sync-me");
121 pcmk__node_status_t *peer = NULL;
122
123 crm_info("Requesting re-sync from %s", (host? host : "all peers"));
124 sync_in_progress = 1;
125
126 crm_xml_add(sync_me, PCMK__XA_T, PCMK__VALUE_CIB);
127 crm_xml_add(sync_me, PCMK__XA_CIB_OP, PCMK__CIB_REQUEST_SYNC_TO_ONE);
128 crm_xml_add(sync_me, PCMK__XA_CIB_DELEGATED_FROM, OUR_NODENAME);
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, pcmk_ipc_based, sync_me);
134 pcmk__xml_free(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 = pcmk__digest_xml(the_cib, true);
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 if (original_schema == NULL) {
222 crm_info("Rejecting upgrade request from %s: No "
223 PCMK_XA_VALIDATE_WITH, host);
224 return -pcmk_err_cib_corrupt;
225 }
226
227 rc = pcmk__update_schema(&scratch, NULL, true, true);
228 rc = pcmk_rc2legacy(rc);
229 new_schema = crm_element_value(scratch, PCMK_XA_VALIDATE_WITH);
230
231 if (pcmk__cmp_schemas_by_name(new_schema, original_schema) > 0) {
232 xmlNode *up = pcmk__xe_create(NULL, __func__);
233
234 rc = pcmk_ok;
235 crm_notice("Upgrade request from %s verified", host);
236
237 crm_xml_add(up, PCMK__XA_T, PCMK__VALUE_CIB);
238 crm_xml_add(up, PCMK__XA_CIB_OP, PCMK__CIB_REQUEST_UPGRADE);
239 crm_xml_add(up, PCMK__XA_CIB_SCHEMA_MAX, new_schema);
240 crm_xml_add(up, PCMK__XA_CIB_DELEGATED_FROM, host);
241 crm_xml_add(up, PCMK__XA_CIB_CLIENTID, client_id);
242 crm_xml_add(up, PCMK__XA_CIB_CALLOPT, call_opts);
243 crm_xml_add(up, PCMK__XA_CIB_CALLID, call_id);
244
245 pcmk__cluster_send_message(NULL, pcmk_ipc_based, up);
246
247 pcmk__xml_free(up);
248
249 } else if(rc == pcmk_ok) {
250 rc = -pcmk_err_schema_unchanged;
251 }
252
253 if (rc != pcmk_ok) {
254
255 pcmk__node_status_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 QB_XS " rc=%d peer=%s", host, pcmk_strerror(rc), rc,
262 (origin? origin->name : "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, pcmk_ipc_based, up)) {
276 crm_warn("Could not send CIB upgrade result to %s", host);
277 }
278 pcmk__xml_free(up);
279 }
280 }
281 pcmk__xml_free(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 pcmk__xml_free(*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
345 return rc;
346 }
347
348 int
349 cib_process_replace_svr(const char *op, int options, const char *section, xmlNode * req,
350 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
351 xmlNode ** answer)
352 {
353 int rc =
354 cib_process_replace(op, options, section, req, input, existing_cib, result_cib, answer);
355
356 if ((rc == pcmk_ok) && pcmk__xe_is(input, PCMK_XE_CIB)) {
357 sync_in_progress = 0;
358 }
359 return rc;
360 }
361
362
363
364
365 int
366 cib_process_delete_absolute(const char *op, int options, const char *section, xmlNode * req,
367 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
368 xmlNode ** answer)
369 {
370 return -EINVAL;
371 }
372
373 static xmlNode *
374 cib_msg_copy(xmlNode *msg)
375 {
376 static const char *field_list[] = {
377 PCMK__XA_T,
378 PCMK__XA_CIB_CLIENTID,
379 PCMK__XA_CIB_CALLOPT,
380 PCMK__XA_CIB_CALLID,
381 PCMK__XA_CIB_OP,
382 PCMK__XA_CIB_ISREPLYTO,
383 PCMK__XA_CIB_SECTION,
384 PCMK__XA_CIB_HOST,
385 PCMK__XA_CIB_RC,
386 PCMK__XA_CIB_DELEGATED_FROM,
387 PCMK__XA_CIB_UPDATE,
388 PCMK__XA_CIB_CLIENTNAME,
389 PCMK__XA_CIB_USER,
390 PCMK__XA_CIB_NOTIFY_TYPE,
391 PCMK__XA_CIB_NOTIFY_ACTIVATE,
392 };
393
394 xmlNode *copy = pcmk__xe_create(NULL, PCMK__XE_COPY);
395
396 for (int lpc = 0; lpc < PCMK__NELEM(field_list); lpc++) {
397 const char *field = field_list[lpc];
398 const char *value = crm_element_value(msg, field);
399
400 if (value != NULL) {
401 crm_xml_add(copy, field, value);
402 }
403 }
404
405 return copy;
406 }
407
408 int
409 sync_our_cib(xmlNode * request, gboolean all)
410 {
411 int result = pcmk_ok;
412 char *digest = NULL;
413 const char *host = crm_element_value(request, PCMK__XA_SRC);
414 const char *op = crm_element_value(request, PCMK__XA_CIB_OP);
415 pcmk__node_status_t *peer = NULL;
416 xmlNode *replace_request = NULL;
417 xmlNode *wrapper = NULL;
418
419 CRM_CHECK(the_cib != NULL, return -EINVAL);
420 CRM_CHECK(all || (host != NULL), return -EINVAL);
421
422 crm_debug("Syncing CIB to %s", all ? "all peers" : host);
423
424 replace_request = cib_msg_copy(request);
425
426 if (host != NULL) {
427 crm_xml_add(replace_request, PCMK__XA_CIB_ISREPLYTO, host);
428 }
429 if (all) {
430 pcmk__xe_remove_attr(replace_request, PCMK__XA_CIB_HOST);
431 }
432
433 crm_xml_add(replace_request, PCMK__XA_CIB_OP, PCMK__CIB_REQUEST_REPLACE);
434
435
436 crm_xml_add(replace_request, PCMK__XA_ORIGINAL_CIB_OP, op);
437
438 pcmk__xe_set_bool_attr(replace_request, PCMK__XA_CIB_UPDATE, true);
439
440 crm_xml_add(replace_request, PCMK_XA_CRM_FEATURE_SET, CRM_FEATURE_SET);
441 digest = pcmk__digest_xml(the_cib, true);
442 crm_xml_add(replace_request, PCMK__XA_DIGEST, digest);
443
444 wrapper = pcmk__xe_create(replace_request, PCMK__XE_CIB_CALLDATA);
445 pcmk__xml_copy(wrapper, the_cib);
446
447 if (!all) {
448 peer = pcmk__get_node(0, host, NULL, pcmk__node_search_cluster_member);
449 }
450 if (!pcmk__cluster_send_message(peer, pcmk_ipc_based, replace_request)) {
451 result = -ENOTCONN;
452 }
453 pcmk__xml_free(replace_request);
454 free(digest);
455 return result;
456 }
457
458 int
459 cib_process_commit_transaction(const char *op, int options, const char *section,
460 xmlNode *req, xmlNode *input,
461 xmlNode *existing_cib, xmlNode **result_cib,
462 xmlNode **answer)
463 {
464
465
466
467
468 int rc = pcmk_rc_ok;
469 const char *client_id = crm_element_value(req, PCMK__XA_CIB_CLIENTID);
470 const char *origin = crm_element_value(req, PCMK__XA_SRC);
471 pcmk__client_t *client = pcmk__find_client_by_id(client_id);
472
473 rc = based_commit_transaction(input, client, origin, result_cib);
474
475 if (rc != pcmk_rc_ok) {
476 char *source = based_transaction_source_str(client, origin);
477
478 crm_err("Could not commit transaction for %s: %s",
479 source, pcmk_rc_str(rc));
480 free(source);
481 }
482 return pcmk_rc2legacy(rc);
483 }
484
485 int
486 cib_process_schemas(const char *op, int options, const char *section, xmlNode *req,
487 xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib,
488 xmlNode **answer)
489 {
490 xmlNode *wrapper = NULL;
491 xmlNode *data = NULL;
492
493 const char *after_ver = NULL;
494 GList *schemas = NULL;
495 GList *already_included = NULL;
496
497 *answer = pcmk__xe_create(NULL, PCMK__XA_SCHEMAS);
498
499 wrapper = pcmk__xe_first_child(req, PCMK__XE_CIB_CALLDATA, NULL, NULL);
500 data = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
501 if (data == NULL) {
502 crm_warn("No data specified in request");
503 return -EPROTO;
504 }
505
506 after_ver = crm_element_value(data, PCMK_XA_VERSION);
507 if (after_ver == NULL) {
508 crm_warn("No version specified in request");
509 return -EPROTO;
510 }
511
512
513
514
515
516 if (pcmk__str_eq(after_ver, pcmk__highest_schema_name(), pcmk__str_none)) {
517 return pcmk_ok;
518 }
519
520 schemas = pcmk__schema_files_later_than(after_ver);
521
522 for (GList *iter = schemas; iter != NULL; iter = iter->next) {
523 pcmk__build_schema_xml_node(*answer, iter->data, &already_included);
524 }
525
526 g_list_free_full(schemas, free);
527 g_list_free_full(already_included, free);
528 return pcmk_ok;
529 }