diff --git a/include/Makefile.am b/include/Makefile.am index 54d68f9441..ca94448984 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,19 +1,20 @@ # # Copyright 2003-2019 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. # MAINTAINERCLEANFILES = Makefile.in config.h.in noinst_HEADERS = config.h \ crm_internal.h \ doxygen.h \ + pacemaker.h \ pacemaker-internal.h \ portability.h pkginclude_HEADERS = crm_config.h SUBDIRS = crm pcmki diff --git a/include/doxygen.h b/include/doxygen.h index 5d465a7ff6..7fa258cd60 100644 --- a/include/doxygen.h +++ b/include/doxygen.h @@ -1,50 +1,52 @@ /* * Copyright 2006-2019 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 DOXYGEN__H # define DOXYGEN__H /** * \file * \brief Fake header file that contains doxygen documentation. * \author Andrew Beekhof * * The purpose of this file is to provide a file that can be used to create * doxygen pages. It should contain _only_ comment blocks. * * * \defgroup core Core API * \defgroup date ISO-8601 Date/Time API * \defgroup cib Configuration API * \defgroup lrmd Executor API * \defgroup pengine Scheduler API * \defgroup fencing Fencing API + * \defgroup pacemaker Pacemaker High Level API */ /** * \mainpage * Welcome to the developer documentation for The Pacemaker Project! For more * information about Pacemaker, please visit the * project web site. * * Here are some pointers on where to go from here. * * Using Pacemaker APIs: * - \ref core * - \ref date * - \ref cib * - \ref lrmd * - \ref pengine * - \ref fencing + * - \ref pacemaker * * Contributing to the Pacemaker Project: * - Pacemaker Development */ #endif /* DOXYGEN__H */ diff --git a/include/pacemaker-internal.h b/include/pacemaker-internal.h index 51d722550b..37399e73a8 100644 --- a/include/pacemaker-internal.h +++ b/include/pacemaker-internal.h @@ -1,20 +1,22 @@ /* * Copyright 2019 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 PACEMAKER_INTERNAL__H # define PACEMAKER_INTERNAL__H # include +# include +# include # include # include # include # include # include #endif diff --git a/include/pacemaker.h b/include/pacemaker.h new file mode 100644 index 0000000000..44d2a82362 --- /dev/null +++ b/include/pacemaker.h @@ -0,0 +1,193 @@ +/* + * Copyright 2019 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 PACEMAKER__H +# define PACEMAKER__H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \file + * \brief High Level API + * \ingroup pacemaker + */ + +# include +# include + +/*! + * \brief Perform a STONITH action. + * + * \param[in] st A connection to the STONITH API. + * \param[in] target The node receiving the action. + * \param[in] action The action to perform. + * \param[in] name Who requested the fence action? + * \param[in] timeout How long to wait for the operation to complete (in seconds). + * \param[in] tolerance If a successful action for \p target happened within + * this many seconds, return 0 without performing the + * action again. + * + * \return 0 on success, or various error codes on error. + */ +int pcmk_fence_action(stonith_t *st, const char *target, const char *action, + const char *name, int timeout, int tolerance); + +/*! + * \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 seconds). + * \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 0 on success, or various error codes on error. + */ +int pcmk_fence_history(xmlNodePtr *xml, stonith_t *st, char *target, int timeout, + bool quiet, int verbose, bool broadcast, bool cleanup); + +/*! + * \brief List all installed STONITH 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 seconds). + * + * \return 0 on success, or various error codes on error. + */ +int pcmk_fence_installed(xmlNodePtr *xml, stonith_t *st, 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 + * + * \return 0 on success, or various error codes on error. + */ +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. + * + * \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 that can do the fencing. + * \param[in] timeout How long to wait for the operation to complete (in seconds). + * + * \return 0 on success, or various error codes on error. + */ +int pcmk_fence_list_targets(xmlNodePtr *xml, stonith_t *st, char *agent, int timeout); + +/*! + * \brief Get metadata for a resource. + * + * \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 seconds). + * + * \return 0 on success, or various error codes on error. + */ +int pcmk_fence_metadata(xmlNodePtr *xml, stonith_t *st, char *agent, int timeout); + +/*! + * \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 seconds). + * + * \return 0 on success, or various error codes on error. + */ +int pcmk_fence_registered(xmlNodePtr *xml, stonith_t *st, char *target, 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. + * + * \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. + * + * \return 0 on success, or various error codes on error. + */ +int pcmk_fence_register_level(stonith_t *st, char *target, int fence_level, + stonith_key_value_t *devices); + +/*! + * \brief Unregister 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. + * + * \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. + * + * \return 0 on success, or various error codes on error. + */ +int pcmk_fence_unregister_level(stonith_t *st, 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. + * + * \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 seconds). + * + * \return 0 on success, or various error codes on error. + */ +int pcmk_fence_validate(xmlNodePtr *xml, stonith_t *st, const char *agent, + const char *id, stonith_key_value_t *params, int timeout); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/pcmki/Makefile.am b/include/pcmki/Makefile.am index 4cf1cf23ab..647f2dca6c 100644 --- a/include/pcmki/Makefile.am +++ b/include/pcmki/Makefile.am @@ -1,19 +1,21 @@ # # Copyright 2019 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. # MAINTAINERCLEANFILES = Makefile.in noinst_HEADERS = pcmki_error.h \ + pcmki_fence.h \ + pcmki_output.h \ pcmki_sched_allocate.h \ pcmki_sched_notif.h \ pcmki_sched_utils.h \ pcmki_scheduler.h \ pcmki_transition.h .PHONY: $(ARCHIVE_VERSION) diff --git a/include/pcmki/pcmki_fence.h b/include/pcmki/pcmki_fence.h new file mode 100644 index 0000000000..c860f6fea0 --- /dev/null +++ b/include/pcmki/pcmki_fence.h @@ -0,0 +1,216 @@ +/* + * Copyright 2019 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 PCMKI_STONITH_H +# define PCMKI_STONITH_H + +# include +# include + +/*! + * \brief Perform a STONITH action. + * + * \note This is the internal version of pcmk_fence_action(). External users + * of the pacemaker API should use that function instead. + * + * \param[in] st A connection to the STONITH API. + * \param[in] target The node receiving the action. + * \param[in] action The action to perform. + * \param[in] name Who requested the fence action? + * \param[in] timeout How long to wait for the operation to complete (in seconds). + * \param[in] tolerance If a successful action for \p target happened within + * this many seconds, return 0 without performing the + * action again. + * + * \return 0 on success, or various error codes on error. + */ +int pcmk__fence_action(stonith_t *st, const char *target, const char *action, + const char *name, int timeout, int tolerance); + +/*! + * \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 seconds). + * \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 0 on success, or various error codes on error. + */ +int pcmk__fence_history(pcmk__output_t *out, stonith_t *st, char *target, + int timeout, bool quiet, int verbose, bool broadcast, + bool cleanup); + +/** + * \brief List all installed STONITH 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 seconds). + * + * \return 0 on success, or various error codes on error. + */ +int pcmk__fence_installed(pcmk__output_t *out, stonith_t *st, 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 0 on success, or various error codes on error. + */ +int pcmk__fence_last(pcmk__output_t *out, const char *target, bool as_nodeid); + +/*! + * \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] agent The agent that can do the fencing. + * \param[in] timeout How long to wait for the operation to complete (in seconds). + * + * \return 0 on success, or various error codes on error. + */ +int pcmk__fence_list_targets(pcmk__output_t *out, stonith_t *st, char *agent, int timeout); + +/*! + * \brief Get metadata for a resource. + * + * \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 seconds). + * + * \return 0 on success, or various error codes on error. + */ +int pcmk__fence_metadata(pcmk__output_t *out, stonith_t *st, char *agent, int timeout); + +/*! + * \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 seconds). + * + * \return 0 on success, or various error codes on error. + */ +int pcmk__fence_registered(pcmk__output_t *out, stonith_t *st, char *target, int timeout); + +/*! + * \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. + * + * \return 0 on success, or various error codes on error. + */ +int pcmk__fence_register_level(stonith_t *st, char *target, int fence_level, + stonith_key_value_t *devices); + +/*! + * \brief Unregister a fencing level for a 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. + * + * \return 0 on success, or various error codes on error. + */ +int pcmk__fence_unregister_level(stonith_t *st, char *target, int fence_level); + +/** + * \brief Validate a STONITH 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 seconds). + * + * \return 0 on success, or various error codes on error. + */ +int pcmk__fence_validate(pcmk__output_t *out, stonith_t *st, const char *agent, + const char *id, stonith_key_value_t *params, int timeout); + +#endif diff --git a/include/pcmki/pcmki_output.h b/include/pcmki/pcmki_output.h new file mode 100644 index 0000000000..fb3be415a7 --- /dev/null +++ b/include/pcmki/pcmki_output.h @@ -0,0 +1,28 @@ +/* + * Copyright 2019 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 PCMKI_OUTPUT_H +# define PCMKI_OUTPUT_H + +#ifdef __cplusplus +extern "C" { +#endif + +# include +# include + +extern pcmk__supported_format_t pcmk__out_formats[]; + +int pcmk__out_prologue(pcmk__output_t **out, xmlNodePtr *xml); +void pcmk__out_epilogue(pcmk__output_t *out, xmlNodePtr *xml, int retval); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/pacemaker/Makefile.am b/lib/pacemaker/Makefile.am index 0d6bff2cbc..b1a584286d 100644 --- a/lib/pacemaker/Makefile.am +++ b/lib/pacemaker/Makefile.am @@ -1,46 +1,48 @@ # # Copyright 2004-2019 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 $(top_srcdir)/Makefile.common AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir) ## libraries lib_LTLIBRARIES = libpacemaker.la ## SOURCES libpacemaker_la_LDFLAGS = -version-info 2:0:1 libpacemaker_la_CFLAGS = $(CFLAGS_HARDENED_LIB) libpacemaker_la_LDFLAGS += $(LDFLAGS_HARDENED_LIB) libpacemaker_la_LIBADD = $(top_builddir)/lib/pengine/libpe_status.la \ $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/lrmd/liblrmd.la \ $(top_builddir)/lib/common/libcrmcommon.la # -L$(top_builddir)/lib/pils -lpils -export-dynamic -module -avoid-version # Use += rather than backlashed continuation lines for parsing by bumplibs.sh libpacemaker_la_SOURCES = +libpacemaker_la_SOURCES += pcmk_fence.c +libpacemaker_la_SOURCES += pcmk_output.c libpacemaker_la_SOURCES += pcmk_sched_allocate.c libpacemaker_la_SOURCES += pcmk_sched_bundle.c libpacemaker_la_SOURCES += pcmk_sched_clone.c libpacemaker_la_SOURCES += pcmk_sched_constraints.c libpacemaker_la_SOURCES += pcmk_sched_graph.c libpacemaker_la_SOURCES += pcmk_sched_group.c libpacemaker_la_SOURCES += pcmk_sched_messages.c libpacemaker_la_SOURCES += pcmk_sched_native.c libpacemaker_la_SOURCES += pcmk_sched_notif.c libpacemaker_la_SOURCES += pcmk_sched_promotable.c libpacemaker_la_SOURCES += pcmk_sched_transition.c libpacemaker_la_SOURCES += pcmk_sched_utilization.c libpacemaker_la_SOURCES += pcmk_sched_utils.c libpacemaker_la_SOURCES += pcmk_trans_graph.c libpacemaker_la_SOURCES += pcmk_trans_unpack.c libpacemaker_la_SOURCES += pcmk_trans_utils.c diff --git a/lib/pacemaker/pcmk_fence.c b/lib/pacemaker/pcmk_fence.c new file mode 100644 index 0000000000..a219ee88a6 --- /dev/null +++ b/lib/pacemaker/pcmk_fence.c @@ -0,0 +1,449 @@ +/* + * Copyright 2009-2019 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 + +static 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; + int timeout; + int tolerance; + int rc; +} async_fence_data; + +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; + char *value = NULL; + + 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) { + return st->cmds->register_level_full(st, st_opts, node, pattern, + name, value, fence_level, + devices); + } + + return st->cmds->remove_level_full(st, st_opts, node, pattern, + name, value, fence_level); +} + +static void +notify_callback(stonith_t * st, stonith_event_t * e) +{ + if (e->result != pcmk_ok) { + return; + } + + if (safe_str_eq(async_fence_data.target, e->target) && + safe_str_eq(async_fence_data.action, e->action)) { + + async_fence_data.rc = e->result; + g_main_loop_quit(mainloop); + } +} + +static void +fence_callback(stonith_t * stonith, stonith_callback_data_t * data) +{ + async_fence_data.rc = data->rc; + + 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) { + fprintf(stderr, "Could not connect to fencer: %s\n", pcmk_strerror(rc)); + g_main_loop_quit(mainloop); + return TRUE; + } + + st->cmds->register_notification(st, T_STONITH_NOTIFY_FENCE, notify_callback); + + call_id = st->cmds->fence(st, + st_opt_allow_suicide, + async_fence_data.target, + async_fence_data.action, + async_fence_data.timeout, async_fence_data.tolerance); + + if (call_id < 0) { + g_main_loop_quit(mainloop); + return TRUE; + } + + st->cmds->register_callback(st, + call_id, + async_fence_data.timeout, + st_opt_timeout_updates, NULL, "callback", fence_callback); + + return TRUE; +} + +int +pcmk__fence_action(stonith_t *st, const char *target, const char *action, + const char *name, int timeout, int tolerance) +{ + crm_trigger_t *trig; + + 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.rc = -1; + + 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); + + return async_fence_data.rc; +} + +int +pcmk_fence_action(stonith_t *st, const char *target, const char *action, + const char *name, int timeout, int tolerance) { + return pcmk__fence_action(st, target, action, name, timeout, tolerance); +} + +int +pcmk__fence_history(pcmk__output_t *out, stonith_t *st, char *target, + int timeout, bool quiet, int verbose, bool broadcast, + bool cleanup) { + stonith_history_t *history = NULL, *hp, *latest = NULL; + int rc = 0; + + if (!quiet) { + 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"); + } + } + + rc = st->cmds->history(st, st_opts | (cleanup ? st_opt_cleanup : 0) | + broadcast ? st_opt_broadcast : 0, + safe_str_eq(target, "*") ? NULL : target, + &history, timeout); + + 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 (quiet || !verbose) { + continue; + } + + out->message(out, "stonith-event", hp, 1, stonith__later_succeeded(hp, history)); + out->increment_list(out); + } + + if (latest) { + if (quiet && out->supports_quiet) { + out->info(out, "%lld", (long long) latest->completed); + } else if (!verbose) { // already printed if verbose + out->message(out, "stonith-event", latest, 0, FALSE); + out->increment_list(out); + } + } + + out->end_list(out); + + stonith_history_free(history); + return rc; +} + +int +pcmk_fence_history(xmlNodePtr *xml, stonith_t *st, char *target, int timeout, + bool quiet, int verbose, bool broadcast, bool cleanup) { + pcmk__output_t *out = NULL; + int rc = 0; + + rc = pcmk__out_prologue(&out, xml); + if (rc != 0) { + return rc; + } + + rc = pcmk__fence_history(out, st, target, timeout, quiet, verbose, + broadcast, cleanup); + pcmk__out_epilogue(out, xml, rc); + return rc; +} + +int +pcmk__fence_installed(pcmk__output_t *out, stonith_t *st, int timeout) { + stonith_key_value_t *devices = NULL; + int rc; + + rc = st->cmds->list_agents(st, st_opt_sync_call, NULL, &devices, timeout); + if (rc < 0) { + return 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 0; +} + +int +pcmk_fence_installed(xmlNodePtr *xml, stonith_t *st, int timeout) { + pcmk__output_t *out = NULL; + int rc = 0; + + rc = pcmk__out_prologue(&out, xml); + if (rc != 0) { + return rc; + } + + rc = pcmk__fence_installed(out, st, timeout); + pcmk__out_epilogue(out, xml, rc); + return rc; +} + +int +pcmk__fence_last(pcmk__output_t *out, const char *target, bool as_nodeid) { + time_t when = 0; + + if (target == NULL) { + return 0; + } + + if (as_nodeid) { + when = stonith_api_time(atol(target), NULL, FALSE); + } else { + when = stonith_api_time(0, target, FALSE); + } + + out->message(out, "last-fenced", target, when); + return 0; +} + +int +pcmk_fence_last(xmlNodePtr *xml, const char *target, bool as_nodeid) { + pcmk__output_t *out = NULL; + int rc = 0; + + rc = pcmk__out_prologue(&out, xml); + if (rc != 0) { + return rc; + } + + rc = pcmk__fence_last(out, target, as_nodeid); + pcmk__out_epilogue(out, xml, rc); + return rc; +} + +int +pcmk__fence_list_targets(pcmk__output_t *out, stonith_t *st, char *agent, int timeout) { + GList *targets = NULL; + char *lists = NULL; + int rc = 0; + + rc = st->cmds->list(st, st_opts, agent, &lists, timeout); + if (rc != 0) { + return 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 0; +} + +int +pcmk_fence_list_targets(xmlNodePtr *xml, stonith_t *st, char *agent, int timeout) { + pcmk__output_t *out = NULL; + int rc = 0; + + rc = pcmk__out_prologue(&out, xml); + if (rc != 0) { + return rc; + } + + rc = pcmk__fence_list_targets(out, st, agent, timeout); + pcmk__out_epilogue(out, xml, rc); + return rc; +} + +int +pcmk__fence_metadata(pcmk__output_t *out, stonith_t *st, char *agent, int timeout) { + char *buffer = NULL; + int rc = st->cmds->metadata(st, st_opt_sync_call, agent, NULL, &buffer, + timeout); + + if (rc != pcmk_ok) { + return rc; + } + + out->output_xml(out, "metadata", buffer); + free(buffer); + return rc; +} + +int +pcmk_fence_metadata(xmlNodePtr *xml, stonith_t *st, char *agent, int timeout) { + pcmk__output_t *out = NULL; + int rc = 0; + + rc = pcmk__out_prologue(&out, xml); + if (rc != 0) { + return rc; + } + + rc = pcmk__fence_metadata(out, st, agent, timeout); + pcmk__out_epilogue(out, xml, rc); + return rc; +} + +int +pcmk__fence_registered(pcmk__output_t *out, stonith_t *st, char *target, int timeout) { + stonith_key_value_t *devices = NULL; + int rc; + + rc = st->cmds->query(st, st_opts, target, &devices, timeout); + if (rc < 0) { + return 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 0; +} + +int +pcmk_fence_registered(xmlNodePtr *xml, stonith_t *st, char *target, int timeout) { + pcmk__output_t *out = NULL; + int rc = 0; + + rc = pcmk__out_prologue(&out, xml); + if (rc != 0) { + return rc; + } + + rc = pcmk__fence_registered(out, st, target, timeout); + pcmk__out_epilogue(out, xml, rc); + return rc; +} + +int +pcmk__fence_register_level(stonith_t *st, char *target, int fence_level, + stonith_key_value_t *devices) { + return handle_level(st, target, fence_level, devices, true); +} + +int +pcmk_fence_register_level(stonith_t *st, char *target, int fence_level, + stonith_key_value_t *devices) { + return pcmk__fence_register_level(st, target, fence_level, devices); +} + +int +pcmk__fence_unregister_level(stonith_t *st, char *target, int fence_level) { + return handle_level(st, target, fence_level, NULL, false); +} + +int +pcmk_fence_unregister_level(stonith_t *st, char *target, int fence_level) { + return pcmk__fence_unregister_level(st, target, fence_level); +} + +int +pcmk__fence_validate(pcmk__output_t *out, stonith_t *st, const char *agent, + const char *id, stonith_key_value_t *params, 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, &output, &error_output); + out->message(out, "validate", agent, id, output, error_output, rc); + return rc; +} + +int +pcmk_fence_validate(xmlNodePtr *xml, stonith_t *st, const char *agent, + const char *id, stonith_key_value_t *params, int timeout) { + pcmk__output_t *out = NULL; + int rc = 0; + + rc = pcmk__out_prologue(&out, xml); + if (rc != 0) { + return rc; + } + + rc = pcmk__fence_validate(out, st, agent, id, params, timeout); + pcmk__out_epilogue(out, xml, rc); + return rc; +} diff --git a/lib/pacemaker/pcmk_output.c b/lib/pacemaker/pcmk_output.c new file mode 100644 index 0000000000..19c5ee9747 --- /dev/null +++ b/lib/pacemaker/pcmk_output.c @@ -0,0 +1,47 @@ +/* + * Copyright 2019 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 + +pcmk__supported_format_t pcmk__out_formats[] = { + PCMK__SUPPORTED_FORMAT_XML, + { NULL, NULL, NULL } +}; + +int +pcmk__out_prologue(pcmk__output_t **out, xmlNodePtr *xml) { + int rc = 0; + + if (*xml != NULL) { + xmlFreeNode(*xml); + } + + pcmk__register_formats(NULL, pcmk__out_formats); + rc = pcmk__output_new(out, "xml", NULL, NULL); + if (rc != 0) { + return rc; + } + + stonith__register_messages(*out); + return rc; +} + +void +pcmk__out_epilogue(pcmk__output_t *out, xmlNodePtr *xml, int retval) { + if (retval == 0) { + out->finish(out, 0, FALSE, (void **) xml); + } + + pcmk__output_free(out); +}