pacemaker 2.1.5-a3f44794f94
Scalable High-Availability cluster resource manager
st_rhcs.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2022 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>
21
22#include "fencing_private.h"
23
24#define RH_STONITH_PREFIX "fence_"
25
34int
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
92static void
93stonith_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
121static int
122stonith__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
184 tmp = create_xml_node(actions, "action");
185 crm_xml_add(tmp, "name", "stop");
186 crm_xml_add(tmp, "timeout", CRM_DEFAULT_OP_TIMEOUT_S);
187
188 tmp = create_xml_node(actions, "action");
189 crm_xml_add(tmp, "name", "start");
190 crm_xml_add(tmp, "timeout", CRM_DEFAULT_OP_TIMEOUT_S);
191 }
192 freeXpathObject(xpathObj);
193
194 // Fudge metadata so parameters are not required in config (pacemaker adds them)
195 stonith_rhcs_parameter_not_required(xml, "action");
196 stonith_rhcs_parameter_not_required(xml, "plug");
197 stonith_rhcs_parameter_not_required(xml, "port");
198
199 if (metadata) {
200 *metadata = xml;
201
202 } else {
203 free_xml(xml);
204 }
205
206 return pcmk_ok;
207}
208
216int
217stonith__rhcs_metadata(const char *agent, int timeout_sec, char **output)
218{
219 char *buffer = NULL;
220 xmlNode *xml = NULL;
221
222 int rc = stonith__rhcs_get_metadata(agent, timeout_sec, &xml);
223
224 if (rc != pcmk_ok) {
225 free_xml(xml);
226 return rc;
227 }
228
229 buffer = dump_xml_formatted_with_text(xml);
230 free_xml(xml);
231 if (buffer == NULL) {
233 }
234 if (output) {
235 *output = buffer;
236 } else {
237 free(buffer);
238 }
239 return pcmk_ok;
240}
241
242bool
243stonith__agent_is_rhcs(const char *agent)
244{
245 struct stat prop;
246 char *buffer = crm_strdup_printf(PCMK__FENCE_BINDIR "/%s", agent);
247 int rc = stat(buffer, &prop);
248
249 free(buffer);
250 return (rc >= 0) && S_ISREG(prop.st_mode);
251}
252
253int
254stonith__rhcs_validate(stonith_t *st, int call_options, const char *target,
255 const char *agent, GHashTable *params,
256 const char * host_arg, int timeout,
257 char **output, char **error_output)
258{
259 int rc = pcmk_ok;
260 int remaining_timeout = timeout;
261 xmlNode *metadata = NULL;
262 stonith_action_t *action = NULL;
264
265 if (host_arg == NULL) {
266 time_t start_time = time(NULL);
267
268 rc = stonith__rhcs_get_metadata(agent, remaining_timeout, &metadata);
269
270 if (rc == pcmk_ok) {
271 uint32_t device_flags = 0;
272
273 stonith__device_parameter_flags(&device_flags, agent, metadata);
275 host_arg = "port";
276
277 } else if (pcmk_is_set(device_flags,
279 host_arg = "plug";
280 }
281 }
282
283 free_xml(metadata);
284
285 remaining_timeout -= time(NULL) - start_time;
286
287 if (rc == -ETIME || remaining_timeout <= 0 ) {
288 return -ETIME;
289 }
290
291 } else if (pcmk__str_eq(host_arg, PCMK__VALUE_NONE, pcmk__str_casei)) {
292 host_arg = NULL;
293 }
294
295 action = stonith__action_create(agent, "validate-all", target, 0,
296 remaining_timeout, params, NULL, host_arg);
297
300
301 if (result != NULL) {
303
304 // Take ownership of output so stonith__destroy_action() doesn't free it
305 if (output != NULL) {
306 *output = result->action_stdout;
307 result->action_stdout = NULL;
308 }
309 if (error_output != NULL) {
310 *error_output = result->action_stderr;
311 result->action_stderr = NULL;
312 }
313 }
315 return rc;
316}
#define CRM_DEFAULT_OP_TIMEOUT_S
Definition: util.h:76
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:121
#define PCMK__FENCE_BINDIR
Definition: config.h:538
A dumping ground.
@ st_device_supports_parameter_port
Definition: internal.h:25
@ st_device_supports_parameter_plug
Definition: internal.h:24
void stonith__destroy_action(stonith_action_t *action)
Definition: st_actions.c:217
void stonith__device_parameter_flags(uint32_t *device_flags, const char *device_name, xmlNode *metadata)
Definition: st_client.c:2386
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
pcmk__action_result_t * stonith__action_result(stonith_action_t *action)
Definition: st_actions.c:242
struct stonith_action_s stonith_action_t
Definition: internal.h:51
int stonith__result2rc(const pcmk__action_result_t *result)
Definition: st_actions.c:330
G_GNUC_INTERNAL int stonith__execute(stonith_action_t *action)
Definition: st_actions.c:698
#define crm_warn(fmt, args...)
Definition: logging.h:360
#define CRM_XS
Definition: logging.h:55
#define crm_notice(fmt, args...)
Definition: logging.h:361
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
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:323
#define PCMK__VALUE_NONE
unsigned int timeout
Definition: pcmk_fence.c:32
stonith_t * st
Definition: pcmk_fence.c:28
const char * action
Definition: pcmk_fence.c:30
pcmk__action_result_t result
Definition: pcmk_fence.c:35
const char * target
Definition: pcmk_fence.c:29
#define ENODATA
Definition: portability.h:145
int alphasort(const void *dirent1, const void *dirent2)
#define ETIME
Definition: portability.h:150
const char * pcmk_strerror(int rc)
Definition: results.c:148
#define pcmk_err_schema_validation
Definition: results.h:73
#define pcmk_ok
Definition: results.h:68
int pcmk_rc2legacy(int rc)
Definition: results.c:521
@ PCMK_EXEC_DONE
Action completed, result is known.
Definition: results.h:312
bool stonith__agent_is_rhcs(const char *agent)
Definition: st_rhcs.c:243
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:254
#define RH_STONITH_PREFIX
Definition: st_rhcs.c:24
int stonith__rhcs_metadata(const char *agent, int timeout_sec, char **output)
Retrieve metadata for RHCS-compatible fence agent.
Definition: st_rhcs.c:217
int stonith__list_rhcs_agents(stonith_key_value_t **devices)
Definition: st_rhcs.c:35
Fencing aka. STONITH.
stonith_key_value_t * stonith_key_value_add(stonith_key_value_t *kvp, const char *key, const char *value)
Definition: st_client.c:1915
bool pcmk__starts_with(const char *str, const char *prefix)
Check whether a string starts with a certain sequence.
Definition: strings.c:484
@ pcmk__str_casei
enum pcmk_exec_status execution_status
xmlXPathObjectPtr xpath_search(xmlNode *xml_top, const char *path)
Definition: xpath.c:139
char * dump_xml_formatted_with_text(xmlNode *msg)
Definition: xml.c:2089
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
Definition: xpath.c:58
void freeXpathObject(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:39
xmlNode * string2xml(const char *input)
Definition: xml.c:930
void free_xml(xmlNode *child)
Definition: xml.c:885
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:749