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

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