root/lib/pacemaker/pcmk_resource.c

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

DEFINITIONS

This source file includes following definitions.
  1. best_op
  2. pcmk__resource_digests
  3. pcmk_resource_digests

   1 /*
   2  * Copyright 2021-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 <errno.h>
  13 #include <glib.h>
  14 #include <libxml/tree.h>
  15 
  16 #include <crm/common/mainloop.h>
  17 #include <crm/common/results.h>
  18 #include <crm/common/output_internal.h>
  19 #include <crm/pengine/internal.h>
  20 
  21 #include <pacemaker.h>
  22 #include <pacemaker-internal.h>
  23 
  24 // Search path for resource operation history (takes node name and resource ID)
  25 #define XPATH_OP_HISTORY "//" XML_CIB_TAG_STATUS                            \
  26                          "/" XML_CIB_TAG_STATE "[@" XML_ATTR_UNAME "='%s']" \
  27                          "/" XML_CIB_TAG_LRM "/" XML_LRM_TAG_RESOURCES      \
  28                          "/" XML_LRM_TAG_RESOURCE "[@" XML_ATTR_ID "='%s']"
  29 
  30 static xmlNode *
  31 best_op(const pcmk_resource_t *rsc, const pcmk_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
  32 {
  33     char *xpath = NULL;
  34     xmlNode *history = NULL;
  35     xmlNode *best = NULL;
  36     bool best_effective_op = false;
  37     guint best_interval = 0;
  38     bool best_failure = false;
  39     const char *best_digest = NULL;
  40 
  41     // Find node's resource history
  42     xpath = crm_strdup_printf(XPATH_OP_HISTORY, node->details->uname, rsc->id);
  43     history = get_xpath_object(xpath, rsc->cluster->input, LOG_NEVER);
  44     free(xpath);
  45 
  46     // Examine each history entry
  47     for (xmlNode *lrm_rsc_op = first_named_child(history, XML_LRM_TAG_RSC_OP);
  48          lrm_rsc_op != NULL; lrm_rsc_op = crm_next_same_xml(lrm_rsc_op)) {
  49 
  50         const char *digest = crm_element_value(lrm_rsc_op,
  51                                                XML_LRM_ATTR_RESTART_DIGEST);
  52         guint interval_ms = 0;
  53         const char *task = crm_element_value(lrm_rsc_op, XML_LRM_ATTR_TASK);
  54         bool effective_op = false;
  55         bool failure = pcmk__ends_with(ID(lrm_rsc_op), "_last_failure_0");
  56 
  57 
  58         crm_element_value_ms(lrm_rsc_op, XML_LRM_ATTR_INTERVAL, &interval_ms);
  59         effective_op = interval_ms == 0
  60                        && pcmk__strcase_any_of(task, PCMK_ACTION_MONITOR,
  61                                                PCMK_ACTION_START,
  62                                                PCMK_ACTION_PROMOTE,
  63                                                PCMK_ACTION_MIGRATE_FROM, NULL);
  64 
  65         if (best == NULL) {
  66             goto is_best;
  67         }
  68 
  69         if (best_effective_op) {
  70             // Do not use an ineffective op if there's an effective one.
  71             if (!effective_op) {
  72                 continue;
  73             }
  74         // Do not use an ineffective non-recurring op if there's a recurring one
  75         } else if (best_interval != 0
  76                    && !effective_op
  77                    && interval_ms == 0) {
  78             continue;
  79         }
  80 
  81         // Do not use last failure if there's a successful one.
  82         if (!best_failure && failure) {
  83             continue;
  84         }
  85 
  86         // Do not use an op without a restart digest if there's one with.
  87         if (best_digest != NULL && digest == NULL) {
  88             continue;
  89         }
  90 
  91         // Do not use an older op if there's a newer one.
  92         if (pe__is_newer_op(best, lrm_rsc_op, true) > 0) {
  93             continue;
  94         }
  95 
  96 is_best:
  97          best = lrm_rsc_op;
  98          best_effective_op = effective_op;
  99          best_interval = interval_ms;
 100          best_failure = failure;
 101          best_digest = digest;
 102     }
 103     return best;
 104 }
 105 
 106 /*!
 107  * \internal
 108  * \brief Calculate and output resource operation digests
 109  *
 110  * \param[in,out] out        Output object
 111  * \param[in,out] rsc        Resource to calculate digests for
 112  * \param[in]     node       Node whose operation history should be used
 113  * \param[in]     overrides  Hash table of configuration parameters to override
 114  *
 115  * \return Standard Pacemaker return code
 116  */
 117 int
 118 pcmk__resource_digests(pcmk__output_t *out, pcmk_resource_t *rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
 119                        const pcmk_node_t *node, GHashTable *overrides)
 120 {
 121     const char *task = NULL;
 122     xmlNode *xml_op = NULL;
 123     op_digest_cache_t *digests = NULL;
 124     guint interval_ms = 0;
 125     int rc = pcmk_rc_ok;
 126 
 127     if ((out == NULL) || (rsc == NULL) || (node == NULL)) {
 128         return EINVAL;
 129     }
 130     if (rsc->variant != pcmk_rsc_variant_primitive) {
 131         // Only primitives get operation digests
 132         return EOPNOTSUPP;
 133     }
 134 
 135     // Find XML of operation history to use
 136     xml_op = best_op(rsc, node);
 137 
 138     // Generate an operation key
 139     if (xml_op != NULL) {
 140         task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
 141         crm_element_value_ms(xml_op, XML_LRM_ATTR_INTERVAL_MS, &interval_ms);
 142     }
 143     if (task == NULL) { // Assume start if no history is available
 144         task = PCMK_ACTION_START;
 145         interval_ms = 0;
 146     }
 147 
 148     // Calculate and show digests
 149     digests = pe__calculate_digests(rsc, task, &interval_ms, node, xml_op,
 150                                     overrides, true, rsc->cluster);
 151     rc = out->message(out, "digests", rsc, node, task, interval_ms, digests);
 152 
 153     pe__free_digests(digests);
 154     return rc;
 155 }
 156 
 157 int
 158 pcmk_resource_digests(xmlNodePtr *xml, pcmk_resource_t *rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
 159                       const pcmk_node_t *node, GHashTable *overrides,
 160                       pcmk_scheduler_t *scheduler)
 161 {
 162     pcmk__output_t *out = NULL;
 163     int rc = pcmk_rc_ok;
 164 
 165     rc = pcmk__xml_output_new(&out, xml);
 166     if (rc != pcmk_rc_ok) {
 167         return rc;
 168     }
 169     pcmk__register_lib_messages(out);
 170     rc = pcmk__resource_digests(out, rsc, node, overrides);
 171     pcmk__xml_output_finish(out, xml);
 172     return rc;
 173 }

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