pacemaker  2.1.8-3980678f03
Scalable High-Availability cluster resource manager
st_lha.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 <stdarg.h>
14 #include <string.h>
15 #include <errno.h>
16 #include <glib.h>
17 #include <dlfcn.h>
18 
19 #include <crm/crm.h>
20 #include <crm/stonith-ng.h>
21 #include <crm/fencing/internal.h>
22 #include <crm/common/xml.h>
23 
24 #include <stonith/stonith.h>
25 
26 #include "fencing_private.h"
27 
28 #define LHA_STONITH_LIBRARY "libstonith.so.1"
29 
30 static void *lha_agents_lib = NULL;
31 
32 // @TODO Use XML string constants and maybe a real XML object
33 static const char META_TEMPLATE[] =
34  "<?xml " PCMK_XA_VERSION "=\"1.0\"?>\n"
35  "<" PCMK_XE_RESOURCE_AGENT " " PCMK_XA_NAME "=\"%s\">\n"
36  " <" PCMK_XE_VERSION ">1.1</" PCMK_XE_VERSION ">\n"
37  " <" PCMK_XE_LONGDESC " " PCMK_XA_LANG "=\"" PCMK__VALUE_EN "\">\n"
38  "%s\n"
39  " </" PCMK_XE_LONGDESC ">\n"
40  " <" PCMK_XE_SHORTDESC " " PCMK_XA_LANG "=\"" PCMK__VALUE_EN "\">"
41  "%s"
42  "</" PCMK_XE_SHORTDESC ">\n"
43  "%s\n"
44  " <" PCMK_XE_ACTIONS ">\n"
46  " " PCMK_META_TIMEOUT "=\"%s\" />\n"
47  " <" PCMK_XE_ACTION " " PCMK_XA_NAME "=\"" PCMK_ACTION_STOP "\""
48  " " PCMK_META_TIMEOUT "=\"15s\" />\n"
50  " " PCMK_META_TIMEOUT "=\"%s\" />\n"
52  " " PCMK_META_TIMEOUT "=\"%s\""
53  " " PCMK_META_INTERVAL "=\"3600s\" />\n"
55  " " PCMK_META_TIMEOUT "=\"15s\" />\n"
56  " </" PCMK_XE_ACTIONS ">\n"
57  " <" PCMK_XE_SPECIAL " " PCMK_XA_TAG "=\"heartbeat\">\n"
58  " <" PCMK_XE_VERSION ">2.0</" PCMK_XE_VERSION ">\n"
59  " </" PCMK_XE_SPECIAL ">\n"
60  "</" PCMK_XE_RESOURCE_AGENT ">\n";
61 
62 static void *
63 find_library_function(void **handle, const char *lib, const char *fn)
64 {
65  void *a_function;
66 
67  if (*handle == NULL) {
68  *handle = dlopen(lib, RTLD_LAZY);
69  if ((*handle) == NULL) {
70  crm_err("Could not open %s: %s", lib, dlerror());
71  return NULL;
72  }
73  }
74 
75  a_function = dlsym(*handle, fn);
76  if (a_function == NULL) {
77  crm_err("Could not find %s in %s: %s", fn, lib, dlerror());
78  }
79 
80  return a_function;
81 }
82 
91 bool
92 stonith__agent_is_lha(const char *agent)
93 {
94  Stonith *stonith_obj = NULL;
95 
96  static bool need_init = true;
97  static Stonith *(*st_new_fn) (const char *) = NULL;
98  static void (*st_del_fn) (Stonith *) = NULL;
99 
100  if (need_init) {
101  need_init = false;
102  st_new_fn = find_library_function(&lha_agents_lib, LHA_STONITH_LIBRARY,
103  "stonith_new");
104  st_del_fn = find_library_function(&lha_agents_lib, LHA_STONITH_LIBRARY,
105  "stonith_delete");
106  }
107 
108  if (lha_agents_lib && st_new_fn && st_del_fn) {
109  stonith_obj = (*st_new_fn) (agent);
110  if (stonith_obj) {
111  (*st_del_fn) (stonith_obj);
112  return true;
113  }
114  }
115  return false;
116 }
117 
118 int
120 {
121  static gboolean need_init = TRUE;
122 
123  int count = 0;
124  char **entry = NULL;
125  char **type_list = NULL;
126  static char **(*type_list_fn) (void) = NULL;
127  static void (*type_free_fn) (char **) = NULL;
128 
129  if (need_init) {
130  need_init = FALSE;
131  type_list_fn = find_library_function(&lha_agents_lib,
133  "stonith_types");
134  type_free_fn = find_library_function(&lha_agents_lib,
136  "stonith_free_hostlist");
137  }
138 
139  if (type_list_fn) {
140  type_list = (*type_list_fn) ();
141  }
142 
143  for (entry = type_list; entry != NULL && *entry; ++entry) {
144  crm_trace("Added: %s", *entry);
145  *devices = stonith_key_value_add(*devices, NULL, *entry);
146  count++;
147  }
148  if (type_list && type_free_fn) {
149  (*type_free_fn) (type_list);
150  }
151  return count;
152 }
153 
154 static void
155 stonith_plugin(int priority, const char *fmt, ...) G_GNUC_PRINTF(2, 3);
156 
157 static void
158 stonith_plugin(int priority, const char *format, ...)
159 {
160  int err = errno;
161 
162  va_list ap;
163  int len = 0;
164  char *string = NULL;
165 
166  va_start(ap, format);
167 
168  len = vasprintf (&string, format, ap);
169  va_end(ap);
170  CRM_ASSERT(len > 0);
171 
172  do_crm_log_alias(priority, __FILE__, __func__, __LINE__, "%s", string);
173 
174  free(string);
175  errno = err;
176 }
177 
178 int
179 stonith__lha_metadata(const char *agent, int timeout, char **output)
180 {
181  int rc = 0;
182  char *buffer = NULL;
183  static const char *no_parameter_info = "<!-- no value -->";
184 
185  Stonith *stonith_obj = NULL;
186 
187  static gboolean need_init = TRUE;
188  static Stonith *(*st_new_fn) (const char *) = NULL;
189  static const char *(*st_info_fn) (Stonith *, int) = NULL;
190  static void (*st_del_fn) (Stonith *) = NULL;
191  static void (*st_log_fn) (Stonith *, PILLogFun) = NULL;
192 
193  if (need_init) {
194  need_init = FALSE;
195  st_new_fn = find_library_function(&lha_agents_lib, LHA_STONITH_LIBRARY,
196  "stonith_new");
197  st_del_fn = find_library_function(&lha_agents_lib, LHA_STONITH_LIBRARY,
198  "stonith_delete");
199  st_log_fn = find_library_function(&lha_agents_lib, LHA_STONITH_LIBRARY,
200  "stonith_set_log");
201  st_info_fn = find_library_function(&lha_agents_lib, LHA_STONITH_LIBRARY,
202  "stonith_get_info");
203  }
204 
205  if (lha_agents_lib && st_new_fn && st_del_fn && st_info_fn && st_log_fn) {
206  char *meta_longdesc = NULL;
207  char *meta_shortdesc = NULL;
208  char *meta_param = NULL;
209  const char *timeout_str = NULL;
210 
211  gchar *meta_longdesc_esc = NULL;
212  gchar *meta_shortdesc_esc = NULL;
213 
214  stonith_obj = st_new_fn(agent);
215  if (stonith_obj != NULL) {
216  st_log_fn(stonith_obj, (PILLogFun) &stonith_plugin);
217 
218  /* A st_info_fn() may free any existing output buffer every time
219  * when it's called. Copy the output every time.
220  */
221  meta_longdesc = pcmk__str_copy(st_info_fn(stonith_obj,
222  ST_DEVICEDESCR));
223  if (meta_longdesc == NULL) {
224  crm_warn("no long description in %s's metadata.", agent);
225  meta_longdesc = pcmk__str_copy(no_parameter_info);
226  }
227 
228  meta_shortdesc = pcmk__str_copy(st_info_fn(stonith_obj,
229  ST_DEVICEID));
230  if (meta_shortdesc == NULL) {
231  crm_warn("no short description in %s's metadata.", agent);
232  meta_shortdesc = pcmk__str_copy(no_parameter_info);
233  }
234 
235  meta_param = pcmk__str_copy(st_info_fn(stonith_obj,
236  ST_CONF_XML));
237  if (meta_param == NULL) {
238  crm_warn("no list of parameters in %s's metadata.", agent);
239  meta_param = pcmk__str_copy(no_parameter_info);
240  }
241 
242  st_del_fn(stonith_obj);
243 
244  } else {
245  errno = EINVAL;
246  crm_perror(LOG_ERR, "Agent %s not found", agent);
247  return -EINVAL;
248  }
249 
250  if (pcmk__xml_needs_escape(meta_longdesc, pcmk__xml_escape_text)) {
251  meta_longdesc_esc = pcmk__xml_escape(meta_longdesc,
253  }
254  if (pcmk__xml_needs_escape(meta_shortdesc, pcmk__xml_escape_text)) {
255  meta_shortdesc_esc = pcmk__xml_escape(meta_shortdesc,
257  }
258 
259  /* @TODO This needs a string that's parsable by crm_get_msec(). In
260  * general, pcmk__readable_interval() doesn't provide that. It works
261  * here because PCMK_DEFAULT_ACTION_TIMEOUT_MS is 20000 -> "20s".
262  */
264  buffer = crm_strdup_printf(META_TEMPLATE, agent,
265  ((meta_longdesc_esc != NULL) ?
266  meta_longdesc_esc : meta_longdesc),
267  ((meta_shortdesc_esc != NULL) ?
268  meta_shortdesc_esc : meta_shortdesc),
269  meta_param, timeout_str, timeout_str,
270  timeout_str);
271 
272  g_free(meta_longdesc_esc);
273  g_free(meta_shortdesc_esc);
274 
275  free(meta_longdesc);
276  free(meta_shortdesc);
277  free(meta_param);
278  }
279  if (output) {
280  *output = buffer;
281  } else {
282  free(buffer);
283  }
284  return rc;
285 }
286 
287 /* Implement a dummy function that uses -lpils so that linkers don't drop the
288  * reference.
289  */
290 
291 #include <pils/plugin.h>
292 
293 const char *i_hate_pils(int rc);
294 
295 const char *
296 i_hate_pils(int rc)
297 {
298  return PIL_strerror(rc);
299 }
300 
301 int
302 stonith__lha_validate(stonith_t *st, int call_options, const char *target,
303  const char *agent, GHashTable *params, int timeout,
304  char **output, char **error_output)
305 {
306  errno = EOPNOTSUPP;
307  crm_perror(LOG_ERR, "Cannot validate Linux-HA fence agents");
308  return -EOPNOTSUPP;
309 }
A dumping ground.
char * pcmk__xml_escape(const char *text, enum pcmk__xml_escape_type type)
Definition: xml.c:1110
#define PCMK_XA_NAME
Definition: xml_names.h:325
#define PCMK_XA_TAG
Definition: xml_names.h:412
bool pcmk__xml_needs_escape(const char *text, enum pcmk__xml_escape_type type)
Definition: xml.c:1028
int stonith__lha_validate(stonith_t *st, int call_options, const char *target, const char *agent, GHashTable *params, int timeout, char **output, char **error_output)
Definition: st_lha.c:302
#define PCMK_ACTION_META_DATA
Definition: actions.h:56
#define PCMK_ACTION_MONITOR
Definition: actions.h:60
int stonith__lha_metadata(const char *agent, int timeout, char **output)
Definition: st_lha.c:179
#define LHA_STONITH_LIBRARY
Definition: st_lha.c:28
#define do_crm_log_alias(level, file, function, line, fmt, args...)
Log a message as if it came from a different code location.
Definition: logging.h:300
#define PCMK_XE_LONGDESC
Definition: xml_names.h:126
const char * i_hate_pils(int rc)
Definition: st_lha.c:296
int stonith__list_lha_agents(stonith_key_value_t **devices)
Definition: st_lha.c:119
stonith_key_value_t * stonith_key_value_add(stonith_key_value_t *kvp, const char *key, const char *value)
Definition: st_client.c:1932
#define PCMK_ACTION_STATUS
Definition: actions.h:73
#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
#define PCMK_XE_VERSION
Definition: xml_names.h:215
stonith_t * st
Definition: pcmk_fence.c:28
#define PCMK__VALUE_EN
#define crm_trace(fmt, args...)
Definition: logging.h:404
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define PCMK_ACTION_START
Definition: actions.h:72
Wrappers for and extensions to libxml2.
#define PCMK_ACTION_STOP
Definition: actions.h:75
#define pcmk__str_copy(str)
#define PCMK_META_TIMEOUT
Definition: options.h:114
#define PCMK_XE_SHORTDESC
Definition: xml_names.h:195
const char * target
Definition: pcmk_fence.c:29
#define PCMK_XE_RESOURCE_AGENT
Definition: xml_names.h:169
#define PCMK_META_INTERVAL
Definition: options.h:91
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:331
#define crm_err(fmt, args...)
Definition: logging.h:391
#define CRM_ASSERT(expr)
Definition: results.h:42
#define PCMK_XE_ACTION
Definition: xml_names.h:60
Fencing aka. STONITH.
#define PCMK_XE_ACTIONS
Definition: xml_names.h:61
bool stonith__agent_is_lha(const char *agent)
Definition: st_lha.c:92
const char * pcmk__readable_interval(guint interval_ms)
Definition: iso8601.c:2134
#define PCMK_XA_LANG
Definition: xml_names.h:308
unsigned int timeout
Definition: pcmk_fence.c:32
#define PCMK_XE_SPECIAL
Definition: xml_names.h:197
#define PCMK_XA_VERSION
Definition: xml_names.h:439