root/lib/fencing/st_rhcs.c

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

DEFINITIONS

This source file includes following definitions.
  1. stonith__list_rhcs_agents
  2. stonith_rhcs_parameter_not_required
  3. stonith__rhcs_get_metadata
  4. stonith__rhcs_metadata
  5. stonith__agent_is_rhcs
  6. stonith__rhcs_validate

   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>
  20 #include <crm/fencing/internal.h>
  21 
  22 #include "fencing_private.h"
  23 
  24 #define RH_STONITH_PREFIX "fence_"
  25 
  26 /*!
  27  * \internal
  28  * \brief Add available RHCS-compatible agents to a list
  29  *
  30  * \param[in,out]  List to add to
  31  *
  32  * \return Number of agents added
  33  */
  34 int
  35 stonith__list_rhcs_agents(stonith_key_value_t **devices)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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 
 114 /*!
 115  * \brief Execute RHCS-compatible agent's metadata action
 116  *
 117  * \param[in]  agent        Agent to execute
 118  * \param[in]  timeout_sec  Action timeout
 119  * \param[out] metadata     Where to store output xmlNode (or NULL to ignore)
 120  */
 121 static int
 122 stonith__rhcs_get_metadata(const char *agent, int timeout_sec,
     /* [previous][next][first][last][top][bottom][index][help] */
 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);
 132     pcmk__action_result_t *result = stonith__action_result(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         }
 139         stonith__destroy_action(action);
 140         return rc;
 141     }
 142 
 143     if (result->execution_status != PCMK_EXEC_DONE) {
 144         crm_warn("Could not execute metadata action for %s: %s",
 145                  agent, pcmk_exec_status_str(result->execution_status));
 146         rc = pcmk_rc2legacy(stonith__result2rc(result));
 147         stonith__destroy_action(action);
 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);
 154         rc = pcmk_rc2legacy(stonith__result2rc(result));
 155         stonith__destroy_action(action);
 156         return rc;
 157     }
 158 
 159     if (result->action_stdout == NULL) {
 160         crm_warn("Metadata action for %s returned no data", agent);
 161         stonith__destroy_action(action);
 162         return -ENODATA;
 163     }
 164 
 165     xml = string2xml(result->action_stdout);
 166     stonith__destroy_action(action);
 167 
 168     if (xml == NULL) {
 169         crm_warn("Metadata for %s is invalid", agent);
 170         return -pcmk_err_schema_validation;
 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 
 209 /*!
 210  * \brief Retrieve metadata for RHCS-compatible fence agent
 211  *
 212  * \param[in]  agent        Agent to execute
 213  * \param[in]  timeout_sec  Action timeout
 214  * \param[out] output       Where to store action output (or NULL to ignore)
 215  */
 216 int
 217 stonith__rhcs_metadata(const char *agent, int timeout_sec, char **output)
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
 232         return -pcmk_err_schema_validation;
 233     }
 234     if (output) {
 235         *output = buffer;
 236     } else {
 237         free(buffer);
 238     }
 239     return pcmk_ok;
 240 }
 241 
 242 bool
 243 stonith__agent_is_rhcs(const char *agent)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 
 253 int
 254 stonith__rhcs_validate(stonith_t *st, int call_options, const char *target,
     /* [previous][next][first][last][top][bottom][index][help] */
 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;
 263     pcmk__action_result_t *result = 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);
 274             if (pcmk_is_set(device_flags, st_device_supports_parameter_port)) {
 275                 host_arg = "port";
 276 
 277             } else if (pcmk_is_set(device_flags,
 278                                    st_device_supports_parameter_plug)) {
 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 
 298     rc = stonith__execute(action);
 299     result = stonith__action_result(action);
 300 
 301     if (result != NULL) {
 302         rc = pcmk_rc2legacy(stonith__result2rc(result));
 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     }
 314     stonith__destroy_action(action);
 315     return rc;
 316 }

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