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