pacemaker 3.0.1-16e74fc4da
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pcmk_resource.c
Go to the documentation of this file.
1/*
2 * Copyright 2021-2025 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> // xmlNode
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->priv->name, rsc->id);
45 history = pcmk__xpath_find_one(rsc->priv->scheduler->input->doc, xpath,
46 LOG_NEVER);
47 free(xpath);
48
49 // Examine each history entry
50 for (xmlNode *lrm_rsc_op = pcmk__xe_first_child(history,
52 NULL);
53 lrm_rsc_op != NULL;
54 lrm_rsc_op = pcmk__xe_next(lrm_rsc_op, PCMK__XE_LRM_RSC_OP)) {
55
56 const char *digest = crm_element_value(lrm_rsc_op,
58 guint interval_ms = 0;
59 const char *task = crm_element_value(lrm_rsc_op, PCMK_XA_OPERATION);
60 bool effective_op = false;
61 bool failure = pcmk__ends_with(pcmk__xe_id(lrm_rsc_op),
62 "_last_failure_0");
63
64
65 crm_element_value_ms(lrm_rsc_op, PCMK_META_INTERVAL, &interval_ms);
66 effective_op = interval_ms == 0
71
72 if (best == NULL) {
73 goto is_best;
74 }
75
76 if (best_effective_op) {
77 // Do not use an ineffective op if there's an effective one.
78 if (!effective_op) {
79 continue;
80 }
81 // Do not use an ineffective non-recurring op if there's a recurring one
82 } else if (best_interval != 0
83 && !effective_op
84 && interval_ms == 0) {
85 continue;
86 }
87
88 // Do not use last failure if there's a successful one.
89 if (!best_failure && failure) {
90 continue;
91 }
92
93 // Do not use an op without a restart digest if there's one with.
94 if (best_digest != NULL && digest == NULL) {
95 continue;
96 }
97
98 // Do not use an older op if there's a newer one.
99 if (pe__is_newer_op(best, lrm_rsc_op) > 0) {
100 continue;
101 }
102
103is_best:
104 best = lrm_rsc_op;
105 best_effective_op = effective_op;
106 best_interval = interval_ms;
107 best_failure = failure;
108 best_digest = digest;
109 }
110 return best;
111}
112
124int
125pcmk__resource_delete(cib_t *cib, uint32_t cib_opts, const char *rsc_id,
126 const char *rsc_type)
127{
128 int rc = pcmk_rc_ok;
129 xmlNode *msg_data = NULL;
130
131 if (cib == NULL) {
132 return ENOTCONN;
133 }
134
135 if (rsc_id == NULL || rsc_type == NULL) {
136 return EINVAL;
137 }
138
139 msg_data = pcmk__xe_create(NULL, rsc_type);
140 crm_xml_add(msg_data, PCMK_XA_ID, rsc_id);
141
142 rc = cib->cmds->remove(cib, PCMK_XE_RESOURCES, msg_data, cib_opts);
143 rc = pcmk_legacy2rc(rc);
144
145 pcmk__xml_free(msg_data);
146 return rc;
147}
148
149int
150pcmk_resource_delete(xmlNodePtr *xml, const char *rsc_id, const char *rsc_type)
151{
152 pcmk__output_t *out = NULL;
153 int rc = pcmk_rc_ok;
154 uint32_t cib_opts = cib_sync_call;
155 cib_t *cib = NULL;
156
157 rc = pcmk__xml_output_new(&out, xml);
158 if (rc != pcmk_rc_ok) {
159 return rc;
160 }
161
162 cib = cib_new();
163 if (cib == NULL) {
165 goto done;
166 }
167
168 rc = cib->cmds->signon(cib, crm_system_name, cib_command);
169 rc = pcmk_legacy2rc(rc);
170
171 if (rc != pcmk_rc_ok) {
172 goto done;
173 }
174
175 rc = pcmk__resource_delete(cib, cib_opts, rsc_id, rsc_type);
176
177done:
178 if (cib != NULL) {
180 }
181
183 return rc;
184}
185
197int
199 const pcmk_node_t *node, GHashTable *overrides)
200{
201 const char *task = NULL;
202 xmlNode *xml_op = NULL;
203 pcmk__op_digest_t *digests = NULL;
204 guint interval_ms = 0;
205 int rc = pcmk_rc_ok;
206
207 if ((out == NULL) || (rsc == NULL) || (node == NULL)) {
208 return EINVAL;
209 }
210
211 if (!pcmk__is_primitive(rsc)) {
212 // Only primitives get operation digests
213 return EOPNOTSUPP;
214 }
215
216 // Find XML of operation history to use
217 xml_op = best_op(rsc, node);
218
219 // Generate an operation key
220 if (xml_op != NULL) {
221 task = crm_element_value(xml_op, PCMK_XA_OPERATION);
222 crm_element_value_ms(xml_op, PCMK_META_INTERVAL, &interval_ms);
223 }
224 if (task == NULL) { // Assume start if no history is available
225 task = PCMK_ACTION_START;
226 interval_ms = 0;
227 }
228
229 // Calculate and show digests
230 digests = pe__calculate_digests(rsc, task, &interval_ms, node, xml_op,
231 overrides, true, rsc->priv->scheduler);
232 rc = out->message(out, "digests", rsc, node, task, interval_ms, digests);
233
234 pe__free_digests(digests);
235 return rc;
236}
237
238int
240 const pcmk_node_t *node, GHashTable *overrides)
241{
242 pcmk__output_t *out = NULL;
243 int rc = pcmk_rc_ok;
244
245 rc = pcmk__xml_output_new(&out, xml);
246 if (rc != pcmk_rc_ok) {
247 return rc;
248 }
250 rc = pcmk__resource_digests(out, rsc, node, overrides);
252 return rc;
253}
#define PCMK_ACTION_PROMOTE
Definition actions.h:57
#define PCMK_ACTION_START
Definition actions.h:63
#define PCMK_ACTION_MIGRATE_FROM
Definition actions.h:49
#define PCMK_ACTION_MONITOR
Definition actions.h:51
int cib__clean_up_connection(cib_t **cib)
Definition cib_utils.c:942
cib_t * cib_new(void)
Create a new CIB connection object.
Definition cib_client.c:562
@ cib_command
Definition cib_types.h:46
@ cib_sync_call
Definition cib_types.h:112
char * crm_system_name
Definition utils.c:45
#define LOG_NEVER
Definition logging.h:48
Wrappers for and extensions to glib mainloop.
#define PCMK_META_INTERVAL
Definition options.h:92
Formatted output for pacemaker tools.
void pcmk__xml_output_finish(pcmk__output_t *out, crm_exit_t exit_status, xmlNodePtr *xml)
Definition output.c:273
int pcmk__xml_output_new(pcmk__output_t **out, xmlNodePtr *xml)
Definition output.c:246
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)
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:302
void pe__free_digests(gpointer ptr)
Definition pe_digest.c:33
int pe__is_newer_op(const xmlNode *xml_a, const xmlNode *xml_b)
Function and executable result codes.
@ pcmk_rc_ok
Definition results.h:159
@ pcmk_rc_cib_corrupt
Definition results.h:147
int pcmk_legacy2rc(int legacy_rc)
Definition results.c:675
crm_exit_t pcmk_rc2exitc(int rc)
Map a function return code to the most similar exit code.
Definition results.c:820
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1029
bool pcmk__ends_with(const char *s, const char *match)
Definition strings.c:610
int(* remove)(cib_t *cib, const char *section, xmlNode *data, int call_options)
Definition cib_types.h:174
int(* signon)(cib_t *cib, const char *name, enum cib_conn_type type)
Definition cib_types.h:124
cib_api_operations_t * cmds
Definition cib_types.h:325
This structure contains everything that makes up a single output formatter.
int(* message)(pcmk__output_t *out, const char *message_id,...)
pcmk_scheduler_t * scheduler
pcmk__resource_private_t * priv
Definition resources.h:61
xmlNode * input
Definition scheduler.h:81
pcmk__node_private_t * priv
Definition nodes.h:85
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
Retrieve the millisecond value of an XML attribute.
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition xml_element.c:43
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
void pcmk__xml_free(xmlNode *xml)
Definition xml.c:816
#define PCMK_XA_OPERATION
Definition xml_names.h:349
#define PCMK_XA_ID
Definition xml_names.h:301
#define PCMK_XE_RESOURCES
Definition xml_names.h:179
#define PCMK__XE_LRM_RSC_OP
#define PCMK__XA_OP_RESTART_DIGEST
xmlNode * pcmk__xpath_find_one(xmlDoc *doc, const char *path, uint8_t level)
Definition xpath.c:206