diff --git a/daemons/controld/controld_fencing.c b/daemons/controld/controld_fencing.c index 4304ae799eb..51367ca1a70 100644 --- a/daemons/controld/controld_fencing.c +++ b/daemons/controld/controld_fencing.c @@ -661,7 +661,7 @@ controld_timer_fencer_connect(gpointer user_data) int rc = pcmk_ok; if (stonith_api == NULL) { - stonith_api = stonith_api_new(); + stonith_api = stonith__api_new(); if (stonith_api == NULL) { crm_err("Could not connect to fencer: API memory allocation failed"); return G_SOURCE_REMOVE; @@ -675,10 +675,10 @@ controld_timer_fencer_connect(gpointer user_data) if (user_data == NULL) { // Blocking (retry failures now until successful) - rc = stonith_api_connect_retry(stonith_api, crm_system_name, 30); - if (rc != pcmk_ok) { + rc = stonith__api_connect_retry(stonith_api, crm_system_name, 30); + if (rc != pcmk_rc_ok) { crm_err("Could not connect to fencer in 30 attempts: %s " - QB_XS " rc=%d", pcmk_strerror(rc), rc); + QB_XS " rc=%d", pcmk_rc_str(rc), rc); } } else { // Non-blocking (retry failures later in main loop) @@ -766,7 +766,7 @@ do_stonith_history_sync(gpointer user_data) stonith_api->cmds->history(stonith_api, st_opt_sync_call | st_opt_broadcast, NULL, &history, 5); - stonith_history_free(history); + stonith__history_free(history); return TRUE; } else { crm_info("Skip triggering stonith history-sync as stonith is disconnected"); diff --git a/daemons/execd/execd_commands.c b/daemons/execd/execd_commands.c index e961d3d661a..a59dee23560 100644 --- a/daemons/execd/execd_commands.c +++ b/daemons/execd/execd_commands.c @@ -1212,7 +1212,7 @@ execd_stonith_start(stonith_t *stonith_api, const lrmd_rsc_t *rsc, g_hash_table_iter_init(&iter, cmd->params); while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) { - device_params = stonith_key_value_add(device_params, key, value); + device_params = stonith__key_value_add(device_params, key, value); } } @@ -1226,7 +1226,7 @@ execd_stonith_start(stonith_t *stonith_api, const lrmd_rsc_t *rsc, cmd->rsc_id, rsc->provider, rsc->type, device_params); - stonith_key_value_freeall(device_params, 1, 1); + stonith__key_value_freeall(device_params, true, true); return rc; } @@ -1283,9 +1283,11 @@ execd_stonith_monitor(stonith_t *stonith_api, lrmd_rsc_t *rsc, lrmd_cmd_t *cmd) static void execute_stonith_action(lrmd_rsc_t *rsc, lrmd_cmd_t *cmd) { - int rc = 0; - bool do_monitor = FALSE; + int rc = pcmk_ok; + const char *rc_s = NULL; + bool do_monitor = false; + // Don't free; belongs to pacemaker-execd.c stonith_t *stonith_api = get_stonith_connection(); if (pcmk__str_eq(cmd->action, PCMK_ACTION_MONITOR, pcmk__str_casei) @@ -1295,17 +1297,19 @@ execute_stonith_action(lrmd_rsc_t *rsc, lrmd_cmd_t *cmd) rsc->fence_probe_result.execution_status, rsc->fence_probe_result.exit_reason); return; + } - } else if (stonith_api == NULL) { + if (stonith_api == NULL) { stonith_action_complete(cmd, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_NOT_CONNECTED, "No connection to fencer"); return; + } - } else if (pcmk__str_eq(cmd->action, PCMK_ACTION_START, pcmk__str_casei)) { + if (pcmk__str_eq(cmd->action, PCMK_ACTION_START, pcmk__str_casei)) { rc = execd_stonith_start(stonith_api, rsc, cmd); if (rc == pcmk_ok) { - do_monitor = TRUE; + do_monitor = true; } } else if (pcmk__str_eq(cmd->action, PCMK_ACTION_STOP, pcmk__str_casei)) { @@ -1313,7 +1317,7 @@ execute_stonith_action(lrmd_rsc_t *rsc, lrmd_cmd_t *cmd) } else if (pcmk__str_eq(cmd->action, PCMK_ACTION_MONITOR, pcmk__str_casei)) { - do_monitor = TRUE; + do_monitor = true; } else { stonith_action_complete(cmd, PCMK_OCF_UNIMPLEMENT_FEATURE, @@ -1325,15 +1329,17 @@ execute_stonith_action(lrmd_rsc_t *rsc, lrmd_cmd_t *cmd) if (do_monitor) { rc = execd_stonith_monitor(stonith_api, rsc, cmd); if (rc == pcmk_ok) { - // Don't clean up yet, we will find out result of the monitor later + // Don't clean up yet. We will get the result of the monitor later. return; } } + if (rc != -pcmk_err_generic) { + rc_s = pcmk_strerror(rc); + } stonith_action_complete(cmd, - ((rc == pcmk_ok)? CRM_EX_OK : CRM_EX_ERROR), - stonith__legacy2status(rc), - ((rc == -pcmk_err_generic)? NULL : pcmk_strerror(rc))); + ((rc == pcmk_rc_ok)? CRM_EX_OK : CRM_EX_ERROR), + stonith__legacy2status(rc), rc_s); } static void diff --git a/daemons/execd/pacemaker-execd.c b/daemons/execd/pacemaker-execd.c index c32f6b26aa2..68daf77bf39 100644 --- a/daemons/execd/pacemaker-execd.c +++ b/daemons/execd/pacemaker-execd.c @@ -1,5 +1,5 @@ /* - * Copyright 2012-2024 the Pacemaker project contributors + * Copyright 2012-2025 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -22,6 +22,7 @@ #include #include #include +#include // stonith__api_new() #include #include "pacemaker-execd.h" @@ -67,23 +68,23 @@ stonith_t * get_stonith_connection(void) { if (stonith_api && stonith_api->state == stonith_disconnected) { - stonith_api_delete(stonith_api); + stonith__api_free(stonith_api); stonith_api = NULL; } if (stonith_api == NULL) { int rc = pcmk_ok; - stonith_api = stonith_api_new(); + stonith_api = stonith__api_new(); if (stonith_api == NULL) { crm_err("Could not connect to fencer: API memory allocation failed"); return NULL; } - rc = stonith_api_connect_retry(stonith_api, crm_system_name, 10); - if (rc != pcmk_ok) { + rc = stonith__api_connect_retry(stonith_api, crm_system_name, 10); + if (rc != pcmk_rc_ok) { crm_err("Could not connect to fencer in 10 attempts: %s " - QB_XS " rc=%d", pcmk_strerror(rc), rc); - stonith_api_delete(stonith_api); + QB_XS " rc=%d", pcmk_rc_str(rc), rc); + stonith__api_free(stonith_api); stonith_api = NULL; } else { stonith_api_operations_t *cmds = stonith_api->cmds; @@ -283,7 +284,7 @@ exit_executor(void) crm_info("Terminating with %d client%s", nclients, pcmk__plural_s(nclients)); - stonith_api_delete(stonith_api); + stonith__api_free(stonith_api); if (ipcs) { mainloop_del_ipc_server(ipcs); } diff --git a/daemons/fenced/cts-fence-helper.c b/daemons/fenced/cts-fence-helper.c index 1424a316230..cc83fd32a31 100644 --- a/daemons/fenced/cts-fence-helper.c +++ b/daemons/fenced/cts-fence-helper.c @@ -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. @@ -44,7 +44,6 @@ typedef void (*mainloop_test_iteration_cb) (int check_event); enum test_modes { test_standard = 0, // test using a specific developer environment - test_passive, // watch notifications only test_api_sanity, // sanity-test stonith client API using fence_dummy test_api_mainloop, // sanity-test mainloop code with async responses }; @@ -61,8 +60,6 @@ mode_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **e options.mode = test_api_mainloop; } else if (pcmk__str_any_of(option_name, "--api_test", "-t", NULL)) { options.mode = test_api_sanity; - } else if (pcmk__str_any_of(option_name, "--passive", "-p", NULL)) { - options.mode = test_passive; } return TRUE; @@ -77,10 +74,6 @@ static GOptionEntry entries[] = { NULL, NULL, }, - { "passive", 'p', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, mode_cb, - NULL, NULL, - }, - { NULL } }; @@ -117,7 +110,7 @@ dispatch_helper(int timeout) while (true) { rc = poll(&pollfd, 1, timeout); /* wait 10 minutes, -1 forever */ if (rc > 0) { - if (!stonith_dispatch(st)) { + if (stonith__api_dispatch(st) != pcmk_rc_ok) { break; } } else { @@ -153,28 +146,6 @@ st_global_callback(stonith_t * stonith, stonith_callback_data_t * data) pcmk__s(stonith__exit_reason(data), "unspecified reason")); } -static void -passive_test(void) -{ - int rc = 0; - - rc = st->cmds->connect(st, crm_system_name, &pollfd.fd); - if (rc != pcmk_ok) { - stonith_api_delete(st); - crm_exit(CRM_EX_DISCONNECT); - } - st->cmds->register_notification(st, PCMK__VALUE_ST_NOTIFY_DISCONNECT, - st_callback); - st->cmds->register_notification(st, PCMK__VALUE_ST_NOTIFY_FENCE, - st_callback); - st->cmds->register_notification(st, STONITH_OP_DEVICE_ADD, st_callback); - st->cmds->register_notification(st, STONITH_OP_DEVICE_DEL, st_callback); - st->cmds->register_callback(st, 0, 120, st_opt_timeout_updates, NULL, "st_global_callback", - st_global_callback); - - dispatch_helper(600 * 1000); -} - #define single_test(cmd, str, num_notifications, expected_rc) \ { \ int rc = 0; \ @@ -205,9 +176,9 @@ run_fence_failure_test(void) { stonith_key_value_t *params = NULL; - params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP, - "false_1_node1=1,2 false_1_node2=3,4"); - params = stonith_key_value_add(params, "mode", "fail"); + params = stonith__key_value_add(params, PCMK_STONITH_HOST_MAP, + "false_1_node1=1,2 false_1_node2=3,4"); + params = stonith__key_value_add(params, "mode", "fail"); single_test(st-> cmds->register_device(st, st_opts, "test-id1", "stonith-ng", "fence_dummy", params), @@ -224,7 +195,7 @@ run_fence_failure_test(void) single_test(st->cmds->remove_device(st, st_opts, "test-id1"), "Remove device1 for failure test", 1, 0); - stonith_key_value_freeall(params, 1, 1); + stonith__key_value_freeall(params, true, true); } static void @@ -232,18 +203,18 @@ run_fence_failure_rollover_test(void) { stonith_key_value_t *params = NULL; - params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP, - "false_1_node1=1,2 false_1_node2=3,4"); - params = stonith_key_value_add(params, "mode", "fail"); + params = stonith__key_value_add(params, PCMK_STONITH_HOST_MAP, + "false_1_node1=1,2 false_1_node2=3,4"); + params = stonith__key_value_add(params, "mode", "fail"); single_test(st-> cmds->register_device(st, st_opts, "test-id1", "stonith-ng", "fence_dummy", params), "Register device1 for rollover test", 1, 0); - stonith_key_value_freeall(params, 1, 1); + stonith__key_value_freeall(params, true, true); params = NULL; - params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP, - "false_1_node1=1,2 false_1_node2=3,4"); - params = stonith_key_value_add(params, "mode", "pass"); + params = stonith__key_value_add(params, PCMK_STONITH_HOST_MAP, + "false_1_node1=1,2 false_1_node2=3,4"); + params = stonith__key_value_add(params, "mode", "pass"); single_test(st-> cmds->register_device(st, st_opts, "test-id2", "stonith-ng", "fence_dummy", params), @@ -264,7 +235,7 @@ run_fence_failure_rollover_test(void) single_test(st->cmds->remove_device(st, st_opts, "test-id2"), "Remove device2 for rollover tests", 1, 0); - stonith_key_value_freeall(params, 1, 1); + stonith__key_value_freeall(params, true, true); } static void @@ -272,15 +243,16 @@ run_standard_test(void) { stonith_key_value_t *params = NULL; - params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP, - "false_1_node1=1,2 false_1_node2=3,4"); - params = stonith_key_value_add(params, "mode", "pass"); - params = stonith_key_value_add(params, "mock_dynamic_hosts", "false_1_node1 false_1_node2"); + params = stonith__key_value_add(params, PCMK_STONITH_HOST_MAP, + "false_1_node1=1,2 false_1_node2=3,4"); + params = stonith__key_value_add(params, "mode", "pass"); + params = stonith__key_value_add(params, "mock_dynamic_hosts", + "false_1_node1 false_1_node2"); single_test(st-> cmds->register_device(st, st_opts, "test-id", "stonith-ng", "fence_dummy", params), "Register", 1, 0); - stonith_key_value_freeall(params, 1, 1); + stonith__key_value_freeall(params, true, true); params = NULL; single_test(st->cmds->list(st, st_opts, "test-id", NULL, 1), @@ -313,7 +285,7 @@ run_standard_test(void) single_test(st->cmds->remove_device(st, st_opts, "test-id"), "Remove test-id", 1, 0); - stonith_key_value_freeall(params, 1, 1); + stonith__key_value_freeall(params, true, true); } static void @@ -323,7 +295,7 @@ sanity_tests(void) rc = st->cmds->connect(st, crm_system_name, &pollfd.fd); if (rc != pcmk_ok) { - stonith_api_delete(st); + stonith__api_free(st); crm_exit(CRM_EX_DISCONNECT); } st->cmds->register_notification(st, PCMK__VALUE_ST_NOTIFY_DISCONNECT, @@ -351,12 +323,12 @@ standard_dev_test(void) rc = st->cmds->connect(st, crm_system_name, &pollfd.fd); if (rc != pcmk_ok) { - stonith_api_delete(st); + stonith__api_free(st); crm_exit(CRM_EX_DISCONNECT); } - params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP, - "some-host=pcmk-7 true_1_node1=3,4"); + params = stonith__key_value_add(params, PCMK_STONITH_HOST_MAP, + "some-host=pcmk-7 true_1_node1=3,4"); rc = st->cmds->register_device(st, st_opts, "test-id", "stonith-ng", "fence_xvm", params); crm_debug("Register: %d", rc); @@ -403,7 +375,7 @@ standard_dev_test(void) rc = st->cmds->remove_device(st, st_opts, "test-id"); crm_debug("Remove test-id: %d", rc); - stonith_key_value_freeall(params, 1, 1); + stonith__key_value_freeall(params, true, true); } static void @@ -528,29 +500,29 @@ test_register_async_devices(int check_event) char buf[16] = { 0, }; stonith_key_value_t *params = NULL; - params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP, - "false_1_node1=1,2"); - params = stonith_key_value_add(params, "mode", "fail"); + params = stonith__key_value_add(params, PCMK_STONITH_HOST_MAP, + "false_1_node1=1,2"); + params = stonith__key_value_add(params, "mode", "fail"); st->cmds->register_device(st, st_opts, "false_1", "stonith-ng", "fence_dummy", params); - stonith_key_value_freeall(params, 1, 1); + stonith__key_value_freeall(params, true, true); params = NULL; - params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP, - "true_1_node1=1,2"); - params = stonith_key_value_add(params, "mode", "pass"); + params = stonith__key_value_add(params, PCMK_STONITH_HOST_MAP, + "true_1_node1=1,2"); + params = stonith__key_value_add(params, "mode", "pass"); st->cmds->register_device(st, st_opts, "true_1", "stonith-ng", "fence_dummy", params); - stonith_key_value_freeall(params, 1, 1); + stonith__key_value_freeall(params, true, true); params = NULL; - params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP, - "custom_timeout_node1=1,2"); - params = stonith_key_value_add(params, "mode", "fail"); - params = stonith_key_value_add(params, "delay", "1000"); + params = stonith__key_value_add(params, PCMK_STONITH_HOST_MAP, + "custom_timeout_node1=1,2"); + params = stonith__key_value_add(params, "mode", "fail"); + params = stonith__key_value_add(params, "delay", "1000"); snprintf(buf, sizeof(buf) - 1, "%d", MAINLOOP_DEFAULT_TIMEOUT + CUSTOM_TIMEOUT_ADDITION); - params = stonith_key_value_add(params, "pcmk_off_timeout", buf); + params = stonith__key_value_add(params, "pcmk_off_timeout", buf); st->cmds->register_device(st, st_opts, "false_custom_timeout", "stonith-ng", "fence_dummy", params); - stonith_key_value_freeall(params, 1, 1); + stonith__key_value_freeall(params, true, true); mainloop_test_done(__func__, true); } @@ -558,9 +530,9 @@ test_register_async_devices(int check_event) static void try_mainloop_connect(int check_event) { - int rc = stonith_api_connect_retry(st, crm_system_name, 10); + int rc = stonith__api_connect_retry(st, crm_system_name, 10); - if (rc == pcmk_ok) { + if (rc == pcmk_rc_ok) { mainloop_test_done(__func__, true); return; } @@ -606,7 +578,7 @@ test_shutdown(int nsig) crm_info("Disconnect: %d", rc); crm_debug("Destroy"); - stonith_api_delete(st); + stonith__api_free(st); } if (rc) { @@ -661,7 +633,7 @@ main(int argc, char **argv) crm_bump_log_level(argc, argv); } - st = stonith_api_new(); + st = stonith__api_new(); if (st == NULL) { exit_code = CRM_EX_DISCONNECT; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, @@ -673,9 +645,6 @@ main(int argc, char **argv) case test_standard: standard_dev_test(); break; - case test_passive: - passive_test(); - break; case test_api_sanity: sanity_tests(); break; diff --git a/daemons/fenced/fenced_cib.c b/daemons/fenced/fenced_cib.c index 90c225569eb..e76b25aeef8 100644 --- a/daemons/fenced/fenced_cib.c +++ b/daemons/fenced/fenced_cib.c @@ -67,50 +67,27 @@ node_has_attr(const char *node, const char *name, const char *value) return (match != NULL); } -static void -add_topology_level(xmlNode *match) -{ - char *desc = NULL; - pcmk__action_result_t result = PCMK__UNKNOWN_RESULT; - - CRM_CHECK(match != NULL, return); - - fenced_register_level(match, &desc, &result); - fenced_send_config_notification(STONITH_OP_LEVEL_ADD, &result, desc); - pcmk__reset_result(&result); - free(desc); -} - -static void -topology_remove_helper(const char *node, int level) -{ - char *desc = NULL; - pcmk__action_result_t result = PCMK__UNKNOWN_RESULT; - xmlNode *data = pcmk__xe_create(NULL, PCMK_XE_FENCING_LEVEL); - - crm_xml_add(data, PCMK__XA_ST_ORIGIN, __func__); - crm_xml_add_int(data, PCMK_XA_INDEX, level); - crm_xml_add(data, PCMK_XA_TARGET, node); - - fenced_unregister_level(data, &desc, &result); - fenced_send_config_notification(STONITH_OP_LEVEL_DEL, &result, desc); - pcmk__reset_result(&result); - pcmk__xml_free(data); - free(desc); -} - static void remove_topology_level(xmlNode *match) { int index = 0; char *key = NULL; + xmlNode *data = NULL; CRM_CHECK(match != NULL, return); key = stonith_level_key(match, fenced_target_by_unknown); crm_element_value_int(match, PCMK_XA_INDEX, &index); - topology_remove_helper(key, index); + + data = pcmk__xe_create(NULL, PCMK_XE_FENCING_LEVEL); + crm_xml_add(data, PCMK__XA_ST_ORIGIN, __func__); + crm_xml_add(data, PCMK_XA_TARGET, key); + crm_xml_add_int(data, PCMK_XA_INDEX, index); + + fenced_unregister_level(data, NULL); + free(key); + pcmk__xml_free(data); } static void @@ -125,7 +102,7 @@ register_fencing_topology(xmlXPathObjectPtr xpathObj) continue; } remove_topology_level(match); - add_topology_level(match); + fenced_register_level(match, NULL); } } @@ -196,7 +173,8 @@ update_stonith_watchdog_timeout_ms(xmlNode *cib) /*! * \internal - * \brief Mark a fence device dirty if its \c cib_registered flag is \c TRUE + * \brief Mark a fence device dirty if its \c fenced_df_cib_registered flag is + * set * * \param[in] key Ignored * \param[in,out] value Fence device (fenced_device_t *) @@ -209,8 +187,8 @@ mark_dirty_if_cib_registered(gpointer key, gpointer value, gpointer user_data) { fenced_device_t *device = value; - if (device->cib_registered) { - device->dirty = TRUE; + if (pcmk_is_set(device->flags, fenced_df_cib_registered)) { + fenced_device_set_flags(device, fenced_df_dirty); } } @@ -232,7 +210,7 @@ device_is_dirty(gpointer key, gpointer value, gpointer user_data) { fenced_device_t *device = value; - return device->dirty; + return pcmk_is_set(device->flags, fenced_df_dirty); } /*! @@ -451,7 +429,7 @@ update_fencing_topology(const char *event, xmlNode *msg) } if (strcmp(op, PCMK_VALUE_CREATE) == 0) { - add_topology_level(change->children); + fenced_register_level(change->children, NULL); } else if (strcmp(op, PCMK_VALUE_MODIFY) == 0) { xmlNode *match = pcmk__xe_first_child(change, @@ -460,7 +438,7 @@ update_fencing_topology(const char *event, xmlNode *msg) if (match != NULL) { remove_topology_level(match->children); - add_topology_level(match->children); + fenced_register_level(match->children, NULL); } } continue; diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c index b31c52bf947..f70f2c56e73 100644 --- a/daemons/fenced/fenced_commands.c +++ b/daemons/fenced/fenced_commands.c @@ -117,6 +117,19 @@ typedef struct { static xmlNode *construct_async_reply(const async_command_t *cmd, const pcmk__action_result_t *result); +/*! + * \internal + * \brief Set a bad fencer API request error in a result object + * + * \param[out] result Result to set + */ +static inline void +set_bad_request_result(pcmk__action_result_t *result) +{ + pcmk__set_result(result, CRM_EX_PROTOCOL, PCMK_EXEC_INVALID, + "Fencer API request missing required information (bug?)"); +} + /*! * \internal * \brief Check whether the fencer's device table contains a watchdog device @@ -164,7 +177,8 @@ fenced_foreach_device_remove(GHRFunc fn) static gboolean is_action_required(const char *action, const fenced_device_t *device) { - return (device != NULL) && device->automatic_unfencing + return (device != NULL) + && pcmk_is_set(device->flags, fenced_df_auto_unfence) && pcmk__str_eq(action, PCMK_ACTION_ON, pcmk__str_none); } @@ -265,7 +279,7 @@ get_action_timeout(const fenced_device_t *device, const char *action, * we will remap to "off", so check timeout for "off" instead */ if (pcmk__str_eq(action, PCMK_ACTION_REBOOT, pcmk__str_none) - && !pcmk_is_set(device->flags, st_device_supports_reboot)) { + && !pcmk_is_set(device->flags, fenced_df_supports_reboot)) { crm_trace("%s doesn't support reboot, using timeout for off instead", device->id); action = PCMK_ACTION_OFF; @@ -337,7 +351,7 @@ fenced_device_supports_on(const char *device_id) 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); + return pcmk_is_set(device->flags, fenced_df_supports_on); } } return false; @@ -500,8 +514,8 @@ get_agent_metadata_cb(gpointer data) { case pcmk_rc_ok: if (device->agent_metadata) { read_action_metadata(device); - stonith__device_parameter_flags(&(device->flags), device->id, - device->agent_metadata); + device->default_host_arg = + stonith__default_host_arg(device->agent_metadata); } return G_SOURCE_REMOVE; @@ -542,7 +556,6 @@ stonith_device_execute(fenced_device_t *device) { int exec_rc = 0; const char *action_str = NULL; - const char *host_arg = NULL; async_command_t *cmd = NULL; stonith_action_t *action = NULL; int active_cmds = 0; @@ -622,7 +635,7 @@ stonith_device_execute(fenced_device_t *device) action_str = cmd->action; if (pcmk__str_eq(cmd->action, PCMK_ACTION_REBOOT, pcmk__str_none) - && !pcmk_is_set(device->flags, st_device_supports_reboot)) { + && !pcmk_is_set(device->flags, fenced_df_supports_reboot)) { crm_notice("Remapping 'reboot' action%s%s using %s to 'off' " "because agent '%s' does not support reboot", @@ -631,16 +644,9 @@ stonith_device_execute(fenced_device_t *device) action_str = PCMK_ACTION_OFF; } - if (pcmk_is_set(device->flags, st_device_supports_parameter_port)) { - host_arg = "port"; - - } else if (pcmk_is_set(device->flags, st_device_supports_parameter_plug)) { - host_arg = "plug"; - } - action = stonith__action_create(device->agent, action_str, cmd->target, cmd->timeout, device->params, - device->aliases, host_arg); + device->aliases, device->default_host_arg); /* for async exec, exec_rc is negative for early error exit otherwise handling of success/errors is done via callbacks */ @@ -929,7 +935,7 @@ get_agent_metadata(const char *agent, xmlNode ** metadata) init_metadata_cache(); buffer = g_hash_table_lookup(metadata_cache, agent); if (buffer == NULL) { - stonith_t *st = stonith_api_new(); + stonith_t *st = stonith__api_new(); int rc; if (st == NULL) { @@ -939,7 +945,7 @@ get_agent_metadata(const char *agent, xmlNode ** metadata) } rc = st->cmds->metadata(st, st_opt_sync_call, agent, NULL, &buffer, 10); - stonith_api_delete(st); + stonith__api_free(st); if (rc || !buffer) { crm_err("Could not retrieve metadata for fencing agent %s", agent); return EAGAIN; @@ -981,14 +987,14 @@ read_action_metadata(fenced_device_t *device) action = crm_element_value(match, PCMK_XA_NAME); if (pcmk__str_eq(action, PCMK_ACTION_LIST, pcmk__str_none)) { - stonith__set_device_flags(device->flags, device->id, - st_device_supports_list); + fenced_device_set_flags(device, fenced_df_supports_list); + } else if (pcmk__str_eq(action, PCMK_ACTION_STATUS, pcmk__str_none)) { - stonith__set_device_flags(device->flags, device->id, - st_device_supports_status); + fenced_device_set_flags(device, fenced_df_supports_status); + } else if (pcmk__str_eq(action, PCMK_ACTION_REBOOT, pcmk__str_none)) { - stonith__set_device_flags(device->flags, device->id, - st_device_supports_reboot); + fenced_device_set_flags(device, fenced_df_supports_reboot); + } else if (pcmk__str_eq(action, PCMK_ACTION_ON, pcmk__str_none)) { /* PCMK_XA_AUTOMATIC means the cluster will unfence a node when it * joins. @@ -998,10 +1004,10 @@ read_action_metadata(fenced_device_t *device) */ if (pcmk__xe_attr_is_true(match, PCMK_XA_AUTOMATIC) || pcmk__xe_attr_is_true(match, PCMK__XA_REQUIRED)) { - device->automatic_unfencing = TRUE; + + fenced_device_set_flags(device, fenced_df_auto_unfence); } - stonith__set_device_flags(device->flags, device->id, - st_device_supports_on); + fenced_device_set_flags(device, fenced_df_supports_on); } if ((action != NULL) @@ -1027,9 +1033,9 @@ target_list_type(fenced_device_t *dev) check_type = PCMK_VALUE_STATIC_LIST; } else if (g_hash_table_lookup(dev->params, PCMK_STONITH_HOST_MAP)) { check_type = PCMK_VALUE_STATIC_LIST; - } else if (pcmk_is_set(dev->flags, st_device_supports_list)) { + } else if (pcmk_is_set(dev->flags, fenced_df_supports_list)) { check_type = PCMK_VALUE_DYNAMIC_LIST; - } else if (pcmk_is_set(dev->flags, st_device_supports_status)) { + } else if (pcmk_is_set(dev->flags, fenced_df_supports_status)) { check_type = PCMK_VALUE_STATUS; } else { check_type = PCMK_VALUE_NONE; @@ -1075,8 +1081,8 @@ build_device_from_xml(const xmlNode *dev) case pcmk_rc_ok: if (device->agent_metadata) { read_action_metadata(device); - stonith__device_parameter_flags(&(device->flags), device->id, - device->agent_metadata); + device->default_host_arg = + stonith__default_host_arg(device->agent_metadata); } break; @@ -1096,7 +1102,7 @@ build_device_from_xml(const xmlNode *dev) value = crm_element_value(dev, PCMK__XA_RSC_PROVIDES); if (pcmk__str_eq(value, PCMK_VALUE_UNFENCING, pcmk__str_casei)) { - device->automatic_unfencing = TRUE; + fenced_device_set_flags(device, fenced_df_auto_unfence); } if (is_action_required(PCMK_ACTION_ON, device)) { @@ -1408,13 +1414,14 @@ fenced_device_register(const xmlNode *dev, bool from_cib) device->id, ndevices, pcmk__plural_s(ndevices)); free_device(device); device = dup; - device->dirty = FALSE; + fenced_device_clear_flags(device, fenced_df_dirty); } else { guint ndevices = 0; fenced_device_t *old = g_hash_table_lookup(device_table, device->id); - if (from_cib && (old != NULL) && old->api_registered) { + if (from_cib && (old != NULL) + && pcmk_is_set(old->flags, fenced_df_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 @@ -1422,7 +1429,7 @@ fenced_device_register(const xmlNode *dev, bool from_cib) */ crm_info("Overwriting existing entry for %s from CIB", device->id); device->pending_ops = old->pending_ops; - device->api_registered = TRUE; + fenced_device_set_flags(device, fenced_df_api_registered); old->pending_ops = NULL; if (device->pending_ops != NULL) { mainloop_set_trigger(device->work); @@ -1436,9 +1443,9 @@ fenced_device_register(const xmlNode *dev, bool from_cib) } if (from_cib) { - device->cib_registered = TRUE; + fenced_device_set_flags(device, fenced_df_cib_registered); } else { - device->api_registered = TRUE; + fenced_device_set_flags(device, fenced_df_api_registered); } done: @@ -1462,23 +1469,28 @@ stonith_device_remove(const char *id, bool from_cib) } if (from_cib) { - device->cib_registered = FALSE; + fenced_device_clear_flags(device, fenced_df_cib_registered); } else { - device->verified = FALSE; - device->api_registered = FALSE; + fenced_device_clear_flags(device, + fenced_df_api_registered|fenced_df_verified); } - if (!device->cib_registered && !device->api_registered) { + if (!pcmk_any_flags_set(device->flags, + fenced_df_api_registered + |fenced_df_cib_registered)) { 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 { // Exactly one is true at this point + const bool cib_registered = pcmk_is_set(device->flags, + fenced_df_cib_registered); + 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")); + (cib_registered? "CIB" : "API")); } } @@ -1588,33 +1600,6 @@ unpack_level_kind(const xmlNode *level) return fenced_target_by_unknown; } -static stonith_key_value_t * -parse_device_list(const char *devices) -{ - int lpc = 0; - int max = 0; - int last = 0; - stonith_key_value_t *output = NULL; - - if (devices == NULL) { - return output; - } - - max = strlen(devices); - for (lpc = 0; lpc <= max; lpc++) { - if (devices[lpc] == ',' || devices[lpc] == 0) { - char *line = strndup(devices + last, lpc - last); - - output = stonith_key_value_add(output, NULL, line); - free(line); - - last = lpc + 1; - } - } - - return output; -} - /*! * \internal * \brief Unpack essential information from topology request XML @@ -1623,14 +1608,13 @@ parse_device_list(const char *devices) * \param[out] mode If not NULL, where to store level kind * \param[out] target If not NULL, where to store representation of target * \param[out] id If not NULL, where to store level number - * \param[out] desc If not NULL, where to store log-friendly level description * * \return Topology level XML from within \p xml, or NULL if not found - * \note The caller is responsible for freeing \p *target and \p *desc if set. + * \note The caller is responsible for freeing \p *target if set. */ static xmlNode * unpack_level_request(xmlNode *xml, enum fenced_target_by *mode, char **target, - int *id, char **desc) + int *id) { enum fenced_target_by local_mode = fenced_target_by_unknown; char *local_target = NULL; @@ -1645,17 +1629,10 @@ unpack_level_request(xmlNode *xml, enum fenced_target_by *mode, char **target, LOG_WARNING); } - if (xml == NULL) { - if (desc != NULL) { - *desc = crm_strdup_printf("missing"); - } - } else { + if (xml != NULL) { local_mode = unpack_level_kind(xml); local_target = stonith_level_key(xml, local_mode); crm_element_value_int(xml, PCMK_XA_INDEX, &local_id); - if (desc != NULL) { - *desc = crm_strdup_printf("%s[%d]", local_target, local_id); - } } if (mode != NULL) { @@ -1684,11 +1661,10 @@ unpack_level_request(xmlNode *xml, enum fenced_target_by *mode, char **target, * the entry's device list for the specified level. * * \param[in] msg XML request for STONITH level registration - * \param[out] desc If not NULL, set to string representation "TARGET[LEVEL]" - * \param[out] result Where to set result of registration + * \param[out] result Where to set result of registration (can be \c NULL) */ void -fenced_register_level(xmlNode *msg, char **desc, pcmk__action_result_t *result) +fenced_register_level(xmlNode *msg, pcmk__action_result_t *result) { int id = 0; xmlNode *level; @@ -1696,14 +1672,13 @@ fenced_register_level(xmlNode *msg, char **desc, pcmk__action_result_t *result) char *target; stonith_topology_t *tp; - stonith_key_value_t *dIter = NULL; - stonith_key_value_t *devices = NULL; + const char *value = NULL; - CRM_CHECK((msg != NULL) && (result != NULL), return); + CRM_CHECK(msg != NULL, return); - level = unpack_level_request(msg, &mode, &target, &id, desc); + level = unpack_level_request(msg, &mode, &target, &id); if (level == NULL) { - fenced_set_protocol_error(result); + set_bad_request_result(result); return; } @@ -1768,14 +1743,20 @@ fenced_register_level(xmlNode *msg, char **desc, pcmk__action_result_t *result) tp->target, id); } - devices = parse_device_list(crm_element_value(level, PCMK_XA_DEVICES)); - for (dIter = devices; dIter; dIter = dIter->next) { - const char *device = dIter->value; + value = crm_element_value(level, PCMK_XA_DEVICES); + if (value != NULL) { + /* Empty string and whitespace are not possible with schema validation + * enabled. Don't bother handling them specially here. + */ + gchar **devices = g_strsplit(value, ",", 0); - crm_trace("Adding device '%s' for %s[%d]", device, tp->target, id); - tp->levels[id] = g_list_append(tp->levels[id], pcmk__str_copy(device)); + for (char **dev = devices; (dev != NULL) && (*dev != NULL); dev++) { + crm_trace("Adding device '%s' for %s[%d]", *dev, tp->target, id); + tp->levels[id] = g_list_append(tp->levels[id], + pcmk__str_copy(*dev)); + } + g_strfreev(devices); } - stonith_key_value_freeall(devices, 1, 1); { int nlevels = count_active_levels(tp); @@ -1796,23 +1777,19 @@ fenced_register_level(xmlNode *msg, char **desc, pcmk__action_result_t *result) * global topology table. * * \param[in] msg XML request for STONITH level registration - * \param[out] desc If not NULL, set to string representation "TARGET[LEVEL]" - * \param[out] result Where to set result of unregistration + * \param[out] result Where to set result of unregistration (can be \c NULL) */ void -fenced_unregister_level(xmlNode *msg, char **desc, - pcmk__action_result_t *result) +fenced_unregister_level(xmlNode *msg, pcmk__action_result_t *result) { int id = -1; stonith_topology_t *tp; char *target; xmlNode *level = NULL; - CRM_CHECK(result != NULL, return); - - level = unpack_level_request(msg, NULL, &target, &id, desc); + level = unpack_level_request(msg, NULL, &target, &id); if (level == NULL) { - fenced_set_protocol_error(result); + set_bad_request_result(result); return; } @@ -1930,7 +1907,7 @@ execute_agent_action(xmlNode *msg, pcmk__action_result_t *result) crm_info("Malformed API action request: device %s, action %s", (id? id : "not specified"), (action? action : "not specified")); - fenced_set_protocol_error(result); + set_bad_request_result(result); return; } @@ -1963,7 +1940,7 @@ execute_agent_action(xmlNode *msg, pcmk__action_result_t *result) "'%s' not found", id); return; - } else if (!device->api_registered + } else if (!pcmk_is_set(device->flags, fenced_df_api_registered) && (strcmp(action, PCMK_ACTION_MONITOR) == 0)) { // Monitors may run only on "started" (API-registered) devices crm_info("Ignoring API '%s' action request because device %s not active", @@ -1976,7 +1953,7 @@ execute_agent_action(xmlNode *msg, pcmk__action_result_t *result) cmd = create_async_command(msg); if (cmd == NULL) { crm_log_xml_warn(msg, "invalid"); - fenced_set_protocol_error(result); + set_bad_request_result(result); return; } @@ -1989,7 +1966,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) { + if (search->support_action_only != fenced_df_none) { fenced_device_t *dev = g_hash_table_lookup(device_table, device); if (dev && !pcmk_is_set(dev->flags, search->support_action_only)) { return; @@ -2133,7 +2110,7 @@ can_fence_host_with_device(fenced_device_t *dev, * or the local node is not allowed to perform it */ if (pcmk__str_eq(action, PCMK_ACTION_ON, pcmk__str_none) - && !pcmk_is_set(dev->flags, st_device_supports_on)) { + && !pcmk_is_set(dev->flags, fenced_df_supports_on)) { check_type = "Agent does not support 'on'"; goto search_report_results; @@ -2445,14 +2422,15 @@ stonith_query_capable_device_cb(GList * devices, void *user_data) crm_xml_add(dev, PCMK_XA_AGENT, device->agent); // Has had successful monitor, list, or status on this node - crm_xml_add_int(dev, PCMK__XA_ST_MONITOR_VERIFIED, device->verified); + crm_xml_add_int(dev, PCMK__XA_ST_MONITOR_VERIFIED, + pcmk_is_set(device->flags, fenced_df_verified)); crm_xml_add_int(dev, PCMK__XA_ST_DEVICE_SUPPORT_FLAGS, device->flags); /* If the originating fencer wants to reboot the node, and we have a * capable device that doesn't support "reboot", remap to "off" instead. */ - if (!pcmk_is_set(device->flags, st_device_supports_reboot) + if (!pcmk_is_set(device->flags, fenced_df_supports_reboot) && pcmk__str_eq(query->action, PCMK_ACTION_REBOOT, pcmk__str_none)) { crm_trace("%s doesn't support reboot, using values for off instead", @@ -2774,12 +2752,13 @@ st_child_done(int pid, const pcmk__action_result_t *result, void *user_data) /* The device is ready to do something else now */ if (device) { - if (!device->verified && pcmk__result_ok(result) + if (!pcmk_is_set(device->flags, fenced_df_verified) + && pcmk__result_ok(result) && pcmk__strcase_any_of(cmd->action, PCMK_ACTION_LIST, PCMK_ACTION_MONITOR, PCMK_ACTION_STATUS, NULL)) { - device->verified = TRUE; + fenced_device_set_flags(device, fenced_df_verified); } mainloop_set_trigger(device->work); @@ -2869,7 +2848,7 @@ fence_locally(xmlNode *msg, pcmk__action_result_t *result) cmd = create_async_command(msg); if (cmd == NULL) { crm_log_xml_warn(msg, "invalid"); - fenced_set_protocol_error(result); + set_bad_request_result(result); return; } @@ -3224,7 +3203,7 @@ handle_query_request(pcmk__request_t *request) get_capable_devices(target, action, timeout, pcmk_is_set(query->call_options, st_opt_allow_self_fencing), - query, stonith_query_capable_device_cb, st_device_supports_none); + query, stonith_query_capable_device_cb, fenced_df_none); return NULL; } @@ -3239,7 +3218,8 @@ handle_notify_request(pcmk__request_t *request) if (flag_name != NULL) { crm_debug("Enabling %s callbacks for client %s", flag_name, pcmk__request_origin(request)); - pcmk__set_client_flags(request->ipc_client, get_stonith_flag(flag_name)); + pcmk__set_client_flags(request->ipc_client, + fenced_parse_notify_flag(flag_name)); } flag_name = crm_element_value(request->xml, PCMK__XA_ST_NOTIFY_DEACTIVATE); @@ -3247,7 +3227,7 @@ handle_notify_request(pcmk__request_t *request) crm_debug("Disabling %s callbacks for client %s", flag_name, pcmk__request_origin(request)); pcmk__clear_client_flags(request->ipc_client, - get_stonith_flag(flag_name)); + fenced_parse_notify_flag(flag_name)); } pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL); @@ -3273,7 +3253,7 @@ handle_relay_request(pcmk__request_t *request) crm_element_value(dev, PCMK__XA_ST_TARGET)); if (initiate_remote_stonith_op(NULL, request->xml, FALSE) == NULL) { - fenced_set_protocol_error(&request->result); + set_bad_request_result(&request->result); return fenced_construct_reply(request->xml, NULL, &request->result); } @@ -3300,7 +3280,7 @@ handle_fence_request(pcmk__request_t *request) NULL); break; default: - fenced_set_protocol_error(&request->result); + set_bad_request_result(&request->result); break; } @@ -3367,7 +3347,7 @@ handle_fence_request(pcmk__request_t *request) } else if (initiate_remote_stonith_op(request->ipc_client, request->xml, FALSE) == NULL) { - fenced_set_protocol_error(&request->result); + set_bad_request_result(&request->result); } else { pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_PENDING, @@ -3452,19 +3432,16 @@ handle_device_delete_request(pcmk__request_t *request) static xmlNode * handle_level_add_request(pcmk__request_t *request) { - char *desc = NULL; const char *op = crm_element_value(request->xml, PCMK__XA_ST_OP); if (is_privileged(request->ipc_client, op)) { - fenced_register_level(request->xml, &desc, &request->result); + fenced_register_level(request->xml, &request->result); } else { - unpack_level_request(request->xml, NULL, NULL, NULL, &desc); + unpack_level_request(request->xml, NULL, NULL, NULL); pcmk__set_result(&request->result, CRM_EX_INSUFFICIENT_PRIV, PCMK_EXEC_INVALID, "Unprivileged users must add level via CIB"); } - fenced_send_config_notification(op, &request->result, desc); - free(desc); return fenced_construct_reply(request->xml, NULL, &request->result); } @@ -3472,19 +3449,16 @@ handle_level_add_request(pcmk__request_t *request) static xmlNode * handle_level_delete_request(pcmk__request_t *request) { - char *desc = NULL; const char *op = crm_element_value(request->xml, PCMK__XA_ST_OP); if (is_privileged(request->ipc_client, op)) { - fenced_unregister_level(request->xml, &desc, &request->result); + fenced_unregister_level(request->xml, &request->result); } else { - unpack_level_request(request->xml, NULL, NULL, NULL, &desc); + unpack_level_request(request->xml, NULL, NULL, NULL); pcmk__set_result(&request->result, CRM_EX_INSUFFICIENT_PRIV, PCMK_EXEC_INVALID, "Unprivileged users must delete level via CIB"); } - fenced_send_config_notification(op, &request->result, desc); - free(desc); return fenced_construct_reply(request->xml, NULL, &request->result); } diff --git a/daemons/fenced/fenced_history.c b/daemons/fenced/fenced_history.c index 9807a7f38cd..412fbd3e8d1 100644 --- a/daemons/fenced/fenced_history.c +++ b/daemons/fenced/fenced_history.c @@ -344,8 +344,8 @@ stonith_local_history_diff_and_merge(GHashTable *remote_history, crm_debug("Updating outdated pending operation %.8s " "(state=%s) according to the one (state=%s) from " "remote peer history", - op->id, stonith_op_state_str(op->state), - stonith_op_state_str(remote_op->state)); + op->id, stonith__op_state_text(op->state), + stonith__op_state_text(remote_op->state)); g_hash_table_steal(remote_history, op->id); op->id = remote_op->id; @@ -361,8 +361,8 @@ stonith_local_history_diff_and_merge(GHashTable *remote_history, crm_debug("Broadcasting operation %.8s (state=%s) to " "update the outdated pending one " "(state=%s) in remote peer history", - op->id, stonith_op_state_str(op->state), - stonith_op_state_str(remote_op->state)); + op->id, stonith__op_state_text(op->state), + stonith__op_state_text(remote_op->state)); g_hash_table_remove(remote_history, op->id); diff --git a/daemons/fenced/fenced_remote.c b/daemons/fenced/fenced_remote.c index 42760b8d27d..870c1dc75c1 100644 --- a/daemons/fenced/fenced_remote.c +++ b/daemons/fenced/fenced_remote.c @@ -139,7 +139,9 @@ count_peer_device(gpointer key, gpointer value, gpointer user_data) if (!props->executed[data->op->phase] && (!data->verified_only || props->verified) - && ((data->support_action_only == st_device_supports_none) || pcmk_is_set(props->device_support_flags, data->support_action_only))) { + && ((data->support_action_only == fenced_df_none) + || pcmk_is_set(props->device_support_flags, + data->support_action_only))) { ++(data->count); } } @@ -187,11 +189,17 @@ find_peer_device(const remote_fencing_op_t *op, const peer_device_info_t *peer, { device_properties_t *props = g_hash_table_lookup(peer->devices, device); - if (props && support_action_only != st_device_supports_none && !pcmk_is_set(props->device_support_flags, support_action_only)) { + if (props == NULL) { return NULL; } - return (props && !props->executed[op->phase] - && !props->disallowed[op->phase])? props : NULL; + if ((support_action_only != fenced_df_none) + && !pcmk_is_set(props->device_support_flags, support_action_only)) { + return NULL; + } + if (props->executed[op->phase] || props->disallowed[op->phase]) { + return NULL; + } + return props; } /*! @@ -217,7 +225,8 @@ grab_peer_device(const remote_fencing_op_t *op, peer_device_info_t *peer, } crm_trace("Removing %s from %s (%d remaining)", - device, peer->host, count_peer_devices(op, peer, FALSE, st_device_supports_none)); + device, peer->host, + count_peer_devices(op, peer, FALSE, fenced_df_none)); props->executed[op->phase] = TRUE; return TRUE; } @@ -505,7 +514,7 @@ finalize_op_duplicates(remote_fencing_op_t *op, xmlNode *data) crm_err("Skipping duplicate notification for %s@%s " QB_XS " state=%s id=%.8s", other->client_name, other->originator, - stonith_op_state_str(other->state), other->id); + stonith__op_state_text(other->state), other->id); } } } @@ -764,11 +773,11 @@ remote_op_query_timeout(gpointer data) } else if (op->query_results) { // Query succeeded, so attempt the actual fencing crm_debug("Query %.8s targeting %s complete (state=%s)", - op->id, op->target, stonith_op_state_str(op->state)); + op->id, op->target, stonith__op_state_text(op->state)); request_peer_fencing(op, NULL); } else { crm_debug("Query %.8s targeting %s timed out (state=%s)", - op->id, op->target, stonith_op_state_str(op->state)); + op->id, op->target, stonith__op_state_text(op->state)); finalize_timed_out_op(op, "No capable peers replied to device query " "within timeout"); } @@ -1339,7 +1348,7 @@ initiate_remote_stonith_op(const pcmk__client_t *client, xmlNode *request, crm_notice("Requesting peer fencing (%s) targeting %s " QB_XS " id=%.8s state=%s base_timeout=%ds", op->action, op->target, op->id, - stonith_op_state_str(op->state), op->base_timeout); + stonith__op_state_text(op->state), op->base_timeout); } query = stonith_create_op(op->client_callid, op->id, STONITH_OP_QUERY, @@ -1677,7 +1686,8 @@ get_op_total_timeout(const remote_fencing_op_t *op, for (iter2 = op->query_results; iter2 != NULL; iter = iter2->next) { peer_device_info_t *peer = iter2->data; - if (find_peer_device(op, peer, iter->data, st_device_supports_on)) { + if (find_peer_device(op, peer, iter->data, + fenced_df_supports_on)) { total_timeout += get_device_timeout(op, peer, iter->data, true); break; @@ -1868,7 +1878,7 @@ request_peer_fencing(remote_fencing_op_t *op, peer_device_info_t *peer) crm_trace("Action %.8s targeting %s for %s is %s", op->id, op->target, op->client_name, - stonith_op_state_str(op->state)); + stonith__op_state_text(op->state)); if ((op->phase == st_phase_on) && (op->devices != NULL)) { /* We are in the "on" phase of a remapped topology reboot. If this @@ -2028,7 +2038,7 @@ request_peer_fencing(remote_fencing_op_t *op, peer_device_info_t *peer) /* We've exhausted all available peers */ crm_info("No remaining peers capable of fencing (%s) %s for client %s " QB_XS " state=%s", op->action, op->target, op->client_name, - stonith_op_state_str(op->state)); + stonith__op_state_text(op->state)); CRM_CHECK(op->state < st_done, return); finalize_timed_out_op(op, "All nodes failed, or are unable, to " "fence target"); @@ -2053,7 +2063,7 @@ request_peer_fencing(remote_fencing_op_t *op, peer_device_info_t *peer) crm_info("No peers (out of %d) have devices capable of fencing " "(%s) %s for client %s " QB_XS " state=%s", op->replies, op->action, op->target, op->client_name, - stonith_op_state_str(op->state)); + stonith__op_state_text(op->state)); pcmk__reset_result(&op->result); pcmk__set_result(&op->result, CRM_EX_ERROR, @@ -2074,7 +2084,7 @@ request_peer_fencing(remote_fencing_op_t *op, peer_device_info_t *peer) crm_info("No peers (out of %d) are capable of fencing (%s) %s " "for client %s " QB_XS " state=%s", op->replies, op->action, op->target, op->client_name, - stonith_op_state_str(op->state)); + stonith__op_state_text(op->state)); } op->state = st_failed; @@ -2143,7 +2153,8 @@ all_topology_devices_found(const remote_fencing_op_t *op) if (skip_target && pcmk__str_eq(peer->host, op->target, pcmk__str_casei)) { continue; } - match = find_peer_device(op, peer, device->data, st_device_supports_none); + match = find_peer_device(op, peer, device->data, + fenced_df_none); } if (!match) { return FALSE; @@ -2249,7 +2260,7 @@ add_device_properties(const xmlNode *xml, remote_fencing_op_t *op, // Nodes <2.1.5 won't set this, so assume unfencing in that case rc = pcmk__xe_get_flags(xml, PCMK__XA_ST_DEVICE_SUPPORT_FLAGS, &(props->device_support_flags), - st_device_supports_on); + fenced_df_supports_on); if (rc != pcmk_rc_ok) { crm_warn("Couldn't determine device support for %s " "(assuming unfencing): %s", device, pcmk_rc_str(rc)); @@ -2423,7 +2434,7 @@ process_remote_stonith_query(xmlNode *msg) crm_info("Discarding query result from %s (%d device%s): " "Operation is %s", peer->host, peer->ndevices, pcmk__plural_s(peer->ndevices), - stonith_op_state_str(op->state)); + stonith__op_state_text(op->state)); } return pcmk_ok; diff --git a/daemons/fenced/fenced_scheduler.c b/daemons/fenced/fenced_scheduler.c index a67fef5c3ab..00a1952c177 100644 --- a/daemons/fenced/fenced_scheduler.c +++ b/daemons/fenced/fenced_scheduler.c @@ -220,12 +220,12 @@ register_if_fencing_device(gpointer data, gpointer user_data) if ((name == NULL) || (value == NULL)) { continue; } - params = stonith_key_value_add(params, name, value); + params = stonith__key_value_add(params, name, value); } xml = create_device_registration_xml(rsc_id, st_namespace_any, agent, params, rsc_provides); - stonith_key_value_freeall(params, 1, 1); + stonith__key_value_freeall(params, true, true); 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 cb862b22845..e1b6e1f6cd8 100644 --- a/daemons/fenced/pacemaker-fenced.c +++ b/daemons/fenced/pacemaker-fenced.c @@ -252,28 +252,34 @@ do_local_reply(const xmlNode *notify_src, pcmk__client_t *client, } } -uint64_t -get_stonith_flag(const char *name) +/*! + * \internal + * \brief Parse a fencer client notification type string to a flag + * + * \param[in] type Notification type string + * + * \return Flag corresponding to \p type, or \c fenced_nf_none if none exists + */ +enum fenced_notify_flags +fenced_parse_notify_flag(const char *type) { - if (pcmk__str_eq(name, PCMK__VALUE_ST_NOTIFY_FENCE, pcmk__str_none)) { - return st_callback_notify_fence; - - } else if (pcmk__str_eq(name, STONITH_OP_DEVICE_ADD, pcmk__str_casei)) { - return st_callback_device_add; - - } else if (pcmk__str_eq(name, STONITH_OP_DEVICE_DEL, pcmk__str_casei)) { - return st_callback_device_del; - - } else if (pcmk__str_eq(name, PCMK__VALUE_ST_NOTIFY_HISTORY, - pcmk__str_none)) { - return st_callback_notify_history; - - } else if (pcmk__str_eq(name, PCMK__VALUE_ST_NOTIFY_HISTORY_SYNCED, - pcmk__str_none)) { - return st_callback_notify_history_synced; - + if (pcmk__str_eq(type, PCMK__VALUE_ST_NOTIFY_FENCE, pcmk__str_none)) { + return fenced_nf_fence_result; + } + if (pcmk__str_eq(type, STONITH_OP_DEVICE_ADD, pcmk__str_none)) { + return fenced_nf_device_registered; + } + if (pcmk__str_eq(type, STONITH_OP_DEVICE_DEL, pcmk__str_none)) { + return fenced_nf_device_removed; + } + if (pcmk__str_eq(type, PCMK__VALUE_ST_NOTIFY_HISTORY, pcmk__str_none)) { + return fenced_nf_history_changed; + } + if (pcmk__str_eq(type, PCMK__VALUE_ST_NOTIFY_HISTORY_SYNCED, + pcmk__str_none)) { + return fenced_nf_history_synced; } - return st_callback_unknown; + return fenced_nf_none; } static void @@ -295,7 +301,7 @@ stonith_notify_client(gpointer key, gpointer value, gpointer user_data) return; } - if (pcmk_is_set(client->flags, get_stonith_flag(type))) { + if (pcmk_is_set(client->flags, fenced_parse_notify_flag(type))) { int rc = pcmk__ipc_send_xml(client, 0, update_msg, crm_ipc_server_event); @@ -377,9 +383,8 @@ fenced_send_notification(const char *type, const pcmk__action_result_t *result, * \internal * \brief Send notifications for a configuration change to subscribed clients * - * \param[in] op Notification type (\c STONITH_OP_DEVICE_ADD, - * \c STONITH_OP_DEVICE_DEL, \c STONITH_OP_LEVEL_ADD, or - * \c STONITH_OP_LEVEL_DEL) + * \param[in] op Notification type (\c STONITH_OP_DEVICE_ADD or + * \c STONITH_OP_DEVICE_DEL) * \param[in] result Operation result * \param[in] desc Description of what changed (either device ID or string * representation of level diff --git a/daemons/fenced/pacemaker-fenced.h b/daemons/fenced/pacemaker-fenced.h index c1590438cc1..23a9b032359 100644 --- a/daemons/fenced/pacemaker-fenced.h +++ b/daemons/fenced/pacemaker-fenced.h @@ -26,6 +26,107 @@ */ gboolean stonith_check_fence_tolerance(int tolerance, const char *target, const char *action); +/*! + * \internal + * \brief Flags for \c fenced_device_t configuration, state, and support + */ +enum fenced_device_flags { + //! This flag has no effect + fenced_df_none = UINT32_C(0), + + //! Device supports list action + fenced_df_supports_list = (UINT32_C(1) << 0), + + //! Device supports on action + fenced_df_supports_on = (UINT32_C(1) << 1), + + //! Device supports reboot action + fenced_df_supports_reboot = (UINT32_C(1) << 2), + + //! Device supports status action + fenced_df_supports_status = (UINT32_C(1) << 3), + + //! Device is automatically used to unfence newly joined nodes + fenced_df_auto_unfence = (UINT32_C(1) << 4), + + //! Device has run a successful list, status, or monitor action on this node + fenced_df_verified = (UINT32_C(1) << 5), + + //! Device has been registered via the stonith API + fenced_df_api_registered = (UINT32_C(1) << 6), + + //! Device has been registered via the fencer's CIB diff callback + fenced_df_cib_registered = (UINT32_C(1) << 7), + + //! Device has not yet been re-registered after a CIB change + fenced_df_dirty = (UINT32_C(1) << 8), +}; + +/*! + * \internal + * \brief Set flags for a fencing device + * + * \param[in,out] device Device whose flags to set (\c fenced_device_t) + * \param[in] set_flags Group of enum fenced_device_flags to set + */ +#define fenced_device_set_flags(device, set_flags) do { \ + pcmk__assert((device) != NULL); \ + (device)->flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE, \ + "Fence device", (device)->id, \ + (device)->flags, set_flags, \ + #set_flags); \ + } while (0) + +/*! + * \internal + * \brief Clear flags for a fencing device + * + * \param[in,out] device Device whose flags to clear (\c fenced_device_t) + * \param[in] clear_flags Group of enum fenced_device_flags to + * clear + */ +#define fenced_device_clear_flags(device, clear_flags) do { \ + pcmk__assert((device) != NULL); \ + (device)->flags = pcmk__clear_flags_as(__func__, __LINE__, \ + LOG_TRACE, "Fence device", \ + (device)->id, \ + (device)->flags, \ + clear_flags, #clear_flags); \ + } while (0) + +/*! + * \internal + * \brief Flags for fencer client notification types + */ +enum fenced_notify_flags { + //! This flag has no effect + fenced_nf_none = UINT32_C(0), + + //! Notify about fencing operation results + fenced_nf_fence_result = (UINT32_C(1) << 0), + + // @TODO Consider notifying about device registrations via the CIB + //! Notify about fencing device registrations via the fencer API + fenced_nf_device_registered = (UINT32_C(1) << 1), + + // @TODO Consider notifying about device removals via the CIB + //! Notify about fencing device removals via the fencer API + fenced_nf_device_removed = (UINT32_C(1) << 2), + + //! Notify about changes to fencing history + fenced_nf_history_changed = (UINT32_C(1) << 3), + + /* @FIXME A comment in stonith_fence_history() says its check is not + * conclusive: it may send a "history synced" notification when the history + * has not been synced. Hence "might have been synced" below. Try to find a + * better test. + */ + //! Notify when the fencing history might have been synced + fenced_nf_history_synced = (UINT32_C(1) << 4), +}; + +enum fenced_notify_flags fenced_parse_notify_flag(const char *type); + typedef struct { char *id; char *agent; @@ -36,10 +137,7 @@ typedef struct { GList *targets; time_t targets_age; - /* whether the cluster should automatically unfence nodes with the device */ - gboolean automatic_unfencing; - - uint32_t flags; // Group of enum st_device_flags + uint32_t flags; // Group of enum fenced_device_flags GHashTable *params; GHashTable *aliases; @@ -47,14 +145,7 @@ typedef struct { mainloop_timer_t *timer; crm_trigger_t *work; xmlNode *agent_metadata; - - /*! A verified device is one that has contacted the - * agent successfully to perform a monitor operation */ - gboolean verified; - - gboolean cib_registered; - gboolean api_registered; - gboolean dirty; + const char *default_host_arg; } fenced_device_t; /* These values are used to index certain arrays by "phase". Usually an @@ -167,16 +258,6 @@ typedef struct remote_fencing_op_s { void fenced_broadcast_op_result(const remote_fencing_op_t *op, bool op_merged); -// Fencer-specific client flags -enum st_client_flags { - st_callback_unknown = UINT64_C(0), - st_callback_notify_fence = (UINT64_C(1) << 0), - st_callback_device_add = (UINT64_C(1) << 2), - st_callback_device_del = (UINT64_C(1) << 4), - st_callback_notify_history = (UINT64_C(1) << 5), - st_callback_notify_history_synced = (UINT64_C(1) << 6) -}; - // How the user specified the target of a topology level enum fenced_target_by { fenced_target_by_unknown = -1, // Invalid or not yet parsed @@ -228,8 +309,6 @@ void init_stonith_remote_op_hash_table(GHashTable **table); void free_metadata_cache(void); void fenced_unregister_handlers(void); -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); @@ -238,10 +317,8 @@ int fenced_device_register(const xmlNode *dev, bool from_cib); void stonith_device_remove(const char *id, bool from_cib); char *stonith_level_key(const xmlNode *msg, enum fenced_target_by); -void fenced_register_level(xmlNode *msg, char **desc, - pcmk__action_result_t *result); -void fenced_unregister_level(xmlNode *msg, char **desc, - pcmk__action_result_t *result); +void fenced_register_level(xmlNode *msg, pcmk__action_result_t *result); +void fenced_unregister_level(xmlNode *msg, pcmk__action_result_t *result); stonith_topology_t *find_topology_for_host(const char *host); @@ -300,29 +377,22 @@ const char *fenced_get_local_node(void); void fenced_scheduler_cleanup(void); void fenced_scheduler_run(xmlNode *cib); -static inline void -fenced_set_protocol_error(pcmk__action_result_t *result) -{ - pcmk__set_result(result, CRM_EX_PROTOCOL, PCMK_EXEC_INVALID, - "Fencer API request missing required information (bug?)"); -} - /*! * \internal * \brief Get the device flag to use with a given action when searching devices * * \param[in] action Action to check * - * \return st_device_supports_on if \p action is "on", otherwise - * st_device_supports_none + * \return \c fenced_df_supports_on if \p action is "on", otherwise + * \c fenced_df_none */ static inline uint32_t fenced_support_flag(const char *action) { if (pcmk__str_eq(action, PCMK_ACTION_ON, pcmk__str_none)) { - return st_device_supports_on; + return fenced_df_supports_on; } - return st_device_supports_none; + return fenced_df_none; } extern GHashTable *topology; diff --git a/include/crm/fencing/internal.h b/include/crm/fencing/internal.h index 46159936457..f81044ddfa7 100644 --- a/include/crm/fencing/internal.h +++ b/include/crm/fencing/internal.h @@ -10,6 +10,8 @@ #ifndef PCMK__CRM_FENCING_INTERNAL__H #define PCMK__CRM_FENCING_INTERNAL__H +#include // bool + #include #include #include @@ -21,22 +23,19 @@ extern "C" { #endif -enum st_device_flags { - st_device_supports_none = (0 << 0), - st_device_supports_list = (1 << 0), - st_device_supports_status = (1 << 1), - st_device_supports_reboot = (1 << 2), - st_device_supports_parameter_plug = (1 << 3), - st_device_supports_parameter_port = (1 << 4), - st_device_supports_on = (1 << 5), -}; - -#define stonith__set_device_flags(device_flags, device_id, flags_to_set) do { \ - device_flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE, \ - "Fence device", device_id, \ - (device_flags), (flags_to_set), \ - #flags_to_set); \ - } while (0) +stonith_t *stonith__api_new(void); +void stonith__api_free(stonith_t *stonith_api); +int stonith__api_dispatch(stonith_t *stonith_api); + +int stonith__api_connect_retry(stonith_t *stonith, const char *name, + int max_attempts); + +bool stonith__agent_exists(const char *name); + +stonith_key_value_t *stonith__key_value_add(stonith_key_value_t *head, + const char *key, const char *value); +void stonith__key_value_freeall(stonith_key_value_t *head, bool keys, + bool values); #define stonith__set_call_options(st_call_opts, call_for, flags_to_set) do { \ st_call_opts = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE, \ @@ -96,13 +95,12 @@ void stonith__register_messages(pcmk__output_t *out); GList *stonith__parse_targets(const char *hosts); +void stonith__history_free(stonith_history_t *head); const char *stonith__later_succeeded(const stonith_history_t *event, const stonith_history_t *top_history); stonith_history_t *stonith__sort_history(stonith_history_t *history); -void stonith__device_parameter_flags(uint32_t *device_flags, - const char *device_name, - xmlNode *metadata); +const char *stonith__default_host_arg(xmlNode *metadata); /* Only 1-9 is allowed for fencing topology levels, * however, 0 is used to unregister all levels in @@ -153,6 +151,8 @@ gchar *stonith__history_description(const stonith_history_t *event, const char *later_succeeded, uint32_t show_opts); +const char *stonith__op_state_text(enum op_state state); + /*! * \internal * \brief Is a fencing operation in pending state? @@ -177,7 +177,6 @@ gboolean stonith__watchdog_fencing_enabled_for_node_api(stonith_t *st, const cha * \param[in,out] st Fencer connection to use * \param[in] call_options Group of enum stonith_call_options * \param[in] rsc_id Resource to validate - * \param[in] namespace_s Type of fence agent to search for * \param[in] agent Fence agent to validate * \param[in,out] params Fence device configuration parameters * \param[in] timeout_sec How long to wait for operation to complete @@ -187,9 +186,8 @@ gboolean stonith__watchdog_fencing_enabled_for_node_api(stonith_t *st, const cha * \return Standard Pacemaker return code */ int stonith__validate(stonith_t *st, int call_options, const char *rsc_id, - const char *namespace_s, const char *agent, - GHashTable *params, int timeout_sec, char **output, - char **error_output); + const char *agent, GHashTable *params, int timeout_sec, + char **output, char **error_output); #ifdef __cplusplus } diff --git a/include/crm/stonith-ng.h b/include/crm/stonith-ng.h index 3ae63885730..2f0b0e84013 100644 --- a/include/crm/stonith-ng.h +++ b/include/crm/stonith-ng.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2024 the Pacemaker project contributors + * Copyright 2004-2025 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -20,10 +20,14 @@ extern "C" { * \ingroup fencing */ -/* IMPORTANT: DLM source code includes this file directly, without having access - * to other Pacemaker headers on its include path, so this file should *not* - * include any other Pacemaker headers. (DLM might be updated to avoid the - * issue, but we should still follow this guideline for a long time after.) +/* IMPORTANT: dlm source code includes this file directly. Until dlm v4.2.0 + * (commit 5afd9fdc), dlm did not have access to other Pacemaker headers on its + * include path. This file should *not* include any other Pacemaker headers + * until we decide that we no longer need to support dlm versions older than + * v4.2.0. + * + * @COMPAT Remove this restriction and take any opportunities to simplify code + * when possible. */ # include @@ -32,100 +36,140 @@ extern "C" { # include // uint32_t # include // time_t -/* *INDENT-OFF* */ +// @TODO Keep this definition but make it internal +/*! + * \brief Fencer API connection state + * \deprecated Do not use + */ enum stonith_state { stonith_connected_command, stonith_connected_query, stonith_disconnected, }; -//! Flags that can be set in call options for API requests +// @TODO Keep this definition but make it internal +/*! + * \brief Flags that can be set in call options for API requests + * + * \deprecated Do not use + */ enum stonith_call_options { - //! No options + // No options + //! \deprecated Do not use st_opt_none = 0, #if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) - //! \deprecated Unused + //! \deprecated Do not use st_opt_verbose = (1 << 0), #endif - //! The fencing target is allowed to execute the request + // The fencing target is allowed to execute the request + //! \deprecated Do not use st_opt_allow_self_fencing = (1 << 1), #if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) - //! \deprecated Use st_opt_allow_self_fencing instead + //! \deprecated Do not use st_opt_allow_suicide = st_opt_allow_self_fencing, #endif // Used internally to indicate that request is manual fence confirmation - //! \internal Do not use + // \internal Do not use + //! \deprecated Do not use st_opt_manual_ack = (1 << 3), - //! Do not return any reply from server + // Do not return any reply from server + //! \deprecated Do not use st_opt_discard_reply = (1 << 4), // Used internally to indicate that request requires a fencing topology - //! \internal Do not use + // \internal Do not use + //! \deprecated Do not use st_opt_topology = (1 << 6), #if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) - //! \deprecated Unused + //! \deprecated Do not use st_opt_scope_local = (1 << 8), #endif - //! Interpret target as node cluster layer ID instead of name + // Interpret target as node cluster layer ID instead of name + //! \deprecated Do not use st_opt_cs_nodeid = (1 << 9), - //! Wait for request to be completed before returning + // Wait for request to be completed before returning + //! \deprecated Do not use st_opt_sync_call = (1 << 12), - //! Request that server send an update with optimal callback timeout + // Request that server send an update with optimal callback timeout + //! \deprecated Do not use st_opt_timeout_updates = (1 << 13), - //! Invoke callback only if request succeeded + // Invoke callback only if request succeeded + //! \deprecated Do not use st_opt_report_only_success = (1 << 14), - //! For a fence history request, request that the history be cleared + // For a fence history request, request that the history be cleared + //! \deprecated Do not use st_opt_cleanup = (1 << 19), - //! For a fence history request, broadcast the request to all nodes + // For a fence history request, broadcast the request to all nodes + //! \deprecated Do not use st_opt_broadcast = (1 << 20), }; -/*! Order matters here, do not change values */ -enum op_state -{ - st_query, - st_exec, - st_done, - st_duplicate, - st_failed, +// Order matters here, do not change values +// @TODO Keep this definition but make it internal +/*! + * \brief Fencing operation states + * \deprecated Do not use + */ +enum op_state { + st_query, //! \deprecated Do not use + st_exec, //! \deprecated Do not use + st_done, //! \deprecated Do not use + st_duplicate, //! \deprecated Do not use + st_failed, //! \deprecated Do not use }; -// Supported fence agent interface standards +// @TODO Keep this definition but make it internal +/*! + * \brief Supported fence agent interface standards + * \deprecated Do not use + */ enum stonith_namespace { - st_namespace_invalid, - st_namespace_any, - st_namespace_internal, // Implemented internally by Pacemaker + st_namespace_invalid, //! \deprecated Do not use + st_namespace_any, //! \deprecated Do not use + + // Implemented internally by Pacemaker + st_namespace_internal, //! \deprecated Do not use /* Neither of these projects are active any longer, but the fence agent * interfaces they created are still in use and supported by Pacemaker. */ - st_namespace_rhcs, // Red Hat Cluster Suite compatible - st_namespace_lha, // Linux-HA compatible -}; + // Red Hat Cluster Suite compatible + st_namespace_rhcs, //! \deprecated Do not use -enum stonith_namespace stonith_text2namespace(const char *namespace_s); -const char *stonith_namespace2text(enum stonith_namespace st_namespace); -enum stonith_namespace stonith_get_namespace(const char *agent, - const char *namespace_s); + // Linux-HA compatible + st_namespace_lha, //! \deprecated Do not use +}; +/* @COMPAT Drop this and use a GList/GSList of pcmk_nvpair_t or a GHashtable as + * appropriate + */ +/*! + * \brief Key-value pair list node + * \deprecated Do not use + */ typedef struct stonith_key_value_s { char *key; char *value; - struct stonith_key_value_s *next; + struct stonith_key_value_s *next; } stonith_key_value_t; +// @TODO Keep this definition but make it internal +/*! + * \brief Fencing history entry + * \deprecated Do not use + */ typedef struct stonith_history_s { char *target; char *action; @@ -139,8 +183,14 @@ typedef struct stonith_history_s { char *exit_reason; } stonith_history_t; +// @TODO Keep this typedef but rename it and make it internal typedef struct stonith_s stonith_t; +// @TODO Keep this definition but make it internal +/*! + * \brief Fencing event + * \deprecated Do not use + */ typedef struct stonith_event_s { char *id; char *operation; @@ -152,13 +202,17 @@ typedef struct stonith_event_s { char *device; - /*! The name of the client that initiated the action. */ + // Name of the client that initiated the action char *client_origin; - //! \internal This field should be treated as internal to Pacemaker void *opaque; } stonith_event_t; +// @TODO Keep this definition but make it internal +/*! + * \brief Data for an asynchronous fencing request callback + * \deprecated Do not use + */ typedef struct stonith_callback_data_s { int rc; int call_id; @@ -168,12 +222,17 @@ typedef struct stonith_callback_data_s { void *opaque; } stonith_callback_data_t; -typedef struct stonith_api_operations_s -{ +// @TODO Keep this object but make it internal +/*! + * \brief Fencer API operations + * \deprecated Use appropriate functions in libpacemaker instead + */ +typedef struct stonith_api_operations_s { /*! * \brief Destroy a fencer connection * * \param[in,out] st Fencer connection to destroy + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*free) (stonith_t *st); @@ -186,6 +245,7 @@ typedef struct stonith_api_operations_s * store IPC file descriptor here * * \return Legacy Pacemaker return code + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*connect) (stonith_t *st, const char *name, int *stonith_fd); @@ -195,6 +255,7 @@ typedef struct stonith_api_operations_s * \param[in,out] st Fencer connection to disconnect * * \return Legacy Pacemaker return code + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*disconnect)(stonith_t *st); @@ -207,6 +268,7 @@ typedef struct stonith_api_operations_s * * \return pcmk_ok (if synchronous) or positive call ID (if asynchronous) * on success, otherwise a negative legacy Pacemaker return code + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*remove_device)(stonith_t *st, int options, const char *name); @@ -225,6 +287,7 @@ typedef struct stonith_api_operations_s * * \return pcmk_ok (if synchronous) or positive call ID (if asynchronous) * on success, otherwise a negative legacy Pacemaker return code + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*register_device)(stonith_t *st, int options, const char *id, const char *namespace_s, const char *agent, @@ -240,6 +303,8 @@ typedef struct stonith_api_operations_s * * \return pcmk_ok (if synchronous) or positive call ID (if asynchronous) * on success, otherwise a negative legacy Pacemaker return code + * \note Not used internally + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*remove_level)(stonith_t *st, int options, const char *node, int level); @@ -255,6 +320,8 @@ typedef struct stonith_api_operations_s * * \return pcmk_ok (if synchronous) or positive call ID (if asynchronous) * on success, otherwise a negative legacy Pacemaker return code + * \note Used only by cts-fence-helper.c internally + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*register_level)(stonith_t *st, int options, const char *node, int level, const stonith_key_value_t *device_list); @@ -266,15 +333,13 @@ typedef struct stonith_api_operations_s * \param[in] call_options Group of enum stonith_call_options * (currently ignored) * \param[in] agent Fence agent to query - * \param[in] namespace_s Type of fence agent to search for ("redhat" - * or "stonith-ng" for RHCS-style, "internal" - * for Pacemaker-internal devices, "heartbeat" - * for LHA-style, or "any" or NULL for any) + * \param[in] namespace_s Ignored * \param[out] output Where to store metadata * \param[in] timeout_sec Error if not complete within this time * * \return Legacy Pacemaker return code * \note The caller is responsible for freeing *output using free(). + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*metadata)(stonith_t *stonith, int call_options, const char *agent, const char *namespace_s, char **output, int timeout_sec); @@ -290,12 +355,12 @@ typedef struct stonith_api_operations_s * Pacemaker-internal devices, "heartbeat" for * LHA-style, or "any" or NULL for all) * \param[out] devices Where to store agent list - * \param[in] timeout Error if unable to complete within this - * (currently ignored) + * \param[in] timeout Ignored * * \return Number of items in list on success, or negative errno otherwise * \note The caller is responsible for freeing the returned list with - * stonith_key_value_freeall(). + * \c stonith__key_value_freeall(). + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*list_agents)(stonith_t *stonith, int call_options, const char *namespace_s, stonith_key_value_t **devices, @@ -312,6 +377,7 @@ typedef struct stonith_api_operations_s * * \return pcmk_ok (if synchronous) or positive call ID (if asynchronous) * on success, otherwise a negative legacy Pacemaker return code + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*list)(stonith_t *stonith, int call_options, const char *id, char **list_info, int timeout); @@ -326,6 +392,7 @@ typedef struct stonith_api_operations_s * * \return pcmk_ok (if synchronous) or positive call ID (if asynchronous) * on success, otherwise a negative legacy Pacemaker return code + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*monitor)(stonith_t *stonith, int call_options, const char *id, int timeout); @@ -341,6 +408,8 @@ typedef struct stonith_api_operations_s * * \return pcmk_ok (if synchronous) or positive call ID (if asynchronous) * on success, otherwise a negative legacy Pacemaker return code + * \note Used only by cts-fence-helper.c internally + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*status)(stonith_t *stonith, int call_options, const char *id, const char *port, int timeout); @@ -358,6 +427,7 @@ typedef struct stonith_api_operations_s * will be returned. * * \return Number of items in list on success, or negative errno otherwise + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*query)(stonith_t *stonith, int call_options, const char *target, stonith_key_value_t **devices, int timeout); @@ -376,6 +446,10 @@ typedef struct stonith_api_operations_s * * \return pcmk_ok (if synchronous) or positive call ID (if asynchronous) * on success, otherwise a negative legacy Pacemaker return code + * \note Used only by cts-fence-helper.c and \c stonith_api_kick() + * internally. The latter might go away eventually if dlm starts using + * \c pcmk_request_fencing(). + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*fence)(stonith_t *stonith, int call_options, const char *node, const char *action, int timeout, int tolerance); @@ -389,6 +463,7 @@ typedef struct stonith_api_operations_s * * \return pcmk_ok (if synchronous) or positive call ID (if asynchronous) * on success, otherwise a negative legacy Pacemaker return code + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*confirm)(stonith_t *stonith, int call_options, const char *target); @@ -402,6 +477,7 @@ typedef struct stonith_api_operations_s * \param[in] timeout Error if unable to complete within this * * \return Legacy Pacemaker return code + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*history)(stonith_t *stonith, int call_options, const char *node, stonith_history_t **history, int timeout); @@ -414,6 +490,7 @@ typedef struct stonith_api_operations_s * \param[in] callback Callback to register * * \return Legacy Pacemaker return code + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*register_notification)(stonith_t *stonith, const char *event, void (*callback)(stonith_t *st, @@ -426,6 +503,7 @@ typedef struct stonith_api_operations_s * \param[in] event Event to unregister callbacks for (NULL for all) * * \return Legacy Pacemaker return code + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*remove_notification)(stonith_t *stonith, const char *event); @@ -445,6 +523,7 @@ typedef struct stonith_api_operations_s * * \return \c TRUE on success, \c FALSE if call_id indicates error, * or -EINVAL if \p stonith is not valid + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*register_callback)(stonith_t *stonith, int call_id, int timeout, int options, void *user_data, @@ -461,6 +540,8 @@ typedef struct stonith_api_operations_s * \param[in] all_callbacks If true, unregister all callbacks * * \return pcmk_ok + * \note Not used internally (but perhaps it should be) + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*remove_callback)(stonith_t *stonith, int call_id, bool all_callbacks); @@ -484,6 +565,7 @@ typedef struct stonith_api_operations_s * on success, otherwise a negative legacy Pacemaker return code * \note The caller should set only one of \p node, \p pattern, or \p attr * and \p value. + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*remove_level_full)(stonith_t *st, int options, const char *node, const char *pattern, @@ -511,6 +593,7 @@ typedef struct stonith_api_operations_s * on success, otherwise a negative legacy Pacemaker return code * * \note The caller should set only one of node, pattern or attr/value. + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*register_level_full)(stonith_t *st, int options, const char *node, const char *pattern, @@ -523,10 +606,7 @@ typedef struct stonith_api_operations_s * \param[in,out] st Fencer connection to use * \param[in] call_options Group of enum stonith_call_options * \param[in] rsc_id ID used to replace CIB secrets in \p params - * \param[in] namespace_s Type of fence agent to validate ("redhat" - * or "stonith-ng" for RHCS-style, "internal" - * for Pacemaker-internal devices, "heartbeat" - * for LHA-style, or "any" or NULL for any) + * \param[in] namespace_s Ignored * \param[in] agent Fence agent to validate * \param[in] params Configuration parameters to pass to agent * \param[in] timeout Fail if no response within this many seconds @@ -536,6 +616,8 @@ typedef struct stonith_api_operations_s * \return pcmk_ok if validation succeeds, -errno otherwise * \note If pcmk_ok is returned, the caller is responsible for freeing * the output (if requested) with free(). + * \note Not used internally + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*validate)(stonith_t *st, int call_options, const char *rsc_id, const char *namespace_s, const char *agent, @@ -559,6 +641,7 @@ typedef struct stonith_api_operations_s * * \return pcmk_ok (if synchronous) or positive call ID (if asynchronous) * on success, otherwise a negative legacy Pacemaker return code + * \deprecated \c stonith_api_operations_t is deprecated for external use */ int (*fence_with_delay)(stonith_t *stonith, int call_options, const char *node, const char *action, int timeout, @@ -566,39 +649,24 @@ typedef struct stonith_api_operations_s } stonith_api_operations_t; +// @TODO Keep this object but make it internal +/*! + * \brief Fencer API connection object + * \deprecated Use appropriate functions in libpacemaker instead + */ struct stonith_s { enum stonith_state state; int call_id; void *st_private; stonith_api_operations_t *cmds; }; -/* *INDENT-ON* */ - -/* Core functions */ -stonith_t *stonith_api_new(void); -void stonith_api_delete(stonith_t * st); - -void stonith_dump_pending_callbacks(stonith_t * st); - -bool stonith_dispatch(stonith_t * st); - -stonith_key_value_t *stonith_key_value_add(stonith_key_value_t * kvp, const char *key, - const char *value); -void stonith_key_value_freeall(stonith_key_value_t * kvp, int keys, int values); - -void stonith_history_free(stonith_history_t *history); - -// Convenience functions -int stonith_api_connect_retry(stonith_t *st, const char *name, - int max_attempts); -const char *stonith_op_state_str(enum op_state state); /* Basic helpers that allows nodes to be fenced and the history to be * queried without mainloop or the caller understanding the full API * * At least one of nodeid and uname are required * - * NOTE: DLM uses both of these + * NOTE: dlm (as of at least 4.3.0) uses these (via the helper functions below) */ int stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off); time_t stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress); @@ -645,9 +713,11 @@ time_t stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress); #define STONITH_LIBRARY "libstonithd.so.56" +// NOTE: dlm (as of at least 4.3.0) uses these (via the helper functions below) typedef int (*st_api_kick_fn) (int nodeid, const char *uname, int timeout, bool off); typedef time_t (*st_api_time_fn) (int nodeid, const char *uname, bool in_progress); +// NOTE: dlm (as of at least 4.3.0) uses this static inline int stonith_api_kick_helper(uint32_t nodeid, int timeout, bool off) { @@ -671,6 +741,7 @@ stonith_api_kick_helper(uint32_t nodeid, int timeout, bool off) return (*st_kick_fn) (nodeid, NULL, timeout, off); } +// NOTE: dlm (as of at least 4.3.0) uses this static inline time_t stonith_api_time_helper(uint32_t nodeid, bool in_progress) { @@ -690,24 +761,60 @@ stonith_api_time_helper(uint32_t nodeid, bool in_progress) return (*st_time_fn) (nodeid, NULL, in_progress); } -/** - * Does the given agent describe a stonith resource that can exist? - * - * \param[in] agent What is the name of the agent? - * \param[in] timeout Timeout to use when querying. If 0 is given, - * use a default of 120. - * - * \return A boolean +#if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) + +/* Normally we'd put this section in a separate file (crm/fencing/compat.h), but + * we can't do that for the reason noted at the top of this file. That does mean + * we have to duplicate these declarations where they're implemented. */ + +//! \deprecated Use appropriate functions in libpacemaker +stonith_t *stonith_api_new(void); + +//! \deprecated Use appropriate functions in libpacemaker +void stonith_api_delete(stonith_t *stonith); + +//! \deprecated Do not use +void stonith_dump_pending_callbacks(stonith_t *stonith); + +//! \deprecated Do not use +bool stonith_dispatch(stonith_t *stonith_api); + +//! \deprecated Do not use +stonith_key_value_t *stonith_key_value_add(stonith_key_value_t *kvp, + const char *key, const char *value); + +//! \deprecated Do not use +void stonith_key_value_freeall(stonith_key_value_t *head, int keys, int values); + +//! \deprecated Do not use +void stonith_history_free(stonith_history_t *head); + +//! \deprecated Do not use +int stonith_api_connect_retry(stonith_t *st, const char *name, + int max_attempts); + +//! \deprecated Do not use +const char *stonith_op_state_str(enum op_state state); + +//! \deprecated Do not use bool stonith_agent_exists(const char *agent, int timeout); -/*! - * \brief Turn fence action into a more readable string - * - * \param[in] action Fence action - */ +//! \deprecated Do not use const char *stonith_action_str(const char *action); +//! \deprecated Do not use +enum stonith_namespace stonith_text2namespace(const char *namespace_s); + +//! \deprecated Do not use +const char *stonith_namespace2text(enum stonith_namespace st_namespace); + +//! \deprecated Do not use +enum stonith_namespace stonith_get_namespace(const char *agent, + const char *namespace_s); + +#endif // !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) + #ifdef __cplusplus } #endif diff --git a/include/pacemaker.h b/include/pacemaker.h index cac2e217657..eae1e233a54 100644 --- a/include/pacemaker.h +++ b/include/pacemaker.h @@ -588,7 +588,7 @@ int pcmk_fence_history(xmlNodePtr *xml, const char *target, unsigned int timeout * * \param[in,out] xml The destination for the result, as an XML tree (if * not NULL, previous contents will be freed and lost) - * \param[in] timeout How long to wait for operation to complete (in ms) + * \param[in] timeout Ignored * * \return Standard Pacemaker return code */ diff --git a/include/pcmki/pcmki_fence.h b/include/pcmki/pcmki_fence.h index 208576bef28..3dec4685639 100644 --- a/include/pcmki/pcmki_fence.h +++ b/include/pcmki/pcmki_fence.h @@ -90,11 +90,10 @@ int pcmk__fence_history(pcmk__output_t *out, stonith_t *st, const char *target, * * \param[in,out] out The output functions structure * \param[in,out] st A connection to the fencer API - * \param[in] timeout How long to wait for the operation to complete (in ms) * * \return Standard Pacemaker return code */ -int pcmk__fence_installed(pcmk__output_t *out, stonith_t *st, unsigned int timeout); +int pcmk__fence_installed(pcmk__output_t *out, stonith_t *st); /*! * \brief When was a device last fenced? diff --git a/lib/fencing/st_actions.c b/lib/fencing/st_actions.c index 5da7acf026d..ad7a17ea26d 100644 --- a/lib/fencing/st_actions.c +++ b/lib/fencing/st_actions.c @@ -110,18 +110,19 @@ append_config_arg(gpointer key, gpointer value, gpointer user_data) * \internal * \brief Create a table of arguments for a fencing action * - * \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] 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 + * \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] device_args Fence device parameters + * \param[in] port_map Target node-to-port mapping for fence device + * \param[in] default_host_arg Default agent parameter for passing target * * \return Newly created hash table of arguments for fencing action */ static GHashTable * make_args(const char *agent, const char *action, const char *target, - GHashTable *device_args, GHashTable *port_map, const char *host_arg) + GHashTable *device_args, GHashTable *port_map, + const char *default_host_arg) { GHashTable *arg_list = NULL; const char *value = NULL; @@ -161,7 +162,7 @@ make_args(const char *agent, const char *action, const char *target, param = g_hash_table_lookup(device_args, PCMK_STONITH_HOST_ARGUMENT); if (param == NULL) { // Use caller's default (likely from agent metadata) - param = host_arg; + param = default_host_arg; } if ((param != NULL) && !pcmk__str_eq(agent, "fence_legacy", pcmk__str_none) @@ -238,13 +239,13 @@ stonith__action_result(stonith_action_t *action) * \internal * \brief Create a new fencing action to be executed * - * \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] 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 - * \param[in] host_arg Agent parameter used to pass target name + * \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] 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 + * \param[in] default_host_arg Default agent parameter for passing target * * \return Newly created fencing action (asserts on error, never NULL) */ @@ -252,12 +253,12 @@ stonith_action_t * stonith__action_create(const char *agent, const char *action_name, const char *target, int timeout_sec, GHashTable *device_args, GHashTable *port_map, - const char *host_arg) + const char *default_host_arg) { stonith_action_t *action = pcmk__assert_alloc(1, sizeof(stonith_action_t)); action->args = make_args(agent, action_name, target, device_args, port_map, - host_arg); + default_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 52d348d27d2..8122af17d91 100644 --- a/lib/fencing/st_client.c +++ b/lib/fencing/st_client.c @@ -85,7 +85,6 @@ struct timer_rec_s { typedef int (*stonith_op_t) (const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **); -bool stonith_dispatch(stonith_t * st); xmlNode *stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data, int call_options); static int stonith_send_command(stonith_t *stonith, const char *op, @@ -96,67 +95,76 @@ static void stonith_connection_destroy(gpointer user_data); static void stonith_send_notification(gpointer data, gpointer user_data); static int stonith_api_del_notification(stonith_t *stonith, const char *event); + /*! - * \brief Get agent namespace by name + * \internal + * \brief Parse fence agent namespace from a string * * \param[in] namespace_s Name of namespace as string * - * \return Namespace as enum value + * \return enum value parsed from \p namespace_s */ -enum stonith_namespace -stonith_text2namespace(const char *namespace_s) +static enum stonith_namespace +parse_namespace(const char *namespace_s) { if (pcmk__str_eq(namespace_s, "any", pcmk__str_null_matches)) { return st_namespace_any; - - } else if (!strcmp(namespace_s, "redhat") - || !strcmp(namespace_s, "stonith-ng")) { + } + /* @TODO Is "redhat" still necessary except for stonith_text2namespace() + * backward compatibility? + */ + if (pcmk__str_any_of(namespace_s, "redhat", "stonith-ng", NULL)) { return st_namespace_rhcs; - - } else if (!strcmp(namespace_s, "internal")) { + } + if (pcmk__str_eq(namespace_s, "internal", pcmk__str_none)) { return st_namespace_internal; - - } else if (!strcmp(namespace_s, "heartbeat")) { + } + if (pcmk__str_eq(namespace_s, "heartbeat", pcmk__str_none)) { return st_namespace_lha; } return st_namespace_invalid; } /*! - * \brief Get agent namespace name + * \internal + * \brief Get name of a fence agent namespace as a string * - * \param[in] namespace Namespace as enum value + * \param[in] st_namespace Namespace as enum value * - * \return Namespace name as string + * \return Name of \p st_namespace as a string */ -const char * -stonith_namespace2text(enum stonith_namespace st_namespace) +static const char * +namespace_text(enum stonith_namespace st_namespace) { switch (st_namespace) { - case st_namespace_any: return "any"; - case st_namespace_rhcs: return "stonith-ng"; - case st_namespace_internal: return "internal"; - case st_namespace_lha: return "heartbeat"; - default: break; + case st_namespace_any: + return "any"; + case st_namespace_rhcs: + return "stonith-ng"; + case st_namespace_internal: + return "internal"; + case st_namespace_lha: + return "heartbeat"; + default: + return "unsupported"; } - return "unsupported"; } /*! - * \brief Determine namespace of a fence agent + * \internal + * \brief Determine fence agent namespace from agent name * - * \param[in] agent Fence agent type - * \param[in] namespace_s Name of agent namespace as string, if known + * This involves external checks (for example, checking the existence of a file + * or calling an external library function). * - * \return Namespace of specified agent, as enum value + * \param[in] agent Fence agent name + * + * \return Namespace to which \p agent belongs, or \c st_namespace_invalid if + * not found */ -enum stonith_namespace -stonith_get_namespace(const char *agent, const char *namespace_s) +static enum stonith_namespace +get_namespace_from_agent(const char *agent) { - if (pcmk__str_eq(namespace_s, "internal", pcmk__str_none)) { - return st_namespace_internal; - } - if (stonith__agent_is_rhcs(agent)) { return st_namespace_rhcs; } @@ -165,7 +173,7 @@ stonith_get_namespace(const char *agent, const char *namespace_s) if (stonith__agent_is_lha(agent)) { return st_namespace_lha; } -#endif +#endif // HAVE_STONITH_STONITH_H return st_namespace_invalid; } @@ -174,7 +182,7 @@ gboolean stonith__watchdog_fencing_enabled_for_node_api(stonith_t *st, const char *node) { gboolean rv = FALSE; - stonith_t *stonith_api = st?st:stonith_api_new(); + stonith_t *stonith_api = (st != NULL)? st : stonith__api_new(); char *list = NULL; if(stonith_api) { @@ -219,7 +227,7 @@ stonith__watchdog_fencing_enabled_for_node_api(stonith_t *st, const char *node) } if (!st) { - stonith_api_delete(stonith_api); + stonith__api_free(stonith_api); } } else { crm_err("Stonith-API for watchdog-fencing-query couldn't be created."); @@ -302,7 +310,7 @@ create_device_registration_xml(const char *id, enum stonith_namespace standard, #if HAVE_STONITH_STONITH_H if (standard == st_namespace_any) { - standard = stonith_get_namespace(agent, NULL); + standard = get_namespace_from_agent(agent); } if (standard == st_namespace_lha) { hash2field((gpointer) "plugin", (gpointer) agent, args); @@ -314,8 +322,7 @@ create_device_registration_xml(const char *id, enum stonith_namespace standard, crm_xml_add(data, PCMK__XA_ST_ORIGIN, __func__); crm_xml_add(data, PCMK_XA_AGENT, agent); if ((standard != st_namespace_any) && (standard != st_namespace_invalid)) { - crm_xml_add(data, PCMK__XA_NAMESPACE, - stonith_namespace2text(standard)); + crm_xml_add(data, PCMK__XA_NAMESPACE, namespace_text(standard)); } if (rsc_provides) { crm_xml_add(data, PCMK__XA_RSC_PROVIDES, rsc_provides); @@ -337,8 +344,7 @@ stonith_api_register_device(stonith_t *st, int call_options, int rc = 0; xmlNode *data = NULL; - data = create_device_registration_xml(id, - stonith_text2namespace(namespace_s), + data = create_device_registration_xml(id, parse_namespace(namespace_s), agent, params, NULL); rc = stonith_send_command(st, STONITH_OP_DEVICE_ADD, data, NULL, call_options, 0); @@ -484,7 +490,7 @@ stonith_api_device_list(stonith_t *stonith, int call_options, int timeout) { int count = 0; - enum stonith_namespace ns = stonith_text2namespace(namespace_s); + enum stonith_namespace ns = parse_namespace(namespace_s); if (devices == NULL) { crm_err("Parameter error: stonith_api_device_list"); @@ -516,14 +522,13 @@ stonith_api_device_metadata(stonith_t *stonith, int call_options, * the cluster is not running, which is important for higher-level tools. */ - enum stonith_namespace ns = stonith_get_namespace(agent, namespace_s); + enum stonith_namespace ns = get_namespace_from_agent(agent); if (timeout_sec <= 0) { timeout_sec = PCMK_DEFAULT_ACTION_TIMEOUT_MS; } - crm_trace("Looking up metadata for %s agent %s", - stonith_namespace2text(ns), agent); + crm_trace("Looking up metadata for %s agent %s", namespace_text(ns), agent); switch (ns) { case st_namespace_rhcs: @@ -573,13 +578,12 @@ stonith_api_query(stonith_t * stonith, int call_options, const char *target, CRM_LOG_ASSERT(match != NULL); if(match != NULL) { + const char *match_id = crm_element_value(match, PCMK_XA_ID); xmlChar *match_path = xmlGetNodePath(match); crm_info("//*[@" PCMK_XA_AGENT "][%d] = %s", lpc, match_path); free(match_path); - *devices = stonith_key_value_add(*devices, NULL, - crm_element_value(match, - PCMK_XA_ID)); + *devices = stonith__key_value_add(*devices, NULL, match_id); } } @@ -762,17 +766,30 @@ stonith_api_history(stonith_t * stonith, int call_options, const char *node, return rc; } -void stonith_history_free(stonith_history_t *history) +/*! + * \internal + * \brief Free a list of fencing history objects and all members of each object + * + * \param[in,out] head Head of fencing history object list + */ +void +stonith__history_free(stonith_history_t *head) { - stonith_history_t *hp, *hp_old; - - for (hp = history; hp; hp_old = hp, hp = hp->next, free(hp_old)) { - free(hp->target); - free(hp->action); - free(hp->origin); - free(hp->delegate); - free(hp->client); - free(hp->exit_reason); + /* @COMPAT Drop "next" member of stonith_history_t, use a GList or GSList, + * and use the appropriate free function (while ensuring the members get + * freed) + */ + while (head != NULL) { + stonith_history_t *next = head->next; + + free(head->target); + free(head->action); + free(head->origin); + free(head->delegate); + free(head->client); + free(head->exit_reason); + free(head); + head = next; } } @@ -1359,26 +1376,6 @@ stonith_api_add_callback(stonith_t * stonith, int call_id, int timeout, int opti return TRUE; } -static void -stonith_dump_pending_op(gpointer key, gpointer value, gpointer user_data) -{ - int call = GPOINTER_TO_INT(key); - stonith_callback_client_t *blob = value; - - crm_debug("Call %d (%s): pending", call, pcmk__s(blob->id, "no ID")); -} - -void -stonith_dump_pending_callbacks(stonith_t * stonith) -{ - stonith_private_t *private = stonith->st_private; - - if (private->stonith_op_callback_table == NULL) { - return; - } - return g_hash_table_foreach(private->stonith_op_callback_table, stonith_dump_pending_op, NULL); -} - /*! * \internal * \brief Get the data section of a fencer notification @@ -1664,35 +1661,43 @@ stonith_send_command(stonith_t * stonith, const char *op, xmlNode * data, xmlNod return rc; } -/* Not used with mainloop */ -bool -stonith_dispatch(stonith_t * st) +/*! + * \internal + * \brief Process IPC messages for a fencer API connection + * + * This is used for testing purposes in scenarios that don't use a mainloop to + * dispatch messages automatically. + * + * \param[in,out] stonith_api Fencer API connetion object + * + * \return Standard Pacemaker return code + */ +int +stonith__api_dispatch(stonith_t *stonith_api) { - gboolean stay_connected = TRUE; stonith_private_t *private = NULL; - pcmk__assert(st != NULL); - private = st->st_private; + pcmk__assert(stonith_api != NULL); + private = stonith_api->st_private; while (crm_ipc_ready(private->ipc)) { - if (crm_ipc_read(private->ipc) > 0) { const char *msg = crm_ipc_buffer(private->ipc); - stonith_dispatch_internal(msg, strlen(msg), st); + stonith_dispatch_internal(msg, strlen(msg), stonith_api); } if (!crm_ipc_connected(private->ipc)) { crm_err("Connection closed"); - stay_connected = FALSE; + return ENOTCONN; } } - return stay_connected; + return pcmk_rc_ok; } static int -stonith_api_free(stonith_t * stonith) +free_stonith_api(stonith_t *stonith) { int rc = pcmk_ok; @@ -1725,15 +1730,6 @@ stonith_api_free(stonith_t * stonith) return rc; } -void -stonith_api_delete(stonith_t * stonith) -{ - crm_trace("Destroying %p", stonith); - if(stonith) { - stonith->cmds->free(stonith); - } -} - static gboolean is_stonith_param(gpointer key, gpointer value, gpointer user_data) { @@ -1742,9 +1738,8 @@ is_stonith_param(gpointer key, gpointer value, gpointer user_data) int stonith__validate(stonith_t *st, int call_options, const char *rsc_id, - const char *namespace_s, const char *agent, - GHashTable *params, int timeout_sec, char **output, - char **error_output) + const char *agent, GHashTable *params, int timeout_sec, + char **output, char **error_output) { int rc = pcmk_rc_ok; @@ -1782,7 +1777,7 @@ stonith__validate(stonith_t *st, int call_options, const char *rsc_id, timeout_sec = PCMK_DEFAULT_ACTION_TIMEOUT_MS; } - switch (stonith_get_namespace(agent, namespace_s)) { + switch (get_namespace_from_agent(agent)) { case st_namespace_rhcs: rc = stonith__rhcs_validate(st, call_options, target, agent, params, host_arg, timeout_sec, @@ -1851,15 +1846,22 @@ stonith_api_validate(stonith_t *st, int call_options, const char *rsc_id, } } - rc = stonith__validate(st, call_options, rsc_id, namespace_s, agent, - params_table, timeout_sec, output, error_output); + rc = stonith__validate(st, call_options, rsc_id, agent, params_table, + timeout_sec, output, error_output); g_hash_table_destroy(params_table); return rc; } +/*! + * \internal + * \brief Create a new fencer API connection object + * + * \return Newly allocated fencer API connection object, or \c NULL on + * allocation failure + */ stonith_t * -stonith_api_new(void) +stonith__api_new(void) { stonith_t *new_stonith = NULL; stonith_private_t *private = NULL; @@ -1891,8 +1893,7 @@ stonith_api_new(void) return NULL; } -/* *INDENT-OFF* */ - new_stonith->cmds->free = stonith_api_free; + new_stonith->cmds->free = free_stonith_api; new_stonith->cmds->connect = stonith_api_signon; new_stonith->cmds->disconnect = stonith_api_signoff; @@ -1922,71 +1923,116 @@ stonith_api_new(void) new_stonith->cmds->register_notification = stonith_api_add_notification; new_stonith->cmds->validate = stonith_api_validate; -/* *INDENT-ON* */ return new_stonith; } /*! - * \brief Make a blocking connection attempt to the fencer + * \internal + * \brief Free a fencer API connection object * - * \param[in,out] st Fencer API object + * \param[in,out] stonith_api Fencer API connection object + */ +void +stonith__api_free(stonith_t *stonith_api) +{ + crm_trace("Destroying %p", stonith_api); + if (stonith_api != NULL) { + stonith_api->cmds->free(stonith_api); + } +} + +/*! + * \internal + * \brief Connect to the fencer, retrying on failure + * + * \param[in,out] stonith Fencer API connection object * \param[in] name Client name to use with fencer - * \param[in] max_attempts Return error if this many attempts fail + * \param[in] max_attempts Maximum number of attempts * - * \return pcmk_ok on success, result of last attempt otherwise + * \return \c pcmk_rc_ok on success, or result of last attempt otherwise */ int -stonith_api_connect_retry(stonith_t *st, const char *name, int max_attempts) +stonith__api_connect_retry(stonith_t *stonith_api, const char *name, + int max_attempts) { - int rc = -EINVAL; // if max_attempts is not positive + int rc = EINVAL; // if max_attempts is not positive for (int attempt = 1; attempt <= max_attempts; attempt++) { - rc = st->cmds->connect(st, name, NULL); - if (rc == pcmk_ok) { - return pcmk_ok; - } else if (attempt < max_attempts) { - crm_notice("Fencer connection attempt %d of %d failed (retrying in 2s): %s " - QB_XS " rc=%d", - attempt, max_attempts, pcmk_strerror(rc), rc); + rc = stonith_api->cmds->connect(stonith_api, name, NULL); + rc = pcmk_legacy2rc(rc); + + if (rc == pcmk_rc_ok) { + return rc; + } + if (attempt < max_attempts) { + crm_notice("Fencer connection attempt %d of %d failed " + "(retrying in 2s): %s " QB_XS " rc=%d", + attempt, max_attempts, pcmk_rc_str(rc), rc); sleep(2); } } crm_notice("Could not connect to fencer: %s " QB_XS " rc=%d", - pcmk_strerror(rc), rc); + pcmk_rc_str(rc), rc); return rc; } +/*! + * \internal + * \brief Append a newly allocated STONITH key-value pair to a list + * + * \param[in,out] head Head of key-value pair list (\c NULL for new list) + * \param[in] key Key to add + * \param[in] value Value to add + * + * \return Head of appended-to list (equal to \p head if \p head is not \c NULL) + * \note The caller is responsible for freeing the return value using + * \c stonith__key_value_freeall(). + */ stonith_key_value_t * -stonith_key_value_add(stonith_key_value_t * head, const char *key, const char *value) +stonith__key_value_add(stonith_key_value_t *head, const char *key, + const char *value) { - stonith_key_value_t *p, *end; + /* @COMPAT Replace this function with pcmk_prepend_nvpair(), and reverse the + * list when finished adding to it; or with a hash table where order does + * not matter + */ + stonith_key_value_t *pair = pcmk__assert_alloc(1, + sizeof(stonith_key_value_t)); - p = pcmk__assert_alloc(1, sizeof(stonith_key_value_t)); - p->key = pcmk__str_copy(key); - p->value = pcmk__str_copy(value); + pair->key = pcmk__str_copy(key); + pair->value = pcmk__str_copy(value); - end = head; - while (end && end->next) { - end = end->next; - } + if (head != NULL) { + stonith_key_value_t *end = head; + + for (; end->next != NULL; end = end->next); + end->next = pair; - if (end) { - end->next = p; } else { - head = p; + head = pair; } return head; } +/*! + * \internal + * \brief Free all items in a \c stonith_key_value_t list + * + * This means freeing the list itself with all of its nodes. Keys and values may + * be freed depending on arguments. + * + * \param[in,out] head Head of list + * \param[in] keys If \c true, free all keys + * \param[in] values If \c true, free all values + */ void -stonith_key_value_freeall(stonith_key_value_t * head, int keys, int values) +stonith__key_value_freeall(stonith_key_value_t *head, bool keys, bool values) { - stonith_key_value_t *p; + while (head != NULL) { + stonith_key_value_t *next = head->next; - while (head) { - p = head->next; if (keys) { free(head->key); } @@ -1994,7 +2040,7 @@ stonith_key_value_freeall(stonith_key_value_t * head, int keys, int values) free(head->value); } free(head); - head = p; + head = next; } } @@ -2005,7 +2051,7 @@ int stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off) { int rc = pcmk_ok; - stonith_t *st = stonith_api_new(); + stonith_t *st = stonith__api_new(); const char *action = off? PCMK_ACTION_OFF : PCMK_ACTION_REBOOT; api_log_open(); @@ -2039,7 +2085,7 @@ stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off) } } - stonith_api_delete(st); + stonith__api_free(st); return rc; } @@ -2048,7 +2094,7 @@ stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress) { int rc = pcmk_ok; time_t when = 0; - stonith_t *st = stonith_api_new(); + stonith_t *st = stonith__api_new(); stonith_history_t *history = NULL, *hp = NULL; if (st == NULL) { @@ -2090,7 +2136,7 @@ stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress) } } - stonith_history_free(history); + stonith__history_free(history); if(rc == pcmk_ok) { api_log(LOG_INFO, "Found %d entries for %u/%s: %d in progress, %d completed", entries, nodeid, uname, progress, completed); @@ -2099,7 +2145,7 @@ stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress) } } - stonith_api_delete(st); + stonith__api_free(st); if(when) { api_log(LOG_INFO, "Node %u/%s last kicked at: %ld", nodeid, uname, (long int)when); @@ -2107,51 +2153,49 @@ stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress) return when; } +/*! + * \internal + * \brief Check whether a fence agent with a given name exists + * + * \param[in] name Agent name + * + * \retval \c true If a fence agent named \p name exists + * \retval \c false Otherwise + */ bool -stonith_agent_exists(const char *agent, int timeout) +stonith__agent_exists(const char *name) { - stonith_t *st = NULL; - stonith_key_value_t *devices = NULL; - stonith_key_value_t *dIter = NULL; - bool rc = FALSE; + stonith_t *stonith_api = NULL; + stonith_key_value_t *agents = NULL; + bool rc = false; - if (agent == NULL) { - return rc; + if (name == NULL) { + return false; } - st = stonith_api_new(); - if (st == NULL) { + stonith_api = stonith__api_new(); + if (stonith_api == NULL) { crm_err("Could not list fence agents: API memory allocation failed"); - return FALSE; + return false; } - st->cmds->list_agents(st, st_opt_sync_call, NULL, &devices, timeout == 0 ? 120 : timeout); - for (dIter = devices; dIter != NULL; dIter = dIter->next) { - if (pcmk__str_eq(dIter->value, agent, pcmk__str_none)) { - rc = TRUE; + // The list_agents method ignores its timeout argument + stonith_api->cmds->list_agents(stonith_api, st_opt_sync_call, NULL, &agents, + 0); + + for (const stonith_key_value_t *iter = agents; iter != NULL; + iter = iter->next) { + if (pcmk__str_eq(iter->value, name, pcmk__str_none)) { + rc = true; break; } } - stonith_key_value_freeall(devices, 1, 1); - stonith_api_delete(st); + stonith__key_value_freeall(agents, true, true); + stonith__api_free(stonith_api); return rc; } -const char * -stonith_action_str(const char *action) -{ - if (action == NULL) { - return "fencing"; - } else if (strcmp(action, PCMK_ACTION_ON) == 0) { - return "unfencing"; - } else if (strcmp(action, PCMK_ACTION_OFF) == 0) { - return "turning off"; - } else { - return action; - } -} - /*! * \internal * \brief Parse a target name from one line of a target list string @@ -2378,23 +2422,31 @@ stonith__sort_history(stonith_history_t *history) } /*! - * \brief Return string equivalent of an operation state value + * \internal + * \brief Return string equivalent of a fencing operation state value * * \param[in] state Fencing operation state value * - * \return Human-friendly string equivalent of state + * \return Human-friendly string equivalent of \p state */ const char * -stonith_op_state_str(enum op_state state) +stonith__op_state_text(enum op_state state) { + // @COMPAT Move this to the fencer after dropping stonith_op_state_str() switch (state) { - case st_query: return "querying"; - case st_exec: return "executing"; - case st_done: return "completed"; - case st_duplicate: return "duplicate"; - case st_failed: return "failed"; + case st_query: + return "querying"; + case st_exec: + return "executing"; + case st_done: + return "completed"; + case st_duplicate: + return "duplicate"; + case st_failed: + return "failed"; + default: + return "unknown"; } - return "unknown"; } stonith_history_t * @@ -2429,46 +2481,53 @@ stonith__event_state_neq(stonith_history_t *history, void *user_data) return history->state != GPOINTER_TO_INT(user_data); } -void -stonith__device_parameter_flags(uint32_t *device_flags, const char *device_name, - xmlNode *metadata) +/*! + * \internal + * \brief Check whether a given parameter exists in a fence agent's metadata + * + * \param[in] metadata Agent metadata + * \param[in] name Parameter name + * + * \retval \c true If \p name exists as a parameter in \p metadata + * \retval \c false Otherwise + */ +static bool +param_is_supported(xmlNode *metadata, const char *name) { - xmlXPathObject *xpath = NULL; - int max = 0; - int lpc = 0; + char *xpath_s = crm_strdup_printf("//" PCMK_XE_PARAMETER + "[@" PCMK_XA_NAME "='%s']", + name); + xmlXPathObject *xpath = pcmk__xpath_search(metadata->doc, xpath_s); + bool supported = (pcmk__xpath_num_results(xpath) > 0); - CRM_CHECK((device_flags != NULL) && (metadata != NULL), return); + free(xpath_s); + xmlXPathFreeObject(xpath); + return supported; +} - xpath = pcmk__xpath_search(metadata->doc, "//" PCMK_XE_PARAMETER); - max = pcmk__xpath_num_results(xpath); +/*! + * \internal + * \brief Get the default host argument based on a device's agent metadata + * + * If an agent supports the "plug" parameter, default to that. Otherwise default + * to the "port" parameter if supported. Otherwise return \c NULL. + * + * \param[in] metadata Agent metadata + * + * \return Parameter name for default host argument + */ +const char * +stonith__default_host_arg(xmlNode *metadata) +{ + CRM_CHECK(metadata != NULL, return NULL); - if (max == 0) { - xmlXPathFreeObject(xpath); - return; + if (param_is_supported(metadata, "plug")) { + return "plug"; } - - for (lpc = 0; lpc < max; lpc++) { - const char *parameter = NULL; - xmlNode *match = pcmk__xpath_result(xpath, lpc); - - CRM_LOG_ASSERT(match != NULL); - if (match == NULL) { - continue; - } - - parameter = crm_element_value(match, PCMK_XA_NAME); - - if (pcmk__str_eq(parameter, "plug", pcmk__str_casei)) { - stonith__set_device_flags(*device_flags, device_name, - st_device_supports_parameter_plug); - - } else if (pcmk__str_eq(parameter, "port", pcmk__str_casei)) { - stonith__set_device_flags(*device_flags, device_name, - st_device_supports_parameter_port); - } + if (param_is_supported(metadata, "port")) { + return "port"; } - - xmlXPathFreeObject(xpath); + return NULL; } /*! @@ -2497,7 +2556,7 @@ stonith__metadata_async(const char *agent, int timeout_sec, void *user_data), void *user_data) { - switch (stonith_get_namespace(agent, NULL)) { + switch (get_namespace_from_agent(agent)) { case st_namespace_rhcs: { stonith_action_t *action = NULL; @@ -2731,3 +2790,153 @@ stonith__event_description(const stonith_event_t *event) ((reason == NULL)? "" : ")"), pcmk__s(event->id, "(none)")); } + +// Deprecated functions kept only for backward API compatibility +// LCOV_EXCL_START + +// See comments in stonith-ng.h for why we re-declare before defining + +stonith_t *stonith_api_new(void); + +stonith_t * +stonith_api_new(void) +{ + return stonith__api_new(); +} + +void stonith_api_delete(stonith_t *stonith); + +void +stonith_api_delete(stonith_t *stonith) +{ + stonith__api_free(stonith); +} + +static void +stonith_dump_pending_op(gpointer key, gpointer value, gpointer user_data) +{ + int call = GPOINTER_TO_INT(key); + stonith_callback_client_t *blob = value; + + crm_debug("Call %d (%s): pending", call, pcmk__s(blob->id, "no ID")); +} + +void stonith_dump_pending_callbacks(stonith_t *stonith); + +void +stonith_dump_pending_callbacks(stonith_t *stonith) +{ + stonith_private_t *private = stonith->st_private; + + if (private->stonith_op_callback_table == NULL) { + return; + } + return g_hash_table_foreach(private->stonith_op_callback_table, + stonith_dump_pending_op, NULL); +} + +bool stonith_dispatch(stonith_t *stonith_api); + +bool +stonith_dispatch(stonith_t *stonith_api) +{ + return (stonith__api_dispatch(stonith_api) == pcmk_rc_ok); +} + +stonith_key_value_t *stonith_key_value_add(stonith_key_value_t *head, + const char *key, const char *value); + +stonith_key_value_t * +stonith_key_value_add(stonith_key_value_t *head, const char *key, + const char *value) +{ + return stonith__key_value_add(head, key, value); +} + +void stonith_key_value_freeall(stonith_key_value_t *head, int keys, int values); + +void +stonith_key_value_freeall(stonith_key_value_t *head, int keys, int values) +{ + stonith__key_value_freeall(head, (keys != 0), (values != 0)); +} + +void stonith_history_free(stonith_history_t *head); + +void +stonith_history_free(stonith_history_t *head) +{ + stonith__history_free(head); +} + +int stonith_api_connect_retry(stonith_t *st, const char *name, + int max_attempts); + +int +stonith_api_connect_retry(stonith_t *st, const char *name, int max_attempts) +{ + return pcmk_rc2legacy(stonith__api_connect_retry(st, name, max_attempts)); +} + +const char *stonith_op_state_str(enum op_state state); + +const char * +stonith_op_state_str(enum op_state state) +{ + return stonith__op_state_text(state); +} + +bool stonith_agent_exists(const char *agent, int timeout); + +bool +stonith_agent_exists(const char *agent, int timeout) +{ + return stonith__agent_exists(agent); +} + +const char *stonith_action_str(const char *action); + +const char * +stonith_action_str(const char *action) +{ + if (action == NULL) { + return "fencing"; + } else if (strcmp(action, PCMK_ACTION_ON) == 0) { + return "unfencing"; + } else if (strcmp(action, PCMK_ACTION_OFF) == 0) { + return "turning off"; + } else { + return action; + } +} + +enum stonith_namespace stonith_text2namespace(const char *namespace_s); + +enum stonith_namespace +stonith_text2namespace(const char *namespace_s) +{ + return parse_namespace(namespace_s); +} + +const char *stonith_namespace2text(enum stonith_namespace st_namespace); + +const char * +stonith_namespace2text(enum stonith_namespace st_namespace) +{ + return namespace_text(st_namespace); +} + +enum stonith_namespace stonith_get_namespace(const char *agent, + const char *namespace_s); + +enum stonith_namespace +stonith_get_namespace(const char *agent, const char *namespace_s) +{ + if (pcmk__str_eq(namespace_s, "internal", pcmk__str_none)) { + return st_namespace_internal; + } + return get_namespace_from_agent(agent); +} + +// LCOV_EXCL_STOP +// End deprecated API diff --git a/lib/fencing/st_lha.c b/lib/fencing/st_lha.c index 7c42c69270a..90bc88015c0 100644 --- a/lib/fencing/st_lha.c +++ b/lib/fencing/st_lha.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2024 the Pacemaker project contributors + * Copyright 2004-2025 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -142,7 +142,7 @@ stonith__list_lha_agents(stonith_key_value_t **devices) for (entry = type_list; entry != NULL && *entry; ++entry) { crm_trace("Added: %s", *entry); - *devices = stonith_key_value_add(*devices, NULL, *entry); + *devices = stonith__key_value_add(*devices, NULL, *entry); count++; } if (type_list && type_free_fn) { diff --git a/lib/fencing/st_output.c b/lib/fencing/st_output.c index 786f9d5a2dd..3ce9d013146 100644 --- a/lib/fencing/st_output.c +++ b/lib/fencing/st_output.c @@ -48,6 +48,26 @@ timespec_string(time_t sec, long nsec, bool show_usec) { |(show_usec? crm_time_usecs : 0)); } +/*! + * \internal + * \brief Return a readable string equivalent of a fencing history item's action + * + * \param[in] history Fencing history entry + * + * \return Readable string equivalent of action belonging to \p history + */ +static const char * +history_action_text(const stonith_history_t *history) +{ + if (pcmk__str_eq(history->action, PCMK_ACTION_ON, pcmk__str_none)) { + return "unfencing"; + } + if (pcmk__str_eq(history->action, PCMK_ACTION_OFF, pcmk__str_none)) { + return "turning off"; + } + return pcmk__s(history->action, "fencing"); +} + /*! * \internal * \brief Return a status-friendly description of fence history entry state @@ -55,7 +75,7 @@ timespec_string(time_t sec, long nsec, bool show_usec) { * \param[in] history Fence history entry to describe * * \return One-word description of history entry state - * \note This is similar to stonith_op_state_str() except user-oriented (i.e. + * \note This is similar to stonith__op_state_text() except user-oriented (i.e., * for cluster status) instead of developer-oriented (for debug logs). */ static const char * @@ -98,8 +118,7 @@ stonith__history_description(const stonith_history_t *history, history->completed_nsec, true); } - pcmk__g_strcat(str, - stonith_action_str(history->action), " of ", history->target, + pcmk__g_strcat(str, history_action_text(history), " of ", history->target, NULL); if (!pcmk_is_set(show_opts, pcmk_show_failed_detail)) { diff --git a/lib/fencing/st_rhcs.c b/lib/fencing/st_rhcs.c index d091ea1153a..04b1c79ab15 100644 --- a/lib/fencing/st_rhcs.c +++ b/lib/fencing/st_rhcs.c @@ -81,7 +81,7 @@ stonith__list_rhcs_agents(stonith_key_value_t **devices) } for (int i = 0; i < file_num; i++) { - *devices = stonith_key_value_add(*devices, NULL, namelist[i]->d_name); + *devices = stonith__key_value_add(*devices, NULL, namelist[i]->d_name); free(namelist[i]); } free(namelist); @@ -282,16 +282,10 @@ stonith__rhcs_validate(stonith_t *st, int call_options, const char *target, rc = stonith__rhcs_get_metadata(agent, remaining_timeout, &metadata); if (rc == pcmk_ok) { - uint32_t device_flags = 0; - - stonith__device_parameter_flags(&device_flags, agent, metadata); - if (pcmk_is_set(device_flags, st_device_supports_parameter_port)) { - host_arg = "port"; - - } else if (pcmk_is_set(device_flags, - st_device_supports_parameter_plug)) { - host_arg = "plug"; - } + host_arg = stonith__default_host_arg(metadata); + crm_trace("Using '%s' as default " PCMK_STONITH_HOST_ARGUMENT + " for %s", + pcmk__s(host_arg, PCMK_VALUE_NONE), agent); } pcmk__xml_free(metadata); diff --git a/lib/lrmd/lrmd_client.c b/lib/lrmd/lrmd_client.c index 23879814f5c..6a37ab5bf41 100644 --- a/lib/lrmd/lrmd_client.c +++ b/lib/lrmd/lrmd_client.c @@ -2057,18 +2057,18 @@ lrmd_internal_proxy_send(lrmd_t * lrmd, xmlNode *msg) } static int -stonith_get_metadata(const char *provider, const char *type, char **output) +stonith_get_metadata(const char *type, char **output) { int rc = pcmk_ok; - stonith_t *stonith_api = stonith_api_new(); + stonith_t *stonith_api = stonith__api_new(); if (stonith_api == NULL) { crm_err("Could not get fence agent meta-data: API memory allocation failed"); return -ENOMEM; } - rc = stonith_api->cmds->metadata(stonith_api, st_opt_sync_call, type, - provider, output, 0); + rc = stonith_api->cmds->metadata(stonith_api, st_opt_sync_call, type, NULL, + output, 0); if ((rc == pcmk_ok) && (*output == NULL)) { rc = -EIO; } @@ -2101,7 +2101,9 @@ lrmd_api_get_metadata_params(lrmd_t *lrmd, const char *standard, if (pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) { lrmd_key_value_freeall(params); - return stonith_get_metadata(provider, type, output); + + // stonith-class resources don't support a provider + return stonith_get_metadata(type, output); } params_table = pcmk__strkey_table(free, free); @@ -2220,7 +2222,7 @@ static int list_stonith_agents(lrmd_list_t ** resources) { int rc = 0; - stonith_t *stonith_api = stonith_api_new(); + stonith_t *stonith_api = stonith__api_new(); stonith_key_value_t *stonith_resources = NULL; stonith_key_value_t *dIter = NULL; @@ -2239,7 +2241,7 @@ list_stonith_agents(lrmd_list_t ** resources) } } - stonith_key_value_freeall(stonith_resources, 1, 0); + stonith__key_value_freeall(stonith_resources, true, false); return rc; } diff --git a/lib/pacemaker/pcmk_fence.c b/lib/pacemaker/pcmk_fence.c index 04e9ee8ad2f..8febb374983 100644 --- a/lib/pacemaker/pcmk_fence.c +++ b/lib/pacemaker/pcmk_fence.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. * @@ -68,12 +68,12 @@ handle_level(stonith_t *st, const char *target, int fence_level, GList *devices, stonith_key_value_t *kvs = NULL; for (GList *iter = devices; iter != NULL; iter = iter->next) { - kvs = stonith_key_value_add(kvs, NULL, iter->data); + kvs = stonith__key_value_add(kvs, NULL, iter->data); } rc = st->cmds->register_level_full(st, st_opts, node, pattern, name, value, fence_level, kvs); - stonith_key_value_freeall(kvs, 0, 1); + stonith__key_value_freeall(kvs, false, true); } else { rc = st->cmds->remove_level_full(st, st_opts, node, pattern, name, value, fence_level); @@ -110,7 +110,7 @@ reduce_fence_history(stonith_history_t *history) || pcmk__str_eq(hp->delegate, np->delegate, pcmk__str_casei))) { /* purge older hp */ - stonith_history_free(hp); + stonith__history_free(hp); break; } } @@ -154,13 +154,13 @@ async_fence_helper(gpointer user_data) { stonith_t *st = async_fence_data.st; int call_id = 0; - int rc = stonith_api_connect_retry(st, async_fence_data.name, 10); + int rc = stonith__api_connect_retry(st, async_fence_data.name, 10); int timeout = 0; - if (rc != pcmk_ok) { + if (rc != pcmk_rc_ok) { g_main_loop_quit(mainloop); pcmk__set_result(&async_fence_data.result, CRM_EX_ERROR, - PCMK_EXEC_NOT_CONNECTED, pcmk_strerror(rc)); + PCMK_EXEC_NOT_CONNECTED, pcmk_rc_str(rc)); return TRUE; } @@ -246,7 +246,7 @@ pcmk_request_fencing(xmlNodePtr *xml, const char *target, const char *action, pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml); st->cmds->disconnect(st); - stonith_api_delete(st); + stonith__api_free(st); return rc; } @@ -287,7 +287,7 @@ pcmk__fence_history(pcmk__output_t *out, stonith_t *st, const char *target, if (cleanup) { // Cleanup doesn't return a history list - stonith_history_free(history); + stonith__history_free(history); return pcmk_legacy2rc(rc); } @@ -322,7 +322,7 @@ pcmk__fence_history(pcmk__output_t *out, stonith_t *st, const char *target, out->end_list(out); - stonith_history_free(history); + stonith__history_free(history); return pcmk_legacy2rc(rc); } @@ -346,18 +346,17 @@ pcmk_fence_history(xmlNodePtr *xml, const char *target, unsigned int timeout, pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml); st->cmds->disconnect(st); - stonith_api_delete(st); + stonith__api_free(st); return rc; } int -pcmk__fence_installed(pcmk__output_t *out, stonith_t *st, unsigned int timeout) +pcmk__fence_installed(pcmk__output_t *out, stonith_t *st) { stonith_key_value_t *devices = NULL; int rc = pcmk_rc_ok; - rc = st->cmds->list_agents(st, st_opt_sync_call, NULL, &devices, - pcmk__timeout_ms2s(timeout)); + rc = st->cmds->list_agents(st, st_opt_sync_call, NULL, &devices, 0); // rc is a negative error code or a positive number of agents if (rc < 0) { return pcmk_legacy2rc(rc); @@ -370,7 +369,7 @@ pcmk__fence_installed(pcmk__output_t *out, stonith_t *st, unsigned int timeout) } out->end_list(out); - stonith_key_value_freeall(devices, 1, 1); + stonith__key_value_freeall(devices, true, true); return pcmk_rc_ok; } @@ -386,11 +385,11 @@ pcmk_fence_installed(xmlNodePtr *xml, unsigned int timeout) return rc; } - rc = pcmk__fence_installed(out, st, timeout); + rc = pcmk__fence_installed(out, st); pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml); st->cmds->disconnect(st); - stonith_api_delete(st); + stonith__api_free(st); return rc; } @@ -472,7 +471,7 @@ pcmk_fence_list_targets(xmlNodePtr *xml, const char *device_id, unsigned int tim pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml); st->cmds->disconnect(st); - stonith_api_delete(st); + stonith__api_free(st); return rc; } @@ -509,7 +508,7 @@ pcmk_fence_metadata(xmlNodePtr *xml, const char *agent, unsigned int timeout) pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml); st->cmds->disconnect(st); - stonith_api_delete(st); + stonith__api_free(st); return rc; } @@ -533,7 +532,7 @@ pcmk__fence_registered(pcmk__output_t *out, stonith_t *st, const char *target, } out->end_list(out); - stonith_key_value_freeall(devices, 1, 1); + stonith__key_value_freeall(devices, true, true); /* Return pcmk_rc_ok here, not the number of results. Callers probably * don't care. @@ -557,7 +556,7 @@ pcmk_fence_registered(xmlNodePtr *xml, const char *target, unsigned int timeout) pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml); st->cmds->disconnect(st); - stonith_api_delete(st); + stonith__api_free(st); return rc; } @@ -585,7 +584,7 @@ pcmk_fence_register_level(xmlNodePtr *xml, const char *target, int fence_level, pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml); st->cmds->disconnect(st); - stonith_api_delete(st); + stonith__api_free(st); return rc; } @@ -611,7 +610,7 @@ pcmk_fence_unregister_level(xmlNodePtr *xml, const char *target, int fence_level pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml); st->cmds->disconnect(st); - stonith_api_delete(st); + stonith__api_free(st); return rc; } @@ -623,7 +622,7 @@ pcmk__fence_validate(pcmk__output_t *out, stonith_t *st, const char *agent, char *error_output = NULL; int rc; - rc = stonith__validate(st, st_opt_sync_call, id, NULL, agent, params, + rc = stonith__validate(st, st_opt_sync_call, id, agent, params, pcmk__timeout_ms2s(timeout), &output, &error_output); out->message(out, "validate", agent, id, output, error_output, rc); return pcmk_legacy2rc(rc); @@ -646,7 +645,7 @@ pcmk_fence_validate(xmlNodePtr *xml, const char *agent, const char *id, pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml); st->cmds->disconnect(st); - stonith_api_delete(st); + stonith__api_free(st); return rc; } diff --git a/lib/pacemaker/pcmk_setup.c b/lib/pacemaker/pcmk_setup.c index 42dd3f7b0ce..80a78c5fb66 100644 --- a/lib/pacemaker/pcmk_setup.c +++ b/lib/pacemaker/pcmk_setup.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 the Pacemaker project contributors + * Copyright 2024-2025 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -103,7 +103,7 @@ pcmk__setup_output_fencing(pcmk__output_t **out, stonith_t **st, xmlNode **xml) return rc; } - *st = stonith_api_new(); + *st = stonith__api_new(); if (*st == NULL) { return ENOMEM; } @@ -111,7 +111,7 @@ pcmk__setup_output_fencing(pcmk__output_t **out, stonith_t **st, xmlNode **xml) rc = (*st)->cmds->connect(*st, crm_system_name, NULL); if (rc < 0) { rc = pcmk_legacy2rc(rc); - stonith_api_delete(*st); + stonith__api_free(*st); return rc; } diff --git a/lib/pacemaker/pcmk_status.c b/lib/pacemaker/pcmk_status.c index 6fc1af7a112..c0052e558a4 100644 --- a/lib/pacemaker/pcmk_status.c +++ b/lib/pacemaker/pcmk_status.c @@ -24,7 +24,7 @@ static stonith_t * fencing_connect(void) { - stonith_t *st = stonith_api_new(); + stonith_t *st = stonith__api_new(); int rc = pcmk_rc_ok; if (st == NULL) { @@ -35,7 +35,7 @@ fencing_connect(void) if (rc == pcmk_rc_ok) { return st; } else { - stonith_api_delete(st); + stonith__api_free(st); return NULL; } } @@ -129,7 +129,7 @@ pcmk__output_cluster_status(pcmk_scheduler_t *scheduler, stonith_t *stonith, g_list_free_full(unames, free); g_list_free_full(resources, free); - stonith_history_free(stonith_history); + stonith__history_free(stonith_history); stonith_history = NULL; return rc; } @@ -276,7 +276,7 @@ pcmk__status(pcmk__output_t *out, cib_t *cib, done: pcmk_free_scheduler(scheduler); - stonith_api_delete(stonith); + stonith__api_free(stonith); pcmk__xml_free(current_cib); return pcmk_rc_ok; } diff --git a/tools/crm_mon.c b/tools/crm_mon.c index c0ad6c47b91..ba3cc415de7 100644 --- a/tools/crm_mon.c +++ b/tools/crm_mon.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2024 the Pacemaker project contributors + * Copyright 2004-2025 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -856,7 +856,7 @@ setup_fencer_connection(void) int rc = pcmk_ok; if (options.fence_connect && st == NULL) { - st = stonith_api_new(); + st = stonith__api_new(); } if (!options.fence_connect || st == NULL || st->state != stonith_disconnected) { @@ -880,7 +880,7 @@ setup_fencer_connection(void) mon_st_callback_display); } } else { - stonith_api_delete(st); + stonith__api_free(st); st = NULL; } @@ -931,7 +931,7 @@ setup_cib_connection(void) out->err(out, "Cannot monitor CIB changes; exiting"); cib__clean_up_connection(&cib); - stonith_api_delete(st); + stonith__api_free(st); st = NULL; } } @@ -2120,7 +2120,7 @@ clean_up(crm_exit_t exit_code) } cib__clean_up_connection(&cib); - stonith_api_delete(st); + stonith__api_free(st); free(options.neg_location_prefix); free(options.only_node); free(options.only_rsc); diff --git a/tools/crm_resource.c b/tools/crm_resource.c index e4ee98c3978..162ae406427 100644 --- a/tools/crm_resource.c +++ b/tools/crm_resource.c @@ -15,6 +15,7 @@ #include #include #include +#include // stonith__agent_exists() #include #include @@ -1161,7 +1162,7 @@ validate_cmdline_config(void) // Check whether agent exists if (pcmk__str_eq(options.class, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_none)) { - if (!stonith_agent_exists(options.agent, 0)) { + if (!stonith__agent_exists(options.agent)) { g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_USAGE, _("%s is not a known stonith agent"), options.agent); return; diff --git a/tools/stonith_admin.c b/tools/stonith_admin.c index b52e7deeb9e..b2b72cc9412 100644 --- a/tools/stonith_admin.c +++ b/tools/stonith_admin.c @@ -556,7 +556,7 @@ main(int argc, char **argv) out->quiet = args->quiet; - st = stonith_api_new(); + st = stonith__api_new(); if (st == NULL) { rc = -ENOMEM; } else if (!no_connect) { @@ -570,7 +570,7 @@ main(int argc, char **argv) switch (action) { case 'I': - rc = pcmk__fence_installed(out, st, options.timeout*1000); + rc = pcmk__fence_installed(out, st); if (rc != pcmk_rc_ok) { out->err(out, "Failed to list installed devices: %s", pcmk_rc_str(rc)); } @@ -610,12 +610,12 @@ main(int argc, char **argv) if (options.params != NULL) { g_hash_table_iter_init(&iter, options.params); while (g_hash_table_iter_next(&iter, &key, &val)) { - params = stonith_key_value_add(params, key, val); + params = stonith__key_value_add(params, key, val); } } rc = st->cmds->register_device(st, st_opts, device, NULL, options.agent, params); - stonith_key_value_freeall(params, 1, 1); + stonith__key_value_freeall(params, true, true); rc = pcmk_legacy2rc(rc); if (rc != pcmk_rc_ok) { @@ -719,7 +719,7 @@ main(int argc, char **argv) if (st != NULL) { st->cmds->disconnect(st); - stonith_api_delete(st); + stonith__api_free(st); } return exit_code;