root/cib/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_quit
  4. cib_process_readwrite
  5. send_sync_request
  6. cib_process_ping
  7. cib_process_sync
  8. cib_process_upgrade_server
  9. cib_process_sync_one
  10. cib_server_process_diff
  11. cib_process_replace_svr
  12. delete_cib_object
  13. cib_process_delete_absolute
  14. check_generation
  15. sync_our_cib

   1 /*
   2  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
   3  *
   4  * This program is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2 of the License, or (at your option) any later version.
   8  *
   9  * This software is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU General Public
  15  * License along with this library; if not, write to the Free Software
  16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  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 /* Maximum number of diffs to ignore while waiting for a resync */
  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,
     /* [previous][next][first][last][top][bottom][index][help] */
  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,
     /* [previous][next][first][last][top][bottom][index][help] */
  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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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 /* Set to 1 when a sync is requested, incremented when a diff is ignored,
 166  * reset to 0 when a sync is received
 167  */
 168 static int sync_in_progress = 0;
 169 
 170 void
 171 send_sync_request(const char *host)
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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         /* Append additional detail so the reciever can log the differences */
 208         add_message_xml(*answer, F_CIB_CALLDATA, the_cib);
 209 
 210     } else {
 211         /* Always include at least the version details */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [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 master should never ignore a diff */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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         /*  placeholder object */
 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         ;                       /* nothing */
 412 
 413     } else if (equiv_node == NULL) {
 414         result = pcmk_ok;
 415 
 416     } else if (xml_has_children(delete_spec) == FALSE) {
 417         /*  only leaves are deleted */
 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             /*  only the first error is likely to be interesting */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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     /* remove the "all == FALSE" condition
 516      *
 517      * sync_from was failing, the local client wasn't being notified
 518      *    because it didn't know it was a reply
 519      * setting this does not prevent the other nodes from applying it
 520      *    if all == TRUE
 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 }

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