root/lib/fencing/st_lha.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. find_library_function
  2. stonith__agent_is_lha
  3. stonith__list_lha_agents
  4. stonith_plugin
  5. stonith__lha_metadata
  6. i_hate_pils
  7. stonith__lha_validate

   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"
  45     "    <" PCMK_XE_ACTION " " PCMK_XA_NAME "=\"" PCMK_ACTION_START "\""
  46                            " " PCMK_META_TIMEOUT "=\"%s\" />\n"
  47     "    <" PCMK_XE_ACTION " " PCMK_XA_NAME "=\"" PCMK_ACTION_STOP "\""
  48                            " " PCMK_META_TIMEOUT "=\"15s\" />\n"
  49     "    <" PCMK_XE_ACTION " " PCMK_XA_NAME "=\"" PCMK_ACTION_STATUS "\""
  50                            " " PCMK_META_TIMEOUT "=\"%s\" />\n"
  51     "    <" PCMK_XE_ACTION " " PCMK_XA_NAME "=\"" PCMK_ACTION_MONITOR "\""
  52                            " " PCMK_META_TIMEOUT "=\"%s\""
  53                            " " PCMK_META_INTERVAL "=\"3600s\" />\n"
  54     "    <" PCMK_XE_ACTION " " PCMK_XA_NAME "=\"" PCMK_ACTION_META_DATA "\""
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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 
  83 /*!
  84  * \internal
  85  * \brief Check whether a given fence agent is an LHA agent
  86  *
  87  * \param[in] agent        Fence agent type
  88  *
  89  * \return true if \p agent is an LHA agent, otherwise false
  90  */
  91 bool
  92 stonith__agent_is_lha(const char *agent)
     /* [previous][next][first][last][top][bottom][index][help] */
  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
 119 stonith__list_lha_agents(stonith_key_value_t **devices)
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
 132                                              LHA_STONITH_LIBRARY,
 133                                              "stonith_types");
 134         type_free_fn = find_library_function(&lha_agents_lib,
 135                                              LHA_STONITH_LIBRARY,
 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);
     /* [previous][next][first][last][top][bottom][index][help] */
 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     pcmk__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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
 252                                                  pcmk__xml_escape_text);
 253         }
 254         if (pcmk__xml_needs_escape(meta_shortdesc, pcmk__xml_escape_text)) {
 255             meta_shortdesc_esc = pcmk__xml_escape(meta_shortdesc,
 256                                                   pcmk__xml_escape_text);
 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          */
 263         timeout_str = pcmk__readable_interval(PCMK_DEFAULT_ACTION_TIMEOUT_MS);
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 297 {
 298     return PIL_strerror(rc);
 299 }
 300 
 301 int
 302 stonith__lha_validate(stonith_t *st, int call_options, const char *target,
     /* [previous][next][first][last][top][bottom][index][help] */
 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 }

/* [previous][next][first][last][top][bottom][index][help] */