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