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

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