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. wait_cb
  31. why_cb
  32. ban_or_move
  33. cleanup
  34. clear_constraints
  35. delete
  36. list_agents
  37. list_providers
  38. list_raw
  39. list_stacks_and_constraints
  40. populate_working_set
  41. refresh
  42. refresh_resource
  43. set_property
  44. show_metadata
  45. validate_cmdline
  46. build_arg_context
  47. main

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

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