diff --git a/cts/cts-fencing.in b/cts/cts-fencing.in
index 034304a974c..30fb39f2989 100644
--- a/cts/cts-fencing.in
+++ b/cts/cts-fencing.in
@@ -570,34 +570,6 @@ class FenceTests(Tests):
test.add_log_pattern("Delaying 'off' action targeting node3 using true3",
negative=True)
- def build_nodeid_tests(self):
- """Register tests that use a corosync node id."""
- our_uname = localname()
-
- # verify nodeid is supplied when nodeid is in the metadata parameters
- test = self.new_test("supply_nodeid",
- "Verify nodeid is given when fence agent has nodeid as parameter")
-
- test.add_cmd("stonith_admin",
- args=f'--output-as=xml -R true1 -a fence_dummy -o mode=pass -o "pcmk_host_list={our_uname}"')
- test.add_cmd("stonith_admin", args=f"--output-as=xml -F {our_uname} -t 3")
- test.add_log_pattern(f"as nodeid with fence action 'off' targeting {our_uname}")
-
- # verify nodeid is _NOT_ supplied when nodeid is not in the metadata parameters
- test = self.new_test("do_not_supply_nodeid",
- "Verify nodeid is _NOT_ given when fence agent does not have nodeid as parameter")
-
- # use a host name that won't be in corosync.conf
- test.add_cmd("stonith_admin",
- args='--output-as=xml -R true1 -a fence_dummy_no_nodeid '
- f'-o mode=pass -o pcmk_host_list="regr-test {our_uname}"')
- test.add_cmd("stonith_admin", args="--output-as=xml -F regr-test -t 3")
- test.add_log_pattern("as nodeid with fence action 'off' targeting regr-test",
- negative=True)
- test.add_cmd("stonith_admin", args=f"--output-as=xml -F {our_uname} -t 3")
- test.add_log_pattern("as nodeid with fence action 'off' targeting {our_uname}",
- negative=True)
-
def build_unfence_tests(self):
"""Register tests that verify unfencing."""
our_uname = localname()
@@ -917,7 +889,6 @@ def main():
tests.build_fence_no_merge_tests()
tests.build_unfence_tests()
tests.build_unfence_on_target_tests()
- tests.build_nodeid_tests()
tests.build_remap_tests()
tests.build_query_tests()
tests.build_metadata_tests()
diff --git a/cts/support/fence_dummy.in b/cts/support/fence_dummy.in
index 42c9a54eb9c..842fe47504f 100644
--- a/cts/support/fence_dummy.in
+++ b/cts/support/fence_dummy.in
@@ -1,7 +1,7 @@
#!@PYTHON@
"""Dummy fence agent for testing."""
-__copyright__ = "Copyright 2012-2024 the Pacemaker project contributors"
+__copyright__ = "Copyright 2012-2025 the Pacemaker project contributors"
__license__ = "GNU General Public License version 2 or later (GPLv2+) WITHOUT ANY WARRANTY"
import io
@@ -159,14 +159,6 @@ ALL_OPT = {
"shortdesc": "Ignored",
"order": 4
},
- "nodeid": {
- "getopt": "i:",
- "longopt": "nodeid",
- "help": "-i, --nodeid Corosync id of fence target (ignored)",
- "required": "0",
- "shortdesc": "Ignored",
- "order": 4
- },
"uuid": {
"getopt": "U:",
"longopt": "uuid",
@@ -446,8 +438,6 @@ def main():
no_reboot = True
elif sys.argv[0].endswith("_no_on"):
no_on = True
- elif sys.argv[0].endswith("_no_nodeid"):
- del ALL_OPT["nodeid"]
device_opt = ALL_OPT.keys()
diff --git a/daemons/fenced/fenced_cib.c b/daemons/fenced/fenced_cib.c
index 887486d04e7..90c225569eb 100644
--- a/daemons/fenced/fenced_cib.c
+++ b/daemons/fenced/fenced_cib.c
@@ -194,6 +194,47 @@ update_stonith_watchdog_timeout_ms(xmlNode *cib)
stonith_watchdog_timeout_ms = timeout_ms;
}
+/*!
+ * \internal
+ * \brief Mark a fence device dirty if its \c cib_registered flag is \c TRUE
+ *
+ * \param[in] key Ignored
+ * \param[in,out] value Fence device (fenced_device_t *)
+ * \param[in] user_data Ignored
+ *
+ * \note This function is suitable for use with \c g_hash_table_foreach().
+ */
+static void
+mark_dirty_if_cib_registered(gpointer key, gpointer value, gpointer user_data)
+{
+ fenced_device_t *device = value;
+
+ if (device->cib_registered) {
+ device->dirty = TRUE;
+ }
+}
+
+/*!
+ * \internal
+ * \brief Return the value of a fence device's \c dirty flag
+ *
+ * \param[in] key Ignored
+ * \param[in] value Fence device (fenced_device_t *)
+ * \param[in] user_data Ignored
+ *
+ * \return \c dirty flag of \p value
+ *
+ * \note This function is suitable for use with
+ * \c g_hash_table_foreach_remove().
+ */
+static gboolean
+device_is_dirty(gpointer key, gpointer value, gpointer user_data)
+{
+ fenced_device_t *device = value;
+
+ return device->dirty;
+}
+
/*!
* \internal
* \brief Update all STONITH device definitions based on current CIB
@@ -201,20 +242,12 @@ update_stonith_watchdog_timeout_ms(xmlNode *cib)
static void
cib_devices_update(void)
{
- GHashTableIter iter;
- stonith_device_t *device = NULL;
-
crm_info("Updating devices to version %s.%s.%s",
crm_element_value(local_cib, PCMK_XA_ADMIN_EPOCH),
crm_element_value(local_cib, PCMK_XA_EPOCH),
crm_element_value(local_cib, PCMK_XA_NUM_UPDATES));
- g_hash_table_iter_init(&iter, device_list);
- while (g_hash_table_iter_next(&iter, NULL, (void **)&device)) {
- if (device->cib_registered) {
- device->dirty = TRUE;
- }
- }
+ fenced_foreach_device(mark_dirty_if_cib_registered, NULL);
/* have list repopulated if cib has a watchdog-fencing-resource
TODO: keep a cached list for queries happening while we are refreshing
@@ -224,78 +257,78 @@ cib_devices_update(void)
fenced_scheduler_run(local_cib);
- g_hash_table_iter_init(&iter, device_list);
- while (g_hash_table_iter_next(&iter, NULL, (void **)&device)) {
- if (device->dirty) {
- g_hash_table_iter_remove(&iter);
- }
- }
+ fenced_foreach_device_remove(device_is_dirty);
}
+#define PRIMITIVE_ID_XP_FRAGMENT "/" PCMK_XE_PRIMITIVE "[@" PCMK_XA_ID "='"
+
static void
-update_cib_stonith_devices(const char *event, xmlNode * msg)
+update_cib_stonith_devices(const xmlNode *patchset)
{
- int format = 1;
- xmlNode *wrapper = pcmk__xe_first_child(msg, PCMK__XE_CIB_UPDATE_RESULT,
- NULL, NULL);
- xmlNode *patchset = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
char *reason = NULL;
- CRM_CHECK(patchset != NULL, return);
- crm_element_value_int(patchset, PCMK_XA_FORMAT, &format);
-
- if (format != 2) {
- crm_warn("Unknown patch format: %d", format);
- return;
- }
-
- for (xmlNode *change = pcmk__xe_first_child(patchset, NULL, NULL, NULL);
+ for (const xmlNode *change = pcmk__xe_first_child(patchset, NULL, NULL,
+ NULL);
change != NULL; change = pcmk__xe_next(change, NULL)) {
const char *op = crm_element_value(change, PCMK_XA_OPERATION);
const char *xpath = crm_element_value(change, PCMK_XA_PATH);
- const char *shortpath = NULL;
+ const char *primitive_xpath = NULL;
if (pcmk__str_eq(op, PCMK_VALUE_MOVE, pcmk__str_null_matches)
|| (strstr(xpath, "/" PCMK_XE_STATUS) != NULL)) {
continue;
}
- if (pcmk__str_eq(op, PCMK_VALUE_DELETE, pcmk__str_none)
- && (strstr(xpath, "/" PCMK_XE_PRIMITIVE) != NULL)) {
+ primitive_xpath = strstr(xpath, PRIMITIVE_ID_XP_FRAGMENT);
+ if ((primitive_xpath != NULL)
+ && pcmk__str_eq(op, PCMK_VALUE_DELETE, pcmk__str_none)) {
+
const char *rsc_id = NULL;
- char *search = NULL;
- char *mutable = NULL;
+ const char *end_quote = NULL;
- if ((strstr(xpath, PCMK_XE_INSTANCE_ATTRIBUTES) != NULL)
- || (strstr(xpath, PCMK_XE_META_ATTRIBUTES) != NULL)) {
+ if ((strstr(primitive_xpath, PCMK_XE_INSTANCE_ATTRIBUTES) != NULL)
+ || (strstr(primitive_xpath, PCMK_XE_META_ATTRIBUTES) != NULL)) {
reason = pcmk__str_copy("(meta) attribute deleted from "
"resource");
break;
}
- mutable = pcmk__str_copy(xpath);
- rsc_id = strstr(mutable, PCMK_XE_PRIMITIVE "[@" PCMK_XA_ID "=\'");
- if (rsc_id != NULL) {
- rsc_id += strlen(PCMK_XE_PRIMITIVE "[@" PCMK_XA_ID "=\'");
- search = strchr(rsc_id, '\'');
+
+ rsc_id = primitive_xpath + sizeof(PRIMITIVE_ID_XP_FRAGMENT) - 1;
+ end_quote = strchr(rsc_id, '\'');
+
+ CRM_LOG_ASSERT(end_quote != NULL);
+ if (end_quote == NULL) {
+ crm_err("Bug: Malformed item in Pacemaker-generated patchset");
+ continue;
}
- if (search != NULL) {
- *search = 0;
- stonith_device_remove(rsc_id, true);
+
+ if (strchr(end_quote, '/') == NULL) {
+ /* The primitive element itself was deleted. If this was a
+ * fencing resource, it's faster to remove it directly than to
+ * run the scheduler and update all device registrations.
+ */
+ char *copy = strndup(rsc_id, end_quote - rsc_id);
+
+ pcmk__assert(copy != NULL);
+ stonith_device_remove(copy, true);
+
/* watchdog_device_update called afterwards
to fall back to implicit definition if needed */
- } else {
- crm_warn("Ignoring malformed CIB update (resource deletion)");
+
+ free(copy);
+ continue;
}
- free(mutable);
-
- } else if (strstr(xpath, "/" PCMK_XE_RESOURCES)
- || strstr(xpath, "/" PCMK_XE_CONSTRAINTS)
- || strstr(xpath, "/" PCMK_XE_RSC_DEFAULTS)) {
- shortpath = strrchr(xpath, '/');
- pcmk__assert(shortpath != NULL);
- reason = crm_strdup_printf("%s %s", op, shortpath+1);
+ }
+
+ if (strstr(xpath, "/" PCMK_XE_RESOURCES)
+ || strstr(xpath, "/" PCMK_XE_CONSTRAINTS)
+ || strstr(xpath, "/" PCMK_XE_RSC_DEFAULTS)) {
+
+ const char *shortpath = strrchr(xpath, '/');
+
+ reason = crm_strdup_printf("%s %s", op, shortpath + 1);
break;
}
}
@@ -313,8 +346,8 @@ static void
watchdog_device_update(void)
{
if (stonith_watchdog_timeout_ms > 0) {
- if (!g_hash_table_lookup(device_list, STONITH_WATCHDOG_ID) &&
- !stonith_watchdog_targets) {
+ if (!fenced_has_watchdog_device()
+ && (stonith_watchdog_targets == NULL)) {
/* getting here watchdog-fencing enabled, no device there yet
and reason isn't stonith_watchdog_targets preventing that
*/
@@ -325,15 +358,14 @@ watchdog_device_update(void)
STONITH_WATCHDOG_ID,
st_namespace_internal,
STONITH_WATCHDOG_AGENT,
- NULL, /* stonith_device_register will add our
+ NULL, /* fenced_device_register() will add our
own name as PCMK_STONITH_HOST_LIST param
so we can skip that here
*/
NULL);
- rc = stonith_device_register(xml, TRUE);
+ rc = fenced_device_register(xml, true);
pcmk__xml_free(xml);
- if (rc != pcmk_ok) {
- rc = pcmk_legacy2rc(rc);
+ if (rc != pcmk_rc_ok) {
exit_code = CRM_EX_FATAL;
crm_crit("Cannot register watchdog pseudo fence agent: %s",
pcmk_rc_str(rc));
@@ -341,7 +373,7 @@ watchdog_device_update(void)
}
}
- } else if (g_hash_table_lookup(device_list, STONITH_WATCHDOG_ID) != NULL) {
+ } else if (fenced_has_watchdog_device()) {
/* be silent if no device - todo parameter to stonith_device_remove */
stonith_device_remove(STONITH_WATCHDOG_ID, true);
}
@@ -465,6 +497,7 @@ update_fencing_topology(const char *event, xmlNode *msg)
static void
update_cib_cache_cb(const char *event, xmlNode * msg)
{
+ xmlNode *patchset = NULL;
long long timeout_ms_saved = stonith_watchdog_timeout_ms;
bool need_full_refresh = false;
@@ -483,7 +516,6 @@ update_cib_cache_cb(const char *event, xmlNode * msg)
if (local_cib != NULL) {
int rc = pcmk_ok;
xmlNode *wrapper = NULL;
- xmlNode *patchset = NULL;
crm_element_value_int(msg, PCMK__XA_CIB_RC, &rc);
if (rc != pcmk_ok) {
@@ -498,6 +530,11 @@ update_cib_cache_cb(const char *event, xmlNode * msg)
switch (rc) {
case pcmk_ok:
case -pcmk_err_old_data:
+ /* @TODO Full refresh (with or without query) in case of
+ * -pcmk_err_old_data? It seems wrong to call
+ * stonith_device_remove() based on primitive deletion in an
+ * old diff.
+ */
break;
case -pcmk_err_diff_resync:
case -pcmk_err_diff_failed:
@@ -532,7 +569,7 @@ update_cib_cache_cb(const char *event, xmlNode * msg)
} else {
// Partial refresh
update_fencing_topology(event, msg);
- update_cib_stonith_devices(event, msg);
+ update_cib_stonith_devices(patchset);
}
watchdog_device_update();
diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c
index 51666992bff..b31c52bf947 100644
--- a/daemons/fenced/fenced_commands.c
+++ b/daemons/fenced/fenced_commands.c
@@ -10,6 +10,7 @@
#include
#include
+#include // bool
#include
#include
#include
@@ -37,7 +38,8 @@
#include
-GHashTable *device_list = NULL;
+static GHashTable *device_table = NULL;
+
GHashTable *topology = NULL;
static GList *cmd_list = NULL;
@@ -76,14 +78,11 @@ static void search_devices_record_result(struct device_search_s *search, const c
gboolean can_fence);
static int get_agent_metadata(const char *agent, xmlNode **metadata);
-static void read_action_metadata(stonith_device_t *device);
+static void read_action_metadata(fenced_device_t *device);
static enum fenced_target_by unpack_level_kind(const xmlNode *level);
-typedef struct async_command_s {
-
+typedef struct {
int id;
- int pid;
- int fd_stdout;
uint32_t options;
int default_timeout; /* seconds */
int timeout; /* seconds */
@@ -98,38 +97,79 @@ typedef struct async_command_s {
char *remote_op_id;
char *target;
- uint32_t target_nodeid;
char *action;
char *device;
+ //! Head of device list (used only for freeing list with command object)
GList *device_list;
- GList *next_device_iter; // device_list entry for next device to execute
+
+ //! Next item to process in \c device_list
+ GList *next_device_iter;
void *internal_user_data;
void (*done_cb) (int pid, const pcmk__action_result_t *result,
void *user_data);
- guint timer_sigterm;
- guint timer_sigkill;
- /*! If the operation timed out, this is the last signal
- * we sent to the process to get it to terminate */
- int last_timeout_signo;
-
- stonith_device_t *active_on;
- stonith_device_t *activating_on;
+
+ fenced_device_t *active_on;
+ fenced_device_t *activating_on;
} async_command_t;
static xmlNode *construct_async_reply(const async_command_t *cmd,
const pcmk__action_result_t *result);
+/*!
+ * \internal
+ * \brief Check whether the fencer's device table contains a watchdog device
+ *
+ * \retval \c true If the device table contains a watchdog device
+ * \retval \c false Otherwise
+ */
+bool
+fenced_has_watchdog_device(void)
+{
+ return (device_table != NULL)
+ && (g_hash_table_lookup(device_table, STONITH_WATCHDOG_ID) != NULL);
+}
+
+/*!
+ * \internal
+ * \brief Call a function for each known fence device
+ *
+ * \param[in] fn Function to call for each device
+ * \param[in,out] user_data User data
+ */
+void
+fenced_foreach_device(GHFunc fn, gpointer user_data)
+{
+ if (device_table != NULL) {
+ g_hash_table_foreach(device_table, fn, user_data);
+ }
+}
+
+/*!
+ * \internal
+ * \brief Remove each known fence device matching a given predicate
+ *
+ * \param[in] fn Function that returns \c TRUE to remove a fence device or
+ * \c FALSE to keep it
+ */
+void
+fenced_foreach_device_remove(GHRFunc fn)
+{
+ if (device_table != NULL) {
+ g_hash_table_foreach_remove(device_table, fn, NULL);
+ }
+}
+
static gboolean
-is_action_required(const char *action, const stonith_device_t *device)
+is_action_required(const char *action, const fenced_device_t *device)
{
return (device != NULL) && device->automatic_unfencing
&& pcmk__str_eq(action, PCMK_ACTION_ON, pcmk__str_none);
}
static int
-get_action_delay_max(const stonith_device_t *device, const char *action)
+get_action_delay_max(const fenced_device_t *device, const char *action)
{
const char *value = NULL;
guint delay_max = 0U;
@@ -148,7 +188,7 @@ get_action_delay_max(const stonith_device_t *device, const char *action)
}
static int
-get_action_delay_base(const stonith_device_t *device, const char *action,
+get_action_delay_base(const fenced_device_t *device, const char *action,
const char *target)
{
char *hash_value = NULL;
@@ -214,7 +254,7 @@ get_action_delay_base(const stonith_device_t *device, const char *action,
* the device is registered, whether by CIB change or API call.
*/
static int
-get_action_timeout(const stonith_device_t *device, const char *action,
+get_action_timeout(const fenced_device_t *device, const char *action,
int default_timeout)
{
if (action && device && device->params) {
@@ -250,13 +290,13 @@ get_action_timeout(const stonith_device_t *device, const char *action,
*
* \return Currently executing device for \p cmd if any, otherwise NULL
*/
-static stonith_device_t *
+static fenced_device_t *
cmd_device(const async_command_t *cmd)
{
- if ((cmd == NULL) || (cmd->device == NULL) || (device_list == NULL)) {
+ if ((cmd == NULL) || (cmd->device == NULL) || (device_table == NULL)) {
return NULL;
}
- return g_hash_table_lookup(device_list, cmd->device);
+ return g_hash_table_lookup(device_table, cmd->device);
}
/*!
@@ -272,8 +312,8 @@ fenced_device_reboot_action(const char *device_id)
{
const char *action = NULL;
- if ((device_list != NULL) && (device_id != NULL)) {
- stonith_device_t *device = g_hash_table_lookup(device_list, device_id);
+ if ((device_table != NULL) && (device_id != NULL)) {
+ fenced_device_t *device = g_hash_table_lookup(device_table, device_id);
if ((device != NULL) && (device->params != NULL)) {
action = g_hash_table_lookup(device->params, "pcmk_reboot_action");
@@ -293,8 +333,8 @@ fenced_device_reboot_action(const char *device_id)
bool
fenced_device_supports_on(const char *device_id)
{
- if ((device_list != NULL) && (device_id != NULL)) {
- stonith_device_t *device = g_hash_table_lookup(device_list, device_id);
+ if ((device_table != NULL) && (device_id != NULL)) {
+ fenced_device_t *device = g_hash_table_lookup(device_table, device_id);
if (device != NULL) {
return pcmk_is_set(device->flags, st_device_supports_on);
@@ -393,7 +433,7 @@ create_async_command(xmlNode *msg)
}
static int
-get_action_limit(stonith_device_t * device)
+get_action_limit(fenced_device_t *device)
{
const char *value = NULL;
int action_limit = 1;
@@ -408,7 +448,7 @@ get_action_limit(stonith_device_t * device)
}
static int
-get_active_cmds(stonith_device_t * device)
+get_active_cmds(fenced_device_t *device)
{
int counter = 0;
GList *gIter = NULL;
@@ -433,11 +473,14 @@ static void
fork_cb(int pid, void *user_data)
{
async_command_t *cmd = (async_command_t *) user_data;
- stonith_device_t * device =
- /* in case of a retry we've done the move from
- activating_on to active_on already
+ fenced_device_t *device = cmd->activating_on;
+
+ if (device == NULL) {
+ /* In case of a retry, we've done the move from activating_on to
+ * active_on already
*/
- cmd->activating_on?cmd->activating_on:cmd->active_on;
+ device = cmd->active_on;
+ }
pcmk__assert(device != NULL);
crm_debug("Operation '%s' [%d]%s%s using %s now running with %ds timeout",
@@ -450,7 +493,7 @@ fork_cb(int pid, void *user_data)
static int
get_agent_metadata_cb(gpointer data) {
- stonith_device_t *device = data;
+ fenced_device_t *device = data;
guint period_ms;
switch (get_agent_metadata(device->agent, &device->agent_metadata)) {
@@ -495,7 +538,7 @@ report_internal_result(async_command_t *cmd, int exit_status,
}
static gboolean
-stonith_device_execute(stonith_device_t * device)
+stonith_device_execute(fenced_device_t *device)
{
int exec_rc = 0;
const char *action_str = NULL;
@@ -596,8 +639,8 @@ stonith_device_execute(stonith_device_t * device)
}
action = stonith__action_create(device->agent, action_str, cmd->target,
- cmd->target_nodeid, cmd->timeout,
- device->params, device->aliases, host_arg);
+ cmd->timeout, device->params,
+ device->aliases, host_arg);
/* for async exec, exec_rc is negative for early error exit
otherwise handling of success/errors is done via callbacks */
@@ -630,7 +673,7 @@ static gboolean
start_delay_helper(gpointer data)
{
async_command_t *cmd = data;
- stonith_device_t *device = cmd_device(cmd);
+ fenced_device_t *device = cmd_device(cmd);
cmd->delay_id = 0;
if (device) {
@@ -641,7 +684,7 @@ start_delay_helper(gpointer data)
}
static void
-schedule_stonith_command(async_command_t * cmd, stonith_device_t * device)
+schedule_stonith_command(async_command_t *cmd, fenced_device_t *device)
{
int delay_max = 0;
int delay_base = 0;
@@ -654,14 +697,6 @@ schedule_stonith_command(async_command_t * cmd, stonith_device_t * device)
free(cmd->device);
}
- if (device->include_nodeid && (cmd->target != NULL)) {
- pcmk__node_status_t *node =
- pcmk__get_node(0, cmd->target, NULL,
- pcmk__node_search_cluster_member);
-
- cmd->target_nodeid = node->cluster_layer_id;
- }
-
cmd->device = pcmk__str_copy(device->id);
cmd->timeout = get_action_timeout(device, cmd->action, cmd->default_timeout);
@@ -724,7 +759,7 @@ static void
free_device(gpointer data)
{
GList *gIter = NULL;
- stonith_device_t *device = data;
+ fenced_device_t *device = data;
g_hash_table_destroy(device->params);
g_hash_table_destroy(device->aliases);
@@ -757,19 +792,28 @@ free_device(gpointer data)
free(device);
}
-void free_device_list(void)
+/*!
+ * \internal
+ * \brief Initialize the table of known fence devices
+ */
+void
+fenced_init_device_table(void)
{
- if (device_list != NULL) {
- g_hash_table_destroy(device_list);
- device_list = NULL;
+ if (device_table == NULL) {
+ device_table = pcmk__strkey_table(NULL, free_device);
}
}
+/*!
+ * \internal
+ * \brief Free the table of known fence devices
+ */
void
-init_device_list(void)
+fenced_free_device_table(void)
{
- if (device_list == NULL) {
- device_list = pcmk__strkey_table(NULL, free_device);
+ if (device_table != NULL) {
+ g_hash_table_destroy(device_table);
+ device_table = NULL;
}
}
@@ -907,29 +951,8 @@ get_agent_metadata(const char *agent, xmlNode ** metadata)
return pcmk_rc_ok;
}
-static gboolean
-is_nodeid_required(xmlNode * xml)
-{
- xmlXPathObject *xpath = NULL;
-
- if (!xml) {
- return FALSE;
- }
-
- xpath = pcmk__xpath_search(xml->doc,
- "//" PCMK_XE_PARAMETER
- "[@" PCMK_XA_NAME "='nodeid']");
- if (pcmk__xpath_num_results(xpath) == 0) {
- xmlXPathFreeObject(xpath);
- return FALSE;
- }
-
- xmlXPathFreeObject(xpath);
- return TRUE;
-}
-
static void
-read_action_metadata(stonith_device_t *device)
+read_action_metadata(fenced_device_t *device)
{
xmlXPathObject *xpath = NULL;
int max = 0;
@@ -992,7 +1015,7 @@ read_action_metadata(stonith_device_t *device)
}
static const char *
-target_list_type(stonith_device_t * dev)
+target_list_type(fenced_device_t *dev)
{
const char *check_type = NULL;
@@ -1016,16 +1039,16 @@ target_list_type(stonith_device_t * dev)
return check_type;
}
-static stonith_device_t *
-build_device_from_xml(xmlNode *dev)
+static fenced_device_t *
+build_device_from_xml(const xmlNode *dev)
{
const char *value;
- stonith_device_t *device = NULL;
+ fenced_device_t *device = NULL;
char *agent = crm_element_value_copy(dev, PCMK_XA_AGENT);
CRM_CHECK(agent != NULL, return device);
- device = pcmk__assert_alloc(1, sizeof(stonith_device_t));
+ device = pcmk__assert_alloc(1, sizeof(fenced_device_t));
device->id = crm_element_value_copy(dev, PCMK_XA_ID);
device->agent = agent;
@@ -1071,11 +1094,6 @@ build_device_from_xml(xmlNode *dev)
break;
}
- value = g_hash_table_lookup(device->params, "nodeid");
- if (!value) {
- device->include_nodeid = is_nodeid_required(device->agent_metadata);
- }
-
value = crm_element_value(dev, PCMK__XA_RSC_PROVIDES);
if (pcmk__str_eq(value, PCMK_VALUE_UNFENCING, pcmk__str_casei)) {
device->automatic_unfencing = TRUE;
@@ -1092,17 +1110,13 @@ build_device_from_xml(xmlNode *dev)
}
device->work = mainloop_add_trigger(G_PRIORITY_HIGH, stonith_device_dispatch, device);
- /* TODO: Hook up priority */
return device;
}
static void
-schedule_internal_command(const char *origin,
- stonith_device_t * device,
- const char *action,
- const char *target,
- int timeout,
+schedule_internal_command(const char *origin, fenced_device_t *device,
+ const char *action, const char *target, int timeout,
void *internal_user_data,
void (*done_cb) (int pid,
const pcmk__action_result_t *result,
@@ -1141,7 +1155,7 @@ status_search_cb(int pid, const pcmk__action_result_t *result, void *user_data)
{
async_command_t *cmd = user_data;
struct device_search_s *search = cmd->internal_user_data;
- stonith_device_t *dev = cmd_device(cmd);
+ fenced_device_t *dev = cmd_device(cmd);
gboolean can = FALSE;
free_async_command(cmd);
@@ -1191,7 +1205,7 @@ dynamic_list_search_cb(int pid, const pcmk__action_result_t *result,
{
async_command_t *cmd = user_data;
struct device_search_s *search = cmd->internal_user_data;
- stonith_device_t *dev = cmd_device(cmd);
+ fenced_device_t *dev = cmd_device(cmd);
gboolean can_fence = FALSE;
free_async_command(cmd);
@@ -1298,12 +1312,12 @@ device_params_diff(GHashTable *first, GHashTable *second) {
/*!
* \internal
- * \brief Checks to see if an identical device already exists in the device_list
+ * \brief Checks to see if an identical device already exists in the table
*/
-static stonith_device_t *
-device_has_duplicate(const stonith_device_t *device)
+static fenced_device_t *
+device_has_duplicate(const fenced_device_t *device)
{
- stonith_device_t *dup = g_hash_table_lookup(device_list, device->id);
+ fenced_device_t *dup = g_hash_table_lookup(device_table, device->id);
if (!dup) {
crm_trace("No match for %s", device->id);
@@ -1325,97 +1339,98 @@ device_has_duplicate(const stonith_device_t *device)
}
int
-stonith_device_register(xmlNode *dev, gboolean from_cib)
+fenced_device_register(const xmlNode *dev, bool from_cib)
{
- stonith_device_t *dup = NULL;
- stonith_device_t *device = build_device_from_xml(dev);
- guint ndevices = 0;
- int rv = pcmk_ok;
+ const char *local_node_name = fenced_get_local_node();
+ fenced_device_t *dup = NULL;
+ fenced_device_t *device = build_device_from_xml(dev);
+ int rc = pcmk_rc_ok;
- CRM_CHECK(device != NULL, return -ENOMEM);
+ CRM_CHECK(device != NULL, return ENOMEM);
/* do we have a watchdog-device? */
- if (pcmk__str_eq(device->id, STONITH_WATCHDOG_ID, pcmk__str_none) ||
- pcmk__str_any_of(device->agent, STONITH_WATCHDOG_AGENT,
- STONITH_WATCHDOG_AGENT_INTERNAL, NULL)) do {
+ if (pcmk__str_eq(device->id, STONITH_WATCHDOG_ID, pcmk__str_none)
+ || pcmk__str_any_of(device->agent, STONITH_WATCHDOG_AGENT,
+ STONITH_WATCHDOG_AGENT_INTERNAL, NULL)) {
+
if (stonith_watchdog_timeout_ms <= 0) {
crm_err("Ignoring watchdog fence device without "
- PCMK_OPT_STONITH_WATCHDOG_TIMEOUT " set.");
- rv = -ENODEV;
- /* fall through to cleanup & return */
- } else if (!pcmk__str_any_of(device->agent, STONITH_WATCHDOG_AGENT,
- STONITH_WATCHDOG_AGENT_INTERNAL, NULL)) {
- crm_err("Ignoring watchdog fence device with unknown "
- "agent '%s' unequal '" STONITH_WATCHDOG_AGENT "'.",
- device->agent?device->agent:"");
- rv = -ENODEV;
- /* fall through to cleanup & return */
- } else if (!pcmk__str_eq(device->id, STONITH_WATCHDOG_ID,
- pcmk__str_none)) {
- crm_err("Ignoring watchdog fence device "
- "named %s !='"STONITH_WATCHDOG_ID"'.",
- device->id?device->id:"");
- rv = -ENODEV;
- /* fall through to cleanup & return */
- } else {
- const char *local_node_name = fenced_get_local_node();
+ PCMK_OPT_STONITH_WATCHDOG_TIMEOUT " set");
+ rc = ENODEV;
+ goto done;
+ }
+ if (!pcmk__str_any_of(device->agent, STONITH_WATCHDOG_AGENT,
+ STONITH_WATCHDOG_AGENT_INTERNAL, NULL)) {
+ crm_err("Ignoring watchdog fence device with unknown agent '%s' "
+ "rather than '" STONITH_WATCHDOG_AGENT "'",
+ pcmk__s(device->agent, ""));
+ rc = ENODEV;
+ goto done;
+ }
+ if (!pcmk__str_eq(device->id, STONITH_WATCHDOG_ID, pcmk__str_none)) {
+ crm_err("Ignoring watchdog fence device named '%s' rather than "
+ "'" STONITH_WATCHDOG_ID "'",
+ pcmk__s(device->id, ""));
+ rc = ENODEV;
+ goto done;
+ }
- if (pcmk__str_eq(device->agent, STONITH_WATCHDOG_AGENT,
- pcmk__str_none)) {
- /* this either has an empty list or the targets
- configured for watchdog-fencing
- */
- g_list_free_full(stonith_watchdog_targets, free);
- stonith_watchdog_targets = device->targets;
- device->targets = NULL;
- }
- if (node_does_watchdog_fencing(local_node_name)) {
- g_list_free_full(device->targets, free);
- device->targets = stonith__parse_targets(local_node_name);
- pcmk__insert_dup(device->params,
- PCMK_STONITH_HOST_LIST, local_node_name);
- /* proceed as with any other stonith-device */
- break;
- }
+ if (pcmk__str_eq(device->agent, STONITH_WATCHDOG_AGENT,
+ pcmk__str_none)) {
+ /* This has either an empty list or the targets configured for
+ * watchdog fencing
+ */
+ g_list_free_full(stonith_watchdog_targets, free);
+ stonith_watchdog_targets = device->targets;
+ device->targets = NULL;
+ }
- crm_debug("Skip registration of watchdog fence device on node not in host-list.");
- /* cleanup and fall through to more cleanup and return */
+ if (!node_does_watchdog_fencing(local_node_name)) {
+ crm_debug("Skip registration of watchdog fence device on node not "
+ "in host list");
device->targets = NULL;
stonith_device_remove(device->id, from_cib);
+ goto done;
}
- free_device(device);
- return rv;
- } while (0);
+
+ // Proceed as with any other fencing device
+ g_list_free_full(device->targets, free);
+ device->targets = stonith__parse_targets(local_node_name);
+ pcmk__insert_dup(device->params, PCMK_STONITH_HOST_LIST,
+ local_node_name);
+ }
dup = device_has_duplicate(device);
- if (dup) {
- ndevices = g_hash_table_size(device_list);
+ if (dup != NULL) {
+ guint ndevices = g_hash_table_size(device_table);
+
crm_debug("Device '%s' already in device list (%d active device%s)",
device->id, ndevices, pcmk__plural_s(ndevices));
free_device(device);
device = dup;
- dup = g_hash_table_lookup(device_list, device->id);
- dup->dirty = FALSE;
+ device->dirty = FALSE;
} else {
- stonith_device_t *old = g_hash_table_lookup(device_list, device->id);
-
- if (from_cib && old && old->api_registered) {
- /* If the cib is writing over an entry that is shared with a stonith client,
- * copy any pending ops that currently exist on the old entry to the new one.
- * Otherwise the pending ops will be reported as failures
+ guint ndevices = 0;
+ fenced_device_t *old = g_hash_table_lookup(device_table, device->id);
+
+ if (from_cib && (old != NULL) && old->api_registered) {
+ /* If the CIB is writing over an entry that is shared with a stonith
+ * client, copy any pending ops that currently exist on the old
+ * entry to the new one. Otherwise the pending ops will be reported
+ * as failures.
*/
crm_info("Overwriting existing entry for %s from CIB", device->id);
device->pending_ops = old->pending_ops;
device->api_registered = TRUE;
old->pending_ops = NULL;
- if (device->pending_ops) {
+ if (device->pending_ops != NULL) {
mainloop_set_trigger(device->work);
}
}
- g_hash_table_replace(device_list, device->id, device);
+ g_hash_table_replace(device_table, device->id, device);
- ndevices = g_hash_table_size(device_list);
+ ndevices = g_hash_table_size(device_table);
crm_notice("Added '%s' to device list (%d active device%s)",
device->id, ndevices, pcmk__plural_s(ndevices));
}
@@ -1426,19 +1441,23 @@ stonith_device_register(xmlNode *dev, gboolean from_cib)
device->api_registered = TRUE;
}
- return pcmk_ok;
+done:
+ if (rc != pcmk_rc_ok) {
+ free_device(device);
+ }
+ return rc;
}
void
stonith_device_remove(const char *id, bool from_cib)
{
- stonith_device_t *device = g_hash_table_lookup(device_list, id);
+ fenced_device_t *device = g_hash_table_lookup(device_table, id);
guint ndevices = 0;
- if (!device) {
- ndevices = g_hash_table_size(device_list);
- crm_info("Device '%s' not found (%d active device%s)",
- id, ndevices, pcmk__plural_s(ndevices));
+ if (device == NULL) {
+ ndevices = g_hash_table_size(device_table);
+ crm_info("Device '%s' not found (%u active device%s)", id, ndevices,
+ pcmk__plural_s(ndevices));
return;
}
@@ -1450,16 +1469,16 @@ stonith_device_remove(const char *id, bool from_cib)
}
if (!device->cib_registered && !device->api_registered) {
- g_hash_table_remove(device_list, id);
- ndevices = g_hash_table_size(device_list);
- crm_info("Removed '%s' from device list (%d active device%s)",
+ g_hash_table_remove(device_table, id);
+ ndevices = g_hash_table_size(device_table);
+ crm_info("Removed '%s' from device list (%u active device%s)",
id, ndevices, pcmk__plural_s(ndevices));
} else {
- crm_trace("Not removing '%s' from device list (%d active) because "
- "still registered via:%s%s",
- id, g_hash_table_size(device_list),
- (device->cib_registered? " cib" : ""),
- (device->api_registered? " api" : ""));
+ // Exactly one is true at this point
+ crm_trace("Not removing '%s' from device list (%u active) because "
+ "still registered via %s",
+ id, g_hash_table_size(device_table),
+ (device->cib_registered? "CIB" : "API"));
}
}
@@ -1905,7 +1924,7 @@ execute_agent_action(xmlNode *msg, pcmk__action_result_t *result)
const char *id = crm_element_value(dev, PCMK__XA_ST_DEVICE_ID);
const char *action = crm_element_value(op, PCMK__XA_ST_DEVICE_ACTION);
async_command_t *cmd = NULL;
- stonith_device_t *device = NULL;
+ fenced_device_t *device = NULL;
if ((id == NULL) || (action == NULL)) {
crm_info("Malformed API action request: device %s, action %s",
@@ -1936,7 +1955,7 @@ execute_agent_action(xmlNode *msg, pcmk__action_result_t *result)
}
}
- device = g_hash_table_lookup(device_list, id);
+ device = g_hash_table_lookup(device_table, id);
if (device == NULL) {
crm_info("Ignoring API '%s' action request because device %s not found",
action, id);
@@ -1971,7 +1990,7 @@ search_devices_record_result(struct device_search_s *search, const char *device,
search->replies_received++;
if (can_fence && device) {
if (search->support_action_only != st_device_supports_none) {
- stonith_device_t *dev = g_hash_table_lookup(device_list, device);
+ fenced_device_t *dev = g_hash_table_lookup(device_table, device);
if (dev && !pcmk_is_set(dev->flags, search->support_action_only)) {
return;
}
@@ -2008,7 +2027,7 @@ search_devices_record_result(struct device_search_s *search, const char *device,
* \return TRUE if local host is allowed to execute action, FALSE otherwise
*/
static gboolean
-localhost_is_eligible(const stonith_device_t *device, const char *action,
+localhost_is_eligible(const fenced_device_t *device, const char *action,
const char *target, gboolean allow_self)
{
gboolean localhost_is_target = pcmk__str_eq(target, fenced_get_local_node(),
@@ -2045,7 +2064,7 @@ localhost_is_eligible(const stonith_device_t *device, const char *action,
* might be remapped to, otherwise false
*/
static bool
-localhost_is_eligible_with_remap(const stonith_device_t *device,
+localhost_is_eligible_with_remap(const fenced_device_t *device,
const char *action, const char *target,
gboolean allow_self)
{
@@ -2081,13 +2100,13 @@ localhost_is_eligible_with_remap(const stonith_device_t *device,
* otherwise \c false
*/
static inline bool
-can_use_target_cache(const stonith_device_t *dev)
+can_use_target_cache(const fenced_device_t *dev)
{
return (dev->targets != NULL) && (time(NULL) < (dev->targets_age + 60));
}
static void
-can_fence_host_with_device(stonith_device_t *dev,
+can_fence_host_with_device(fenced_device_t *dev,
struct device_search_s *search)
{
gboolean can = FALSE;
@@ -2201,7 +2220,7 @@ can_fence_host_with_device(stonith_device_t *dev,
static void
search_devices(gpointer key, gpointer value, gpointer user_data)
{
- stonith_device_t *dev = value;
+ fenced_device_t *dev = value;
struct device_search_s *search = user_data;
can_fence_host_with_device(dev, search);
@@ -2215,7 +2234,7 @@ get_capable_devices(const char *host, const char *action, int timeout,
uint32_t support_action_only)
{
struct device_search_s *search;
- guint ndevices = g_hash_table_size(device_list);
+ guint ndevices = g_hash_table_size(device_table);
if (ndevices == 0) {
callback(NULL, user_data);
@@ -2241,7 +2260,7 @@ get_capable_devices(const char *host, const char *action, int timeout,
ndevices, pcmk__plural_s(ndevices),
(search->action? search->action : "unknown action"),
(search->host? search->host : "any node"));
- g_hash_table_foreach(device_list, search_devices, search);
+ fenced_foreach_device(search_devices, search);
}
struct st_query_data {
@@ -2264,7 +2283,7 @@ struct st_query_data {
*/
static void
add_action_specific_attributes(xmlNode *xml, const char *action,
- const stonith_device_t *device,
+ const fenced_device_t *device,
const char *target)
{
int action_specific_timeout;
@@ -2324,7 +2343,7 @@ add_action_specific_attributes(xmlNode *xml, const char *action,
* \param[in] allow_self Whether self-fencing is allowed
*/
static void
-add_disallowed(xmlNode *xml, const char *action, const stonith_device_t *device,
+add_disallowed(xmlNode *xml, const char *action, const fenced_device_t *device,
const char *target, gboolean allow_self)
{
if (!localhost_is_eligible(device, action, target, allow_self)) {
@@ -2346,7 +2365,7 @@ add_disallowed(xmlNode *xml, const char *action, const stonith_device_t *device,
*/
static void
add_action_reply(xmlNode *xml, const char *action,
- const stonith_device_t *device, const char *target,
+ const fenced_device_t *device, const char *target,
gboolean allow_self)
{
xmlNode *child = pcmk__xe_create(xml, PCMK__XE_ST_DEVICE_ACTION);
@@ -2408,7 +2427,7 @@ stonith_query_capable_device_cb(GList * devices, void *user_data)
crm_xml_add(list, PCMK__XA_ST_TARGET, query->target);
for (lpc = devices; lpc != NULL; lpc = lpc->next) {
- stonith_device_t *device = g_hash_table_lookup(device_list, lpc->data);
+ fenced_device_t *device = g_hash_table_lookup(device_table, lpc->data);
const char *action = query->action;
xmlNode *dev = NULL;
@@ -2640,7 +2659,7 @@ send_async_reply(const async_command_t *cmd, const pcmk__action_result_t *result
static void
cancel_stonith_command(async_command_t * cmd)
{
- stonith_device_t *device = cmd_device(cmd);
+ fenced_device_t *device = cmd_device(cmd);
if (device) {
crm_trace("Cancel scheduled '%s' action using %s",
@@ -2722,12 +2741,12 @@ reply_to_duplicates(async_command_t *cmd, const pcmk__action_result_t *result,
*
* \return Next device required for action if any, otherwise NULL
*/
-static stonith_device_t *
+static fenced_device_t *
next_required_device(async_command_t *cmd)
{
for (GList *iter = cmd->next_device_iter; iter != NULL; iter = iter->next) {
- stonith_device_t *next_device = g_hash_table_lookup(device_list,
- iter->data);
+ fenced_device_t *next_device = g_hash_table_lookup(device_table,
+ iter->data);
if (is_action_required(cmd->action, next_device)) {
/* This is only called for successful actions, so it's OK to skip
@@ -2745,8 +2764,8 @@ st_child_done(int pid, const pcmk__action_result_t *result, void *user_data)
{
async_command_t *cmd = user_data;
- stonith_device_t *device = NULL;
- stonith_device_t *next_device = NULL;
+ fenced_device_t *device = NULL;
+ fenced_device_t *next_device = NULL;
CRM_CHECK(cmd != NULL, return);
@@ -2773,7 +2792,7 @@ st_child_done(int pid, const pcmk__action_result_t *result, void *user_data)
&& !is_action_required(cmd->action, device)) {
/* if this device didn't work out, see if there are any others we can try.
* if the failed device was 'required', we can't pick another device. */
- next_device = g_hash_table_lookup(device_list,
+ next_device = g_hash_table_lookup(device_table,
cmd->next_device_iter->data);
cmd->next_device_iter = cmd->next_device_iter->next;
}
@@ -2791,34 +2810,18 @@ st_child_done(int pid, const pcmk__action_result_t *result, void *user_data)
}
}
-static gint
-sort_device_priority(gconstpointer a, gconstpointer b)
-{
- const stonith_device_t *dev_a = a;
- const stonith_device_t *dev_b = b;
-
- if (dev_a->priority > dev_b->priority) {
- return -1;
- } else if (dev_a->priority < dev_b->priority) {
- return 1;
- }
- return 0;
-}
-
static void
stonith_fence_get_devices_cb(GList * devices, void *user_data)
{
async_command_t *cmd = user_data;
- stonith_device_t *device = NULL;
+ fenced_device_t *device = NULL;
guint ndevices = g_list_length(devices);
crm_info("Found %d matching device%s for target '%s'",
ndevices, pcmk__plural_s(ndevices), cmd->target);
if (devices != NULL) {
- /* Order based on priority */
- devices = g_list_sort(devices, sort_device_priority);
- device = g_hash_table_lookup(device_list, devices->data);
+ device = g_hash_table_lookup(device_table, devices->data);
}
if (device == NULL) { // No device found
@@ -2832,7 +2835,11 @@ stonith_fence_get_devices_cb(GList * devices, void *user_data)
free_async_command(cmd);
g_list_free_full(devices, free);
- } else { // Device found, schedule it for fencing
+ } else {
+ /* Device found. Schedule a fencing command for it.
+ *
+ * Assign devices to device_list so that it will be freed with cmd.
+ */
cmd->device_list = devices;
cmd->next_device_iter = devices->next;
schedule_stonith_command(cmd, device);
@@ -2850,7 +2857,7 @@ static void
fence_locally(xmlNode *msg, pcmk__action_result_t *result)
{
const char *device_id = NULL;
- stonith_device_t *device = NULL;
+ fenced_device_t *device = NULL;
async_command_t *cmd = NULL;
xmlNode *dev = NULL;
@@ -2868,7 +2875,7 @@ fence_locally(xmlNode *msg, pcmk__action_result_t *result)
device_id = crm_element_value(dev, PCMK__XA_ST_DEVICE_ID);
if (device_id != NULL) {
- device = g_hash_table_lookup(device_list, device_id);
+ device = g_hash_table_lookup(device_table, device_id);
if (device == NULL) {
crm_err("Requested device '%s' is not available", device_id);
pcmk__format_result(result, CRM_EX_ERROR, PCMK_EXEC_NO_FENCE_DEVICE,
@@ -3403,8 +3410,9 @@ handle_device_add_request(pcmk__request_t *request)
"//" PCMK__XE_ST_DEVICE_ID, LOG_ERR);
if (is_privileged(request->ipc_client, op)) {
- int rc = stonith_device_register(dev, FALSE);
+ int rc = fenced_device_register(dev, false);
+ rc = pcmk_rc2legacy(rc);
pcmk__set_result(&request->result,
((rc == pcmk_ok)? CRM_EX_OK : CRM_EX_ERROR),
stonith__legacy2status(rc),
diff --git a/daemons/fenced/fenced_scheduler.c b/daemons/fenced/fenced_scheduler.c
index 46d74320fcc..a67fef5c3ab 100644
--- a/daemons/fenced/fenced_scheduler.c
+++ b/daemons/fenced/fenced_scheduler.c
@@ -226,7 +226,7 @@ register_if_fencing_device(gpointer data, gpointer user_data)
xml = create_device_registration_xml(rsc_id, st_namespace_any, agent,
params, rsc_provides);
stonith_key_value_freeall(params, 1, 1);
- pcmk__assert(stonith_device_register(xml, TRUE) == pcmk_ok);
+ pcmk__assert(fenced_device_register(xml, true) == pcmk_rc_ok);
pcmk__xml_free(xml);
}
diff --git a/daemons/fenced/pacemaker-fenced.c b/daemons/fenced/pacemaker-fenced.c
index 32a3f2bf562..cb862b22845 100644
--- a/daemons/fenced/pacemaker-fenced.c
+++ b/daemons/fenced/pacemaker-fenced.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2009-2024 the Pacemaker project contributors
+ * Copyright 2009-2025 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
@@ -437,7 +437,7 @@ stonith_cleanup(void)
pcmk__client_cleanup();
free_stonith_remote_op_list();
free_topology_list();
- free_device_list();
+ fenced_free_device_table();
free_metadata_cache();
fenced_unregister_handlers();
}
@@ -634,7 +634,7 @@ main(int argc, char **argv)
setup_cib();
}
- init_device_list();
+ fenced_init_device_table();
init_topology_list();
pcmk__serve_fenced_ipc(&ipcs, &ipc_callbacks);
diff --git a/daemons/fenced/pacemaker-fenced.h b/daemons/fenced/pacemaker-fenced.h
index 04aadedc39e..c1590438cc1 100644
--- a/daemons/fenced/pacemaker-fenced.h
+++ b/daemons/fenced/pacemaker-fenced.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2009-2024 the Pacemaker project contributors
+ * Copyright 2009-2025 the Pacemaker project contributors
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
@@ -26,7 +26,7 @@
*/
gboolean stonith_check_fence_tolerance(int tolerance, const char *target, const char *action);
-typedef struct stonith_device_s {
+typedef struct {
char *id;
char *agent;
char *namespace;
@@ -35,14 +35,9 @@ typedef struct stonith_device_s {
GString *on_target_actions;
GList *targets;
time_t targets_age;
- gboolean has_attr_map;
-
- // Whether target's nodeid should be passed as a parameter to the agent
- gboolean include_nodeid;
/* whether the cluster should automatically unfence nodes with the device */
gboolean automatic_unfencing;
- guint priority;
uint32_t flags; // Group of enum st_device_flags
@@ -60,7 +55,7 @@ typedef struct stonith_device_s {
gboolean cib_registered;
gboolean api_registered;
gboolean dirty;
-} stonith_device_t;
+} fenced_device_t;
/* These values are used to index certain arrays by "phase". Usually an
* operation has only one "phase", so phase is always zero. However, some
@@ -220,8 +215,12 @@ typedef struct stonith_topology_s {
void stonith_shutdown(int nsig);
-void init_device_list(void);
-void free_device_list(void);
+void fenced_init_device_table(void);
+void fenced_free_device_table(void);
+bool fenced_has_watchdog_device(void);
+void fenced_foreach_device(GHFunc fn, gpointer user_data);
+void fenced_foreach_device_remove(GHRFunc fn);
+
void init_topology_list(void);
void free_topology_list(void);
void free_stonith_remote_op_list(void);
@@ -234,7 +233,7 @@ uint64_t get_stonith_flag(const char *name);
void stonith_command(pcmk__client_t *client, uint32_t id, uint32_t flags,
xmlNode *op_request, const char *remote_peer);
-int stonith_device_register(xmlNode *msg, gboolean from_cib);
+int fenced_device_register(const xmlNode *dev, bool from_cib);
void stonith_device_remove(const char *id, bool from_cib);
@@ -326,7 +325,6 @@ fenced_support_flag(const char *action)
return st_device_supports_none;
}
-extern GHashTable *device_list;
extern GHashTable *topology;
extern long long stonith_watchdog_timeout_ms;
extern GList *stonith_watchdog_targets;
diff --git a/doc/sphinx/Pacemaker_Explained/fencing.rst b/doc/sphinx/Pacemaker_Explained/fencing.rst
index 915f69fd0b9..dce479e3c61 100644
--- a/doc/sphinx/Pacemaker_Explained/fencing.rst
+++ b/doc/sphinx/Pacemaker_Explained/fencing.rst
@@ -179,17 +179,6 @@ fencing resource (*not* meta-attributes, even though they are interpreted by
Pacemaker rather than the fence agent). These are also listed in the man page
for ``pacemaker-fenced``.
-.. Not_Yet_Implemented:
-
- +----------------------+---------+--------------------+----------------------------------------+
- | priority | integer | 0 | .. index:: |
- | | | | single: priority |
- | | | | |
- | | | | The priority of the fence device. |
- | | | | Devices are tried in order of highest |
- | | | | priority to lowest. |
- +----------------------+---------+--------------------+----------------------------------------+
-
.. list-table:: **Additional Properties of Fencing Resources**
:class: longtable
:widths: 2 1 2 4
diff --git a/include/crm/fencing/internal.h b/include/crm/fencing/internal.h
index d46dab7ab9a..46159936457 100644
--- a/include/crm/fencing/internal.h
+++ b/include/crm/fencing/internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the Pacemaker project contributors
+ * Copyright 2011-2025 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
@@ -58,7 +58,6 @@ typedef struct stonith_action_s stonith_action_t;
stonith_action_t *stonith__action_create(const char *agent,
const char *action_name,
const char *target,
- uint32_t target_nodeid,
int timeout_sec,
GHashTable *device_args,
GHashTable *port_map,
diff --git a/lib/fencing/st_actions.c b/lib/fencing/st_actions.c
index d085ff8ab30..5da7acf026d 100644
--- a/lib/fencing/st_actions.c
+++ b/lib/fencing/st_actions.c
@@ -113,7 +113,6 @@ append_config_arg(gpointer key, gpointer value, gpointer user_data)
* \param[in] agent Fencing agent name
* \param[in] action Name of fencing action
* \param[in] target Name of target node for fencing action
- * \param[in] target_nodeid Node ID of target node for fencing action
* \param[in] device_args Fence device parameters
* \param[in] port_map Target node-to-port mapping for fence device
* \param[in] host_arg Argument name for passing target
@@ -122,8 +121,7 @@ append_config_arg(gpointer key, gpointer value, gpointer user_data)
*/
static GHashTable *
make_args(const char *agent, const char *action, const char *target,
- uint32_t target_nodeid, GHashTable *device_args,
- GHashTable *port_map, const char *host_arg)
+ GHashTable *device_args, GHashTable *port_map, const char *host_arg)
{
GHashTable *arg_list = NULL;
const char *value = NULL;
@@ -159,16 +157,6 @@ make_args(const char *agent, const char *action, const char *target,
*/
pcmk__insert_dup(arg_list, "nodename", target);
- // If the target's node ID was specified, pass it, too
- if (target_nodeid != 0) {
- char *nodeid = crm_strdup_printf("%" PRIu32, target_nodeid);
-
- // cts-fencing looks for this log message
- crm_info("Passing '%s' as nodeid with fence action '%s' targeting %s",
- nodeid, action, pcmk__s(target, "no node"));
- g_hash_table_insert(arg_list, strdup("nodeid"), nodeid);
- }
-
// Check whether target should be specified as some other argument
param = g_hash_table_lookup(device_args, PCMK_STONITH_HOST_ARGUMENT);
if (param == NULL) {
@@ -253,7 +241,6 @@ stonith__action_result(stonith_action_t *action)
* \param[in] agent Fence agent to use
* \param[in] action_name Fencing action to be executed
* \param[in] target Name of target of fencing action (if known)
- * \param[in] target_nodeid Node ID of target of fencing action (if known)
* \param[in] timeout_sec Timeout to be used when executing action
* \param[in] device_args Parameters to pass to fence agent
* \param[in] port_map Mapping of target names to device ports
@@ -263,14 +250,14 @@ stonith__action_result(stonith_action_t *action)
*/
stonith_action_t *
stonith__action_create(const char *agent, const char *action_name,
- const char *target, uint32_t target_nodeid,
- int timeout_sec, GHashTable *device_args,
- GHashTable *port_map, const char *host_arg)
+ const char *target, int timeout_sec,
+ GHashTable *device_args, GHashTable *port_map,
+ const char *host_arg)
{
stonith_action_t *action = pcmk__assert_alloc(1, sizeof(stonith_action_t));
- action->args = make_args(agent, action_name, target, target_nodeid,
- device_args, port_map, host_arg);
+ action->args = make_args(agent, action_name, target, device_args, port_map,
+ host_arg);
crm_debug("Preparing '%s' action targeting %s using agent %s",
action_name, pcmk__s(target, "no node"), agent);
action->agent = strdup(agent);
diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c
index a2c541c366b..52d348d27d2 100644
--- a/lib/fencing/st_client.c
+++ b/lib/fencing/st_client.c
@@ -2504,8 +2504,8 @@ stonith__metadata_async(const char *agent, int timeout_sec,
int rc = pcmk_ok;
action = stonith__action_create(agent, PCMK_ACTION_METADATA,
- NULL, 0, timeout_sec, NULL,
- NULL, NULL);
+ NULL, timeout_sec, NULL, NULL,
+ NULL);
rc = stonith__execute_async(action, user_data, callback, NULL);
if (rc != pcmk_ok) {
diff --git a/lib/fencing/st_rhcs.c b/lib/fencing/st_rhcs.c
index 6d0c6f94476..d091ea1153a 100644
--- a/lib/fencing/st_rhcs.c
+++ b/lib/fencing/st_rhcs.c
@@ -129,8 +129,8 @@ stonith__rhcs_get_metadata(const char *agent, int timeout_sec,
xmlXPathObject *xpathObj = NULL;
stonith_action_t *action = stonith__action_create(agent,
PCMK_ACTION_METADATA,
- NULL, 0, timeout_sec,
- NULL, NULL, NULL);
+ NULL, timeout_sec, NULL,
+ NULL, NULL);
int rc = stonith__execute(action);
pcmk__action_result_t *result = stonith__action_result(action);
@@ -306,7 +306,7 @@ stonith__rhcs_validate(stonith_t *st, int call_options, const char *target,
host_arg = NULL;
}
- action = stonith__action_create(agent, PCMK_ACTION_VALIDATE_ALL, target, 0,
+ action = stonith__action_create(agent, PCMK_ACTION_VALIDATE_ALL, target,
remaining_timeout, params, NULL, host_arg);
rc = stonith__execute(action);