root/lib/pacemaker/pcmk_sched_transition.c

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

DEFINITIONS

This source file includes following definitions.
  1. inject_transient_attr
  2. update_failcounts
  3. create_node_entry
  4. create_op
  5. inject_op
  6. inject_node_state
  7. modify_node
  8. find_resource_xml
  9. inject_resource
  10. find_ticket_state
  11. set_ticket_state_attr
  12. modify_configuration
  13. exec_pseudo_action
  14. exec_rsc_action
  15. exec_crmd_action
  16. exec_stonith_action
  17. run_simulation

   1 /*
   2  * Copyright 2009-2021 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 
  16 #include <sys/stat.h>
  17 #include <sys/param.h>
  18 #include <sys/types.h>
  19 #include <dirent.h>
  20 
  21 #include <crm/crm.h>
  22 #include <crm/lrmd.h>           // lrmd_event_data_t, lrmd_free_event()
  23 #include <crm/cib.h>
  24 #include <crm/common/util.h>
  25 #include <crm/common/iso8601.h>
  26 #include <crm/common/xml_internal.h>
  27 #include <crm/pengine/status.h>
  28 #include <pacemaker-internal.h>
  29 
  30 static pcmk__output_t *out = NULL;
  31 static cib_t *fake_cib = NULL;
  32 static GList *fake_resource_list = NULL;
  33 static GList *fake_op_fail_list = NULL;
  34 gboolean bringing_nodes_online = FALSE;
  35 
  36 #define STATUS_PATH_MAX 512
  37 
  38 #define NEW_NODE_TEMPLATE "//"XML_CIB_TAG_NODE"[@uname='%s']"
  39 #define NODE_TEMPLATE "//"XML_CIB_TAG_STATE"[@uname='%s']"
  40 #define RSC_TEMPLATE "//"XML_CIB_TAG_STATE"[@uname='%s']//"XML_LRM_TAG_RESOURCE"[@id='%s']"
  41 
  42 
  43 static void
  44 inject_transient_attr(xmlNode * cib_node, const char *name, const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
  45 {
  46     xmlNode *attrs = NULL;
  47     xmlNode *instance_attrs = NULL;
  48     const char *node_uuid = ID(cib_node);
  49 
  50     out->message(out, "inject-attr", name, value, cib_node);
  51 
  52     attrs = first_named_child(cib_node, XML_TAG_TRANSIENT_NODEATTRS);
  53     if (attrs == NULL) {
  54         attrs = create_xml_node(cib_node, XML_TAG_TRANSIENT_NODEATTRS);
  55         crm_xml_add(attrs, XML_ATTR_ID, node_uuid);
  56     }
  57 
  58     instance_attrs = first_named_child(attrs, XML_TAG_ATTR_SETS);
  59     if (instance_attrs == NULL) {
  60         instance_attrs = create_xml_node(attrs, XML_TAG_ATTR_SETS);
  61         crm_xml_add(instance_attrs, XML_ATTR_ID, node_uuid);
  62     }
  63 
  64     crm_create_nvpair_xml(instance_attrs, NULL, name, value);
  65 }
  66 
  67 static void
  68 update_failcounts(xmlNode * cib_node, const char *resource, const char *task,
     /* [previous][next][first][last][top][bottom][index][help] */
  69                   guint interval_ms, int rc)
  70 {
  71     if (rc == 0) {
  72         return;
  73 
  74     } else if ((rc == 7) && (interval_ms == 0)) {
  75         return;
  76 
  77     } else {
  78         char *name = NULL;
  79         char *now = pcmk__ttoa(time(NULL));
  80 
  81         name = pcmk__failcount_name(resource, task, interval_ms);
  82         inject_transient_attr(cib_node, name, "value++");
  83         free(name);
  84 
  85         name = pcmk__lastfailure_name(resource, task, interval_ms);
  86         inject_transient_attr(cib_node, name, now);
  87         free(name);
  88         free(now);
  89     }
  90 }
  91 
  92 static void
  93 create_node_entry(cib_t * cib_conn, const char *node)
     /* [previous][next][first][last][top][bottom][index][help] */
  94 {
  95     int rc = pcmk_ok;
  96     char *xpath = crm_strdup_printf(NEW_NODE_TEMPLATE, node);
  97 
  98     rc = cib_conn->cmds->query(cib_conn, xpath, NULL, cib_xpath | cib_sync_call | cib_scope_local);
  99 
 100     if (rc == -ENXIO) {
 101         xmlNode *cib_object = create_xml_node(NULL, XML_CIB_TAG_NODE);
 102 
 103         crm_xml_add(cib_object, XML_ATTR_ID, node); // Use node name as ID
 104         crm_xml_add(cib_object, XML_ATTR_UNAME, node);
 105         cib_conn->cmds->create(cib_conn, XML_CIB_TAG_NODES, cib_object,
 106                                cib_sync_call | cib_scope_local);
 107         /* Not bothering with subsequent query to see if it exists,
 108            we'll bomb out later in the call to query_node_uuid()... */
 109 
 110         free_xml(cib_object);
 111     }
 112 
 113     free(xpath);
 114 }
 115 
 116 static lrmd_event_data_t *
 117 create_op(xmlNode *cib_resource, const char *task, guint interval_ms,
     /* [previous][next][first][last][top][bottom][index][help] */
 118           int outcome)
 119 {
 120     lrmd_event_data_t *op = NULL;
 121     xmlNode *xop = NULL;
 122 
 123     op = lrmd_new_event(ID(cib_resource), task, interval_ms);
 124     op->rc = outcome;
 125     op->op_status = 0;
 126     op->params = NULL;          /* TODO: Fill me in */
 127     op->t_run = (unsigned int) time(NULL);
 128     op->t_rcchange = op->t_run;
 129 
 130     op->call_id = 0;
 131     for (xop = pcmk__xe_first_child(cib_resource); xop != NULL;
 132          xop = pcmk__xe_next(xop)) {
 133 
 134         int tmp = 0;
 135 
 136         crm_element_value_int(xop, XML_LRM_ATTR_CALLID, &tmp);
 137         if (tmp > op->call_id) {
 138             op->call_id = tmp;
 139         }
 140     }
 141     op->call_id++;
 142 
 143     return op;
 144 }
 145 
 146 static xmlNode *
 147 inject_op(xmlNode * cib_resource, lrmd_event_data_t * op, int target_rc)
     /* [previous][next][first][last][top][bottom][index][help] */
 148 {
 149     return pcmk__create_history_xml(cib_resource, op, CRM_FEATURE_SET,
 150                                     target_rc, NULL, crm_system_name,
 151                                     LOG_TRACE);
 152 }
 153 
 154 static xmlNode *
 155 inject_node_state(cib_t * cib_conn, const char *node, const char *uuid)
     /* [previous][next][first][last][top][bottom][index][help] */
 156 {
 157     int rc = pcmk_ok;
 158     xmlNode *cib_object = NULL;
 159     char *xpath = crm_strdup_printf(NODE_TEMPLATE, node);
 160 
 161     if (bringing_nodes_online) {
 162         create_node_entry(cib_conn, node);
 163     }
 164 
 165     rc = cib_conn->cmds->query(cib_conn, xpath, &cib_object,
 166                                cib_xpath | cib_sync_call | cib_scope_local);
 167 
 168     if (cib_object && ID(cib_object) == NULL) {
 169         crm_err("Detected multiple node_state entries for xpath=%s, bailing", xpath);
 170         crm_log_xml_warn(cib_object, "Duplicates");
 171         free(xpath);
 172         crm_exit(CRM_EX_SOFTWARE);
 173         return NULL; // not reached, but makes static analysis happy
 174     }
 175 
 176     if (rc == -ENXIO) {
 177         char *found_uuid = NULL;
 178 
 179         if (uuid == NULL) {
 180             query_node_uuid(cib_conn, node, &found_uuid, NULL);
 181         } else {
 182             found_uuid = strdup(uuid);
 183         }
 184 
 185         cib_object = create_xml_node(NULL, XML_CIB_TAG_STATE);
 186         crm_xml_add(cib_object, XML_ATTR_UUID, found_uuid);
 187         crm_xml_add(cib_object, XML_ATTR_UNAME, node);
 188         cib_conn->cmds->create(cib_conn, XML_CIB_TAG_STATUS, cib_object,
 189                                cib_sync_call | cib_scope_local);
 190         free_xml(cib_object);
 191         free(found_uuid);
 192 
 193         rc = cib_conn->cmds->query(cib_conn, xpath, &cib_object,
 194                                    cib_xpath | cib_sync_call | cib_scope_local);
 195         crm_trace("injecting node state for %s. rc is %d", node, rc);
 196     }
 197 
 198     free(xpath);
 199     CRM_ASSERT(rc == pcmk_ok);
 200     return cib_object;
 201 }
 202 
 203 static xmlNode *
 204 modify_node(cib_t * cib_conn, char *node, gboolean up)
     /* [previous][next][first][last][top][bottom][index][help] */
 205 {
 206     xmlNode *cib_node = inject_node_state(cib_conn, node, NULL);
 207 
 208     if (up) {
 209         crm_xml_add(cib_node, XML_NODE_IN_CLUSTER, XML_BOOLEAN_YES);
 210         crm_xml_add(cib_node, XML_NODE_IS_PEER, ONLINESTATUS);
 211         crm_xml_add(cib_node, XML_NODE_JOIN_STATE, CRMD_JOINSTATE_MEMBER);
 212         crm_xml_add(cib_node, XML_NODE_EXPECTED, CRMD_JOINSTATE_MEMBER);
 213 
 214     } else {
 215         crm_xml_add(cib_node, XML_NODE_IN_CLUSTER, XML_BOOLEAN_NO);
 216         crm_xml_add(cib_node, XML_NODE_IS_PEER, OFFLINESTATUS);
 217         crm_xml_add(cib_node, XML_NODE_JOIN_STATE, CRMD_JOINSTATE_DOWN);
 218         crm_xml_add(cib_node, XML_NODE_EXPECTED, CRMD_JOINSTATE_DOWN);
 219     }
 220 
 221     crm_xml_add(cib_node, XML_ATTR_ORIGIN, crm_system_name);
 222     return cib_node;
 223 }
 224 
 225 static xmlNode *
 226 find_resource_xml(xmlNode * cib_node, const char *resource)
     /* [previous][next][first][last][top][bottom][index][help] */
 227 {
 228     xmlNode *match = NULL;
 229     const char *node = crm_element_value(cib_node, XML_ATTR_UNAME);
 230     char *xpath = crm_strdup_printf(RSC_TEMPLATE, node, resource);
 231 
 232     match = get_xpath_object(xpath, cib_node, LOG_TRACE);
 233     free(xpath);
 234     return match;
 235 }
 236 
 237 
 238 static xmlNode *
 239 inject_resource(xmlNode * cib_node, const char *resource, const char *lrm_name,
     /* [previous][next][first][last][top][bottom][index][help] */
 240                 const char *rclass, const char *rtype, const char *rprovider)
 241 {
 242     xmlNode *lrm = NULL;
 243     xmlNode *container = NULL;
 244     xmlNode *cib_resource = NULL;
 245     char *xpath = NULL;
 246 
 247     cib_resource = find_resource_xml(cib_node, resource);
 248     if (cib_resource != NULL) {
 249         /* If an existing LRM history entry uses the resource name,
 250          * continue using it, even if lrm_name is different.
 251          */
 252         return cib_resource;
 253     }
 254 
 255     // Check for history entry under preferred name
 256     if (strcmp(resource, lrm_name)) {
 257         cib_resource = find_resource_xml(cib_node, lrm_name);
 258         if (cib_resource != NULL) {
 259             return cib_resource;
 260         }
 261     }
 262 
 263     /* One day, add query for class, provider, type */
 264 
 265     if (rclass == NULL || rtype == NULL) {
 266         out->err(out, "Resource %s not found in the status section of %s."
 267                  "  Please supply the class and type to continue", resource, ID(cib_node));
 268         return NULL;
 269 
 270     } else if (!pcmk__strcase_any_of(rclass, PCMK_RESOURCE_CLASS_OCF, PCMK_RESOURCE_CLASS_STONITH,
 271                                      PCMK_RESOURCE_CLASS_SERVICE, PCMK_RESOURCE_CLASS_UPSTART,
 272                                      PCMK_RESOURCE_CLASS_SYSTEMD, PCMK_RESOURCE_CLASS_LSB, NULL)) {
 273         out->err(out, "Invalid class for %s: %s", resource, rclass);
 274         return NULL;
 275 
 276     } else if (pcmk_is_set(pcmk_get_ra_caps(rclass), pcmk_ra_cap_provider)
 277                 && (rprovider == NULL)) {
 278         out->err(out, "Please specify the provider for resource %s", resource);
 279         return NULL;
 280     }
 281 
 282     xpath = (char *)xmlGetNodePath(cib_node);
 283     crm_info("Injecting new resource %s into %s '%s'", lrm_name, xpath, ID(cib_node));
 284     free(xpath);
 285 
 286     lrm = first_named_child(cib_node, XML_CIB_TAG_LRM);
 287     if (lrm == NULL) {
 288         const char *node_uuid = ID(cib_node);
 289 
 290         lrm = create_xml_node(cib_node, XML_CIB_TAG_LRM);
 291         crm_xml_add(lrm, XML_ATTR_ID, node_uuid);
 292     }
 293 
 294     container = first_named_child(lrm, XML_LRM_TAG_RESOURCES);
 295     if (container == NULL) {
 296         container = create_xml_node(lrm, XML_LRM_TAG_RESOURCES);
 297     }
 298 
 299     cib_resource = create_xml_node(container, XML_LRM_TAG_RESOURCE);
 300 
 301     // If we're creating a new entry, use the preferred name
 302     crm_xml_add(cib_resource, XML_ATTR_ID, lrm_name);
 303 
 304     crm_xml_add(cib_resource, XML_AGENT_ATTR_CLASS, rclass);
 305     crm_xml_add(cib_resource, XML_AGENT_ATTR_PROVIDER, rprovider);
 306     crm_xml_add(cib_resource, XML_ATTR_TYPE, rtype);
 307 
 308     return cib_resource;
 309 }
 310 
 311 #define XPATH_MAX 1024
 312 
 313 static int
 314 find_ticket_state(cib_t * the_cib, const char *ticket_id, xmlNode ** ticket_state_xml)
     /* [previous][next][first][last][top][bottom][index][help] */
 315 {
 316     int offset = 0;
 317     int rc = pcmk_ok;
 318     xmlNode *xml_search = NULL;
 319 
 320     char *xpath_string = NULL;
 321 
 322     CRM_ASSERT(ticket_state_xml != NULL);
 323     *ticket_state_xml = NULL;
 324 
 325     xpath_string = calloc(1, XPATH_MAX);
 326     offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "%s", "/cib/status/tickets");
 327 
 328     if (ticket_id) {
 329         offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "/%s[@id=\"%s\"]",
 330                            XML_CIB_TAG_TICKET_STATE, ticket_id);
 331     }
 332     CRM_LOG_ASSERT(offset > 0);
 333     rc = the_cib->cmds->query(the_cib, xpath_string, &xml_search,
 334                               cib_sync_call | cib_scope_local | cib_xpath);
 335 
 336     if (rc != pcmk_ok) {
 337         goto bail;
 338     }
 339 
 340     crm_log_xml_debug(xml_search, "Match");
 341     if (xml_has_children(xml_search)) {
 342         if (ticket_id) {
 343             out->err(out, "Multiple ticket_states match ticket_id=%s", ticket_id);
 344         }
 345         *ticket_state_xml = xml_search;
 346     } else {
 347         *ticket_state_xml = xml_search;
 348     }
 349 
 350   bail:
 351     free(xpath_string);
 352     return rc;
 353 }
 354 
 355 static int
 356 set_ticket_state_attr(const char *ticket_id, const char *attr_name,
     /* [previous][next][first][last][top][bottom][index][help] */
 357                       const char *attr_value, cib_t * cib, int cib_options)
 358 {
 359     int rc = pcmk_ok;
 360     xmlNode *xml_top = NULL;
 361     xmlNode *ticket_state_xml = NULL;
 362 
 363     rc = find_ticket_state(cib, ticket_id, &ticket_state_xml);
 364     if (rc == pcmk_ok) {
 365         crm_debug("Found a match state for ticket: id=%s", ticket_id);
 366         xml_top = ticket_state_xml;
 367 
 368     } else if (rc != -ENXIO) {
 369         return rc;
 370 
 371     } else {
 372         xmlNode *xml_obj = NULL;
 373 
 374         xml_top = create_xml_node(NULL, XML_CIB_TAG_STATUS);
 375         xml_obj = create_xml_node(xml_top, XML_CIB_TAG_TICKETS);
 376         ticket_state_xml = create_xml_node(xml_obj, XML_CIB_TAG_TICKET_STATE);
 377         crm_xml_add(ticket_state_xml, XML_ATTR_ID, ticket_id);
 378     }
 379 
 380     crm_xml_add(ticket_state_xml, attr_name, attr_value);
 381 
 382     crm_log_xml_debug(xml_top, "Update");
 383 
 384     rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, xml_top, cib_options);
 385 
 386     free_xml(xml_top);
 387 
 388     return rc;
 389 }
 390 
 391 void
 392 modify_configuration(pe_working_set_t * data_set, cib_t *cib,
     /* [previous][next][first][last][top][bottom][index][help] */
 393                      const char *quorum, const char *watchdog, GList *node_up, GList *node_down, GList *node_fail,
 394                      GList *op_inject, GList *ticket_grant, GList *ticket_revoke,
 395                      GList *ticket_standby, GList *ticket_activate)
 396 {
 397     int rc = pcmk_ok;
 398     GList *gIter = NULL;
 399 
 400     xmlNode *cib_op = NULL;
 401     xmlNode *cib_node = NULL;
 402     xmlNode *cib_resource = NULL;
 403 
 404     lrmd_event_data_t *op = NULL;
 405 
 406     out = data_set->priv;
 407 
 408     out->message(out, "inject-modify-config", quorum, watchdog);
 409 
 410     if (quorum) {
 411         xmlNode *top = create_xml_node(NULL, XML_TAG_CIB);
 412 
 413         /* crm_xml_add(top, XML_ATTR_DC_UUID, dc_uuid);      */
 414         crm_xml_add(top, XML_ATTR_HAVE_QUORUM, quorum);
 415 
 416         rc = cib->cmds->modify(cib, NULL, top, cib_sync_call | cib_scope_local);
 417         CRM_ASSERT(rc == pcmk_ok);
 418     }
 419 
 420     if (watchdog) {
 421         rc = update_attr_delegate(cib, cib_sync_call | cib_scope_local,
 422                              XML_CIB_TAG_CRMCONFIG, NULL, NULL, NULL, NULL,
 423                              XML_ATTR_HAVE_WATCHDOG, watchdog, FALSE, NULL, NULL);
 424 
 425         CRM_ASSERT(rc == pcmk_ok);
 426     }
 427 
 428     for (gIter = node_up; gIter != NULL; gIter = gIter->next) {
 429         char *node = (char *)gIter->data;
 430 
 431         out->message(out, "inject-modify-node", "Online", node);
 432 
 433         cib_node = modify_node(cib, node, TRUE);
 434         CRM_ASSERT(cib_node != NULL);
 435 
 436         rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node,
 437                                       cib_sync_call | cib_scope_local);
 438         CRM_ASSERT(rc == pcmk_ok);
 439         free_xml(cib_node);
 440     }
 441 
 442     for (gIter = node_down; gIter != NULL; gIter = gIter->next) {
 443         char xpath[STATUS_PATH_MAX];
 444         char *node = (char *)gIter->data;
 445 
 446         out->message(out, "inject-modify-node", "Offline", node);
 447 
 448         cib_node = modify_node(cib, node, FALSE);
 449         CRM_ASSERT(cib_node != NULL);
 450 
 451         rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node,
 452                                       cib_sync_call | cib_scope_local);
 453         CRM_ASSERT(rc == pcmk_ok);
 454         free_xml(cib_node);
 455 
 456         snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", node, XML_CIB_TAG_LRM);
 457         cib->cmds->remove(cib, xpath, NULL,
 458                                       cib_xpath | cib_sync_call | cib_scope_local);
 459 
 460         snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", node,
 461                  XML_TAG_TRANSIENT_NODEATTRS);
 462         cib->cmds->remove(cib, xpath, NULL,
 463                                       cib_xpath | cib_sync_call | cib_scope_local);
 464 
 465     }
 466 
 467     for (gIter = node_fail; gIter != NULL; gIter = gIter->next) {
 468         char *node = (char *)gIter->data;
 469 
 470         out->message(out, "inject-modify-node", "Failing", node);
 471 
 472         cib_node = modify_node(cib, node, TRUE);
 473         crm_xml_add(cib_node, XML_NODE_IN_CLUSTER, XML_BOOLEAN_NO);
 474         CRM_ASSERT(cib_node != NULL);
 475 
 476         rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node,
 477                                       cib_sync_call | cib_scope_local);
 478         CRM_ASSERT(rc == pcmk_ok);
 479         free_xml(cib_node);
 480     }
 481 
 482     for (gIter = ticket_grant; gIter != NULL; gIter = gIter->next) {
 483         char *ticket_id = (char *)gIter->data;
 484 
 485         out->message(out, "inject-modify-ticket", "Granting", ticket_id);
 486 
 487         rc = set_ticket_state_attr(ticket_id, "granted", "true",
 488                                    cib, cib_sync_call | cib_scope_local);
 489 
 490         CRM_ASSERT(rc == pcmk_ok);
 491     }
 492 
 493     for (gIter = ticket_revoke; gIter != NULL; gIter = gIter->next) {
 494         char *ticket_id = (char *)gIter->data;
 495 
 496         out->message(out, "inject-modify-ticket", "Revoking", ticket_id);
 497 
 498         rc = set_ticket_state_attr(ticket_id, "granted", "false",
 499                                    cib, cib_sync_call | cib_scope_local);
 500 
 501         CRM_ASSERT(rc == pcmk_ok);
 502     }
 503 
 504     for (gIter = ticket_standby; gIter != NULL; gIter = gIter->next) {
 505         char *ticket_id = (char *)gIter->data;
 506 
 507         out->message(out, "inject-modify-ticket", "Standby", ticket_id);
 508 
 509         rc = set_ticket_state_attr(ticket_id, "standby", "true",
 510                                    cib, cib_sync_call | cib_scope_local);
 511 
 512         CRM_ASSERT(rc == pcmk_ok);
 513     }
 514 
 515     for (gIter = ticket_activate; gIter != NULL; gIter = gIter->next) {
 516         char *ticket_id = (char *)gIter->data;
 517 
 518         out->message(out, "inject-modify-ticket", "Activating", ticket_id);
 519 
 520         rc = set_ticket_state_attr(ticket_id, "standby", "false",
 521                                    cib, cib_sync_call | cib_scope_local);
 522 
 523         CRM_ASSERT(rc == pcmk_ok);
 524     }
 525 
 526     for (gIter = op_inject; gIter != NULL; gIter = gIter->next) {
 527         char *spec = (char *)gIter->data;
 528 
 529         int rc = 0;
 530         int outcome = 0;
 531         guint interval_ms = 0;
 532 
 533         char *key = NULL;
 534         char *node = NULL;
 535         char *task = NULL;
 536         char *resource = NULL;
 537 
 538         const char *rtype = NULL;
 539         const char *rclass = NULL;
 540         const char *rprovider = NULL;
 541 
 542         pe_resource_t *rsc = NULL;
 543 
 544         out->message(out, "inject-spec", spec);
 545 
 546         key = calloc(1, strlen(spec) + 1);
 547         node = calloc(1, strlen(spec) + 1);
 548         rc = sscanf(spec, "%[^@]@%[^=]=%d", key, node, &outcome);
 549         if (rc != 3) {
 550             out->err(out, "Invalid operation spec: %s.  Only found %d fields", spec, rc);
 551             free(key);
 552             free(node);
 553             continue;
 554         }
 555 
 556         parse_op_key(key, &resource, &task, &interval_ms);
 557 
 558         rsc = pe_find_resource(data_set->resources, resource);
 559         if (rsc == NULL) {
 560             out->err(out, "Invalid resource name: %s", resource);
 561         } else {
 562             rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
 563             rtype = crm_element_value(rsc->xml, XML_ATTR_TYPE);
 564             rprovider = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
 565 
 566             cib_node = inject_node_state(cib, node, NULL);
 567             CRM_ASSERT(cib_node != NULL);
 568 
 569             update_failcounts(cib_node, resource, task, interval_ms, outcome);
 570 
 571             cib_resource = inject_resource(cib_node, resource, resource,
 572                                            rclass, rtype, rprovider);
 573             CRM_ASSERT(cib_resource != NULL);
 574 
 575             op = create_op(cib_resource, task, interval_ms, outcome);
 576             CRM_ASSERT(op != NULL);
 577 
 578             cib_op = inject_op(cib_resource, op, 0);
 579             CRM_ASSERT(cib_op != NULL);
 580             lrmd_free_event(op);
 581 
 582             rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node,
 583                                           cib_sync_call | cib_scope_local);
 584             CRM_ASSERT(rc == pcmk_ok);
 585         }
 586         free(task);
 587         free(node);
 588         free(key);
 589     }
 590 
 591     if (!out->is_quiet(out)) {
 592         out->end_list(out);
 593     }
 594 }
 595 
 596 static gboolean
 597 exec_pseudo_action(crm_graph_t * graph, crm_action_t * action)
     /* [previous][next][first][last][top][bottom][index][help] */
 598 {
 599     const char *node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
 600     const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY);
 601 
 602     action->confirmed = TRUE;
 603     out->message(out, "inject-pseudo-action", node, task);
 604 
 605     update_graph(graph, action);
 606     return TRUE;
 607 }
 608 
 609 static gboolean
 610 exec_rsc_action(crm_graph_t * graph, crm_action_t * action)
     /* [previous][next][first][last][top][bottom][index][help] */
 611 {
 612     int rc = 0;
 613     GList *gIter = NULL;
 614     lrmd_event_data_t *op = NULL;
 615     int target_outcome = 0;
 616 
 617     const char *rtype = NULL;
 618     const char *rclass = NULL;
 619     const char *resource = NULL;
 620     const char *rprovider = NULL;
 621     const char *lrm_name = NULL;
 622     const char *operation = crm_element_value(action->xml, "operation");
 623     const char *target_rc_s = crm_meta_value(action->params, XML_ATTR_TE_TARGET_RC);
 624 
 625     xmlNode *cib_node = NULL;
 626     xmlNode *cib_resource = NULL;
 627     xmlNode *action_rsc = first_named_child(action->xml, XML_CIB_TAG_RESOURCE);
 628 
 629     char *node = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET);
 630     char *uuid = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET_UUID);
 631     const char *router_node = crm_element_value(action->xml, XML_LRM_ATTR_ROUTER_NODE);
 632 
 633     if (pcmk__strcase_any_of(operation, CRM_OP_PROBED, CRM_OP_REPROBE, NULL)) {
 634         crm_info("Skipping %s op for %s", operation, node);
 635         goto done;
 636     }
 637 
 638     if (action_rsc == NULL) {
 639         crm_log_xml_err(action->xml, "Bad");
 640         free(node); free(uuid);
 641         return FALSE;
 642     }
 643 
 644     /* Look for the preferred name
 645      * If not found, try the expected 'local' name
 646      * If not found use the preferred name anyway
 647      */
 648     resource = crm_element_value(action_rsc, XML_ATTR_ID);
 649     CRM_ASSERT(resource != NULL); // makes static analysis happy
 650     lrm_name = resource; // Preferred name when writing history
 651     if (pe_find_resource(fake_resource_list, resource) == NULL) {
 652         const char *longname = crm_element_value(action_rsc, XML_ATTR_ID_LONG);
 653 
 654         if (longname && pe_find_resource(fake_resource_list, longname)) {
 655             resource = longname;
 656         }
 657     }
 658 
 659     if (pcmk__strcase_any_of(operation, "delete", RSC_METADATA, NULL)) {
 660         out->message(out, "inject-rsc-action", resource, operation, node, (guint) 0);
 661         goto done;
 662     }
 663 
 664     rclass = crm_element_value(action_rsc, XML_AGENT_ATTR_CLASS);
 665     rtype = crm_element_value(action_rsc, XML_ATTR_TYPE);
 666     rprovider = crm_element_value(action_rsc, XML_AGENT_ATTR_PROVIDER);
 667 
 668     pcmk__scan_min_int(target_rc_s, &target_outcome, 0);
 669 
 670     CRM_ASSERT(fake_cib->cmds->query(fake_cib, NULL, NULL, cib_sync_call | cib_scope_local) ==
 671                pcmk_ok);
 672 
 673     cib_node = inject_node_state(fake_cib, node, (router_node? node : uuid));
 674     CRM_ASSERT(cib_node != NULL);
 675 
 676     cib_resource = inject_resource(cib_node, resource, lrm_name,
 677                                    rclass, rtype, rprovider);
 678     if (cib_resource == NULL) {
 679         crm_err("invalid resource in transition");
 680         free(node); free(uuid);
 681         free_xml(cib_node);
 682         return FALSE;
 683     }
 684 
 685     op = convert_graph_action(cib_resource, action, 0, target_outcome);
 686 
 687     out->message(out, "inject-rsc-action", resource, op->op_type, node, op->interval_ms);
 688 
 689     for (gIter = fake_op_fail_list; gIter != NULL; gIter = gIter->next) {
 690         char *spec = (char *)gIter->data;
 691         char *key = NULL;
 692         const char *match_name = NULL;
 693 
 694         // Allow user to specify anonymous clone with or without instance number
 695         key = crm_strdup_printf(PCMK__OP_FMT "@%s=", resource, op->op_type,
 696                                 op->interval_ms, node);
 697         if (strncasecmp(key, spec, strlen(key)) == 0) {
 698             match_name = resource;
 699         }
 700         free(key);
 701 
 702         if ((match_name == NULL) && strcmp(resource, lrm_name)) {
 703             key = crm_strdup_printf(PCMK__OP_FMT "@%s=", lrm_name, op->op_type,
 704                                     op->interval_ms, node);
 705             if (strncasecmp(key, spec, strlen(key)) == 0) {
 706                 match_name = lrm_name;
 707             }
 708             free(key);
 709         }
 710 
 711         if (match_name != NULL) {
 712 
 713             rc = sscanf(spec, "%*[^=]=%d", (int *) &op->rc);
 714             // ${match_name}_${task}_${interval_in_ms}@${node}=${rc}
 715 
 716             if (rc != 1) {
 717                 out->err(out,
 718                          "Invalid failed operation spec: %s. Result code must be integer",
 719                          spec);
 720                 continue;
 721             }
 722             action->failed = TRUE;
 723             graph->abort_priority = INFINITY;
 724             out->info(out, "Pretending action %d failed with rc=%d", action->id, op->rc);
 725             update_failcounts(cib_node, match_name, op->op_type,
 726                               op->interval_ms, op->rc);
 727             break;
 728         }
 729     }
 730 
 731     inject_op(cib_resource, op, target_outcome);
 732     lrmd_free_event(op);
 733 
 734     rc = fake_cib->cmds->modify(fake_cib, XML_CIB_TAG_STATUS, cib_node,
 735                                   cib_sync_call | cib_scope_local);
 736     CRM_ASSERT(rc == pcmk_ok);
 737 
 738   done:
 739     free(node); free(uuid);
 740     free_xml(cib_node);
 741     action->confirmed = TRUE;
 742     update_graph(graph, action);
 743     return TRUE;
 744 }
 745 
 746 static gboolean
 747 exec_crmd_action(crm_graph_t * graph, crm_action_t * action)
     /* [previous][next][first][last][top][bottom][index][help] */
 748 {
 749     const char *node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
 750     const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
 751     xmlNode *rsc = first_named_child(action->xml, XML_CIB_TAG_RESOURCE);
 752 
 753     action->confirmed = TRUE;
 754     out->message(out, "inject-cluster-action", node, task, rsc);
 755     update_graph(graph, action);
 756     return TRUE;
 757 }
 758 
 759 static gboolean
 760 exec_stonith_action(crm_graph_t * graph, crm_action_t * action)
     /* [previous][next][first][last][top][bottom][index][help] */
 761 {
 762     const char *op = crm_meta_value(action->params, "stonith_action");
 763     char *target = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET);
 764 
 765     out->message(out, "inject-fencing-action", target, op);
 766 
 767     if(!pcmk__str_eq(op, "on", pcmk__str_casei)) {
 768         int rc = 0;
 769         char xpath[STATUS_PATH_MAX];
 770         xmlNode *cib_node = modify_node(fake_cib, target, FALSE);
 771 
 772         crm_xml_add(cib_node, XML_ATTR_ORIGIN, __func__);
 773         CRM_ASSERT(cib_node != NULL);
 774 
 775         rc = fake_cib->cmds->replace(fake_cib, XML_CIB_TAG_STATUS, cib_node,
 776                                    cib_sync_call | cib_scope_local);
 777         CRM_ASSERT(rc == pcmk_ok);
 778 
 779         snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", target, XML_CIB_TAG_LRM);
 780         fake_cib->cmds->remove(fake_cib, xpath, NULL,
 781                                       cib_xpath | cib_sync_call | cib_scope_local);
 782 
 783         snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", target,
 784                  XML_TAG_TRANSIENT_NODEATTRS);
 785         fake_cib->cmds->remove(fake_cib, xpath, NULL,
 786                                       cib_xpath | cib_sync_call | cib_scope_local);
 787 
 788         free_xml(cib_node);
 789     }
 790 
 791     action->confirmed = TRUE;
 792     update_graph(graph, action);
 793     free(target);
 794     return TRUE;
 795 }
 796 
 797 int
 798 run_simulation(pe_working_set_t * data_set, cib_t *cib, GList *op_fail_list)
     /* [previous][next][first][last][top][bottom][index][help] */
 799 {
 800     crm_graph_t *transition = NULL;
 801     enum transition_status graph_rc = -1;
 802 
 803     crm_graph_functions_t exec_fns = {
 804         exec_pseudo_action,
 805         exec_rsc_action,
 806         exec_crmd_action,
 807         exec_stonith_action,
 808     };
 809 
 810     out = data_set->priv;
 811 
 812     fake_cib = cib;
 813     fake_op_fail_list = op_fail_list;
 814 
 815     if (!out->is_quiet(out)) {
 816         out->begin_list(out, NULL, NULL, "Executing Cluster Transition");
 817     }
 818 
 819     set_graph_functions(&exec_fns);
 820     transition = unpack_graph(data_set->graph, crm_system_name);
 821     print_graph(LOG_DEBUG, transition);
 822 
 823     fake_resource_list = data_set->resources;
 824     do {
 825         graph_rc = run_graph(transition);
 826 
 827     } while (graph_rc == transition_active);
 828     fake_resource_list = NULL;
 829 
 830     if (graph_rc != transition_complete) {
 831         out->err(out, "Transition failed: %s", transition_status(graph_rc));
 832         print_graph(LOG_ERR, transition);
 833     }
 834     destroy_graph(transition);
 835     if (graph_rc != transition_complete) {
 836         out->err(out, "An invalid transition was produced");
 837     }
 838 
 839     if (!out->is_quiet(out)) {
 840         xmlNode *cib_object = NULL;
 841         int rc = fake_cib->cmds->query(fake_cib, NULL, &cib_object, cib_sync_call | cib_scope_local);
 842 
 843         CRM_ASSERT(rc == pcmk_ok);
 844         pe_reset_working_set(data_set);
 845         data_set->input = cib_object;
 846 
 847         out->end_list(out);
 848     }
 849 
 850     if (graph_rc != transition_complete) {
 851         return graph_rc;
 852     }
 853     return 0;
 854 }

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