pacemaker 2.1.8-2.1.8
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pcmk_resource.c
Go to the documentation of this file.
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>
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
32static xmlNode *
33best_op(const pcmk_resource_t *rsc, const pcmk_node_t *node)
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,
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,
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
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
101is_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
122int
123pcmk__resource_delete(cib_t *cib, uint32_t cib_opts, const char *rsc_id,
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
147int
148pcmk_resource_delete(xmlNodePtr *xml, const char *rsc_id, const char *rsc_type)
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) {
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
175done:
176 if (cib != NULL) {
178 }
179
181 return rc;
182}
183
195int
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
235int
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 }
247 rc = pcmk__resource_digests(out, rsc, node, overrides);
249 return rc;
250}
#define PCMK_ACTION_PROMOTE
Definition actions.h:66
#define PCMK_ACTION_START
Definition actions.h:72
#define PCMK_ACTION_MIGRATE_FROM
Definition actions.h:58
#define PCMK_ACTION_MONITOR
Definition actions.h:60
int cib__clean_up_connection(cib_t **cib)
Definition cib_utils.c:1046
cib_t * cib_new(void)
Create a new CIB connection object.
Definition cib_client.c:616
@ cib_command
Definition cib_types.h:51
@ cib_sync_call
Definition cib_types.h:133
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
char * crm_system_name
Definition utils.c:50
#define LOG_NEVER
Definition logging.h:48
Wrappers for and extensions to glib mainloop.
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:446
int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
Retrieve the millisecond value of an XML attribute.
Definition nvpair.c:539
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition nvpair.c:301
#define PCMK_META_INTERVAL
Definition options.h:91
Formatted output for pacemaker tools.
void pcmk__xml_output_finish(pcmk__output_t *out, crm_exit_t exit_status, xmlNodePtr *xml)
Definition output.c:271
int pcmk__xml_output_new(pcmk__output_t **out, xmlNodePtr *xml)
Definition output.c:244
High Level API.
#define XPATH_OP_HISTORY
int pcmk__resource_delete(cib_t *cib, uint32_t cib_opts, const char *rsc_id, const char *rsc_type)
int pcmk_resource_digests(xmlNodePtr *xml, pcmk_resource_t *rsc, const pcmk_node_t *node, GHashTable *overrides)
Calculate and output resource operation digests.
int pcmk__resource_digests(pcmk__output_t *out, pcmk_resource_t *rsc, const pcmk_node_t *node, GHashTable *overrides)
int pcmk_resource_delete(xmlNodePtr *xml, const char *rsc_id, const char *rsc_type)
Remove a resource.
void pcmk__register_lib_messages(pcmk__output_t *out)
int pe__is_newer_op(const xmlNode *xml_a, const xmlNode *xml_b, bool same_node_default)
pcmk__op_digest_t * pe__calculate_digests(pcmk_resource_t *rsc, const char *task, guint *interval_ms, const pcmk_node_t *node, const xmlNode *xml_op, GHashTable *overrides, bool calc_secure, pcmk_scheduler_t *scheduler)
Definition pe_digest.c:306
void pe__free_digests(gpointer ptr)
Definition pe_digest.c:33
Function and executable result codes.
@ pcmk_rc_ok
Definition results.h:162
@ pcmk_rc_cib_corrupt
Definition results.h:150
int pcmk_legacy2rc(int legacy_rc)
Definition results.c:559
crm_exit_t pcmk_rc2exitc(int rc)
Map a function return code to the most similar exit code.
Definition results.c:702
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1026
bool pcmk__ends_with(const char *s, const char *match)
Definition strings.c:608
int(* remove)(cib_t *cib, const char *section, xmlNode *data, int call_options)
Definition cib_types.h:237
int(* signon)(cib_t *cib, const char *name, enum cib_conn_type type)
Definition cib_types.h:159
cib_api_operations_t * cmds
Definition cib_types.h:399
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 nodes.h:167
const char * uname
Definition nodes.h:73
pcmk_scheduler_t * cluster
Definition resources.h:408
xmlNode * input
Definition scheduler.h:196
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition xpath.c:189
void free_xml(xmlNode *child)
Definition xml.c:867
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition xml.c:440
xmlNode * pcmk__xe_next_same(const xmlNode *node)
Definition xml.c:2108
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition xml.c:720
#define PCMK_XA_OPERATION
Definition xml_names.h:344
#define PCMK_XA_ID
Definition xml_names.h:296
#define PCMK_XE_RESOURCES
Definition xml_names.h:175
#define PCMK__XE_LRM_RSC_OP
#define PCMK__XA_OP_RESTART_DIGEST