root/tools/stonith_admin.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. add_env_params
  2. add_stonith_device
  3. add_tolerance
  4. add_stonith_params
  5. set_tag
  6. build_arg_context
  7. request_fencing
  8. main

   1 /*
   2  * Copyright 2009-2024 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <sys/param.h>
  13 #include <stdio.h>
  14 #include <sys/types.h>
  15 #include <sys/stat.h>
  16 #include <unistd.h>
  17 #include <sys/utsname.h>
  18 
  19 #include <errno.h>
  20 #include <fcntl.h>
  21 #include <stdbool.h>
  22 #include <stdlib.h>
  23 #include <string.h>
  24 
  25 #include <crm/crm.h>
  26 #include <crm/common/ipc.h>
  27 #include <crm/cluster/internal.h>
  28 #include <crm/common/cmdline_internal.h>
  29 #include <crm/common/output_internal.h>
  30 
  31 #include <crm/stonith-ng.h>
  32 #include <crm/fencing/internal.h>   // stonith__register_messages()
  33 #include <crm/cib.h>
  34 #include <crm/pengine/status.h>
  35 
  36 #include <crm/common/xml.h>
  37 #include <pacemaker-internal.h>
  38 
  39 #define SUMMARY "stonith_admin - Access the Pacemaker fencing API"
  40 
  41 char action = 0;
  42 
  43 struct {
  44     gboolean as_nodeid;
  45     gboolean broadcast;
  46     gboolean cleanup;
  47     gboolean installed;
  48     gboolean metadata;
  49     gboolean registered;
  50     gboolean validate_cfg;
  51     GList *devices;
  52     GHashTable *params;
  53     int fence_level;
  54     int timeout ;
  55     long long tolerance_ms;
  56     int delay;
  57     char *agent;
  58     char *confirm_host;
  59     char *fence_host;
  60     char *history;
  61     char *last_fenced;
  62     char *query;
  63     char *reboot_host;
  64     char *register_dev;
  65     char *register_level;
  66     char *targets;
  67     char *terminate;
  68     char *unfence_host;
  69     char *unregister_dev;
  70     char *unregister_level;
  71 } options = {
  72     .timeout = 120,
  73     .delay = 0
  74 };
  75 
  76 gboolean add_env_params(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
  77 gboolean add_stonith_device(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
  78 gboolean add_stonith_params(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
  79 gboolean add_tolerance(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
  80 gboolean set_tag(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
  81 
  82 #define INDENT "                                    "
  83 
  84 /* *INDENT-OFF* */
  85 static GOptionEntry defn_entries[] = {
  86     { "register", 'R', 0, G_OPTION_ARG_STRING, &options.register_dev,
  87       "Register the named stonith device. Requires: --agent.\n"
  88       INDENT "Optional: --option, --env-option.",
  89       "DEVICE" },
  90     { "deregister", 'D', 0, G_OPTION_ARG_STRING, &options.unregister_dev,
  91       "De-register the named stonith device.",
  92       "DEVICE" },
  93     { "register-level", 'r', 0, G_OPTION_ARG_STRING, &options.register_level,
  94       "Register a stonith level for the named target,\n"
  95       INDENT "specified as one of NAME, @PATTERN, or ATTR=VALUE.\n"
  96       INDENT "Requires: --index and one or more --device entries.",
  97       "TARGET" },
  98     { "deregister-level", 'd', 0, G_OPTION_ARG_STRING, &options.unregister_level,
  99       "Unregister a stonith level for the named target,\n"
 100       INDENT "specified as for --register-level. Requires: --index",
 101       "TARGET" },
 102 
 103     { NULL }
 104 };
 105 
 106 static GOptionEntry query_entries[] = {
 107     { "list", 'l', 0, G_OPTION_ARG_STRING, &options.terminate,
 108       "List devices that can terminate the specified host.\n"
 109       INDENT "Optional: --timeout",
 110       "HOST" },
 111     { "list-registered", 'L', 0, G_OPTION_ARG_NONE, &options.registered,
 112       "List all registered devices. Optional: --timeout.",
 113       NULL },
 114     { "list-installed", 'I', 0, G_OPTION_ARG_NONE, &options.installed,
 115       "List all installed devices. Optional: --timeout.",
 116       NULL },
 117     { "list-targets", 's', 0, G_OPTION_ARG_STRING, &options.targets,
 118       "List the targets that can be fenced by the\n"
 119       INDENT "named device. Optional: --timeout.",
 120       "DEVICE" },
 121     { "metadata", 'M', 0, G_OPTION_ARG_NONE, &options.metadata,
 122       "Show agent metadata. Requires: --agent.\n"
 123       INDENT "Optional: --timeout.",
 124       NULL },
 125     { "query", 'Q', 0, G_OPTION_ARG_STRING, &options.query,
 126       "Check the named device's status. Optional: --timeout.",
 127       "DEVICE" },
 128     { "history", 'H', 0, G_OPTION_ARG_STRING, &options.history,
 129       "Show last successful fencing operation for named node\n"
 130       INDENT "(or '*' for all nodes). Optional: --timeout, --cleanup,\n"
 131       INDENT "--quiet (show only the operation's epoch timestamp),\n"
 132       INDENT "--verbose (show all recorded and pending operations),\n"
 133       INDENT "--broadcast (update history from all nodes available).",
 134       "NODE" },
 135     { "last", 'h', 0, G_OPTION_ARG_STRING, &options.last_fenced,
 136       "Indicate when the named node was last fenced.\n"
 137       INDENT "Optional: --as-node-id.",
 138       "NODE" },
 139     { "validate", 'K', 0, G_OPTION_ARG_NONE, &options.validate_cfg,
 140       "Validate a fence device configuration.\n"
 141       INDENT "Requires: --agent. Optional: --option, --env-option,\n"
 142       INDENT "--quiet (print no output, only return status).",
 143       NULL },
 144 
 145     { NULL }
 146 };
 147 
 148 static GOptionEntry fence_entries[] = {
 149     { "fence", 'F', 0, G_OPTION_ARG_STRING, &options.fence_host,
 150       "Fence named host. Optional: --timeout, --tolerance, --delay.",
 151       "HOST" },
 152     { "unfence", 'U', 0, G_OPTION_ARG_STRING, &options.unfence_host,
 153       "Unfence named host. Optional: --timeout, --tolerance, --delay.",
 154       "HOST" },
 155     { "reboot", 'B', 0, G_OPTION_ARG_STRING, &options.reboot_host,
 156       "Reboot named host. Optional: --timeout, --tolerance, --delay.",
 157       "HOST" },
 158     { "confirm", 'C', 0, G_OPTION_ARG_STRING, &options.confirm_host,
 159       "Tell cluster that named host is now safely down.",
 160       "HOST", },
 161 
 162     { NULL }
 163 };
 164 
 165 static GOptionEntry addl_entries[] = {
 166     { "cleanup", 'c', 0, G_OPTION_ARG_NONE, &options.cleanup,
 167       "Cleanup wherever appropriate. Requires --history.",
 168       NULL },
 169     { "broadcast", 'b', 0, G_OPTION_ARG_NONE, &options.broadcast,
 170       "Broadcast wherever appropriate.",
 171       NULL },
 172     { "agent", 'a', 0, G_OPTION_ARG_STRING, &options.agent,
 173       "The agent to use (for example, fence_xvm;\n"
 174       INDENT "with --register, --metadata, --validate).",
 175       "AGENT" },
 176     { "option", 'o', 0, G_OPTION_ARG_CALLBACK, add_stonith_params,
 177       "Specify a device configuration parameter as NAME=VALUE\n"
 178       INDENT "(may be specified multiple times; with --register,\n"
 179       INDENT "--validate).",
 180       "PARAM" },
 181     { "env-option", 'e', 0, G_OPTION_ARG_CALLBACK, add_env_params,
 182       "Specify a device configuration parameter with the\n"
 183       INDENT "specified name, using the value of the\n"
 184       INDENT "environment variable of the same name prefixed with\n"
 185       INDENT "OCF_RESKEY_ (may be specified multiple times;\n"
 186       INDENT "with --register, --validate).",
 187       "PARAM" },
 188     { "tag", 'T', 0, G_OPTION_ARG_CALLBACK, set_tag,
 189       "Identify fencing operations in logs with the specified\n"
 190       INDENT "tag; useful when multiple entities might invoke\n"
 191       INDENT "stonith_admin (used with most commands).",
 192       "TAG" },
 193     { "device", 'v', 0, G_OPTION_ARG_CALLBACK, add_stonith_device,
 194       "Device ID (with --register-level, device to associate with\n"
 195       INDENT "a given host and level; may be specified multiple times)"
 196 #if PCMK__ENABLE_CIBSECRETS
 197       "\n" INDENT "(with --validate, name to use to load CIB secrets)"
 198 #endif
 199       ".",
 200       "DEVICE" },
 201     { "index", 'i', 0, G_OPTION_ARG_INT, &options.fence_level,
 202       "The stonith level (1-9) (with --register-level,\n"
 203       INDENT "--deregister-level).",
 204       "LEVEL" },
 205     { "timeout", 't', 0, G_OPTION_ARG_INT, &options.timeout,
 206       "Operation timeout in seconds (default 120;\n"
 207       INDENT "used with most commands).",
 208       "SECONDS" },
 209     { "delay", 'y', 0, G_OPTION_ARG_INT, &options.delay,
 210       "Apply a fencing delay in seconds. Any static/random delays from\n"
 211       INDENT "pcmk_delay_base/max will be added, otherwise all\n"
 212       INDENT "disabled with the value -1\n"
 213       INDENT "(default 0; with --fence, --reboot, --unfence).",
 214       "SECONDS" },
 215     { "as-node-id", 'n', 0, G_OPTION_ARG_NONE, &options.as_nodeid,
 216       "(Advanced) The supplied node is the corosync node ID\n"
 217       INDENT "(with --last).",
 218       NULL },
 219     { "tolerance", 0, 0, G_OPTION_ARG_CALLBACK, add_tolerance,
 220       "(Advanced) Do nothing if an equivalent --fence request\n"
 221       INDENT "succeeded less than this many seconds earlier\n"
 222       INDENT "(with --fence, --unfence, --reboot).",
 223       "SECONDS" },
 224 
 225     { NULL }
 226 };
 227 /* *INDENT-ON* */
 228 
 229 static pcmk__supported_format_t formats[] = {
 230     PCMK__SUPPORTED_FORMAT_HTML,
 231     PCMK__SUPPORTED_FORMAT_NONE,
 232     PCMK__SUPPORTED_FORMAT_TEXT,
 233     PCMK__SUPPORTED_FORMAT_XML,
 234     { NULL, NULL, NULL }
 235 };
 236 
 237 static const int st_opts = st_opt_sync_call|st_opt_allow_self_fencing;
 238 
 239 static char *name = NULL;
 240 
 241 gboolean
 242 add_env_params(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 243     char *key = crm_strdup_printf("OCF_RESKEY_%s", optarg);
 244     const char *env = getenv(key);
 245     gboolean retval = TRUE;
 246 
 247     if (env == NULL) {
 248         g_set_error(error, PCMK__EXITC_ERROR, CRM_EX_INVALID_PARAM, "Invalid option: -e %s", optarg);
 249         retval = FALSE;
 250     } else {
 251         crm_info("Got: '%s'='%s'", optarg, env);
 252 
 253         if (options.params != NULL) {
 254             options.params = pcmk__strkey_table(free, free);
 255         }
 256 
 257         pcmk__insert_dup(options.params, optarg, env);
 258     }
 259 
 260     free(key);
 261     return retval;
 262 }
 263 
 264 gboolean
 265 add_stonith_device(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 266     options.devices = g_list_append(options.devices, pcmk__str_copy(optarg));
 267     return TRUE;
 268 }
 269 
 270 gboolean
 271 add_tolerance(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 272     // pcmk__request_fencing() expects an unsigned int
 273     options.tolerance_ms = crm_get_msec(optarg);
 274 
 275     if (options.tolerance_ms < 0) {
 276         crm_warn("Ignoring invalid tolerance '%s'", optarg);
 277         options.tolerance_ms = 0;
 278     } else {
 279         options.tolerance_ms = QB_MIN(options.tolerance_ms, UINT_MAX);
 280     }
 281     return TRUE;
 282 }
 283 
 284 gboolean
 285 add_stonith_params(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 286     char *name = NULL;
 287     char *value = NULL;
 288     int rc = 0;
 289     gboolean retval = TRUE;
 290 
 291     crm_info("Scanning: -o %s", optarg);
 292 
 293     rc = pcmk__scan_nvpair(optarg, &name, &value);
 294 
 295     if (rc != 2) {
 296         rc = pcmk_legacy2rc(rc);
 297         g_set_error(error, PCMK__RC_ERROR, rc, "Invalid option: -o %s: %s", optarg, pcmk_rc_str(rc));
 298         retval = FALSE;
 299     } else {
 300         crm_info("Got: '%s'='%s'", name, value);
 301 
 302         if (options.params == NULL) {
 303             options.params = pcmk__strkey_table(free, free);
 304         }
 305 
 306         pcmk__insert_dup(options.params, name, value);
 307     }
 308 
 309     free(name);
 310     free(value);
 311     return retval;
 312 }
 313 
 314 gboolean
 315 set_tag(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 316     free(name);
 317     name = crm_strdup_printf("%s.%s", crm_system_name, optarg);
 318     return TRUE;
 319 }
 320 
 321 static GOptionContext *
 322 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
     /* [previous][next][first][last][top][bottom][index][help] */
 323     GOptionContext *context = NULL;
 324 
 325     GOptionEntry extra_prog_entries[] = {
 326         { "quiet", 'q', 0, G_OPTION_ARG_NONE, &(args->quiet),
 327           "Be less descriptive in output.",
 328           NULL },
 329 
 330         { NULL }
 331     };
 332 
 333     context = pcmk__build_arg_context(args, "text (default), html, xml", group, NULL);
 334 
 335     /* Add the -q option, which cannot be part of the globally supported options
 336      * because some tools use that flag for something else.
 337      */
 338     pcmk__add_main_args(context, extra_prog_entries);
 339 
 340     pcmk__add_arg_group(context, "definition", "Device Definition Commands:",
 341                         "Show device definition help", defn_entries);
 342     pcmk__add_arg_group(context, "queries", "Queries:",
 343                         "Show query help", query_entries);
 344     pcmk__add_arg_group(context, "fence", "Fencing Commands:",
 345                         "Show fence help", fence_entries);
 346     pcmk__add_arg_group(context, "additional", "Additional Options:",
 347                         "Show additional options", addl_entries);
 348     return context;
 349 }
 350 
 351 // \return Standard Pacemaker return code
 352 static int
 353 request_fencing(stonith_t *st, const char *target, const char *command,
     /* [previous][next][first][last][top][bottom][index][help] */
 354                 GError **error)
 355 {
 356     char *reason = NULL;
 357     int rc = pcmk__request_fencing(st, target, command, name,
 358                                    options.timeout * 1000,
 359                                    options.tolerance_ms, options.delay,
 360                                    &reason);
 361 
 362     if (rc != pcmk_rc_ok) {
 363         const char *rc_str = pcmk_rc_str(rc);
 364         const char *what = "fence";
 365 
 366         if (strcmp(command, PCMK_ACTION_ON) == 0) {
 367             what = "unfence";
 368         }
 369 
 370         // If reason is identical to return code string, don't display it twice
 371         if (pcmk__str_eq(rc_str, reason, pcmk__str_none)) {
 372             free(reason);
 373             reason = NULL;
 374         }
 375 
 376         g_set_error(error, PCMK__RC_ERROR, rc,
 377                     "Couldn't %s %s: %s%s%s%s",
 378                     what, target, rc_str,
 379                     ((reason == NULL)? "" : " ("),
 380                     ((reason == NULL)? "" : reason),
 381                     ((reason == NULL)? "" : ")"));
 382     }
 383     free(reason);
 384     return rc;
 385 }
 386 
 387 int
 388 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 389 {
 390     int rc = 0;
 391     crm_exit_t exit_code = CRM_EX_OK;
 392     bool no_connect = false;
 393     bool required_agent = false;
 394 
 395     char *target = NULL;
 396     const char *device = NULL;
 397     stonith_t *st = NULL;
 398 
 399     GError *error = NULL;
 400 
 401     pcmk__output_t *out = NULL;
 402 
 403     GOptionGroup *output_group = NULL;
 404     pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
 405     gchar **processed_args = pcmk__cmdline_preproc(argv, "adehilorstvyBCDFHQRTU");
 406     GOptionContext *context = build_arg_context(args, &output_group);
 407 
 408     pcmk__register_formats(output_group, formats);
 409     if (!g_option_context_parse_strv(context, &processed_args, &error)) {
 410         exit_code = CRM_EX_USAGE;
 411         goto done;
 412     }
 413 
 414     pcmk__cli_init_logging("stonith_admin", args->verbosity);
 415 
 416     if (name == NULL) {
 417         name = strdup(crm_system_name);
 418     }
 419 
 420     rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
 421     if (rc != pcmk_rc_ok) {
 422         exit_code = CRM_EX_ERROR;
 423         g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Error creating output format %s: %s",
 424                     args->output_ty, pcmk_rc_str(rc));
 425         goto done;
 426     }
 427 
 428     pcmk__output_enable_list_element(out);
 429 
 430     stonith__register_messages(out);
 431 
 432     if (args->version) {
 433         out->version(out, false);
 434         goto done;
 435     }
 436 
 437     if (options.validate_cfg) {
 438         required_agent = true;
 439         no_connect = true;
 440         action = 'K';
 441     }
 442 
 443     if (options.installed) {
 444         no_connect = true;
 445         action = 'I';
 446     }
 447 
 448     if (options.registered) {
 449         action = 'L';
 450     }
 451 
 452     if (options.register_dev != NULL) {
 453         required_agent = true;
 454         action = 'R';
 455         device = options.register_dev;
 456     }
 457 
 458     if (options.query != NULL) {
 459         action = 'Q';
 460         device = options.query;
 461     }
 462 
 463     if (options.unregister_dev != NULL) {
 464         action = 'D';
 465         device = options.unregister_dev;
 466     }
 467 
 468     if (options.targets != NULL) {
 469         action = 's';
 470         device = options.targets;
 471     }
 472 
 473     if (options.terminate != NULL) {
 474         action = 'L';
 475         target = options.terminate;
 476     }
 477 
 478     if (options.metadata) {
 479         no_connect = true;
 480         required_agent = true;
 481         action = 'M';
 482     }
 483 
 484     if (options.reboot_host != NULL) {
 485         no_connect = true;
 486         action = 'B';
 487         target = options.reboot_host;
 488         crm_log_args(argc, argv);
 489     }
 490 
 491     if (options.fence_host != NULL) {
 492         no_connect = true;
 493         action = 'F';
 494         target = options.fence_host;
 495         crm_log_args(argc, argv);
 496     }
 497 
 498     if (options.unfence_host != NULL) {
 499         no_connect = true;
 500         action = 'U';
 501         target = options.unfence_host;
 502         crm_log_args(argc, argv);
 503     }
 504 
 505     if (options.confirm_host != NULL) {
 506         action = 'C';
 507         target = options.confirm_host;
 508         crm_log_args(argc, argv);
 509     }
 510 
 511     if (options.last_fenced != NULL) {
 512         action = 'h';
 513         target = options.last_fenced;
 514     }
 515 
 516     if (options.history != NULL) {
 517         action = 'H';
 518         target = options.history;
 519     }
 520 
 521     if (options.register_level != NULL) {
 522         action = 'r';
 523         target = options.register_level;
 524     }
 525 
 526     if (options.unregister_level != NULL) {
 527         action = 'd';
 528         target = options.unregister_level;
 529     }
 530 
 531     if ((options.timeout > (UINT_MAX / 1000)) || (options.timeout < 0)) {
 532         out->err(out, "Integer value \"%d\" for -t out of range", options.timeout);
 533         exit_code = CRM_EX_USAGE;
 534         goto done;
 535     }
 536 
 537     if (action == 0) {
 538         char *help = g_option_context_get_help(context, TRUE, NULL);
 539 
 540         out->err(out, "%s", help);
 541         g_free(help);
 542         exit_code = CRM_EX_USAGE;
 543         goto done;
 544     }
 545 
 546     if (required_agent && options.agent == NULL) {
 547         char *help = g_option_context_get_help(context, TRUE, NULL);
 548 
 549         out->err(out, "Please specify an agent to query using -a,--agent [value]");
 550         out->err(out, "%s", help);
 551         g_free(help);
 552         exit_code = CRM_EX_USAGE;
 553         goto done;
 554     }
 555 
 556     out->quiet = args->quiet;
 557 
 558     st = stonith_api_new();
 559     if (st == NULL) {
 560         rc = -ENOMEM;
 561     } else if (!no_connect) {
 562         rc = st->cmds->connect(st, name, NULL);
 563     }
 564     if (rc < 0) {
 565         out->err(out, "Could not connect to fencer: %s", pcmk_strerror(rc));
 566         exit_code = CRM_EX_DISCONNECT;
 567         goto done;
 568     }
 569 
 570     switch (action) {
 571         case 'I':
 572             rc = pcmk__fence_installed(out, st, options.timeout*1000);
 573             if (rc != pcmk_rc_ok) {
 574                 out->err(out, "Failed to list installed devices: %s", pcmk_rc_str(rc));
 575             }
 576 
 577             break;
 578 
 579         case 'L':
 580             rc = pcmk__fence_registered(out, st, target, options.timeout*1000);
 581             if (rc != pcmk_rc_ok) {
 582                 out->err(out, "Failed to list registered devices: %s", pcmk_rc_str(rc));
 583             }
 584 
 585             break;
 586 
 587         case 'Q':
 588             rc = st->cmds->monitor(st, st_opts, device, options.timeout);
 589             if (rc != pcmk_rc_ok) {
 590                 rc = st->cmds->list(st, st_opts, device, NULL, options.timeout);
 591             }
 592             rc = pcmk_legacy2rc(rc);
 593             break;
 594 
 595         case 's':
 596             rc = pcmk__fence_list_targets(out, st, device, options.timeout*1000);
 597             if (rc != pcmk_rc_ok) {
 598                 out->err(out, "Couldn't list targets: %s", pcmk_rc_str(rc));
 599             }
 600 
 601             break;
 602 
 603         case 'R': {
 604             /* register_device wants a stonith_key_value_t instead of a GHashTable */
 605             stonith_key_value_t *params = NULL;
 606             GHashTableIter iter;
 607             gpointer key, val;
 608 
 609             if (options.params != NULL) {
 610                 g_hash_table_iter_init(&iter, options.params);
 611                 while (g_hash_table_iter_next(&iter, &key, &val)) {
 612                     params = stonith_key_value_add(params, key, val);
 613                 }
 614             }
 615             rc = st->cmds->register_device(st, st_opts, device, NULL, options.agent,
 616                                            params);
 617             stonith_key_value_freeall(params, 1, 1);
 618 
 619             rc = pcmk_legacy2rc(rc);
 620             if (rc != pcmk_rc_ok) {
 621                 out->err(out, "Can't register device %s using agent %s: %s",
 622                          device, options.agent, pcmk_rc_str(rc));
 623             }
 624             break;
 625         }
 626 
 627         case 'D':
 628             rc = st->cmds->remove_device(st, st_opts, device);
 629             rc = pcmk_legacy2rc(rc);
 630             if (rc != pcmk_rc_ok) {
 631                 out->err(out, "Can't unregister device %s: %s",
 632                          device, pcmk_rc_str(rc));
 633             }
 634             break;
 635 
 636         case 'd':
 637             rc = pcmk__fence_unregister_level(st, target, options.fence_level);
 638             if (rc != pcmk_rc_ok) {
 639                 out->err(out, "Can't unregister topology level %d for %s: %s",
 640                          options.fence_level, target, pcmk_rc_str(rc));
 641             }
 642             break;
 643 
 644         case 'r':
 645             rc = pcmk__fence_register_level(st, target, options.fence_level, options.devices);
 646             if (rc != pcmk_rc_ok) {
 647                 out->err(out, "Can't register topology level %d for %s: %s",
 648                          options.fence_level, target, pcmk_rc_str(rc));
 649             }
 650             break;
 651 
 652         case 'M':
 653             rc = pcmk__fence_metadata(out, st, options.agent, options.timeout*1000);
 654             if (rc != pcmk_rc_ok) {
 655                 out->err(out, "Can't get fence agent meta-data: %s",
 656                          pcmk_rc_str(rc));
 657             }
 658 
 659             break;
 660 
 661         case 'C':
 662             rc = st->cmds->confirm(st, st_opts, target);
 663             rc = pcmk_legacy2rc(rc);
 664             break;
 665 
 666         case 'B':
 667             rc = request_fencing(st, target, PCMK_ACTION_REBOOT, &error);
 668             break;
 669 
 670         case 'F':
 671             rc = request_fencing(st, target, PCMK_ACTION_OFF, &error);
 672             break;
 673 
 674         case 'U':
 675             rc = request_fencing(st, target, PCMK_ACTION_ON, &error);
 676             break;
 677 
 678         case 'h':
 679             rc = pcmk__fence_last(out, target, options.as_nodeid);
 680             break;
 681 
 682         case 'H':
 683             rc = pcmk__fence_history(out, st, target, options.timeout*1000, args->verbosity,
 684                                      options.broadcast, options.cleanup);
 685             break;
 686 
 687         case 'K':
 688             device = NULL;
 689             if (options.devices != NULL) {
 690                 device = g_list_nth_data(options.devices, 0);
 691             }
 692 
 693             rc = pcmk__fence_validate(out, st, options.agent, device, options.params,
 694                                         options.timeout*1000);
 695             break;
 696     }
 697 
 698     crm_info("Command returned: %s (%d)", pcmk_rc_str(rc), rc);
 699     exit_code = pcmk_rc2exitc(rc);
 700 
 701   done:
 702     g_strfreev(processed_args);
 703     pcmk__free_arg_context(context);
 704 
 705     pcmk__output_and_clear_error(&error, out);
 706 
 707     if (out != NULL) {
 708         out->finish(out, exit_code, true, NULL);
 709         pcmk__output_free(out);
 710     }
 711     pcmk__unregister_formats();
 712     free(name);
 713     g_list_free_full(options.devices, free);
 714 
 715     if (options.params != NULL) {
 716         g_hash_table_destroy(options.params);
 717     }
 718 
 719     if (st != NULL) {
 720         st->cmds->disconnect(st);
 721         stonith_api_delete(st);
 722     }
 723 
 724     return exit_code;
 725 }

/* [previous][next][first][last][top][bottom][index][help] */