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
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 #include <crm/msg_xml.h>
28
29 #include <crm/common/xml.h>
30 #include <crm/common/ipc_internal.h>
31 #include <crm/common/xml_internal.h>
32 #include <crm/cluster/internal.h>
33
34 #include <pacemaker-based.h>
35
36
37 #define MAX_DIFF_RETRY 5
38
39 bool based_is_primary = false;
40
41 xmlNode *the_cib = NULL;
42
43 int
44 cib_process_shutdown_req(const char *op, int options, const char *section, xmlNode * req,
45 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
46 xmlNode ** answer)
47 {
48 const char *host = crm_element_value(req, F_ORIG);
49
50 *answer = NULL;
51
52 if (crm_element_value(req, F_CIB_ISREPLY) == NULL) {
53 crm_info("Peer %s is requesting to shut down", host);
54 return pcmk_ok;
55 }
56
57 if (cib_shutdown_flag == FALSE) {
58 crm_err("Peer %s mistakenly thinks we wanted to shut down", host);
59 return -EINVAL;
60 }
61
62 crm_info("Peer %s has acknowledged our shutdown request", host);
63 terminate_cib(__func__, 0);
64 return pcmk_ok;
65 }
66
67
68 int
69 cib_process_noop(const char *op, int options, const char *section, xmlNode *req,
70 xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib,
71 xmlNode **answer)
72 {
73 crm_trace("Processing \"%s\" event", op);
74 *answer = NULL;
75 return pcmk_ok;
76 }
77
78 int
79 cib_process_readwrite(const char *op, int options, const char *section, xmlNode * req,
80 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
81 xmlNode ** answer)
82 {
83 int result = pcmk_ok;
84
85 crm_trace("Processing \"%s\" event", op);
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 = create_xml_node(NULL, "sync-me");
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, F_TYPE, "cib");
126 crm_xml_add(sync_me, F_CIB_OPERATION, PCMK__CIB_REQUEST_SYNC_TO_ONE);
127 crm_xml_add(sync_me, F_CIB_DELEGATED,
128 stand_alone? "localhost" : crm_cluster->uname);
129
130 send_cluster_message(host ? crm_get_peer(0, host) : NULL, crm_msg_cib, sync_me, FALSE);
131 free_xml(sync_me);
132 }
133
134 int
135 cib_process_ping(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
136 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
137 {
138 const char *host = crm_element_value(req, F_ORIG);
139 const char *seq = crm_element_value(req, F_CIB_PING_ID);
140 char *digest = calculate_xml_versioned_digest(the_cib, FALSE, TRUE, CRM_FEATURE_SET);
141
142 crm_trace("Processing \"%s\" event %s from %s", op, seq, host);
143 *answer = create_xml_node(NULL, XML_CRM_TAG_PING);
144
145 crm_xml_add(*answer, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
146 crm_xml_add(*answer, XML_ATTR_DIGEST, digest);
147 crm_xml_add(*answer, F_CIB_PING_ID, seq);
148
149 pcmk__if_tracing(
150 {
151
152 add_message_xml(*answer, F_CIB_CALLDATA, the_cib);
153 },
154 if (the_cib != NULL) {
155
156 xmlNode *shallow = create_xml_node(NULL,
157 (const char *) the_cib->name);
158
159 copy_in_properties(shallow, the_cib);
160 add_message_xml(*answer, F_CIB_CALLDATA, shallow);
161 free_xml(shallow);
162 }
163 );
164
165 crm_info("Reporting our current digest to %s: %s for %s.%s.%s",
166 host, digest,
167 crm_element_value(existing_cib, XML_ATTR_GENERATION_ADMIN),
168 crm_element_value(existing_cib, XML_ATTR_GENERATION),
169 crm_element_value(existing_cib, XML_ATTR_NUMUPDATES));
170
171 free(digest);
172
173 return pcmk_ok;
174 }
175
176 int
177 cib_process_sync(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
178 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
179 {
180 return sync_our_cib(req, TRUE);
181 }
182
183 int
184 cib_process_upgrade_server(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
185 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
186 {
187 int rc = pcmk_ok;
188
189 *answer = NULL;
190
191 if(crm_element_value(req, F_CIB_SCHEMA_MAX)) {
192
193
194
195
196
197 return cib_process_upgrade(
198 op, options, section, req, input, existing_cib, result_cib, answer);
199
200 } else {
201 int new_version = 0;
202 int current_version = 0;
203 xmlNode *scratch = copy_xml(existing_cib);
204 const char *host = crm_element_value(req, F_ORIG);
205 const char *value = crm_element_value(existing_cib, XML_ATTR_VALIDATION);
206 const char *client_id = crm_element_value(req, F_CIB_CLIENTID);
207 const char *call_opts = crm_element_value(req, F_CIB_CALLOPTS);
208 const char *call_id = crm_element_value(req, F_CIB_CALLID);
209
210 crm_trace("Processing \"%s\" event", op);
211 if (value != NULL) {
212 current_version = get_schema_version(value);
213 }
214
215 rc = update_validation(&scratch, &new_version, 0, TRUE, TRUE);
216 if (new_version > current_version) {
217 xmlNode *up = create_xml_node(NULL, __func__);
218
219 rc = pcmk_ok;
220 crm_notice("Upgrade request from %s verified", host);
221
222 crm_xml_add(up, F_TYPE, "cib");
223 crm_xml_add(up, F_CIB_OPERATION, PCMK__CIB_REQUEST_UPGRADE);
224 crm_xml_add(up, F_CIB_SCHEMA_MAX, get_schema_name(new_version));
225 crm_xml_add(up, F_CIB_DELEGATED, host);
226 crm_xml_add(up, F_CIB_CLIENTID, client_id);
227 crm_xml_add(up, F_CIB_CALLOPTS, call_opts);
228 crm_xml_add(up, F_CIB_CALLID, call_id);
229
230 if (cib_legacy_mode() && based_is_primary) {
231 rc = cib_process_upgrade(
232 op, options, section, up, input, existing_cib, result_cib, answer);
233
234 } else {
235 send_cluster_message(NULL, crm_msg_cib, up, FALSE);
236 }
237
238 free_xml(up);
239
240 } else if(rc == pcmk_ok) {
241 rc = -pcmk_err_schema_unchanged;
242 }
243
244 if (rc != pcmk_ok) {
245
246 crm_node_t *origin = pcmk__search_cluster_node_cache(0, host, NULL);
247
248 crm_info("Rejecting upgrade request from %s: %s "
249 CRM_XS " rc=%d peer=%s", host, pcmk_strerror(rc), rc,
250 (origin? origin->uname : "lost"));
251
252 if (origin) {
253 xmlNode *up = create_xml_node(NULL, __func__);
254
255 crm_xml_add(up, F_TYPE, "cib");
256 crm_xml_add(up, F_CIB_OPERATION, PCMK__CIB_REQUEST_UPGRADE);
257 crm_xml_add(up, F_CIB_DELEGATED, host);
258 crm_xml_add(up, F_CIB_ISREPLY, host);
259 crm_xml_add(up, F_CIB_CLIENTID, client_id);
260 crm_xml_add(up, F_CIB_CALLOPTS, call_opts);
261 crm_xml_add(up, F_CIB_CALLID, call_id);
262 crm_xml_add_int(up, F_CIB_UPGRADE_RC, rc);
263 if (send_cluster_message(origin, crm_msg_cib, up, TRUE)
264 == FALSE) {
265 crm_warn("Could not send CIB upgrade result to %s", host);
266 }
267 free_xml(up);
268 }
269 }
270 free_xml(scratch);
271 }
272 return rc;
273 }
274
275 int
276 cib_process_sync_one(const char *op, int options, const char *section, xmlNode * req,
277 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
278 xmlNode ** answer)
279 {
280 return sync_our_cib(req, FALSE);
281 }
282
283 int
284 cib_server_process_diff(const char *op, int options, const char *section, xmlNode * req,
285 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
286 xmlNode ** answer)
287 {
288 int rc = pcmk_ok;
289
290 if (sync_in_progress > MAX_DIFF_RETRY) {
291
292
293
294 sync_in_progress = 0;
295 }
296
297
298 if (sync_in_progress && !based_is_primary) {
299 int diff_add_updates = 0;
300 int diff_add_epoch = 0;
301 int diff_add_admin_epoch = 0;
302
303 int diff_del_updates = 0;
304 int diff_del_epoch = 0;
305 int diff_del_admin_epoch = 0;
306
307 cib_diff_version_details(input,
308 &diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates,
309 &diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);
310
311 sync_in_progress++;
312 crm_notice("Not applying diff %d.%d.%d -> %d.%d.%d (sync in progress)",
313 diff_del_admin_epoch, diff_del_epoch, diff_del_updates,
314 diff_add_admin_epoch, diff_add_epoch, diff_add_updates);
315 return -pcmk_err_diff_resync;
316 }
317
318 rc = cib_process_diff(op, options, section, req, input, existing_cib, result_cib, answer);
319 crm_trace("result: %s (%d), %s", pcmk_strerror(rc), rc,
320 (based_is_primary? "primary": "secondary"));
321
322 if ((rc == -pcmk_err_diff_resync) && !based_is_primary) {
323 free_xml(*result_cib);
324 *result_cib = NULL;
325 send_sync_request(NULL);
326
327 } else if (rc == -pcmk_err_diff_resync) {
328 rc = -pcmk_err_diff_failed;
329 if (options & cib_force_diff) {
330 crm_warn("Not requesting full refresh in R/W mode");
331 }
332
333 } else if ((rc != pcmk_ok) && !based_is_primary && cib_legacy_mode()) {
334 crm_warn("Requesting full CIB refresh because update failed: %s"
335 CRM_XS " rc=%d", pcmk_strerror(rc), rc);
336
337 pcmk__log_xml_patchset(LOG_INFO, input);
338 free_xml(*result_cib);
339 *result_cib = NULL;
340 send_sync_request(NULL);
341 }
342
343 return rc;
344 }
345
346 int
347 cib_process_replace_svr(const char *op, int options, const char *section, xmlNode * req,
348 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
349 xmlNode ** answer)
350 {
351 int rc =
352 cib_process_replace(op, options, section, req, input, existing_cib, result_cib, answer);
353
354 if ((rc == pcmk_ok) && pcmk__xe_is(input, XML_TAG_CIB)) {
355 sync_in_progress = 0;
356 }
357 return rc;
358 }
359
360
361 int
362 cib_process_delete_absolute(const char *op, int options, const char *section, xmlNode * req,
363 xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
364 xmlNode ** answer)
365 {
366 return -EINVAL;
367 }
368
369 static xmlNode *
370 cib_msg_copy(xmlNode *msg)
371 {
372 static const char *field_list[] = {
373 F_XML_TAGNAME,
374 F_TYPE,
375 F_CIB_CLIENTID,
376 F_CIB_CALLOPTS,
377 F_CIB_CALLID,
378 F_CIB_OPERATION,
379 F_CIB_ISREPLY,
380 F_CIB_SECTION,
381 F_CIB_HOST,
382 F_CIB_RC,
383 F_CIB_DELEGATED,
384 F_CIB_OBJID,
385 F_CIB_OBJTYPE,
386 F_CIB_EXISTING,
387 F_CIB_SEENCOUNT,
388 F_CIB_TIMEOUT,
389 F_CIB_GLOBAL_UPDATE,
390 F_CIB_CLIENTNAME,
391 F_CIB_USER,
392 F_CIB_NOTIFY_TYPE,
393 F_CIB_NOTIFY_ACTIVATE
394 };
395
396 xmlNode *copy = create_xml_node(NULL, "copy");
397
398 CRM_ASSERT(copy != NULL);
399
400 for (int lpc = 0; lpc < PCMK__NELEM(field_list); lpc++) {
401 const char *field = field_list[lpc];
402 const char *value = crm_element_value(msg, field);
403
404 if (value != NULL) {
405 crm_xml_add(copy, field, value);
406 }
407 }
408
409 return copy;
410 }
411
412 int
413 sync_our_cib(xmlNode * request, gboolean all)
414 {
415 int result = pcmk_ok;
416 char *digest = NULL;
417 const char *host = crm_element_value(request, F_ORIG);
418 const char *op = crm_element_value(request, F_CIB_OPERATION);
419
420 xmlNode *replace_request = NULL;
421
422 CRM_CHECK(the_cib != NULL, return -EINVAL);
423 CRM_CHECK(all || (host != NULL), return -EINVAL);
424
425 crm_debug("Syncing CIB to %s", all ? "all peers" : host);
426
427 replace_request = cib_msg_copy(request);
428
429 if (host != NULL) {
430 crm_xml_add(replace_request, F_CIB_ISREPLY, host);
431 }
432 if (all) {
433 xml_remove_prop(replace_request, F_CIB_HOST);
434 }
435
436 crm_xml_add(replace_request, F_CIB_OPERATION, PCMK__CIB_REQUEST_REPLACE);
437 crm_xml_add(replace_request, "original_" F_CIB_OPERATION, op);
438 pcmk__xe_set_bool_attr(replace_request, F_CIB_GLOBAL_UPDATE, true);
439
440 crm_xml_add(replace_request, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
441 digest = calculate_xml_versioned_digest(the_cib, FALSE, TRUE, CRM_FEATURE_SET);
442 crm_xml_add(replace_request, XML_ATTR_DIGEST, digest);
443
444 add_message_xml(replace_request, F_CIB_CALLDATA, the_cib);
445
446 if (send_cluster_message
447 (all ? NULL : crm_get_peer(0, host), crm_msg_cib, replace_request, FALSE) == FALSE) {
448 result = -ENOTCONN;
449 }
450 free_xml(replace_request);
451 free(digest);
452 return result;
453 }
454
455 int
456 cib_process_commit_transaction(const char *op, int options, const char *section,
457 xmlNode *req, xmlNode *input,
458 xmlNode *existing_cib, xmlNode **result_cib,
459 xmlNode **answer)
460 {
461
462
463
464
465 int rc = pcmk_rc_ok;
466 const char *client_id = crm_element_value(req, F_CIB_CLIENTID);
467 const char *origin = crm_element_value(req, F_ORIG);
468 pcmk__client_t *client = pcmk__find_client_by_id(client_id);
469
470 rc = based_commit_transaction(input, client, origin, result_cib);
471
472 if (rc != pcmk_rc_ok) {
473 char *source = based_transaction_source_str(client, origin);
474
475 crm_err("Could not commit transaction for %s: %s",
476 source, pcmk_rc_str(rc));
477 free(source);
478 }
479 return pcmk_rc2legacy(rc);
480 }