diff --git a/tools/Makefile.am b/tools/Makefile.am index 29d6890c5c..37498147c2 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,160 +1,161 @@ # # 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 if BUILD_SYSTEMD systemdsystemunit_DATA = crm_mon.service endif noinst_HEADERS = crm_mon.h crm_resource.h pcmkdir = $(datadir)/$(PACKAGE) pcmk_DATA = report.common report.collector sbin_SCRIPTS = crm_report crm_standby crm_master crm_failcount if BUILD_CIBSECRETS sbin_SCRIPTS += cibsecret endif noinst_SCRIPTS = pcmk_simtimes EXTRA_DIST = crm_diff.8.inc \ crm_mon.sysconfig \ crm_mon.8.inc \ crm_node.8.inc \ fix-manpages \ stonith_admin.8.inc sbin_PROGRAMS = attrd_updater \ cibadmin \ crmadmin \ crm_simulate \ crm_attribute \ crm_diff \ crm_error \ crm_mon \ crm_node \ crm_resource \ crm_rule \ crm_shadow \ crm_verify \ crm_ticket \ iso8601 \ stonith_admin if BUILD_SERVICELOG sbin_PROGRAMS += notifyServicelogEvent endif if BUILD_OPENIPMI_SERVICELOG sbin_PROGRAMS += ipmiservicelogd endif ## SOURCES # A few tools are just thin wrappers around crm_attribute. # This makes their help get updated when crm_attribute changes # (see Makefile.common). MAN8DEPS = crm_attribute crmadmin_SOURCES = crmadmin.c crmadmin_LDADD = $(top_builddir)/lib/pengine/libpe_status.la \ $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/common/libcrmcommon.la crm_error_SOURCES = crm_error.c crm_error_LDADD = $(top_builddir)/lib/common/libcrmcommon.la cibadmin_SOURCES = cibadmin.c cibadmin_LDADD = $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/common/libcrmcommon.la crm_shadow_SOURCES = crm_shadow.c crm_shadow_LDADD = $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/common/libcrmcommon.la crm_node_SOURCES = crm_node.c crm_node_LDADD = $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/common/libcrmcommon.la crm_simulate_SOURCES = crm_simulate.c crm_simulate_LDADD = $(top_builddir)/lib/pengine/libpe_status.la \ $(top_builddir)/lib/pacemaker/libpacemaker.la \ $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/common/libcrmcommon.la crm_diff_SOURCES = crm_diff.c crm_diff_LDADD = $(top_builddir)/lib/common/libcrmcommon.la crm_mon_SOURCES = crm_mon.c crm_mon_curses.c crm_mon_print.c crm_mon_runtime.c crm_mon_xml.c crm_mon_LDADD = $(top_builddir)/lib/pengine/libpe_status.la \ $(top_builddir)/lib/fencing/libstonithd.la \ $(top_builddir)/lib/pacemaker/libpacemaker.la \ $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/common/libcrmcommon.la \ $(CURSESLIBS) crm_verify_SOURCES = crm_verify.c crm_verify_LDADD = $(top_builddir)/lib/pengine/libpe_status.la \ $(top_builddir)/lib/pacemaker/libpacemaker.la \ $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/common/libcrmcommon.la crm_attribute_SOURCES = crm_attribute.c crm_attribute_LDADD = $(top_builddir)/lib/cluster/libcrmcluster.la \ $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/common/libcrmcommon.la crm_resource_SOURCES = crm_resource.c crm_resource_ban.c crm_resource_runtime.c crm_resource_print.c crm_resource_LDADD = $(top_builddir)/lib/pengine/libpe_rules.la \ $(top_builddir)/lib/fencing/libstonithd.la \ $(top_builddir)/lib/lrmd/liblrmd.la \ $(top_builddir)/lib/services/libcrmservice.la \ $(top_builddir)/lib/pengine/libpe_status.la \ $(top_builddir)/lib/pacemaker/libpacemaker.la \ $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/common/libcrmcommon.la crm_rule_SOURCES = crm_rule.c crm_rule_LDADD = $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/pengine/libpe_rules.la \ $(top_builddir)/lib/pengine/libpe_status.la \ $(top_builddir)/lib/common/libcrmcommon.la iso8601_SOURCES = iso8601.c iso8601_LDADD = $(top_builddir)/lib/common/libcrmcommon.la attrd_updater_SOURCES = attrd_updater.c attrd_updater_LDADD = $(top_builddir)/lib/common/libcrmcommon.la crm_ticket_SOURCES = crm_ticket.c crm_ticket_LDADD = $(top_builddir)/lib/pengine/libpe_rules.la \ $(top_builddir)/lib/pengine/libpe_status.la \ $(top_builddir)/lib/pacemaker/libpacemaker.la \ $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/common/libcrmcommon.la stonith_admin_SOURCES = stonith_admin.c -stonith_admin_LDADD = $(top_builddir)/lib/common/libcrmcommon.la \ +stonith_admin_LDADD = $(top_builddir)/lib/pacemaker/libpacemaker.la \ $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/pengine/libpe_status.la \ - $(top_builddir)/lib/fencing/libstonithd.la + $(top_builddir)/lib/fencing/libstonithd.la \ + $(top_builddir)/lib/common/libcrmcommon.la if BUILD_SERVICELOG notifyServicelogEvent_SOURCES = notifyServicelogEvent.c notifyServicelogEvent_CFLAGS = $(SERVICELOG_CFLAGS) notifyServicelogEvent_LDADD = $(top_builddir)/lib/common/libcrmcommon.la $(SERVICELOG_LIBS) endif if BUILD_OPENIPMI_SERVICELOG ipmiservicelogd_SOURCES = ipmiservicelogd.c ipmiservicelogd_CFLAGS = $(OPENIPMI_SERVICELOG_CFLAGS) $(SERVICELOG_CFLAGS) ipmiservicelogd_LDFLAGS = $(top_builddir)/lib/common/libcrmcommon.la $(OPENIPMI_SERVICELOG_LIBS) $(SERVICELOG_LIBS) endif CLEANFILES = $(man8_MANS) diff --git a/tools/stonith_admin.c b/tools/stonith_admin.c index f5023a79fd..7ca4321a68 100644 --- a/tools/stonith_admin.c +++ b/tools/stonith_admin.c @@ -1,853 +1,612 @@ /* * 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 #include #include #include #include #include #include #include -#include #include #include #include #include #include #include +#include #define SUMMARY "stonith_admin - Access the Pacemaker fencing API" char action = 0; struct { gboolean as_nodeid; gboolean broadcast; gboolean cleanup; gboolean installed; gboolean metadata; gboolean registered; gboolean validate_cfg; stonith_key_value_t *devices; stonith_key_value_t *params; int fence_level; int timeout ; int tolerance; char *agent; char *confirm_host; char *fence_host; char *history; char *last_fenced; char *query; char *reboot_host; char *register_dev; char *register_level; char *targets; char *terminate; char *unfence_host; char *unregister_dev; char *unregister_level; } options = { .timeout = 120 }; gboolean add_env_params(const gchar *option_name, const gchar *optarg, gpointer data, GError **error); gboolean add_stonith_device(const gchar *option_name, const gchar *optarg, gpointer data, GError **error); gboolean add_stonith_params(const gchar *option_name, const gchar *optarg, gpointer data, GError **error); gboolean add_tolerance(const gchar *option_name, const gchar *optarg, gpointer data, GError **error); gboolean set_tag(const gchar *option_name, const gchar *optarg, gpointer data, GError **error); #define INDENT " " /* *INDENT-OFF* */ static GOptionEntry defn_entries[] = { { "register", 'R', 0, G_OPTION_ARG_STRING, &options.register_dev, "Register the named stonith device. Requires: --agent.\n" INDENT "Optional: --option, --env-option.", "DEVICE" }, { "deregister", 'D', 0, G_OPTION_ARG_STRING, &options.unregister_dev, "De-register the named stonith device.", "DEVICE" }, { "register-level", 'r', 0, G_OPTION_ARG_STRING, &options.register_level, "Register a stonith level for the named target,\n" INDENT "specified as one of NAME, @PATTERN, or ATTR=VALUE.\n" INDENT "Requires: --index and one or more --device entries.", "TARGET" }, { "deregister-level", 'd', 0, G_OPTION_ARG_STRING, &options.unregister_level, "Unregister a stonith level for the named target,\n" INDENT "specified as for --register-level. Requires: --index", "TARGET" }, { NULL } }; static GOptionEntry query_entries[] = { { "list", 'l', 0, G_OPTION_ARG_STRING, &options.terminate, "List devices that can terminate the specified host.\n" INDENT "Optional: --timeout", "HOST" }, { "list-registered", 'L', 0, G_OPTION_ARG_NONE, &options.registered, "List all registered devices. Optional: --timeout.", NULL }, { "list-installed", 'I', 0, G_OPTION_ARG_NONE, &options.installed, "List all installed devices. Optional: --timeout.", NULL }, { "list-targets", 's', 0, G_OPTION_ARG_STRING, &options.targets, "List the targets that can be fenced by the\n" INDENT "named device. Optional: --timeout.", "DEVICE" }, { "metadata", 'M', 0, G_OPTION_ARG_NONE, &options.metadata, "Show agent metadata. Requires: --agent.\n" INDENT "Optional: --timeout.", NULL }, { "query", 'Q', 0, G_OPTION_ARG_STRING, &options.query, "Check the named device's status. Optional: --timeout.", "DEVICE" }, { "history", 'H', 0, G_OPTION_ARG_STRING, &options.history, "Show last successful fencing operation for named node\n" INDENT "(or '*' for all nodes). Optional: --timeout, --cleanup,\n" INDENT "--quiet (show only the operation's epoch timestamp),\n" INDENT "--verbose (show all recorded and pending operations),\n" INDENT "--broadcast (update history from all nodes available).", "NODE" }, { "last", 'h', 0, G_OPTION_ARG_STRING, &options.last_fenced, "Indicate when the named node was last fenced.\n" INDENT "Optional: --as-node-id.", "NODE" }, { "validate", 'K', 0, G_OPTION_ARG_NONE, &options.validate_cfg, "Validate a fence device configuration.\n" INDENT "Requires: --agent. Optional: --option, --env-option,\n" INDENT "--quiet (print no output, only return status).", NULL }, { NULL } }; static GOptionEntry fence_entries[] = { { "fence", 'F', 0, G_OPTION_ARG_STRING, &options.fence_host, "Fence named host. Optional: --timeout, --tolerance.", "HOST" }, { "unfence", 'U', 0, G_OPTION_ARG_STRING, &options.unfence_host, "Unfence named host. Optional: --timeout, --tolerance.", "HOST" }, { "reboot", 'B', 0, G_OPTION_ARG_STRING, &options.reboot_host, "Reboot named host. Optional: --timeout, --tolerance.", "HOST" }, { "confirm", 'C', 0, G_OPTION_ARG_STRING, &options.confirm_host, "Tell cluster that named host is now safely down.", "HOST", }, { NULL } }; static GOptionEntry addl_entries[] = { { "cleanup", 'c', 0, G_OPTION_ARG_NONE, &options.cleanup, "Cleanup wherever appropriate. Requires --history.", NULL }, { "broadcast", 'b', 0, G_OPTION_ARG_NONE, &options.broadcast, "Broadcast wherever appropriate.", NULL }, { "agent", 'a', 0, G_OPTION_ARG_STRING, &options.agent, "The agent to use (for example, fence_xvm;\n" INDENT "with --register, --metadata, --validate).", "AGENT" }, { "option", 'o', 0, G_OPTION_ARG_CALLBACK, add_stonith_params, "Specify a device configuration parameter as NAME=VALUE\n" INDENT "(may be specified multiple times; with --register,\n" INDENT "--validate).", "PARAM" }, { "env-option", 'e', 0, G_OPTION_ARG_CALLBACK, add_env_params, "Specify a device configuration parameter with the\n" INDENT "specified name, using the value of the\n" INDENT "environment variable of the same name prefixed with\n" INDENT "OCF_RESKEY_ (may be specified multiple times;\n" INDENT "with --register, --validate).", "PARAM" }, { "tag", 'T', 0, G_OPTION_ARG_CALLBACK, set_tag, "Identify fencing operations in logs with the specified\n" INDENT "tag; useful when multiple entities might invoke\n" INDENT "stonith_admin (used with most commands).", "TAG" }, { "device", 'v', 0, G_OPTION_ARG_CALLBACK, add_stonith_device, "Device ID (with --register-level, device to associate with\n" INDENT "a given host and level; may be specified multiple times)" #if SUPPORT_CIBSECRETS "\n" INDENT "(with --validate, name to use to load CIB secrets)" #endif ".", "DEVICE" }, { "index", 'i', 0, G_OPTION_ARG_INT, &options.fence_level, "The stonith level (1-9) (with --register-level,\n" INDENT "--deregister-level).", "LEVEL" }, { "timeout", 't', 0, G_OPTION_ARG_INT, &options.timeout, "Operation timeout in seconds (default 120;\n" INDENT "used with most commands).", "SECONDS" }, { "as-node-id", 'n', 0, G_OPTION_ARG_NONE, &options.as_nodeid, "(Advanced) The supplied node is the corosync node ID\n" INDENT "(with --last).", NULL }, { "tolerance", 0, 0, G_OPTION_ARG_CALLBACK, add_tolerance, "(Advanced) Do nothing if an equivalent --fence request\n" INDENT "succeeded less than this many seconds earlier\n" INDENT "(with --fence, --unfence, --reboot).", "SECONDS" }, { NULL } }; /* *INDENT-ON* */ static pcmk__supported_format_t formats[] = { PCMK__SUPPORTED_FORMAT_HTML, PCMK__SUPPORTED_FORMAT_TEXT, PCMK__SUPPORTED_FORMAT_XML, { NULL, NULL, NULL } }; static int st_opts = st_opt_sync_call | st_opt_allow_suicide; -static GMainLoop *mainloop = NULL; -struct { - stonith_t *st; - const char *target; - const char *action; - char *name; - int timeout; - int tolerance; - int rc; -} async_fence_data; +static char *name = NULL; gboolean add_env_params(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) { char *key = crm_concat("OCF_RESKEY", optarg, '_'); const char *env = getenv(key); gboolean retval = TRUE; if (env == NULL) { crm_err("Invalid option: -e %s", optarg); g_set_error(error, G_OPTION_ERROR, CRM_EX_INVALID_PARAM, "Invalid option: -e %s", optarg); retval = FALSE; } else { crm_info("Got: '%s'='%s'", optarg, env); options.params = stonith_key_value_add(options.params, optarg, env); } free(key); return retval; } gboolean add_stonith_device(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) { options.devices = stonith_key_value_add(options.devices, NULL, optarg); return TRUE; } gboolean add_tolerance(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) { options.tolerance = crm_get_msec(optarg) / 1000; return TRUE; } gboolean add_stonith_params(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) { char *name = NULL; char *value = NULL; int rc = 0; gboolean retval = TRUE; crm_info("Scanning: -o %s", optarg); rc = pcmk_scan_nvpair(optarg, &name, &value); if (rc != 2) { crm_err("Invalid option: -o %s: %s", optarg, pcmk_strerror(rc)); g_set_error(error, G_OPTION_ERROR, rc, "Invalid option: -o %s: %s", optarg, pcmk_strerror(rc)); retval = FALSE; } else { crm_info("Got: '%s'='%s'", name, value); options.params = stonith_key_value_add(options.params, name, value); } free(name); free(value); return retval; } gboolean set_tag(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) { - free(async_fence_data.name); - async_fence_data.name = crm_strdup_printf("%s.%s", crm_system_name, optarg); - return TRUE; -} - -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); - + free(name); + name = crm_strdup_printf("%s.%s", crm_system_name, optarg); return TRUE; } -static int -mainloop_fencing(stonith_t * st, const char *target, const char *action, int timeout, int tolerance) -{ - crm_trigger_t *trig; - - async_fence_data.st = st; - 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); - - return async_fence_data.rc; -} - -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 int -handle_history(stonith_t *st, const char *target, int timeout, int quiet, - int verbose, int cleanup, int broadcast, pcmk__output_t *out) -{ - 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; -} - -static int -validate(stonith_t *st, const char *agent, const char *id, - stonith_key_value_t *params, int timeout, int quiet, - pcmk__output_t *out) -{ - int rc = 1; - char *output = NULL; - char *error_output = NULL; - - rc = st->cmds->validate(st, st_opt_sync_call, id, NULL, agent, params, - timeout, &output, &error_output); - - if (quiet) { - return rc; - } - - out->message(out, "validate", agent, id, output, error_output, rc); - return rc; -} - -static void -show_last_fenced(pcmk__output_t *out, const char *target) -{ - time_t when = 0; - - if (target == NULL) { - // Not really possible, but makes static analysis happy - return; - } - if (options.as_nodeid) { - uint32_t nodeid = atol(target); - when = stonith_api_time(nodeid, NULL, FALSE); - } else { - when = stonith_api_time(0, target, FALSE); - } - out->message(out, "last-fenced", target, when); -} - -static int -show_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) { - out->output_xml(out, "metadata", buffer); - } else { - out->err(out, "Can't get fence agent meta-data: %s", - pcmk_strerror(rc)); - } - free(buffer); - return rc; -} - static GOptionContext * build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) { GOptionContext *context = NULL; GOptionEntry extra_prog_entries[] = { { "quiet", 'q', 0, G_OPTION_ARG_NONE, &(args->quiet), "Be less descriptive in output.", NULL }, { NULL } }; context = pcmk__build_arg_context(args, "text (default), html, xml", group); /* Add the -q option, which cannot be part of the globally supported options * because some tools use that flag for something else. */ pcmk__add_main_args(context, extra_prog_entries); pcmk__add_arg_group(context, "definition", "Device Definition Commands:", "Show device definition help", defn_entries); pcmk__add_arg_group(context, "queries", "Queries:", "Show query help", query_entries); pcmk__add_arg_group(context, "fence", "Fencing Commands:", "Show fence help", fence_entries); pcmk__add_arg_group(context, "additional", "Additional Options:", "Show additional options", addl_entries); return context; } int main(int argc, char **argv) { int rc = 0; bool no_connect = false; bool required_agent = false; char *target = NULL; - char *lists = NULL; const char *device = NULL; crm_exit_t exit_code = CRM_EX_OK; stonith_t *st = NULL; - stonith_key_value_t *dIter = NULL; pcmk__output_t *out = NULL; pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY); GError *error = NULL; GOptionContext *context = NULL; GOptionGroup *output_group = NULL; gchar **processed_args = NULL; context = build_arg_context(args, &output_group); pcmk__register_formats(output_group, formats); crm_log_cli_init("stonith_admin"); - async_fence_data.name = strdup(crm_system_name); + name = strdup(crm_system_name); processed_args = pcmk__cmdline_preproc(argv, "adehilorstvBCDFHQRTU"); if (!g_option_context_parse_strv(context, &processed_args, &error)) { fprintf(stderr, "%s: %s\n", g_get_prgname(), error->message); exit_code = CRM_EX_USAGE; goto done; } for (int i = 0; i < args->verbosity; i++) { crm_bump_log_level(argc, argv); } rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv); if (rc != 0) { fprintf(stderr, "Error creating output format %s: %s\n", args->output_ty, pcmk_strerror(rc)); exit_code = CRM_EX_ERROR; goto done; } stonith__register_messages(out); if (args->version) { out->version(out, false); goto done; } if (options.validate_cfg) { required_agent = true; no_connect = true; action = 'K'; } if (options.installed) { no_connect = true; action = 'I'; } if (options.registered) { action = 'L'; } if (options.register_dev != NULL) { required_agent = true; action = 'R'; device = options.register_dev; } if (options.query != NULL) { action = 'Q'; device = options.query; } if (options.unregister_dev != NULL) { action = 'D'; device = options.unregister_dev; } if (options.targets != NULL) { action = 's'; device = options.targets; } if (options.terminate != NULL) { action = 'L'; target = options.terminate; } if (options.metadata) { no_connect = true; required_agent = true; action = 'M'; } if (options.reboot_host != NULL) { no_connect = true; action = 'B'; target = options.reboot_host; crm_log_args(argc, argv); } if (options.fence_host != NULL) { no_connect = true; action = 'F'; target = options.fence_host; crm_log_args(argc, argv); } if (options.unfence_host != NULL) { no_connect = true; action = 'U'; target = options.unfence_host; crm_log_args(argc, argv); } if (options.confirm_host != NULL) { action = 'C'; target = options.confirm_host; crm_log_args(argc, argv); } if (options.last_fenced != NULL) { action = 'h'; target = options.last_fenced; } if (options.history != NULL) { action = 'H'; target = options.history; } if (options.register_level != NULL) { action = 'r'; target = options.register_level; } if (options.unregister_level != NULL) { action = 'd'; target = options.unregister_level; } if (optind > argc || action == 0) { out->err(out, "%s", g_option_context_get_help(context, TRUE, NULL)); exit_code = CRM_EX_USAGE; goto done; } if (required_agent && options.agent == NULL) { out->err(out, "Please specify an agent to query using -a,--agent [value]"); out->err(out, "%s", g_option_context_get_help(context, TRUE, NULL)); exit_code = CRM_EX_USAGE; goto done; } st = stonith_api_new(); if (st == NULL) { rc = -ENOMEM; } else if (!no_connect) { - rc = st->cmds->connect(st, async_fence_data.name, NULL); + rc = st->cmds->connect(st, name, NULL); } if (rc < 0) { out->err(out, "Could not connect to fencer: %s", pcmk_strerror(rc)); exit_code = CRM_EX_DISCONNECT; goto done; } switch (action) { case 'I': - rc = st->cmds->list_agents(st, st_opt_sync_call, NULL, &options.devices, options.timeout); + rc = pcmk__fence_installed(out, st, options.timeout); if (rc < 0) { out->err(out, "Failed to list installed devices: %s", pcmk_strerror(rc)); - break; - } - - out->begin_list(out, "fence device", "fence devices", "Installed fence devices"); - for (dIter = options.devices; dIter; dIter = dIter->next) { - out->list_item(out, "device", "%s", dIter->value); } - out->end_list(out); - rc = 0; - - stonith_key_value_freeall(options.devices, 1, 1); break; case 'L': - rc = st->cmds->query(st, st_opts, target, &options.devices, options.timeout); + rc = pcmk__fence_registered(out, st, target, options.timeout); if (rc < 0) { out->err(out, "Failed to list registered devices: %s", pcmk_strerror(rc)); - break; } - out->begin_list(out, "fence device", "fence devices", "Registered fence devices"); - for (dIter = options.devices; dIter; dIter = dIter->next) { - out->list_item(out, "device", "%s", dIter->value); - } - - out->end_list(out); - rc = 0; - - stonith_key_value_freeall(options.devices, 1, 1); break; case 'Q': rc = st->cmds->monitor(st, st_opts, device, options.timeout); if (rc < 0) { rc = st->cmds->list(st, st_opts, device, NULL, options.timeout); } break; + case 's': - rc = st->cmds->list(st, st_opts, device, &lists, options.timeout); - if (rc == 0) { - GList *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); - - } else if (rc != 0) { + rc = pcmk__fence_list_targets(out, st, target, options.timeout); + if (rc < 0) { out->err(out, "Couldn't list targets: %s", pcmk_strerror(rc)); } + break; + case 'R': rc = st->cmds->register_device(st, st_opts, device, NULL, options.agent, options.params); break; + case 'D': rc = st->cmds->remove_device(st, st_opts, device); break; + case 'd': + rc = pcmk__fence_unregister_level(st, target, options.fence_level); + break; + case 'r': - rc = handle_level(st, target, options.fence_level, options.devices, action == 'r'); + rc = pcmk__fence_register_level(st, target, options.fence_level, options.devices); break; + case 'M': - rc = show_metadata(out, st, options.agent, options.timeout); + rc = pcmk__fence_metadata(out, st, options.agent, options.timeout); + if (rc != 0) { + out->err(out, "Can't get fence agent meta-data: %s", pcmk_strerror(rc)); + } + break; + case 'C': rc = st->cmds->confirm(st, st_opts, target); break; + case 'B': - rc = mainloop_fencing(st, target, "reboot", options.timeout, options.tolerance); + rc = pcmk__fence_action(st, target, "reboot", name, options.timeout, + options.tolerance); break; + case 'F': - rc = mainloop_fencing(st, target, "off", options.timeout, options.tolerance); + rc = pcmk__fence_action(st, target, "off", name, options.timeout, + options.tolerance); break; + case 'U': - rc = mainloop_fencing(st, target, "on", options.timeout, options.tolerance); + rc = pcmk__fence_action(st, target, "on", name, options.timeout, + options.tolerance); break; + case 'h': - show_last_fenced(out, target); + rc = pcmk__fence_last(out, target, options.as_nodeid); break; + case 'H': - rc = handle_history(st, target, options.timeout, args->quiet, - args->verbosity, options.cleanup, - options.broadcast, out); + rc = pcmk__fence_history(out, st, target, options.timeout, args->quiet, + args->verbosity, options.broadcast, options.cleanup); break; + case 'K': - device = (options.devices ? options.devices->key : NULL); - rc = validate(st, options.agent, device, options.params, - options.timeout, args->quiet, out); + device = options.devices ? options.devices->key : NULL; + rc = pcmk__fence_validate(out, st, options.agent, device, options.params, + options.timeout); break; } crm_info("Command returned: %s (%d)", pcmk_strerror(rc), rc); exit_code = crm_errno2exit(rc); done: g_strfreev(processed_args); g_clear_error(&error); pcmk__free_arg_context(context); if (out != NULL) { out->finish(out, exit_code, true, NULL); pcmk__output_free(out); } - free(async_fence_data.name); + free(name); stonith_key_value_freeall(options.params, 1, 1); if (st != NULL) { st->cmds->disconnect(st); stonith_api_delete(st); } return exit_code; }