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_delete
  3. pcmk_resource_delete
  4. pcmk__resource_digests
  5. pcmk_resource_digests

   1 /*
   2  * Copyright 2021-2025 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>                // xmlNode
  15 
  16 #include <crm/cib/internal.h>
  17 #include <crm/common/mainloop.h>
  18 #include <crm/common/results.h>
  19 #include <crm/common/output_internal.h>
  20 #include <crm/pengine/internal.h>
  21 
  22 #include <pacemaker.h>
  23 #include <pacemaker-internal.h>
  24 
  25 // Search path for resource operation history (takes node name and resource ID)
  26 #define XPATH_OP_HISTORY "//" PCMK_XE_STATUS                            \
  27                          "/" PCMK__XE_NODE_STATE                        \
  28                          "[@" PCMK_XA_UNAME "='%s']"                    \
  29                          "/" PCMK__XE_LRM "/" PCMK__XE_LRM_RESOURCES    \
  30                          "/" PCMK__XE_LRM_RESOURCE "[@" PCMK_XA_ID "='%s']"
  31 
  32 static xmlNode *
  33 best_op(const pcmk_resource_t *rsc, const pcmk_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
  34 {
  35     char *xpath = NULL;
  36     xmlNode *history = NULL;
  37     xmlNode *best = NULL;
  38     bool best_effective_op = false;
  39     guint best_interval = 0;
  40     bool best_failure = false;
  41     const char *best_digest = NULL;
  42 
  43     // Find node's resource history
  44     xpath = crm_strdup_printf(XPATH_OP_HISTORY, node->priv->name, rsc->id);
  45     history = pcmk__xpath_find_one(rsc->priv->scheduler->input->doc, xpath,
  46                                    LOG_NEVER);
  47     free(xpath);
  48 
  49     // Examine each history entry
  50     for (xmlNode *lrm_rsc_op = pcmk__xe_first_child(history,
  51                                                     PCMK__XE_LRM_RSC_OP, NULL,
  52                                                     NULL);
  53          lrm_rsc_op != NULL;
  54          lrm_rsc_op = pcmk__xe_next(lrm_rsc_op, PCMK__XE_LRM_RSC_OP)) {
  55 
  56         const char *digest = crm_element_value(lrm_rsc_op,
  57                                                PCMK__XA_OP_RESTART_DIGEST);
  58         guint interval_ms = 0;
  59         const char *task = crm_element_value(lrm_rsc_op, PCMK_XA_OPERATION);
  60         bool effective_op = false;
  61         bool failure = pcmk__ends_with(pcmk__xe_id(lrm_rsc_op),
  62                                        "_last_failure_0");
  63 
  64 
  65         crm_element_value_ms(lrm_rsc_op, PCMK_META_INTERVAL, &interval_ms);
  66         effective_op = interval_ms == 0
  67                        && pcmk__strcase_any_of(task, PCMK_ACTION_MONITOR,
  68                                                PCMK_ACTION_START,
  69                                                PCMK_ACTION_PROMOTE,
  70                                                PCMK_ACTION_MIGRATE_FROM, NULL);
  71 
  72         if (best == NULL) {
  73             goto is_best;
  74         }
  75 
  76         if (best_effective_op) {
  77             // Do not use an ineffective op if there's an effective one.
  78             if (!effective_op) {
  79                 continue;
  80             }
  81         // Do not use an ineffective non-recurring op if there's a recurring one
  82         } else if (best_interval != 0
  83                    && !effective_op
  84                    && interval_ms == 0) {
  85             continue;
  86         }
  87 
  88         // Do not use last failure if there's a successful one.
  89         if (!best_failure && failure) {
  90             continue;
  91         }
  92 
  93         // Do not use an op without a restart digest if there's one with.
  94         if (best_digest != NULL && digest == NULL) {
  95             continue;
  96         }
  97 
  98         // Do not use an older op if there's a newer one.
  99         if (pe__is_newer_op(best, lrm_rsc_op) > 0) {
 100             continue;
 101         }
 102 
 103 is_best:
 104          best = lrm_rsc_op;
 105          best_effective_op = effective_op;
 106          best_interval = interval_ms;
 107          best_failure = failure;
 108          best_digest = digest;
 109     }
 110     return best;
 111 }
 112 
 113 /*!
 114  * \internal
 115  * \brief Remove a resource
 116  *
 117  * \param[in,out] cib       An open connection to the CIB
 118  * \param[in]     cib_opts  Options to use in the CIB operation call
 119  * \param[in]     rsc_id    Resource to remove
 120  * \param[in]     rsc_type  Type of the resource ("primitive", "group", etc.)
 121  *
 122  * \return Standard Pacemaker return code
 123  */
 124 int
 125 pcmk__resource_delete(cib_t *cib, uint32_t cib_opts, const char *rsc_id,
     /* [previous][next][first][last][top][bottom][index][help] */
 126                       const char *rsc_type)
 127 {
 128     int rc = pcmk_rc_ok;
 129     xmlNode *msg_data = NULL;
 130 
 131     if (cib == NULL) {
 132         return ENOTCONN;
 133     }
 134 
 135     if (rsc_id == NULL || rsc_type == NULL) {
 136         return EINVAL;
 137     }
 138 
 139     msg_data = pcmk__xe_create(NULL, rsc_type);
 140     crm_xml_add(msg_data, PCMK_XA_ID, rsc_id);
 141 
 142     rc = cib->cmds->remove(cib, PCMK_XE_RESOURCES, msg_data, cib_opts);
 143     rc = pcmk_legacy2rc(rc);
 144 
 145     pcmk__xml_free(msg_data);
 146     return rc;
 147 }
 148 
 149 int
 150 pcmk_resource_delete(xmlNodePtr *xml, const char *rsc_id, const char *rsc_type)
     /* [previous][next][first][last][top][bottom][index][help] */
 151 {
 152     pcmk__output_t *out = NULL;
 153     int rc = pcmk_rc_ok;
 154     uint32_t cib_opts = cib_sync_call;
 155     cib_t *cib = NULL;
 156 
 157     rc = pcmk__xml_output_new(&out, xml);
 158     if (rc != pcmk_rc_ok) {
 159         return rc;
 160     }
 161 
 162     cib = cib_new();
 163     if (cib == NULL) {
 164         rc = pcmk_rc_cib_corrupt;
 165         goto done;
 166     }
 167 
 168     rc = cib->cmds->signon(cib, crm_system_name, cib_command);
 169     rc = pcmk_legacy2rc(rc);
 170 
 171     if (rc != pcmk_rc_ok) {
 172         goto done;
 173     }
 174 
 175     rc = pcmk__resource_delete(cib, cib_opts, rsc_id, rsc_type);
 176 
 177 done:
 178     if (cib != NULL) {
 179         cib__clean_up_connection(&cib);
 180     }
 181 
 182     pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
 183     return rc;
 184 }
 185 
 186 /*!
 187  * \internal
 188  * \brief Calculate and output resource operation digests
 189  *
 190  * \param[in,out] out        Output object
 191  * \param[in,out] rsc        Resource to calculate digests for
 192  * \param[in]     node       Node whose operation history should be used
 193  * \param[in]     overrides  Hash table of configuration parameters to override
 194  *
 195  * \return Standard Pacemaker return code
 196  */
 197 int
 198 pcmk__resource_digests(pcmk__output_t *out, pcmk_resource_t *rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
 199                        const pcmk_node_t *node, GHashTable *overrides)
 200 {
 201     const char *task = NULL;
 202     xmlNode *xml_op = NULL;
 203     pcmk__op_digest_t *digests = NULL;
 204     guint interval_ms = 0;
 205     int rc = pcmk_rc_ok;
 206 
 207     if ((out == NULL) || (rsc == NULL) || (node == NULL)) {
 208         return EINVAL;
 209     }
 210 
 211     if (!pcmk__is_primitive(rsc)) {
 212         // Only primitives get operation digests
 213         return EOPNOTSUPP;
 214     }
 215 
 216     // Find XML of operation history to use
 217     xml_op = best_op(rsc, node);
 218 
 219     // Generate an operation key
 220     if (xml_op != NULL) {
 221         task = crm_element_value(xml_op, PCMK_XA_OPERATION);
 222         crm_element_value_ms(xml_op, PCMK_META_INTERVAL, &interval_ms);
 223     }
 224     if (task == NULL) { // Assume start if no history is available
 225         task = PCMK_ACTION_START;
 226         interval_ms = 0;
 227     }
 228 
 229     // Calculate and show digests
 230     digests = pe__calculate_digests(rsc, task, &interval_ms, node, xml_op,
 231                                     overrides, true, rsc->priv->scheduler);
 232     rc = out->message(out, "digests", rsc, node, task, interval_ms, digests);
 233 
 234     pe__free_digests(digests);
 235     return rc;
 236 }
 237 
 238 int
 239 pcmk_resource_digests(xmlNodePtr *xml, pcmk_resource_t *rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
 240                       const pcmk_node_t *node, GHashTable *overrides)
 241 {
 242     pcmk__output_t *out = NULL;
 243     int rc = pcmk_rc_ok;
 244 
 245     rc = pcmk__xml_output_new(&out, xml);
 246     if (rc != pcmk_rc_ok) {
 247         return rc;
 248     }
 249     pcmk__register_lib_messages(out);
 250     rc = pcmk__resource_digests(out, rsc, node, overrides);
 251     pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
 252     return rc;
 253 }

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