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