pacemaker 2.1.5-a3f44794f94
Scalable High-Availability cluster resource manager
pcmk_resource.c
Go to the documentation of this file.
1/*
2 * Copyright 2021-2022 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>
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
30static xmlNode *
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, data_set->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,
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
62 RSC_MIGRATED, NULL);
63
64 if (best == NULL) {
65 goto is_best;
66 }
67
68 if (best_effective_op) {
69 // Do not use an ineffective op if there's an effective one.
70 if (!effective_op) {
71 continue;
72 }
73 // Do not use an ineffective non-recurring op if there's a recurring one.
74 } else if (best_interval != 0
75 && !effective_op
76 && interval_ms == 0) {
77 continue;
78 }
79
80 // Do not use last failure if there's a successful one.
81 if (!best_failure && failure) {
82 continue;
83 }
84
85 // Do not use an op without a restart digest if there's one with.
86 if (best_digest != NULL && digest == NULL) {
87 continue;
88 }
89
90 // Do not use an older op if there's a newer one.
91 if (pe__is_newer_op(best, lrm_rsc_op, true) > 0) {
92 continue;
93 }
94
95is_best:
96 best = lrm_rsc_op;
97 best_effective_op = effective_op;
98 best_interval = interval_ms;
99 best_failure = failure;
100 best_digest = digest;
101 }
102 return best;
103}
104
116int
118 pe_node_t *node, GHashTable *overrides)
119{
120 const char *task = NULL;
121 xmlNode *xml_op = NULL;
122 op_digest_cache_t *digests = NULL;
123 guint interval_ms = 0;
124 int rc = pcmk_rc_ok;
125
126 if ((out == NULL) || (rsc == NULL) || (node == NULL)) {
127 return EINVAL;
128 }
129 if (rsc->variant != pe_native) {
130 // Only primitives get operation digests
131 return EOPNOTSUPP;
132 }
133
134 // Find XML of operation history to use
135 xml_op = best_op(rsc, node, rsc->cluster);
136
137 // Generate an operation key
138 if (xml_op != NULL) {
139 task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
140 crm_element_value_ms(xml_op, XML_LRM_ATTR_INTERVAL_MS, &interval_ms);
141 }
142 if (task == NULL) { // Assume start if no history is available
143 task = RSC_START;
144 interval_ms = 0;
145 }
146
147 // Calculate and show digests
148 digests = pe__calculate_digests(rsc, task, &interval_ms, node, xml_op,
149 overrides, true, rsc->cluster);
150 rc = out->message(out, "digests", rsc, node, task, interval_ms, digests);
151
152 pe__free_digests(digests);
153 return rc;
154}
155
156int
158 pe_node_t *node, GHashTable *overrides,
160{
161 pcmk__output_t *out = NULL;
162 int rc = pcmk_rc_ok;
163
164 rc = pcmk__xml_output_new(&out, xml);
165 if (rc != pcmk_rc_ok) {
166 return rc;
167 }
169 rc = pcmk__resource_digests(out, rsc, node, overrides);
170 pcmk__xml_output_finish(out, xml);
171 return rc;
172}
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define RSC_PROMOTE
Definition: crm.h:205
#define RSC_START
Definition: crm.h:199
#define RSC_STATUS
Definition: crm.h:213
#define RSC_MIGRATED
Definition: crm.h:197
#define LOG_NEVER
Definition: logging.h:47
Wrappers for and extensions to glib mainloop.
#define XML_LRM_TAG_RSC_OP
Definition: msg_xml.h:268
#define ID(x)
Definition: msg_xml.h:468
#define XML_LRM_ATTR_INTERVAL
Definition: msg_xml.h:294
#define XML_LRM_ATTR_RESTART_DIGEST
Definition: msg_xml.h:316
#define XML_LRM_ATTR_TASK
Definition: msg_xml.h:300
#define XML_LRM_ATTR_INTERVAL_MS
Definition: msg_xml.h:298
pe_working_set_t * data_set
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:517
int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
Retrieve the millisecond value of an XML attribute.
Definition: nvpair.c:610
Formatted output for pacemaker tools.
int pcmk__xml_output_new(pcmk__output_t **out, xmlNodePtr *xml)
Definition: output.c:201
void pcmk__xml_output_finish(pcmk__output_t *out, xmlNodePtr *xml)
Definition: output.c:223
High Level API.
#define XPATH_OP_HISTORY
Definition: pcmk_resource.c:25
int pcmk__resource_digests(pcmk__output_t *out, pe_resource_t *rsc, pe_node_t *node, GHashTable *overrides)
int pcmk_resource_digests(xmlNodePtr *xml, pe_resource_t *rsc, pe_node_t *node, GHashTable *overrides, pe_working_set_t *data_set)
Calculate and output resource operation digests.
void pcmk__register_lib_messages(pcmk__output_t *out)
Definition: pcmk_output.c:2195
@ pe_native
Definition: pe_types.h:38
int pe__is_newer_op(const xmlNode *xml_a, const xmlNode *xml_b, bool same_node_default)
Definition: pe_actions.c:1494
op_digest_cache_t * pe__calculate_digests(pe_resource_t *rsc, const char *task, guint *interval_ms, pe_node_t *node, xmlNode *xml_op, GHashTable *overrides, bool calc_secure, pe_working_set_t *data_set)
Definition: pe_digest.c:298
void pe__free_digests(gpointer ptr)
Definition: pe_digest.c:34
Function and executable result codes.
@ pcmk_rc_ok
Definition: results.h:148
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:928
bool pcmk__ends_with(const char *s, const char *match)
Definition: strings.c:536
This structure contains everything that makes up a single output formatter.
int(* message)(pcmk__output_t *out, const char *message_id,...)
struct pe_node_shared_s * details
Definition: pe_types.h:252
const char * uname
Definition: pe_types.h:216
enum pe_obj_types variant
Definition: pe_types.h:338
pe_working_set_t * cluster
Definition: pe_types.h:335
char * id
Definition: pe_types.h:329
xmlNode * input
Definition: pe_types.h:144
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2930
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:214
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:2956