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