pacemaker  2.1.7-0f7f88312f
Scalable High-Availability cluster resource manager
st_rhcs.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2023 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/stonith-ng.h>
20 #include <crm/fencing/internal.h>
21 
22 #include "fencing_private.h"
23 
24 #define RH_STONITH_PREFIX "fence_"
25 
34 int
36 {
37  // Essentially: ls -1 @sbin_dir@/fence_*
38 
39  int count = 0, i;
40  struct dirent **namelist;
41  const int file_num = scandir(PCMK__FENCE_BINDIR, &namelist, 0, alphasort);
42 
43 #if _POSIX_C_SOURCE < 200809L && !(defined(O_SEARCH) || defined(O_PATH))
44  char buffer[FILENAME_MAX + 1];
45 #elif defined(O_SEARCH)
46  const int dirfd = open(PCMK__FENCE_BINDIR, O_SEARCH);
47 #else
48  const int dirfd = open(PCMK__FENCE_BINDIR, O_PATH);
49 #endif
50 
51  for (i = 0; i < file_num; i++) {
52  struct stat prop;
53 
54  if (pcmk__starts_with(namelist[i]->d_name, RH_STONITH_PREFIX)) {
55 #if _POSIX_C_SOURCE < 200809L && !(defined(O_SEARCH) || defined(O_PATH))
56  snprintf(buffer, sizeof(buffer), "%s/%s", PCMK__FENCE_BINDIR,
57  namelist[i]->d_name);
58  if (stat(buffer, &prop) == 0 && S_ISREG(prop.st_mode)) {
59 #else
60  if (dirfd == -1) {
61  if (i == 0) {
62  crm_notice("Problem with listing %s directory"
63  CRM_XS "errno=%d", RH_STONITH_PREFIX, errno);
64  }
65  free(namelist[i]);
66  continue;
67  }
68  /* note: we can possibly prevent following symlinks here,
69  which may be a good idea, but fall on the nose when
70  these agents are moved elsewhere & linked back */
71  if (fstatat(dirfd, namelist[i]->d_name, &prop, 0) == 0
72  && S_ISREG(prop.st_mode)) {
73 #endif
74  *devices = stonith_key_value_add(*devices, NULL,
75  namelist[i]->d_name);
76  count++;
77  }
78  }
79  free(namelist[i]);
80  }
81  if (file_num > 0) {
82  free(namelist);
83  }
84 #if _POSIX_C_SOURCE >= 200809L || defined(O_SEARCH) || defined(O_PATH)
85  if (dirfd >= 0) {
86  close(dirfd);
87  }
88 #endif
89  return count;
90 }
91 
92 static void
93 stonith_rhcs_parameter_not_required(xmlNode *metadata, const char *parameter)
94 {
95  char *xpath = NULL;
96  xmlXPathObject *xpathObj = NULL;
97 
98  CRM_CHECK(metadata != NULL, return);
99  CRM_CHECK(parameter != NULL, return);
100 
101  xpath = crm_strdup_printf("//parameter[@name='%s']", parameter);
102  /* Fudge metadata so that the parameter isn't required in config
103  * Pacemaker handles and adds it */
104  xpathObj = xpath_search(metadata, xpath);
105  if (numXpathResults(xpathObj) > 0) {
106  xmlNode *tmp = getXpathResult(xpathObj, 0);
107 
108  crm_xml_add(tmp, "required", "0");
109  }
110  freeXpathObject(xpathObj);
111  free(xpath);
112 }
113 
121 static int
122 stonith__rhcs_get_metadata(const char *agent, int timeout_sec,
123  xmlNode **metadata)
124 {
125  xmlNode *xml = NULL;
126  xmlNode *actions = NULL;
127  xmlXPathObject *xpathObj = NULL;
128  stonith_action_t *action = stonith__action_create(agent, "metadata", NULL,
129  0, timeout_sec, NULL,
130  NULL, NULL);
131  int rc = stonith__execute(action);
133 
134  if (result == NULL) {
135  if (rc < 0) {
136  crm_warn("Could not execute metadata action for %s: %s "
137  CRM_XS " rc=%d", agent, pcmk_strerror(rc), rc);
138  }
140  return rc;
141  }
142 
144  crm_warn("Could not execute metadata action for %s: %s",
145  agent, pcmk_exec_status_str(result->execution_status));
148  return rc;
149  }
150 
151  if (!pcmk__result_ok(result)) {
152  crm_warn("Metadata action for %s returned error code %d",
153  agent, result->exit_status);
156  return rc;
157  }
158 
159  if (result->action_stdout == NULL) {
160  crm_warn("Metadata action for %s returned no data", agent);
162  return -ENODATA;
163  }
164 
167 
168  if (xml == NULL) {
169  crm_warn("Metadata for %s is invalid", agent);
171  }
172 
173  xpathObj = xpath_search(xml, "//actions");
174  if (numXpathResults(xpathObj) > 0) {
175  actions = getXpathResult(xpathObj, 0);
176  }
177  freeXpathObject(xpathObj);
178 
179  // Add start and stop (implemented by pacemaker, not agent) to meta-data
180  xpathObj = xpath_search(xml, "//action[@name='stop']");
181  if (numXpathResults(xpathObj) <= 0) {
182  xmlNode *tmp = NULL;
183  const char *timeout_str = NULL;
184 
186 
187  tmp = create_xml_node(actions, "action");
188  crm_xml_add(tmp, "name", PCMK_ACTION_STOP);
189  crm_xml_add(tmp, "timeout", timeout_str);
190 
191  tmp = create_xml_node(actions, "action");
192  crm_xml_add(tmp, "name", PCMK_ACTION_START);
193  crm_xml_add(tmp, "timeout", timeout_str);
194  }
195  freeXpathObject(xpathObj);
196 
197  // Fudge metadata so parameters are not required in config (pacemaker adds them)
198  stonith_rhcs_parameter_not_required(xml, "action");
199  stonith_rhcs_parameter_not_required(xml, "plug");
200  stonith_rhcs_parameter_not_required(xml, "port");
201 
202  if (metadata) {
203  *metadata = xml;
204 
205  } else {
206  free_xml(xml);
207  }
208 
209  return pcmk_ok;
210 }
211 
219 int
220 stonith__rhcs_metadata(const char *agent, int timeout_sec, char **output)
221 {
222  char *buffer = NULL;
223  xmlNode *xml = NULL;
224 
225  int rc = stonith__rhcs_get_metadata(agent, timeout_sec, &xml);
226 
227  if (rc != pcmk_ok) {
228  free_xml(xml);
229  return rc;
230  }
231 
232  buffer = dump_xml_formatted_with_text(xml);
233  free_xml(xml);
234  if (buffer == NULL) {
236  }
237  if (output) {
238  *output = buffer;
239  } else {
240  free(buffer);
241  }
242  return pcmk_ok;
243 }
244 
245 bool
246 stonith__agent_is_rhcs(const char *agent)
247 {
248  struct stat prop;
249  char *buffer = crm_strdup_printf(PCMK__FENCE_BINDIR "/%s", agent);
250  int rc = stat(buffer, &prop);
251 
252  free(buffer);
253  return (rc >= 0) && S_ISREG(prop.st_mode);
254 }
255 
256 int
257 stonith__rhcs_validate(stonith_t *st, int call_options, const char *target,
258  const char *agent, GHashTable *params,
259  const char * host_arg, int timeout,
260  char **output, char **error_output)
261 {
262  int rc = pcmk_ok;
263  int remaining_timeout = timeout;
264  xmlNode *metadata = NULL;
265  stonith_action_t *action = NULL;
267 
268  if (host_arg == NULL) {
269  time_t start_time = time(NULL);
270 
271  rc = stonith__rhcs_get_metadata(agent, remaining_timeout, &metadata);
272 
273  if (rc == pcmk_ok) {
274  uint32_t device_flags = 0;
275 
276  stonith__device_parameter_flags(&device_flags, agent, metadata);
277  if (pcmk_is_set(device_flags, st_device_supports_parameter_port)) {
278  host_arg = "port";
279 
280  } else if (pcmk_is_set(device_flags,
282  host_arg = "plug";
283  }
284  }
285 
286  free_xml(metadata);
287 
288  remaining_timeout -= time(NULL) - start_time;
289 
290  if (rc == -ETIME || remaining_timeout <= 0 ) {
291  return -ETIME;
292  }
293 
294  } else if (pcmk__str_eq(host_arg, PCMK__VALUE_NONE, pcmk__str_casei)) {
295  host_arg = NULL;
296  }
297 
299  remaining_timeout, params, NULL, host_arg);
300 
301  rc = stonith__execute(action);
303 
304  if (result != NULL) {
306 
307  // Take ownership of output so stonith__destroy_action() doesn't free it
308  if (output != NULL) {
309  *output = result->action_stdout;
310  result->action_stdout = NULL;
311  }
312  if (error_output != NULL) {
313  *error_output = result->action_stderr;
314  result->action_stderr = NULL;
315  }
316  }
318  return rc;
319 }
void stonith__destroy_action(stonith_action_t *action)
Definition: st_actions.c:217
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:238
struct stonith_action_s stonith_action_t
Definition: internal.h:51
#define pcmk_err_schema_validation
Definition: results.h:73
A dumping ground.
#define crm_notice(fmt, args...)
Definition: logging.h:383
bool stonith__agent_is_rhcs(const char *agent)
Definition: st_rhcs.c:246
const char * pcmk_strerror(int rc)
Definition: results.c:149
#define ETIME
Definition: portability.h:111
#define PCMK__FENCE_BINDIR
Definition: config.h:559
int pcmk_rc2legacy(int rc)
Definition: results.c:546
int stonith__result2rc(const pcmk__action_result_t *result)
Definition: st_actions.c:330
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:302
#define PCMK__VALUE_NONE
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:257
const char * action
Definition: pcmk_fence.c:30
xmlNode * string2xml(const char *input)
Definition: xml.c:800
stonith_key_value_t * stonith_key_value_add(stonith_key_value_t *kvp, const char *key, const char *value)
Definition: st_client.c:1927
#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:382
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:2400
pcmk__action_result_t * stonith__action_result(stonith_action_t *action)
Definition: st_actions.c:242
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:99
#define PCMK_ACTION_START
Definition: actions.h:71
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:638
Action completed, result is known.
Definition: results.h:318
#define PCMK_ACTION_STOP
Definition: actions.h:74
void free_xml(xmlNode *child)
Definition: xml.c:783
char * dump_xml_formatted_with_text(const xmlNode *xml)
Definition: xml.c:1632
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:24
pcmk__action_result_t result
Definition: pcmk_fence.c:35
int stonith__list_rhcs_agents(stonith_key_value_t **devices)
Definition: st_rhcs.c:35
Fencing aka. STONITH.
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
Definition: xpath.c:58
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:265
int stonith__rhcs_metadata(const char *agent, int timeout_sec, char **output)
Retrieve metadata for RHCS-compatible fence agent.
Definition: st_rhcs.c:220
#define pcmk_ok
Definition: results.h:68
#define PCMK_ACTION_VALIDATE_ALL
Definition: actions.h:76
const char * pcmk__readable_interval(guint interval_ms)
Definition: iso8601.c:1926
bool pcmk__starts_with(const char *str, const char *prefix)
Check whether a string starts with a certain sequence.
Definition: strings.c:481
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:698