root/lib/pacemaker/pcmk_injections.c

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

DEFINITIONS

This source file includes following definitions.
  1. inject_transient_attr
  2. pcmk__inject_failcount
  3. create_node_entry
  4. create_op
  5. pcmk__inject_action_result
  6. pcmk__inject_node
  7. pcmk__inject_node_state_change
  8. find_resource_xml
  9. pcmk__inject_resource_history
  10. find_ticket_state
  11. set_ticket_state_attr
  12. inject_action
  13. pcmk__inject_scheduler_input
  14. pcmk_free_injections

   1 /*
   2  * Copyright 2009-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 
  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/cib/internal.h>
  25 #include <crm/common/util.h>
  26 #include <crm/common/iso8601.h>
  27 #include <crm/common/xml_internal.h>
  28 #include <crm/lrmd_internal.h>
  29 #include <crm/pengine/status.h>
  30 #include <pacemaker-internal.h>
  31 
  32 #include "libpacemaker_private.h"
  33 
  34 bool pcmk__simulate_node_config = false;
  35 
  36 #define XPATH_NODE_CONFIG   "//" XML_CIB_TAG_NODE "[@" XML_ATTR_UNAME "='%s']"
  37 #define XPATH_NODE_STATE    "//" XML_CIB_TAG_STATE "[@" XML_ATTR_UNAME "='%s']"
  38 #define XPATH_RSC_HISTORY   XPATH_NODE_STATE \
  39                             "//" XML_LRM_TAG_RESOURCE "[@" XML_ATTR_ID "='%s']"
  40 
  41 
  42 /*!
  43  * \internal
  44  * \brief Inject a fictitious transient node attribute into scheduler input
  45  *
  46  * \param[in,out] out       Output object for displaying error messages
  47  * \param[in,out] cib_node  node_state XML to inject attribute into
  48  * \param[in]     name      Transient node attribute name to inject
  49  * \param[in]     value     Transient node attribute value to inject
  50  */
  51 static void
  52 inject_transient_attr(pcmk__output_t *out, xmlNode *cib_node,
     /* [previous][next][first][last][top][bottom][index][help] */
  53                       const char *name, const char *value)
  54 {
  55     xmlNode *attrs = NULL;
  56     xmlNode *instance_attrs = NULL;
  57     const char *node_uuid = ID(cib_node);
  58 
  59     out->message(out, "inject-attr", name, value, cib_node);
  60 
  61     attrs = first_named_child(cib_node, XML_TAG_TRANSIENT_NODEATTRS);
  62     if (attrs == NULL) {
  63         attrs = create_xml_node(cib_node, XML_TAG_TRANSIENT_NODEATTRS);
  64         crm_xml_add(attrs, XML_ATTR_ID, node_uuid);
  65     }
  66 
  67     instance_attrs = first_named_child(attrs, XML_TAG_ATTR_SETS);
  68     if (instance_attrs == NULL) {
  69         instance_attrs = create_xml_node(attrs, XML_TAG_ATTR_SETS);
  70         crm_xml_add(instance_attrs, XML_ATTR_ID, node_uuid);
  71     }
  72 
  73     crm_create_nvpair_xml(instance_attrs, NULL, name, value);
  74 }
  75 
  76 /*!
  77  * \internal
  78  * \brief Inject a fictitious fail count into a scheduler input
  79  *
  80  * \param[in,out] out          Output object for displaying error messages
  81  * \param[in,out] cib_node     Node state XML to inject into
  82  * \param[in]     resource     ID of resource for fail count to inject
  83  * \param[in]     task         Action name for fail count to inject
  84  * \param[in]     interval_ms  Action interval (in milliseconds) for fail count
  85  * \param[in]     rc           Action result for fail count to inject (if 0, or
  86  *                             7 when interval_ms is 0, inject nothing)
  87  */
  88 void
  89 pcmk__inject_failcount(pcmk__output_t *out, xmlNode *cib_node,
     /* [previous][next][first][last][top][bottom][index][help] */
  90                        const char *resource, const char *task,
  91                        guint interval_ms, int rc)
  92 {
  93     if (rc == 0) {
  94         return;
  95 
  96     } else if ((rc == 7) && (interval_ms == 0)) {
  97         return;
  98 
  99     } else {
 100         char *name = NULL;
 101         char *now = pcmk__ttoa(time(NULL));
 102 
 103         name = pcmk__failcount_name(resource, task, interval_ms);
 104         inject_transient_attr(out, cib_node, name, "value++");
 105         free(name);
 106 
 107         name = pcmk__lastfailure_name(resource, task, interval_ms);
 108         inject_transient_attr(out, cib_node, name, now);
 109         free(name);
 110 
 111         free(now);
 112     }
 113 }
 114 
 115 /*!
 116  * \internal
 117  * \brief Create a CIB configuration entry for a fictitious node
 118  *
 119  * \param[in,out] cib_conn  CIB object to use
 120  * \param[in]     node      Node name to use
 121  */
 122 static void
 123 create_node_entry(cib_t *cib_conn, const char *node)
     /* [previous][next][first][last][top][bottom][index][help] */
 124 {
 125     int rc = pcmk_ok;
 126     char *xpath = crm_strdup_printf(XPATH_NODE_CONFIG, node);
 127 
 128     rc = cib_conn->cmds->query(cib_conn, xpath, NULL,
 129                                cib_xpath|cib_sync_call|cib_scope_local);
 130 
 131     if (rc == -ENXIO) { // Only add if not already existing
 132         xmlNode *cib_object = create_xml_node(NULL, XML_CIB_TAG_NODE);
 133 
 134         crm_xml_add(cib_object, XML_ATTR_ID, node); // Use node name as ID
 135         crm_xml_add(cib_object, XML_ATTR_UNAME, node);
 136         cib_conn->cmds->create(cib_conn, XML_CIB_TAG_NODES, cib_object,
 137                                cib_sync_call|cib_scope_local);
 138         /* Not bothering with subsequent query to see if it exists,
 139            we'll bomb out later in the call to query_node_uuid()... */
 140 
 141         free_xml(cib_object);
 142     }
 143 
 144     free(xpath);
 145 }
 146 
 147 /*!
 148  * \internal
 149  * \brief Synthesize a fake executor event for an action
 150  *
 151  * \param[in] cib_resource  XML for any existing resource action history
 152  * \param[in] task          Name of action to synthesize
 153  * \param[in] interval_ms   Interval of action to synthesize
 154  * \param[in] outcome       Result of action to synthesize
 155  *
 156  * \return Newly allocated executor event
 157  * \note It is the caller's responsibility to free the result with
 158  *       lrmd_free_event().
 159  */
 160 static lrmd_event_data_t *
 161 create_op(const xmlNode *cib_resource, const char *task, guint interval_ms,
     /* [previous][next][first][last][top][bottom][index][help] */
 162           int outcome)
 163 {
 164     lrmd_event_data_t *op = NULL;
 165     xmlNode *xop = NULL;
 166 
 167     op = lrmd_new_event(ID(cib_resource), task, interval_ms);
 168     lrmd__set_result(op, outcome, PCMK_EXEC_DONE, "Simulated action result");
 169     op->params = NULL; // Not needed for simulation purposes
 170     op->t_run = (unsigned int) time(NULL);
 171     op->t_rcchange = op->t_run;
 172 
 173     // Use a call ID higher than any existing history entries
 174     op->call_id = 0;
 175     for (xop = pcmk__xe_first_child(cib_resource); xop != NULL;
 176          xop = pcmk__xe_next(xop)) {
 177 
 178         int tmp = 0;
 179 
 180         crm_element_value_int(xop, XML_LRM_ATTR_CALLID, &tmp);
 181         if (tmp > op->call_id) {
 182             op->call_id = tmp;
 183         }
 184     }
 185     op->call_id++;
 186 
 187     return op;
 188 }
 189 
 190 /*!
 191  * \internal
 192  * \brief Inject a fictitious resource history entry into a scheduler input
 193  *
 194  * \param[in,out] cib_resource  Resource history XML to inject entry into
 195  * \param[in,out] op            Action result to inject
 196  * \param[in]     target_rc     Expected result for action to inject
 197  *
 198  * \return XML of injected resource history entry
 199  */
 200 xmlNode *
 201 pcmk__inject_action_result(xmlNode *cib_resource, lrmd_event_data_t *op,
     /* [previous][next][first][last][top][bottom][index][help] */
 202                            int target_rc)
 203 {
 204     return pcmk__create_history_xml(cib_resource, op, CRM_FEATURE_SET,
 205                                     target_rc, NULL, crm_system_name);
 206 }
 207 
 208 /*!
 209  * \internal
 210  * \brief Inject a fictitious node into a scheduler input
 211  *
 212  * \param[in,out] cib_conn  Scheduler input CIB to inject node into
 213  * \param[in]     node      Name of node to inject
 214  * \param[in]     uuid      UUID of node to inject
 215  *
 216  * \return XML of node_state entry for new node
 217  * \note If the global pcmk__simulate_node_config has been set to true, a
 218  *       node entry in the configuration section will be added, as well as a
 219  *       node state entry in the status section.
 220  */
 221 xmlNode *
 222 pcmk__inject_node(cib_t *cib_conn, const char *node, const char *uuid)
     /* [previous][next][first][last][top][bottom][index][help] */
 223 {
 224     int rc = pcmk_ok;
 225     xmlNode *cib_object = NULL;
 226     char *xpath = crm_strdup_printf(XPATH_NODE_STATE, node);
 227     bool duplicate = false;
 228     char *found_uuid = NULL;
 229 
 230     if (pcmk__simulate_node_config) {
 231         create_node_entry(cib_conn, node);
 232     }
 233 
 234     rc = cib_conn->cmds->query(cib_conn, xpath, &cib_object,
 235                                cib_xpath|cib_sync_call|cib_scope_local);
 236 
 237     if ((cib_object != NULL) && (ID(cib_object) == NULL)) {
 238         crm_err("Detected multiple node_state entries for xpath=%s, bailing",
 239                 xpath);
 240         duplicate = true;
 241         goto done;
 242     }
 243 
 244     if (rc == -ENXIO) {
 245         if (uuid == NULL) {
 246             query_node_uuid(cib_conn, node, &found_uuid, NULL);
 247         } else {
 248             found_uuid = strdup(uuid);
 249         }
 250 
 251         if (found_uuid) {
 252             char *xpath_by_uuid = crm_strdup_printf("//" XML_CIB_TAG_STATE "[@" XML_ATTR_ID "='%s']",
 253                                                     found_uuid);
 254 
 255             // It's possible that a node_state entry doesn't have an uname yet.
 256             rc = cib_conn->cmds->query(cib_conn, xpath_by_uuid, &cib_object,
 257                                        cib_xpath|cib_sync_call|cib_scope_local);
 258 
 259             if ((cib_object != NULL) && (ID(cib_object) == NULL)) {
 260                 crm_err("Detected multiple node_state entries for xpath=%s, bailing",
 261                         xpath_by_uuid);
 262                 duplicate = true;
 263                 free(xpath_by_uuid);
 264                 goto done;
 265 
 266             } else if (cib_object != NULL) {
 267                 crm_xml_add(cib_object, XML_ATTR_UNAME, node);
 268 
 269                 rc = cib_conn->cmds->modify(cib_conn, XML_CIB_TAG_STATUS, cib_object,
 270                                             cib_sync_call|cib_scope_local);
 271             }
 272 
 273             free(xpath_by_uuid);
 274         }
 275     }
 276 
 277     if (rc == -ENXIO) {
 278         cib_object = create_xml_node(NULL, XML_CIB_TAG_STATE);
 279         crm_xml_add(cib_object, XML_ATTR_ID, found_uuid);
 280         crm_xml_add(cib_object, XML_ATTR_UNAME, node);
 281         cib_conn->cmds->create(cib_conn, XML_CIB_TAG_STATUS, cib_object,
 282                                cib_sync_call|cib_scope_local);
 283         free_xml(cib_object);
 284 
 285         rc = cib_conn->cmds->query(cib_conn, xpath, &cib_object,
 286                                    cib_xpath|cib_sync_call|cib_scope_local);
 287         crm_trace("Injecting node state for %s (rc=%d)", node, rc);
 288     }
 289 
 290 done:
 291     free(found_uuid);
 292     free(xpath);
 293 
 294     if (duplicate) {
 295         crm_log_xml_warn(cib_object, "Duplicates");
 296         crm_exit(CRM_EX_SOFTWARE);
 297         return NULL; // not reached, but makes static analysis happy
 298     }
 299 
 300     CRM_ASSERT(rc == pcmk_ok);
 301     return cib_object;
 302 }
 303 
 304 /*!
 305  * \internal
 306  * \brief Inject a fictitious node state change into a scheduler input
 307  *
 308  * \param[in,out] cib_conn  Scheduler input CIB to inject into
 309  * \param[in]     node      Name of node to inject change for
 310  * \param[in]     up        If true, change state to online, otherwise offline
 311  *
 312  * \return XML of changed (or added) node state entry
 313  */
 314 xmlNode *
 315 pcmk__inject_node_state_change(cib_t *cib_conn, const char *node, bool up)
     /* [previous][next][first][last][top][bottom][index][help] */
 316 {
 317     xmlNode *cib_node = pcmk__inject_node(cib_conn, node, NULL);
 318 
 319     if (up) {
 320         pcmk__xe_set_props(cib_node,
 321                            XML_NODE_IN_CLUSTER, XML_BOOLEAN_YES,
 322                            XML_NODE_IS_PEER, ONLINESTATUS,
 323                            XML_NODE_JOIN_STATE, CRMD_JOINSTATE_MEMBER,
 324                            XML_NODE_EXPECTED, CRMD_JOINSTATE_MEMBER,
 325                            NULL);
 326     } else {
 327         pcmk__xe_set_props(cib_node,
 328                            XML_NODE_IN_CLUSTER, XML_BOOLEAN_NO,
 329                            XML_NODE_IS_PEER, OFFLINESTATUS,
 330                            XML_NODE_JOIN_STATE, CRMD_JOINSTATE_DOWN,
 331                            XML_NODE_EXPECTED, CRMD_JOINSTATE_DOWN,
 332                            NULL);
 333     }
 334     crm_xml_add(cib_node, XML_ATTR_ORIGIN, crm_system_name);
 335     return cib_node;
 336 }
 337 
 338 /*!
 339  * \internal
 340  * \brief Check whether a node has history for a given resource
 341  *
 342  * \param[in,out] cib_node  Node state XML to check
 343  * \param[in]     resource  Resource name to check for
 344  *
 345  * \return Resource's lrm_resource XML entry beneath \p cib_node if found,
 346  *         otherwise NULL
 347  */
 348 static xmlNode *
 349 find_resource_xml(xmlNode *cib_node, const char *resource)
     /* [previous][next][first][last][top][bottom][index][help] */
 350 {
 351     const char *node = crm_element_value(cib_node, XML_ATTR_UNAME);
 352     char *xpath = crm_strdup_printf(XPATH_RSC_HISTORY, node, resource);
 353     xmlNode *match = get_xpath_object(xpath, cib_node, LOG_TRACE);
 354 
 355     free(xpath);
 356     return match;
 357 }
 358 
 359 /*!
 360  * \internal
 361  * \brief Inject a resource history element into a scheduler input
 362  *
 363  * \param[in,out] out       Output object for displaying error messages
 364  * \param[in,out] cib_node  Node state XML to inject resource history entry into
 365  * \param[in]     resource  ID (in configuration) of resource to inject
 366  * \param[in]     lrm_name  ID as used in history (could be clone instance)
 367  * \param[in]     rclass    Resource agent class of resource to inject
 368  * \param[in]     rtype     Resource agent type of resource to inject
 369  * \param[in]     rprovider Resource agent provider of resource to inject
 370  *
 371  * \return XML of injected resource history element
 372  * \note If a history element already exists under either \p resource or
 373  *       \p lrm_name, this will return it rather than injecting a new one.
 374  */
 375 xmlNode *
 376 pcmk__inject_resource_history(pcmk__output_t *out, xmlNode *cib_node,
     /* [previous][next][first][last][top][bottom][index][help] */
 377                               const char *resource, const char *lrm_name,
 378                               const char *rclass, const char *rtype,
 379                               const char *rprovider)
 380 {
 381     xmlNode *lrm = NULL;
 382     xmlNode *container = NULL;
 383     xmlNode *cib_resource = NULL;
 384 
 385     cib_resource = find_resource_xml(cib_node, resource);
 386     if (cib_resource != NULL) {
 387         /* If an existing LRM history entry uses the resource name,
 388          * continue using it, even if lrm_name is different.
 389          */
 390         return cib_resource;
 391     }
 392 
 393     // Check for history entry under preferred name
 394     if (strcmp(resource, lrm_name) != 0) {
 395         cib_resource = find_resource_xml(cib_node, lrm_name);
 396         if (cib_resource != NULL) {
 397             return cib_resource;
 398         }
 399     }
 400 
 401     if ((rclass == NULL) || (rtype == NULL)) {
 402         // @TODO query configuration for class, provider, type
 403         out->err(out, "Resource %s not found in the status section of %s."
 404                  "  Please supply the class and type to continue", resource, ID(cib_node));
 405         return NULL;
 406 
 407     } else if (!pcmk__strcase_any_of(rclass,
 408                                      PCMK_RESOURCE_CLASS_OCF,
 409                                      PCMK_RESOURCE_CLASS_STONITH,
 410                                      PCMK_RESOURCE_CLASS_SERVICE,
 411                                      PCMK_RESOURCE_CLASS_UPSTART,
 412                                      PCMK_RESOURCE_CLASS_SYSTEMD,
 413                                      PCMK_RESOURCE_CLASS_LSB, NULL)) {
 414         out->err(out, "Invalid class for %s: %s", resource, rclass);
 415         return NULL;
 416 
 417     } else if (pcmk_is_set(pcmk_get_ra_caps(rclass), pcmk_ra_cap_provider)
 418                && (rprovider == NULL)) {
 419         // @TODO query configuration for provider
 420         out->err(out, "Please specify the provider for resource %s", resource);
 421         return NULL;
 422     }
 423 
 424     crm_info("Injecting new resource %s into node state '%s'",
 425              lrm_name, ID(cib_node));
 426 
 427     lrm = first_named_child(cib_node, XML_CIB_TAG_LRM);
 428     if (lrm == NULL) {
 429         const char *node_uuid = ID(cib_node);
 430 
 431         lrm = create_xml_node(cib_node, XML_CIB_TAG_LRM);
 432         crm_xml_add(lrm, XML_ATTR_ID, node_uuid);
 433     }
 434 
 435     container = first_named_child(lrm, XML_LRM_TAG_RESOURCES);
 436     if (container == NULL) {
 437         container = create_xml_node(lrm, XML_LRM_TAG_RESOURCES);
 438     }
 439 
 440     cib_resource = create_xml_node(container, XML_LRM_TAG_RESOURCE);
 441 
 442     // If we're creating a new entry, use the preferred name
 443     crm_xml_add(cib_resource, XML_ATTR_ID, lrm_name);
 444 
 445     crm_xml_add(cib_resource, XML_AGENT_ATTR_CLASS, rclass);
 446     crm_xml_add(cib_resource, XML_AGENT_ATTR_PROVIDER, rprovider);
 447     crm_xml_add(cib_resource, XML_ATTR_TYPE, rtype);
 448 
 449     return cib_resource;
 450 }
 451 
 452 static int
 453 find_ticket_state(pcmk__output_t *out, cib_t *the_cib, const char *ticket_id,
     /* [previous][next][first][last][top][bottom][index][help] */
 454                   xmlNode **ticket_state_xml)
 455 {
 456     int rc = pcmk_ok;
 457     xmlNode *xml_search = NULL;
 458 
 459     GString *xpath = g_string_sized_new(256);
 460 
 461     CRM_ASSERT(ticket_state_xml != NULL);
 462     *ticket_state_xml = NULL;
 463 
 464     g_string_append(xpath,
 465                     "/" XML_TAG_CIB "/" XML_CIB_TAG_STATUS
 466                     "/" XML_CIB_TAG_TICKETS);
 467 
 468     if (ticket_id) {
 469         pcmk__g_strcat(xpath,
 470                        "/" XML_CIB_TAG_TICKET_STATE
 471                        "[@" XML_ATTR_ID "=\"", ticket_id, "\"]", NULL);
 472     }
 473     rc = the_cib->cmds->query(the_cib, (const char *) xpath->str, &xml_search,
 474                               cib_sync_call|cib_scope_local|cib_xpath);
 475     g_string_free(xpath, TRUE);
 476 
 477     if (rc != pcmk_ok) {
 478         return rc;
 479     }
 480 
 481     crm_log_xml_debug(xml_search, "Match");
 482     if (xml_has_children(xml_search) && (ticket_id != NULL)) {
 483         out->err(out, "Multiple ticket_states match ticket_id=%s", ticket_id);
 484     }
 485     *ticket_state_xml = xml_search;
 486 
 487     return rc;
 488 }
 489 
 490 /*!
 491  * \internal
 492  * \brief Inject a ticket attribute into ticket state
 493  *
 494  * \param[in,out] out          Output object for displaying error messages
 495  * \param[in]     ticket_id    Ticket whose state should be changed
 496  * \param[in]     attr_name    Ticket attribute name to inject
 497  * \param[in]     attr_value   Boolean value of ticket attribute to inject
 498  * \param[in,out] cib          CIB object to use
 499  *
 500  * \return Standard Pacemaker return code
 501  */
 502 static int
 503 set_ticket_state_attr(pcmk__output_t *out, const char *ticket_id,
     /* [previous][next][first][last][top][bottom][index][help] */
 504                       const char *attr_name, bool attr_value, cib_t *cib)
 505 {
 506     int rc = pcmk_rc_ok;
 507     xmlNode *xml_top = NULL;
 508     xmlNode *ticket_state_xml = NULL;
 509 
 510     // Check for an existing ticket state entry
 511     rc = find_ticket_state(out, cib, ticket_id, &ticket_state_xml);
 512     rc = pcmk_legacy2rc(rc);
 513 
 514     if (rc == pcmk_rc_ok) { // Ticket state found, use it
 515         crm_debug("Injecting attribute into existing ticket state %s",
 516                   ticket_id);
 517         xml_top = ticket_state_xml;
 518 
 519     } else if (rc == ENXIO) { // No ticket state, create it
 520         xmlNode *xml_obj = NULL;
 521 
 522         xml_top = create_xml_node(NULL, XML_CIB_TAG_STATUS);
 523         xml_obj = create_xml_node(xml_top, XML_CIB_TAG_TICKETS);
 524         ticket_state_xml = create_xml_node(xml_obj, XML_CIB_TAG_TICKET_STATE);
 525         crm_xml_add(ticket_state_xml, XML_ATTR_ID, ticket_id);
 526 
 527     } else { // Error
 528         return rc;
 529     }
 530 
 531     // Add the attribute to the ticket state
 532     pcmk__xe_set_bool_attr(ticket_state_xml, attr_name, attr_value);
 533     crm_log_xml_debug(xml_top, "Update");
 534 
 535     // Commit the change to the CIB
 536     rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, xml_top,
 537                            cib_sync_call|cib_scope_local);
 538     rc = pcmk_legacy2rc(rc);
 539 
 540     free_xml(xml_top);
 541     return rc;
 542 }
 543 
 544 /*!
 545  * \internal
 546  * \brief Inject a fictitious action into the cluster
 547  *
 548  * \param[in,out] out       Output object for displaying error messages
 549  * \param[in]     spec      Action specification to inject
 550  * \param[in,out] cib       CIB object for scheduler input
 551  * \param[in]     data_set  Cluster working set
 552  */
 553 static void
 554 inject_action(pcmk__output_t *out, const char *spec, cib_t *cib,
     /* [previous][next][first][last][top][bottom][index][help] */
 555               const pe_working_set_t *data_set)
 556 {
 557     int rc;
 558     int outcome = PCMK_OCF_OK;
 559     guint interval_ms = 0;
 560 
 561     char *key = NULL;
 562     char *node = NULL;
 563     char *task = NULL;
 564     char *resource = NULL;
 565 
 566     const char *rtype = NULL;
 567     const char *rclass = NULL;
 568     const char *rprovider = NULL;
 569 
 570     xmlNode *cib_op = NULL;
 571     xmlNode *cib_node = NULL;
 572     xmlNode *cib_resource = NULL;
 573     const pe_resource_t *rsc = NULL;
 574     lrmd_event_data_t *op = NULL;
 575 
 576     out->message(out, "inject-spec", spec);
 577 
 578     key = calloc(1, strlen(spec) + 1);
 579     node = calloc(1, strlen(spec) + 1);
 580     rc = sscanf(spec, "%[^@]@%[^=]=%d", key, node, &outcome);
 581     if (rc != 3) {
 582         out->err(out, "Invalid operation spec: %s.  Only found %d fields",
 583                  spec, rc);
 584         goto done;
 585     }
 586 
 587     parse_op_key(key, &resource, &task, &interval_ms);
 588 
 589     rsc = pe_find_resource(data_set->resources, resource);
 590     if (rsc == NULL) {
 591         out->err(out, "Invalid resource name: %s", resource);
 592         goto done;
 593     }
 594 
 595     rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
 596     rtype = crm_element_value(rsc->xml, XML_ATTR_TYPE);
 597     rprovider = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
 598 
 599     cib_node = pcmk__inject_node(cib, node, NULL);
 600     CRM_ASSERT(cib_node != NULL);
 601 
 602     pcmk__inject_failcount(out, cib_node, resource, task, interval_ms, outcome);
 603 
 604     cib_resource = pcmk__inject_resource_history(out, cib_node,
 605                                                  resource, resource,
 606                                                  rclass, rtype, rprovider);
 607     CRM_ASSERT(cib_resource != NULL);
 608 
 609     op = create_op(cib_resource, task, interval_ms, outcome);
 610     CRM_ASSERT(op != NULL);
 611 
 612     cib_op = pcmk__inject_action_result(cib_resource, op, 0);
 613     CRM_ASSERT(cib_op != NULL);
 614     lrmd_free_event(op);
 615 
 616     rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node,
 617                            cib_sync_call|cib_scope_local);
 618     CRM_ASSERT(rc == pcmk_ok);
 619 
 620 done:
 621     free(task);
 622     free(node);
 623     free(key);
 624 }
 625 
 626 /*!
 627  * \internal
 628  * \brief Inject fictitious scheduler inputs
 629  *
 630  * \param[in,out] data_set    Cluster working set
 631  * \param[in,out] cib         CIB object for scheduler input to modify
 632  * \param[in]     injections  Injections to apply
 633  */
 634 void
 635 pcmk__inject_scheduler_input(pe_working_set_t *data_set, cib_t *cib,
     /* [previous][next][first][last][top][bottom][index][help] */
 636                              const pcmk_injections_t *injections)
 637 {
 638     int rc = pcmk_ok;
 639     const GList *iter = NULL;
 640     xmlNode *cib_node = NULL;
 641     pcmk__output_t *out = data_set->priv;
 642 
 643     out->message(out, "inject-modify-config", injections->quorum,
 644                  injections->watchdog);
 645     if (injections->quorum != NULL) {
 646         xmlNode *top = create_xml_node(NULL, XML_TAG_CIB);
 647 
 648         /* crm_xml_add(top, XML_ATTR_DC_UUID, dc_uuid);      */
 649         crm_xml_add(top, XML_ATTR_HAVE_QUORUM, injections->quorum);
 650 
 651         rc = cib->cmds->modify(cib, NULL, top, cib_sync_call|cib_scope_local);
 652         CRM_ASSERT(rc == pcmk_ok);
 653     }
 654 
 655     if (injections->watchdog != NULL) {
 656         rc = cib__update_node_attr(out, cib, cib_sync_call|cib_scope_local,
 657                                    XML_CIB_TAG_CRMCONFIG, NULL, NULL, NULL, NULL,
 658                                    XML_ATTR_HAVE_WATCHDOG, injections->watchdog,
 659                                    NULL, NULL);
 660         CRM_ASSERT(rc == pcmk_rc_ok);
 661     }
 662 
 663     for (iter = injections->node_up; iter != NULL; iter = iter->next) {
 664         const char *node = (const char *) iter->data;
 665 
 666         out->message(out, "inject-modify-node", "Online", node);
 667 
 668         cib_node = pcmk__inject_node_state_change(cib, node, true);
 669         CRM_ASSERT(cib_node != NULL);
 670 
 671         rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node,
 672                                cib_sync_call|cib_scope_local);
 673         CRM_ASSERT(rc == pcmk_ok);
 674         free_xml(cib_node);
 675     }
 676 
 677     for (iter = injections->node_down; iter != NULL; iter = iter->next) {
 678         const char *node = (const char *) iter->data;
 679         char *xpath = NULL;
 680 
 681         out->message(out, "inject-modify-node", "Offline", node);
 682 
 683         cib_node = pcmk__inject_node_state_change(cib, node, false);
 684         CRM_ASSERT(cib_node != NULL);
 685 
 686         rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node,
 687                                cib_sync_call|cib_scope_local);
 688         CRM_ASSERT(rc == pcmk_ok);
 689         free_xml(cib_node);
 690 
 691         xpath = crm_strdup_printf("//node_state[@uname='%s']/%s",
 692                                   node, XML_CIB_TAG_LRM);
 693         cib->cmds->remove(cib, xpath, NULL,
 694                           cib_xpath|cib_sync_call|cib_scope_local);
 695         free(xpath);
 696 
 697         xpath = crm_strdup_printf("//node_state[@uname='%s']/%s",
 698                                   node, XML_TAG_TRANSIENT_NODEATTRS);
 699         cib->cmds->remove(cib, xpath, NULL,
 700                           cib_xpath|cib_sync_call|cib_scope_local);
 701         free(xpath);
 702     }
 703 
 704     for (iter = injections->node_fail; iter != NULL; iter = iter->next) {
 705         const char *node = (const char *) iter->data;
 706 
 707         out->message(out, "inject-modify-node", "Failing", node);
 708 
 709         cib_node = pcmk__inject_node_state_change(cib, node, true);
 710         crm_xml_add(cib_node, XML_NODE_IN_CLUSTER, XML_BOOLEAN_NO);
 711         CRM_ASSERT(cib_node != NULL);
 712 
 713         rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node,
 714                                cib_sync_call|cib_scope_local);
 715         CRM_ASSERT(rc == pcmk_ok);
 716         free_xml(cib_node);
 717     }
 718 
 719     for (iter = injections->ticket_grant; iter != NULL; iter = iter->next) {
 720         const char *ticket_id = (const char *) iter->data;
 721 
 722         out->message(out, "inject-modify-ticket", "Granting", ticket_id);
 723 
 724         rc = set_ticket_state_attr(out, ticket_id, "granted", true, cib);
 725         CRM_ASSERT(rc == pcmk_rc_ok);
 726     }
 727 
 728     for (iter = injections->ticket_revoke; iter != NULL; iter = iter->next) {
 729         const char *ticket_id = (const char *) iter->data;
 730 
 731         out->message(out, "inject-modify-ticket", "Revoking", ticket_id);
 732 
 733         rc = set_ticket_state_attr(out, ticket_id, "granted", false, cib);
 734         CRM_ASSERT(rc == pcmk_rc_ok);
 735     }
 736 
 737     for (iter = injections->ticket_standby; iter != NULL; iter = iter->next) {
 738         const char *ticket_id = (const char *) iter->data;
 739 
 740         out->message(out, "inject-modify-ticket", "Standby", ticket_id);
 741 
 742         rc = set_ticket_state_attr(out, ticket_id, "standby", true, cib);
 743         CRM_ASSERT(rc == pcmk_rc_ok);
 744     }
 745 
 746     for (iter = injections->ticket_activate; iter != NULL; iter = iter->next) {
 747         const char *ticket_id = (const char *) iter->data;
 748 
 749         out->message(out, "inject-modify-ticket", "Activating", ticket_id);
 750 
 751         rc = set_ticket_state_attr(out, ticket_id, "standby", false, cib);
 752         CRM_ASSERT(rc == pcmk_rc_ok);
 753     }
 754 
 755     for (iter = injections->op_inject; iter != NULL; iter = iter->next) {
 756         inject_action(out, (const char *) iter->data, cib, data_set);
 757     }
 758 
 759     if (!out->is_quiet(out)) {
 760         out->end_list(out);
 761     }
 762 }
 763 
 764 void
 765 pcmk_free_injections(pcmk_injections_t *injections)
     /* [previous][next][first][last][top][bottom][index][help] */
 766 {
 767     if (injections == NULL) {
 768         return;
 769     }
 770 
 771     g_list_free_full(injections->node_up, g_free);
 772     g_list_free_full(injections->node_down, g_free);
 773     g_list_free_full(injections->node_fail, g_free);
 774     g_list_free_full(injections->op_fail, g_free);
 775     g_list_free_full(injections->op_inject, g_free);
 776     g_list_free_full(injections->ticket_grant, g_free);
 777     g_list_free_full(injections->ticket_revoke, g_free);
 778     g_list_free_full(injections->ticket_standby, g_free);
 779     g_list_free_full(injections->ticket_activate, g_free);
 780     free(injections->quorum);
 781     free(injections->watchdog);
 782 
 783     free(injections);
 784 }

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