root/tools/crm_resource.c

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

DEFINITIONS

This source file includes following definitions.
  1. bye
  2. quit_main_loop
  3. resource_ipc_timeout
  4. controller_event_callback
  5. start_mainloop
  6. compare_id
  7. build_constraint_list
  8. agent_provider_cb
  9. attr_set_type_cb
  10. class_cb
  11. cleanup_refresh_cb
  12. delete_cb
  13. expired_cb
  14. get_agent_spec
  15. list_agents_cb
  16. list_providers_cb
  17. list_standards_cb
  18. list_alternatives_cb
  19. metadata_cb
  20. option_cb
  21. fail_cb
  22. flag_cb
  23. get_param_prop_cb
  24. list_cb
  25. set_delete_param_cb
  26. set_prop_cb
  27. timeout_cb
  28. validate_or_force_cb
  29. restart_cb
  30. digests_cb
  31. wait_cb
  32. why_cb
  33. ban_or_move
  34. cleanup
  35. clear_constraints
  36. delete
  37. list_agents
  38. list_providers
  39. populate_working_set
  40. refresh
  41. refresh_resource
  42. set_property
  43. show_metadata
  44. validate_cmdline_config
  45. build_arg_context
  46. main

   1 /*
   2  * Copyright 2004-2021 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 <crm_resource.h>
  13 #include <crm/lrmd_internal.h>
  14 #include <crm/common/cmdline_internal.h>
  15 #include <crm/common/lists_internal.h>
  16 #include <crm/common/output.h>
  17 #include <pacemaker-internal.h>
  18 
  19 #include <sys/param.h>
  20 #include <stdio.h>
  21 #include <sys/types.h>
  22 #include <unistd.h>
  23 #include <stdlib.h>
  24 #include <errno.h>
  25 #include <fcntl.h>
  26 #include <libgen.h>
  27 #include <time.h>
  28 
  29 #include <crm/crm.h>
  30 #include <crm/stonith-ng.h>
  31 #include <crm/common/ipc_controld.h>
  32 #include <crm/cib/internal.h>
  33 
  34 #define SUMMARY "crm_resource - perform tasks related to Pacemaker cluster resources"
  35 
  36 enum rsc_command {
  37     cmd_none = 0,           // No command option given (yet)
  38     cmd_ban,
  39     cmd_cleanup,
  40     cmd_clear,
  41     cmd_colocations,
  42     cmd_colocations_deep,
  43     cmd_cts,
  44     cmd_delete,
  45     cmd_delete_param,
  46     cmd_digests,
  47     cmd_execute_agent,
  48     cmd_fail,
  49     cmd_get_param,
  50     cmd_get_property,
  51     cmd_list_active_ops,
  52     cmd_list_agents,
  53     cmd_list_all_ops,
  54     cmd_list_alternatives,
  55     cmd_list_instances,
  56     cmd_list_providers,
  57     cmd_list_resources,
  58     cmd_list_standards,
  59     cmd_locate,
  60     cmd_metadata,
  61     cmd_move,
  62     cmd_query_raw_xml,
  63     cmd_query_xml,
  64     cmd_refresh,
  65     cmd_restart,
  66     cmd_set_param,
  67     cmd_set_property,
  68     cmd_wait,
  69     cmd_why,
  70 };
  71 
  72 struct {
  73     enum rsc_command rsc_cmd;     // crm_resource command to perform
  74 
  75     // Infrastructure that given command needs to work
  76     gboolean require_cib;         // Whether command requires CIB IPC
  77     int cib_options;              // Options to use with CIB IPC calls
  78     gboolean require_crmd;        // Whether command requires controller IPC
  79     gboolean require_dataset;     // Whether command requires populated data set
  80     gboolean require_resource;    // Whether command requires resource specified
  81     gboolean require_node;        // Whether command requires node specified
  82     int find_flags;               // Flags to use when searching for resource
  83 
  84     // Command-line option values
  85     gchar *rsc_id;                // Value of --resource
  86     gchar *rsc_type;              // Value of --resource-type
  87     gboolean force;               // --force was given
  88     gboolean clear_expired;       // --expired was given
  89     gboolean recursive;           // --recursive was given
  90     gboolean promoted_role_only;  // --promoted was given
  91     gchar *host_uname;            // Value of --node
  92     gchar *interval_spec;         // Value of --interval
  93     gchar *move_lifetime;         // Value of --lifetime
  94     gchar *operation;             // Value of --operation
  95     const char *attr_set_type;    // Instance, meta, or utilization attribute
  96     gchar *prop_id;               // --nvpair (attribute XML ID)
  97     char *prop_name;              // Attribute name
  98     gchar *prop_set;              // --set-name (attribute block XML ID)
  99     gchar *prop_value;            // --parameter-value (attribute value)
 100     int timeout_ms;               // Parsed from --timeout value
 101     char *agent_spec;             // Standard and/or provider and/or agent
 102     gchar *xml_file;              // Value of (deprecated) --xml-file
 103     int check_level;              // Optional value of --validate or --force-check
 104 
 105     // Resource configuration specified via command-line arguments
 106     gboolean cmdline_config;      // Resource configuration was via arguments
 107     char *v_agent;                // Value of --agent
 108     char *v_class;                // Value of --class
 109     char *v_provider;             // Value of --provider
 110     GHashTable *cmdline_params;   // Resource parameters specified
 111 
 112     // Positional command-line arguments
 113     gchar **remainder;            // Positional arguments as given
 114     GHashTable *override_params;  // Resource parameter values that override config
 115 } options = {
 116     .attr_set_type = XML_TAG_ATTR_SETS,
 117     .check_level = -1,
 118     .cib_options = cib_sync_call,
 119     .require_cib = TRUE,
 120     .require_dataset = TRUE,
 121     .require_resource = TRUE,
 122 };
 123 
 124 #if 0
 125 // @COMPAT @TODO enable this at next backward compatibility break
 126 #define SET_COMMAND(cmd) do {                                               \
 127         if (options.rsc_cmd != cmd_none) {                                  \
 128             g_set_error(error, PCMK__EXITC_ERROR, CRM_EX_USAGE,             \
 129                         "Only one command option may be specified");        \
 130             return FALSE;                                                   \
 131         }                                                                   \
 132         options.rsc_cmd = (cmd);                                            \
 133     } while (0)
 134 #else
 135 #define SET_COMMAND(cmd) do { options.rsc_cmd = (cmd); } while (0)
 136 #endif
 137 
 138 gboolean agent_provider_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
 139 gboolean attr_set_type_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
 140 gboolean class_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
 141 gboolean cleanup_refresh_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
 142 gboolean delete_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
 143 gboolean expired_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
 144 gboolean list_agents_cb(const gchar *option_name, const gchar *optarg,
 145                         gpointer data, GError **error);
 146 gboolean list_providers_cb(const gchar *option_name, const gchar *optarg,
 147                            gpointer data, GError **error);
 148 gboolean list_standards_cb(const gchar *option_name, const gchar *optarg,
 149                            gpointer data, GError **error);
 150 gboolean list_alternatives_cb(const gchar *option_name, const gchar *optarg,
 151                               gpointer data, GError **error);
 152 gboolean metadata_cb(const gchar *option_name, const gchar *optarg,
 153                      gpointer data, GError **error);
 154 gboolean option_cb(const gchar *option_name, const gchar *optarg,
 155                    gpointer data, GError **error);
 156 gboolean fail_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
 157 gboolean flag_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
 158 gboolean get_param_prop_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
 159 gboolean list_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
 160 gboolean set_delete_param_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
 161 gboolean set_prop_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
 162 gboolean timeout_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
 163 gboolean validate_or_force_cb(const gchar *option_name, const gchar *optarg,
 164                               gpointer data, GError **error);
 165 gboolean restart_cb(const gchar *option_name, const gchar *optarg,
 166                     gpointer data, GError **error);
 167 gboolean digests_cb(const gchar *option_name, const gchar *optarg,
 168                     gpointer data, GError **error);
 169 gboolean wait_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
 170 gboolean why_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
 171 
 172 static crm_exit_t exit_code = CRM_EX_OK;
 173 static pcmk__output_t *out = NULL;
 174 static pcmk__common_args_t *args = NULL;
 175 
 176 // Things that should be cleaned up on exit
 177 static GError *error = NULL;
 178 static GMainLoop *mainloop = NULL;
 179 static cib_t *cib_conn = NULL;
 180 static pcmk_ipc_api_t *controld_api = NULL;
 181 static pe_working_set_t *data_set = NULL;
 182 
 183 #define MESSAGE_TIMEOUT_S 60
 184 
 185 #define INDENT "                                    "
 186 
 187 static pcmk__supported_format_t formats[] = {
 188     PCMK__SUPPORTED_FORMAT_NONE,
 189     PCMK__SUPPORTED_FORMAT_TEXT,
 190     PCMK__SUPPORTED_FORMAT_XML,
 191     { NULL, NULL, NULL }
 192 };
 193 
 194 // Clean up and exit
 195 static crm_exit_t
 196 bye(crm_exit_t ec)
     /* [previous][next][first][last][top][bottom][index][help] */
 197 {
 198     pcmk__output_and_clear_error(error, out);
 199 
 200     if (out != NULL) {
 201         out->finish(out, ec, true, NULL);
 202         pcmk__output_free(out);
 203     }
 204 
 205     if (cib_conn != NULL) {
 206         cib_t *save_cib_conn = cib_conn;
 207 
 208         cib_conn = NULL; // Ensure we can't free this twice
 209         save_cib_conn->cmds->signoff(save_cib_conn);
 210         cib_delete(save_cib_conn);
 211     }
 212     if (controld_api != NULL) {
 213         pcmk_ipc_api_t *save_controld_api = controld_api;
 214 
 215         controld_api = NULL; // Ensure we can't free this twice
 216         pcmk_free_ipc_api(save_controld_api);
 217     }
 218     if (mainloop != NULL) {
 219         g_main_loop_unref(mainloop);
 220         mainloop = NULL;
 221     }
 222     pe_free_working_set(data_set);
 223     data_set = NULL;
 224     crm_exit(ec);
 225     return ec;
 226 }
 227 
 228 static void
 229 quit_main_loop(crm_exit_t ec)
     /* [previous][next][first][last][top][bottom][index][help] */
 230 {
 231     exit_code = ec;
 232     if (mainloop != NULL) {
 233         GMainLoop *mloop = mainloop;
 234 
 235         mainloop = NULL; // Don't re-enter this block
 236         pcmk_quit_main_loop(mloop, 10);
 237         g_main_loop_unref(mloop);
 238     }
 239 }
 240 
 241 static gboolean
 242 resource_ipc_timeout(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 243 {
 244     // Start with newline because "Waiting for ..." message doesn't have one
 245     if (error != NULL) {
 246         g_clear_error(&error);
 247     }
 248 
 249     g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_TIMEOUT,
 250                 "Aborting because no messages received in %d seconds", MESSAGE_TIMEOUT_S);
 251 
 252     quit_main_loop(CRM_EX_TIMEOUT);
 253     return FALSE;
 254 }
 255 
 256 static void
 257 controller_event_callback(pcmk_ipc_api_t *api, enum pcmk_ipc_event event_type,
     /* [previous][next][first][last][top][bottom][index][help] */
 258                           crm_exit_t status, void *event_data, void *user_data)
 259 {
 260     switch (event_type) {
 261         case pcmk_ipc_event_disconnect:
 262             if (exit_code == CRM_EX_DISCONNECT) { // Unexpected
 263                 crm_info("Connection to controller was terminated");
 264             }
 265             quit_main_loop(exit_code);
 266             break;
 267 
 268         case pcmk_ipc_event_reply:
 269             if (status != CRM_EX_OK) {
 270                 out->err(out, "Error: bad reply from controller: %s",
 271                          crm_exit_str(status));
 272                 pcmk_disconnect_ipc(api);
 273                 quit_main_loop(status);
 274             } else {
 275                 if ((pcmk_controld_api_replies_expected(api) == 0)
 276                     && mainloop && g_main_loop_is_running(mainloop)) {
 277                     out->info(out, "... got reply (done)");
 278                     crm_debug("Got all the replies we expected");
 279                     pcmk_disconnect_ipc(api);
 280                     quit_main_loop(CRM_EX_OK);
 281                 } else {
 282                     out->info(out, "... got reply");
 283                 }
 284             }
 285             break;
 286 
 287         default:
 288             break;
 289     }
 290 }
 291 
 292 static void
 293 start_mainloop(pcmk_ipc_api_t *capi)
     /* [previous][next][first][last][top][bottom][index][help] */
 294 {
 295     unsigned int count = pcmk_controld_api_replies_expected(capi);
 296 
 297     if (count > 0) {
 298         out->info(out, "Waiting for %d %s from the controller",
 299                   count, pcmk__plural_alt(count, "reply", "replies"));
 300         exit_code = CRM_EX_DISCONNECT; // For unexpected disconnects
 301         mainloop = g_main_loop_new(NULL, FALSE);
 302         g_timeout_add(MESSAGE_TIMEOUT_S * 1000, resource_ipc_timeout, NULL);
 303         g_main_loop_run(mainloop);
 304     }
 305 }
 306 
 307 static int
 308 compare_id(gconstpointer a, gconstpointer b)
     /* [previous][next][first][last][top][bottom][index][help] */
 309 {
 310     return strcmp((const char *)a, (const char *)b);
 311 }
 312 
 313 static GList *
 314 build_constraint_list(xmlNode *root)
     /* [previous][next][first][last][top][bottom][index][help] */
 315 {
 316     GList *retval = NULL;
 317     xmlNode *cib_constraints = NULL;
 318     xmlXPathObjectPtr xpathObj = NULL;
 319     int ndx = 0;
 320 
 321     cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, root);
 322     xpathObj = xpath_search(cib_constraints, "//" XML_CONS_TAG_RSC_LOCATION);
 323 
 324     for (ndx = 0; ndx < numXpathResults(xpathObj); ndx++) {
 325         xmlNode *match = getXpathResult(xpathObj, ndx);
 326         retval = g_list_insert_sorted(retval, (gpointer) ID(match), compare_id);
 327     }
 328 
 329     freeXpathObject(xpathObj);
 330     return retval;
 331 }
 332 
 333 /* short option letters still available: eEJkKXyYZ */
 334 
 335 static GOptionEntry query_entries[] = {
 336     { "list", 'L', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, list_cb,
 337       "List all cluster resources with status",
 338       NULL },
 339     { "list-raw", 'l', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, list_cb,
 340       "List IDs of all instantiated resources (individual members\n"
 341       INDENT "rather than groups etc.)",
 342       NULL },
 343     { "list-cts", 'c', G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, list_cb,
 344       NULL,
 345       NULL },
 346     { "list-operations", 'O', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, list_cb,
 347       "List active resource operations, optionally filtered by\n"
 348       INDENT "--resource and/or --node",
 349       NULL },
 350     { "list-all-operations", 'o', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, list_cb,
 351       "List all resource operations, optionally filtered by\n"
 352       INDENT "--resource and/or --node",
 353       NULL },
 354     { "list-standards", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
 355       list_standards_cb,
 356       "List supported standards",
 357       NULL },
 358     { "list-ocf-providers", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
 359       list_providers_cb,
 360       "List all available OCF providers",
 361       NULL },
 362     { "list-agents", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK,
 363       list_agents_cb,
 364       "List all agents available for the named standard and/or provider",
 365       "STD:PROV" },
 366     { "list-ocf-alternatives", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK,
 367       list_alternatives_cb,
 368       "List all available providers for the named OCF agent",
 369       "AGENT" },
 370     { "show-metadata", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK,
 371       metadata_cb,
 372       "Show the metadata for the named class:provider:agent",
 373       "SPEC" },
 374     { "query-xml", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, flag_cb,
 375       "Show XML configuration of resource (after any template expansion)",
 376       NULL },
 377     { "query-xml-raw", 'w', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, flag_cb,
 378       "Show XML configuration of resource (before any template expansion)",
 379       NULL },
 380     { "get-parameter", 'g', G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, get_param_prop_cb,
 381       "Display named parameter for resource (use instance attribute\n"
 382       INDENT "unless --meta or --utilization is specified)",
 383       "PARAM" },
 384     { "get-property", 'G', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, get_param_prop_cb,
 385       "Display named property of resource ('class', 'type', or 'provider') "
 386       "(requires --resource)",
 387       "PROPERTY" },
 388     { "locate", 'W', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, flag_cb,
 389       "Show node(s) currently running resource",
 390       NULL },
 391     { "stack", 'A', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, flag_cb,
 392       "Display the (co)location constraints that apply to a resource\n"
 393       INDENT "and the resources is it colocated with",
 394       NULL },
 395     { "constraints", 'a', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, flag_cb,
 396       "Display the (co)location constraints that apply to a resource",
 397       NULL },
 398     { "why", 'Y', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, why_cb,
 399       "Show why resources are not running, optionally filtered by\n"
 400       INDENT "--resource and/or --node",
 401       NULL },
 402 
 403     { NULL }
 404 };
 405 
 406 static GOptionEntry command_entries[] = {
 407     { "validate", 0, G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK,
 408       validate_or_force_cb,
 409       "Validate resource configuration by calling agent's validate-all\n"
 410       INDENT "action. The configuration may be specified either by giving an\n"
 411       INDENT "existing resource name with -r, or by specifying --class,\n"
 412       INDENT "--agent, and --provider arguments, along with any number of\n"
 413       INDENT "--option arguments. An optional LEVEL argument can be given\n"
 414       INDENT "to control the level of checking performed.",
 415       "LEVEL" },
 416     { "cleanup", 'C', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, cleanup_refresh_cb,
 417       "If resource has any past failures, clear its history and fail\n"
 418       INDENT "count. Optionally filtered by --resource, --node, --operation\n"
 419       INDENT "and --interval (otherwise all). --operation and --interval\n"
 420       INDENT "apply to fail counts, but entire history is always clear, to\n"
 421       INDENT "allow current state to be rechecked. If the named resource is\n"
 422       INDENT "part of a group, or one numbered instance of a clone or bundled\n"
 423       INDENT "resource, the clean-up applies to the whole collective resource\n"
 424       INDENT "unless --force is given.",
 425       NULL },
 426     { "refresh", 'R', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, cleanup_refresh_cb,
 427       "Delete resource's history (including failures) so its current state\n"
 428       INDENT "is rechecked. Optionally filtered by --resource and --node\n"
 429       INDENT "(otherwise all). If the named resource is part of a group, or one\n"
 430       INDENT "numbered instance of a clone or bundled resource, the refresh\n"
 431       INDENT "applies to the whole collective resource unless --force is given.",
 432       NULL },
 433     { "set-parameter", 'p', G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, set_delete_param_cb,
 434       "Set named parameter for resource (requires -v). Use instance\n"
 435       INDENT "attribute unless --meta or --utilization is specified.",
 436       "PARAM" },
 437     { "delete-parameter", 'd', G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, set_delete_param_cb,
 438       "Delete named parameter for resource. Use instance attribute\n"
 439       INDENT "unless --meta or --utilization is specified.",
 440       "PARAM" },
 441     { "set-property", 'S', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, set_prop_cb,
 442       "Set named property of resource ('class', 'type', or 'provider') "
 443       "(requires -r, -t, -v)",
 444       "PROPERTY" },
 445 
 446     { NULL }
 447 };
 448 
 449 static GOptionEntry location_entries[] = {
 450     { "move", 'M', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, flag_cb,
 451       "Create a constraint to move resource. If --node is specified,\n"
 452       INDENT "the constraint will be to move to that node, otherwise it\n"
 453       INDENT "will be to ban the current node. Unless --force is specified\n"
 454       INDENT "this will return an error if the resource is already running\n"
 455       INDENT "on the specified node. If --force is specified, this will\n"
 456       INDENT "always ban the current node.\n"
 457       INDENT "Optional: --lifetime, --promoted. NOTE: This may prevent the\n"
 458       INDENT "resource from running on its previous location until the\n"
 459       INDENT "implicit constraint expires or is removed with --clear.",
 460       NULL },
 461     { "ban", 'B', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, flag_cb,
 462       "Create a constraint to keep resource off a node.\n"
 463       INDENT "Optional: --node, --lifetime, --promoted.\n"
 464       INDENT "NOTE: This will prevent the resource from running on the\n"
 465       INDENT "affected node until the implicit constraint expires or is\n"
 466       INDENT "removed with --clear. If --node is not specified, it defaults\n"
 467       INDENT "to the node currently running the resource for primitives\n"
 468       INDENT "and groups, or the promoted instance of promotable clones with\n"
 469       INDENT "promoted-max=1 (all other situations result in an error as\n"
 470       INDENT "there is no sane default).",
 471       NULL },
 472     { "clear", 'U', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, flag_cb,
 473       "Remove all constraints created by the --ban and/or --move\n"
 474       INDENT "commands. Requires: --resource. Optional: --node, --promoted,\n"
 475       INDENT "--expired. If --node is not specified, all constraints created\n"
 476       INDENT "by --ban and --move will be removed for the named resource. If\n"
 477       INDENT "--node and --force are specified, any constraint created by\n"
 478       INDENT "--move will be cleared, even if it is not for the specified\n"
 479       INDENT "node. If --expired is specified, only those constraints whose\n"
 480       INDENT "lifetimes have expired will be removed.",
 481       NULL },
 482     { "expired", 'e', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, expired_cb,
 483       "Modifies the --clear argument to remove constraints with\n"
 484       INDENT "expired lifetimes.",
 485       NULL },
 486     { "lifetime", 'u', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &options.move_lifetime,
 487       "Lifespan (as ISO 8601 duration) of created constraints (with\n"
 488       INDENT "-B, -M) see https://en.wikipedia.org/wiki/ISO_8601#Durations)",
 489       "TIMESPEC" },
 490     { "promoted", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE,
 491       &options.promoted_role_only,
 492       "Limit scope of command to promoted role (with -B, -M, -U). For\n"
 493       INDENT "-B and -M, previously promoted instances may remain\n"
 494       INDENT "active in the unpromoted role.",
 495       NULL },
 496 
 497     // Deprecated since 2.1.0
 498     { "master", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE,
 499       &options.promoted_role_only,
 500       "Deprecated: Use --promoted instead", NULL },
 501 
 502     { NULL }
 503 };
 504 
 505 static GOptionEntry advanced_entries[] = {
 506     { "delete", 'D', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, delete_cb,
 507       "(Advanced) Delete a resource from the CIB. Required: -t",
 508       NULL },
 509     { "fail", 'F', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, fail_cb,
 510       "(Advanced) Tell the cluster this resource has failed",
 511       NULL },
 512     { "restart", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, restart_cb,
 513       "(Advanced) Tell the cluster to restart this resource and\n"
 514       INDENT "anything that depends on it",
 515       NULL },
 516     { "wait", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, wait_cb,
 517       "(Advanced) Wait until the cluster settles into a stable state",
 518       NULL },
 519     { "digests", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, digests_cb,
 520       "(Advanced) Show parameter hashes that Pacemaker uses to detect\n"
 521       INDENT "configuration changes (only accurate if there is resource\n"
 522       INDENT "history on the specified node). Required: --resource, --node.\n"
 523       INDENT "Optional: any NAME=VALUE parameters will be used to override\n"
 524       INDENT "the configuration (to see what the hash would be with those\n"
 525       INDENT "changes).",
 526       NULL },
 527     { "force-demote", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
 528       validate_or_force_cb,
 529       "(Advanced) Bypass the cluster and demote a resource on the local\n"
 530       INDENT "node. Unless --force is specified, this will refuse to do so if\n"
 531       INDENT "the cluster believes the resource is a clone instance already\n"
 532       INDENT "running on the local node.",
 533       NULL },
 534     { "force-stop", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
 535       validate_or_force_cb,
 536       "(Advanced) Bypass the cluster and stop a resource on the local node",
 537       NULL },
 538     { "force-start", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
 539       validate_or_force_cb,
 540       "(Advanced) Bypass the cluster and start a resource on the local\n"
 541       INDENT "node. Unless --force is specified, this will refuse to do so if\n"
 542       INDENT "the cluster believes the resource is a clone instance already\n"
 543       INDENT "running on the local node.",
 544       NULL },
 545     { "force-promote", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
 546       validate_or_force_cb,
 547       "(Advanced) Bypass the cluster and promote a resource on the local\n"
 548       INDENT "node. Unless --force is specified, this will refuse to do so if\n"
 549       INDENT "the cluster believes the resource is a clone instance already\n"
 550       INDENT "running on the local node.",
 551       NULL },
 552     { "force-check", 0, G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK,
 553       validate_or_force_cb,
 554       "(Advanced) Bypass the cluster and check the state of a resource on\n"
 555       INDENT "the local node. An optional LEVEL argument can be given\n"
 556       INDENT "to control the level of checking performed.",
 557       "LEVEL" },
 558 
 559     { NULL }
 560 };
 561 
 562 static GOptionEntry addl_entries[] = {
 563     { "node", 'N', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &options.host_uname,
 564       "Node name",
 565       "NAME" },
 566     { "recursive", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &options.recursive,
 567       "Follow colocation chains when using --set-parameter",
 568       NULL },
 569     { "resource-type", 't', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &options.rsc_type,
 570       "Resource XML element (primitive, group, etc.) (with -D)",
 571       "ELEMENT" },
 572     { "parameter-value", 'v', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &options.prop_value,
 573       "Value to use with -p",
 574       "PARAM" },
 575     { "meta", 'm', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, attr_set_type_cb,
 576       "Use resource meta-attribute instead of instance attribute\n"
 577       INDENT "(with -p, -g, -d)",
 578       NULL },
 579     { "utilization", 'z', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, attr_set_type_cb,
 580       "Use resource utilization attribute instead of instance attribute\n"
 581       INDENT "(with -p, -g, -d)",
 582       NULL },
 583     { "operation", 'n', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &options.operation,
 584       "Operation to clear instead of all (with -C -r)",
 585       "OPERATION" },
 586     { "interval", 'I', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &options.interval_spec,
 587       "Interval of operation to clear (default 0) (with -C -r -n)",
 588       "N" },
 589     { "class", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, class_cb,
 590       "The standard the resource agent conforms to (for example, ocf).\n"
 591       INDENT "Use with --agent, --provider, --option, and --validate.",
 592       "CLASS" },
 593     { "agent", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, agent_provider_cb,
 594       "The agent to use (for example, IPaddr). Use with --class,\n"
 595       INDENT "--provider, --option, and --validate.",
 596       "AGENT" },
 597     { "provider", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, agent_provider_cb,
 598       "The vendor that supplies the resource agent (for example,\n"
 599       INDENT "heartbeat). Use with --class, --agent, --option, and --validate.",
 600       "PROVIDER" },
 601     { "option", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, option_cb,
 602       "Specify a device configuration parameter as NAME=VALUE (may be\n"
 603       INDENT "specified multiple times). Use with --validate and without the\n"
 604       INDENT "-r option.",
 605       "PARAM" },
 606     { "set-name", 's', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &options.prop_set,
 607       "(Advanced) XML ID of attributes element to use (with -p, -d)",
 608       "ID" },
 609     { "nvpair", 'i', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &options.prop_id,
 610       "(Advanced) XML ID of nvpair element to use (with -p, -d)",
 611       "ID" },
 612     { "timeout", 'T', G_OPTION_FLAG_NONE, G_OPTION_ARG_CALLBACK, timeout_cb,
 613       "(Advanced) Abort if command does not finish in this time (with\n"
 614       INDENT "--restart, --wait, --force-*)",
 615       "N" },
 616     { "force", 'f', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &options.force,
 617       "If making CIB changes, do so regardless of quorum. See help for\n"
 618       INDENT "individual commands for additional behavior.",
 619       NULL },
 620     { "xml-file", 'x', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_FILENAME, &options.xml_file,
 621       NULL,
 622       "FILE" },
 623     { "host-uname", 'H', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &options.host_uname,
 624       NULL,
 625       "HOST" },
 626 
 627     { NULL }
 628 };
 629 
 630 gboolean
 631 agent_provider_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 632     options.cmdline_config = TRUE;
 633     options.require_resource = FALSE;
 634 
 635     if (pcmk__str_eq(option_name, "--provider", pcmk__str_casei)) {
 636         if (options.v_provider) {
 637            free(options.v_provider);
 638         }
 639         options.v_provider = strdup(optarg);
 640     } else {
 641         if (options.v_agent) {
 642            free(options.v_agent);
 643         }
 644         options.v_agent = strdup(optarg);
 645     }
 646 
 647     return TRUE;
 648 }
 649 
 650 gboolean
 651 attr_set_type_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 652     if (pcmk__str_any_of(option_name, "-m", "--meta", NULL)) {
 653         options.attr_set_type = XML_TAG_META_SETS;
 654     } else if (pcmk__str_any_of(option_name, "-z", "--utilization", NULL)) {
 655         options.attr_set_type = XML_TAG_UTILIZATION;
 656     }
 657 
 658     return TRUE;
 659 }
 660 
 661 gboolean
 662 class_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 663     if (options.v_class != NULL) {
 664         free(options.v_class);
 665     }
 666 
 667     options.v_class = strdup(optarg);
 668 
 669     options.cmdline_config = TRUE;
 670     options.require_resource = FALSE;
 671     return TRUE;
 672 }
 673 
 674 gboolean
 675 cleanup_refresh_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 676     if (pcmk__str_any_of(option_name, "-C", "--cleanup", NULL)) {
 677         SET_COMMAND(cmd_cleanup);
 678     } else {
 679         SET_COMMAND(cmd_refresh);
 680     }
 681 
 682     options.require_resource = FALSE;
 683     if (getenv("CIB_file") == NULL) {
 684         options.require_crmd = TRUE;
 685     }
 686     options.find_flags = pe_find_renamed|pe_find_anon;
 687     return TRUE;
 688 }
 689 
 690 gboolean
 691 delete_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 692     options.require_dataset = FALSE;
 693     SET_COMMAND(cmd_delete);
 694     options.find_flags = pe_find_renamed|pe_find_any;
 695     return TRUE;
 696 }
 697 
 698 gboolean
 699 expired_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 700     options.clear_expired = TRUE;
 701     options.require_resource = FALSE;
 702     return TRUE;
 703 }
 704 
 705 static void
 706 get_agent_spec(const gchar *optarg)
     /* [previous][next][first][last][top][bottom][index][help] */
 707 {
 708     options.require_cib = FALSE;
 709     options.require_dataset = FALSE;
 710     options.require_resource = FALSE;
 711     if (options.agent_spec != NULL) {
 712         free(options.agent_spec);
 713         options.agent_spec = NULL;
 714     }
 715     if (optarg != NULL) {
 716         options.agent_spec = strdup(optarg);
 717     }
 718 }
 719 
 720 gboolean
 721 list_agents_cb(const gchar *option_name, const gchar *optarg, gpointer data,
     /* [previous][next][first][last][top][bottom][index][help] */
 722                GError **error)
 723 {
 724     SET_COMMAND(cmd_list_agents);
 725     get_agent_spec(optarg);
 726     return TRUE;
 727 }
 728 
 729 gboolean
 730 list_providers_cb(const gchar *option_name, const gchar *optarg, gpointer data,
     /* [previous][next][first][last][top][bottom][index][help] */
 731                   GError **error)
 732 {
 733     SET_COMMAND(cmd_list_providers);
 734     get_agent_spec(optarg);
 735     return TRUE;
 736 }
 737 
 738 gboolean
 739 list_standards_cb(const gchar *option_name, const gchar *optarg, gpointer data,
     /* [previous][next][first][last][top][bottom][index][help] */
 740                   GError **error)
 741 {
 742     SET_COMMAND(cmd_list_standards);
 743     options.require_cib = FALSE;
 744     options.require_dataset = FALSE;
 745     options.require_resource = FALSE;
 746     return TRUE;
 747 }
 748 
 749 gboolean
 750 list_alternatives_cb(const gchar *option_name, const gchar *optarg,
     /* [previous][next][first][last][top][bottom][index][help] */
 751                      gpointer data, GError **error)
 752 {
 753     SET_COMMAND(cmd_list_alternatives);
 754     get_agent_spec(optarg);
 755     return TRUE;
 756 }
 757 
 758 gboolean
 759 metadata_cb(const gchar *option_name, const gchar *optarg, gpointer data,
     /* [previous][next][first][last][top][bottom][index][help] */
 760             GError **error)
 761 {
 762     SET_COMMAND(cmd_metadata);
 763     get_agent_spec(optarg);
 764     return TRUE;
 765 }
 766 
 767 gboolean
 768 option_cb(const gchar *option_name, const gchar *optarg, gpointer data,
     /* [previous][next][first][last][top][bottom][index][help] */
 769           GError **error)
 770 {
 771     char *name = NULL;
 772     char *value = NULL;
 773 
 774     if (pcmk__scan_nvpair(optarg, &name, &value) != 2) {
 775         return FALSE;
 776     }
 777     if (options.cmdline_params == NULL) {
 778         options.cmdline_params = pcmk__strkey_table(free, free);
 779     }
 780     g_hash_table_replace(options.cmdline_params, name, value);
 781     return TRUE;
 782 }
 783 
 784 gboolean
 785 fail_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 786     options.require_crmd = TRUE;
 787     options.require_node = TRUE;
 788     SET_COMMAND(cmd_fail);
 789     return TRUE;
 790 }
 791 
 792 gboolean
 793 flag_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 794     if (pcmk__str_any_of(option_name, "-U", "--clear", NULL)) {
 795         options.find_flags = pe_find_renamed|pe_find_anon;
 796         SET_COMMAND(cmd_clear);
 797     } else if (pcmk__str_any_of(option_name, "-B", "--ban", NULL)) {
 798         options.find_flags = pe_find_renamed|pe_find_anon;
 799         SET_COMMAND(cmd_ban);
 800     } else if (pcmk__str_any_of(option_name, "-M", "--move", NULL)) {
 801         options.find_flags = pe_find_renamed|pe_find_anon;
 802         SET_COMMAND(cmd_move);
 803     } else if (pcmk__str_any_of(option_name, "-q", "--query-xml", NULL)) {
 804         options.find_flags = pe_find_renamed|pe_find_any;
 805         SET_COMMAND(cmd_query_xml);
 806     } else if (pcmk__str_any_of(option_name, "-w", "--query-xml-raw", NULL)) {
 807         options.find_flags = pe_find_renamed|pe_find_any;
 808         SET_COMMAND(cmd_query_raw_xml);
 809     } else if (pcmk__str_any_of(option_name, "-W", "--locate", NULL)) {
 810         options.find_flags = pe_find_renamed|pe_find_anon;
 811         SET_COMMAND(cmd_locate);
 812     } else if (pcmk__str_any_of(option_name, "-A", "--stack", NULL)) {
 813         options.find_flags = pe_find_renamed|pe_find_anon;
 814         SET_COMMAND(cmd_colocations_deep);
 815     } else {
 816         options.find_flags = pe_find_renamed|pe_find_anon;
 817         SET_COMMAND(cmd_colocations);
 818     }
 819 
 820     return TRUE;
 821 }
 822 
 823 gboolean
 824 get_param_prop_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 825     if (pcmk__str_any_of(option_name, "-g", "--get-parameter", NULL)) {
 826         SET_COMMAND(cmd_get_param);
 827     } else {
 828         SET_COMMAND(cmd_get_property);
 829     }
 830 
 831     if (options.prop_name) {
 832         free(options.prop_name);
 833     }
 834 
 835     options.prop_name = strdup(optarg);
 836     options.find_flags = pe_find_renamed|pe_find_any;
 837     return TRUE;
 838 }
 839 
 840 gboolean
 841 list_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 842     if (pcmk__str_any_of(option_name, "-c", "--list-cts", NULL)) {
 843         SET_COMMAND(cmd_cts);
 844     } else if (pcmk__str_any_of(option_name, "-L", "--list", NULL)) {
 845         SET_COMMAND(cmd_list_resources);
 846     } else if (pcmk__str_any_of(option_name, "-l", "--list-raw", NULL)) {
 847         SET_COMMAND(cmd_list_instances);
 848     } else if (pcmk__str_any_of(option_name, "-O", "--list-operations", NULL)) {
 849         SET_COMMAND(cmd_list_active_ops);
 850     } else {
 851         SET_COMMAND(cmd_list_all_ops);
 852     }
 853 
 854     options.require_resource = FALSE;
 855     return TRUE;
 856 }
 857 
 858 gboolean
 859 set_delete_param_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 860     if (pcmk__str_any_of(option_name, "-p", "--set-parameter", NULL)) {
 861         SET_COMMAND(cmd_set_param);
 862     } else {
 863         SET_COMMAND(cmd_delete_param);
 864     }
 865 
 866     if (options.prop_name) {
 867         free(options.prop_name);
 868     }
 869 
 870     options.prop_name = strdup(optarg);
 871     options.find_flags = pe_find_renamed|pe_find_any;
 872     return TRUE;
 873 }
 874 
 875 gboolean
 876 set_prop_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 877     options.require_dataset = FALSE;
 878 
 879     if (options.prop_name) {
 880         free(options.prop_name);
 881     }
 882 
 883     options.prop_name = strdup(optarg);
 884     SET_COMMAND(cmd_set_property);
 885     options.find_flags = pe_find_renamed|pe_find_any;
 886     return TRUE;
 887 }
 888 
 889 gboolean
 890 timeout_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 891     options.timeout_ms = crm_get_msec(optarg);
 892     return TRUE;
 893 }
 894 
 895 gboolean
 896 validate_or_force_cb(const gchar *option_name, const gchar *optarg,
     /* [previous][next][first][last][top][bottom][index][help] */
 897                      gpointer data, GError **error)
 898 {
 899     SET_COMMAND(cmd_execute_agent);
 900     if (options.operation) {
 901         g_free(options.operation);
 902     }
 903     options.operation = g_strdup(option_name + 2); // skip "--"
 904     options.find_flags = pe_find_renamed|pe_find_anon;
 905     if (options.override_params == NULL) {
 906         options.override_params = pcmk__strkey_table(free, free);
 907     }
 908 
 909     if (optarg != NULL) {
 910         if (pcmk__scan_min_int(optarg, &options.check_level, 0) != pcmk_rc_ok) {
 911             g_set_error(error, G_OPTION_ERROR, CRM_EX_INVALID_PARAM,
 912                         "Invalid check level setting: %s", optarg);
 913             return FALSE;
 914         }
 915     }
 916 
 917     return TRUE;
 918 }
 919 
 920 gboolean
 921 restart_cb(const gchar *option_name, const gchar *optarg, gpointer data,
     /* [previous][next][first][last][top][bottom][index][help] */
 922            GError **error)
 923 {
 924     SET_COMMAND(cmd_restart);
 925     options.find_flags = pe_find_renamed|pe_find_anon;
 926     return TRUE;
 927 }
 928 
 929 gboolean
 930 digests_cb(const gchar *option_name, const gchar *optarg, gpointer data,
     /* [previous][next][first][last][top][bottom][index][help] */
 931            GError **error)
 932 {
 933     SET_COMMAND(cmd_digests);
 934     options.find_flags = pe_find_renamed|pe_find_anon;
 935     if (options.override_params == NULL) {
 936         options.override_params = pcmk__strkey_table(free, free);
 937     }
 938     options.require_node = TRUE;
 939     options.require_dataset = TRUE;
 940     return TRUE;
 941 }
 942 
 943 gboolean
 944 wait_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 945     SET_COMMAND(cmd_wait);
 946     options.require_resource = FALSE;
 947     options.require_dataset = FALSE;
 948     return TRUE;
 949 }
 950 
 951 gboolean
 952 why_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 953     options.require_resource = FALSE;
 954     SET_COMMAND(cmd_why);
 955     options.find_flags = pe_find_renamed|pe_find_anon;
 956     return TRUE;
 957 }
 958 
 959 static int
 960 ban_or_move(pcmk__output_t *out, pe_resource_t *rsc, const char *move_lifetime)
     /* [previous][next][first][last][top][bottom][index][help] */
 961 {
 962     int rc = pcmk_rc_ok;
 963     pe_node_t *current = NULL;
 964     unsigned int nactive = 0;
 965 
 966     CRM_CHECK(rsc != NULL, return EINVAL);
 967 
 968     current = pe__find_active_requires(rsc, &nactive);
 969 
 970     if (nactive == 1) {
 971         rc = cli_resource_ban(out, options.rsc_id, current->details->uname, move_lifetime, NULL,
 972                               cib_conn, options.cib_options, options.promoted_role_only);
 973 
 974     } else if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
 975         int count = 0;
 976         GList *iter = NULL;
 977 
 978         current = NULL;
 979         for(iter = rsc->children; iter; iter = iter->next) {
 980             pe_resource_t *child = (pe_resource_t *)iter->data;
 981             enum rsc_role_e child_role = child->fns->state(child, TRUE);
 982 
 983             if (child_role == RSC_ROLE_PROMOTED) {
 984                 count++;
 985                 current = pe__current_node(child);
 986             }
 987         }
 988 
 989         if(count == 1 && current) {
 990             rc = cli_resource_ban(out, options.rsc_id, current->details->uname, move_lifetime, NULL,
 991                                   cib_conn, options.cib_options, options.promoted_role_only);
 992 
 993         } else {
 994             rc = EINVAL;
 995             g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_USAGE,
 996                         "Resource '%s' not moved: active in %d locations (promoted in %d).\n"
 997                         "To prevent '%s' from running on a specific location, "
 998                         "specify a node."
 999                         "To prevent '%s' from being promoted at a specific "
1000                         "location, specify a node and the --promoted option.",
1001                         options.rsc_id, nactive, count, options.rsc_id, options.rsc_id);
1002         }
1003 
1004     } else {
1005         rc = EINVAL;
1006         g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_USAGE,
1007                     "Resource '%s' not moved: active in %d locations.\n"
1008                     "To prevent '%s' from running on a specific location, "
1009                     "specify a node.",
1010                     options.rsc_id, nactive, options.rsc_id);
1011     }
1012 
1013     return rc;
1014 }
1015 
1016 static void
1017 cleanup(pcmk__output_t *out, pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
1018 {
1019     int rc = pcmk_rc_ok;
1020 
1021     if (options.force == FALSE) {
1022         rsc = uber_parent(rsc);
1023     }
1024 
1025     crm_debug("Erasing failures of %s (%s requested) on %s",
1026               rsc->id, options.rsc_id, (options.host_uname? options.host_uname: "all nodes"));
1027     rc = cli_resource_delete(controld_api, options.host_uname, rsc, options.operation,
1028                              options.interval_spec, TRUE, data_set, options.force);
1029 
1030     if ((rc == pcmk_rc_ok) && !out->is_quiet(out)) {
1031         // Show any reasons why resource might stay stopped
1032         cli_resource_check(out, cib_conn, rsc);
1033     }
1034 
1035     if (rc == pcmk_rc_ok) {
1036         start_mainloop(controld_api);
1037     }
1038 }
1039 
1040 static int
1041 clear_constraints(pcmk__output_t *out, xmlNodePtr *cib_xml_copy)
     /* [previous][next][first][last][top][bottom][index][help] */
1042 {
1043     GList *before = NULL;
1044     GList *after = NULL;
1045     GList *remaining = NULL;
1046     GList *ele = NULL;
1047     pe_node_t *dest = NULL;
1048     int rc = pcmk_rc_ok;
1049 
1050     if (!out->is_quiet(out)) {
1051         before = build_constraint_list(data_set->input);
1052     }
1053 
1054     if (options.clear_expired) {
1055         rc = cli_resource_clear_all_expired(data_set->input, cib_conn, options.cib_options,
1056                                             options.rsc_id, options.host_uname,
1057                                             options.promoted_role_only);
1058 
1059     } else if (options.host_uname) {
1060         dest = pe_find_node(data_set->nodes, options.host_uname);
1061         if (dest == NULL) {
1062             rc = pcmk_rc_node_unknown;
1063             if (!out->is_quiet(out)) {
1064                 g_list_free(before);
1065             }
1066             return rc;
1067         }
1068         rc = cli_resource_clear(options.rsc_id, dest->details->uname, NULL,
1069                                 cib_conn, options.cib_options, TRUE, options.force);
1070 
1071     } else {
1072         rc = cli_resource_clear(options.rsc_id, NULL, data_set->nodes,
1073                                 cib_conn, options.cib_options, TRUE, options.force);
1074     }
1075 
1076     if (!out->is_quiet(out)) {
1077         rc = cib_conn->cmds->query(cib_conn, NULL, cib_xml_copy, cib_scope_local | cib_sync_call);
1078         rc = pcmk_legacy2rc(rc);
1079 
1080         if (rc != pcmk_rc_ok) {
1081             g_set_error(&error, PCMK__RC_ERROR, rc,
1082                         "Could not get modified CIB: %s\n", pcmk_strerror(rc));
1083             g_list_free(before);
1084             free_xml(*cib_xml_copy);
1085             *cib_xml_copy = NULL;
1086             return rc;
1087         }
1088 
1089         data_set->input = *cib_xml_copy;
1090         cluster_status(data_set);
1091 
1092         after = build_constraint_list(data_set->input);
1093         remaining = pcmk__subtract_lists(before, after, (GCompareFunc) strcmp);
1094 
1095         for (ele = remaining; ele != NULL; ele = ele->next) {
1096             out->info(out, "Removing constraint: %s", (char *) ele->data);
1097         }
1098 
1099         g_list_free(before);
1100         g_list_free(after);
1101         g_list_free(remaining);
1102     }
1103 
1104     return rc;
1105 }
1106 
1107 static int
1108 delete(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1109 {
1110     int rc = pcmk_rc_ok;
1111     xmlNode *msg_data = NULL;
1112 
1113     if (options.rsc_type == NULL) {
1114         rc = ENXIO;
1115         g_set_error(&error, PCMK__RC_ERROR, rc,
1116                     "You need to specify a resource type with -t");
1117         return rc;
1118     }
1119 
1120     msg_data = create_xml_node(NULL, options.rsc_type);
1121     crm_xml_add(msg_data, XML_ATTR_ID, options.rsc_id);
1122 
1123     rc = cib_conn->cmds->remove(cib_conn, XML_CIB_TAG_RESOURCES, msg_data,
1124                                 options.cib_options);
1125     rc = pcmk_legacy2rc(rc);
1126     free_xml(msg_data);
1127     return rc;
1128 }
1129 
1130 static int
1131 list_agents(pcmk__output_t *out, const char *agent_spec)
     /* [previous][next][first][last][top][bottom][index][help] */
1132 {
1133     int rc = pcmk_rc_ok;
1134     char *provider = strchr(agent_spec, ':');
1135     lrmd_t *lrmd_conn = NULL;
1136     lrmd_list_t *list = NULL;
1137 
1138     rc = lrmd__new(&lrmd_conn, NULL, NULL, 0);
1139     if (rc != pcmk_rc_ok) {
1140         goto error;
1141     }
1142 
1143     if (provider) {
1144         *provider++ = 0;
1145     }
1146 
1147     rc = lrmd_conn->cmds->list_agents(lrmd_conn, &list, agent_spec, provider);
1148 
1149     if (rc > 0) {
1150         rc = out->message(out, "agents-list", list, agent_spec, provider);
1151     } else {
1152         rc = pcmk_rc_error;
1153     }
1154 
1155 error:
1156     if (rc != pcmk_rc_ok) {
1157         if (provider == NULL) {
1158             g_set_error(&error, PCMK__RC_ERROR, rc,
1159                         "No agents found for standard '%s'", agent_spec);
1160         } else {
1161             g_set_error(&error, PCMK__RC_ERROR, rc,
1162                         "No agents found for standard '%s' and provider '%s'",
1163                         agent_spec, provider);
1164         }
1165     }
1166 
1167     lrmd_api_delete(lrmd_conn);
1168     return rc;
1169 }
1170 
1171 static int
1172 list_providers(pcmk__output_t *out, const char *agent_spec)
     /* [previous][next][first][last][top][bottom][index][help] */
1173 {
1174     int rc;
1175     const char *text = NULL;
1176     lrmd_t *lrmd_conn = NULL;
1177     lrmd_list_t *list = NULL;
1178 
1179     rc = lrmd__new(&lrmd_conn, NULL, NULL, 0);
1180     if (rc != pcmk_rc_ok) {
1181         goto error;
1182     }
1183 
1184     switch (options.rsc_cmd) {
1185         case cmd_list_alternatives:
1186             rc = lrmd_conn->cmds->list_ocf_providers(lrmd_conn, agent_spec, &list);
1187 
1188             if (rc > 0) {
1189                 rc = out->message(out, "alternatives-list", list, agent_spec);
1190             } else {
1191                 rc = pcmk_rc_error;
1192             }
1193 
1194             text = "OCF providers";
1195             break;
1196         case cmd_list_standards:
1197             rc = lrmd_conn->cmds->list_standards(lrmd_conn, &list);
1198 
1199             if (rc > 0) {
1200                 rc = out->message(out, "standards-list", list);
1201             } else {
1202                 rc = pcmk_rc_error;
1203             }
1204 
1205             text = "standards";
1206             break;
1207         case cmd_list_providers:
1208             rc = lrmd_conn->cmds->list_ocf_providers(lrmd_conn, agent_spec, &list);
1209 
1210             if (rc > 0) {
1211                 rc = out->message(out, "providers-list", list, agent_spec);
1212             } else {
1213                 rc = pcmk_rc_error;
1214             }
1215 
1216             text = "OCF providers";
1217             break;
1218         default:
1219             g_set_error(&error, PCMK__RC_ERROR, pcmk_rc_error, "Bug");
1220             lrmd_api_delete(lrmd_conn);
1221             return pcmk_rc_error;
1222     }
1223 
1224 error:
1225     if (rc != pcmk_rc_ok) {
1226         if (agent_spec != NULL) {
1227             rc = ENXIO;
1228             g_set_error(&error, PCMK__RC_ERROR, rc,
1229                         "No %s found for %s", text, agent_spec);
1230 
1231         } else {
1232             rc = ENXIO;
1233             g_set_error(&error, PCMK__RC_ERROR, rc,
1234                         "No %s found", text);
1235         }
1236     }
1237 
1238     lrmd_api_delete(lrmd_conn);
1239     return rc;
1240 }
1241 
1242 static int
1243 populate_working_set(xmlNodePtr *cib_xml_copy)
     /* [previous][next][first][last][top][bottom][index][help] */
1244 {
1245     int rc = pcmk_rc_ok;
1246 
1247     if (options.xml_file != NULL) {
1248         *cib_xml_copy = filename2xml(options.xml_file);
1249         if (*cib_xml_copy == NULL) {
1250             rc = pcmk_rc_cib_corrupt;
1251         }
1252     } else {
1253         rc = cib_conn->cmds->query(cib_conn, NULL, cib_xml_copy, cib_scope_local | cib_sync_call);
1254         rc = pcmk_legacy2rc(rc);
1255     }
1256 
1257     if (rc == pcmk_rc_ok) {
1258         data_set = pe_new_working_set();
1259         if (data_set == NULL) {
1260             rc = ENOMEM;
1261         } else {
1262             pe__set_working_set_flags(data_set,
1263                                       pe_flag_no_counts|pe_flag_no_compat);
1264             data_set->priv = out;
1265             rc = update_working_set_xml(data_set, cib_xml_copy);
1266         }
1267     }
1268 
1269     if (rc != pcmk_rc_ok) {
1270         free_xml(*cib_xml_copy);
1271         *cib_xml_copy = NULL;
1272         return rc;
1273     }
1274 
1275     cluster_status(data_set);
1276     return pcmk_rc_ok;
1277 }
1278 
1279 static int
1280 refresh(pcmk__output_t *out)
     /* [previous][next][first][last][top][bottom][index][help] */
1281 {
1282     int rc = pcmk_rc_ok;
1283     const char *router_node = options.host_uname;
1284     int attr_options = pcmk__node_attr_none;
1285 
1286     if (options.host_uname) {
1287         pe_node_t *node = pe_find_node(data_set->nodes, options.host_uname);
1288 
1289         if (pe__is_guest_or_remote_node(node)) {
1290             node = pe__current_node(node->details->remote_rsc);
1291             if (node == NULL) {
1292                 rc = ENXIO;
1293                 g_set_error(&error, PCMK__RC_ERROR, rc,
1294                             "No cluster connection to Pacemaker Remote node %s detected",
1295                             options.host_uname);
1296                 return rc;
1297             }
1298             router_node = node->details->uname;
1299             attr_options |= pcmk__node_attr_remote;
1300         }
1301     }
1302 
1303     if (controld_api == NULL) {
1304         out->info(out, "Dry run: skipping clean-up of %s due to CIB_file",
1305                   options.host_uname? options.host_uname : "all nodes");
1306         rc = pcmk_rc_ok;
1307         return rc;
1308     }
1309 
1310     crm_debug("Re-checking the state of all resources on %s", options.host_uname?options.host_uname:"all nodes");
1311 
1312     rc = pcmk__node_attr_request_clear(NULL, options.host_uname,
1313                                        NULL, NULL, NULL,
1314                                        NULL, attr_options);
1315 
1316     if (pcmk_controld_api_reprobe(controld_api, options.host_uname,
1317                                   router_node) == pcmk_rc_ok) {
1318         start_mainloop(controld_api);
1319     }
1320 
1321     return rc;
1322 }
1323 
1324 static void
1325 refresh_resource(pcmk__output_t *out, pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
1326 {
1327     int rc = pcmk_rc_ok;
1328 
1329     if (options.force == FALSE) {
1330         rsc = uber_parent(rsc);
1331     }
1332 
1333     crm_debug("Re-checking the state of %s (%s requested) on %s",
1334               rsc->id, options.rsc_id, (options.host_uname? options.host_uname: "all nodes"));
1335     rc = cli_resource_delete(controld_api, options.host_uname, rsc, NULL,
1336                              0, FALSE, data_set, options.force);
1337 
1338     if ((rc == pcmk_rc_ok) && !out->is_quiet(out)) {
1339         // Show any reasons why resource might stay stopped
1340         cli_resource_check(out, cib_conn, rsc);
1341     }
1342 
1343     if (rc == pcmk_rc_ok) {
1344         start_mainloop(controld_api);
1345     }
1346 }
1347 
1348 static int
1349 set_property(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1350 {
1351     int rc = pcmk_rc_ok;
1352     xmlNode *msg_data = NULL;
1353 
1354     if (pcmk__str_empty(options.rsc_type)) {
1355         g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_USAGE,
1356                     "Must specify -t with resource type");
1357         rc = ENXIO;
1358         return rc;
1359 
1360     } else if (pcmk__str_empty(options.prop_value)) {
1361         g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_USAGE,
1362                     "Must supply -v with new value");
1363         rc = ENXIO;
1364         return rc;
1365     }
1366 
1367     CRM_LOG_ASSERT(options.prop_name != NULL);
1368 
1369     msg_data = create_xml_node(NULL, options.rsc_type);
1370     crm_xml_add(msg_data, XML_ATTR_ID, options.rsc_id);
1371     crm_xml_add(msg_data, options.prop_name, options.prop_value);
1372 
1373     rc = cib_conn->cmds->modify(cib_conn, XML_CIB_TAG_RESOURCES, msg_data,
1374                                 options.cib_options);
1375     rc = pcmk_legacy2rc(rc);
1376     free_xml(msg_data);
1377 
1378     return rc;
1379 }
1380 
1381 static int
1382 show_metadata(pcmk__output_t *out, const char *agent_spec)
     /* [previous][next][first][last][top][bottom][index][help] */
1383 {
1384     int rc = pcmk_rc_ok;
1385     char *standard = NULL;
1386     char *provider = NULL;
1387     char *type = NULL;
1388     char *metadata = NULL;
1389     lrmd_t *lrmd_conn = NULL;
1390 
1391     rc = lrmd__new(&lrmd_conn, NULL, NULL, 0);
1392     if (rc != pcmk_rc_ok) {
1393         g_set_error(&error, PCMK__RC_ERROR, rc,
1394                     "Could not create executor connection");
1395         lrmd_api_delete(lrmd_conn);
1396         return rc;
1397     }
1398 
1399     rc = crm_parse_agent_spec(agent_spec, &standard, &provider, &type);
1400     rc = pcmk_legacy2rc(rc);
1401 
1402     if (rc == pcmk_rc_ok) {
1403         rc = lrmd_conn->cmds->get_metadata(lrmd_conn, standard,
1404                                            provider, type,
1405                                            &metadata, 0);
1406         rc = pcmk_legacy2rc(rc);
1407 
1408         if (metadata) {
1409             out->output_xml(out, "metadata", metadata);
1410         } else {
1411             /* We were given a validly formatted spec, but it doesn't necessarily
1412              * match up with anything that exists.  Use ENXIO as the return code
1413              * here because that maps to an exit code of CRM_EX_NOSUCH, which
1414              * probably is the most common reason to get here.
1415              */
1416             rc = ENXIO;
1417             g_set_error(&error, PCMK__RC_ERROR, rc,
1418                         "Metadata query for %s failed: %s",
1419                         agent_spec, pcmk_rc_str(rc));
1420         }
1421     } else {
1422         rc = ENXIO;
1423         g_set_error(&error, PCMK__RC_ERROR, rc,
1424                     "'%s' is not a valid agent specification", agent_spec);
1425     }
1426 
1427     lrmd_api_delete(lrmd_conn);
1428     return rc;
1429 }
1430 
1431 static void
1432 validate_cmdline_config(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1433 {
1434     // Cannot use both --resource and command-line resource configuration
1435     if (options.rsc_id != NULL) {
1436         g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_USAGE,
1437                     "--resource cannot be used with --class, --agent, and --provider");
1438 
1439     // Not all commands support command-line resource configuration
1440     } else if (options.rsc_cmd != cmd_execute_agent) {
1441         g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_USAGE,
1442                     "--class, --agent, and --provider can only be used with "
1443                     "--validate and --force-*");
1444 
1445     // Not all of --class, --agent, and --provider need to be given.  Not all
1446     // classes support the concept of a provider.  Check that what we were given
1447     // is valid.
1448     } else if (pcmk__str_eq(options.v_class, "stonith", pcmk__str_none)) {
1449         if (options.v_provider != NULL) {
1450             g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_USAGE,
1451                         "stonith does not support providers");
1452 
1453         } else if (stonith_agent_exists(options.v_agent, 0) == FALSE) {
1454             g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_USAGE,
1455                         "%s is not a known stonith agent", options.v_agent ? options.v_agent : "");
1456         }
1457 
1458     } else if (resources_agent_exists(options.v_class, options.v_provider, options.v_agent) == FALSE) {
1459         g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_USAGE,
1460                     "%s:%s:%s is not a known resource",
1461                     options.v_class ? options.v_class : "",
1462                     options.v_provider ? options.v_provider : "",
1463                     options.v_agent ? options.v_agent : "");
1464     }
1465 
1466     if (error != NULL) {
1467         return;
1468     }
1469 
1470     if (options.cmdline_params == NULL) {
1471         options.cmdline_params = pcmk__strkey_table(free, free);
1472     }
1473     options.require_resource = FALSE;
1474     options.require_dataset = FALSE;
1475     options.require_cib = FALSE;
1476 }
1477 
1478 static GOptionContext *
1479 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
     /* [previous][next][first][last][top][bottom][index][help] */
1480     GOptionContext *context = NULL;
1481 
1482     GOptionEntry extra_prog_entries[] = {
1483         { "quiet", 'Q', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &(args->quiet),
1484           "Be less descriptive in output.",
1485           NULL },
1486         { "resource", 'r', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &options.rsc_id,
1487           "Resource ID",
1488           "ID" },
1489         { G_OPTION_REMAINING, 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING_ARRAY, &options.remainder,
1490           NULL,
1491           NULL },
1492 
1493         { NULL }
1494     };
1495 
1496     const char *description = "Examples:\n\n"
1497                               "List the available OCF agents:\n\n"
1498                               "\t# crm_resource --list-agents ocf\n\n"
1499                               "List the available OCF agents from the linux-ha project:\n\n"
1500                               "\t# crm_resource --list-agents ocf:heartbeat\n\n"
1501                               "Move 'myResource' to a specific node:\n\n"
1502                               "\t# crm_resource --resource myResource --move --node altNode\n\n"
1503                               "Allow (but not force) 'myResource' to move back to its original "
1504                               "location:\n\n"
1505                               "\t# crm_resource --resource myResource --clear\n\n"
1506                               "Stop 'myResource' (and anything that depends on it):\n\n"
1507                               "\t# crm_resource --resource myResource --set-parameter target-role "
1508                               "--meta --parameter-value Stopped\n\n"
1509                               "Tell the cluster not to manage 'myResource' (the cluster will not "
1510                               "attempt to start or stop the\n"
1511                               "resource under any circumstances; useful when performing maintenance "
1512                               "tasks on a resource):\n\n"
1513                               "\t# crm_resource --resource myResource --set-parameter is-managed "
1514                               "--meta --parameter-value false\n\n"
1515                               "Erase the operation history of 'myResource' on 'aNode' (the cluster "
1516                               "will 'forget' the existing\n"
1517                               "resource state, including any errors, and attempt to recover the"
1518                               "resource; useful when a resource\n"
1519                               "had failed permanently and has been repaired by an administrator):\n\n"
1520                               "\t# crm_resource --resource myResource --cleanup --node aNode\n\n";
1521 
1522     context = pcmk__build_arg_context(args, "text (default), xml", group, NULL);
1523     g_option_context_set_description(context, description);
1524 
1525     /* Add the -Q option, which cannot be part of the globally supported options
1526      * because some tools use that flag for something else.
1527      */
1528     pcmk__add_main_args(context, extra_prog_entries);
1529 
1530     pcmk__add_arg_group(context, "queries", "Queries:",
1531                         "Show query help", query_entries);
1532     pcmk__add_arg_group(context, "commands", "Commands:",
1533                         "Show command help", command_entries);
1534     pcmk__add_arg_group(context, "locations", "Locations:",
1535                         "Show location help", location_entries);
1536     pcmk__add_arg_group(context, "advanced", "Advanced:",
1537                         "Show advanced option help", advanced_entries);
1538     pcmk__add_arg_group(context, "additional", "Additional Options:",
1539                         "Show additional options", addl_entries);
1540     return context;
1541 }
1542 
1543 int
1544 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
1545 {
1546     xmlNode *cib_xml_copy = NULL;
1547     pe_resource_t *rsc = NULL;
1548     pe_node_t *node = NULL;
1549     int rc = pcmk_rc_ok;
1550 
1551     GOptionGroup *output_group = NULL;
1552     gchar **processed_args = NULL;
1553     GOptionContext *context = NULL;
1554 
1555     /*
1556      * Parse command line arguments
1557      */
1558 
1559     args = pcmk__new_common_args(SUMMARY);
1560     processed_args = pcmk__cmdline_preproc(argv, "GHINSTdginpstuvx");
1561     context = build_arg_context(args, &output_group);
1562 
1563     pcmk__register_formats(output_group, formats);
1564     if (!g_option_context_parse_strv(context, &processed_args, &error)) {
1565         exit_code = CRM_EX_USAGE;
1566         goto done;
1567     }
1568 
1569     pcmk__cli_init_logging("crm_resource", args->verbosity);
1570 
1571     rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
1572     if (rc != pcmk_rc_ok) {
1573         exit_code = CRM_EX_ERROR;
1574         g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Error creating output format %s: %s",
1575                     args->output_ty, pcmk_rc_str(rc));
1576         goto done;
1577     }
1578 
1579     pe__register_messages(out);
1580     crm_resource_register_messages(out);
1581     lrmd__register_messages(out);
1582     pcmk__register_lib_messages(out);
1583 
1584     out->quiet = args->quiet;
1585 
1586     crm_log_args(argc, argv);
1587 
1588     /*
1589      * Validate option combinations
1590      */
1591 
1592     // If the user didn't explicitly specify a command, list resources
1593     if (options.rsc_cmd == cmd_none) {
1594         options.rsc_cmd = cmd_list_resources;
1595         options.require_resource = FALSE;
1596     }
1597 
1598     // --expired without --clear/-U doesn't make sense
1599     if (options.clear_expired && (options.rsc_cmd != cmd_clear)) {
1600         exit_code = CRM_EX_USAGE;
1601         g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "--expired requires --clear or -U");
1602         goto done;
1603     }
1604 
1605     if ((options.remainder != NULL) && (options.override_params != NULL)) {
1606         // Commands that use positional arguments will create override_params
1607         for (gchar **s = options.remainder; *s; s++) {
1608             char *name = calloc(1, strlen(*s));
1609             char *value = calloc(1, strlen(*s));
1610             int rc = sscanf(*s, "%[^=]=%s", name, value);
1611 
1612             if (rc == 2) {
1613                 g_hash_table_replace(options.override_params, name, value);
1614 
1615             } else {
1616                 exit_code = CRM_EX_USAGE;
1617                 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
1618                             "Error parsing '%s' as a name=value pair",
1619                             argv[optind]);
1620                 free(value);
1621                 free(name);
1622                 goto done;
1623             }
1624         }
1625 
1626     } else if (options.remainder != NULL) {
1627         gchar **strv = NULL;
1628         gchar *msg = NULL;
1629         int i = 1;
1630         int len = 0;
1631 
1632         for (gchar **s = options.remainder; *s; s++) {
1633             len++;
1634         }
1635 
1636         CRM_ASSERT(len > 0);
1637 
1638         strv = calloc(len, sizeof(char *));
1639         strv[0] = strdup("non-option ARGV-elements:");
1640 
1641         for (gchar **s = options.remainder; *s; s++) {
1642             strv[i] = crm_strdup_printf("[%d of %d] %s\n", i, len, *s);
1643             i++;
1644         }
1645 
1646         exit_code = CRM_EX_USAGE;
1647         msg = g_strjoinv("", strv);
1648         g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "%s", msg);
1649         g_free(msg);
1650 
1651         for(i = 0; i < len; i++) {
1652             free(strv[i]);
1653         }
1654         free(strv);
1655 
1656         goto done;
1657     }
1658 
1659     if (pcmk__str_eq(args->output_ty, "xml", pcmk__str_none)) {
1660         /* Kind of a hack to display XML lists using a real tag instead of <list>.  This just
1661          * saves from having to write custom messages to build the lists around all these things
1662          */
1663         switch (options.rsc_cmd) {
1664             case cmd_execute_agent:
1665             case cmd_list_resources:
1666             case cmd_query_xml:
1667             case cmd_query_raw_xml:
1668             case cmd_list_active_ops:
1669             case cmd_list_all_ops:
1670             case cmd_colocations:
1671             case cmd_colocations_deep:
1672                 pcmk__force_args(context, &error, "%s --xml-simple-list --xml-substitute", g_get_prgname());
1673                 break;
1674 
1675             default:
1676                 pcmk__force_args(context, &error, "%s --xml-substitute", g_get_prgname());
1677                 break;
1678         }
1679     } else if (pcmk__str_eq(args->output_ty, "text", pcmk__str_null_matches)) {
1680         if (options.rsc_cmd == cmd_colocations || options.rsc_cmd == cmd_colocations_deep ||
1681             options.rsc_cmd == cmd_list_resources) {
1682             pcmk__force_args(context, &error, "%s --text-fancy", g_get_prgname());
1683         }
1684     }
1685 
1686     if (args->version) {
1687         out->version(out, false);
1688         goto done;
1689     }
1690 
1691     if (options.cmdline_config) {
1692         /* A resource configuration was given on the command line. Sanity-check
1693          * the values and set error if they don't make sense.
1694          */
1695         validate_cmdline_config();
1696         if (error != NULL) {
1697             exit_code = CRM_EX_USAGE;
1698             goto done;
1699         }
1700 
1701     } else if (options.cmdline_params != NULL) {
1702         // @COMPAT @TODO error out here when we can break backward compatibility
1703         g_hash_table_destroy(options.cmdline_params);
1704         options.cmdline_params = NULL;
1705     }
1706 
1707     if (options.require_resource && (options.rsc_id == NULL)) {
1708         exit_code = CRM_EX_USAGE;
1709         g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
1710                     "Must supply a resource id with -r");
1711         goto done;
1712     }
1713     if (options.require_node && (options.host_uname == NULL)) {
1714         exit_code = CRM_EX_USAGE;
1715         g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
1716                     "Must supply a node name with -N");
1717         goto done;
1718     }
1719 
1720     /*
1721      * Set up necessary connections
1722      */
1723 
1724     if (options.force) {
1725         crm_debug("Forcing...");
1726         cib__set_call_options(options.cib_options, crm_system_name,
1727                               cib_quorum_override);
1728     }
1729 
1730     if (options.find_flags && options.rsc_id) {
1731         options.require_dataset = TRUE;
1732     }
1733 
1734     // Establish a connection to the CIB if needed
1735     if (options.require_cib) {
1736         cib_conn = cib_new();
1737         if ((cib_conn == NULL) || (cib_conn->cmds == NULL)) {
1738             exit_code = CRM_EX_DISCONNECT;
1739             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
1740                         "Could not create CIB connection");
1741             goto done;
1742         }
1743         rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command);
1744         rc = pcmk_legacy2rc(rc);
1745         if (rc != pcmk_rc_ok) {
1746             exit_code = pcmk_rc2exitc(rc);
1747             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
1748                         "Could not connect to the CIB: %s", pcmk_rc_str(rc));
1749             goto done;
1750         }
1751     }
1752 
1753     /* Populate working set from XML file if specified or CIB query otherwise */
1754     if (options.require_dataset) {
1755         rc = populate_working_set(&cib_xml_copy);
1756         if (rc != pcmk_rc_ok) {
1757             exit_code = pcmk_rc2exitc(rc);
1758             goto done;
1759         }
1760     }
1761 
1762     // If command requires that resource exist if specified, find it
1763     if (options.find_flags && options.rsc_id) {
1764         rsc = pe_find_resource_with_flags(data_set->resources, options.rsc_id,
1765                                           options.find_flags);
1766         if (rsc == NULL) {
1767             exit_code = CRM_EX_NOSUCH;
1768             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
1769                         "Resource '%s' not found", options.rsc_id);
1770             goto done;
1771         }
1772     }
1773 
1774     // If user supplied a node name, check whether it exists
1775     if ((options.host_uname != NULL) && (data_set != NULL)) {
1776         node = pe_find_node(data_set->nodes, options.host_uname);
1777     }
1778 
1779     // Establish a connection to the controller if needed
1780     if (options.require_crmd) {
1781         rc = pcmk_new_ipc_api(&controld_api, pcmk_ipc_controld);
1782         if (rc != pcmk_rc_ok) {
1783             exit_code = pcmk_rc2exitc(rc);
1784             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
1785                         "Error connecting to the controller: %s", pcmk_rc_str(rc));
1786             goto done;
1787         }
1788         pcmk_register_ipc_callback(controld_api, controller_event_callback,
1789                                    NULL);
1790         rc = pcmk_connect_ipc(controld_api, pcmk_ipc_dispatch_main);
1791         if (rc != pcmk_rc_ok) {
1792             exit_code = pcmk_rc2exitc(rc);
1793             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
1794                         "Error connecting to the controller: %s", pcmk_rc_str(rc));
1795             goto done;
1796         }
1797     }
1798 
1799     /*
1800      * Handle requested command
1801      */
1802 
1803     switch (options.rsc_cmd) {
1804         case cmd_list_resources: {
1805             GList *all = NULL;
1806             all = g_list_prepend(all, (gpointer) "*");
1807             rc = out->message(out, "resource-list", data_set,
1808                               pcmk_show_inactive_rscs | pcmk_show_rsc_only | pcmk_show_pending,
1809                               TRUE, all, all, FALSE);
1810             g_list_free(all);
1811 
1812             if (rc == pcmk_rc_no_output) {
1813                 rc = ENXIO;
1814             }
1815             break;
1816         }
1817 
1818         case cmd_list_instances:
1819             rc = out->message(out, "resource-names-list", data_set->resources);
1820 
1821             if (rc != pcmk_rc_ok) {
1822                 rc = ENXIO;
1823             }
1824 
1825             break;
1826 
1827         case cmd_list_standards:
1828         case cmd_list_providers:
1829         case cmd_list_alternatives:
1830             rc = list_providers(out, options.agent_spec);
1831             break;
1832 
1833         case cmd_list_agents:
1834             rc = list_agents(out, options.agent_spec);
1835             break;
1836 
1837         case cmd_metadata:
1838             rc = show_metadata(out, options.agent_spec);
1839             break;
1840 
1841         case cmd_restart:
1842             /* We don't pass data_set because rsc needs to stay valid for the
1843              * entire lifetime of cli_resource_restart(), but it will reset and
1844              * update the working set multiple times, so it needs to use its own
1845              * copy.
1846              */
1847             rc = cli_resource_restart(out, rsc, options.host_uname,
1848                                       options.move_lifetime, options.timeout_ms,
1849                                       cib_conn, options.cib_options,
1850                                       options.promoted_role_only,
1851                                       options.force);
1852             break;
1853 
1854         case cmd_wait:
1855             rc = wait_till_stable(out, options.timeout_ms, cib_conn);
1856             break;
1857 
1858         case cmd_execute_agent:
1859             if (options.cmdline_config) {
1860                 exit_code = cli_resource_execute_from_params(out, NULL,
1861                     options.v_class, options.v_provider, options.v_agent,
1862                     options.operation, options.cmdline_params,
1863                     options.override_params, options.timeout_ms,
1864                     args->verbosity, options.force, options.check_level);
1865             } else {
1866                 exit_code = cli_resource_execute(rsc, options.rsc_id,
1867                     options.operation, options.override_params,
1868                     options.timeout_ms, cib_conn, data_set,
1869                     args->verbosity, options.force, options.check_level);
1870             }
1871             goto done;
1872 
1873         case cmd_digests:
1874             node = pe_find_node(data_set->nodes, options.host_uname);
1875             if (node == NULL) {
1876                 rc = pcmk_rc_node_unknown;
1877             } else {
1878                 rc = pcmk__resource_digests(out, rsc, node,
1879                                             options.override_params, data_set);
1880             }
1881             break;
1882 
1883         case cmd_colocations:
1884             rc = out->message(out, "stacks-constraints", rsc, data_set, false);
1885             break;
1886 
1887         case cmd_colocations_deep:
1888             rc = out->message(out, "stacks-constraints", rsc, data_set, true);
1889             break;
1890 
1891         case cmd_cts:
1892             rc = pcmk_rc_ok;
1893             g_list_foreach(data_set->resources, (GFunc) cli_resource_print_cts, out);
1894             cli_resource_print_cts_constraints(data_set);
1895             break;
1896 
1897         case cmd_fail:
1898             rc = cli_resource_fail(controld_api, options.host_uname,
1899                                    options.rsc_id, data_set);
1900             if (rc == pcmk_rc_ok) {
1901                 start_mainloop(controld_api);
1902             }
1903             break;
1904 
1905         case cmd_list_active_ops:
1906             rc = cli_resource_print_operations(options.rsc_id,
1907                                                options.host_uname, TRUE,
1908                                                data_set);
1909             break;
1910 
1911         case cmd_list_all_ops:
1912             rc = cli_resource_print_operations(options.rsc_id,
1913                                                options.host_uname, FALSE,
1914                                                data_set);
1915             break;
1916 
1917         case cmd_locate: {
1918             GList *nodes = cli_resource_search(rsc, options.rsc_id, data_set);
1919             rc = out->message(out, "resource-search-list", nodes, options.rsc_id);
1920             g_list_free_full(nodes, free);
1921             break;
1922         }
1923 
1924         case cmd_query_xml:
1925             rc = cli_resource_print(rsc, data_set, TRUE);
1926             break;
1927 
1928         case cmd_query_raw_xml:
1929             rc = cli_resource_print(rsc, data_set, FALSE);
1930             break;
1931 
1932         case cmd_why:
1933             if ((options.host_uname != NULL) && (node == NULL)) {
1934                 rc = pcmk_rc_node_unknown;
1935             } else {
1936                 rc = out->message(out, "resource-reasons-list", cib_conn,
1937                                   data_set->resources, rsc, node);
1938             }
1939             break;
1940 
1941         case cmd_clear:
1942             rc = clear_constraints(out, &cib_xml_copy);
1943             break;
1944 
1945         case cmd_move:
1946             if (options.host_uname == NULL) {
1947                 rc = ban_or_move(out, rsc, options.move_lifetime);
1948             } else {
1949                 rc = cli_resource_move(rsc, options.rsc_id, options.host_uname,
1950                                        options.move_lifetime, cib_conn,
1951                                        options.cib_options, data_set,
1952                                        options.promoted_role_only,
1953                                        options.force);
1954             }
1955 
1956             if (rc == EINVAL) {
1957                 exit_code = CRM_EX_USAGE;
1958                 goto done;
1959             }
1960 
1961             break;
1962 
1963         case cmd_ban:
1964             if (options.host_uname == NULL) {
1965                 rc = ban_or_move(out, rsc, options.move_lifetime);
1966             } else if (node == NULL) {
1967                 rc = pcmk_rc_node_unknown;
1968             } else {
1969                 rc = cli_resource_ban(out, options.rsc_id, node->details->uname,
1970                                       options.move_lifetime, NULL, cib_conn,
1971                                       options.cib_options,
1972                                       options.promoted_role_only);
1973             }
1974 
1975             if (rc == EINVAL) {
1976                 exit_code = CRM_EX_USAGE;
1977                 goto done;
1978             }
1979 
1980             break;
1981 
1982         case cmd_get_property:
1983             rc = out->message(out, "property-list", rsc, options.prop_name);
1984             if (rc == pcmk_rc_no_output) {
1985                 rc = ENXIO;
1986             }
1987 
1988             break;
1989 
1990         case cmd_set_property:
1991             rc = set_property();
1992             break;
1993 
1994         case cmd_get_param: {
1995             unsigned int count = 0;
1996             GHashTable *params = NULL;
1997             pe_node_t *current = pe__find_active_on(rsc, &count, NULL);
1998             bool free_params = true;
1999 
2000             if (count > 1) {
2001                 out->err(out, "%s is active on more than one node,"
2002                          " returning the default value for %s", rsc->id, crm_str(options.prop_name));
2003                 current = NULL;
2004             }
2005 
2006             crm_debug("Looking up %s in %s", options.prop_name, rsc->id);
2007 
2008             if (pcmk__str_eq(options.attr_set_type, XML_TAG_ATTR_SETS, pcmk__str_casei)) {
2009                 params = pe_rsc_params(rsc, current, data_set);
2010                 free_params = false;
2011 
2012             } else if (pcmk__str_eq(options.attr_set_type, XML_TAG_META_SETS, pcmk__str_casei)) {
2013                 params = pcmk__strkey_table(free, free);
2014                 get_meta_attributes(params, rsc, current, data_set);
2015 
2016             } else {
2017                 params = pcmk__strkey_table(free, free);
2018                 pe__unpack_dataset_nvpairs(rsc->xml, XML_TAG_UTILIZATION, NULL, params,
2019                                            NULL, FALSE, data_set);
2020             }
2021 
2022             rc = out->message(out, "attribute-list", rsc, options.prop_name, params);
2023             if (free_params) {
2024                 g_hash_table_destroy(params);
2025             }
2026             break;
2027         }
2028 
2029         case cmd_set_param:
2030             if (pcmk__str_empty(options.prop_value)) {
2031                 exit_code = CRM_EX_USAGE;
2032                 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
2033                             "You need to supply a value with the -v option");
2034                 goto done;
2035             }
2036 
2037             /* coverity[var_deref_model] False positive */
2038             rc = cli_resource_update_attribute(rsc, options.rsc_id,
2039                                                options.prop_set,
2040                                                options.attr_set_type,
2041                                                options.prop_id,
2042                                                options.prop_name,
2043                                                options.prop_value,
2044                                                options.recursive, cib_conn,
2045                                                options.cib_options, data_set,
2046                                                options.force);
2047             break;
2048 
2049         case cmd_delete_param:
2050             /* coverity[var_deref_model] False positive */
2051             rc = cli_resource_delete_attribute(rsc, options.rsc_id,
2052                                                options.prop_set,
2053                                                options.attr_set_type,
2054                                                options.prop_id,
2055                                                options.prop_name, cib_conn,
2056                                                options.cib_options, data_set,
2057                                                options.force);
2058             break;
2059 
2060         case cmd_cleanup:
2061             if (rsc == NULL) {
2062                 rc = cli_cleanup_all(controld_api, options.host_uname,
2063                                      options.operation, options.interval_spec,
2064                                      data_set);
2065                 if (rc == pcmk_rc_ok) {
2066                     start_mainloop(controld_api);
2067                 }
2068             } else {
2069                 cleanup(out, rsc);
2070             }
2071             break;
2072 
2073         case cmd_refresh:
2074             if (rsc == NULL) {
2075                 rc = refresh(out);
2076             } else {
2077                 refresh_resource(out, rsc);
2078             }
2079             break;
2080 
2081         case cmd_delete:
2082             rc = delete();
2083             break;
2084 
2085         default:
2086             exit_code = CRM_EX_USAGE;
2087             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
2088                         "Unimplemented command: %d", (int) options.rsc_cmd);
2089             goto done;
2090     }
2091 
2092     /* Convert rc into an exit code. */
2093     if (rc != pcmk_rc_ok && rc != pcmk_rc_no_output) {
2094         if (rc == pcmk_rc_no_quorum) {
2095             g_prefix_error(&error, "To ignore quorum, use the force option.\n");
2096         }
2097 
2098         exit_code = pcmk_rc2exitc(rc);
2099     }
2100 
2101     /*
2102      * Clean up and exit
2103      */
2104 
2105 done:
2106     /* When we get here, exit_code has been set one of two ways - either at one of
2107      * the spots where there's a "goto done" (which itself could have happened either
2108      * directly or by calling pcmk_rc2exitc), or just up above after any of the break
2109      * statements.
2110      *
2111      * Thus, we can use just exit_code here to decide what to do.
2112      */
2113     if (exit_code != CRM_EX_OK && exit_code != CRM_EX_USAGE) {
2114         if (error != NULL) {
2115             char *msg = crm_strdup_printf("%s\nError performing operation: %s",
2116                                           error->message, crm_exit_str(exit_code));
2117             g_clear_error(&error);
2118             g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "%s", msg);
2119             free(msg);
2120         } else {
2121             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
2122                         "Error performing operation: %s", crm_exit_str(exit_code));
2123         }
2124     }
2125 
2126     g_free(options.host_uname);
2127     g_free(options.interval_spec);
2128     g_free(options.move_lifetime);
2129     g_free(options.operation);
2130     g_free(options.prop_id);
2131     free(options.prop_name);
2132     g_free(options.prop_set);
2133     g_free(options.prop_value);
2134     g_free(options.rsc_id);
2135     g_free(options.rsc_type);
2136     free(options.agent_spec);
2137     free(options.v_agent);
2138     free(options.v_class);
2139     free(options.v_provider);
2140     g_free(options.xml_file);
2141     g_strfreev(options.remainder);
2142 
2143     if (options.override_params != NULL) {
2144         g_hash_table_destroy(options.override_params);
2145     }
2146 
2147     /* options.cmdline_params does not need to be destroyed here.  See the
2148      * comments in cli_resource_execute_from_params.
2149      */
2150 
2151     g_strfreev(processed_args);
2152     g_option_context_free(context);
2153 
2154     return bye(exit_code);
2155 }

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