This source file includes following definitions.
- resource_ipc_timeout
- resource_ipc_connection_destroy
- start_mainloop
- resource_ipc_callback
- main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 #include <crm_resource.h>
21
22 #include <sys/param.h>
23
24 #include <crm/crm.h>
25
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <libgen.h>
34 #include <time.h>
35
36 bool BE_QUIET = FALSE;
37 bool scope_master = FALSE;
38 int cib_options = cib_sync_call;
39
40 GMainLoop *mainloop = NULL;
41
42 #define message_timeout_ms 60*1000
43
44 static gboolean
45 resource_ipc_timeout(gpointer data)
46 {
47 fprintf(stderr, "No messages received in %d seconds.. aborting\n",
48 (int)message_timeout_ms / 1000);
49 crm_err("No messages received in %d seconds", (int)message_timeout_ms / 1000);
50 return crm_exit(-1);
51 }
52
53 static void
54 resource_ipc_connection_destroy(gpointer user_data)
55 {
56 crm_info("Connection to CRMd was terminated");
57 crm_exit(1);
58 }
59
60 static void
61 start_mainloop(void)
62 {
63 if (crmd_replies_needed == 0) {
64 return;
65 }
66
67 mainloop = g_main_new(FALSE);
68 fprintf(stderr, "Waiting for %d replies from the CRMd", crmd_replies_needed);
69 crm_debug("Waiting for %d replies from the CRMd", crmd_replies_needed);
70
71 g_timeout_add(message_timeout_ms, resource_ipc_timeout, NULL);
72 g_main_run(mainloop);
73 }
74
75 static int
76 resource_ipc_callback(const char *buffer, ssize_t length, gpointer userdata)
77 {
78 xmlNode *msg = string2xml(buffer);
79
80 fprintf(stderr, ".");
81 crm_log_xml_trace(msg, "[inbound]");
82
83 crmd_replies_needed--;
84 if ((crmd_replies_needed == 0) && mainloop
85 && g_main_loop_is_running(mainloop)) {
86
87 fprintf(stderr, " OK\n");
88 crm_debug("Got all the replies we expected");
89 return crm_exit(pcmk_ok);
90 }
91
92 free_xml(msg);
93 return 0;
94 }
95
96 struct ipc_client_callbacks crm_callbacks = {
97 .dispatch = resource_ipc_callback,
98 .destroy = resource_ipc_connection_destroy,
99 };
100
101
102
103
104
105 static struct crm_option long_options[] = {
106
107 {
108 "help", no_argument, NULL, '?',
109 "\t\tDisplay this text and exit"
110 },
111 {
112 "version", no_argument, NULL, '$',
113 "\t\tDisplay version information and exit"
114 },
115 {
116 "verbose", no_argument, NULL, 'V',
117 "\t\tIncrease debug output (may be specified multiple times)"
118 },
119 {
120 "quiet", no_argument, NULL, 'Q',
121 "\t\tBe less descriptive in results"
122 },
123 {
124 "resource", required_argument, NULL, 'r',
125 "\tResource ID"
126 },
127
128 { "-spacer-", no_argument, NULL, '-', "\nQueries:" },
129 {
130 "list", no_argument, NULL, 'L',
131 "\t\tList all cluster resources with status"},
132 {
133 "list-raw", no_argument, NULL, 'l',
134 "\t\tList IDs of all instantiated resources (individual members rather than groups etc.)"
135 },
136 {
137 "list-cts", no_argument, NULL, 'c',
138 NULL, pcmk_option_hidden
139 },
140 {
141 "list-operations", no_argument, NULL, 'O',
142 "\tList active resource operations, optionally filtered by --resource and/or --node"
143 },
144 {
145 "list-all-operations", no_argument, NULL, 'o',
146 "List all resource operations, optionally filtered by --resource and/or --node"
147 },
148 {
149 "pending", no_argument, NULL, 'j',
150 "\t\tDisplay pending state if 'record-pending' is enabled",
151 pcmk_option_hidden
152 },
153 {
154 "list-standards", no_argument, NULL, 0,
155 "\tList supported standards"
156 },
157 {
158 "list-ocf-providers", no_argument, NULL, 0,
159 "List all available OCF providers"
160 },
161 {
162 "list-agents", required_argument, NULL, 0,
163 "List all agents available for the named standard and/or provider."
164 },
165 {
166 "list-ocf-alternatives", required_argument, NULL, 0,
167 "List all available providers for the named OCF agent"
168 },
169 {
170 "show-metadata", required_argument, NULL, 0,
171 "Show the metadata for the named class:provider:agent"
172 },
173 {
174 "query-xml", no_argument, NULL, 'q',
175 "\tShow XML configuration of resource (after any template expansion)"
176 },
177 {
178 "query-xml-raw", no_argument, NULL, 'w',
179 "\tShow XML configuration of resource (before any template expansion)"
180 },
181 {
182 "get-parameter", required_argument, NULL, 'g',
183 "Display named parameter for resource.\n"
184 "\t\t\t\tUse instance attribute unless --meta or --utilization is specified"
185 },
186 {
187 "get-property", required_argument, NULL, 'G',
188 "Display named property of resource ('class', 'type', or 'provider') (requires --resource)",
189 pcmk_option_hidden
190 },
191 {
192 "locate", no_argument, NULL, 'W',
193 "\t\tShow node(s) currently running resource"
194 },
195 {
196 "stack", no_argument, NULL, 'A',
197 "\t\tDisplay the prerequisites and dependents of a resource"
198 },
199 {
200 "constraints", no_argument, NULL, 'a',
201 "\tDisplay the (co)location constraints that apply to a resource"
202 },
203 {
204 "why", no_argument, NULL, 'Y',
205 "\t\tShow why resources are not running, optionally filtered by --resource and/or --node"
206 },
207
208 { "-spacer-", no_argument, NULL, '-', "\nCommands:" },
209 {
210 "validate", no_argument, NULL, 0,
211 "\t\tCall the validate-all action of the local given resource"
212 },
213 {
214 "cleanup", no_argument, NULL, 'C',
215 #if 0
216
217 "\t\tDelete failed operations from a resource's history allowing its current state to be rechecked.\n"
218 "\t\t\t\tOptionally filtered by --resource, --node, --operation, and --interval (otherwise all).\n"
219 },
220 {
221 "refresh", no_argument, NULL, 'R',
222 #endif
223 "\t\tDelete resource's history (including failures) so its current state is rechecked.\n"
224 "\t\t\t\tOptionally filtered by --resource, --node, --operation, and --interval (otherwise all).\n"
225 "\t\t\t\tUnless --force is specified, resource's group or clone (if any) will also be cleaned"
226 },
227 {
228 "set-parameter", required_argument, NULL, 'p',
229 "Set named parameter for resource (requires -v).\n"
230 "\t\t\t\tUse instance attribute unless --meta or --utilization is specified."
231 },
232 {
233 "delete-parameter", required_argument, NULL, 'd',
234 "Delete named parameter for resource.\n"
235 "\t\t\t\tUse instance attribute unless --meta or --utilization is specified."
236 },
237 {
238 "set-property", required_argument, NULL, 'S',
239 "Set named property of resource ('class', 'type', or 'provider') (requires -r, -t, -v)",
240 pcmk_option_hidden
241 },
242
243 { "-spacer-", no_argument, NULL, '-', "\nResource location:" },
244 {
245 "move", no_argument, NULL, 'M',
246 "\t\tCreate a constraint to move resource. If --node is specified, the constraint\n"
247 "\t\t\t\twill be to move to that node, otherwise it will be to ban the current node.\n"
248 "\t\t\t\tUnless --force is specified, this will return an error if the resource is\n"
249 "\t\t\t\talready running on the specified node. If --force is specified, this will\n"
250 "\t\t\t\talways ban the current node. Optional: --lifetime, --master.\n"
251 "\t\t\t\tNOTE: This may prevent the resource from running on its previous location\n"
252 "\t\t\t\tuntil the implicit constraint expires or is removed with --clear."
253 },
254 {
255 "ban", no_argument, NULL, 'B',
256 "\t\tCreate a constraint to keep resource off a node. Optional: --node, --lifetime, --master.\n"
257 "\t\t\t\tNOTE: This will prevent the resource from running on the affected node\n"
258 "\t\t\t\tuntil the implicit constraint expires or is removed with --clear.\n"
259 "\t\t\t\tIf --node is not specified, it defaults to the node currently running the resource\n"
260 "\t\t\t\tfor primitives and groups, or the master for master/slave clones with master-max=1\n"
261 "\t\t\t\t(all other situations result in an error as there is no sane default).\n"
262 },
263 {
264 "clear", no_argument, NULL, 'U',
265 "\t\tRemove all constraints created by the --ban and/or --move commands.\n"
266 "\t\t\t\tRequires: --resource. Optional: --node, --master.\n"
267 "\t\t\t\tIf --node is not specified, all constraints created by --ban and --move\n"
268 "\t\t\t\twill be removed for the named resource. If --node and --force are specified,\n"
269 "\t\t\t\tany constraint created by --move will be cleared, even if it is not for the specified node."
270 },
271 {
272 "lifetime", required_argument, NULL, 'u',
273 "\tLifespan (as ISO 8601 duration) of created constraints (with -B, -M)\n"
274 "\t\t\t\t(see https://en.wikipedia.org/wiki/ISO_8601#Durations)"
275 },
276 {
277 "master", no_argument, NULL, 0,
278 "\t\tLimit scope of command to the Master role (with -B, -M, -U).\n"
279 "\t\t\t\tFor -B and -M, the previous master may remain active in the Slave role."
280 },
281
282 { "-spacer-", no_argument, NULL, '-', "\nAdvanced Commands:" },
283 {
284 "delete", no_argument, NULL, 'D',
285 "\t\t(Advanced) Delete a resource from the CIB. Required: -t"
286 },
287 {
288 "fail", no_argument, NULL, 'F',
289 "\t\t(Advanced) Tell the cluster this resource has failed"
290 },
291 {
292 "restart", no_argument, NULL, 0,
293 "\t\t(Advanced) Tell the cluster to restart this resource and anything that depends on it"
294 },
295 {
296 "wait", no_argument, NULL, 0,
297 "\t\t(Advanced) Wait until the cluster settles into a stable state"
298 },
299 {
300 "force-demote", no_argument, NULL, 0,
301 "\t(Advanced) Bypass the cluster and demote a resource on the local node.\n"
302 "\t\t\t\tUnless --force is specified, this will refuse to do so if the cluster\n"
303 "\t\t\t\tbelieves the resource is a clone instance already running on the local node."
304 },
305 {
306 "force-stop", no_argument, NULL, 0,
307 "\t(Advanced) Bypass the cluster and stop a resource on the local node."
308 },
309 {
310 "force-start", no_argument, NULL, 0,
311 "\t(Advanced) Bypass the cluster and start a resource on the local node.\n"
312 "\t\t\t\tUnless --force is specified, this will refuse to do so if the cluster\n"
313 "\t\t\t\tbelieves the resource is a clone instance already running on the local node."
314 },
315 {
316 "force-promote", no_argument, NULL, 0,
317 "\t(Advanced) Bypass the cluster and promote a resource on the local node.\n"
318 "\t\t\t\tUnless --force is specified, this will refuse to do so if the cluster\n"
319 "\t\t\t\tbelieves the resource is a clone instance already running on the local node."
320 },
321 {
322 "force-check", no_argument, NULL, 0,
323 "\t(Advanced) Bypass the cluster and check the state of a resource on the local node."
324 },
325
326 { "-spacer-", no_argument, NULL, '-', "\nAdditional Options:" },
327 {
328 "node", required_argument, NULL, 'N',
329 "\tNode name"
330 },
331 {
332 "recursive", no_argument, NULL, 0,
333 "\tFollow colocation chains when using --set-parameter"
334 },
335 {
336 "resource-type", required_argument, NULL, 't',
337 "Resource XML element (primitive, group, etc.) (with -D)"
338 },
339 {
340 "parameter-value", required_argument, NULL, 'v',
341 "Value to use with -p"
342 },
343 {
344 "meta", no_argument, NULL, 'm',
345 "\t\tUse resource meta-attribute instead of instance attribute (with -p, -g, -d)"
346 },
347 {
348 "utilization", no_argument, NULL, 'z',
349 "\tUse resource utilization attribute instead of instance attribute (with -p, -g, -d)"
350 },
351 {
352 "operation", required_argument, NULL, 'n',
353 "\tOperation to clear instead of all (with -C -r)"
354 },
355 {
356 "interval", required_argument, NULL, 'I',
357 "\tInterval of operation to clear (default 0) (with -C -r -n)"
358 },
359 {
360 "set-name", required_argument, NULL, 's',
361 "\t(Advanced) XML ID of attributes element to use (with -p, -d)"
362 },
363 {
364 "nvpair", required_argument, NULL, 'i',
365 "\t(Advanced) XML ID of nvpair element to use (with -p, -d)"
366 },
367 {
368 "timeout", required_argument, NULL, 'T',
369 "\t(Advanced) Abort if command does not finish in this time (with --restart, --wait, --force-*)"
370 },
371 {
372 "force", no_argument, NULL, 'f',
373 "\t\tIf making CIB changes, do so regardless of quorum.\n"
374 "\t\t\t\tSee help for individual commands for additional behavior.\n"
375 },
376 {
377 "xml-file", required_argument, NULL, 'x',
378 NULL, pcmk_option_hidden
379 },
380
381
382 {"host-uname", required_argument, NULL, 'H', NULL, pcmk_option_hidden},
383 {"migrate", no_argument, NULL, 'M', NULL, pcmk_option_hidden},
384 {"un-migrate", no_argument, NULL, 'U', NULL, pcmk_option_hidden},
385 {"un-move", no_argument, NULL, 'U', NULL, pcmk_option_hidden},
386
387 {"refresh", 0, 0, 'R', NULL, pcmk_option_hidden},
388 {"reprobe", no_argument, NULL, 'P', NULL, pcmk_option_hidden},
389
390 {"-spacer-", 1, NULL, '-', "\nExamples:", pcmk_option_paragraph},
391 {"-spacer-", 1, NULL, '-', "List the available OCF agents:", pcmk_option_paragraph},
392 {"-spacer-", 1, NULL, '-', " crm_resource --list-agents ocf", pcmk_option_example},
393 {"-spacer-", 1, NULL, '-', "List the available OCF agents from the linux-ha project:", pcmk_option_paragraph},
394 {"-spacer-", 1, NULL, '-', " crm_resource --list-agents ocf:heartbeat", pcmk_option_example},
395 {"-spacer-", 1, NULL, '-', "Move 'myResource' to a specific node:", pcmk_option_paragraph},
396 {"-spacer-", 1, NULL, '-', " crm_resource --resource myResource --move --node altNode", pcmk_option_example},
397 {"-spacer-", 1, NULL, '-', "Allow (but not force) 'myResource' to move back to its original location:", pcmk_option_paragraph},
398 {"-spacer-", 1, NULL, '-', " crm_resource --resource myResource --clear", pcmk_option_example},
399 {"-spacer-", 1, NULL, '-', "Stop 'myResource' (and anything that depends on it):", pcmk_option_paragraph},
400 {"-spacer-", 1, NULL, '-', " crm_resource --resource myResource --set-parameter target-role --meta --parameter-value Stopped", pcmk_option_example},
401 {"-spacer-", 1, NULL, '-', "Tell the cluster not to manage 'myResource':", pcmk_option_paragraph},
402 {"-spacer-", 1, NULL, '-', "The cluster will not attempt to start or stop the resource under any circumstances."},
403 {"-spacer-", 1, NULL, '-', "Useful when performing maintenance tasks on a resource.", pcmk_option_paragraph},
404 {"-spacer-", 1, NULL, '-', " crm_resource --resource myResource --set-parameter is-managed --meta --parameter-value false", pcmk_option_example},
405 {"-spacer-", 1, NULL, '-', "Erase the operation history of 'myResource' on 'aNode':", pcmk_option_paragraph},
406 {"-spacer-", 1, NULL, '-', "The cluster will 'forget' the existing resource state (including any errors) and attempt to recover the resource."},
407 {"-spacer-", 1, NULL, '-', "Useful when a resource had failed permanently and has been repaired by an administrator.", pcmk_option_paragraph},
408 {"-spacer-", 1, NULL, '-', " crm_resource --resource myResource --cleanup --node aNode", pcmk_option_example},
409
410 {0, 0, 0, 0}
411 };
412
413
414
415 int
416 main(int argc, char **argv)
417 {
418 char rsc_cmd = 'L';
419
420 const char *rsc_id = NULL;
421 const char *host_uname = NULL;
422 const char *prop_name = NULL;
423 const char *prop_value = NULL;
424 const char *rsc_type = NULL;
425 const char *prop_id = NULL;
426 const char *prop_set = NULL;
427 const char *rsc_long_cmd = NULL;
428 const char *longname = NULL;
429 const char *operation = NULL;
430 const char *interval = NULL;
431 const char *cib_file = getenv("CIB_file");
432 GHashTable *override_params = NULL;
433
434 char *xml_file = NULL;
435 crm_ipc_t *crmd_channel = NULL;
436 pe_working_set_t data_set = { 0, };
437 cib_t *cib_conn = NULL;
438 resource_t *rsc = NULL;
439 bool recursive = FALSE;
440 char *our_pid = NULL;
441
442 bool require_resource = TRUE;
443 bool require_dataset = TRUE;
444 bool require_crmd = FALSE;
445 bool just_errors = TRUE;
446
447 int rc = pcmk_ok;
448 int is_ocf_rc = 0;
449 int option_index = 0;
450 int timeout_ms = 0;
451 int argerr = 0;
452 int flag;
453 int find_flags = 0;
454
455 crm_log_cli_init("crm_resource");
456 crm_set_options(NULL, "(query|command) [options]", long_options,
457 "Perform tasks related to cluster resources.\nAllows resources to be queried (definition and location), modified, and moved around the cluster.\n");
458
459 while (1) {
460 flag = crm_get_option_long(argc, argv, &option_index, &longname);
461 if (flag == -1)
462 break;
463
464 switch (flag) {
465 case 0:
466 if (safe_str_eq("master", longname)) {
467 scope_master = TRUE;
468
469 } else if(safe_str_eq(longname, "recursive")) {
470 recursive = TRUE;
471
472 } else if (safe_str_eq("wait", longname)) {
473 rsc_cmd = flag;
474 rsc_long_cmd = longname;
475 require_resource = FALSE;
476 require_dataset = FALSE;
477
478 } else if (
479 safe_str_eq("validate", longname)
480 || safe_str_eq("restart", longname)
481 || safe_str_eq("force-demote", longname)
482 || safe_str_eq("force-stop", longname)
483 || safe_str_eq("force-start", longname)
484 || safe_str_eq("force-promote", longname)
485 || safe_str_eq("force-check", longname)) {
486 rsc_cmd = flag;
487 rsc_long_cmd = longname;
488 find_flags = pe_find_renamed|pe_find_anon;
489 crm_log_args(argc, argv);
490
491 } else if (safe_str_eq("list-ocf-providers", longname)
492 || safe_str_eq("list-ocf-alternatives", longname)
493 || safe_str_eq("list-standards", longname)) {
494 const char *text = NULL;
495 lrmd_list_t *list = NULL;
496 lrmd_list_t *iter = NULL;
497 lrmd_t *lrmd_conn = lrmd_api_new();
498
499 if (safe_str_eq("list-ocf-providers", longname)
500 || safe_str_eq("list-ocf-alternatives", longname)) {
501 rc = lrmd_conn->cmds->list_ocf_providers(lrmd_conn, optarg, &list);
502 text = "OCF providers";
503
504 } else if (safe_str_eq("list-standards", longname)) {
505 rc = lrmd_conn->cmds->list_standards(lrmd_conn, &list);
506 text = "standards";
507 }
508
509 if (rc > 0) {
510 rc = 0;
511 for (iter = list; iter != NULL; iter = iter->next) {
512 rc++;
513 printf("%s\n", iter->val);
514 }
515 lrmd_list_freeall(list);
516
517 } else if (optarg) {
518 fprintf(stderr, "No %s found for %s\n", text, optarg);
519 } else {
520 fprintf(stderr, "No %s found\n", text);
521 }
522
523 lrmd_api_delete(lrmd_conn);
524 return crm_exit(rc);
525
526 } else if (safe_str_eq("show-metadata", longname)) {
527 char *standard = NULL;
528 char *provider = NULL;
529 char *type = NULL;
530 char *metadata = NULL;
531 lrmd_t *lrmd_conn = lrmd_api_new();
532
533 rc = crm_parse_agent_spec(optarg, &standard, &provider, &type);
534 if (rc == pcmk_ok) {
535 rc = lrmd_conn->cmds->get_metadata(lrmd_conn, standard,
536 provider, type,
537 &metadata, 0);
538 } else {
539 fprintf(stderr,
540 "'%s' is not a valid agent specification\n",
541 optarg);
542 }
543
544 if (metadata) {
545 printf("%s\n", metadata);
546 } else {
547 fprintf(stderr, "Metadata query for %s failed: %s\n",
548 optarg, pcmk_strerror(rc));
549 }
550 lrmd_api_delete(lrmd_conn);
551 return crm_exit(rc);
552
553 } else if (safe_str_eq("list-agents", longname)) {
554 lrmd_list_t *list = NULL;
555 lrmd_list_t *iter = NULL;
556 char *provider = strchr (optarg, ':');
557 lrmd_t *lrmd_conn = lrmd_api_new();
558
559 if (provider) {
560 *provider++ = 0;
561 }
562 rc = lrmd_conn->cmds->list_agents(lrmd_conn, &list, optarg, provider);
563
564 if (rc > 0) {
565 rc = 0;
566 for (iter = list; iter != NULL; iter = iter->next) {
567 printf("%s\n", iter->val);
568 rc++;
569 }
570 lrmd_list_freeall(list);
571 rc = 0;
572 } else {
573 fprintf(stderr, "No agents found for standard=%s, provider=%s\n",
574 optarg, (provider? provider : "*"));
575 rc = -1;
576 }
577 lrmd_api_delete(lrmd_conn);
578 return crm_exit(rc);
579
580 } else {
581 crm_err("Unhandled long option: %s", longname);
582 }
583 break;
584 case 'V':
585 resource_verbose++;
586 crm_bump_log_level(argc, argv);
587 break;
588 case '$':
589 case '?':
590 crm_help(flag, EX_OK);
591 break;
592 case 'x':
593 xml_file = strdup(optarg);
594 break;
595 case 'Q':
596 BE_QUIET = TRUE;
597 break;
598 case 'm':
599 attr_set_type = XML_TAG_META_SETS;
600 break;
601 case 'z':
602 attr_set_type = XML_TAG_UTILIZATION;
603 break;
604 case 'u':
605 move_lifetime = strdup(optarg);
606 break;
607 case 'f':
608 do_force = TRUE;
609 crm_log_args(argc, argv);
610 break;
611 case 'i':
612 prop_id = optarg;
613 break;
614 case 's':
615 prop_set = optarg;
616 break;
617 case 'r':
618 rsc_id = optarg;
619 break;
620 case 'v':
621 prop_value = optarg;
622 break;
623 case 't':
624 rsc_type = optarg;
625 break;
626 case 'T':
627 timeout_ms = crm_get_msec(optarg);
628 break;
629
630 case 'R':
631 case 'P':
632 crm_log_args(argc, argv);
633 require_resource = FALSE;
634 if (cib_file == NULL) {
635 require_crmd = TRUE;
636 }
637 just_errors = FALSE;
638 rsc_cmd = 'C';
639 find_flags = pe_find_renamed|pe_find_anon;
640 break;
641
642 case 'C':
643 crm_log_args(argc, argv);
644 require_resource = FALSE;
645 if (cib_file == NULL) {
646 require_crmd = TRUE;
647 }
648 just_errors = FALSE;
649 rsc_cmd = 'C';
650 find_flags = pe_find_renamed|pe_find_anon;
651 break;
652
653 case 'n':
654 operation = optarg;
655 break;
656
657 case 'I':
658 interval = optarg;
659 break;
660
661 case 'D':
662 require_dataset = FALSE;
663 crm_log_args(argc, argv);
664 rsc_cmd = flag;
665 find_flags = pe_find_renamed|pe_find_any;
666 break;
667
668 case 'F':
669 require_crmd = TRUE;
670 crm_log_args(argc, argv);
671 rsc_cmd = flag;
672 break;
673
674 case 'U':
675 case 'B':
676 case 'M':
677 crm_log_args(argc, argv);
678 rsc_cmd = flag;
679 find_flags = pe_find_renamed|pe_find_anon;
680 break;
681
682 case 'c':
683 case 'L':
684 case 'l':
685 case 'O':
686 case 'o':
687 require_resource = FALSE;
688 rsc_cmd = flag;
689 break;
690
691 case 'Y':
692 require_resource = FALSE;
693 rsc_cmd = flag;
694 find_flags = pe_find_renamed|pe_find_anon;
695 break;
696
697 case 'q':
698 case 'w':
699 rsc_cmd = flag;
700 find_flags = pe_find_renamed|pe_find_any;
701 break;
702
703 case 'W':
704 case 'A':
705 case 'a':
706 rsc_cmd = flag;
707 find_flags = pe_find_renamed|pe_find_anon;
708 break;
709
710 case 'j':
711 print_pending = TRUE;
712 break;
713
714 case 'S':
715 require_dataset = FALSE;
716 crm_log_args(argc, argv);
717 prop_name = optarg;
718 rsc_cmd = flag;
719 find_flags = pe_find_renamed|pe_find_any;
720 break;
721
722 case 'p':
723 case 'd':
724 crm_log_args(argc, argv);
725 prop_name = optarg;
726 rsc_cmd = flag;
727 find_flags = pe_find_renamed|pe_find_any;
728 break;
729
730 case 'G':
731 case 'g':
732 prop_name = optarg;
733 rsc_cmd = flag;
734 find_flags = pe_find_renamed|pe_find_any;
735 break;
736 case 'h':
737 case 'H':
738 case 'N':
739 crm_trace("Option %c => %s", flag, optarg);
740 host_uname = optarg;
741 break;
742
743 default:
744 CMD_ERR("Argument code 0%o (%c) is not (?yet?) supported", flag, flag);
745 ++argerr;
746 break;
747 }
748 }
749
750
751 if (rsc_cmd == 'L') {
752 require_resource = FALSE;
753 }
754
755 if (optind < argc
756 && argv[optind] != NULL
757 && rsc_cmd == 0
758 && rsc_long_cmd) {
759
760 override_params = crm_str_table_new();
761 while (optind < argc && argv[optind] != NULL) {
762 char *name = calloc(1, strlen(argv[optind]));
763 char *value = calloc(1, strlen(argv[optind]));
764 int rc = sscanf(argv[optind], "%[^=]=%s", name, value);
765
766 if(rc == 2) {
767 g_hash_table_replace(override_params, name, value);
768
769 } else {
770 CMD_ERR("Error parsing '%s' as a name=value pair for --%s", argv[optind], rsc_long_cmd);
771 free(value);
772 free(name);
773 argerr++;
774 }
775 optind++;
776 }
777
778 } else if (optind < argc && argv[optind] != NULL && rsc_cmd == 0) {
779 CMD_ERR("non-option ARGV-elements: ");
780 while (optind < argc && argv[optind] != NULL) {
781 CMD_ERR("[%d of %d] %s ", optind, argc, argv[optind]);
782 optind++;
783 argerr++;
784 }
785 }
786
787 if (optind > argc) {
788 ++argerr;
789 }
790
791 if (argerr) {
792 CMD_ERR("Invalid option(s) supplied, use --help for valid usage");
793 return crm_exit(EX_USAGE);
794 }
795
796 our_pid = crm_getpid_s();
797
798 if (do_force) {
799 crm_debug("Forcing...");
800 cib_options |= cib_quorum_override;
801 }
802
803 data_set.input = NULL;
804
805 if (require_resource && !rsc_id) {
806 CMD_ERR("Must supply a resource id with -r");
807 rc = -ENXIO;
808 goto bail;
809 }
810
811 if (find_flags && rsc_id) {
812 require_dataset = TRUE;
813 }
814
815
816 cib_conn = cib_new();
817 rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command);
818 if (rc != pcmk_ok) {
819 CMD_ERR("Error signing on to the CIB service: %s", pcmk_strerror(rc));
820 goto bail;
821 }
822
823
824 if (require_dataset) {
825 xmlNode *cib_xml_copy = NULL;
826
827 if (xml_file != NULL) {
828 cib_xml_copy = filename2xml(xml_file);
829
830 } else {
831 rc = cib_conn->cmds->query(cib_conn, NULL, &cib_xml_copy, cib_scope_local | cib_sync_call);
832 }
833
834 if(rc != pcmk_ok) {
835 goto bail;
836 }
837
838
839 set_working_set_defaults(&data_set);
840 rc = update_working_set_xml(&data_set, &cib_xml_copy);
841 if (rc != pcmk_ok) {
842 goto bail;
843 }
844 cluster_status(&data_set);
845 }
846
847
848 if (find_flags && rsc_id) {
849 rsc = pe_find_resource_with_flags(data_set.resources, rsc_id,
850 find_flags);
851 if (rsc == NULL) {
852 CMD_ERR("Resource '%s' not found", rsc_id);
853 rc = -ENXIO;
854 goto bail;
855 }
856 }
857
858
859 if (require_crmd) {
860 xmlNode *xml = NULL;
861 mainloop_io_t *source =
862 mainloop_add_ipc_client(CRM_SYSTEM_CRMD, G_PRIORITY_DEFAULT, 0, NULL, &crm_callbacks);
863 crmd_channel = mainloop_get_ipc_client(source);
864
865 if (crmd_channel == NULL) {
866 CMD_ERR("Error signing on to the CRMd service");
867 rc = -ENOTCONN;
868 goto bail;
869 }
870
871 xml = create_hello_message(our_pid, crm_system_name, "0", "1");
872 crm_ipc_send(crmd_channel, xml, 0, 0, NULL);
873 free_xml(xml);
874 }
875
876
877 if (rsc_cmd == 'L') {
878 rc = pcmk_ok;
879 cli_resource_print_list(&data_set, FALSE);
880
881 } else if (rsc_cmd == 'l') {
882 int found = 0;
883 GListPtr lpc = NULL;
884
885 rc = pcmk_ok;
886 for (lpc = data_set.resources; lpc != NULL; lpc = lpc->next) {
887 rsc = (resource_t *) lpc->data;
888
889 found++;
890 cli_resource_print_raw(rsc);
891 }
892
893 if (found == 0) {
894 printf("NO resources configured\n");
895 rc = -ENXIO;
896 }
897
898 } else if (rsc_cmd == 0 && rsc_long_cmd && safe_str_eq(rsc_long_cmd, "restart")) {
899 rc = cli_resource_restart(rsc, host_uname, timeout_ms, cib_conn);
900
901 } else if (rsc_cmd == 0 && rsc_long_cmd && safe_str_eq(rsc_long_cmd, "wait")) {
902 rc = wait_till_stable(timeout_ms, cib_conn);
903
904 } else if (rsc_cmd == 0 && rsc_long_cmd) {
905
906 rc = cli_resource_execute(rsc, rsc_id, rsc_long_cmd, override_params,
907 timeout_ms, cib_conn, &data_set);
908 if (rc >= 0) {
909 is_ocf_rc = 1;
910 }
911
912 } else if (rsc_cmd == 'A' || rsc_cmd == 'a') {
913 GListPtr lpc = NULL;
914 xmlNode *cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, data_set.input);
915
916 unpack_constraints(cib_constraints, &data_set);
917
918
919 rsc = uber_parent(rsc);
920
921 for (lpc = data_set.resources; lpc != NULL; lpc = lpc->next) {
922 resource_t *r = (resource_t *) lpc->data;
923
924 clear_bit(r->flags, pe_rsc_allocating);
925 }
926
927 cli_resource_print_colocation(rsc, TRUE, rsc_cmd == 'A', 1);
928
929 fprintf(stdout, "* %s\n", rsc->id);
930 cli_resource_print_location(rsc, NULL);
931
932 for (lpc = data_set.resources; lpc != NULL; lpc = lpc->next) {
933 resource_t *r = (resource_t *) lpc->data;
934
935 clear_bit(r->flags, pe_rsc_allocating);
936 }
937
938 cli_resource_print_colocation(rsc, FALSE, rsc_cmd == 'A', 1);
939
940 } else if (rsc_cmd == 'c') {
941 GListPtr lpc = NULL;
942
943 rc = pcmk_ok;
944 for (lpc = data_set.resources; lpc != NULL; lpc = lpc->next) {
945 rsc = (resource_t *) lpc->data;
946 cli_resource_print_cts(rsc);
947 }
948 cli_resource_print_cts_constraints(&data_set);
949
950 } else if (rsc_cmd == 'F') {
951 rc = cli_resource_fail(crmd_channel, host_uname, rsc_id, &data_set);
952 if (rc == pcmk_ok) {
953 start_mainloop();
954 }
955
956 } else if (rsc_cmd == 'O') {
957 rc = cli_resource_print_operations(rsc_id, host_uname, TRUE, &data_set);
958
959 } else if (rsc_cmd == 'o') {
960 rc = cli_resource_print_operations(rsc_id, host_uname, FALSE, &data_set);
961
962 } else if (rsc_cmd == 'W') {
963 rc = cli_resource_search(rsc, rsc_id, &data_set);
964 if (rc >= 0) {
965 rc = pcmk_ok;
966 }
967
968 } else if (rsc_cmd == 'q') {
969 rc = cli_resource_print(rsc, &data_set, TRUE);
970
971 } else if (rsc_cmd == 'w') {
972 rc = cli_resource_print(rsc, &data_set, FALSE);
973
974 } else if (rsc_cmd == 'Y') {
975 node_t *dest = NULL;
976
977 if (host_uname) {
978 dest = pe_find_node(data_set.nodes, host_uname);
979 if (dest == NULL) {
980 CMD_ERR("Unknown node: %s", host_uname);
981 rc = -ENXIO;
982 goto bail;
983 }
984 }
985 cli_resource_why(cib_conn, data_set.resources, rsc, dest);
986 rc = pcmk_ok;
987
988 } else if (rsc_cmd == 'U') {
989 node_t *dest = NULL;
990
991 if (host_uname) {
992 dest = pe_find_node(data_set.nodes, host_uname);
993 if (dest == NULL) {
994 CMD_ERR("Unknown node: %s", host_uname);
995 rc = -ENXIO;
996 goto bail;
997 }
998 rc = cli_resource_clear(rsc_id, dest->details->uname, NULL, cib_conn);
999
1000 } else {
1001 rc = cli_resource_clear(rsc_id, NULL, data_set.nodes, cib_conn);
1002 }
1003
1004 } else if (rsc_cmd == 'M' && host_uname) {
1005 rc = cli_resource_move(rsc, rsc_id, host_uname, cib_conn, &data_set);
1006
1007 } else if (rsc_cmd == 'B' && host_uname) {
1008 node_t *dest = pe_find_node(data_set.nodes, host_uname);
1009
1010 if (dest == NULL) {
1011 CMD_ERR("Error performing operation: node '%s' is unknown", host_uname);
1012 rc = -ENXIO;
1013 goto bail;
1014 }
1015 rc = cli_resource_ban(rsc_id, dest->details->uname, NULL, cib_conn);
1016
1017 } else if (rsc_cmd == 'B' || rsc_cmd == 'M') {
1018 rc = -EINVAL;
1019 if (g_list_length(rsc->running_on) == 1) {
1020 node_t *current = rsc->running_on->data;
1021 rc = cli_resource_ban(rsc_id, current->details->uname, NULL, cib_conn);
1022
1023 } else if(rsc->variant == pe_master) {
1024 int count = 0;
1025 GListPtr iter = NULL;
1026 node_t *current = NULL;
1027
1028 for(iter = rsc->children; iter; iter = iter->next) {
1029 resource_t *child = (resource_t *)iter->data;
1030 enum rsc_role_e child_role = child->fns->state(child, TRUE);
1031
1032 if(child_role == RSC_ROLE_MASTER) {
1033 count++;
1034 current = child->running_on->data;
1035 }
1036 }
1037
1038 if(count == 1 && current) {
1039 rc = cli_resource_ban(rsc_id, current->details->uname, NULL, cib_conn);
1040
1041 } else {
1042 CMD_ERR("Resource '%s' not moved: active in %d locations (promoted in %d).", rsc_id, g_list_length(rsc->running_on), count);
1043 CMD_ERR("You can prevent '%s' from running on a specific location with: --ban --node <name>", rsc_id);
1044 CMD_ERR("You can prevent '%s' from being promoted at a specific location with:"
1045 " --ban --master --node <name>", rsc_id);
1046 }
1047
1048 } else {
1049 CMD_ERR("Resource '%s' not moved: active in %d locations.", rsc_id, g_list_length(rsc->running_on));
1050 CMD_ERR("You can prevent '%s' from running on a specific location with: --ban --node <name>", rsc_id);
1051 }
1052
1053 } else if (rsc_cmd == 'G') {
1054 rc = cli_resource_print_property(rsc, prop_name, &data_set);
1055
1056 } else if (rsc_cmd == 'S') {
1057 xmlNode *msg_data = NULL;
1058
1059 if ((rsc_type == NULL) || !strlen(rsc_type)) {
1060 CMD_ERR("Must specify -t with resource type");
1061 rc = -ENXIO;
1062 goto bail;
1063
1064 } else if ((prop_value == NULL) || !strlen(prop_value)) {
1065 CMD_ERR("Must supply -v with new value");
1066 rc = -EINVAL;
1067 goto bail;
1068 }
1069
1070 CRM_LOG_ASSERT(prop_name != NULL);
1071
1072 msg_data = create_xml_node(NULL, rsc_type);
1073 crm_xml_add(msg_data, XML_ATTR_ID, rsc_id);
1074 crm_xml_add(msg_data, prop_name, prop_value);
1075
1076 rc = cib_conn->cmds->modify(cib_conn, XML_CIB_TAG_RESOURCES, msg_data, cib_options);
1077 free_xml(msg_data);
1078
1079 } else if (rsc_cmd == 'g') {
1080 rc = cli_resource_print_attribute(rsc, prop_name, &data_set);
1081
1082 } else if (rsc_cmd == 'p') {
1083 if (prop_value == NULL || strlen(prop_value) == 0) {
1084 CMD_ERR("You need to supply a value with the -v option");
1085 rc = -EINVAL;
1086 goto bail;
1087 }
1088
1089
1090 rc = cli_resource_update_attribute(rsc, rsc_id, prop_set, prop_id,
1091 prop_name, prop_value, recursive,
1092 cib_conn, &data_set);
1093
1094 } else if (rsc_cmd == 'd') {
1095
1096 rc = cli_resource_delete_attribute(rsc, rsc_id, prop_set, prop_id,
1097 prop_name, cib_conn, &data_set);
1098
1099 } else if (rsc_cmd == 'C' && just_errors) {
1100 crmd_replies_needed = 0;
1101 for (xmlNode *xml_op = __xml_first_child(data_set.failed); xml_op != NULL;
1102 xml_op = __xml_next(xml_op)) {
1103
1104 const char *node = crm_element_value(xml_op, XML_ATTR_UNAME);
1105 const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
1106 const char *task_interval = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL);
1107 const char *resource_name = crm_element_value(xml_op, XML_LRM_ATTR_RSCID);
1108
1109 if(resource_name == NULL) {
1110 continue;
1111 } else if(host_uname && safe_str_neq(host_uname, node)) {
1112 continue;
1113 } else if(rsc_id && safe_str_neq(rsc_id, resource_name)) {
1114 continue;
1115 } else if(operation && safe_str_neq(operation, task)) {
1116 continue;
1117 } else if(interval && safe_str_neq(interval, task_interval)) {
1118 continue;
1119 }
1120
1121 crm_debug("Erasing %s failure for %s (%s detected) on %s",
1122 task, rsc->id, resource_name, node);
1123 rc = cli_resource_delete(crmd_channel, node, rsc, task,
1124 task_interval, &data_set);
1125 }
1126
1127 if(rsc && (rc == pcmk_ok) && (BE_QUIET == FALSE)) {
1128
1129 cli_resource_check(cib_conn, rsc);
1130 }
1131
1132 if (rc == pcmk_ok) {
1133 start_mainloop();
1134 }
1135
1136 } else if ((rsc_cmd == 'C') && rsc) {
1137 if(do_force == FALSE) {
1138 rsc = uber_parent(rsc);
1139 }
1140
1141 crm_debug("Re-checking the state of %s (%s requested) on %s",
1142 rsc->id, rsc_id, host_uname);
1143 crmd_replies_needed = 0;
1144 rc = cli_resource_delete(crmd_channel, host_uname, rsc, operation,
1145 interval, &data_set);
1146
1147 if(rc == pcmk_ok && BE_QUIET == FALSE) {
1148
1149 cli_resource_check(cib_conn, rsc);
1150 }
1151
1152 if (rc == pcmk_ok) {
1153 start_mainloop();
1154 }
1155
1156 } else if (rsc_cmd == 'C') {
1157 #if HAVE_ATOMIC_ATTRD
1158 const char *router_node = host_uname;
1159 xmlNode *msg_data = NULL;
1160 xmlNode *cmd = NULL;
1161 int attr_options = attrd_opt_none;
1162
1163 if (host_uname) {
1164 node_t *node = pe_find_node(data_set.nodes, host_uname);
1165
1166 if (node && is_remote_node(node)) {
1167 if (node->details->remote_rsc == NULL || node->details->remote_rsc->running_on == NULL) {
1168 CMD_ERR("No lrmd connection detected to remote node %s", host_uname);
1169 rc = -ENXIO;
1170 goto bail;
1171 }
1172 node = node->details->remote_rsc->running_on->data;
1173 router_node = node->details->uname;
1174 attr_options |= attrd_opt_remote;
1175 }
1176 }
1177
1178 if (crmd_channel == NULL) {
1179 printf("Dry run: skipping clean-up of %s due to CIB_file\n",
1180 host_uname? host_uname : "all nodes");
1181 rc = pcmk_ok;
1182 goto bail;
1183 }
1184
1185 msg_data = create_xml_node(NULL, "crm-resource-reprobe-op");
1186 crm_xml_add(msg_data, XML_LRM_ATTR_TARGET, host_uname);
1187 if (safe_str_neq(router_node, host_uname)) {
1188 crm_xml_add(msg_data, XML_LRM_ATTR_ROUTER_NODE, router_node);
1189 }
1190
1191 cmd = create_request(CRM_OP_REPROBE, msg_data, router_node,
1192 CRM_SYSTEM_CRMD, crm_system_name, our_pid);
1193 free_xml(msg_data);
1194
1195 crm_debug("Re-checking the state of all resources on %s", host_uname?host_uname:"all nodes");
1196
1197 rc = attrd_clear_delegate(NULL, host_uname, NULL, NULL, NULL, NULL,
1198 attr_options);
1199
1200 if (crm_ipc_send(crmd_channel, cmd, 0, 0, NULL) > 0) {
1201 start_mainloop();
1202 }
1203
1204 free_xml(cmd);
1205 #else
1206 GListPtr rIter = NULL;
1207
1208 crmd_replies_needed = 0;
1209 for (rIter = data_set.resources; rIter; rIter = rIter->next) {
1210 rsc = rIter->data;
1211 cli_resource_delete(crmd_channel, host_uname, rsc, NULL, NULL,
1212 &data_set);
1213 }
1214
1215 start_mainloop();
1216 #endif
1217
1218 } else if (rsc_cmd == 'D') {
1219 xmlNode *msg_data = NULL;
1220
1221 if (rsc_type == NULL) {
1222 CMD_ERR("You need to specify a resource type with -t");
1223 rc = -ENXIO;
1224 goto bail;
1225 }
1226
1227 msg_data = create_xml_node(NULL, rsc_type);
1228 crm_xml_add(msg_data, XML_ATTR_ID, rsc_id);
1229
1230 rc = cib_conn->cmds->delete(cib_conn, XML_CIB_TAG_RESOURCES, msg_data, cib_options);
1231 free_xml(msg_data);
1232
1233 } else {
1234 CMD_ERR("Unknown command: %c", rsc_cmd);
1235 }
1236
1237 bail:
1238
1239 free(our_pid);
1240
1241 if (data_set.input != NULL) {
1242 cleanup_alloc_calculations(&data_set);
1243 }
1244 if (cib_conn != NULL) {
1245 cib_conn->cmds->signoff(cib_conn);
1246 cib_delete(cib_conn);
1247 }
1248
1249 if (rc == -pcmk_err_no_quorum) {
1250 CMD_ERR("Error performing operation: %s", pcmk_strerror(rc));
1251 CMD_ERR("Try using -f");
1252
1253 } else if (rc != pcmk_ok && !is_ocf_rc) {
1254 CMD_ERR("Error performing operation: %s", pcmk_strerror(rc));
1255 }
1256
1257 return crm_exit(rc);
1258 }