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 = lrmd_api_new();
1136     lrmd_list_t *list = NULL;
1137 
1138     if (provider) {
1139         *provider++ = 0;
1140     }
1141 
1142     rc = lrmd_conn->cmds->list_agents(lrmd_conn, &list, agent_spec, provider);
1143 
1144     if (rc > 0) {
1145         rc = out->message(out, "agents-list", list, agent_spec, provider);
1146     } else {
1147         rc = pcmk_rc_error;
1148     }
1149 
1150     if (rc != pcmk_rc_ok) {
1151         if (provider == NULL) {
1152             g_set_error(&error, PCMK__RC_ERROR, rc,
1153                         "No agents found for standard '%s'", agent_spec);
1154         } else {
1155             g_set_error(&error, PCMK__RC_ERROR, rc,
1156                         "No agents found for standard '%s' and provider '%s'",
1157                         agent_spec, provider);
1158         }
1159     }
1160 
1161     lrmd_api_delete(lrmd_conn);
1162     return rc;
1163 }
1164 
1165 static int
1166 list_providers(pcmk__output_t *out, const char *agent_spec)
     /* [previous][next][first][last][top][bottom][index][help] */
1167 {
1168     int rc;
1169     const char *text = NULL;
1170     lrmd_t *lrmd_conn = lrmd_api_new();
1171     lrmd_list_t *list = NULL;
1172 
1173     switch (options.rsc_cmd) {
1174         case cmd_list_alternatives:
1175             rc = lrmd_conn->cmds->list_ocf_providers(lrmd_conn, agent_spec, &list);
1176 
1177             if (rc > 0) {
1178                 rc = out->message(out, "alternatives-list", list, agent_spec);
1179             } else {
1180                 rc = pcmk_rc_error;
1181             }
1182 
1183             text = "OCF providers";
1184             break;
1185         case cmd_list_standards:
1186             rc = lrmd_conn->cmds->list_standards(lrmd_conn, &list);
1187 
1188             if (rc > 0) {
1189                 rc = out->message(out, "standards-list", list);
1190             } else {
1191                 rc = pcmk_rc_error;
1192             }
1193 
1194             text = "standards";
1195             break;
1196         case cmd_list_providers:
1197             rc = lrmd_conn->cmds->list_ocf_providers(lrmd_conn, agent_spec, &list);
1198 
1199             if (rc > 0) {
1200                 rc = out->message(out, "providers-list", list, agent_spec);
1201             } else {
1202                 rc = pcmk_rc_error;
1203             }
1204 
1205             text = "OCF providers";
1206             break;
1207         default:
1208             g_set_error(&error, PCMK__RC_ERROR, pcmk_rc_error, "Bug");
1209             lrmd_api_delete(lrmd_conn);
1210             return pcmk_rc_error;
1211     }
1212 
1213     if (rc != pcmk_rc_ok) {
1214         if (agent_spec != NULL) {
1215             rc = ENXIO;
1216             g_set_error(&error, PCMK__RC_ERROR, rc,
1217                         "No %s found for %s", text, agent_spec);
1218 
1219         } else {
1220             rc = ENXIO;
1221             g_set_error(&error, PCMK__RC_ERROR, rc,
1222                         "No %s found", text);
1223         }
1224     }
1225 
1226     lrmd_api_delete(lrmd_conn);
1227     return rc;
1228 }
1229 
1230 static int
1231 populate_working_set(xmlNodePtr *cib_xml_copy)
     /* [previous][next][first][last][top][bottom][index][help] */
1232 {
1233     int rc = pcmk_rc_ok;
1234 
1235     if (options.xml_file != NULL) {
1236         *cib_xml_copy = filename2xml(options.xml_file);
1237         if (*cib_xml_copy == NULL) {
1238             rc = pcmk_rc_cib_corrupt;
1239         }
1240     } else {
1241         rc = cib_conn->cmds->query(cib_conn, NULL, cib_xml_copy, cib_scope_local | cib_sync_call);
1242         rc = pcmk_legacy2rc(rc);
1243     }
1244 
1245     if (rc == pcmk_rc_ok) {
1246         data_set = pe_new_working_set();
1247         if (data_set == NULL) {
1248             rc = ENOMEM;
1249         } else {
1250             pe__set_working_set_flags(data_set,
1251                                       pe_flag_no_counts|pe_flag_no_compat);
1252             data_set->priv = out;
1253             rc = update_working_set_xml(data_set, cib_xml_copy);
1254         }
1255     }
1256 
1257     if (rc != pcmk_rc_ok) {
1258         free_xml(*cib_xml_copy);
1259         *cib_xml_copy = NULL;
1260         return rc;
1261     }
1262 
1263     cluster_status(data_set);
1264     return pcmk_rc_ok;
1265 }
1266 
1267 static int
1268 refresh(pcmk__output_t *out)
     /* [previous][next][first][last][top][bottom][index][help] */
1269 {
1270     int rc = pcmk_rc_ok;
1271     const char *router_node = options.host_uname;
1272     int attr_options = pcmk__node_attr_none;
1273 
1274     if (options.host_uname) {
1275         pe_node_t *node = pe_find_node(data_set->nodes, options.host_uname);
1276 
1277         if (pe__is_guest_or_remote_node(node)) {
1278             node = pe__current_node(node->details->remote_rsc);
1279             if (node == NULL) {
1280                 rc = ENXIO;
1281                 g_set_error(&error, PCMK__RC_ERROR, rc,
1282                             "No cluster connection to Pacemaker Remote node %s detected",
1283                             options.host_uname);
1284                 return rc;
1285             }
1286             router_node = node->details->uname;
1287             attr_options |= pcmk__node_attr_remote;
1288         }
1289     }
1290 
1291     if (controld_api == NULL) {
1292         out->info(out, "Dry run: skipping clean-up of %s due to CIB_file",
1293                   options.host_uname? options.host_uname : "all nodes");
1294         rc = pcmk_rc_ok;
1295         return rc;
1296     }
1297 
1298     crm_debug("Re-checking the state of all resources on %s", options.host_uname?options.host_uname:"all nodes");
1299 
1300     rc = pcmk__node_attr_request_clear(NULL, options.host_uname,
1301                                        NULL, NULL, NULL,
1302                                        NULL, attr_options);
1303 
1304     if (pcmk_controld_api_reprobe(controld_api, options.host_uname,
1305                                   router_node) == pcmk_rc_ok) {
1306         start_mainloop(controld_api);
1307     }
1308 
1309     return rc;
1310 }
1311 
1312 static void
1313 refresh_resource(pcmk__output_t *out, pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
1314 {
1315     int rc = pcmk_rc_ok;
1316 
1317     if (options.force == FALSE) {
1318         rsc = uber_parent(rsc);
1319     }
1320 
1321     crm_debug("Re-checking the state of %s (%s requested) on %s",
1322               rsc->id, options.rsc_id, (options.host_uname? options.host_uname: "all nodes"));
1323     rc = cli_resource_delete(controld_api, options.host_uname, rsc, NULL,
1324                              0, FALSE, data_set, options.force);
1325 
1326     if ((rc == pcmk_rc_ok) && !out->is_quiet(out)) {
1327         // Show any reasons why resource might stay stopped
1328         cli_resource_check(out, cib_conn, rsc);
1329     }
1330 
1331     if (rc == pcmk_rc_ok) {
1332         start_mainloop(controld_api);
1333     }
1334 }
1335 
1336 static int
1337 set_property(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1338 {
1339     int rc = pcmk_rc_ok;
1340     xmlNode *msg_data = NULL;
1341 
1342     if (pcmk__str_empty(options.rsc_type)) {
1343         g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_USAGE,
1344                     "Must specify -t with resource type");
1345         rc = ENXIO;
1346         return rc;
1347 
1348     } else if (pcmk__str_empty(options.prop_value)) {
1349         g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_USAGE,
1350                     "Must supply -v with new value");
1351         rc = ENXIO;
1352         return rc;
1353     }
1354 
1355     CRM_LOG_ASSERT(options.prop_name != NULL);
1356 
1357     msg_data = create_xml_node(NULL, options.rsc_type);
1358     crm_xml_add(msg_data, XML_ATTR_ID, options.rsc_id);
1359     crm_xml_add(msg_data, options.prop_name, options.prop_value);
1360 
1361     rc = cib_conn->cmds->modify(cib_conn, XML_CIB_TAG_RESOURCES, msg_data,
1362                                 options.cib_options);
1363     rc = pcmk_legacy2rc(rc);
1364     free_xml(msg_data);
1365 
1366     return rc;
1367 }
1368 
1369 static int
1370 show_metadata(pcmk__output_t *out, const char *agent_spec)
     /* [previous][next][first][last][top][bottom][index][help] */
1371 {
1372     int rc = pcmk_rc_ok;
1373     char *standard = NULL;
1374     char *provider = NULL;
1375     char *type = NULL;
1376     char *metadata = NULL;
1377     lrmd_t *lrmd_conn = lrmd_api_new();
1378 
1379     rc = crm_parse_agent_spec(agent_spec, &standard, &provider, &type);
1380     rc = pcmk_legacy2rc(rc);
1381 
1382     if (rc == pcmk_rc_ok) {
1383         rc = lrmd_conn->cmds->get_metadata(lrmd_conn, standard,
1384                                            provider, type,
1385                                            &metadata, 0);
1386         rc = pcmk_legacy2rc(rc);
1387 
1388         if (metadata) {
1389             out->output_xml(out, "metadata", metadata);
1390         } else {
1391             /* We were given a validly formatted spec, but it doesn't necessarily
1392              * match up with anything that exists.  Use ENXIO as the return code
1393              * here because that maps to an exit code of CRM_EX_NOSUCH, which
1394              * probably is the most common reason to get here.
1395              */
1396             rc = ENXIO;
1397             g_set_error(&error, PCMK__RC_ERROR, rc,
1398                         "Metadata query for %s failed: %s",
1399                         agent_spec, pcmk_rc_str(rc));
1400         }
1401     } else {
1402         rc = ENXIO;
1403         g_set_error(&error, PCMK__RC_ERROR, rc,
1404                     "'%s' is not a valid agent specification", agent_spec);
1405     }
1406 
1407     lrmd_api_delete(lrmd_conn);
1408     return rc;
1409 }
1410 
1411 static void
1412 validate_cmdline_config(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1413 {
1414     // Cannot use both --resource and command-line resource configuration
1415     if (options.rsc_id != NULL) {
1416         g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_USAGE,
1417                     "--resource cannot be used with --class, --agent, and --provider");
1418 
1419     // Not all commands support command-line resource configuration
1420     } else if (options.rsc_cmd != cmd_execute_agent) {
1421         g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_USAGE,
1422                     "--class, --agent, and --provider can only be used with "
1423                     "--validate and --force-*");
1424 
1425     // Not all of --class, --agent, and --provider need to be given.  Not all
1426     // classes support the concept of a provider.  Check that what we were given
1427     // is valid.
1428     } else if (pcmk__str_eq(options.v_class, "stonith", pcmk__str_none)) {
1429         if (options.v_provider != NULL) {
1430             g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_USAGE,
1431                         "stonith does not support providers");
1432 
1433         } else if (stonith_agent_exists(options.v_agent, 0) == FALSE) {
1434             g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_USAGE,
1435                         "%s is not a known stonith agent", options.v_agent ? options.v_agent : "");
1436         }
1437 
1438     } else if (resources_agent_exists(options.v_class, options.v_provider, options.v_agent) == FALSE) {
1439         g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_USAGE,
1440                     "%s:%s:%s is not a known resource",
1441                     options.v_class ? options.v_class : "",
1442                     options.v_provider ? options.v_provider : "",
1443                     options.v_agent ? options.v_agent : "");
1444     }
1445 
1446     if (error != NULL) {
1447         return;
1448     }
1449 
1450     if (options.cmdline_params == NULL) {
1451         options.cmdline_params = pcmk__strkey_table(free, free);
1452     }
1453     options.require_resource = FALSE;
1454     options.require_dataset = FALSE;
1455     options.require_cib = FALSE;
1456 }
1457 
1458 static GOptionContext *
1459 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
     /* [previous][next][first][last][top][bottom][index][help] */
1460     GOptionContext *context = NULL;
1461 
1462     GOptionEntry extra_prog_entries[] = {
1463         { "quiet", 'Q', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &(args->quiet),
1464           "Be less descriptive in output.",
1465           NULL },
1466         { "resource", 'r', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &options.rsc_id,
1467           "Resource ID",
1468           "ID" },
1469         { G_OPTION_REMAINING, 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING_ARRAY, &options.remainder,
1470           NULL,
1471           NULL },
1472 
1473         { NULL }
1474     };
1475 
1476     const char *description = "Examples:\n\n"
1477                               "List the available OCF agents:\n\n"
1478                               "\t# crm_resource --list-agents ocf\n\n"
1479                               "List the available OCF agents from the linux-ha project:\n\n"
1480                               "\t# crm_resource --list-agents ocf:heartbeat\n\n"
1481                               "Move 'myResource' to a specific node:\n\n"
1482                               "\t# crm_resource --resource myResource --move --node altNode\n\n"
1483                               "Allow (but not force) 'myResource' to move back to its original "
1484                               "location:\n\n"
1485                               "\t# crm_resource --resource myResource --clear\n\n"
1486                               "Stop 'myResource' (and anything that depends on it):\n\n"
1487                               "\t# crm_resource --resource myResource --set-parameter target-role "
1488                               "--meta --parameter-value Stopped\n\n"
1489                               "Tell the cluster not to manage 'myResource' (the cluster will not "
1490                               "attempt to start or stop the\n"
1491                               "resource under any circumstances; useful when performing maintenance "
1492                               "tasks on a resource):\n\n"
1493                               "\t# crm_resource --resource myResource --set-parameter is-managed "
1494                               "--meta --parameter-value false\n\n"
1495                               "Erase the operation history of 'myResource' on 'aNode' (the cluster "
1496                               "will 'forget' the existing\n"
1497                               "resource state, including any errors, and attempt to recover the"
1498                               "resource; useful when a resource\n"
1499                               "had failed permanently and has been repaired by an administrator):\n\n"
1500                               "\t# crm_resource --resource myResource --cleanup --node aNode\n\n";
1501 
1502     context = pcmk__build_arg_context(args, "text (default), xml", group, NULL);
1503     g_option_context_set_description(context, description);
1504 
1505     /* Add the -Q option, which cannot be part of the globally supported options
1506      * because some tools use that flag for something else.
1507      */
1508     pcmk__add_main_args(context, extra_prog_entries);
1509 
1510     pcmk__add_arg_group(context, "queries", "Queries:",
1511                         "Show query help", query_entries);
1512     pcmk__add_arg_group(context, "commands", "Commands:",
1513                         "Show command help", command_entries);
1514     pcmk__add_arg_group(context, "locations", "Locations:",
1515                         "Show location help", location_entries);
1516     pcmk__add_arg_group(context, "advanced", "Advanced:",
1517                         "Show advanced option help", advanced_entries);
1518     pcmk__add_arg_group(context, "additional", "Additional Options:",
1519                         "Show additional options", addl_entries);
1520     return context;
1521 }
1522 
1523 int
1524 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
1525 {
1526     xmlNode *cib_xml_copy = NULL;
1527     pe_resource_t *rsc = NULL;
1528     pe_node_t *node = NULL;
1529     int rc = pcmk_rc_ok;
1530 
1531     GOptionGroup *output_group = NULL;
1532     gchar **processed_args = NULL;
1533     GOptionContext *context = NULL;
1534 
1535     /*
1536      * Parse command line arguments
1537      */
1538 
1539     args = pcmk__new_common_args(SUMMARY);
1540     processed_args = pcmk__cmdline_preproc(argv, "GHINSTdginpstuvx");
1541     context = build_arg_context(args, &output_group);
1542 
1543     pcmk__register_formats(output_group, formats);
1544     if (!g_option_context_parse_strv(context, &processed_args, &error)) {
1545         exit_code = CRM_EX_USAGE;
1546         goto done;
1547     }
1548 
1549     pcmk__cli_init_logging("crm_resource", args->verbosity);
1550 
1551     rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
1552     if (rc != pcmk_rc_ok) {
1553         exit_code = CRM_EX_ERROR;
1554         g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Error creating output format %s: %s",
1555                     args->output_ty, pcmk_rc_str(rc));
1556         goto done;
1557     }
1558 
1559     pe__register_messages(out);
1560     crm_resource_register_messages(out);
1561     lrmd__register_messages(out);
1562     pcmk__register_lib_messages(out);
1563 
1564     out->quiet = args->quiet;
1565 
1566     crm_log_args(argc, argv);
1567 
1568     /*
1569      * Validate option combinations
1570      */
1571 
1572     // If the user didn't explicitly specify a command, list resources
1573     if (options.rsc_cmd == cmd_none) {
1574         options.rsc_cmd = cmd_list_resources;
1575         options.require_resource = FALSE;
1576     }
1577 
1578     // --expired without --clear/-U doesn't make sense
1579     if (options.clear_expired && (options.rsc_cmd != cmd_clear)) {
1580         exit_code = CRM_EX_USAGE;
1581         g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "--expired requires --clear or -U");
1582         goto done;
1583     }
1584 
1585     if ((options.remainder != NULL) && (options.override_params != NULL)) {
1586         // Commands that use positional arguments will create override_params
1587         for (gchar **s = options.remainder; *s; s++) {
1588             char *name = calloc(1, strlen(*s));
1589             char *value = calloc(1, strlen(*s));
1590             int rc = sscanf(*s, "%[^=]=%s", name, value);
1591 
1592             if (rc == 2) {
1593                 g_hash_table_replace(options.override_params, name, value);
1594 
1595             } else {
1596                 exit_code = CRM_EX_USAGE;
1597                 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
1598                             "Error parsing '%s' as a name=value pair",
1599                             argv[optind]);
1600                 free(value);
1601                 free(name);
1602                 goto done;
1603             }
1604         }
1605 
1606     } else if (options.remainder != NULL) {
1607         gchar **strv = NULL;
1608         gchar *msg = NULL;
1609         int i = 1;
1610         int len = 0;
1611 
1612         for (gchar **s = options.remainder; *s; s++) {
1613             len++;
1614         }
1615 
1616         CRM_ASSERT(len > 0);
1617 
1618         strv = calloc(len, sizeof(char *));
1619         strv[0] = strdup("non-option ARGV-elements:");
1620 
1621         for (gchar **s = options.remainder; *s; s++) {
1622             strv[i] = crm_strdup_printf("[%d of %d] %s\n", i, len, *s);
1623             i++;
1624         }
1625 
1626         exit_code = CRM_EX_USAGE;
1627         msg = g_strjoinv("", strv);
1628         g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "%s", msg);
1629         g_free(msg);
1630 
1631         for(i = 0; i < len; i++) {
1632             free(strv[i]);
1633         }
1634         free(strv);
1635 
1636         goto done;
1637     }
1638 
1639     if (pcmk__str_eq(args->output_ty, "xml", pcmk__str_none)) {
1640         /* Kind of a hack to display XML lists using a real tag instead of <list>.  This just
1641          * saves from having to write custom messages to build the lists around all these things
1642          */
1643         switch (options.rsc_cmd) {
1644             case cmd_execute_agent:
1645             case cmd_list_resources:
1646             case cmd_query_xml:
1647             case cmd_query_raw_xml:
1648             case cmd_list_active_ops:
1649             case cmd_list_all_ops:
1650             case cmd_colocations:
1651             case cmd_colocations_deep:
1652                 pcmk__force_args(context, &error, "%s --xml-simple-list --xml-substitute", g_get_prgname());
1653                 break;
1654 
1655             default:
1656                 pcmk__force_args(context, &error, "%s --xml-substitute", g_get_prgname());
1657                 break;
1658         }
1659     } else if (pcmk__str_eq(args->output_ty, "text", pcmk__str_null_matches)) {
1660         if (options.rsc_cmd == cmd_colocations || options.rsc_cmd == cmd_colocations_deep ||
1661             options.rsc_cmd == cmd_list_resources) {
1662             pcmk__force_args(context, &error, "%s --text-fancy", g_get_prgname());
1663         }
1664     }
1665 
1666     if (args->version) {
1667         out->version(out, false);
1668         goto done;
1669     }
1670 
1671     if (options.cmdline_config) {
1672         /* A resource configuration was given on the command line. Sanity-check
1673          * the values and set error if they don't make sense.
1674          */
1675         validate_cmdline_config();
1676         if (error != NULL) {
1677             exit_code = CRM_EX_USAGE;
1678             goto done;
1679         }
1680 
1681     } else if (options.cmdline_params != NULL) {
1682         // @COMPAT @TODO error out here when we can break backward compatibility
1683         g_hash_table_destroy(options.cmdline_params);
1684         options.cmdline_params = NULL;
1685     }
1686 
1687     if (options.require_resource && (options.rsc_id == NULL)) {
1688         exit_code = CRM_EX_USAGE;
1689         g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
1690                     "Must supply a resource id with -r");
1691         goto done;
1692     }
1693     if (options.require_node && (options.host_uname == NULL)) {
1694         exit_code = CRM_EX_USAGE;
1695         g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
1696                     "Must supply a node name with -N");
1697         goto done;
1698     }
1699 
1700     /*
1701      * Set up necessary connections
1702      */
1703 
1704     if (options.force) {
1705         crm_debug("Forcing...");
1706         cib__set_call_options(options.cib_options, crm_system_name,
1707                               cib_quorum_override);
1708     }
1709 
1710     if (options.find_flags && options.rsc_id) {
1711         options.require_dataset = TRUE;
1712     }
1713 
1714     // Establish a connection to the CIB if needed
1715     if (options.require_cib) {
1716         cib_conn = cib_new();
1717         if ((cib_conn == NULL) || (cib_conn->cmds == NULL)) {
1718             exit_code = CRM_EX_DISCONNECT;
1719             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
1720                         "Could not create CIB connection");
1721             goto done;
1722         }
1723         rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command);
1724         rc = pcmk_legacy2rc(rc);
1725         if (rc != pcmk_rc_ok) {
1726             exit_code = pcmk_rc2exitc(rc);
1727             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
1728                         "Could not connect to the CIB: %s", pcmk_rc_str(rc));
1729             goto done;
1730         }
1731     }
1732 
1733     /* Populate working set from XML file if specified or CIB query otherwise */
1734     if (options.require_dataset) {
1735         rc = populate_working_set(&cib_xml_copy);
1736         if (rc != pcmk_rc_ok) {
1737             exit_code = pcmk_rc2exitc(rc);
1738             goto done;
1739         }
1740     }
1741 
1742     // If command requires that resource exist if specified, find it
1743     if (options.find_flags && options.rsc_id) {
1744         rsc = pe_find_resource_with_flags(data_set->resources, options.rsc_id,
1745                                           options.find_flags);
1746         if (rsc == NULL) {
1747             exit_code = CRM_EX_NOSUCH;
1748             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
1749                         "Resource '%s' not found", options.rsc_id);
1750             goto done;
1751         }
1752     }
1753 
1754     // If user supplied a node name, check whether it exists
1755     if ((options.host_uname != NULL) && (data_set != NULL)) {
1756         node = pe_find_node(data_set->nodes, options.host_uname);
1757     }
1758 
1759     // Establish a connection to the controller if needed
1760     if (options.require_crmd) {
1761         rc = pcmk_new_ipc_api(&controld_api, pcmk_ipc_controld);
1762         if (rc != pcmk_rc_ok) {
1763             exit_code = pcmk_rc2exitc(rc);
1764             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
1765                         "Error connecting to the controller: %s", pcmk_rc_str(rc));
1766             goto done;
1767         }
1768         pcmk_register_ipc_callback(controld_api, controller_event_callback,
1769                                    NULL);
1770         rc = pcmk_connect_ipc(controld_api, pcmk_ipc_dispatch_main);
1771         if (rc != pcmk_rc_ok) {
1772             exit_code = pcmk_rc2exitc(rc);
1773             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
1774                         "Error connecting to the controller: %s", pcmk_rc_str(rc));
1775             goto done;
1776         }
1777     }
1778 
1779     /*
1780      * Handle requested command
1781      */
1782 
1783     switch (options.rsc_cmd) {
1784         case cmd_list_resources: {
1785             GList *all = NULL;
1786             all = g_list_prepend(all, (gpointer) "*");
1787             rc = out->message(out, "resource-list", data_set,
1788                               pcmk_show_inactive_rscs | pcmk_show_rsc_only | pcmk_show_pending,
1789                               TRUE, all, all, FALSE);
1790             g_list_free(all);
1791 
1792             if (rc == pcmk_rc_no_output) {
1793                 rc = ENXIO;
1794             }
1795             break;
1796         }
1797 
1798         case cmd_list_instances:
1799             rc = out->message(out, "resource-names-list", data_set->resources);
1800 
1801             if (rc != pcmk_rc_ok) {
1802                 rc = ENXIO;
1803             }
1804 
1805             break;
1806 
1807         case cmd_list_standards:
1808         case cmd_list_providers:
1809         case cmd_list_alternatives:
1810             rc = list_providers(out, options.agent_spec);
1811             break;
1812 
1813         case cmd_list_agents:
1814             rc = list_agents(out, options.agent_spec);
1815             break;
1816 
1817         case cmd_metadata:
1818             rc = show_metadata(out, options.agent_spec);
1819             break;
1820 
1821         case cmd_restart:
1822             /* We don't pass data_set because rsc needs to stay valid for the
1823              * entire lifetime of cli_resource_restart(), but it will reset and
1824              * update the working set multiple times, so it needs to use its own
1825              * copy.
1826              */
1827             rc = cli_resource_restart(out, rsc, options.host_uname,
1828                                       options.move_lifetime, options.timeout_ms,
1829                                       cib_conn, options.cib_options,
1830                                       options.promoted_role_only,
1831                                       options.force);
1832             break;
1833 
1834         case cmd_wait:
1835             rc = wait_till_stable(out, options.timeout_ms, cib_conn);
1836             break;
1837 
1838         case cmd_execute_agent:
1839             if (options.cmdline_config) {
1840                 exit_code = cli_resource_execute_from_params(out, NULL,
1841                     options.v_class, options.v_provider, options.v_agent,
1842                     options.operation, options.cmdline_params,
1843                     options.override_params, options.timeout_ms,
1844                     args->verbosity, options.force, options.check_level);
1845             } else {
1846                 exit_code = cli_resource_execute(rsc, options.rsc_id,
1847                     options.operation, options.override_params,
1848                     options.timeout_ms, cib_conn, data_set,
1849                     args->verbosity, options.force, options.check_level);
1850             }
1851             goto done;
1852 
1853         case cmd_digests:
1854             node = pe_find_node(data_set->nodes, options.host_uname);
1855             if (node == NULL) {
1856                 rc = pcmk_rc_node_unknown;
1857             } else {
1858                 rc = pcmk__resource_digests(out, rsc, node,
1859                                             options.override_params, data_set);
1860             }
1861             break;
1862 
1863         case cmd_colocations:
1864             rc = out->message(out, "stacks-constraints", rsc, data_set, false);
1865             break;
1866 
1867         case cmd_colocations_deep:
1868             rc = out->message(out, "stacks-constraints", rsc, data_set, true);
1869             break;
1870 
1871         case cmd_cts:
1872             rc = pcmk_rc_ok;
1873 
1874             for (GList *lpc = data_set->resources; lpc != NULL;
1875                  lpc = lpc->next) {
1876 
1877                 rsc = (pe_resource_t *) lpc->data;
1878                 cli_resource_print_cts(out, rsc);
1879             }
1880 
1881             cli_resource_print_cts_constraints(data_set);
1882             break;
1883 
1884         case cmd_fail:
1885             rc = cli_resource_fail(controld_api, options.host_uname,
1886                                    options.rsc_id, data_set);
1887             if (rc == pcmk_rc_ok) {
1888                 start_mainloop(controld_api);
1889             }
1890             break;
1891 
1892         case cmd_list_active_ops:
1893             rc = cli_resource_print_operations(options.rsc_id,
1894                                                options.host_uname, TRUE,
1895                                                data_set);
1896             break;
1897 
1898         case cmd_list_all_ops:
1899             rc = cli_resource_print_operations(options.rsc_id,
1900                                                options.host_uname, FALSE,
1901                                                data_set);
1902             break;
1903 
1904         case cmd_locate: {
1905             GList *nodes = cli_resource_search(rsc, options.rsc_id, data_set);
1906             rc = out->message(out, "resource-search-list", nodes, options.rsc_id);
1907             g_list_free_full(nodes, free);
1908             break;
1909         }
1910 
1911         case cmd_query_xml:
1912             rc = cli_resource_print(rsc, data_set, TRUE);
1913             break;
1914 
1915         case cmd_query_raw_xml:
1916             rc = cli_resource_print(rsc, data_set, FALSE);
1917             break;
1918 
1919         case cmd_why:
1920             if ((options.host_uname != NULL) && (node == NULL)) {
1921                 rc = pcmk_rc_node_unknown;
1922             } else {
1923                 rc = out->message(out, "resource-reasons-list", cib_conn,
1924                                   data_set->resources, rsc, node);
1925             }
1926             break;
1927 
1928         case cmd_clear:
1929             rc = clear_constraints(out, &cib_xml_copy);
1930             break;
1931 
1932         case cmd_move:
1933             if (options.host_uname == NULL) {
1934                 rc = ban_or_move(out, rsc, options.move_lifetime);
1935             } else {
1936                 rc = cli_resource_move(rsc, options.rsc_id, options.host_uname,
1937                                        options.move_lifetime, cib_conn,
1938                                        options.cib_options, data_set,
1939                                        options.promoted_role_only,
1940                                        options.force);
1941             }
1942 
1943             if (rc == EINVAL) {
1944                 exit_code = CRM_EX_USAGE;
1945                 goto done;
1946             }
1947 
1948             break;
1949 
1950         case cmd_ban:
1951             if (options.host_uname == NULL) {
1952                 rc = ban_or_move(out, rsc, options.move_lifetime);
1953             } else if (node == NULL) {
1954                 rc = pcmk_rc_node_unknown;
1955             } else {
1956                 rc = cli_resource_ban(out, options.rsc_id, node->details->uname,
1957                                       options.move_lifetime, NULL, cib_conn,
1958                                       options.cib_options,
1959                                       options.promoted_role_only);
1960             }
1961 
1962             if (rc == EINVAL) {
1963                 exit_code = CRM_EX_USAGE;
1964                 goto done;
1965             }
1966 
1967             break;
1968 
1969         case cmd_get_property:
1970             rc = out->message(out, "property-list", rsc, options.prop_name);
1971             if (rc == pcmk_rc_no_output) {
1972                 rc = ENXIO;
1973             }
1974 
1975             break;
1976 
1977         case cmd_set_property:
1978             rc = set_property();
1979             break;
1980 
1981         case cmd_get_param: {
1982             unsigned int count = 0;
1983             GHashTable *params = NULL;
1984             pe_node_t *current = pe__find_active_on(rsc, &count, NULL);
1985             bool free_params = true;
1986 
1987             if (count > 1) {
1988                 out->err(out, "%s is active on more than one node,"
1989                          " returning the default value for %s", rsc->id, crm_str(options.prop_name));
1990                 current = NULL;
1991             }
1992 
1993             crm_debug("Looking up %s in %s", options.prop_name, rsc->id);
1994 
1995             if (pcmk__str_eq(options.attr_set_type, XML_TAG_ATTR_SETS, pcmk__str_casei)) {
1996                 params = pe_rsc_params(rsc, current, data_set);
1997                 free_params = false;
1998 
1999             } else if (pcmk__str_eq(options.attr_set_type, XML_TAG_META_SETS, pcmk__str_casei)) {
2000                 params = pcmk__strkey_table(free, free);
2001                 get_meta_attributes(params, rsc, current, data_set);
2002 
2003             } else {
2004                 params = pcmk__strkey_table(free, free);
2005                 pe__unpack_dataset_nvpairs(rsc->xml, XML_TAG_UTILIZATION, NULL, params,
2006                                            NULL, FALSE, data_set);
2007             }
2008 
2009             rc = out->message(out, "attribute-list", rsc, options.prop_name, params);
2010             if (free_params) {
2011                 g_hash_table_destroy(params);
2012             }
2013             break;
2014         }
2015 
2016         case cmd_set_param:
2017             if (pcmk__str_empty(options.prop_value)) {
2018                 exit_code = CRM_EX_USAGE;
2019                 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
2020                             "You need to supply a value with the -v option");
2021                 goto done;
2022             }
2023 
2024             /* coverity[var_deref_model] False positive */
2025             rc = cli_resource_update_attribute(rsc, options.rsc_id,
2026                                                options.prop_set,
2027                                                options.attr_set_type,
2028                                                options.prop_id,
2029                                                options.prop_name,
2030                                                options.prop_value,
2031                                                options.recursive, cib_conn,
2032                                                options.cib_options, data_set,
2033                                                options.force);
2034             break;
2035 
2036         case cmd_delete_param:
2037             /* coverity[var_deref_model] False positive */
2038             rc = cli_resource_delete_attribute(rsc, options.rsc_id,
2039                                                options.prop_set,
2040                                                options.attr_set_type,
2041                                                options.prop_id,
2042                                                options.prop_name, cib_conn,
2043                                                options.cib_options, data_set,
2044                                                options.force);
2045             break;
2046 
2047         case cmd_cleanup:
2048             if (rsc == NULL) {
2049                 rc = cli_cleanup_all(controld_api, options.host_uname,
2050                                      options.operation, options.interval_spec,
2051                                      data_set);
2052                 if (rc == pcmk_rc_ok) {
2053                     start_mainloop(controld_api);
2054                 }
2055             } else {
2056                 cleanup(out, rsc);
2057             }
2058             break;
2059 
2060         case cmd_refresh:
2061             if (rsc == NULL) {
2062                 rc = refresh(out);
2063             } else {
2064                 refresh_resource(out, rsc);
2065             }
2066             break;
2067 
2068         case cmd_delete:
2069             rc = delete();
2070             break;
2071 
2072         default:
2073             exit_code = CRM_EX_USAGE;
2074             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
2075                         "Unimplemented command: %d", (int) options.rsc_cmd);
2076             goto done;
2077     }
2078 
2079     /* Convert rc into an exit code. */
2080     if (rc != pcmk_rc_ok && rc != pcmk_rc_no_output) {
2081         if (rc == pcmk_rc_no_quorum) {
2082             g_prefix_error(&error, "To ignore quorum, use the force option.\n");
2083         }
2084 
2085         exit_code = pcmk_rc2exitc(rc);
2086     }
2087 
2088     /*
2089      * Clean up and exit
2090      */
2091 
2092 done:
2093     /* When we get here, exit_code has been set one of two ways - either at one of
2094      * the spots where there's a "goto done" (which itself could have happened either
2095      * directly or by calling pcmk_rc2exitc), or just up above after any of the break
2096      * statements.
2097      *
2098      * Thus, we can use just exit_code here to decide what to do.
2099      */
2100     if (exit_code != CRM_EX_OK && exit_code != CRM_EX_USAGE) {
2101         if (error != NULL) {
2102             char *msg = crm_strdup_printf("%s\nError performing operation: %s",
2103                                           error->message, crm_exit_str(exit_code));
2104             g_clear_error(&error);
2105             g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "%s", msg);
2106             free(msg);
2107         } else {
2108             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
2109                         "Error performing operation: %s", crm_exit_str(exit_code));
2110         }
2111     }
2112 
2113     g_free(options.host_uname);
2114     g_free(options.interval_spec);
2115     g_free(options.move_lifetime);
2116     g_free(options.operation);
2117     g_free(options.prop_id);
2118     free(options.prop_name);
2119     g_free(options.prop_set);
2120     g_free(options.prop_value);
2121     g_free(options.rsc_id);
2122     g_free(options.rsc_type);
2123     free(options.agent_spec);
2124     free(options.v_agent);
2125     free(options.v_class);
2126     free(options.v_provider);
2127     g_free(options.xml_file);
2128     g_strfreev(options.remainder);
2129 
2130     if (options.override_params != NULL) {
2131         g_hash_table_destroy(options.override_params);
2132     }
2133 
2134     /* options.cmdline_params does not need to be destroyed here.  See the
2135      * comments in cli_resource_execute_from_params.
2136      */
2137 
2138     g_strfreev(processed_args);
2139     g_option_context_free(context);
2140 
2141     return bye(exit_code);
2142 }

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