This source file includes following definitions.
- bye
- quit_main_loop
- resource_ipc_timeout
- controller_event_callback
- start_mainloop
- compare_id
- build_constraint_list
- agent_provider_cb
- attr_set_type_cb
- class_cb
- cleanup_refresh_cb
- delete_cb
- expired_cb
- get_agent_spec
- list_agents_cb
- list_providers_cb
- list_standards_cb
- list_alternatives_cb
- metadata_cb
- option_cb
- fail_cb
- flag_cb
- get_param_prop_cb
- list_cb
- set_delete_param_cb
- set_prop_cb
- timeout_cb
- validate_or_force_cb
- restart_cb
- wait_cb
- why_cb
- ban_or_move
- cleanup
- clear_constraints
- delete
- list_agents
- list_providers
- list_raw
- list_stacks_and_constraints
- populate_working_set
- refresh
- refresh_resource
- set_property
- show_metadata
- validate_cmdline
- build_arg_context
- main
1
2
3
4
5
6
7
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,
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;
69 const char *attr_set_type;
70 int cib_options;
71 gboolean clear_expired;
72 int find_flags;
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;
86 gboolean require_crmd;
87 gboolean require_dataset;
88 gboolean require_resource;
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;
95 char *v_agent;
96 char *v_class;
97 char *v_provider;
98 gboolean validate_cmdline;
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
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
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
170 static crm_exit_t
171 bye(crm_exit_t ec)
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;
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;
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)
203 {
204 exit_code = ec;
205 if (mainloop != NULL) {
206 GMainLoop *mloop = mainloop;
207
208 mainloop = NULL;
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)
216 {
217
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,
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) {
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)
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;
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)
281 {
282 return strcmp((const char *)a, (const char *)b);
283 }
284
285 static GListPtr
286 build_constraint_list(xmlNode *root)
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
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) {
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) {
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) {
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) {
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) {
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) {
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)
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,
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,
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,
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,
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,
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,
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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,
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);
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,
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) {
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) {
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)
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)
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
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)
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()
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)
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)
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()
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)
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
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)
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
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()
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)
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
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()
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)
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)
1389 {
1390
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
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
1401
1402
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) {
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
1480
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)
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
1535 if (options.rsc_cmd == cmd_none) {
1536 options.rsc_cmd = cmd_list_resources;
1537 options.require_resource = FALSE;
1538 }
1539
1540
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
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
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
1611
1612 if (options.validate_cmdline) {
1613 validate_cmdline(&exit_code);
1614 goto done;
1615 } else if (options.validate_options != NULL) {
1616
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
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
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
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
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
1724
1725
1726
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
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
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
1969
1970
1971
1972 g_strfreev(processed_args);
1973 g_option_context_free(context);
1974
1975 return bye(exit_code);
1976 }