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. cib_process_delete_absolute
  12. sync_our_cib

   1 /*
   2  * Copyright 2004-2022 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 bool based_is_primary = 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 (strcmp(PCMK__CIB_REQUEST_NOOP, op) != 0) {
  90         result = -EPROTONOSUPPORT;
  91         crm_err("Action [%s] is not supported by the CIB manager", op);
  92     }
  93     return result;
  94 }
  95 
  96 int
  97 cib_process_readwrite(const char *op, int options, const char *section, xmlNode * req,
     /* [previous][next][first][last][top][bottom][index][help] */
  98                       xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
  99                       xmlNode ** answer)
 100 {
 101     int result = pcmk_ok;
 102 
 103     crm_trace("Processing \"%s\" event", op);
 104 
 105     if (pcmk__str_eq(op, PCMK__CIB_REQUEST_IS_PRIMARY, pcmk__str_none)) {
 106         if (based_is_primary) {
 107             result = pcmk_ok;
 108         } else {
 109             result = -EPERM;
 110         }
 111         return result;
 112     }
 113 
 114     if (pcmk__str_eq(op, PCMK__CIB_REQUEST_PRIMARY, pcmk__str_none)) {
 115         if (!based_is_primary) {
 116             crm_info("We are now in R/W mode");
 117             based_is_primary = true;
 118         } else {
 119             crm_debug("We are still in R/W mode");
 120         }
 121 
 122     } else if (based_is_primary) {
 123         crm_info("We are now in R/O mode");
 124         based_is_primary = false;
 125     }
 126 
 127     return result;
 128 }
 129 
 130 /* Set to 1 when a sync is requested, incremented when a diff is ignored,
 131  * reset to 0 when a sync is received
 132  */
 133 static int sync_in_progress = 0;
 134 
 135 void
 136 send_sync_request(const char *host)
     /* [previous][next][first][last][top][bottom][index][help] */
 137 {
 138     xmlNode *sync_me = create_xml_node(NULL, "sync-me");
 139 
 140     crm_info("Requesting re-sync from %s", (host? host : "all peers"));
 141     sync_in_progress = 1;
 142 
 143     crm_xml_add(sync_me, F_TYPE, "cib");
 144     crm_xml_add(sync_me, F_CIB_OPERATION, PCMK__CIB_REQUEST_SYNC_TO_ONE);
 145     crm_xml_add(sync_me, F_CIB_DELEGATED, cib_our_uname);
 146 
 147     send_cluster_message(host ? crm_get_peer(0, host) : NULL, crm_msg_cib, sync_me, FALSE);
 148     free_xml(sync_me);
 149 }
 150 
 151 int
 152 cib_process_ping(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     /* [previous][next][first][last][top][bottom][index][help] */
 153                  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 154 {
 155     const char *host = crm_element_value(req, F_ORIG);
 156     const char *seq = crm_element_value(req, F_CIB_PING_ID);
 157     char *digest = calculate_xml_versioned_digest(the_cib, FALSE, TRUE, CRM_FEATURE_SET);
 158 
 159     static struct qb_log_callsite *cs = NULL;
 160 
 161     crm_trace("Processing \"%s\" event %s from %s", op, seq, host);
 162     *answer = create_xml_node(NULL, XML_CRM_TAG_PING);
 163 
 164     crm_xml_add(*answer, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
 165     crm_xml_add(*answer, XML_ATTR_DIGEST, digest);
 166     crm_xml_add(*answer, F_CIB_PING_ID, seq);
 167 
 168     if (cs == NULL) {
 169         cs = qb_log_callsite_get(__func__, __FILE__, __func__, LOG_TRACE,
 170                                  __LINE__, crm_trace_nonlog);
 171     }
 172     if (cs && cs->targets) {
 173         /* Append additional detail so the reciever can log the differences */
 174         add_message_xml(*answer, F_CIB_CALLDATA, the_cib);
 175 
 176     } else {
 177         /* Always include at least the version details */
 178         const char *tag = TYPE(the_cib);
 179         xmlNode *shallow = create_xml_node(NULL, tag);
 180 
 181         copy_in_properties(shallow, the_cib);
 182         add_message_xml(*answer, F_CIB_CALLDATA, shallow);
 183         free_xml(shallow);
 184     }
 185 
 186     crm_info("Reporting our current digest to %s: %s for %s.%s.%s (%p %d)",
 187              host, digest,
 188              crm_element_value(existing_cib, XML_ATTR_GENERATION_ADMIN),
 189              crm_element_value(existing_cib, XML_ATTR_GENERATION),
 190              crm_element_value(existing_cib, XML_ATTR_NUMUPDATES),
 191              existing_cib,
 192              cs && cs->targets);
 193 
 194     free(digest);
 195 
 196     return pcmk_ok;
 197 }
 198 
 199 int
 200 cib_process_sync(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     /* [previous][next][first][last][top][bottom][index][help] */
 201                  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 202 {
 203     return sync_our_cib(req, TRUE);
 204 }
 205 
 206 int
 207 cib_process_upgrade_server(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     /* [previous][next][first][last][top][bottom][index][help] */
 208                            xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 209 {
 210     int rc = pcmk_ok;
 211 
 212     *answer = NULL;
 213 
 214     if(crm_element_value(req, F_CIB_SCHEMA_MAX)) {
 215         /* The originator of an upgrade request sends it to the DC, without
 216          * F_CIB_SCHEMA_MAX. If an upgrade is needed, the DC re-broadcasts the
 217          * request with F_CIB_SCHEMA_MAX, and each node performs the upgrade
 218          * (and notifies its local clients) here.
 219          */
 220         return cib_process_upgrade(
 221             op, options, section, req, input, existing_cib, result_cib, answer);
 222 
 223     } else {
 224         int new_version = 0;
 225         int current_version = 0;
 226         xmlNode *scratch = copy_xml(existing_cib);
 227         const char *host = crm_element_value(req, F_ORIG);
 228         const char *value = crm_element_value(existing_cib, XML_ATTR_VALIDATION);
 229         const char *client_id = crm_element_value(req, F_CIB_CLIENTID);
 230         const char *call_opts = crm_element_value(req, F_CIB_CALLOPTS);
 231         const char *call_id = crm_element_value(req, F_CIB_CALLID);
 232 
 233         crm_trace("Processing \"%s\" event", op);
 234         if (value != NULL) {
 235             current_version = get_schema_version(value);
 236         }
 237 
 238         rc = update_validation(&scratch, &new_version, 0, TRUE, TRUE);
 239         if (new_version > current_version) {
 240             xmlNode *up = create_xml_node(NULL, __func__);
 241 
 242             rc = pcmk_ok;
 243             crm_notice("Upgrade request from %s verified", host);
 244 
 245             crm_xml_add(up, F_TYPE, "cib");
 246             crm_xml_add(up, F_CIB_OPERATION, PCMK__CIB_REQUEST_UPGRADE);
 247             crm_xml_add(up, F_CIB_SCHEMA_MAX, get_schema_name(new_version));
 248             crm_xml_add(up, F_CIB_DELEGATED, host);
 249             crm_xml_add(up, F_CIB_CLIENTID, client_id);
 250             crm_xml_add(up, F_CIB_CALLOPTS, call_opts);
 251             crm_xml_add(up, F_CIB_CALLID, call_id);
 252 
 253             if (cib_legacy_mode() && based_is_primary) {
 254                 rc = cib_process_upgrade(
 255                     op, options, section, up, input, existing_cib, result_cib, answer);
 256 
 257             } else {
 258                 send_cluster_message(NULL, crm_msg_cib, up, FALSE);
 259             }
 260 
 261             free_xml(up);
 262 
 263         } else if(rc == pcmk_ok) {
 264             rc = -pcmk_err_schema_unchanged;
 265         }
 266 
 267         if (rc != pcmk_ok) {
 268             // Notify originating peer so it can notify its local clients
 269             crm_node_t *origin = pcmk__search_cluster_node_cache(0, host);
 270 
 271             crm_info("Rejecting upgrade request from %s: %s "
 272                      CRM_XS " rc=%d peer=%s", host, pcmk_strerror(rc), rc,
 273                      (origin? origin->uname : "lost"));
 274 
 275             if (origin) {
 276                 xmlNode *up = create_xml_node(NULL, __func__);
 277 
 278                 crm_xml_add(up, F_TYPE, "cib");
 279                 crm_xml_add(up, F_CIB_OPERATION, PCMK__CIB_REQUEST_UPGRADE);
 280                 crm_xml_add(up, F_CIB_DELEGATED, host);
 281                 crm_xml_add(up, F_CIB_ISREPLY, host);
 282                 crm_xml_add(up, F_CIB_CLIENTID, client_id);
 283                 crm_xml_add(up, F_CIB_CALLOPTS, call_opts);
 284                 crm_xml_add(up, F_CIB_CALLID, call_id);
 285                 crm_xml_add_int(up, F_CIB_UPGRADE_RC, rc);
 286                 if (send_cluster_message(origin, crm_msg_cib, up, TRUE)
 287                     == FALSE) {
 288                     crm_warn("Could not send CIB upgrade result to %s", host);
 289                 }
 290                 free_xml(up);
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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         /* Don't ignore diffs forever; the last request may have been lost.
 315          * If the diff fails, we'll ask for another full resync.
 316          */
 317         sync_in_progress = 0;
 318     }
 319 
 320     // The primary instance should never ignore a diff
 321     if (sync_in_progress && !based_is_primary) {
 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,
 343               (based_is_primary? "primary": "secondary"));
 344 
 345     if ((rc == -pcmk_err_diff_resync) && !based_is_primary) {
 346         free_xml(*result_cib);
 347         *result_cib = NULL;
 348         send_sync_request(NULL);
 349 
 350     } else if (rc == -pcmk_err_diff_resync) {
 351         rc = -pcmk_err_diff_failed;
 352         if (options & cib_force_diff) {
 353             crm_warn("Not requesting full refresh in R/W mode");
 354         }
 355 
 356     } else if ((rc != pcmk_ok) && !based_is_primary && cib_legacy_mode()) {
 357         crm_warn("Requesting full CIB refresh because update failed: %s"
 358                  CRM_XS " rc=%d", pcmk_strerror(rc), rc);
 359         xml_log_patchset(LOG_INFO, __func__, input);
 360         free_xml(*result_cib);
 361         *result_cib = NULL;
 362         send_sync_request(NULL);
 363     }
 364 
 365     return rc;
 366 }
 367 
 368 int
 369 cib_process_replace_svr(const char *op, int options, const char *section, xmlNode * req,
     /* [previous][next][first][last][top][bottom][index][help] */
 370                         xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
 371                         xmlNode ** answer)
 372 {
 373     const char *tag = crm_element_name(input);
 374     int rc =
 375         cib_process_replace(op, options, section, req, input, existing_cib, result_cib, answer);
 376     if (rc == pcmk_ok && pcmk__str_eq(tag, XML_TAG_CIB, pcmk__str_casei)) {
 377         sync_in_progress = 0;
 378     }
 379     return rc;
 380 }
 381 
 382 int
 383 cib_process_delete_absolute(const char *op, int options, const char *section, xmlNode * req,
     /* [previous][next][first][last][top][bottom][index][help] */
 384                             xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
 385                             xmlNode ** answer)
 386 {
 387     return -EINVAL;
 388 }
 389 
 390 int
 391 sync_our_cib(xmlNode * request, gboolean all)
     /* [previous][next][first][last][top][bottom][index][help] */
 392 {
 393     int result = pcmk_ok;
 394     char *digest = NULL;
 395     const char *host = crm_element_value(request, F_ORIG);
 396     const char *op = crm_element_value(request, F_CIB_OPERATION);
 397 
 398     xmlNode *replace_request = NULL;
 399 
 400     CRM_CHECK(the_cib != NULL, return -EINVAL);
 401 
 402     replace_request = cib_msg_copy(request, FALSE);
 403     CRM_CHECK(replace_request != NULL, return -EINVAL);
 404 
 405     crm_debug("Syncing CIB to %s", all ? "all peers" : host);
 406     if (all == FALSE && host == NULL) {
 407         crm_log_xml_err(request, "bad sync");
 408     }
 409 
 410     /* remove the "all == FALSE" condition
 411      *
 412      * sync_from was failing, the local client wasn't being notified
 413      *    because it didn't know it was a reply
 414      * setting this does not prevent the other nodes from applying it
 415      *    if all == TRUE
 416      */
 417     if (host != NULL) {
 418         crm_xml_add(replace_request, F_CIB_ISREPLY, host);
 419     }
 420     if (all) {
 421         xml_remove_prop(replace_request, F_CIB_HOST);
 422     }
 423 
 424     crm_xml_add(replace_request, F_CIB_OPERATION, PCMK__CIB_REQUEST_REPLACE);
 425     crm_xml_add(replace_request, "original_" F_CIB_OPERATION, op);
 426     pcmk__xe_set_bool_attr(replace_request, F_CIB_GLOBAL_UPDATE, true);
 427 
 428     crm_xml_add(replace_request, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
 429     digest = calculate_xml_versioned_digest(the_cib, FALSE, TRUE, CRM_FEATURE_SET);
 430     crm_xml_add(replace_request, XML_ATTR_DIGEST, digest);
 431 
 432     add_message_xml(replace_request, F_CIB_CALLDATA, the_cib);
 433 
 434     if (send_cluster_message
 435         (all ? NULL : crm_get_peer(0, host), crm_msg_cib, replace_request, FALSE) == FALSE) {
 436         result = -ENOTCONN;
 437     }
 438     free_xml(replace_request);
 439     free(digest);
 440     return result;
 441 }

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