root/lrmd/test.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. test_exit
  2. test_shutdown
  3. read_events
  4. timeout_err
  5. connection_events
  6. try_connect
  7. start_test
  8. generate_params
  9. main

   1 /*
   2  * Copyright (c) 2012 David Vossel <davidvossel@gmail.com>
   3  *
   4  * This library is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU Lesser General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2.1 of the License, or (at your option) any later version.
   8  * 
   9  * This library is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * Lesser General Public License for more details.
  13  * 
  14  * You should have received a copy of the GNU Lesser General Public
  15  * License along with this library; if not, write to the Free Software
  16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  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 /* *INDENT-OFF* */
  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 /* *INDENT-ON* */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
 119 {
 120     lrmd_api_delete(lrmd_conn);
 121     lrmd_conn = NULL;
 122 }
 123 
 124 static void
 125 read_events(lrmd_event_data_t * event)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 161 {
 162     int rc = event->connection_rc;
 163 
 164     if (event->type != lrmd_event_connect) {
 165         /* ignore */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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;             /* we'll hear back in async callback */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 203 {
 204     int rc = 0;
 205 
 206     if (!options.no_connect) {
 207         if (!lrmd_conn->cmds->is_connected(lrmd_conn)) {
 208             try_connect();
 209             /* async connect -- this function will get called back into */
 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         /* just make the call and exit regardless of anything else. */
 342         test_exit(0);
 343     }
 344 
 345     return 0;
 346 }
 347 
 348 static int
 349 generate_params(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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     /* if we can't perform an api_call or listen for events, 
 586      * there is nothing to do */
 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 }

/* [previous][next][first][last][top][bottom][index][help] */