LCOV - code coverage report
Current view: top level - pacemaker - pcmk_resource.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 31 109 28.4 %
Date: 2024-05-07 11:09:47 Functions: 2 5 40.0 %

          Line data    Source code
       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           0 : best_op(const pcmk_resource_t *rsc, const pcmk_node_t *node)
      34             : {
      35           0 :     char *xpath = NULL;
      36           0 :     xmlNode *history = NULL;
      37           0 :     xmlNode *best = NULL;
      38           0 :     bool best_effective_op = false;
      39           0 :     guint best_interval = 0;
      40           0 :     bool best_failure = false;
      41           0 :     const char *best_digest = NULL;
      42             : 
      43             :     // Find node's resource history
      44           0 :     xpath = crm_strdup_printf(XPATH_OP_HISTORY, node->details->uname, rsc->id);
      45           0 :     history = get_xpath_object(xpath, rsc->cluster->input, LOG_NEVER);
      46           0 :     free(xpath);
      47             : 
      48             :     // Examine each history entry
      49           0 :     for (xmlNode *lrm_rsc_op = pcmk__xe_first_child(history,
      50             :                                                     PCMK__XE_LRM_RSC_OP, NULL,
      51             :                                                     NULL);
      52           0 :          lrm_rsc_op != NULL; lrm_rsc_op = pcmk__xe_next_same(lrm_rsc_op)) {
      53             : 
      54           0 :         const char *digest = crm_element_value(lrm_rsc_op,
      55             :                                                PCMK__XA_OP_RESTART_DIGEST);
      56           0 :         guint interval_ms = 0;
      57           0 :         const char *task = crm_element_value(lrm_rsc_op, PCMK_XA_OPERATION);
      58           0 :         bool effective_op = false;
      59           0 :         bool failure = pcmk__ends_with(pcmk__xe_id(lrm_rsc_op),
      60             :                                        "_last_failure_0");
      61             : 
      62             : 
      63           0 :         crm_element_value_ms(lrm_rsc_op, PCMK_META_INTERVAL, &interval_ms);
      64           0 :         effective_op = interval_ms == 0
      65           0 :                        && pcmk__strcase_any_of(task, PCMK_ACTION_MONITOR,
      66             :                                                PCMK_ACTION_START,
      67             :                                                PCMK_ACTION_PROMOTE,
      68             :                                                PCMK_ACTION_MIGRATE_FROM, NULL);
      69             : 
      70           0 :         if (best == NULL) {
      71           0 :             goto is_best;
      72             :         }
      73             : 
      74           0 :         if (best_effective_op) {
      75             :             // Do not use an ineffective op if there's an effective one.
      76           0 :             if (!effective_op) {
      77           0 :                 continue;
      78             :             }
      79             :         // Do not use an ineffective non-recurring op if there's a recurring one
      80           0 :         } else if (best_interval != 0
      81           0 :                    && !effective_op
      82           0 :                    && interval_ms == 0) {
      83           0 :             continue;
      84             :         }
      85             : 
      86             :         // Do not use last failure if there's a successful one.
      87           0 :         if (!best_failure && failure) {
      88           0 :             continue;
      89             :         }
      90             : 
      91             :         // Do not use an op without a restart digest if there's one with.
      92           0 :         if (best_digest != NULL && digest == NULL) {
      93           0 :             continue;
      94             :         }
      95             : 
      96             :         // Do not use an older op if there's a newer one.
      97           0 :         if (pe__is_newer_op(best, lrm_rsc_op, true) > 0) {
      98           0 :             continue;
      99             :         }
     100             : 
     101           0 : is_best:
     102           0 :          best = lrm_rsc_op;
     103           0 :          best_effective_op = effective_op;
     104           0 :          best_interval = interval_ms;
     105           0 :          best_failure = failure;
     106           0 :          best_digest = digest;
     107             :     }
     108           0 :     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           5 : pcmk__resource_delete(cib_t *cib, uint32_t cib_opts, const char *rsc_id,
     124             :                       const char *rsc_type)
     125             : {
     126           5 :     int rc = pcmk_rc_ok;
     127           5 :     xmlNode *msg_data = NULL;
     128             : 
     129           5 :     if (cib == NULL) {
     130           0 :         return ENOTCONN;
     131             :     }
     132             : 
     133           5 :     if (rsc_id == NULL || rsc_type == NULL) {
     134           2 :         return EINVAL;
     135             :     }
     136             : 
     137           3 :     msg_data = pcmk__xe_create(NULL, rsc_type);
     138           3 :     crm_xml_add(msg_data, PCMK_XA_ID, rsc_id);
     139             : 
     140           3 :     rc = cib->cmds->remove(cib, PCMK_XE_RESOURCES, msg_data, cib_opts);
     141           3 :     rc = pcmk_legacy2rc(rc);
     142             : 
     143           3 :     free_xml(msg_data);
     144           3 :     return rc;
     145             : }
     146             : 
     147             : int
     148           6 : pcmk_resource_delete(xmlNodePtr *xml, const char *rsc_id, const char *rsc_type)
     149             : {
     150           6 :     pcmk__output_t *out = NULL;
     151           6 :     int rc = pcmk_rc_ok;
     152           6 :     uint32_t cib_opts = cib_sync_call;
     153           6 :     cib_t *cib = NULL;
     154             : 
     155           6 :     rc = pcmk__xml_output_new(&out, xml);
     156           6 :     if (rc != pcmk_rc_ok) {
     157           0 :         return rc;
     158             :     }
     159             : 
     160           6 :     cib = cib_new();
     161           6 :     if (cib == NULL) {
     162           0 :         rc = pcmk_rc_cib_corrupt;
     163           0 :         goto done;
     164             :     }
     165             : 
     166           6 :     rc = cib->cmds->signon(cib, crm_system_name, cib_command);
     167           6 :     rc = pcmk_legacy2rc(rc);
     168             : 
     169           6 :     if (rc != pcmk_rc_ok) {
     170           1 :         goto done;
     171             :     }
     172             : 
     173           5 :     rc = pcmk__resource_delete(cib, cib_opts, rsc_id, rsc_type);
     174             : 
     175           6 : done:
     176           6 :     if (cib != NULL) {
     177           6 :         cib__clean_up_connection(&cib);
     178             :     }
     179             : 
     180           6 :     pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
     181           6 :     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           0 : pcmk__resource_digests(pcmk__output_t *out, pcmk_resource_t *rsc,
     197             :                        const pcmk_node_t *node, GHashTable *overrides)
     198             : {
     199           0 :     const char *task = NULL;
     200           0 :     xmlNode *xml_op = NULL;
     201           0 :     pcmk__op_digest_t *digests = NULL;
     202           0 :     guint interval_ms = 0;
     203           0 :     int rc = pcmk_rc_ok;
     204             : 
     205           0 :     if ((out == NULL) || (rsc == NULL) || (node == NULL)) {
     206           0 :         return EINVAL;
     207             :     }
     208           0 :     if (rsc->variant != pcmk_rsc_variant_primitive) {
     209             :         // Only primitives get operation digests
     210           0 :         return EOPNOTSUPP;
     211             :     }
     212             : 
     213             :     // Find XML of operation history to use
     214           0 :     xml_op = best_op(rsc, node);
     215             : 
     216             :     // Generate an operation key
     217           0 :     if (xml_op != NULL) {
     218           0 :         task = crm_element_value(xml_op, PCMK_XA_OPERATION);
     219           0 :         crm_element_value_ms(xml_op, PCMK_META_INTERVAL, &interval_ms);
     220             :     }
     221           0 :     if (task == NULL) { // Assume start if no history is available
     222           0 :         task = PCMK_ACTION_START;
     223           0 :         interval_ms = 0;
     224             :     }
     225             : 
     226             :     // Calculate and show digests
     227           0 :     digests = pe__calculate_digests(rsc, task, &interval_ms, node, xml_op,
     228             :                                     overrides, true, rsc->cluster);
     229           0 :     rc = out->message(out, "digests", rsc, node, task, interval_ms, digests);
     230             : 
     231           0 :     pe__free_digests(digests);
     232           0 :     return rc;
     233             : }
     234             : 
     235             : // @COMPAT The scheduler parameter is unused and can be removed at the next break
     236             : int
     237           0 : pcmk_resource_digests(xmlNodePtr *xml, pcmk_resource_t *rsc,
     238             :                       const pcmk_node_t *node, GHashTable *overrides,
     239             :                       pcmk_scheduler_t *scheduler)
     240             : {
     241           0 :     pcmk__output_t *out = NULL;
     242           0 :     int rc = pcmk_rc_ok;
     243             : 
     244           0 :     rc = pcmk__xml_output_new(&out, xml);
     245           0 :     if (rc != pcmk_rc_ok) {
     246           0 :         return rc;
     247             :     }
     248           0 :     pcmk__register_lib_messages(out);
     249           0 :     rc = pcmk__resource_digests(out, rsc, node, overrides);
     250           0 :     pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
     251           0 :     return rc;
     252             : }

Generated by: LCOV version 1.14