This source file includes following definitions.
- cib_process_shutdown_req
- cib_process_default
- 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
- delete_cib_object
- cib_process_delete_absolute
- sync_our_cib
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 <crm/crm.h>
23 #include <crm/cib/internal.h>
24 #include <crm/msg_xml.h>
25
26 #include <crm/common/xml.h>
27 #include <crm/common/ipc_internal.h>
28 #include <crm/common/xml_internal.h>
29 #include <crm/cluster/internal.h>
30
31 #include <pacemaker-based.h>
32
33
34 #define MAX_DIFF_RETRY 5
35
36 gboolean cib_is_master = FALSE;
37
38 xmlNode *the_cib = NULL;
39 int revision_check(xmlNode * cib_update, xmlNode * cib_copy, int flags);
40 int get_revision(xmlNode * xml_obj, int cur_revision);
41
42 int updateList(xmlNode * local_cib, xmlNode * update_command, xmlNode * failed,
43 int operation, const char *section);
44
45 gboolean update_results(xmlNode * failed, xmlNode * target, const char *operation, int return_code);
46
47 int cib_update_counter(xmlNode * xml_obj, const char *field, gboolean reset);
48
49 int sync_our_cib(xmlNode * request, gboolean all);
50
51 int
52 cib_process_shutdown_req(const char *op, int options, const char *section, xmlNode * req,
53 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
54 xmlNode ** answer)
55 {
56 const char *host = crm_element_value(req, F_ORIG);
57
58 *answer = NULL;
59
60 if (crm_element_value(req, F_CIB_ISREPLY) == NULL) {
61 crm_info("Peer %s is requesting to shut down", host);
62 return pcmk_ok;
63 }
64
65 if (cib_shutdown_flag == FALSE) {
66 crm_err("Peer %s mistakenly thinks we wanted to shut down", host);
67 return -EINVAL;
68 }
69
70 crm_info("Peer %s has acknowledged our shutdown request", host);
71 terminate_cib(__func__, 0);
72 return pcmk_ok;
73 }
74
75 int
76 cib_process_default(const char *op, int options, const char *section, xmlNode * req,
77 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
78 xmlNode ** answer)
79 {
80 int result = pcmk_ok;
81
82 crm_trace("Processing \"%s\" event", op);
83 *answer = NULL;
84
85 if (op == NULL) {
86 result = -EINVAL;
87 crm_err("No operation specified");
88
89 } else if (strcasecmp(CRM_OP_NOOP, op) == 0) {
90 ;
91
92 } else {
93 result = -EPROTONOSUPPORT;
94 crm_err("Action [%s] is not supported by the CIB manager", op);
95 }
96 return result;
97 }
98
99 int
100 cib_process_readwrite(const char *op, int options, const char *section, xmlNode * req,
101 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
102 xmlNode ** answer)
103 {
104 int result = pcmk_ok;
105
106 crm_trace("Processing \"%s\" event", op);
107
108 if (pcmk__str_eq(op, CIB_OP_ISMASTER, pcmk__str_casei)) {
109 if (cib_is_master == TRUE) {
110 result = pcmk_ok;
111 } else {
112 result = -EPERM;
113 }
114 return result;
115 }
116
117 if (pcmk__str_eq(op, CIB_OP_MASTER, pcmk__str_casei)) {
118 if (cib_is_master == FALSE) {
119 crm_info("We are now in R/W mode");
120 cib_is_master = TRUE;
121 } else {
122 crm_debug("We are still in R/W mode");
123 }
124
125 } else if (cib_is_master) {
126 crm_info("We are now in R/O mode");
127 cib_is_master = FALSE;
128 }
129
130 return result;
131 }
132
133
134
135
136 static int sync_in_progress = 0;
137
138 void
139 send_sync_request(const char *host)
140 {
141 xmlNode *sync_me = create_xml_node(NULL, "sync-me");
142
143 crm_info("Requesting re-sync from %s", (host? host : "all peers"));
144 sync_in_progress = 1;
145
146 crm_xml_add(sync_me, F_TYPE, "cib");
147 crm_xml_add(sync_me, F_CIB_OPERATION, CIB_OP_SYNC_ONE);
148 crm_xml_add(sync_me, F_CIB_DELEGATED, cib_our_uname);
149
150 send_cluster_message(host ? crm_get_peer(0, host) : NULL, crm_msg_cib, sync_me, FALSE);
151 free_xml(sync_me);
152 }
153
154 int
155 cib_process_ping(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
156 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
157 {
158 const char *host = crm_element_value(req, F_ORIG);
159 const char *seq = crm_element_value(req, F_CIB_PING_ID);
160 char *digest = calculate_xml_versioned_digest(the_cib, FALSE, TRUE, CRM_FEATURE_SET);
161
162 static struct qb_log_callsite *cs = NULL;
163
164 crm_trace("Processing \"%s\" event %s from %s", op, seq, host);
165 *answer = create_xml_node(NULL, XML_CRM_TAG_PING);
166
167 crm_xml_add(*answer, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
168 crm_xml_add(*answer, XML_ATTR_DIGEST, digest);
169 crm_xml_add(*answer, F_CIB_PING_ID, seq);
170
171 if (cs == NULL) {
172 cs = qb_log_callsite_get(__func__, __FILE__, __func__, LOG_TRACE,
173 __LINE__, crm_trace_nonlog);
174 }
175 if (cs && cs->targets) {
176
177 add_message_xml(*answer, F_CIB_CALLDATA, the_cib);
178
179 } else {
180
181 const char *tag = TYPE(the_cib);
182 xmlNode *shallow = create_xml_node(NULL, tag);
183
184 copy_in_properties(shallow, the_cib);
185 add_message_xml(*answer, F_CIB_CALLDATA, shallow);
186 free_xml(shallow);
187 }
188
189 crm_info("Reporting our current digest to %s: %s for %s.%s.%s (%p %d)",
190 host, digest,
191 crm_element_value(existing_cib, XML_ATTR_GENERATION_ADMIN),
192 crm_element_value(existing_cib, XML_ATTR_GENERATION),
193 crm_element_value(existing_cib, XML_ATTR_NUMUPDATES),
194 existing_cib,
195 cs && cs->targets);
196
197 free(digest);
198
199 return pcmk_ok;
200 }
201
202 int
203 cib_process_sync(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
204 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
205 {
206 return sync_our_cib(req, TRUE);
207 }
208
209 int
210 cib_process_upgrade_server(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
211 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
212 {
213 int rc = pcmk_ok;
214
215 *answer = NULL;
216
217 if(crm_element_value(req, F_CIB_SCHEMA_MAX)) {
218
219
220
221
222
223 return cib_process_upgrade(
224 op, options, section, req, input, existing_cib, result_cib, answer);
225
226 } else {
227 int new_version = 0;
228 int current_version = 0;
229 xmlNode *scratch = copy_xml(existing_cib);
230 const char *host = crm_element_value(req, F_ORIG);
231 const char *value = crm_element_value(existing_cib, XML_ATTR_VALIDATION);
232 const char *client_id = crm_element_value(req, F_CIB_CLIENTID);
233 const char *call_opts = crm_element_value(req, F_CIB_CALLOPTS);
234 const char *call_id = crm_element_value(req, F_CIB_CALLID);
235
236 crm_trace("Processing \"%s\" event", op);
237 if (value != NULL) {
238 current_version = get_schema_version(value);
239 }
240
241 rc = update_validation(&scratch, &new_version, 0, TRUE, TRUE);
242 if (new_version > current_version) {
243 xmlNode *up = create_xml_node(NULL, __func__);
244
245 rc = pcmk_ok;
246 crm_notice("Upgrade request from %s verified", host);
247
248 crm_xml_add(up, F_TYPE, "cib");
249 crm_xml_add(up, F_CIB_OPERATION, CIB_OP_UPGRADE);
250 crm_xml_add(up, F_CIB_SCHEMA_MAX, get_schema_name(new_version));
251 crm_xml_add(up, F_CIB_DELEGATED, host);
252 crm_xml_add(up, F_CIB_CLIENTID, client_id);
253 crm_xml_add(up, F_CIB_CALLOPTS, call_opts);
254 crm_xml_add(up, F_CIB_CALLID, call_id);
255
256 if (cib_legacy_mode() && cib_is_master) {
257 rc = cib_process_upgrade(
258 op, options, section, up, input, existing_cib, result_cib, answer);
259
260 } else {
261 send_cluster_message(NULL, crm_msg_cib, up, FALSE);
262 }
263
264 free_xml(up);
265
266 } else if(rc == pcmk_ok) {
267 rc = -pcmk_err_schema_unchanged;
268 }
269
270 if (rc != pcmk_ok) {
271
272 crm_node_t *origin = crm_find_peer(0, host);
273
274 crm_info("Rejecting upgrade request from %s: %s "
275 CRM_XS " rc=%d peer=%s", host, pcmk_strerror(rc), rc,
276 (origin? origin->uname : "lost"));
277
278 if (origin) {
279 xmlNode *up = create_xml_node(NULL, __func__);
280
281 crm_xml_add(up, F_TYPE, "cib");
282 crm_xml_add(up, F_CIB_OPERATION, CIB_OP_UPGRADE);
283 crm_xml_add(up, F_CIB_DELEGATED, host);
284 crm_xml_add(up, F_CIB_ISREPLY, host);
285 crm_xml_add(up, F_CIB_CLIENTID, client_id);
286 crm_xml_add(up, F_CIB_CALLOPTS, call_opts);
287 crm_xml_add(up, F_CIB_CALLID, call_id);
288 crm_xml_add_int(up, F_CIB_UPGRADE_RC, rc);
289 if (send_cluster_message(origin, crm_msg_cib, up, TRUE)
290 == FALSE) {
291 crm_warn("Could not send CIB upgrade result to %s", host);
292 }
293 free_xml(up);
294 }
295 }
296 free_xml(scratch);
297 }
298 return rc;
299 }
300
301 int
302 cib_process_sync_one(const char *op, int options, const char *section, xmlNode * req,
303 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
304 xmlNode ** answer)
305 {
306 return sync_our_cib(req, FALSE);
307 }
308
309 int
310 cib_server_process_diff(const char *op, int options, const char *section, xmlNode * req,
311 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
312 xmlNode ** answer)
313 {
314 int rc = pcmk_ok;
315
316 if (sync_in_progress > MAX_DIFF_RETRY) {
317
318
319
320 sync_in_progress = 0;
321 }
322
323
324 if (sync_in_progress && !cib_is_master) {
325 int diff_add_updates = 0;
326 int diff_add_epoch = 0;
327 int diff_add_admin_epoch = 0;
328
329 int diff_del_updates = 0;
330 int diff_del_epoch = 0;
331 int diff_del_admin_epoch = 0;
332
333 cib_diff_version_details(input,
334 &diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates,
335 &diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);
336
337 sync_in_progress++;
338 crm_notice("Not applying diff %d.%d.%d -> %d.%d.%d (sync in progress)",
339 diff_del_admin_epoch, diff_del_epoch, diff_del_updates,
340 diff_add_admin_epoch, diff_add_epoch, diff_add_updates);
341 return -pcmk_err_diff_resync;
342 }
343
344 rc = cib_process_diff(op, options, section, req, input, existing_cib, result_cib, answer);
345 crm_trace("result: %s (%d), %s", pcmk_strerror(rc), rc, cib_is_master?"master":"slave");
346
347 if (rc == -pcmk_err_diff_resync && cib_is_master == FALSE) {
348 free_xml(*result_cib);
349 *result_cib = NULL;
350 send_sync_request(NULL);
351
352 } else if (rc == -pcmk_err_diff_resync) {
353 rc = -pcmk_err_diff_failed;
354 if (options & cib_force_diff) {
355 crm_warn("Not requesting full refresh in R/W mode");
356 }
357
358 } else if ((rc != pcmk_ok) && !cib_is_master && cib_legacy_mode()) {
359 crm_warn("Requesting full CIB refresh because update failed: %s"
360 CRM_XS " rc=%d", pcmk_strerror(rc), rc);
361 xml_log_patchset(LOG_INFO, __func__, input);
362 free_xml(*result_cib);
363 *result_cib = NULL;
364 send_sync_request(NULL);
365 }
366
367 return rc;
368 }
369
370 int
371 cib_process_replace_svr(const char *op, int options, const char *section, xmlNode * req,
372 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
373 xmlNode ** answer)
374 {
375 const char *tag = crm_element_name(input);
376 int rc =
377 cib_process_replace(op, options, section, req, input, existing_cib, result_cib, answer);
378 if (rc == pcmk_ok && pcmk__str_eq(tag, XML_TAG_CIB, pcmk__str_casei)) {
379 sync_in_progress = 0;
380 }
381 return rc;
382 }
383
384 static int
385 delete_cib_object(xmlNode * parent, xmlNode * delete_spec)
386 {
387 const char *object_name = NULL;
388 const char *object_id = NULL;
389 xmlNode *equiv_node = NULL;
390 int result = pcmk_ok;
391
392 if (delete_spec != NULL) {
393 object_name = crm_element_name(delete_spec);
394 }
395 object_id = crm_element_value(delete_spec, XML_ATTR_ID);
396
397 crm_trace("Processing: <%s id=%s>", crm_str(object_name), crm_str(object_id));
398
399 if (delete_spec == NULL) {
400 result = -EINVAL;
401
402 } else if (parent == NULL) {
403 result = -EINVAL;
404
405 } else if (object_id == NULL) {
406
407 equiv_node = find_xml_node(parent, object_name, FALSE);
408
409 } else {
410 equiv_node = pcmk__xe_match(parent, object_name, XML_ATTR_ID,
411 object_id);
412 }
413
414 if (result != pcmk_ok) {
415 ;
416
417 } else if (equiv_node == NULL) {
418 result = pcmk_ok;
419
420 } else if (xml_has_children(delete_spec) == FALSE) {
421
422 crm_debug("Removing leaf: <%s id=%s>", crm_str(object_name), crm_str(object_id));
423 free_xml(equiv_node);
424 equiv_node = NULL;
425
426 } else {
427 xmlNode *child = NULL;
428
429 for (child = pcmk__xml_first_child(delete_spec); child != NULL;
430 child = pcmk__xml_next(child)) {
431 int tmp_result = delete_cib_object(equiv_node, child);
432
433
434 if (tmp_result != pcmk_ok && result == pcmk_ok) {
435 result = tmp_result;
436 }
437 }
438 }
439
440 return result;
441 }
442
443 int
444 cib_process_delete_absolute(const char *op, int options, const char *section, xmlNode * req,
445 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
446 xmlNode ** answer)
447 {
448 xmlNode *failed = NULL;
449 int result = pcmk_ok;
450 xmlNode *update_section = NULL;
451
452 crm_trace("Processing \"%s\" event for section=%s", op, crm_str(section));
453 if (pcmk__str_eq(XML_CIB_TAG_SECTION_ALL, section, pcmk__str_casei)) {
454 section = NULL;
455
456 } else if (pcmk__str_eq(XML_TAG_CIB, section, pcmk__str_casei)) {
457 section = NULL;
458
459 } else if (pcmk__str_eq(crm_element_name(input), XML_TAG_CIB, pcmk__str_casei)) {
460 section = NULL;
461 }
462
463 CRM_CHECK(strcasecmp(CIB_OP_DELETE, op) == 0, return -EINVAL);
464
465 if (input == NULL) {
466 crm_err("Cannot perform modification with no data");
467 return -EINVAL;
468 }
469
470 failed = create_xml_node(NULL, XML_TAG_FAILED);
471
472 update_section = get_object_root(section, *result_cib);
473 result = delete_cib_object(update_section, input);
474 update_results(failed, input, op, result);
475
476 if ((result == pcmk_ok) && xml_has_children(failed)) {
477 result = -EINVAL;
478 }
479
480 if (result != pcmk_ok) {
481 crm_log_xml_err(failed, "CIB Update failures");
482 *answer = failed;
483
484 } else {
485 free_xml(failed);
486 }
487
488 return result;
489 }
490
491 int
492 sync_our_cib(xmlNode * request, gboolean all)
493 {
494 int result = pcmk_ok;
495 char *digest = NULL;
496 const char *host = crm_element_value(request, F_ORIG);
497 const char *op = crm_element_value(request, F_CIB_OPERATION);
498
499 xmlNode *replace_request = cib_msg_copy(request, FALSE);
500
501 CRM_CHECK(the_cib != NULL,;);
502 CRM_CHECK(replace_request != NULL,;);
503
504 crm_debug("Syncing CIB to %s", all ? "all peers" : host);
505 if (all == FALSE && host == NULL) {
506 crm_log_xml_err(request, "bad sync");
507 }
508
509
510
511
512
513
514
515
516 if (host != NULL) {
517 crm_xml_add(replace_request, F_CIB_ISREPLY, host);
518 }
519 if (all) {
520 xml_remove_prop(replace_request, F_CIB_HOST);
521 }
522
523 crm_xml_add(replace_request, F_CIB_OPERATION, CIB_OP_REPLACE);
524 crm_xml_add(replace_request, "original_" F_CIB_OPERATION, op);
525 crm_xml_add(replace_request, F_CIB_GLOBAL_UPDATE, XML_BOOLEAN_TRUE);
526
527 crm_xml_add(replace_request, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
528 digest = calculate_xml_versioned_digest(the_cib, FALSE, TRUE, CRM_FEATURE_SET);
529 crm_xml_add(replace_request, XML_ATTR_DIGEST, digest);
530
531 add_message_xml(replace_request, F_CIB_CALLDATA, the_cib);
532
533 if (send_cluster_message
534 (all ? NULL : crm_get_peer(0, host), crm_msg_cib, replace_request, FALSE) == FALSE) {
535 result = -ENOTCONN;
536 }
537 free_xml(replace_request);
538 free(digest);
539 return result;
540 }