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

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