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

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