pacemaker 2.1.8-2.1.8
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
actions.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-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 Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11
12#ifndef _GNU_SOURCE
13# define _GNU_SOURCE
14#endif
15
16#include <stdio.h>
17#include <string.h>
18#include <stdlib.h>
19#include <sys/types.h>
20#include <ctype.h>
21
22#include <crm/crm.h>
23#include <crm/lrmd.h>
24#include <crm/common/xml.h>
26#include <crm/common/util.h>
28
36const char *
38{
39 switch (action) {
41 return PCMK_ACTION_STOP;
42
45
47 return PCMK_ACTION_START;
48
51
54
57
60
62 return PCMK_ACTION_NOTIFY;
63
66
69
72
74 return PCMK_ACTION_DEMOTE;
75
78
79 default: // pcmk_action_unspecified or invalid
80 return "no_action";
81 }
82}
83
91enum action_tasks
92pcmk_parse_action(const char *action_name)
93{
94 if (pcmk__str_eq(action_name, PCMK_ACTION_STOP, pcmk__str_none)) {
95 return pcmk_action_stop;
96
97 } else if (pcmk__str_eq(action_name, PCMK_ACTION_STOPPED, pcmk__str_none)) {
99
100 } else if (pcmk__str_eq(action_name, PCMK_ACTION_START, pcmk__str_none)) {
101 return pcmk_action_start;
102
103 } else if (pcmk__str_eq(action_name, PCMK_ACTION_RUNNING, pcmk__str_none)) {
104 return pcmk_action_started;
105
106 } else if (pcmk__str_eq(action_name, PCMK_ACTION_DO_SHUTDOWN,
109
110 } else if (pcmk__str_eq(action_name, PCMK_ACTION_STONITH, pcmk__str_none)) {
111 return pcmk_action_fence;
112
113 } else if (pcmk__str_eq(action_name, PCMK_ACTION_MONITOR, pcmk__str_none)) {
114 return pcmk_action_monitor;
115
116 } else if (pcmk__str_eq(action_name, PCMK_ACTION_NOTIFY, pcmk__str_none)) {
117 return pcmk_action_notify;
118
119 } else if (pcmk__str_eq(action_name, PCMK_ACTION_NOTIFIED,
122
123 } else if (pcmk__str_eq(action_name, PCMK_ACTION_PROMOTE, pcmk__str_none)) {
124 return pcmk_action_promote;
125
126 } else if (pcmk__str_eq(action_name, PCMK_ACTION_DEMOTE, pcmk__str_none)) {
127 return pcmk_action_demote;
128
129 } else if (pcmk__str_eq(action_name, PCMK_ACTION_PROMOTED,
132
133 } else if (pcmk__str_eq(action_name, PCMK_ACTION_DEMOTED, pcmk__str_none)) {
134 return pcmk_action_demoted;
135 }
137}
138
146const char *
148{
149 switch (on_fail) {
151 return "ignore";
152
154 return "demote";
155
157 return "block";
158
160 return "recover";
161
162 case pcmk_on_fail_ban:
163 return "migrate";
164
166 return "stop";
167
169 return "fence";
170
172 return "standby";
173
175 return "restart-container";
176
178 return "reset-remote";
179 }
180 return "<unknown>";
181}
182
195char *
196pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
197{
198 CRM_ASSERT(rsc_id != NULL);
199 CRM_ASSERT(op_type != NULL);
200 return crm_strdup_printf(PCMK__OP_FMT, rsc_id, op_type, interval_ms);
201}
202
203static inline gboolean
204convert_interval(const char *s, guint *interval_ms)
205{
206 unsigned long l;
207
208 errno = 0;
209 l = strtoul(s, NULL, 10);
210
211 if (errno != 0) {
212 return FALSE;
213 }
214
215 *interval_ms = (guint) l;
216 return TRUE;
217}
218
230static size_t
231match_before(const char *key, size_t position, const char **matches)
232{
233 for (int i = 0; matches[i] != NULL; ++i) {
234 const size_t match_len = strlen(matches[i]);
235
236 // Must have at least X_MATCH before position
237 if (position > (match_len + 1)) {
238 const size_t possible = position - match_len - 1;
239
240 if ((key[possible] == '_')
241 && (strncmp(key + possible + 1, matches[i], match_len) == 0)) {
242 return possible;
243 }
244 }
245 }
246 return 0;
247}
248
249gboolean
250parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
251{
252 guint local_interval_ms = 0;
253 const size_t key_len = (key == NULL)? 0 : strlen(key);
254
255 // Operation keys must be formatted as RSC_ACTION_INTERVAL
256 size_t action_underbar = 0; // Index in key of underbar before ACTION
257 size_t interval_underbar = 0; // Index in key of underbar before INTERVAL
258 size_t possible = 0;
259
260 /* Underbar was a poor choice of separator since both RSC and ACTION can
261 * contain underbars. Here, list action names and name prefixes that can.
262 */
263 const char *actions_with_underbars[] = {
266 NULL
267 };
268 const char *action_prefixes_with_underbars[] = {
269 "pre_" PCMK_ACTION_NOTIFY,
270 "post_" PCMK_ACTION_NOTIFY,
271 "confirmed-pre_" PCMK_ACTION_NOTIFY,
272 "confirmed-post_" PCMK_ACTION_NOTIFY,
273 NULL,
274 };
275
276 // Initialize output variables in case of early return
277 if (rsc_id) {
278 *rsc_id = NULL;
279 }
280 if (op_type) {
281 *op_type = NULL;
282 }
283 if (interval_ms) {
284 *interval_ms = 0;
285 }
286
287 // RSC_ACTION_INTERVAL implies a minimum of 5 characters
288 if (key_len < 5) {
289 return FALSE;
290 }
291
292 // Find, parse, and validate interval
293 interval_underbar = key_len - 2;
294 while ((interval_underbar > 2) && (key[interval_underbar] != '_')) {
295 --interval_underbar;
296 }
297 if ((interval_underbar == 2)
298 || !convert_interval(key + interval_underbar + 1, &local_interval_ms)) {
299 return FALSE;
300 }
301
302 // Find the base (OCF) action name, disregarding prefixes
303 action_underbar = match_before(key, interval_underbar,
304 actions_with_underbars);
305 if (action_underbar == 0) {
306 action_underbar = interval_underbar - 2;
307 while ((action_underbar > 0) && (key[action_underbar] != '_')) {
308 --action_underbar;
309 }
310 if (action_underbar == 0) {
311 return FALSE;
312 }
313 }
314 possible = match_before(key, action_underbar,
315 action_prefixes_with_underbars);
316 if (possible != 0) {
317 action_underbar = possible;
318 }
319
320 // Set output variables
321 if (rsc_id != NULL) {
322 *rsc_id = strndup(key, action_underbar);
323 pcmk__mem_assert(*rsc_id);
324 }
325 if (op_type != NULL) {
326 *op_type = strndup(key + action_underbar + 1,
327 interval_underbar - action_underbar - 1);
328 pcmk__mem_assert(*op_type);
329 }
330 if (interval_ms != NULL) {
331 *interval_ms = local_interval_ms;
332 }
333 return TRUE;
334}
335
336char *
337pcmk__notify_key(const char *rsc_id, const char *notify_type,
338 const char *op_type)
339{
340 CRM_CHECK(rsc_id != NULL, return NULL);
341 CRM_CHECK(op_type != NULL, return NULL);
342 CRM_CHECK(notify_type != NULL, return NULL);
343 return crm_strdup_printf("%s_%s_notify_%s_0",
344 rsc_id, notify_type, op_type);
345}
346
362gboolean
363decode_transition_magic(const char *magic, char **uuid, int *transition_id, int *action_id,
364 int *op_status, int *op_rc, int *target_rc)
365{
366 int res = 0;
367 char *key = NULL;
368 gboolean result = TRUE;
369 int local_op_status = -1;
370 int local_op_rc = -1;
371
372 CRM_CHECK(magic != NULL, return FALSE);
373
374#ifdef HAVE_SSCANF_M
375 res = sscanf(magic, "%d:%d;%ms", &local_op_status, &local_op_rc, &key);
376#else
377 // magic must have >=4 other characters
378 key = pcmk__assert_alloc(1, strlen(magic) - 3);
379 res = sscanf(magic, "%d:%d;%s", &local_op_status, &local_op_rc, key);
380#endif
381 if (res == EOF) {
382 crm_err("Could not decode transition information '%s': %s",
383 magic, pcmk_rc_str(errno));
384 result = FALSE;
385 } else if (res < 3) {
386 crm_warn("Transition information '%s' incomplete (%d of 3 expected items)",
387 magic, res);
388 result = FALSE;
389 } else {
390 if (op_status) {
391 *op_status = local_op_status;
392 }
393 if (op_rc) {
394 *op_rc = local_op_rc;
395 }
396 result = decode_transition_key(key, uuid, transition_id, action_id,
397 target_rc);
398 }
399 free(key);
400 return result;
401}
402
403char *
404pcmk__transition_key(int transition_id, int action_id, int target_rc,
405 const char *node)
406{
407 CRM_CHECK(node != NULL, return NULL);
408 return crm_strdup_printf("%d:%d:%d:%-*s",
409 action_id, transition_id, target_rc, 36, node);
410}
411
425gboolean
426decode_transition_key(const char *key, char **uuid, int *transition_id, int *action_id,
427 int *target_rc)
428{
429 int local_transition_id = -1;
430 int local_action_id = -1;
431 int local_target_rc = -1;
432 char local_uuid[37] = { '\0' };
433
434 // Initialize any supplied output arguments
435 if (uuid) {
436 *uuid = NULL;
437 }
438 if (transition_id) {
439 *transition_id = -1;
440 }
441 if (action_id) {
442 *action_id = -1;
443 }
444 if (target_rc) {
445 *target_rc = -1;
446 }
447
448 CRM_CHECK(key != NULL, return FALSE);
449 if (sscanf(key, "%d:%d:%d:%36s", &local_action_id, &local_transition_id,
450 &local_target_rc, local_uuid) != 4) {
451 crm_err("Invalid transition key '%s'", key);
452 return FALSE;
453 }
454 if (strlen(local_uuid) != 36) {
455 crm_warn("Invalid UUID '%s' in transition key '%s'", local_uuid, key);
456 }
457 if (uuid) {
458 *uuid = pcmk__str_copy(local_uuid);
459 }
460 if (transition_id) {
461 *transition_id = local_transition_id;
462 }
463 if (action_id) {
464 *action_id = local_action_id;
465 }
466 if (target_rc) {
467 *target_rc = local_target_rc;
468 }
469 return TRUE;
470}
471
472int
474{
475 int rc = 0;
476
477 if (op && op->user_data) {
478 decode_transition_key(op->user_data, NULL, NULL, NULL, &rc);
479 }
480 return rc;
481}
482
483gboolean
485{
486 switch (op->op_status) {
489 return FALSE;
490
493 case PCMK_EXEC_ERROR:
498 return TRUE;
499
500 default:
501 if (target_rc != op->rc) {
502 return TRUE;
503 }
504 }
505
506 return FALSE;
507}
508
520xmlNode *
521crm_create_op_xml(xmlNode *parent, const char *prefix, const char *task,
522 const char *interval_spec, const char *timeout)
523{
524 xmlNode *xml_op;
525
526 CRM_CHECK(prefix && task && interval_spec, return NULL);
527
529 crm_xml_set_id(xml_op, "%s-%s-%s", prefix, task, interval_spec);
530 crm_xml_add(xml_op, PCMK_META_INTERVAL, interval_spec);
531 crm_xml_add(xml_op, PCMK_XA_NAME, task);
532 if (timeout) {
534 }
535 return xml_op;
536}
537
547bool
548crm_op_needs_metadata(const char *rsc_class, const char *op)
549{
550 /* Agent metadata is used to determine whether an agent reload is possible,
551 * so if this op is not relevant to that feature, we don't need metadata.
552 */
553
554 CRM_CHECK((rsc_class != NULL) || (op != NULL), return false);
555
556 if ((rsc_class != NULL)
558 // Metadata is needed only for resource classes that use parameters
559 return false;
560 }
561 if (op == NULL) {
562 return true;
563 }
564
565 // Metadata is needed only for these actions
570 PCMK_ACTION_NOTIFY, NULL);
571}
572
582bool
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition actions.c:250
char * pcmk__notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition actions.c:337
const char * pcmk_on_fail_text(enum action_fail_response on_fail)
Get string equivalent of a failure handling type.
Definition actions.c:147
gboolean decode_transition_key(const char *key, char **uuid, int *transition_id, int *action_id, int *target_rc)
Parse a transition key into its constituent parts.
Definition actions.c:426
int rsc_op_expected_rc(const lrmd_event_data_t *op)
Definition actions.c:473
char * pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key (RESOURCE_ACTION_INTERVAL)
Definition actions.c:196
bool pcmk__is_fencing_action(const char *action)
Definition actions.c:583
xmlNode * crm_create_op_xml(xmlNode *parent, const char *prefix, const char *task, const char *interval_spec, const char *timeout)
Create a CIB XML element for an operation.
Definition actions.c:521
gboolean did_rsc_op_fail(lrmd_event_data_t *op, int target_rc)
Definition actions.c:484
char * pcmk__transition_key(int transition_id, int action_id, int target_rc, const char *node)
Definition actions.c:404
const char * pcmk_action_text(enum action_tasks action)
Get string equivalent of an action type.
Definition actions.c:37
enum action_tasks pcmk_parse_action(const char *action_name)
Parse an action type from an action name.
Definition actions.c:92
bool crm_op_needs_metadata(const char *rsc_class, const char *op)
Check whether an operation requires resource agent meta-data.
Definition actions.c:548
gboolean decode_transition_magic(const char *magic, char **uuid, int *transition_id, int *action_id, int *op_status, int *op_rc, int *target_rc)
Parse a transition magic string into its constituent parts.
Definition actions.c:363
#define PCMK_ACTION_PROMOTED
Definition actions.h:67
#define PCMK_ACTION_STOP
Definition actions.h:75
#define PCMK_ACTION_RUNNING
Definition actions.h:71
#define PCMK_ACTION_REBOOT
Definition actions.h:68
#define PCMK_ACTION_PROMOTE
Definition actions.h:66
#define PCMK_ACTION_START
Definition actions.h:72
#define PCMK_ACTION_NOTIFIED
Definition actions.h:61
action_fail_response
Definition actions.h:130
@ pcmk_on_fail_ban
Definition actions.h:150
@ pcmk_on_fail_fence_node
Definition actions.h:162
@ pcmk_on_fail_ignore
Definition actions.h:144
@ pcmk_on_fail_restart_container
Definition actions.h:167
@ pcmk_on_fail_demote
Definition actions.h:178
@ pcmk_on_fail_standby_node
Definition actions.h:159
@ pcmk_on_fail_block
Definition actions.h:153
@ pcmk_on_fail_reset_remote
Definition actions.h:175
@ pcmk_on_fail_stop
Definition actions.h:156
@ pcmk_on_fail_restart
Definition actions.h:147
#define PCMK_ACTION_MIGRATE_FROM
Definition actions.h:58
#define PCMK_ACTION_RELOAD
Definition actions.h:69
#define PCMK_ACTION_MIGRATE_TO
Definition actions.h:59
action_tasks
Definition actions.h:83
@ pcmk_action_start
Definition actions.h:92
@ pcmk_action_fence
Definition actions.h:105
@ pcmk_action_demote
Definition actions.h:101
@ pcmk_action_stopped
Definition actions.h:90
@ pcmk_action_promote
Definition actions.h:98
@ pcmk_action_started
Definition actions.h:93
@ pcmk_action_notified
Definition actions.h:96
@ pcmk_action_demoted
Definition actions.h:102
@ pcmk_action_stop
Definition actions.h:89
@ pcmk_action_shutdown
Definition actions.h:104
@ pcmk_action_unspecified
Definition actions.h:84
@ pcmk_action_promoted
Definition actions.h:99
@ pcmk_action_notify
Definition actions.h:95
@ pcmk_action_monitor
Definition actions.h:85
#define PCMK_ACTION_STOPPED
Definition actions.h:76
#define PCMK_ACTION_MONITOR
Definition actions.h:60
#define PCMK_ACTION_STONITH
Definition actions.h:74
#define PCMK_ACTION_RELOAD_AGENT
Definition actions.h:70
#define PCMK_ACTION_DEMOTED
Definition actions.h:50
#define PCMK_ACTION_OFF
Definition actions.h:63
#define PCMK_ACTION_DEMOTE
Definition actions.h:49
#define PCMK_ACTION_DO_SHUTDOWN
Definition actions.h:51
#define PCMK_ACTION_NOTIFY
Definition actions.h:62
#define PCMK__ACTION_POWEROFF
#define PCMK__OP_FMT
printf-style format to create operation key from resource, action, interval
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
Definition agents.c:31
@ pcmk_ra_cap_params
Definition agents.h:61
const char * parent
Definition cib.c:27
#define pcmk__assert_alloc(nmemb, size)
Definition internal.h:297
Utility functions.
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:98
A dumping ground.
#define crm_warn(fmt, args...)
Definition logging.h:392
#define CRM_CHECK(expr, failure_action)
Definition logging.h:245
#define crm_err(fmt, args...)
Definition logging.h:389
Resource agent executor.
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
#define PCMK_META_TIMEOUT
Definition options.h:114
unsigned int timeout
Definition pcmk_fence.c:32
const char * action
Definition pcmk_fence.c:30
pcmk__action_result_t result
Definition pcmk_fence.c:35
#define CRM_ASSERT(expr)
Definition results.h:42
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition results.c:501
@ PCMK_EXEC_CANCELLED
Action was cancelled.
Definition results.h:334
@ PCMK_EXEC_NO_SECRETS
Necessary CIB secrets are unavailable.
Definition results.h:344
@ PCMK_EXEC_INVALID
Action cannot be attempted (e.g. shutdown)
Definition results.h:342
@ PCMK_EXEC_ERROR
Execution failed, may be retried.
Definition results.h:337
@ PCMK_EXEC_NOT_SUPPORTED
Agent does not implement requested action.
Definition results.h:336
@ PCMK_EXEC_TIMEOUT
Action did not complete in time.
Definition results.h:335
@ PCMK_EXEC_PENDING
Action is in progress.
Definition results.h:332
@ PCMK_EXEC_NO_FENCE_DEVICE
No fence device is configured for target.
Definition results.h:343
@ PCMK_EXEC_NOT_CONNECTED
No connection to executor.
Definition results.h:341
#define pcmk__mem_assert(ptr)
Scheduler API.
op_status
@ pcmk__str_none
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1050
#define pcmk__str_copy(str)
const char * user_data
Definition lrmd_events.h:45
enum ocf_exitcode rc
Definition lrmd_events.h:63
Wrappers for and extensions to libxml2.
void crm_xml_set_id(xmlNode *xml, const char *format,...) G_GNUC_PRINTF(2
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition xml.c:720
#define PCMK_XA_NAME
Definition xml_names.h:325
#define PCMK_XE_OP
Definition xml_names.h:143