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-2023 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 
  40 int
  41 cib_process_shutdown_req(const char *op, int options, const char *section, xmlNode * req,
     /* [previous][next][first][last][top][bottom][index][help] */
  42                          xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
  43                          xmlNode ** answer)
  44 {
  45     const char *host = crm_element_value(req, F_ORIG);
  46 
  47     *answer = NULL;
  48 
  49     if (crm_element_value(req, F_CIB_ISREPLY) == NULL) {
  50         crm_info("Peer %s is requesting to shut down", host);
  51         return pcmk_ok;
  52     }
  53 
  54     if (cib_shutdown_flag == FALSE) {
  55         crm_err("Peer %s mistakenly thinks we wanted to shut down", host);
  56         return -EINVAL;
  57     }
  58 
  59     crm_info("Peer %s has acknowledged our shutdown request", host);
  60     terminate_cib(__func__, 0);
  61     return pcmk_ok;
  62 }
  63 
  64 int
  65 cib_process_default(const char *op, int options, const char *section, xmlNode * req,
     /* [previous][next][first][last][top][bottom][index][help] */
  66                     xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
  67                     xmlNode ** answer)
  68 {
  69     int result = pcmk_ok;
  70 
  71     crm_trace("Processing \"%s\" event", op);
  72     *answer = NULL;
  73 
  74     if (op == NULL) {
  75         result = -EINVAL;
  76         crm_err("No operation specified");
  77 
  78     } else if (strcmp(PCMK__CIB_REQUEST_NOOP, op) != 0) {
  79         result = -EPROTONOSUPPORT;
  80         crm_err("Action [%s] is not supported by the CIB manager", op);
  81     }
  82     return result;
  83 }
  84 
  85 int
  86 cib_process_readwrite(const char *op, int options, const char *section, xmlNode * req,
     /* [previous][next][first][last][top][bottom][index][help] */
  87                       xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
  88                       xmlNode ** answer)
  89 {
  90     int result = pcmk_ok;
  91 
  92     crm_trace("Processing \"%s\" event", op);
  93 
  94     if (pcmk__str_eq(op, PCMK__CIB_REQUEST_IS_PRIMARY, pcmk__str_none)) {
  95         if (based_is_primary) {
  96             result = pcmk_ok;
  97         } else {
  98             result = -EPERM;
  99         }
 100         return result;
 101     }
 102 
 103     if (pcmk__str_eq(op, PCMK__CIB_REQUEST_PRIMARY, pcmk__str_none)) {
 104         if (!based_is_primary) {
 105             crm_info("We are now in R/W mode");
 106             based_is_primary = true;
 107         } else {
 108             crm_debug("We are still in R/W mode");
 109         }
 110 
 111     } else if (based_is_primary) {
 112         crm_info("We are now in R/O mode");
 113         based_is_primary = false;
 114     }
 115 
 116     return result;
 117 }
 118 
 119 /* Set to 1 when a sync is requested, incremented when a diff is ignored,
 120  * reset to 0 when a sync is received
 121  */
 122 static int sync_in_progress = 0;
 123 
 124 void
 125 send_sync_request(const char *host)
     /* [previous][next][first][last][top][bottom][index][help] */
 126 {
 127     xmlNode *sync_me = create_xml_node(NULL, "sync-me");
 128 
 129     crm_info("Requesting re-sync from %s", (host? host : "all peers"));
 130     sync_in_progress = 1;
 131 
 132     crm_xml_add(sync_me, F_TYPE, "cib");
 133     crm_xml_add(sync_me, F_CIB_OPERATION, PCMK__CIB_REQUEST_SYNC_TO_ONE);
 134     crm_xml_add(sync_me, F_CIB_DELEGATED,
 135                 stand_alone? "localhost" : crm_cluster->uname);
 136 
 137     send_cluster_message(host ? crm_get_peer(0, host) : NULL, crm_msg_cib, sync_me, FALSE);
 138     free_xml(sync_me);
 139 }
 140 
 141 int
 142 cib_process_ping(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     /* [previous][next][first][last][top][bottom][index][help] */
 143                  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 144 {
 145     const char *host = crm_element_value(req, F_ORIG);
 146     const char *seq = crm_element_value(req, F_CIB_PING_ID);
 147     char *digest = calculate_xml_versioned_digest(the_cib, FALSE, TRUE, CRM_FEATURE_SET);
 148 
 149     crm_trace("Processing \"%s\" event %s from %s", op, seq, host);
 150     *answer = create_xml_node(NULL, XML_CRM_TAG_PING);
 151 
 152     crm_xml_add(*answer, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
 153     crm_xml_add(*answer, XML_ATTR_DIGEST, digest);
 154     crm_xml_add(*answer, F_CIB_PING_ID, seq);
 155 
 156     pcmk__if_tracing(
 157         {
 158             // Append additional detail so the receiver can log the differences
 159             add_message_xml(*answer, F_CIB_CALLDATA, the_cib);
 160         },
 161         {
 162             // Always include at least the version details
 163             const char *tag = TYPE(the_cib);
 164             xmlNode *shallow = create_xml_node(NULL, tag);
 165 
 166             copy_in_properties(shallow, the_cib);
 167             add_message_xml(*answer, F_CIB_CALLDATA, shallow);
 168             free_xml(shallow);
 169         }
 170     );
 171 
 172     crm_info("Reporting our current digest to %s: %s for %s.%s.%s",
 173              host, digest,
 174              crm_element_value(existing_cib, XML_ATTR_GENERATION_ADMIN),
 175              crm_element_value(existing_cib, XML_ATTR_GENERATION),
 176              crm_element_value(existing_cib, XML_ATTR_NUMUPDATES));
 177 
 178     free(digest);
 179 
 180     return pcmk_ok;
 181 }
 182 
 183 int
 184 cib_process_sync(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     /* [previous][next][first][last][top][bottom][index][help] */
 185                  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 186 {
 187     return sync_our_cib(req, TRUE);
 188 }
 189 
 190 int
 191 cib_process_upgrade_server(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     /* [previous][next][first][last][top][bottom][index][help] */
 192                            xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 193 {
 194     int rc = pcmk_ok;
 195 
 196     *answer = NULL;
 197 
 198     if(crm_element_value(req, F_CIB_SCHEMA_MAX)) {
 199         /* The originator of an upgrade request sends it to the DC, without
 200          * F_CIB_SCHEMA_MAX. If an upgrade is needed, the DC re-broadcasts the
 201          * request with F_CIB_SCHEMA_MAX, and each node performs the upgrade
 202          * (and notifies its local clients) here.
 203          */
 204         return cib_process_upgrade(
 205             op, options, section, req, input, existing_cib, result_cib, answer);
 206 
 207     } else {
 208         int new_version = 0;
 209         int current_version = 0;
 210         xmlNode *scratch = copy_xml(existing_cib);
 211         const char *host = crm_element_value(req, F_ORIG);
 212         const char *value = crm_element_value(existing_cib, XML_ATTR_VALIDATION);
 213         const char *client_id = crm_element_value(req, F_CIB_CLIENTID);
 214         const char *call_opts = crm_element_value(req, F_CIB_CALLOPTS);
 215         const char *call_id = crm_element_value(req, F_CIB_CALLID);
 216 
 217         crm_trace("Processing \"%s\" event", op);
 218         if (value != NULL) {
 219             current_version = get_schema_version(value);
 220         }
 221 
 222         rc = update_validation(&scratch, &new_version, 0, TRUE, TRUE);
 223         if (new_version > current_version) {
 224             xmlNode *up = create_xml_node(NULL, __func__);
 225 
 226             rc = pcmk_ok;
 227             crm_notice("Upgrade request from %s verified", host);
 228 
 229             crm_xml_add(up, F_TYPE, "cib");
 230             crm_xml_add(up, F_CIB_OPERATION, PCMK__CIB_REQUEST_UPGRADE);
 231             crm_xml_add(up, F_CIB_SCHEMA_MAX, get_schema_name(new_version));
 232             crm_xml_add(up, F_CIB_DELEGATED, host);
 233             crm_xml_add(up, F_CIB_CLIENTID, client_id);
 234             crm_xml_add(up, F_CIB_CALLOPTS, call_opts);
 235             crm_xml_add(up, F_CIB_CALLID, call_id);
 236 
 237             if (cib_legacy_mode() && based_is_primary) {
 238                 rc = cib_process_upgrade(
 239                     op, options, section, up, input, existing_cib, result_cib, answer);
 240 
 241             } else {
 242                 send_cluster_message(NULL, crm_msg_cib, up, FALSE);
 243             }
 244 
 245             free_xml(up);
 246 
 247         } else if(rc == pcmk_ok) {
 248             rc = -pcmk_err_schema_unchanged;
 249         }
 250 
 251         if (rc != pcmk_ok) {
 252             // Notify originating peer so it can notify its local clients
 253             crm_node_t *origin = pcmk__search_cluster_node_cache(0, host);
 254 
 255             crm_info("Rejecting upgrade request from %s: %s "
 256                      CRM_XS " rc=%d peer=%s", host, pcmk_strerror(rc), rc,
 257                      (origin? origin->uname : "lost"));
 258 
 259             if (origin) {
 260                 xmlNode *up = create_xml_node(NULL, __func__);
 261 
 262                 crm_xml_add(up, F_TYPE, "cib");
 263                 crm_xml_add(up, F_CIB_OPERATION, PCMK__CIB_REQUEST_UPGRADE);
 264                 crm_xml_add(up, F_CIB_DELEGATED, host);
 265                 crm_xml_add(up, F_CIB_ISREPLY, host);
 266                 crm_xml_add(up, F_CIB_CLIENTID, client_id);
 267                 crm_xml_add(up, F_CIB_CALLOPTS, call_opts);
 268                 crm_xml_add(up, F_CIB_CALLID, call_id);
 269                 crm_xml_add_int(up, F_CIB_UPGRADE_RC, rc);
 270                 if (send_cluster_message(origin, crm_msg_cib, up, TRUE)
 271                     == FALSE) {
 272                     crm_warn("Could not send CIB upgrade result to %s", host);
 273                 }
 274                 free_xml(up);
 275             }
 276         }
 277         free_xml(scratch);
 278     }
 279     return rc;
 280 }
 281 
 282 int
 283 cib_process_sync_one(const char *op, int options, const char *section, xmlNode * req,
     /* [previous][next][first][last][top][bottom][index][help] */
 284                      xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
 285                      xmlNode ** answer)
 286 {
 287     return sync_our_cib(req, FALSE);
 288 }
 289 
 290 int
 291 cib_server_process_diff(const char *op, int options, const char *section, xmlNode * req,
     /* [previous][next][first][last][top][bottom][index][help] */
 292                         xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
 293                         xmlNode ** answer)
 294 {
 295     int rc = pcmk_ok;
 296 
 297     if (sync_in_progress > MAX_DIFF_RETRY) {
 298         /* Don't ignore diffs forever; the last request may have been lost.
 299          * If the diff fails, we'll ask for another full resync.
 300          */
 301         sync_in_progress = 0;
 302     }
 303 
 304     // The primary instance should never ignore a diff
 305     if (sync_in_progress && !based_is_primary) {
 306         int diff_add_updates = 0;
 307         int diff_add_epoch = 0;
 308         int diff_add_admin_epoch = 0;
 309 
 310         int diff_del_updates = 0;
 311         int diff_del_epoch = 0;
 312         int diff_del_admin_epoch = 0;
 313 
 314         cib_diff_version_details(input,
 315                                  &diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates,
 316                                  &diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);
 317 
 318         sync_in_progress++;
 319         crm_notice("Not applying diff %d.%d.%d -> %d.%d.%d (sync in progress)",
 320                    diff_del_admin_epoch, diff_del_epoch, diff_del_updates,
 321                    diff_add_admin_epoch, diff_add_epoch, diff_add_updates);
 322         return -pcmk_err_diff_resync;
 323     }
 324 
 325     rc = cib_process_diff(op, options, section, req, input, existing_cib, result_cib, answer);
 326     crm_trace("result: %s (%d), %s", pcmk_strerror(rc), rc,
 327               (based_is_primary? "primary": "secondary"));
 328 
 329     if ((rc == -pcmk_err_diff_resync) && !based_is_primary) {
 330         free_xml(*result_cib);
 331         *result_cib = NULL;
 332         send_sync_request(NULL);
 333 
 334     } else if (rc == -pcmk_err_diff_resync) {
 335         rc = -pcmk_err_diff_failed;
 336         if (options & cib_force_diff) {
 337             crm_warn("Not requesting full refresh in R/W mode");
 338         }
 339 
 340     } else if ((rc != pcmk_ok) && !based_is_primary && cib_legacy_mode()) {
 341         crm_warn("Requesting full CIB refresh because update failed: %s"
 342                  CRM_XS " rc=%d", pcmk_strerror(rc), rc);
 343 
 344         pcmk__output_set_log_level(logger_out, LOG_INFO);
 345         logger_out->message(logger_out, "xml-patchset", input);
 346         free_xml(*result_cib);
 347         *result_cib = NULL;
 348         send_sync_request(NULL);
 349     }
 350 
 351     return rc;
 352 }
 353 
 354 int
 355 cib_process_replace_svr(const char *op, int options, const char *section, xmlNode * req,
     /* [previous][next][first][last][top][bottom][index][help] */
 356                         xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
 357                         xmlNode ** answer)
 358 {
 359     const char *tag = crm_element_name(input);
 360     int rc =
 361         cib_process_replace(op, options, section, req, input, existing_cib, result_cib, answer);
 362     if (rc == pcmk_ok && pcmk__str_eq(tag, XML_TAG_CIB, pcmk__str_casei)) {
 363         sync_in_progress = 0;
 364     }
 365     return rc;
 366 }
 367 
 368 int
 369 cib_process_delete_absolute(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     return -EINVAL;
 374 }
 375 
 376 int
 377 sync_our_cib(xmlNode * request, gboolean all)
     /* [previous][next][first][last][top][bottom][index][help] */
 378 {
 379     int result = pcmk_ok;
 380     char *digest = NULL;
 381     const char *host = crm_element_value(request, F_ORIG);
 382     const char *op = crm_element_value(request, F_CIB_OPERATION);
 383 
 384     xmlNode *replace_request = NULL;
 385 
 386     CRM_CHECK(the_cib != NULL, return -EINVAL);
 387 
 388     replace_request = cib_msg_copy(request, FALSE);
 389     CRM_CHECK(replace_request != NULL, return -EINVAL);
 390 
 391     crm_debug("Syncing CIB to %s", all ? "all peers" : host);
 392     if (all == FALSE && host == NULL) {
 393         crm_log_xml_err(request, "bad sync");
 394     }
 395 
 396     /* remove the "all == FALSE" condition
 397      *
 398      * sync_from was failing, the local client wasn't being notified
 399      *    because it didn't know it was a reply
 400      * setting this does not prevent the other nodes from applying it
 401      *    if all == TRUE
 402      */
 403     if (host != NULL) {
 404         crm_xml_add(replace_request, F_CIB_ISREPLY, host);
 405     }
 406     if (all) {
 407         xml_remove_prop(replace_request, F_CIB_HOST);
 408     }
 409 
 410     crm_xml_add(replace_request, F_CIB_OPERATION, PCMK__CIB_REQUEST_REPLACE);
 411     crm_xml_add(replace_request, "original_" F_CIB_OPERATION, op);
 412     pcmk__xe_set_bool_attr(replace_request, F_CIB_GLOBAL_UPDATE, true);
 413 
 414     crm_xml_add(replace_request, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
 415     digest = calculate_xml_versioned_digest(the_cib, FALSE, TRUE, CRM_FEATURE_SET);
 416     crm_xml_add(replace_request, XML_ATTR_DIGEST, digest);
 417 
 418     add_message_xml(replace_request, F_CIB_CALLDATA, the_cib);
 419 
 420     if (send_cluster_message
 421         (all ? NULL : crm_get_peer(0, host), crm_msg_cib, replace_request, FALSE) == FALSE) {
 422         result = -ENOTCONN;
 423     }
 424     free_xml(replace_request);
 425     free(digest);
 426     return result;
 427 }

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