pacemaker  2.1.9-49aab99839
Scalable High-Availability cluster resource manager
st_rhcs.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 #include <stdio.h>
13 #include <string.h>
14 #include <sys/stat.h>
15 #include <glib.h>
16 #include <dirent.h>
17 
18 #include <crm/crm.h>
19 #include <crm/common/xml.h>
20 #include <crm/stonith-ng.h>
21 #include <crm/fencing/internal.h>
22 
23 #include "fencing_private.h"
24 
25 #define RH_STONITH_PREFIX "fence_"
26 
35 int
37 {
38  // Essentially: ls -1 @sbin_dir@/fence_*
39 
40  int count = 0, i;
41  struct dirent **namelist;
42  const int file_num = scandir(PCMK__FENCE_BINDIR, &namelist, 0, alphasort);
43 
44 #if _POSIX_C_SOURCE < 200809L && !(defined(O_SEARCH) || defined(O_PATH))
45  char buffer[FILENAME_MAX + 1];
46 #elif defined(O_SEARCH)
47  const int dirfd = open(PCMK__FENCE_BINDIR, O_SEARCH);
48 #else
49  const int dirfd = open(PCMK__FENCE_BINDIR, O_PATH);
50 #endif
51 
52  for (i = 0; i < file_num; i++) {
53  struct stat prop;
54 
55  if (pcmk__starts_with(namelist[i]->d_name, RH_STONITH_PREFIX)) {
56 #if _POSIX_C_SOURCE < 200809L && !(defined(O_SEARCH) || defined(O_PATH))
57  snprintf(buffer, sizeof(buffer), "%s/%s", PCMK__FENCE_BINDIR,
58  namelist[i]->d_name);
59  if (stat(buffer, &prop) == 0 && S_ISREG(prop.st_mode)) {
60 #else
61  if (dirfd == -1) {
62  if (i == 0) {
63  crm_notice("Problem with listing %s directory "
64  CRM_XS " errno=%d", RH_STONITH_PREFIX, errno);
65  }
66  free(namelist[i]);
67  continue;
68  }
69  /* note: we can possibly prevent following symlinks here,
70  which may be a good idea, but fall on the nose when
71  these agents are moved elsewhere & linked back */
72  if (fstatat(dirfd, namelist[i]->d_name, &prop, 0) == 0
73  && S_ISREG(prop.st_mode)) {
74 #endif
75  *devices = stonith_key_value_add(*devices, NULL,
76  namelist[i]->d_name);
77  count++;
78  }
79  }
80  free(namelist[i]);
81  }
82  if (file_num > 0) {
83  free(namelist);
84  }
85 #if _POSIX_C_SOURCE >= 200809L || defined(O_SEARCH) || defined(O_PATH)
86  if (dirfd >= 0) {
87  close(dirfd);
88  }
89 #endif
90  return count;
91 }
92 
93 static void
94 stonith_rhcs_parameter_not_required(xmlNode *metadata, const char *parameter)
95 {
96  char *xpath = NULL;
97  xmlXPathObject *xpathObj = NULL;
98 
99  CRM_CHECK(metadata != NULL, return);
100  CRM_CHECK(parameter != NULL, return);
101 
102  xpath = crm_strdup_printf("//" PCMK_XE_PARAMETER "[@" PCMK_XA_NAME "='%s']",
103  parameter);
104  /* Fudge metadata so that the parameter isn't required in config
105  * Pacemaker handles and adds it */
106  xpathObj = xpath_search(metadata, xpath);
107  if (numXpathResults(xpathObj) > 0) {
108  xmlNode *tmp = getXpathResult(xpathObj, 0);
109 
110  crm_xml_add(tmp, "required", "0");
111  }
112  freeXpathObject(xpathObj);
113  free(xpath);
114 }
115 
123 static int
124 stonith__rhcs_get_metadata(const char *agent, int timeout_sec,
125  xmlNode **metadata)
126 {
127  xmlNode *xml = NULL;
128  xmlNode *actions = NULL;
129  xmlXPathObject *xpathObj = NULL;
132  NULL, 0, timeout_sec,
133  NULL, NULL, NULL);
134  int rc = stonith__execute(action);
136 
137  if (result == NULL) {
138  if (rc < 0) {
139  crm_warn("Could not execute metadata action for %s: %s "
140  CRM_XS " rc=%d", agent, pcmk_strerror(rc), rc);
141  }
143  return rc;
144  }
145 
147  crm_warn("Could not execute metadata action for %s: %s",
148  agent, pcmk_exec_status_str(result->execution_status));
151  return rc;
152  }
153 
154  if (!pcmk__result_ok(result)) {
155  crm_warn("Metadata action for %s returned error code %d",
156  agent, result->exit_status);
159  return rc;
160  }
161 
162  if (result->action_stdout == NULL) {
163  crm_warn("Metadata action for %s returned no data", agent);
165  return -ENODATA;
166  }
167 
170 
171  if (xml == NULL) {
172  crm_warn("Metadata for %s is invalid", agent);
174  }
175 
176  xpathObj = xpath_search(xml, "//" PCMK_XE_ACTIONS);
177  if (numXpathResults(xpathObj) > 0) {
178  actions = getXpathResult(xpathObj, 0);
179  }
180  freeXpathObject(xpathObj);
181 
182  // Add start and stop (implemented by pacemaker, not agent) to meta-data
183  xpathObj = xpath_search(xml,
184  "//" PCMK_XE_ACTION
185  "[@" PCMK_XA_NAME "='" PCMK_ACTION_STOP "']");
186  if (numXpathResults(xpathObj) <= 0) {
187  xmlNode *tmp = NULL;
188  const char *timeout_str = NULL;
189 
191 
192  tmp = pcmk__xe_create(actions, PCMK_XE_ACTION);
194  crm_xml_add(tmp, PCMK_META_TIMEOUT, timeout_str);
195 
196  tmp = pcmk__xe_create(actions, PCMK_XE_ACTION);
198  crm_xml_add(tmp, PCMK_META_TIMEOUT, timeout_str);
199  }
200  freeXpathObject(xpathObj);
201 
202  // Fudge metadata so parameters are not required in config (pacemaker adds them)
203  stonith_rhcs_parameter_not_required(xml, "action");
204  stonith_rhcs_parameter_not_required(xml, "plug");
205  stonith_rhcs_parameter_not_required(xml, "port");
206 
207  if (metadata) {
208  *metadata = xml;
209 
210  } else {
211  free_xml(xml);
212  }
213 
214  return pcmk_ok;
215 }
216 
224 int
225 stonith__rhcs_metadata(const char *agent, int timeout_sec, char **output)
226 {
227  GString *buffer = NULL;
228  xmlNode *xml = NULL;
229 
230  int rc = stonith__rhcs_get_metadata(agent, timeout_sec, &xml);
231 
232  if (rc != pcmk_ok) {
233  goto done;
234  }
235 
236  buffer = g_string_sized_new(1024);
238 
239  if (pcmk__str_empty(buffer->str)) {
241  goto done;
242  }
243 
244  if (output != NULL) {
245  pcmk__str_update(output, buffer->str);
246  }
247 
248 done:
249  if (buffer != NULL) {
250  g_string_free(buffer, TRUE);
251  }
252  free_xml(xml);
253  return rc;
254 }
255 
256 bool
257 stonith__agent_is_rhcs(const char *agent)
258 {
259  struct stat prop;
260  char *buffer = crm_strdup_printf(PCMK__FENCE_BINDIR "/%s", agent);
261  int rc = stat(buffer, &prop);
262 
263  free(buffer);
264  return (rc >= 0) && S_ISREG(prop.st_mode);
265 }
266 
267 int
268 stonith__rhcs_validate(stonith_t *st, int call_options, const char *target,
269  const char *agent, GHashTable *params,
270  const char * host_arg, int timeout,
271  char **output, char **error_output)
272 {
273  int rc = pcmk_ok;
274  int remaining_timeout = timeout;
275  xmlNode *metadata = NULL;
276  stonith_action_t *action = NULL;
278 
279  if (host_arg == NULL) {
280  time_t start_time = time(NULL);
281 
282  rc = stonith__rhcs_get_metadata(agent, remaining_timeout, &metadata);
283 
284  if (rc == pcmk_ok) {
285  uint32_t device_flags = 0;
286 
287  stonith__device_parameter_flags(&device_flags, agent, metadata);
288  if (pcmk_is_set(device_flags, st_device_supports_parameter_port)) {
289  host_arg = "port";
290 
291  } else if (pcmk_is_set(device_flags,
293  host_arg = "plug";
294  }
295  }
296 
297  free_xml(metadata);
298 
299  remaining_timeout -= time(NULL) - start_time;
300 
301  if (rc == -ETIME || remaining_timeout <= 0 ) {
302  return -ETIME;
303  }
304 
305  } else if (pcmk__str_eq(host_arg, PCMK_VALUE_NONE, pcmk__str_casei)) {
306  host_arg = NULL;
307  }
308 
310  remaining_timeout, params, NULL, host_arg);
311 
312  rc = stonith__execute(action);
314 
315  if (result != NULL) {
317 
318  // Take ownership of output so stonith__destroy_action() doesn't free it
319  if (output != NULL) {
320  *output = result->action_stdout;
321  result->action_stdout = NULL;
322  }
323  if (error_output != NULL) {
324  *error_output = result->action_stderr;
325  result->action_stderr = NULL;
326  }
327  }
329  return rc;
330 }
void stonith__destroy_action(stonith_action_t *action)
Definition: st_actions.c:215
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:245
struct stonith_action_s stonith_action_t
Definition: internal.h:51
#define pcmk_err_schema_validation
Definition: results.h:71
A dumping ground.
#define crm_notice(fmt, args...)
Definition: logging.h:397
bool stonith__agent_is_rhcs(const char *agent)
Definition: st_rhcs.c:257
const char * pcmk_strerror(int rc)
Definition: results.c:151
#define ETIME
Definition: portability.h:111
#define PCMK_XA_NAME
Definition: xml_names.h:330
#define PCMK__FENCE_BINDIR
Definition: config.h:565
int pcmk_rc2legacy(int rc)
Definition: results.c:548
void pcmk__xml_string(const xmlNode *data, uint32_t options, GString *buffer, int depth)
Definition: xml_io.c:490
int stonith__result2rc(const pcmk__action_result_t *result)
Definition: st_actions.c:326
enum pcmk_exec_status execution_status
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:313
int stonith__rhcs_validate(stonith_t *st, int call_options, const char *target, const char *agent, GHashTable *params, const char *host_arg, int timeout, char **output, char **error_output)
Definition: st_rhcs.c:268
Include indentation and newlines.
Definition: xml_internal.h:140
const char * action
Definition: pcmk_fence.c:30
stonith_key_value_t * stonith_key_value_add(stonith_key_value_t *kvp, const char *key, const char *value)
Definition: st_client.c:1933
#define PCMK_DEFAULT_ACTION_TIMEOUT_MS
Default timeout (in milliseconds) for non-metadata actions.
Definition: actions.h:38
#define crm_warn(fmt, args...)
Definition: logging.h:394
stonith_t * st
Definition: pcmk_fence.c:28
void stonith__device_parameter_flags(uint32_t *device_flags, const char *device_name, xmlNode *metadata)
Definition: st_client.c:2405
pcmk__action_result_t * stonith__action_result(stonith_action_t *action)
Definition: st_actions.c:240
#define PCMK_XE_PARAMETER
Definition: xml_names.h:158
#define PCMK_VALUE_NONE
Definition: options.h:178
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:94
#define PCMK_ACTION_START
Definition: actions.h:72
void pcmk__str_update(char **str, const char *value)
Definition: strings.c:1289
Wrappers for and extensions to libxml2.
Action completed, result is known.
Definition: results.h:329
#define PCMK_ACTION_STOP
Definition: actions.h:75
void free_xml(xmlNode *child)
Definition: xml.c:958
xmlNode * pcmk__xml_parse(const char *input)
Definition: xml_io.c:245
#define PCMK_META_TIMEOUT
Definition: options.h:114
const char * target
Definition: pcmk_fence.c:29
#define CRM_XS
Definition: logging.h:56
#define ENODATA
Definition: portability.h:106
xmlXPathObjectPtr xpath_search(const xmlNode *xml_top, const char *path)
Definition: xpath.c:139
#define RH_STONITH_PREFIX
Definition: st_rhcs.c:25
pcmk__action_result_t result
Definition: pcmk_fence.c:35
int stonith__list_rhcs_agents(stonith_key_value_t **devices)
Definition: st_rhcs.c:36
#define PCMK_XE_ACTION
Definition: xml_names.h:60
Fencing aka. STONITH.
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
Definition: xpath.c:58
#define PCMK_ACTION_METADATA
Definition: actions.h:57
#define PCMK_XE_ACTIONS
Definition: xml_names.h:61
stonith_action_t * stonith__action_create(const char *agent, const char *action_name, const char *target, uint32_t target_nodeid, int timeout_sec, GHashTable *device_args, GHashTable *port_map, const char *host_arg)
Definition: st_actions.c:263
int stonith__rhcs_metadata(const char *agent, int timeout_sec, char **output)
Retrieve metadata for RHCS-compatible fence agent.
Definition: st_rhcs.c:225
Include XML text nodes.
Definition: xml_internal.h:153
#define pcmk_ok
Definition: results.h:65
#define PCMK_ACTION_VALIDATE_ALL
Definition: actions.h:77
const char * pcmk__readable_interval(guint interval_ms)
Definition: iso8601.c:2206
bool pcmk__starts_with(const char *str, const char *prefix)
Check whether a string starts with a certain sequence.
Definition: strings.c:568
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition: xml.c:770
void freeXpathObject(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:39
unsigned int timeout
Definition: pcmk_fence.c:32
G_GNUC_INTERNAL int stonith__execute(stonith_action_t *action)
Definition: st_actions.c:694