root/daemons/based/based_messages.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cib_process_shutdown_req
  2. cib_process_default
  3. cib_process_readwrite
  4. send_sync_request
  5. cib_process_ping
  6. cib_process_sync
  7. cib_process_upgrade_server
  8. cib_process_sync_one
  9. cib_server_process_diff
  10. cib_process_replace_svr
  11. delete_cib_object
  12. cib_process_delete_absolute
  13. sync_our_cib

   1 /*
   2  * Copyright 2004-2020 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   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 /* Maximum number of diffs to ignore while waiting for a resync */
  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,
     /* [previous][next][first][last][top][bottom][index][help] */
  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,
     /* [previous][next][first][last][top][bottom][index][help] */
  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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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 /* Set to 1 when a sync is requested, incremented when a diff is ignored,
 134  * reset to 0 when a sync is received
 135  */
 136 static int sync_in_progress = 0;
 137 
 138 void
 139 send_sync_request(const char *host)
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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         /* Append additional detail so the reciever can log the differences */
 177         add_message_xml(*answer, F_CIB_CALLDATA, the_cib);
 178 
 179     } else {
 180         /* Always include at least the version details */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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         /* The originator of an upgrade request sends it to the DC, without
 219          * F_CIB_SCHEMA_MAX. If an upgrade is needed, the DC re-broadcasts the
 220          * request with F_CIB_SCHEMA_MAX, and each node performs the upgrade
 221          * (and notifies its local clients) here.
 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             // Notify originating peer so it can notify its local clients
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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         /* Don't ignore diffs forever; the last request may have been lost.
 318          * If the diff fails, we'll ask for another full resync.
 319          */
 320         sync_in_progress = 0;
 321     }
 322 
 323     /* The master should never ignore a diff */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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         /*  placeholder object */
 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         ;                       /* nothing */
 416 
 417     } else if (equiv_node == NULL) {
 418         result = pcmk_ok;
 419 
 420     } else if (xml_has_children(delete_spec) == FALSE) {
 421         /*  only leaves are deleted */
 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             /*  only the first error is likely to be interesting */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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     /* remove the "all == FALSE" condition
 510      *
 511      * sync_from was failing, the local client wasn't being notified
 512      *    because it didn't know it was a reply
 513      * setting this does not prevent the other nodes from applying it
 514      *    if all == TRUE
 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 }

/* [previous][next][first][last][top][bottom][index][help] */