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

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