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