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-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 
  24 /*!
  25  * \internal
  26  * \brief Add available RHCS-compatible agents to a list
  27  *
  28  * \param[in,out]  List to add to
  29  *
  30  * \return Number of agents added
  31  */
  32 int
  33 stonith__list_rhcs_agents(stonith_key_value_t **devices)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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 
 112 /*!
 113  * \brief Execute RHCS-compatible agent's meta-data action
 114  *
 115  * \param[in]  agent    Agent to execute
 116  * \param[in]  timeout  Action timeout
 117  * \param[out] metadata Where to store output xmlNode (or NULL to ignore)
 118  *
 119  * \todo timeout is currently ignored; shouldn't we use it?
 120  */
 121 static int
 122 stonith__rhcs_get_metadata(const char *agent, int timeout, xmlNode **metadata)
     /* [previous][next][first][last][top][bottom][index][help] */
 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);
 135         stonith__destroy_action(action);
 136         return rc;
 137     }
 138 
 139     stonith__action_result(action, &rc, &buffer, NULL);
 140     stonith__destroy_action(action);
 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);
 158         return -pcmk_err_schema_validation;
 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 
 197 /*!
 198  * \brief Execute RHCS-compatible agent's meta-data action
 199  *
 200  * \param[in]  agent    Agent to execute
 201  * \param[in]  timeout  Action timeout
 202  * \param[out] output   Where to store action output (or NULL to ignore)
 203  *
 204  * \todo timeout is currently ignored; shouldn't we use it?
 205  */
 206 int
 207 stonith__rhcs_metadata(const char *agent, int timeout, char **output)
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
 222         return -pcmk_err_schema_validation;
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
 267                                    st_device_supports_parameter_plug)) {
 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 
 288     rc = stonith__execute(action);
 289     if (rc == pcmk_ok) {
 290         stonith__action_result(action, &rc, output, error_output);
 291     }
 292     stonith__destroy_action(action);
 293     return rc;
 294 }

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