pacemaker  2.0.5-ba59be712
Scalable High-Availability cluster resource manager
st_rhcs.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2020 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 #define RH_STONITH_PREFIX "fence_"
23 
32 int
34 {
35  // Essentially: ls -1 @sbin_dir@/fence_*
36 
37  int count = 0, i;
38  struct dirent **namelist;
39  const int file_num = scandir(PCMK__FENCE_BINDIR, &namelist, 0, alphasort);
40 
41 #if _POSIX_C_SOURCE < 200809L && !(defined(O_SEARCH) || defined(O_PATH))
42  char buffer[FILENAME_MAX + 1];
43 #elif defined(O_SEARCH)
44  const int dirfd = open(PCMK__FENCE_BINDIR, O_SEARCH);
45 #else
46  const int dirfd = open(PCMK__FENCE_BINDIR, O_PATH);
47 #endif
48 
49  for (i = 0; i < file_num; i++) {
50  struct stat prop;
51 
52  if (pcmk__starts_with(namelist[i]->d_name, RH_STONITH_PREFIX)) {
53 #if _POSIX_C_SOURCE < 200809L && !(defined(O_SEARCH) || defined(O_PATH))
54  snprintf(buffer, sizeof(buffer), "%s/%s", PCMK__FENCE_BINDIR,
55  namelist[i]->d_name);
56  if (stat(buffer, &prop) == 0 && S_ISREG(prop.st_mode)) {
57 #else
58  if (dirfd == -1) {
59  if (i == 0) {
60  crm_notice("Problem with listing %s directory"
61  CRM_XS "errno=%d", RH_STONITH_PREFIX, errno);
62  }
63  free(namelist[i]);
64  continue;
65  }
66  /* note: we can possibly prevent following symlinks here,
67  which may be a good idea, but fall on the nose when
68  these agents are moved elsewhere & linked back */
69  if (fstatat(dirfd, namelist[i]->d_name, &prop, 0) == 0
70  && S_ISREG(prop.st_mode)) {
71 #endif
72  *devices = stonith_key_value_add(*devices, NULL,
73  namelist[i]->d_name);
74  count++;
75  }
76  }
77  free(namelist[i]);
78  }
79  if (file_num > 0) {
80  free(namelist);
81  }
82 #if _POSIX_C_SOURCE >= 200809L || defined(O_SEARCH) || defined(O_PATH)
83  if (dirfd >= 0) {
84  close(dirfd);
85  }
86 #endif
87  return count;
88 }
89 
90 static void
91 stonith_rhcs_parameter_not_required(xmlNode *metadata, const char *parameter)
92 {
93  char *xpath = NULL;
94  xmlXPathObject *xpathObj = NULL;
95 
96  CRM_CHECK(metadata != NULL, return);
97  CRM_CHECK(parameter != NULL, return);
98 
99  xpath = crm_strdup_printf("//parameter[@name='%s']", parameter);
100  /* Fudge metadata so that the parameter isn't required in config
101  * Pacemaker handles and adds it */
102  xpathObj = xpath_search(metadata, xpath);
103  if (numXpathResults(xpathObj) > 0) {
104  xmlNode *tmp = getXpathResult(xpathObj, 0);
105 
106  crm_xml_add(tmp, "required", "0");
107  }
108  freeXpathObject(xpathObj);
109  free(xpath);
110 }
111 
121 static int
122 stonith__rhcs_get_metadata(const char *agent, int timeout, xmlNode **metadata)
123 {
124  char *buffer = NULL;
125  xmlNode *xml = NULL;
126  xmlNode *actions = NULL;
127  xmlXPathObject *xpathObj = NULL;
128  stonith_action_t *action = stonith_action_create(agent, "metadata", NULL, 0,
129  5, NULL, NULL, NULL);
130  int rc = stonith__execute(action);
131 
132  if (rc < 0) {
133  crm_warn("Could not execute metadata action for %s: %s "
134  CRM_XS " rc=%d", agent, pcmk_strerror(rc), rc);
136  return rc;
137  }
138 
139  stonith__action_result(action, &rc, &buffer, NULL);
141  if (rc < 0) {
142  crm_warn("Metadata action for %s failed: %s " CRM_XS "rc=%d",
143  agent, pcmk_strerror(rc), rc);
144  free(buffer);
145  return rc;
146  }
147 
148  if (buffer == NULL) {
149  crm_warn("Metadata action for %s returned no data", agent);
150  return -ENODATA;
151  }
152 
153  xml = string2xml(buffer);
154  free(buffer);
155  buffer = NULL;
156  if (xml == NULL) {
157  crm_warn("Metadata for %s is invalid", agent);
159  }
160 
161  xpathObj = xpath_search(xml, "//actions");
162  if (numXpathResults(xpathObj) > 0) {
163  actions = getXpathResult(xpathObj, 0);
164  }
165  freeXpathObject(xpathObj);
166 
167  // Add start and stop (implemented by pacemaker, not agent) to meta-data
168  xpathObj = xpath_search(xml, "//action[@name='stop']");
169  if (numXpathResults(xpathObj) <= 0) {
170  xmlNode *tmp = NULL;
171 
172  tmp = create_xml_node(actions, "action");
173  crm_xml_add(tmp, "name", "stop");
174  crm_xml_add(tmp, "timeout", CRM_DEFAULT_OP_TIMEOUT_S);
175 
176  tmp = create_xml_node(actions, "action");
177  crm_xml_add(tmp, "name", "start");
178  crm_xml_add(tmp, "timeout", CRM_DEFAULT_OP_TIMEOUT_S);
179  }
180  freeXpathObject(xpathObj);
181 
182  // Fudge metadata so parameters are not required in config (pacemaker adds them)
183  stonith_rhcs_parameter_not_required(xml, "action");
184  stonith_rhcs_parameter_not_required(xml, "plug");
185  stonith_rhcs_parameter_not_required(xml, "port");
186 
187  if (metadata) {
188  *metadata = xml;
189 
190  } else {
191  free_xml(xml);
192  }
193 
194  return pcmk_ok;
195 }
196 
206 int
207 stonith__rhcs_metadata(const char *agent, int timeout, char **output)
208 {
209  char *buffer = NULL;
210  xmlNode *xml = NULL;
211 
212  int rc = stonith__rhcs_get_metadata(agent, timeout, &xml);
213 
214  if (rc != pcmk_ok) {
215  free_xml(xml);
216  return rc;
217  }
218 
219  buffer = dump_xml_formatted_with_text(xml);
220  free_xml(xml);
221  if (buffer == NULL) {
223  }
224  if (output) {
225  *output = buffer;
226  } else {
227  free(buffer);
228  }
229  return pcmk_ok;
230 }
231 
232 bool
233 stonith__agent_is_rhcs(const char *agent)
234 {
235  struct stat prop;
236  char *buffer = crm_strdup_printf(PCMK__FENCE_BINDIR "/%s", agent);
237  int rc = stat(buffer, &prop);
238 
239  free(buffer);
240  return (rc >= 0) && S_ISREG(prop.st_mode);
241 }
242 
243 int
244 stonith__rhcs_validate(stonith_t *st, int call_options, const char *target,
245  const char *agent, GHashTable *params,
246  const char * host_arg, int timeout,
247  char **output, char **error_output)
248 {
249  int rc = pcmk_ok;
250  int remaining_timeout = timeout;
251  xmlNode *metadata = NULL;
252  stonith_action_t *action = NULL;
253 
254  if (host_arg == NULL) {
255  time_t start_time = time(NULL);
256 
257  rc = stonith__rhcs_get_metadata(agent, remaining_timeout, &metadata);
258 
259  if (rc == pcmk_ok) {
260  uint32_t device_flags = 0;
261 
262  stonith__device_parameter_flags(&device_flags, agent, metadata);
263  if (pcmk_is_set(device_flags, st_device_supports_parameter_port)) {
264  host_arg = "port";
265 
266  } else if (pcmk_is_set(device_flags,
268  host_arg = "plug";
269  }
270  }
271 
272  free_xml(metadata);
273 
274  remaining_timeout -= time(NULL) - start_time;
275 
276  if (rc == -ETIME || remaining_timeout <= 0 ) {
277  return -ETIME;
278  }
279 
280  } else if (pcmk__str_eq(host_arg, "none", pcmk__str_casei)) {
281  host_arg = NULL;
282  }
283 
284  action = stonith_action_create(agent, "validate-all",
285  target, 0, remaining_timeout, params,
286  NULL, host_arg);
287 
289  if (rc == pcmk_ok) {
290  stonith__action_result(action, &rc, output, error_output);
291  }
293  return rc;
294 }
void stonith__destroy_action(stonith_action_t *action)
Definition: st_client.c:582
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:215
struct stonith_action_s stonith_action_t
Definition: internal.h:50
#define pcmk_err_schema_validation
Definition: results.h:72
A dumping ground.
#define crm_notice(fmt, args...)
Definition: logging.h:349
bool stonith__agent_is_rhcs(const char *agent)
Definition: st_rhcs.c:233
const char * pcmk_strerror(int rc)
Definition: results.c:58
#define ETIME
Definition: portability.h:165
void stonith__action_result(stonith_action_t *action, int *rc, char **output, char **error_output)
Definition: st_client.c:613
#define PCMK__FENCE_BINDIR
Definition: config.h:544
int stonith__execute(stonith_action_t *action)
Definition: st_client.c:897
int alphasort(const void *dirent1, const void *dirent2)
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:317
stonith_action_t * stonith_action_create(const char *agent, const char *_action, const char *victim, uint32_t victim_nodeid, int timeout, GHashTable *device_args, GHashTable *port_map, const char *host_arg)
Definition: st_client.c:642
int stonith__rhcs_metadata(const char *agent, int timeout, char **output)
Execute RHCS-compatible agent's meta-data action.
Definition: st_rhcs.c:207
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:244
const char * action
Definition: pcmk_fence.c:30
xmlNode * string2xml(const char *input)
Definition: xml.c:835
stonith_key_value_t * stonith_key_value_add(stonith_key_value_t *kvp, const char *key, const char *value)
Definition: st_client.c:2207
#define crm_warn(fmt, args...)
Definition: logging.h:348
stonith_t * st
Definition: pcmk_fence.c:28
int rc
Definition: pcmk_fence.c:35
void stonith__device_parameter_flags(uint32_t *device_flags, const char *device_name, xmlNode *metadata)
Definition: st_client.c:2660
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:196
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:663
#define CRM_DEFAULT_OP_TIMEOUT_S
Definition: util.h:134
void free_xml(xmlNode *child)
Definition: xml.c:790
const char * target
Definition: pcmk_fence.c:29
#define CRM_XS
Definition: logging.h:54
#define ENODATA
Definition: portability.h:161
#define RH_STONITH_PREFIX
Definition: st_rhcs.c:22
int stonith__list_rhcs_agents(stonith_key_value_t **devices)
Definition: st_rhcs.c:33
xmlXPathObjectPtr xpath_search(xmlNode *xml_top, const char *path)
Definition: xpath.c:138
Fencing aka. STONITH.
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
Definition: xpath.c:57
#define pcmk_ok
Definition: results.h:67
bool pcmk__starts_with(const char *str, const char *prefix)
Check whether a string starts with a certain sequence.
Definition: strings.c:452
void freeXpathObject(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:38
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
unsigned int timeout
Definition: pcmk_fence.c:32
char * dump_xml_formatted_with_text(xmlNode *msg)
Definition: xml.c:1977