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 #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 meta-data action
 116  *
 117  * \param[in]  agent    Agent to execute
 118  * \param[in]  timeout  Action timeout
 119  * \param[out] metadata Where to store output xmlNode (or NULL to ignore)
 120  *
 121  * \todo timeout is currently ignored; shouldn't we use it?
 122  */
 123 static int
 124 stonith__rhcs_get_metadata(const char *agent, int timeout, xmlNode **metadata)
     /* [previous][next][first][last][top][bottom][index][help] */
 125 {
 126     char *buffer = NULL;
 127     xmlNode *xml = NULL;
 128     xmlNode *actions = NULL;
 129     xmlXPathObject *xpathObj = NULL;
 130     stonith_action_t *action = stonith_action_create(agent, "metadata", NULL, 0,
 131                                                      5, NULL, NULL, NULL);
 132     int rc = stonith__execute(action);
 133 
 134     if (rc < 0) {
 135         crm_warn("Could not execute metadata action for %s: %s "
 136                  CRM_XS " rc=%d", agent, pcmk_strerror(rc), rc);
 137         stonith__destroy_action(action);
 138         return rc;
 139     }
 140 
 141     stonith__action_result(action, &rc, &buffer, NULL);
 142     stonith__destroy_action(action);
 143     if (rc < 0) {
 144         crm_warn("Metadata action for %s failed: %s " CRM_XS "rc=%d",
 145                  agent, pcmk_strerror(rc), rc);
 146         free(buffer);
 147         return rc;
 148     }
 149 
 150     if (buffer == NULL) {
 151         crm_warn("Metadata action for %s returned no data", agent);
 152         return -ENODATA;
 153     }
 154 
 155     xml = string2xml(buffer);
 156     free(buffer);
 157     buffer = NULL;
 158     if (xml == NULL) {
 159         crm_warn("Metadata for %s is invalid", agent);
 160         return -pcmk_err_schema_validation;
 161     }
 162 
 163     xpathObj = xpath_search(xml, "//actions");
 164     if (numXpathResults(xpathObj) > 0) {
 165         actions = getXpathResult(xpathObj, 0);
 166     }
 167     freeXpathObject(xpathObj);
 168 
 169     // Add start and stop (implemented by pacemaker, not agent) to meta-data
 170     xpathObj = xpath_search(xml, "//action[@name='stop']");
 171     if (numXpathResults(xpathObj) <= 0) {
 172         xmlNode *tmp = NULL;
 173 
 174         tmp = create_xml_node(actions, "action");
 175         crm_xml_add(tmp, "name", "stop");
 176         crm_xml_add(tmp, "timeout", CRM_DEFAULT_OP_TIMEOUT_S);
 177 
 178         tmp = create_xml_node(actions, "action");
 179         crm_xml_add(tmp, "name", "start");
 180         crm_xml_add(tmp, "timeout", CRM_DEFAULT_OP_TIMEOUT_S);
 181     }
 182     freeXpathObject(xpathObj);
 183 
 184     // Fudge metadata so parameters are not required in config (pacemaker adds them)
 185     stonith_rhcs_parameter_not_required(xml, "action");
 186     stonith_rhcs_parameter_not_required(xml, "plug");
 187     stonith_rhcs_parameter_not_required(xml, "port");
 188 
 189     if (metadata) {
 190         *metadata = xml;
 191 
 192     } else {
 193         free_xml(xml);
 194     }
 195 
 196     return pcmk_ok;
 197 }
 198 
 199 /*!
 200  * \brief Execute RHCS-compatible agent's meta-data action
 201  *
 202  * \param[in]  agent    Agent to execute
 203  * \param[in]  timeout  Action timeout
 204  * \param[out] output   Where to store action output (or NULL to ignore)
 205  *
 206  * \todo timeout is currently ignored; shouldn't we use it?
 207  */
 208 int
 209 stonith__rhcs_metadata(const char *agent, int timeout, char **output)
     /* [previous][next][first][last][top][bottom][index][help] */
 210 {
 211     char *buffer = NULL;
 212     xmlNode *xml = NULL;
 213 
 214     int rc = stonith__rhcs_get_metadata(agent, timeout, &xml);
 215 
 216     if (rc != pcmk_ok) {
 217         free_xml(xml);
 218         return rc;
 219     }
 220 
 221     buffer = dump_xml_formatted_with_text(xml);
 222     free_xml(xml);
 223     if (buffer == NULL) {
 224         return -pcmk_err_schema_validation;
 225     }
 226     if (output) {
 227         *output = buffer;
 228     } else {
 229         free(buffer);
 230     }
 231     return pcmk_ok;
 232 }
 233 
 234 bool
 235 stonith__agent_is_rhcs(const char *agent)
     /* [previous][next][first][last][top][bottom][index][help] */
 236 {
 237     struct stat prop;
 238     char *buffer = crm_strdup_printf(PCMK__FENCE_BINDIR "/%s", agent);
 239     int rc = stat(buffer, &prop);
 240 
 241     free(buffer);
 242     return (rc >= 0) && S_ISREG(prop.st_mode);
 243 }
 244 
 245 int
 246 stonith__rhcs_validate(stonith_t *st, int call_options, const char *target,
     /* [previous][next][first][last][top][bottom][index][help] */
 247                        const char *agent, GHashTable *params,
 248                        const char * host_arg, int timeout,
 249                        char **output, char **error_output)
 250 {
 251     int rc = pcmk_ok;
 252     int remaining_timeout = timeout;
 253     xmlNode *metadata = NULL;
 254     stonith_action_t *action = NULL;
 255 
 256     if (host_arg == NULL) {
 257         time_t start_time = time(NULL);
 258 
 259         rc = stonith__rhcs_get_metadata(agent, remaining_timeout, &metadata);
 260 
 261         if (rc == pcmk_ok) {
 262             uint32_t device_flags = 0;
 263 
 264             stonith__device_parameter_flags(&device_flags, agent, metadata);
 265             if (pcmk_is_set(device_flags, st_device_supports_parameter_port)) {
 266                 host_arg = "port";
 267 
 268             } else if (pcmk_is_set(device_flags,
 269                                    st_device_supports_parameter_plug)) {
 270                 host_arg = "plug";
 271             }
 272         }
 273 
 274         free_xml(metadata);
 275 
 276         remaining_timeout -= time(NULL) - start_time;
 277 
 278         if (rc == -ETIME || remaining_timeout <= 0 ) {
 279             return -ETIME;
 280         }
 281 
 282     } else if (pcmk__str_eq(host_arg, "none", pcmk__str_casei)) {
 283         host_arg = NULL;
 284     }
 285 
 286     action = stonith_action_create(agent, "validate-all",
 287                                    target, 0, remaining_timeout, params,
 288                                    NULL, host_arg);
 289 
 290     rc = stonith__execute(action);
 291     if (rc == pcmk_ok) {
 292         stonith__action_result(action, &rc, output, error_output);
 293     }
 294     stonith__destroy_action(action);
 295     return rc;
 296 }

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