This source file includes following definitions.
- test_exit
- test_shutdown
- read_events
- timeout_err
- connection_events
- try_connect
- start_test
- generate_params
- main
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <glib.h>
13 #include <unistd.h>
14
15 #include <crm/crm.h>
16 #include <crm/services.h>
17 #include <crm/common/mainloop.h>
18
19 #include <crm/pengine/status.h>
20 #include <crm/pengine/internal.h>
21 #include <crm/cib.h>
22 #include <crm/lrmd.h>
23
24 static pcmk__cli_option_t long_options[] = {
25
26 {
27 "help", no_argument, NULL, '?',
28 NULL, pcmk__option_default
29 },
30 {
31 "verbose", no_argument, NULL, 'V',
32 "\t\tPrint out logs and events to screen", pcmk__option_default
33 },
34 {
35 "quiet", no_argument, NULL, 'Q',
36 "\t\tSuppress all output to screen", pcmk__option_default
37 },
38 {
39 "tls", no_argument, NULL, 'S',
40 "\t\tUse TLS backend for local connection", pcmk__option_default
41 },
42 {
43 "listen", required_argument, NULL, 'l',
44 "\tListen for a specific event string", pcmk__option_default
45 },
46 {
47 "api-call", required_argument, NULL, 'c',
48 "\tDirectly relates to executor API functions", pcmk__option_default
49 },
50 {
51 "no-wait", no_argument, NULL, 'w',
52 "\tMake api call and do not wait for result", pcmk__option_default
53 },
54 {
55 "is-running", no_argument, NULL, 'R',
56 "\tDetermine if a resource is registered and running",
57 pcmk__option_default
58 },
59 {
60 "notify-orig", no_argument, NULL, 'n',
61 "\tOnly notify this client the results of an API action",
62 pcmk__option_default
63 },
64 {
65 "notify-changes", no_argument, NULL, 'o',
66 "\tOnly notify client changes to recurring operations",
67 pcmk__option_default
68 },
69 {
70 "-spacer-", no_argument, NULL, '-',
71 "\nParameters for api-call option", pcmk__option_default
72 },
73 {
74 "action", required_argument, NULL, 'a',
75 NULL, pcmk__option_default
76 },
77 {
78 "rsc-id", required_argument, NULL, 'r',
79 NULL, pcmk__option_default
80 },
81 {
82 "cancel-call-id", required_argument, NULL, 'x',
83 NULL, pcmk__option_default
84 },
85 {
86 "provider", required_argument, NULL, 'P',
87 NULL, pcmk__option_default
88 },
89 {
90 "class", required_argument, NULL, 'C',
91 NULL, pcmk__option_default
92 },
93 {
94 "type", required_argument, NULL, 'T',
95 NULL, pcmk__option_default
96 },
97 {
98 "interval", required_argument, NULL, 'i',
99 NULL, pcmk__option_default
100 },
101 {
102 "timeout", required_argument, NULL, 't',
103 NULL, pcmk__option_default
104 },
105 {
106 "start-delay", required_argument, NULL, 's',
107 NULL, pcmk__option_default
108 },
109 {
110 "param-key", required_argument, NULL, 'k',
111 NULL, pcmk__option_default
112 },
113 {
114 "param-val", required_argument, NULL, 'v',
115 NULL, pcmk__option_default
116 },
117 {
118 "-spacer-", no_argument, NULL, '-',
119 NULL, pcmk__option_default
120 },
121 { 0, 0, 0, 0 }
122 };
123
124 static cib_t *cib_conn = NULL;
125 static int exec_call_id = 0;
126 static int exec_call_opts = 0;
127 static gboolean start_test(gpointer user_data);
128 static void try_connect(void);
129
130 static struct {
131 int verbose;
132 int quiet;
133 guint interval_ms;
134 int timeout;
135 int start_delay;
136 int cancel_call_id;
137 int no_wait;
138 int is_running;
139 int no_connect;
140 const char *api_call;
141 const char *rsc_id;
142 const char *provider;
143 const char *class;
144 const char *type;
145 const char *action;
146 const char *listen;
147 lrmd_key_value_t *params;
148 } options;
149
150 static GMainLoop *mainloop = NULL;
151 static lrmd_t *lrmd_conn = NULL;
152
153 static char event_buf_v0[1024];
154
155 static void
156 test_exit(crm_exit_t exit_code)
157 {
158 lrmd_api_delete(lrmd_conn);
159 crm_exit(exit_code);
160 }
161
162 #define print_result(result) \
163 if (!options.quiet) { \
164 result; \
165 } \
166
167 #define report_event(event) \
168 snprintf(event_buf_v0, sizeof(event_buf_v0), "NEW_EVENT event_type:%s rsc_id:%s action:%s rc:%s op_status:%s", \
169 lrmd_event_type2str(event->type), \
170 event->rsc_id, \
171 event->op_type ? event->op_type : "none", \
172 services_ocf_exitcode_str(event->rc), \
173 services_lrm_status_str(event->op_status)); \
174 crm_info("%s", event_buf_v0);
175
176 static void
177 test_shutdown(int nsig)
178 {
179 lrmd_api_delete(lrmd_conn);
180 lrmd_conn = NULL;
181 }
182
183 static void
184 read_events(lrmd_event_data_t * event)
185 {
186 report_event(event);
187 if (options.listen) {
188 if (pcmk__str_eq(options.listen, event_buf_v0, pcmk__str_casei)) {
189 print_result(printf("LISTEN EVENT SUCCESSFUL\n"));
190 test_exit(CRM_EX_OK);
191 }
192 }
193
194 if (exec_call_id && (event->call_id == exec_call_id)) {
195 if (event->op_status == 0 && event->rc == 0) {
196 print_result(printf("API-CALL SUCCESSFUL for 'exec'\n"));
197 } else {
198 print_result(printf("API-CALL FAILURE for 'exec', rc:%d lrmd_op_status:%s\n",
199 event->rc, services_lrm_status_str(event->op_status)));
200 test_exit(CRM_EX_ERROR);
201 }
202
203 if (!options.listen) {
204 test_exit(CRM_EX_OK);
205 }
206 }
207 }
208
209 static gboolean
210 timeout_err(gpointer data)
211 {
212 print_result(printf("LISTEN EVENT FAILURE - timeout occurred, never found.\n"));
213 test_exit(CRM_EX_TIMEOUT);
214 return FALSE;
215 }
216
217 static void
218 connection_events(lrmd_event_data_t * event)
219 {
220 int rc = event->connection_rc;
221
222 if (event->type != lrmd_event_connect) {
223
224 return;
225 }
226
227 if (!rc) {
228 crm_info("Executor client connection established");
229 start_test(NULL);
230 return;
231 } else {
232 sleep(1);
233 try_connect();
234 crm_notice("Executor client connection failed");
235 }
236 }
237
238 static void
239 try_connect(void)
240 {
241 int tries = 10;
242 static int num_tries = 0;
243 int rc = 0;
244
245 lrmd_conn->cmds->set_callback(lrmd_conn, connection_events);
246 for (; num_tries < tries; num_tries++) {
247 rc = lrmd_conn->cmds->connect_async(lrmd_conn, crm_system_name, 3000);
248
249 if (!rc) {
250 return;
251 }
252 sleep(1);
253 }
254
255 print_result(printf("API CONNECTION FAILURE\n"));
256 test_exit(CRM_EX_ERROR);
257 }
258
259 static gboolean
260 start_test(gpointer user_data)
261 {
262 int rc = 0;
263
264 if (!options.no_connect) {
265 if (!lrmd_conn->cmds->is_connected(lrmd_conn)) {
266 try_connect();
267
268 return 0;
269 }
270 }
271 lrmd_conn->cmds->set_callback(lrmd_conn, read_events);
272
273 if (options.timeout) {
274 g_timeout_add(options.timeout, timeout_err, NULL);
275 }
276
277 if (!options.api_call) {
278 return 0;
279 }
280
281 if (pcmk__str_eq(options.api_call, "exec", pcmk__str_casei)) {
282 rc = lrmd_conn->cmds->exec(lrmd_conn,
283 options.rsc_id,
284 options.action,
285 NULL,
286 options.interval_ms,
287 options.timeout,
288 options.start_delay, exec_call_opts, options.params);
289
290 if (rc > 0) {
291 exec_call_id = rc;
292 print_result(printf("API-CALL 'exec' action pending, waiting on response\n"));
293 }
294
295 } else if (pcmk__str_eq(options.api_call, "register_rsc", pcmk__str_casei)) {
296 rc = lrmd_conn->cmds->register_rsc(lrmd_conn,
297 options.rsc_id,
298 options.class, options.provider, options.type, 0);
299 } else if (pcmk__str_eq(options.api_call, "get_rsc_info", pcmk__str_casei)) {
300 lrmd_rsc_info_t *rsc_info;
301
302 rsc_info = lrmd_conn->cmds->get_rsc_info(lrmd_conn, options.rsc_id, 0);
303
304 if (rsc_info) {
305 print_result(printf("RSC_INFO: id:%s class:%s provider:%s type:%s\n",
306 rsc_info->id, rsc_info->standard,
307 rsc_info->provider ? rsc_info->provider : "<none>",
308 rsc_info->type));
309 lrmd_free_rsc_info(rsc_info);
310 rc = pcmk_ok;
311 } else {
312 rc = -1;
313 }
314 } else if (pcmk__str_eq(options.api_call, "unregister_rsc", pcmk__str_casei)) {
315 rc = lrmd_conn->cmds->unregister_rsc(lrmd_conn, options.rsc_id, 0);
316 } else if (pcmk__str_eq(options.api_call, "cancel", pcmk__str_casei)) {
317 rc = lrmd_conn->cmds->cancel(lrmd_conn, options.rsc_id, options.action,
318 options.interval_ms);
319 } else if (pcmk__str_eq(options.api_call, "metadata", pcmk__str_casei)) {
320 char *output = NULL;
321
322 rc = lrmd_conn->cmds->get_metadata(lrmd_conn,
323 options.class,
324 options.provider, options.type, &output, 0);
325 if (rc == pcmk_ok) {
326 print_result(printf("%s", output));
327 free(output);
328 }
329 } else if (pcmk__str_eq(options.api_call, "list_agents", pcmk__str_casei)) {
330 lrmd_list_t *list = NULL;
331 lrmd_list_t *iter = NULL;
332
333 rc = lrmd_conn->cmds->list_agents(lrmd_conn, &list, options.class, options.provider);
334
335 if (rc > 0) {
336 print_result(printf("%d agents found\n", rc));
337 for (iter = list; iter != NULL; iter = iter->next) {
338 print_result(printf("%s\n", iter->val));
339 }
340 lrmd_list_freeall(list);
341 rc = 0;
342 } else {
343 print_result(printf("API_CALL FAILURE - no agents found\n"));
344 rc = -1;
345 }
346 } else if (pcmk__str_eq(options.api_call, "list_ocf_providers", pcmk__str_casei)) {
347 lrmd_list_t *list = NULL;
348 lrmd_list_t *iter = NULL;
349
350 rc = lrmd_conn->cmds->list_ocf_providers(lrmd_conn, options.type, &list);
351
352 if (rc > 0) {
353 print_result(printf("%d providers found\n", rc));
354 for (iter = list; iter != NULL; iter = iter->next) {
355 print_result(printf("%s\n", iter->val));
356 }
357 lrmd_list_freeall(list);
358 rc = 0;
359 } else {
360 print_result(printf("API_CALL FAILURE - no providers found\n"));
361 rc = -1;
362 }
363
364 } else if (pcmk__str_eq(options.api_call, "list_standards", pcmk__str_casei)) {
365 lrmd_list_t *list = NULL;
366 lrmd_list_t *iter = NULL;
367
368 rc = lrmd_conn->cmds->list_standards(lrmd_conn, &list);
369
370 if (rc > 0) {
371 print_result(printf("%d standards found\n", rc));
372 for (iter = list; iter != NULL; iter = iter->next) {
373 print_result(printf("%s\n", iter->val));
374 }
375 lrmd_list_freeall(list);
376 rc = 0;
377 } else {
378 print_result(printf("API_CALL FAILURE - no providers found\n"));
379 rc = -1;
380 }
381
382 } else if (pcmk__str_eq(options.api_call, "get_recurring_ops", pcmk__str_casei)) {
383 GList *op_list = NULL;
384 GList *op_item = NULL;
385 rc = lrmd_conn->cmds->get_recurring_ops(lrmd_conn, options.rsc_id, 0, 0,
386 &op_list);
387
388 for (op_item = op_list; op_item != NULL; op_item = op_item->next) {
389 lrmd_op_info_t *op_info = op_item->data;
390
391 print_result(printf("RECURRING_OP: %s_%s_%s timeout=%sms\n",
392 op_info->rsc_id, op_info->action,
393 op_info->interval_ms_s, op_info->timeout_ms_s));
394 lrmd_free_op_info(op_info);
395 }
396 g_list_free(op_list);
397
398 } else if (options.api_call) {
399 print_result(printf("API-CALL FAILURE unknown action '%s'\n", options.action));
400 test_exit(CRM_EX_ERROR);
401 }
402
403 if (rc < 0) {
404 print_result(printf("API-CALL FAILURE for '%s' api_rc:%d\n", options.api_call, rc));
405 test_exit(CRM_EX_ERROR);
406 }
407
408 if (options.api_call && rc == pcmk_ok) {
409 print_result(printf("API-CALL SUCCESSFUL for '%s'\n", options.api_call));
410 if (!options.listen) {
411 test_exit(CRM_EX_OK);
412 }
413 }
414
415 if (options.no_wait) {
416
417 test_exit(CRM_EX_OK);
418 }
419
420 return 0;
421 }
422
423 static int
424 generate_params(void)
425 {
426 int rc = 0;
427 pe_working_set_t *data_set = NULL;
428 xmlNode *cib_xml_copy = NULL;
429 pe_resource_t *rsc = NULL;
430 GHashTable *params = NULL;
431 GHashTable *meta = NULL;
432 GHashTableIter iter;
433
434 if (options.params) {
435 return 0;
436 }
437
438 data_set = pe_new_working_set();
439 if (data_set == NULL) {
440 crm_crit("Could not allocate working set");
441 return -ENOMEM;
442 }
443 pe__set_working_set_flags(data_set, pe_flag_no_counts|pe_flag_no_compat);
444
445 cib_conn = cib_new();
446 rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_query);
447 if (rc != pcmk_ok) {
448 crm_err("Could not connect to the CIB manager: %s", pcmk_strerror(rc));
449 rc = -1;
450 goto param_gen_bail;
451 }
452
453 rc = cib_conn->cmds->query(cib_conn, NULL, &cib_xml_copy, cib_scope_local | cib_sync_call);
454 if (rc != pcmk_ok) {
455 crm_err("Error retrieving cib copy: %s (%d)", pcmk_strerror(rc), rc);
456 goto param_gen_bail;
457
458 } else if (cib_xml_copy == NULL) {
459 rc = -ENODATA;
460 crm_err("Error retrieving cib copy: %s (%d)", pcmk_strerror(rc), rc);
461 goto param_gen_bail;
462 }
463
464 if (cli_config_update(&cib_xml_copy, NULL, FALSE) == FALSE) {
465 crm_err("Error updating cib configuration");
466 rc = -1;
467 goto param_gen_bail;
468 }
469
470 data_set->input = cib_xml_copy;
471 data_set->now = crm_time_new(NULL);
472
473 cluster_status(data_set);
474 if (options.rsc_id) {
475 rsc = pe_find_resource_with_flags(data_set->resources, options.rsc_id,
476 pe_find_renamed|pe_find_any);
477 }
478
479 if (!rsc) {
480 crm_err("Resource does not exist in config");
481 rc = -1;
482 goto param_gen_bail;
483 }
484
485 params = pe_rsc_params(rsc, NULL, data_set);
486 meta = pcmk__strkey_table(free, free);
487
488 get_meta_attributes(meta, rsc, NULL, data_set);
489
490 if (params != NULL) {
491 char *key = NULL;
492 char *value = NULL;
493
494 g_hash_table_iter_init(&iter, params);
495 while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
496 options.params = lrmd_key_value_add(options.params, key, value);
497 }
498 }
499
500 if (meta) {
501 char *key = NULL;
502 char *value = NULL;
503
504 g_hash_table_iter_init(&iter, meta);
505 while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
506 char *crm_name = crm_meta_name(key);
507
508 options.params = lrmd_key_value_add(options.params, crm_name, value);
509 free(crm_name);
510 }
511 g_hash_table_destroy(meta);
512 }
513
514 param_gen_bail:
515 pe_free_working_set(data_set);
516 return rc;
517 }
518
519 int
520 main(int argc, char **argv)
521 {
522 int option_index = 0;
523 int argerr = 0;
524 int flag;
525 char *key = NULL;
526 char *val = NULL;
527 gboolean use_tls = FALSE;
528 crm_trigger_t *trig;
529
530 pcmk__cli_init_logging("cts-exec-helper", 0);
531 pcmk__set_cli_options(NULL, "<mode> [options]", long_options,
532 "inject commands into the Pacemaker executor, "
533 "and watch for events");
534
535 while (1) {
536 flag = pcmk__next_cli_option(argc, argv, &option_index, NULL);
537 if (flag == -1)
538 break;
539
540 switch (flag) {
541 case '?':
542 pcmk__cli_help(flag, CRM_EX_OK);
543 break;
544 case 'V':
545 ++options.verbose;
546 crm_bump_log_level(argc, argv);
547 break;
548 case 'Q':
549 options.quiet = 1;
550 options.verbose = 0;
551 break;
552 case 'l':
553 options.listen = optarg;
554 break;
555 case 'w':
556 options.no_wait = 1;
557 break;
558 case 'R':
559 options.is_running = 1;
560 break;
561 case 'n':
562 exec_call_opts = lrmd_opt_notify_orig_only;
563 break;
564 case 'o':
565 exec_call_opts = lrmd_opt_notify_changes_only;
566 break;
567 case 'c':
568 options.api_call = optarg;
569 break;
570 case 'a':
571 options.action = optarg;
572 break;
573 case 'r':
574 options.rsc_id = optarg;
575 break;
576 case 'x':
577 if(optarg) {
578 options.cancel_call_id = atoi(optarg);
579 }
580 break;
581 case 'P':
582 options.provider = optarg;
583 break;
584 case 'C':
585 options.class = optarg;
586 break;
587 case 'T':
588 options.type = optarg;
589 break;
590 case 'i':
591 if(optarg) {
592 options.interval_ms = crm_parse_interval_spec(optarg);
593 }
594 break;
595 case 't':
596 if(optarg) {
597 options.timeout = atoi(optarg);
598 }
599 break;
600 case 's':
601 if(optarg) {
602 options.start_delay = atoi(optarg);
603 }
604 break;
605 case 'k':
606 key = optarg;
607 if (key && val) {
608 options.params = lrmd_key_value_add(options.params, key, val);
609 key = val = NULL;
610 }
611 break;
612 case 'v':
613 val = optarg;
614 if (key && val) {
615 options.params = lrmd_key_value_add(options.params, key, val);
616 key = val = NULL;
617 }
618 break;
619 case 'S':
620 use_tls = TRUE;
621 break;
622 default:
623 ++argerr;
624 break;
625 }
626 }
627
628 if (argerr) {
629 pcmk__cli_help('?', CRM_EX_USAGE);
630 }
631 if (optind > argc) {
632 ++argerr;
633 }
634
635 if (!options.listen && pcmk__strcase_any_of(options.api_call, "metadata", "list_agents",
636 "list_standards", "list_ocf_providers", NULL)) {
637 options.no_connect = 1;
638 }
639
640 crm_log_init(NULL, LOG_INFO, TRUE, (options.verbose? TRUE : FALSE),
641 argc, argv, FALSE);
642
643 if (options.is_running) {
644 if (!options.timeout) {
645 options.timeout = 30000;
646 }
647 options.interval_ms = 0;
648 if (!options.rsc_id) {
649 crm_err("rsc-id must be given when is-running is used");
650 test_exit(CRM_EX_ERROR);
651 }
652
653 if (generate_params()) {
654 print_result(printf
655 ("Failed to retrieve rsc parameters from cib, can not determine if rsc is running.\n"));
656 test_exit(CRM_EX_ERROR);
657 }
658 options.api_call = "exec";
659 options.action = "monitor";
660 exec_call_opts = lrmd_opt_notify_orig_only;
661 }
662
663
664
665 if (!options.api_call && !options.listen) {
666 crm_err("Nothing to be done. Please specify 'api-call' and/or 'listen'");
667 return CRM_EX_OK;
668 }
669
670 if (use_tls) {
671 lrmd_conn = lrmd_remote_api_new(NULL, "localhost", 0);
672 } else {
673 lrmd_conn = lrmd_api_new();
674 }
675 trig = mainloop_add_trigger(G_PRIORITY_HIGH, start_test, NULL);
676 mainloop_set_trigger(trig);
677 mainloop_add_signal(SIGTERM, test_shutdown);
678
679 crm_info("Starting");
680 mainloop = g_main_loop_new(NULL, FALSE);
681 g_main_loop_run(mainloop);
682
683 if (cib_conn != NULL) {
684 cib_conn->cmds->signoff(cib_conn);
685 cib_delete(cib_conn);
686 }
687
688 test_exit(CRM_EX_OK);
689 return CRM_EX_OK;
690 }