diff --git a/daemons/fenced/fenced_scheduler.c b/daemons/fenced/fenced_scheduler.c index f75c7bfe71..8359c04ffa 100644 --- a/daemons/fenced/fenced_scheduler.c +++ b/daemons/fenced/fenced_scheduler.c @@ -1,239 +1,227 @@ /* * Copyright 2009-2023 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. */ #include #include #include #include #include #include #include #include static pcmk_scheduler_t *fenced_data_set = NULL; /*! * \internal * \brief Initialize scheduler data for fencer purposes * * \return Standard Pacemaker return code */ int fenced_scheduler_init(void) { pcmk__output_t *logger = NULL; int rc = pcmk__log_output_new(&logger); if (rc != pcmk_rc_ok) { return rc; } fenced_data_set = pe_new_working_set(); if (fenced_data_set == NULL) { pcmk__output_free(logger); return ENOMEM; } pe__register_messages(logger); pcmk__register_lib_messages(logger); pcmk__output_set_log_level(logger, LOG_TRACE); fenced_data_set->priv = logger; return pcmk_rc_ok; } /*! * \internal * \brief Free all scheduler-related resources */ void fenced_scheduler_cleanup(void) { if (fenced_data_set != NULL) { pcmk__output_t *logger = fenced_data_set->priv; if (logger != NULL) { logger->finish(logger, CRM_EX_OK, true, NULL); pcmk__output_free(logger); fenced_data_set->priv = NULL; } pe_free_working_set(fenced_data_set); fenced_data_set = NULL; } } /*! * \internal * \brief Check whether the local node is in a resource's allowed node list * * \param[in] rsc Resource to check * * \return Pointer to node if found, otherwise NULL */ static pcmk_node_t * local_node_allowed_for(const pcmk_resource_t *rsc) { if ((rsc != NULL) && (stonith_our_uname != NULL)) { GHashTableIter iter; pcmk_node_t *node = NULL; g_hash_table_iter_init(&iter, rsc->allowed_nodes); while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) { if (pcmk__str_eq(node->details->uname, stonith_our_uname, pcmk__str_casei)) { return node; } } } return NULL; } -#define rsc_name(x) x->clone_name?x->clone_name:x->id - /*! * \internal - * \brief If a resource or any of its children are STONITH devices, update their - * definitions given a cluster working set. + * \brief If a given resource or any of its children are fencing devices, + * register the devices * * \param[in,out] data Resource to check - * \param[in,out] user_data Cluster working set with device information + * \param[in,out] user_data Ignored */ static void -cib_device_update(pcmk_resource_t *rsc, pcmk_scheduler_t *data_set) +register_if_fencing_device(gpointer data, gpointer user_data) { + pcmk_resource_t *rsc = data; + + xmlNode *xml = NULL; + GHashTableIter hash_iter; pcmk_node_t *node = NULL; + const char *name = NULL; const char *value = NULL; const char *rclass = NULL; - pcmk_node_t *parent = NULL; - - /* If this is a complex resource, check children rather than this resource itself. */ - if(rsc->children) { - GList *gIter = NULL; - for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) { - cib_device_update(gIter->data, data_set); - if(pe_rsc_is_clone(rsc)) { - crm_trace("Only processing one copy of the clone %s", rsc->id); - break; + const char *agent = NULL; + const char *rsc_provides = NULL; + stonith_key_value_t *params = NULL; + + // If this is a collective resource, check children instead + if (rsc->children != NULL) { + for (GList *iter = rsc->children; iter != NULL; iter = iter->next) { + register_if_fencing_device(iter->data, NULL); + if (pe_rsc_is_clone(rsc)) { + return; // Only one instance needs to be checked for clones } } return; } - /* We only care about STONITH resources. */ rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); if (!pcmk__str_eq(rclass, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) { - return; + return; // Not a fencing device } - /* If this STONITH resource is disabled, remove it. */ if (pe__resource_is_disabled(rsc)) { - crm_info("Device %s has been disabled", rsc->id); + crm_info("Ignoring fencing device %s because it is disabled", rsc->id); return; } - /* if watchdog-fencing is disabled handle any watchdog-fence - resource as if it was disabled - */ if ((stonith_watchdog_timeout_ms <= 0) && pcmk__str_eq(rsc->id, STONITH_WATCHDOG_ID, pcmk__str_none)) { - crm_info("Watchdog-fencing disabled thus handling " - "device %s as disabled", rsc->id); + crm_info("Ignoring fencing device %s " + "because watchdog fencing is disabled", rsc->id); return; } - /* Check whether our node is allowed for this resource (and its parent if in a group) */ + // Check whether local node is allowed to run resource node = local_node_allowed_for(rsc); - if (rsc->parent && (rsc->parent->variant == pcmk_rsc_variant_group)) { - parent = local_node_allowed_for(rsc->parent); + if (node == NULL) { + crm_info("Ignoring fencing device %s " + "because local node is not allowed to run it", rsc->id); + return; } - - if(node == NULL) { - /* Our node is disallowed, so remove the device */ - GHashTableIter iter; - - crm_info("Device %s has been disabled on %s: unknown", rsc->id, stonith_our_uname); - g_hash_table_iter_init(&iter, rsc->allowed_nodes); - while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) { - crm_trace("Available: %s = %d", pe__node_name(node), node->weight); - } - + if (node->weight < 0) { + crm_info("Ignoring fencing device %s " + "because local node has preference %s for it", + rsc->id, pcmk_readable_score(node->weight)); return; + } - } else if(node->weight < 0 || (parent && parent->weight < 0)) { - /* Our node (or its group) is disallowed by score, so remove the device */ - int score = (node->weight < 0)? node->weight : parent->weight; + // If device is in a group, check whether local node is allowed for group + if ((rsc->parent != NULL) + && (rsc->parent->variant == pcmk_rsc_variant_group)) { + pcmk_node_t *group_node = local_node_allowed_for(rsc->parent); - crm_info("Device %s has been disabled on %s: score=%s", - rsc->id, stonith_our_uname, pcmk_readable_score(score)); - return; - - } else { - /* Our node is allowed, so update the device information */ - int rc; - xmlNode *data; - GHashTable *rsc_params = NULL; - GHashTableIter gIter; - stonith_key_value_t *params = NULL; + if ((group_node != NULL) && (group_node->weight < 0)) { + crm_info("Ignoring fencing device %s " + "because local node has preference %s for its group", + rsc->id, pcmk_readable_score(group_node->weight)); + return; + } + } - const char *name = NULL; - const char *agent = crm_element_value(rsc->xml, XML_EXPR_ATTR_TYPE); - const char *rsc_provides = NULL; + crm_debug("Reloading configuration of fencing device %s", rsc->id); - crm_debug("Device %s is allowed on %s: score=%d", rsc->id, stonith_our_uname, node->weight); - rsc_params = pe_rsc_params(rsc, node, data_set); - get_meta_attributes(rsc->meta, rsc, node, data_set); + agent = crm_element_value(rsc->xml, XML_EXPR_ATTR_TYPE); - rsc_provides = g_hash_table_lookup(rsc->meta, PCMK_STONITH_PROVIDES); + get_meta_attributes(rsc->meta, rsc, node, fenced_data_set); + rsc_provides = g_hash_table_lookup(rsc->meta, PCMK_STONITH_PROVIDES); - g_hash_table_iter_init(&gIter, rsc_params); - while (g_hash_table_iter_next(&gIter, (gpointer *) & name, (gpointer *) & value)) { - if (!name || !value) { - continue; - } - params = stonith_key_value_add(params, name, value); - crm_trace(" %s=%s", name, value); + g_hash_table_iter_init(&hash_iter, + pe_rsc_params(rsc, node, fenced_data_set)); + while (g_hash_table_iter_next(&hash_iter, (gpointer *) &name, + (gpointer *) &value)) { + if ((name == NULL) || (value == NULL)) { + continue; } - - data = create_device_registration_xml(rsc_name(rsc), st_namespace_any, - agent, params, rsc_provides); - stonith_key_value_freeall(params, 1, 1); - rc = stonith_device_register(data, TRUE); - CRM_ASSERT(rc == pcmk_ok); - free_xml(data); + params = stonith_key_value_add(params, name, value); } + + xml = create_device_registration_xml(pcmk__s(rsc->clone_name, rsc->id), + st_namespace_any, agent, params, + rsc_provides); + stonith_key_value_freeall(params, 1, 1); + CRM_ASSERT(stonith_device_register(xml, TRUE) == pcmk_ok); + free_xml(xml); } /*! * \internal * \brief Run the scheduler for fencer purposes * * \param[in] cib Cluster's current CIB */ void fenced_scheduler_run(xmlNode *cib) { CRM_CHECK((cib != NULL) && (fenced_data_set != NULL), return); if (fenced_data_set->now != NULL) { crm_time_free(fenced_data_set->now); fenced_data_set->now = NULL; } fenced_data_set->localhost = stonith_our_uname; pcmk__schedule_actions(cib, pcmk_sched_location_only |pcmk_sched_no_compat |pcmk_sched_no_counts, fenced_data_set); - g_list_foreach(fenced_data_set->resources, (GFunc) cib_device_update, - fenced_data_set); + g_list_foreach(fenced_data_set->resources, register_if_fencing_device, + NULL); fenced_data_set->input = NULL; // Wasn't a copy, so don't let API free it pe_reset_working_set(fenced_data_set); }