root/daemons/fenced/fenced_scheduler.c

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

DEFINITIONS

This source file includes following definitions.
  1. fenced_scheduler_init
  2. fenced_set_local_node
  3. fenced_get_local_node
  4. fenced_scheduler_cleanup
  5. local_node_allowed_for
  6. register_if_fencing_device
  7. fenced_scheduler_run

   1 /*
   2  * Copyright 2009-2025 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 General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8 */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <stdio.h>
  13 #include <errno.h>
  14 #include <glib.h>
  15 
  16 #include <crm/pengine/status.h>
  17 #include <crm/pengine/internal.h>
  18 
  19 #include <pacemaker-internal.h>
  20 #include <pacemaker-fenced.h>
  21 
  22 // fenced_scheduler_run() assumes it's the only place scheduler->input gets set
  23 static pcmk_scheduler_t *scheduler = NULL;
  24 
  25 /*!
  26  * \internal
  27  * \brief Initialize scheduler data for fencer purposes
  28  *
  29  * \return Standard Pacemaker return code
  30  */
  31 int
  32 fenced_scheduler_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  33 {
  34     pcmk__output_t *logger = NULL;
  35     int rc = pcmk__log_output_new(&logger);
  36 
  37     if (rc != pcmk_rc_ok) {
  38         return rc;
  39     }
  40 
  41     scheduler = pcmk_new_scheduler();
  42     if (scheduler == NULL) {
  43         pcmk__output_free(logger);
  44         return ENOMEM;
  45     }
  46 
  47     pe__register_messages(logger);
  48     pcmk__register_lib_messages(logger);
  49     pcmk__output_set_log_level(logger, LOG_TRACE);
  50     scheduler->priv->out = logger;
  51 
  52     return pcmk_rc_ok;
  53 }
  54 
  55 /*!
  56  * \internal
  57  * \brief Set the local node name for scheduling purposes
  58  *
  59  * \param[in] node_name  Name to set as local node name
  60  */
  61 void
  62 fenced_set_local_node(const char *node_name)
     /* [previous][next][first][last][top][bottom][index][help] */
  63 {
  64     pcmk__assert(scheduler != NULL);
  65 
  66     scheduler->priv->local_node_name = pcmk__str_copy(node_name);
  67 }
  68 
  69 /*!
  70  * \internal
  71  * \brief Get the local node name
  72  *
  73  * \return Local node name
  74  */
  75 const char *
  76 fenced_get_local_node(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  77 {
  78     if (scheduler == NULL) {
  79         return NULL;
  80     }
  81     return scheduler->priv->local_node_name;
  82 }
  83 
  84 /*!
  85  * \internal
  86  * \brief Free all scheduler-related resources
  87  */
  88 void
  89 fenced_scheduler_cleanup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  90 {
  91     if (scheduler != NULL) {
  92         pcmk__output_t *logger = scheduler->priv->out;
  93 
  94         if (logger != NULL) {
  95             logger->finish(logger, CRM_EX_OK, true, NULL);
  96             pcmk__output_free(logger);
  97             scheduler->priv->out = NULL;
  98         }
  99         pcmk_free_scheduler(scheduler);
 100         scheduler = NULL;
 101     }
 102 }
 103 
 104 /*!
 105  * \internal
 106  * \brief Check whether the local node is in a resource's allowed node list
 107  *
 108  * \param[in] rsc  Resource to check
 109  *
 110  * \return Pointer to node if found, otherwise NULL
 111  */
 112 static pcmk_node_t *
 113 local_node_allowed_for(const pcmk_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 114 {
 115     if ((rsc != NULL) && (scheduler->priv->local_node_name != NULL)) {
 116         GHashTableIter iter;
 117         pcmk_node_t *node = NULL;
 118 
 119         g_hash_table_iter_init(&iter, rsc->priv->allowed_nodes);
 120         while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
 121             if (pcmk__str_eq(node->priv->name, scheduler->priv->local_node_name,
 122                              pcmk__str_casei)) {
 123                 return node;
 124             }
 125         }
 126     }
 127     return NULL;
 128 }
 129 
 130 /*!
 131  * \internal
 132  * \brief If a given resource or any of its children are fencing devices,
 133  *        register the devices
 134  *
 135  * \param[in,out] data       Resource to check
 136  * \param[in,out] user_data  Ignored
 137  */
 138 static void
 139 register_if_fencing_device(gpointer data, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 140 {
 141     pcmk_resource_t *rsc = data;
 142     const char *rsc_id = pcmk__s(rsc->priv->history_id, rsc->id);
 143 
 144     xmlNode *xml = NULL;
 145     GHashTableIter hash_iter;
 146     pcmk_node_t *node = NULL;
 147     const char *name = NULL;
 148     const char *value = NULL;
 149     const char *agent = NULL;
 150     const char *rsc_provides = NULL;
 151     stonith_key_value_t *params = NULL;
 152 
 153     // If this is a collective resource, check children instead
 154     if (rsc->priv->children != NULL) {
 155 
 156         for (GList *iter = rsc->priv->children;
 157              iter != NULL; iter = iter->next) {
 158 
 159             register_if_fencing_device(iter->data, NULL);
 160             if (pcmk__is_clone(rsc)) {
 161                 return; // Only one instance needs to be checked for clones
 162             }
 163         }
 164         return;
 165     }
 166 
 167     if (!pcmk_is_set(rsc->flags, pcmk__rsc_fence_device)) {
 168         return; // Not a fencing device
 169     }
 170 
 171     if (pe__resource_is_disabled(rsc)) {
 172         crm_info("Ignoring fencing device %s because it is disabled", rsc->id);
 173         return;
 174     }
 175 
 176     if ((stonith_watchdog_timeout_ms <= 0) &&
 177         pcmk__str_eq(rsc->id, STONITH_WATCHDOG_ID, pcmk__str_none)) {
 178         crm_info("Ignoring fencing device %s "
 179                  "because watchdog fencing is disabled", rsc->id);
 180         return;
 181     }
 182 
 183     // Check whether local node is allowed to run resource
 184     node = local_node_allowed_for(rsc);
 185     if (node == NULL) {
 186         crm_info("Ignoring fencing device %s "
 187                  "because local node is not allowed to run it", rsc->id);
 188         return;
 189     }
 190     if (node->assign->score < 0) {
 191         crm_info("Ignoring fencing device %s "
 192                  "because local node has preference %s for it",
 193                  rsc->id, pcmk_readable_score(node->assign->score));
 194         return;
 195     }
 196 
 197     // If device is in a group, check whether local node is allowed for group
 198     if (pcmk__is_group(rsc->priv->parent)) {
 199         pcmk_node_t *group_node = local_node_allowed_for(rsc->priv->parent);
 200 
 201         if ((group_node != NULL) && (group_node->assign->score < 0)) {
 202             crm_info("Ignoring fencing device %s "
 203                      "because local node has preference %s for its group",
 204                      rsc->id, pcmk_readable_score(group_node->assign->score));
 205             return;
 206         }
 207     }
 208 
 209     crm_debug("Reloading configuration of fencing device %s", rsc->id);
 210 
 211     agent = crm_element_value(rsc->priv->xml, PCMK_XA_TYPE);
 212 
 213     get_meta_attributes(rsc->priv->meta, rsc, NULL, scheduler);
 214     rsc_provides = g_hash_table_lookup(rsc->priv->meta,
 215                                        PCMK_STONITH_PROVIDES);
 216 
 217     g_hash_table_iter_init(&hash_iter, pe_rsc_params(rsc, node, scheduler));
 218     while (g_hash_table_iter_next(&hash_iter, (gpointer *) &name,
 219                                   (gpointer *) &value)) {
 220         if ((name == NULL) || (value == NULL)) {
 221             continue;
 222         }
 223         params = stonith__key_value_add(params, name, value);
 224     }
 225 
 226     xml = create_device_registration_xml(rsc_id, st_namespace_any, agent,
 227                                          params, rsc_provides);
 228     stonith__key_value_freeall(params, true, true);
 229     pcmk__assert(fenced_device_register(xml, true) == pcmk_rc_ok);
 230     pcmk__xml_free(xml);
 231 }
 232 
 233 /*!
 234  * \internal
 235  * \brief Run the scheduler for fencer purposes
 236  *
 237  * \param[in] cib  CIB to use as scheduler input
 238  *
 239  * \note Scheduler object is reset before returning, but \p cib is not freed.
 240  */
 241 void
 242 fenced_scheduler_run(xmlNode *cib)
     /* [previous][next][first][last][top][bottom][index][help] */
 243 {
 244     CRM_CHECK((cib != NULL) && (scheduler != NULL)
 245               && (scheduler->input == NULL), return);
 246 
 247     pcmk_reset_scheduler(scheduler);
 248 
 249     scheduler->input = cib;
 250     pcmk__set_scheduler_flags(scheduler,
 251                               pcmk__sched_location_only|pcmk__sched_no_counts);
 252     pcmk__schedule_actions(scheduler);
 253     g_list_foreach(scheduler->priv->resources, register_if_fencing_device,
 254                    NULL);
 255 
 256     scheduler->input = NULL; // Wasn't a copy, so don't let API free it
 257     pcmk_reset_scheduler(scheduler);
 258 }

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