diff --git a/include/pacemaker.h b/include/pacemaker.h index 45cee00654..73176412d5 100644 --- a/include/pacemaker.h +++ b/include/pacemaker.h @@ -1,525 +1,511 @@ /* * Copyright 2019-2023 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #ifndef PCMK__PACEMAKER__H # define PCMK__PACEMAKER__H # include # include # include # include # include #ifdef __cplusplus extern "C" { #endif /** * \file * \brief High Level API * \ingroup pacemaker */ /*! * \brief Modify operation of running a cluster simulation. */ enum pcmk_sim_flags { pcmk_sim_none = 0, pcmk_sim_all_actions = 1 << 0, pcmk_sim_show_pending = 1 << 1, pcmk_sim_process = 1 << 2, pcmk_sim_show_scores = 1 << 3, pcmk_sim_show_utilization = 1 << 4, pcmk_sim_simulate = 1 << 5, pcmk_sim_sanitized = 1 << 6, pcmk_sim_verbose = 1 << 7, }; /*! * \brief Synthetic cluster events that can be injected into the cluster * for running simulations. */ typedef struct { /*! A list of node names (gchar *) to simulate bringing online */ GList *node_up; /*! A list of node names (gchar *) to simulate bringing offline */ GList *node_down; /*! A list of node names (gchar *) to simulate failing */ GList *node_fail; /*! A list of operations (gchar *) to inject. The format of these strings * is described in the "Operation Specification" section of crm_simulate * help output. */ GList *op_inject; /*! A list of operations (gchar *) that should return a given error code * if they fail. The format of these strings is described in the * "Operation Specification" section of crm_simulate help output. */ GList *op_fail; /*! A list of tickets (gchar *) to simulate granting */ GList *ticket_grant; /*! A list of tickets (gchar *) to simulate revoking */ GList *ticket_revoke; /*! A list of tickets (gchar *) to simulate putting on standby */ GList *ticket_standby; /*! A list of tickets (gchar *) to simulate activating */ GList *ticket_activate; /*! Does the cluster have an active watchdog device? */ char *watchdog; /*! Does the cluster have quorum? */ char *quorum; } pcmk_injections_t; /*! * \brief Get and output controller status * * \param[in,out] xml Destination for the result, as an XML tree * \param[in] node_name Name of node whose status is desired * (\p NULL for DC) * \param[in] message_timeout_ms How long to wait for a reply from the * \p pacemaker-controld API. If 0, * \p pcmk_ipc_dispatch_sync will be used. * Otherwise, \p pcmk_ipc_dispatch_poll will * be used. * * \return Standard Pacemaker return code */ int pcmk_controller_status(xmlNodePtr *xml, const char *node_name, unsigned int message_timeout_ms); /*! * \brief Get and output designated controller node name * * \param[in,out] xml Destination for the result, as an XML tree * \param[in] message_timeout_ms How long to wait for a reply from the * \p pacemaker-controld API. If 0, * \p pcmk_ipc_dispatch_sync will be used. * Otherwise, \p pcmk_ipc_dispatch_poll will * be used. * * \return Standard Pacemaker return code */ int pcmk_designated_controller(xmlNodePtr *xml, unsigned int message_timeout_ms); /*! * \brief Free a :pcmk_injections_t structure * * \param[in,out] injections The structure to be freed */ void pcmk_free_injections(pcmk_injections_t *injections); /*! * \brief Get and optionally output node info corresponding to a node ID from * the controller * * \param[in,out] xml Destination for the result, as an XML tree * \param[in,out] node_id ID of node whose name to get. If \p NULL * or 0, get the local node name. If not * \p NULL, store the true node ID here on * success. * \param[out] node_name If not \p NULL, where to store the node * name * \param[out] uuid If not \p NULL, where to store the node * UUID * \param[out] state If not \p NULL, where to store the * membership state * \param[out] is_remote If not \p NULL, where to store whether the * node is a Pacemaker Remote node * \param[out] have_quorum If not \p NULL, where to store whether the * node has quorum * \param[in] show_output Whether to output the node info * \param[in] message_timeout_ms How long to wait for a reply from the * \p pacemaker-controld API. If 0, * \p pcmk_ipc_dispatch_sync will be used. * Otherwise, \p pcmk_ipc_dispatch_poll will * be used. * * \return Standard Pacemaker return code * * \note The caller is responsible for freeing \p *node_name, \p *uuid, and * \p *state using \p free(). */ int pcmk_query_node_info(xmlNodePtr *xml, uint32_t *node_id, char **node_name, char **uuid, char **state, bool *have_quorum, bool *is_remote, bool show_output, unsigned int message_timeout_ms); /*! * \brief Get the node name corresponding to a node ID from the controller * * \param[in,out] xml Destination for the result, as an XML tree * \param[in,out] node_id ID of node whose name to get (or 0 for the * local node) * \param[out] node_name If not \p NULL, where to store the node * name * \param[in] message_timeout_ms How long to wait for a reply from the * \p pacemaker-controld API. If 0, * \p pcmk_ipc_dispatch_sync will be used. * Otherwise, \p pcmk_ipc_dispatch_poll will * be used. * * \return Standard Pacemaker return code * * \note The caller is responsible for freeing \p *node_name using \p free(). */ static inline int pcmk_query_node_name(xmlNodePtr *xml, uint32_t node_id, char **node_name, unsigned int message_timeout_ms) { return pcmk_query_node_info(xml, &node_id, node_name, NULL, NULL, NULL, NULL, false, message_timeout_ms); } /*! * \brief Get and output \p pacemakerd status * * \param[in,out] xml Destination for the result, as an XML tree * \param[in] ipc_name IPC name for request * \param[in] message_timeout_ms How long to wait for a reply from the * \p pacemakerd API. If 0, * \p pcmk_ipc_dispatch_sync will be used. * Otherwise, \p pcmk_ipc_dispatch_poll will * be used. * * \return Standard Pacemaker return code */ int pcmk_pacemakerd_status(xmlNodePtr *xml, const char *ipc_name, unsigned int message_timeout_ms); /*! * \brief Calculate and output resource operation digests * * \param[out] xml Where to store XML with result * \param[in,out] rsc Resource to calculate digests for * \param[in] node Node whose operation history should be used * \param[in] overrides Hash table of configuration parameters to override * \param[in] data_set Cluster working set (with status) * * \return Standard Pacemaker return code */ int pcmk_resource_digests(xmlNodePtr *xml, pe_resource_t *rsc, const pe_node_t *node, GHashTable *overrides, pe_working_set_t *data_set); /*! * \brief Simulate a cluster's response to events * * This high-level function essentially implements crm_simulate(8). It operates * on an input CIB file and various lists of events that can be simulated. It * optionally writes out a variety of artifacts to show the results of the * simulation. Output can be modified with various flags. * * \param[in,out] xml The destination for the result, as an XML tree * \param[in,out] data_set Working set for the cluster * \param[in] injections A structure containing cluster events * (node up/down, tickets, injected operations) * \param[in] flags A bitfield of :pcmk_sim_flags to modify * operation of the simulation * \param[in] section_opts Which portions of the cluster status output * should be displayed? * \param[in] use_date Date to set the cluster's time to (may be NULL) * \param[in] input_file The source CIB file, which may be overwritten by * this function (may be NULL) * \param[in] graph_file Where to write the XML-formatted transition graph * (may be NULL, in which case no file will be * written) * \param[in] dot_file Where to write the dot(1) formatted transition * graph (may be NULL, in which case no file will * be written) * * \return Standard Pacemaker return code */ int pcmk_simulate(xmlNodePtr *xml, pe_working_set_t *data_set, const pcmk_injections_t *injections, unsigned int flags, unsigned int section_opts, const char *use_date, const char *input_file, const char *graph_file, const char *dot_file); /*! * \brief Get nodes list * * \param[in,out] xml The destination for the result, as an XML tree. * \param[in] node_types Node type(s) to return (default: all) * * \return Standard Pacemaker return code */ int pcmk_list_nodes(xmlNodePtr *xml, const char *node_types); /*! * \brief Output the current status of the cluster, formatted in the same way * that `crm_mon --output-as=xml` would. * * \param[in,out] xml The destination for the result, as an XML tree. * * \return Standard Pacemaker return code */ int pcmk_status(xmlNodePtr *xml); /*! * \brief Check whether each rule in a list is in effect * * \param[in,out] xml The destination for the result, as an XML tree * \param[in] input The CIB XML to check (if \c NULL, use current CIB) * \param[in] date Check whether the rule is in effect at this date and * time (if \c NULL, use current date and time) * \param[in] rule_ids The IDs of the rules to check, as a NULL- * terminated list. * * \return Standard Pacemaker return code */ int pcmk_check_rules(xmlNodePtr *xml, xmlNodePtr input, const crm_time_t *date, const char **rule_ids); /*! * \brief Check whether a given rule is in effect * * \param[in,out] xml The destination for the result, as an XML tree * \param[in] input The CIB XML to check (if \c NULL, use current CIB) * \param[in] date Check whether the rule is in effect at this date and * time (if \c NULL, use current date and time) * \param[in] rule_ids The ID of the rule to check * * \return Standard Pacemaker return code */ static inline int pcmk_check_rule(xmlNodePtr *xml, xmlNodePtr input, const crm_time_t *date, const char *rule_id) { const char *rule_ids[] = {rule_id, NULL}; return pcmk_check_rules(xml, input, date, rule_ids); } /* * \enum pcmk_rc_disp_flags * \brief Bit flags to control which fields of result code info are displayed */ enum pcmk_rc_disp_flags { pcmk_rc_disp_none = 0, //!< (Does nothing) pcmk_rc_disp_code = (1 << 0), //!< Display result code number pcmk_rc_disp_name = (1 << 1), //!< Display result code name pcmk_rc_disp_desc = (1 << 2), //!< Display result code description }; /* * \brief Display the name and/or description of a result code * * \param[in,out] xml The destination for the result, as an XML tree * \param[in] code The result code * \param[in] type Interpret \c code as this type of result code. * Supported values: \c pcmk_result_legacy, * \c pcmk_result_rc, \c pcmk_result_exitcode. * \param[in] flags Group of \c pcmk_rc_disp_flags * * \return Standard Pacemaker return code */ int pcmk_show_result_code(xmlNodePtr *xml, int code, enum pcmk_result_type type, uint32_t flags); /*! * \brief List all valid result codes in a particular family * * \param[in,out] xml The destination for the result, as an XML tree * \param[in] type The family of result codes to list. Supported * values: \c pcmk_result_legacy, \c pcmk_result_rc, * \c pcmk_result_exitcode. * \param[in] flags Group of \c pcmk_rc_disp_flags * * \return Standard Pacemaker return code */ int pcmk_list_result_codes(xmlNodePtr *xml, enum pcmk_result_type type, uint32_t flags); #ifdef BUILD_PUBLIC_LIBPACEMAKER /*! * \brief Ask the cluster to perform fencing * - * \param[in] st A connection to the fencer API - * \param[in] target The node that should be fenced - * \param[in] action The fencing action (on, off, reboot) to perform - * \param[in] name Who requested the fence action? - * \param[in] timeout How long to wait for the operation to complete (in ms) - * \param[in] tolerance If a successful action for \p target happened within - * this many ms, return 0 without performing the action - * again - * \param[in] delay Apply this delay (in milliseconds) before initiating the - * fencing action (a value of -1 applies no delay and also - * disables any fencing delay from pcmk_delay_base and - * pcmk_delay_max) - * \param[out] reason If not NULL, where to put descriptive failure reason + * \param[in,out] st A connection to the fencer API + * \param[in] target The node that should be fenced + * \param[in] action The fencing action (on, off, reboot) to perform + * \param[in] name Who requested the fence action? + * \param[in] timeout How long to wait for operation to complete (in ms) + * \param[in] tolerance If a successful action for \p target happened within + * this many ms, return 0 without performing the action + * again + * \param[in] delay Apply this delay (in milliseconds) before initiating + * fencing action (-1 applies no delay and also + * disables any fencing delay from pcmk_delay_base and + * pcmk_delay_max) + * \param[out] reason If not NULL, where to put descriptive failure reason * * \return Standard Pacemaker return code * \note If \p reason is not NULL, the caller is responsible for freeing its * returned value. */ int pcmk_request_fencing(stonith_t *st, const char *target, const char *action, const char *name, unsigned int timeout, unsigned int tolerance, int delay, char **reason); /*! - * \brief List the fencing operations that have occurred for a specific node. + * \brief List the fencing operations that have occurred for a specific node * * \note If \p xml is not NULL, it will be freed first and the previous * contents lost. * - * \param[in,out] xml The destination for the result, as an XML tree. - * \param[in] st A connection to the STONITH API. - * \param[in] target The node to get history for. - * \param[in] timeout How long to wait for the operation to complete (in ms). - * \param[in] quiet Suppress most output. - * \param[in] verbose Include additional output. - * \param[in] broadcast Gather fencing history from all nodes. - * \param[in] cleanup Clean up fencing history after listing. + * \param[in,out] xml The destination for the result, as an XML tree + * \param[in,out] st A connection to the fencer API + * \param[in] target The node to get history for + * \param[in] timeout How long to wait for operation to complete (in ms) + * \param[in] quiet Suppress most output + * \param[in] verbose Include additional output + * \param[in] broadcast Gather fencing history from all nodes + * \param[in] cleanup Clean up fencing history after listing * * \return Standard Pacemaker return code */ -int pcmk_fence_history(xmlNodePtr *xml, stonith_t *st, char *target, +int pcmk_fence_history(xmlNodePtr *xml, stonith_t *st, const char *target, unsigned int timeout, bool quiet, int verbose, bool broadcast, bool cleanup); /*! - * \brief List all installed STONITH agents. + * \brief List all installed fence agents * - * \note If \p xml is not NULL, it will be freed first and the previous - * contents lost. - * - * \param[in,out] xml The destination for the result, as an XML tree. - * \param[in] st A connection to the STONITH API. - * \param[in] timeout How long to wait for the operation to complete (in ms). + * \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,out] st A connection to the fencer API + * \param[in] timeout How long to wait for operation to complete (in ms) * * \return Standard Pacemaker return code */ int pcmk_fence_installed(xmlNodePtr *xml, stonith_t *st, unsigned int timeout); /*! * \brief When was a device last fenced? * - * \note If \p xml is not NULL, it will be freed first and the previous - * contents lost. - * - * \param[in,out] xml The destination for the result, as an XML tree. - * \param[in] target The node that was fenced. - * \param[in] as_nodeid + * \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] target The node that was fenced + * \param[in] as_nodeid If true, \p target has node ID rather than name * * \return Standard Pacemaker return code */ int pcmk_fence_last(xmlNodePtr *xml, const char *target, bool as_nodeid); /*! - * \brief List nodes that can be fenced. - * - * \note If \p xml is not NULL, it will be freed first and the previous - * contents lost. + * \brief List nodes that can be fenced * - * \param[in,out] xml The destination for the result, as an XML tree - * \param[in] st A connection to the STONITH API + * \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,out] st A connection to the fencer API * \param[in] device_id Resource ID of fence device to check - * \param[in] timeout How long to wait for the operation to complete (in ms) + * \param[in] timeout How long to wait for operation to complete (in ms) * * \return Standard Pacemaker return code */ int pcmk_fence_list_targets(xmlNodePtr *xml, stonith_t *st, const char *device_id, unsigned int timeout); /*! - * \brief Get metadata for a resource. + * \brief Get metadata for a fence agent * * \note If \p xml is not NULL, it will be freed first and the previous * contents lost. * - * \param[in,out] xml The destination for the result, as an XML tree. - * \param[in] st A connection to the STONITH API. - * \param[in] agent The fence agent to get metadata for. - * \param[in] timeout How long to wait for the operation to complete (in ms). + * \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,out] st A connection to the fencer API + * \param[in] agent The fence agent to get metadata for + * \param[in] timeout How long to wait for operation to complete (in ms) * * \return Standard Pacemaker return code */ -int pcmk_fence_metadata(xmlNodePtr *xml, stonith_t *st, char *agent, +int pcmk_fence_metadata(xmlNodePtr *xml, stonith_t *st, const char *agent, unsigned int timeout); /*! - * \brief List registered fence devices. + * \brief List registered fence devices * - * \note If \p xml is not NULL, it will be freed first and the previous - * contents lost. - * - * \param[in,out] xml The destination for the result, as an XML tree. - * \param[in] st A connection to the STONITH API. - * \param[in] target If not NULL, only return devices that can fence - * this node. - * \param[in] timeout How long to wait for the operation to complete (in ms). + * \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,out] st A connection to the fencer API + * \param[in] target If not NULL, return only devices that can fence this + * \param[in] timeout How long to wait for operation to complete (in ms) * * \return Standard Pacemaker return code */ -int pcmk_fence_registered(xmlNodePtr *xml, stonith_t *st, char *target, +int pcmk_fence_registered(xmlNodePtr *xml, stonith_t *st, const char *target, unsigned int timeout); /*! - * \brief Register a fencing level for a specific node, node regex, or attribute. - * - * \p target can take three different forms: - * - name=value, in which case \p target is an attribute. - * - @pattern, in which case \p target is a node regex. - * - Otherwise, \p target is a node name. + * \brief Register a fencing topology level * - * \param[in] st A connection to the STONITH API. - * \param[in] target The object to register a fencing level for. - * \param[in] fence_level Index number of level to add. - * \param[in] devices Devices to use in level. + * \param[in,out] st A connection to the fencer API + * \param[in] target What fencing level targets (as "name=value" to + * target by given node attribute, or "@pattern" to + * target by node name pattern, or a node name) + * \param[in] fence_level Index number of level to add + * \param[in] devices Devices to use in level * * \return Standard Pacemaker return code */ -int pcmk_fence_register_level(stonith_t *st, char *target, int fence_level, - stonith_key_value_t *devices); +int pcmk_fence_register_level(stonith_t *st, const char *target, + int fence_level, + const stonith_key_value_t *devices); /*! - * \brief Unregister a fencing level for a specific node, node regex, or attribute. + * \brief Unregister a fencing topology level * - * \p target can take three different forms: - * - name=value, in which case \p target is an attribute. - * - @pattern, in which case \p target is a node regex. - * - Otherwise, \p target is a node name. - * - * \param[in] st A connection to the STONITH API. - * \param[in] target The object to unregister a fencing level for. - * \param[in] fence_level Index number of level to remove. + * \param[in,out] st A connection to the fencer API + * \param[in] target What fencing level targets (as "name=value" to + * target by given node attribute, or "@pattern" to + * target by node name pattern, or a node name) + * \param[in] fence_level Index number of level to remove * * \return Standard Pacemaker return code */ -int pcmk_fence_unregister_level(stonith_t *st, char *target, int fence_level); +int pcmk_fence_unregister_level(stonith_t *st, const char *target, + int fence_level); /*! - * \brief Validate a STONITH device configuration. - * - * \note If \p xml is not NULL, it will be freed first and the previous - * contents lost. + * \brief Validate a fence device configuration * - * \param[in,out] xml The destination for the result, as an XML tree. - * \param[in] st A connection to the STONITH API. - * \param[in] agent The agent to validate (for example, "fence_xvm"). - * \param[in] id STONITH device ID (may be NULL). - * \param[in] params STONITH device configuration parameters. - * \param[in] timeout How long to wait for the operation to complete (in ms). + * \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,out] st A connection to the fencer API + * \param[in] agent The agent to validate (for example, "fence_xvm") + * \param[in] id Fence device ID (may be NULL) + * \param[in] params Fence device configuration parameters + * \param[in] timeout How long to wait for operation to complete (in ms) * * \return Standard Pacemaker return code */ int pcmk_fence_validate(xmlNodePtr *xml, stonith_t *st, const char *agent, - const char *id, stonith_key_value_t *params, + const char *id, const stonith_key_value_t *params, unsigned int timeout); #endif #ifdef __cplusplus } #endif #endif diff --git a/include/pcmki/pcmki_fence.h b/include/pcmki/pcmki_fence.h index 2c7cf96393..e96edf4960 100644 --- a/include/pcmki/pcmki_fence.h +++ b/include/pcmki/pcmki_fence.h @@ -1,249 +1,250 @@ /* * Copyright 2019-2022 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #ifndef PCMK__PCMKI_PCMKI_FENCE__H # define PCMK__PCMKI_PCMKI_FENCE__H # include # include /*! * \brief Control how much of the fencing history is output. */ enum pcmk__fence_history { pcmk__fence_history_none, pcmk__fence_history_reduced, pcmk__fence_history_full }; /*! * \brief Ask the cluster to perform fencing * * \note This is the internal version of pcmk_request_fencing(). External users * of the pacemaker API should use that function instead. * - * \param[in] st A connection to the fencer API - * \param[in] target The node that should be fenced - * \param[in] action The fencing action (on, off, reboot) to perform - * \param[in] name Who requested the fence action? - * \param[in] timeout How long to wait for the operation to complete (in ms) - * \param[in] tolerance If a successful action for \p target happened within - * this many milliseconds, return success without - * performing the action again - * \param[in] delay Apply this delay (in milliseconds) before initiating the - * fencing action (a value of -1 applies no delay and also - * disables any fencing delay from pcmk_delay_base and - * pcmk_delay_max) - * \param[out] reason If not NULL, where to put descriptive failure reason + * \param[in,out] st A connection to the fencer API + * \param[in] target The node that should be fenced + * \param[in] action The fencing action (on, off, reboot) to perform + * \param[in] name Who requested the fence action? + * \param[in] timeout How long to wait for operation to complete (in ms) + * \param[in] tolerance If a successful action for \p target happened within + * this many milliseconds, return success without + * performing the action again + * \param[in] delay Apply this delay (in milliseconds) before initiating + * fencing action (a value of -1 applies no delay and + * disables any fencing delay from pcmk_delay_base and + * pcmk_delay_max) + * \param[out] reason If not NULL, where to put descriptive failure reason * * \return Standard Pacemaker return code * \note If \p reason is not NULL, the caller is responsible for freeing its * returned value. * \todo delay is eventually used with g_timeout_add() and should be guint */ int pcmk__request_fencing(stonith_t *st, const char *target, const char *action, const char *name, unsigned int timeout, unsigned int tolerance, int delay, char **reason); /*! - * \brief List the fencing operations that have occurred for a specific node. + * \brief List the fencing operations that have occurred for a specific node * * \note This is the internal version of pcmk_fence_history(). External users * of the pacemaker API should use that function instead. * * \note \p out should be initialized with pcmk__output_new() before calling this * function and destroyed with out->finish and pcmk__output_free() before * reusing it with any other functions in this library. * - * \param[in,out] out The output functions structure. - * \param[in] st A connection to the STONITH API. - * \param[in] target The node to get history for. - * \param[in] timeout How long to wait for the operation to complete (in ms). - * \param[in] verbose Include additional output. - * \param[in] broadcast Gather fencing history from all nodes. - * \param[in] cleanup Clean up fencing history after listing. + * \param[in,out] out The output functions structure + * \param[in,out] st A connection to the fencer API + * \param[in] target The node to get history for + * \param[in] timeout How long to wait for operation to complete (in ms) + * \param[in] verbose Include additional output + * \param[in] broadcast Gather fencing history from all nodes + * \param[in] cleanup Clean up fencing history after listing * * \return Standard Pacemaker return code */ -int pcmk__fence_history(pcmk__output_t *out, stonith_t *st, char *target, +int pcmk__fence_history(pcmk__output_t *out, stonith_t *st, const char *target, unsigned int timeout, int verbose, bool broadcast, bool cleanup); -/** - * \brief List all installed STONITH agents. +/*! + * \brief List all installed fence agents * * \note This is the internal version of pcmk_fence_installed(). External users * of the pacemaker API should use that function instead. * * \note \p out should be initialized with pcmk__output_new() before calling this * function and destroyed with out->finish and pcmk__output_free() before * reusing it with any other functions in this library. * - * \param[in,out] out The output functions structure. - * \param[in] st A connection to the STONITH API. - * \param[in] timeout How long to wait for the operation to complete (in ms). + * \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); /*! * \brief When was a device last fenced? * * \note This is the internal version of pcmk_fence_last(). External users * of the pacemaker API should use that function instead. * * \note \p out should be initialized with pcmk__output_new() before calling this * function and destroyed with out->finish and pcmk__output_free() before * reusing it with any other functions in this library. * * \param[in,out] out The output functions structure. * \param[in] target The node that was fenced. * \param[in] as_nodeid * * \return Standard Pacemaker return code */ int pcmk__fence_last(pcmk__output_t *out, const char *target, bool as_nodeid); /*! - * \brief List nodes that can be fenced. + * \brief List nodes that can be fenced * * \note This is the internal version of pcmk_fence_list_targets(). External users * of the pacemaker API should use that function instead. * * \note \p out should be initialized with pcmk__output_new() before calling this * function and destroyed with out->finish and pcmk__output_free() before * reusing it with any other functions in this library. * * \param[in,out] out The output functions structure - * \param[in] st A connection to the STONITH API + * \param[in,out] st A connection to the fencer API * \param[in] device_id Resource ID of fence device to check - * \param[in] timeout How long to wait for the operation to complete (in ms) + * \param[in] timeout How long to wait for operation to complete (in ms) * * \return Standard Pacemaker return code */ int pcmk__fence_list_targets(pcmk__output_t *out, stonith_t *st, const char *device_id, unsigned int timeout); /*! - * \brief Get metadata for a resource. + * \brief Get metadata for a fence agent * * \note This is the internal version of pcmk_fence_metadata(). External users * of the pacemaker API should use that function instead. * * \note \p out should be initialized with pcmk__output_new() before calling this * function and destroyed with out->finish and pcmk__output_free() before * reusing it with any other functions in this library. * - * \param[in,out] out The output functions structure. - * \param[in] st A connection to the STONITH API. - * \param[in] agent The fence agent to get metadata for. - * \param[in] timeout How long to wait for the operation to complete (in ms). + * \param[in,out] out The output functions structure + * \param[in,out] st A connection to the fencer API + * \param[in] agent The fence agent to get metadata for + * \param[in] timeout How long to wait for the operation to complete (in ms) * * \return Standard Pacemaker return code */ -int pcmk__fence_metadata(pcmk__output_t *out, stonith_t *st, char *agent, +int pcmk__fence_metadata(pcmk__output_t *out, stonith_t *st, const char *agent, unsigned int timeout); /*! - * \brief List registered fence devices. + * \brief List registered fence devices * * \note This is the internal version of pcmk_fence_metadata(). External users * of the pacemaker API should use that function instead. * * \note \p out should be initialized with pcmk__output_new() before calling this * function and destroyed with out->finish and pcmk__output_free() before * reusing it with any other functions in this library. * - * \param[in,out] out The output functions structure. - * \param[in] st A connection to the STONITH API. - * \param[in] target If not NULL, only return devices that can fence - * this node. - * \param[in] timeout How long to wait for the operation to complete (in ms). + * \param[in,out] out The output functions structure + * \param[in,out] st A connection to the fencer API + * \param[in] target If not NULL, return only devices that can fence this + * \param[in] timeout How long to wait for the operation to complete (in ms) * * \return Standard Pacemaker return code */ -int pcmk__fence_registered(pcmk__output_t *out, stonith_t *st, char *target, - unsigned int timeout); +int pcmk__fence_registered(pcmk__output_t *out, stonith_t *st, + const char *target, unsigned int timeout); /*! - * \brief Register a fencing level for a specific node, node regex, or attribute. + * \brief Register a fencing level for a specific node, node regex, or attribute * * \note This is the internal version of pcmk_fence_register_level(). External users * of the pacemaker API should use that function instead. * * \p target can take three different forms: * - name=value, in which case \p target is an attribute. * - @pattern, in which case \p target is a node regex. * - Otherwise, \p target is a node name. * - * \param[in] st A connection to the STONITH API. - * \param[in] target The object to register a fencing level for. - * \param[in] fence_level Index number of level to add. - * \param[in] devices Devices to use in level. + * \param[in,out] st A connection to the fencer API + * \param[in] target The object to register a fencing level for + * \param[in] fence_level Index number of level to add + * \param[in] devices Devices to use in level * * \return Standard Pacemaker return code */ -int pcmk__fence_register_level(stonith_t *st, char *target, int fence_level, - stonith_key_value_t *devices); +int pcmk__fence_register_level(stonith_t *st, const char *target, + int fence_level, + const stonith_key_value_t *devices); /*! - * \brief Unregister a fencing level for a specific node, node regex, or attribute. + * \brief Unregister a fencing level for specific node, node regex, or attribute * * \note This is the internal version of pcmk_fence_unregister_level(). External users * of the pacemaker API should use that function instead. * * \p target can take three different forms: * - name=value, in which case \p target is an attribute. * - @pattern, in which case \p target is a node regex. * - Otherwise, \p target is a node name. * - * \param[in] st A connection to the STONITH API. - * \param[in] target The object to unregister a fencing level for. - * \param[in] fence_level Index number of level to remove. + * \param[in,out] st A connection to the fencer API + * \param[in] target The object to unregister a fencing level for + * \param[in] fence_level Index number of level to remove * * \return Standard Pacemaker return code */ -int pcmk__fence_unregister_level(stonith_t *st, char *target, int fence_level); +int pcmk__fence_unregister_level(stonith_t *st, const char *target, + int fence_level); -/** - * \brief Validate a STONITH device configuration. +/*! + * \brief Validate a fence device configuration * * \note This is the internal version of pcmk_stonith_validate(). External users * of the pacemaker API should use that function instead. * * \note \p out should be initialized with pcmk__output_new() before calling this * function and destroyed with out->finish and pcmk__output_free() before * reusing it with any other functions in this library. * - * \param[in,out] out The output functions structure. - * \param[in] st A connection to the STONITH API. - * \param[in] agent The agent to validate (for example, "fence_xvm"). - * \param[in] id STONITH device ID (may be NULL). - * \param[in] params STONITH device configuration parameters. - * \param[in] timeout How long to wait for the operation to complete (in ms). + * \param[in,out] out The output functions structure + * \param[in,out] st A connection to the fencer API + * \param[in] agent The agent to validate (for example, "fence_xvm") + * \param[in] id Fence device ID (may be NULL) + * \param[in] params Fence device configuration parameters + * \param[in] timeout How long to wait for the operation to complete (in ms) * * \return Standard Pacemaker return code */ int pcmk__fence_validate(pcmk__output_t *out, stonith_t *st, const char *agent, - const char *id, stonith_key_value_t *params, + const char *id, const stonith_key_value_t *params, unsigned int timeout); -/** - * \brief Fetch STONITH history, optionally reducing it. +/*! + * \brief Fetch fencing history, optionally reducing it * - * \param[in] st The STONITH API object - * \param[out] stonith_history Destination for storing the history - * \param[in] fence_history How much of the fencing history to display? + * \param[in,out] st A connection to the fencer API + * \param[out] stonith_history Destination for storing the history + * \param[in] fence_history How much of the fencing history to display * * \return Standard Pacemaker return code */ int pcmk__get_fencing_history(stonith_t *st, stonith_history_t **stonith_history, enum pcmk__fence_history fence_history); #endif diff --git a/lib/pacemaker/pcmk_fence.c b/lib/pacemaker/pcmk_fence.c index 0db7ce105f..bb531c3eca 100644 --- a/lib/pacemaker/pcmk_fence.c +++ b/lib/pacemaker/pcmk_fence.c @@ -1,605 +1,625 @@ /* - * Copyright 2009-2022 the Pacemaker project contributors + * Copyright 2009-2023 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. */ #include #include #include #include #include #include #include #include #include #include #include static const int st_opts = st_opt_sync_call | st_opt_allow_suicide; static GMainLoop *mainloop = NULL; static struct { stonith_t *st; const char *target; const char *action; char *name; unsigned int timeout; unsigned int tolerance; int delay; pcmk__action_result_t result; } async_fence_data = { NULL, }; static int -handle_level(stonith_t *st, char *target, int fence_level, - stonith_key_value_t *devices, bool added) { - char *node = NULL; - char *pattern = NULL; - char *name = NULL; +handle_level(stonith_t *st, const char *target, int fence_level, + const stonith_key_value_t *devices, bool added) +{ + const char *node = NULL; + const char *pattern = NULL; + const char *name = NULL; char *value = NULL; int rc = pcmk_rc_ok; if (target == NULL) { // Not really possible, but makes static analysis happy return EINVAL; } /* Determine if targeting by attribute, node name pattern or node name */ value = strchr(target, '='); if (value != NULL) { name = target; *value++ = '\0'; } else if (*target == '@') { pattern = target + 1; } else { node = target; } /* Register or unregister level as appropriate */ if (added) { rc = st->cmds->register_level_full(st, st_opts, node, pattern, name, value, fence_level, devices); } else { rc = st->cmds->remove_level_full(st, st_opts, node, pattern, name, value, fence_level); } return pcmk_legacy2rc(rc); } static stonith_history_t * reduce_fence_history(stonith_history_t *history) { stonith_history_t *new, *hp, *np; if (!history) { return history; } new = history; hp = new->next; new->next = NULL; while (hp) { stonith_history_t *hp_next = hp->next; hp->next = NULL; for (np = new; ; np = np->next) { if ((hp->state == st_done) || (hp->state == st_failed)) { /* action not in progress */ if (pcmk__str_eq(hp->target, np->target, pcmk__str_casei) && pcmk__str_eq(hp->action, np->action, pcmk__str_none) && (hp->state == np->state) && ((hp->state == st_done) || pcmk__str_eq(hp->delegate, np->delegate, pcmk__str_casei))) { /* purge older hp */ stonith_history_free(hp); break; } } if (!np->next) { np->next = hp; break; } } hp = hp_next; } return new; } static void notify_callback(stonith_t * st, stonith_event_t * e) { if (pcmk__str_eq(async_fence_data.target, e->target, pcmk__str_casei) && pcmk__str_eq(async_fence_data.action, e->action, pcmk__str_none)) { pcmk__set_result(&async_fence_data.result, stonith__event_exit_status(e), stonith__event_execution_status(e), stonith__event_exit_reason(e)); g_main_loop_quit(mainloop); } } static void fence_callback(stonith_t * stonith, stonith_callback_data_t * data) { pcmk__set_result(&async_fence_data.result, stonith__exit_status(data), stonith__execution_status(data), stonith__exit_reason(data)); g_main_loop_quit(mainloop); } static gboolean 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); if (rc != pcmk_ok) { g_main_loop_quit(mainloop); pcmk__set_result(&async_fence_data.result, CRM_EX_ERROR, PCMK_EXEC_NOT_CONNECTED, pcmk_strerror(rc)); return TRUE; } st->cmds->register_notification(st, T_STONITH_NOTIFY_FENCE, notify_callback); call_id = st->cmds->fence_with_delay(st, st_opt_allow_suicide, async_fence_data.target, async_fence_data.action, async_fence_data.timeout/1000, async_fence_data.tolerance/1000, async_fence_data.delay); if (call_id < 0) { g_main_loop_quit(mainloop); pcmk__set_result(&async_fence_data.result, CRM_EX_ERROR, PCMK_EXEC_ERROR, pcmk_strerror(call_id)); return TRUE; } st->cmds->register_callback(st, call_id, async_fence_data.timeout/1000, st_opt_timeout_updates, NULL, "callback", fence_callback); return TRUE; } int pcmk__request_fencing(stonith_t *st, const char *target, const char *action, const char *name, unsigned int timeout, unsigned int tolerance, int delay, char **reason) { crm_trigger_t *trig; int rc = pcmk_rc_ok; async_fence_data.st = st; async_fence_data.name = strdup(name); async_fence_data.target = target; async_fence_data.action = action; async_fence_data.timeout = timeout; async_fence_data.tolerance = tolerance; async_fence_data.delay = delay; pcmk__set_result(&async_fence_data.result, CRM_EX_ERROR, PCMK_EXEC_UNKNOWN, NULL); trig = mainloop_add_trigger(G_PRIORITY_HIGH, async_fence_helper, NULL); mainloop_set_trigger(trig); mainloop = g_main_loop_new(NULL, FALSE); g_main_loop_run(mainloop); free(async_fence_data.name); if (reason != NULL) { // Give the caller ownership of the exit reason *reason = async_fence_data.result.exit_reason; async_fence_data.result.exit_reason = NULL; } rc = stonith__result2rc(&async_fence_data.result); pcmk__reset_result(&async_fence_data.result); return rc; } #ifdef BUILD_PUBLIC_LIBPACEMAKER int pcmk_request_fencing(stonith_t *st, const char *target, const char *action, const char *name, unsigned int timeout, unsigned int tolerance, int delay, char **reason) { return pcmk__request_fencing(st, target, action, name, timeout, tolerance, delay, reason); } #endif int -pcmk__fence_history(pcmk__output_t *out, stonith_t *st, char *target, +pcmk__fence_history(pcmk__output_t *out, stonith_t *st, const char *target, unsigned int timeout, int verbose, bool broadcast, - bool cleanup) { + bool cleanup) +{ stonith_history_t *history = NULL, *hp, *latest = NULL; int rc = pcmk_rc_ok; int opts = 0; if (cleanup) { out->info(out, "cleaning up fencing-history%s%s", target ? " for node " : "", target ? target : ""); } if (broadcast) { out->info(out, "gather fencing-history from all nodes"); } stonith__set_call_options(opts, target, st_opts); if (cleanup) { stonith__set_call_options(opts, target, st_opt_cleanup); } if (broadcast) { stonith__set_call_options(opts, target, st_opt_broadcast); } rc = st->cmds->history(st, opts, pcmk__str_eq(target, "*", pcmk__str_none)? NULL : target, &history, timeout/1000); if (cleanup) { // Cleanup doesn't return a history list stonith_history_free(history); return pcmk_legacy2rc(rc); } out->begin_list(out, "event", "events", "Fencing history"); history = stonith__sort_history(history); for (hp = history; hp; hp = hp->next) { if (hp->state == st_done) { latest = hp; } if (out->is_quiet(out) || !verbose) { continue; } out->message(out, "stonith-event", hp, true, false, stonith__later_succeeded(hp, history), (uint32_t) pcmk_show_failed_detail); out->increment_list(out); } if (latest) { if (out->is_quiet(out)) { out->message(out, "stonith-event", latest, false, true, NULL, (uint32_t) pcmk_show_failed_detail); } else if (!verbose) { // already printed if verbose out->message(out, "stonith-event", latest, false, false, NULL, (uint32_t) pcmk_show_failed_detail); out->increment_list(out); } } out->end_list(out); stonith_history_free(history); return pcmk_legacy2rc(rc); } #ifdef BUILD_PUBLIC_LIBPACEMAKER int -pcmk_fence_history(xmlNodePtr *xml, stonith_t *st, char *target, unsigned int timeout, - bool quiet, int verbose, bool broadcast, bool cleanup) { +pcmk_fence_history(xmlNodePtr *xml, stonith_t *st, const char *target, + unsigned int timeout, bool quiet, int verbose, + bool broadcast, bool cleanup) +{ pcmk__output_t *out = NULL; int rc = pcmk_rc_ok; rc = pcmk__xml_output_new(&out, xml); if (rc != pcmk_rc_ok) { return rc; } stonith__register_messages(out); out->quiet = quiet; rc = pcmk__fence_history(out, st, target, timeout, verbose, broadcast, cleanup); pcmk__xml_output_finish(out, xml); return rc; } #endif int -pcmk__fence_installed(pcmk__output_t *out, stonith_t *st, unsigned int timeout) { +pcmk__fence_installed(pcmk__output_t *out, stonith_t *st, unsigned int timeout) +{ stonith_key_value_t *devices = NULL; int rc = pcmk_rc_ok; rc = st->cmds->list_agents(st, st_opt_sync_call, NULL, &devices, timeout/1000); /* list_agents returns a negative error code or a positive number of agents. */ if (rc < 0) { return pcmk_legacy2rc(rc); } out->begin_list(out, "fence device", "fence devices", "Installed fence devices"); for (stonith_key_value_t *dIter = devices; dIter; dIter = dIter->next) { out->list_item(out, "device", "%s", dIter->value); } out->end_list(out); stonith_key_value_freeall(devices, 1, 1); return pcmk_rc_ok; } #ifdef BUILD_PUBLIC_LIBPACEMAKER int -pcmk_fence_installed(xmlNodePtr *xml, stonith_t *st, unsigned int timeout) { +pcmk_fence_installed(xmlNodePtr *xml, stonith_t *st, unsigned int timeout) +{ pcmk__output_t *out = NULL; int rc = pcmk_rc_ok; rc = pcmk__xml_output_new(&out, xml); if (rc != pcmk_rc_ok) { return rc; } stonith__register_messages(out); rc = pcmk__fence_installed(out, st, timeout); pcmk__xml_output_finish(out, xml); return rc; } #endif int -pcmk__fence_last(pcmk__output_t *out, const char *target, bool as_nodeid) { +pcmk__fence_last(pcmk__output_t *out, const char *target, bool as_nodeid) +{ time_t when = 0; if (target == NULL) { return pcmk_rc_ok; } if (as_nodeid) { when = stonith_api_time(atol(target), NULL, FALSE); } else { when = stonith_api_time(0, target, FALSE); } return out->message(out, "last-fenced", target, when); } #ifdef BUILD_PUBLIC_LIBPACEMAKER int -pcmk_fence_last(xmlNodePtr *xml, const char *target, bool as_nodeid) { +pcmk_fence_last(xmlNodePtr *xml, const char *target, bool as_nodeid) +{ pcmk__output_t *out = NULL; int rc = pcmk_rc_ok; rc = pcmk__xml_output_new(&out, xml); if (rc != pcmk_rc_ok) { return rc; } stonith__register_messages(out); rc = pcmk__fence_last(out, target, as_nodeid); pcmk__xml_output_finish(out, xml); return rc; } #endif int pcmk__fence_list_targets(pcmk__output_t *out, stonith_t *st, - const char *device_id, unsigned int timeout) { + const char *device_id, unsigned int timeout) +{ GList *targets = NULL; char *lists = NULL; int rc = pcmk_rc_ok; rc = st->cmds->list(st, st_opts, device_id, &lists, timeout/1000); if (rc != pcmk_rc_ok) { return pcmk_legacy2rc(rc); } targets = stonith__parse_targets(lists); out->begin_list(out, "fence target", "fence targets", "Fence Targets"); while (targets != NULL) { out->list_item(out, NULL, "%s", (const char *) targets->data); targets = targets->next; } out->end_list(out); free(lists); return rc; } #ifdef BUILD_PUBLIC_LIBPACEMAKER int pcmk_fence_list_targets(xmlNodePtr *xml, stonith_t *st, const char *device_id, - unsigned int timeout) { + unsigned int timeout) +{ pcmk__output_t *out = NULL; int rc = pcmk_rc_ok; rc = pcmk__xml_output_new(&out, xml); if (rc != pcmk_rc_ok) { return rc; } stonith__register_messages(out); rc = pcmk__fence_list_targets(out, st, device_id, timeout); pcmk__xml_output_finish(out, xml); return rc; } #endif int -pcmk__fence_metadata(pcmk__output_t *out, stonith_t *st, char *agent, - unsigned int timeout) { +pcmk__fence_metadata(pcmk__output_t *out, stonith_t *st, const char *agent, + unsigned int timeout) +{ char *buffer = NULL; int rc = st->cmds->metadata(st, st_opt_sync_call, agent, NULL, &buffer, timeout/1000); if (rc != pcmk_rc_ok) { return pcmk_legacy2rc(rc); } out->output_xml(out, "metadata", buffer); free(buffer); return rc; } #ifdef BUILD_PUBLIC_LIBPACEMAKER int -pcmk_fence_metadata(xmlNodePtr *xml, stonith_t *st, char *agent, - unsigned int timeout) { +pcmk_fence_metadata(xmlNodePtr *xml, stonith_t *st, const char *agent, + unsigned int timeout) +{ pcmk__output_t *out = NULL; int rc = pcmk_rc_ok; rc = pcmk__xml_output_new(&out, xml); if (rc != pcmk_rc_ok) { return rc; } stonith__register_messages(out); rc = pcmk__fence_metadata(out, st, agent, timeout); pcmk__xml_output_finish(out, xml); return rc; } #endif int -pcmk__fence_registered(pcmk__output_t *out, stonith_t *st, char *target, - unsigned int timeout) { +pcmk__fence_registered(pcmk__output_t *out, stonith_t *st, const char *target, + unsigned int timeout) +{ stonith_key_value_t *devices = NULL; int rc = pcmk_rc_ok; rc = st->cmds->query(st, st_opts, target, &devices, timeout/1000); /* query returns a negative error code or a positive number of results. */ if (rc < 0) { return pcmk_legacy2rc(rc); } out->begin_list(out, "fence device", "fence devices", "Registered fence devices"); for (stonith_key_value_t *dIter = devices; dIter; dIter = dIter->next) { out->list_item(out, "device", "%s", dIter->value); } out->end_list(out); stonith_key_value_freeall(devices, 1, 1); /* Return pcmk_rc_ok here, not the number of results. Callers probably * don't care. */ return pcmk_rc_ok; } #ifdef BUILD_PUBLIC_LIBPACEMAKER int -pcmk_fence_registered(xmlNodePtr *xml, stonith_t *st, char *target, - unsigned int timeout) { +pcmk_fence_registered(xmlNodePtr *xml, stonith_t *st, const char *target, + unsigned int timeout) +{ pcmk__output_t *out = NULL; int rc = pcmk_rc_ok; rc = pcmk__xml_output_new(&out, xml); if (rc != pcmk_rc_ok) { return rc; } stonith__register_messages(out); rc = pcmk__fence_registered(out, st, target, timeout); pcmk__xml_output_finish(out, xml); return rc; } #endif int -pcmk__fence_register_level(stonith_t *st, char *target, int fence_level, - stonith_key_value_t *devices) { +pcmk__fence_register_level(stonith_t *st, const char *target, int fence_level, + const stonith_key_value_t *devices) +{ return handle_level(st, target, fence_level, devices, true); } #ifdef BUILD_PUBLIC_LIBPACEMAKER int -pcmk_fence_register_level(stonith_t *st, char *target, int fence_level, - stonith_key_value_t *devices) { +pcmk_fence_register_level(stonith_t *st, const char *target, int fence_level, + const stonith_key_value_t *devices) +{ return pcmk__fence_register_level(st, target, fence_level, devices); } #endif int -pcmk__fence_unregister_level(stonith_t *st, char *target, int fence_level) { +pcmk__fence_unregister_level(stonith_t *st, const char *target, int fence_level) +{ return handle_level(st, target, fence_level, NULL, false); } #ifdef BUILD_PUBLIC_LIBPACEMAKER int -pcmk_fence_unregister_level(stonith_t *st, char *target, int fence_level) { +pcmk_fence_unregister_level(stonith_t *st, const char *target, int fence_level) +{ return pcmk__fence_unregister_level(st, target, fence_level); } #endif int pcmk__fence_validate(pcmk__output_t *out, stonith_t *st, const char *agent, - const char *id, stonith_key_value_t *params, - unsigned int timeout) { + const char *id, const stonith_key_value_t *params, + unsigned int timeout) +{ char *output = NULL; char *error_output = NULL; int rc; rc = st->cmds->validate(st, st_opt_sync_call, id, NULL, agent, params, timeout/1000, &output, &error_output); out->message(out, "validate", agent, id, output, error_output, rc); return pcmk_legacy2rc(rc); } #ifdef BUILD_PUBLIC_LIBPACEMAKER int pcmk_fence_validate(xmlNodePtr *xml, stonith_t *st, const char *agent, - const char *id, stonith_key_value_t *params, - unsigned int timeout) { + const char *id, const stonith_key_value_t *params, + unsigned int timeout) +{ pcmk__output_t *out = NULL; int rc = pcmk_rc_ok; rc = pcmk__xml_output_new(&out, xml); if (rc != pcmk_rc_ok) { return rc; } stonith__register_messages(out); rc = pcmk__fence_validate(out, st, agent, id, params, timeout); pcmk__xml_output_finish(out, xml); return rc; } #endif int pcmk__get_fencing_history(stonith_t *st, stonith_history_t **stonith_history, enum pcmk__fence_history fence_history) { int rc = pcmk_rc_ok; if ((st == NULL) || (st->state == stonith_disconnected)) { rc = ENOTCONN; } else if (fence_history != pcmk__fence_history_none) { rc = st->cmds->history(st, st_opt_sync_call, NULL, stonith_history, 120); rc = pcmk_legacy2rc(rc); if (rc != pcmk_rc_ok) { return rc; } *stonith_history = stonith__sort_history(*stonith_history); if (fence_history == pcmk__fence_history_reduced) { *stonith_history = reduce_fence_history(*stonith_history); } } return rc; }