root/daemons/execd/cts-exec-helper.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 2012-2020 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU Lesser General Public License
   7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   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     // long option, argument type, storage, short option, description, flags
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 178 {
 179     lrmd_api_delete(lrmd_conn);
 180     lrmd_conn = NULL;
 181 }
 182 
 183 static void
 184 read_events(lrmd_event_data_t * event)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 219 {
 220     int rc = event->connection_rc;
 221 
 222     if (event->type != lrmd_event_connect) {
 223         /* ignore */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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, "pacemaker-execd", 3000);
 248 
 249         if (!rc) {
 250             return;             /* we'll hear back in async callback */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 261 {
 262     int rc = 0;
 263 
 264     if (!options.no_connect) {
 265         if (!lrmd_conn->cmds->is_connected(lrmd_conn)) {
 266             try_connect();
 267             /* async connect -- this function will get called back into */
 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         /* just make the call and exit regardless of anything else. */
 417         test_exit(CRM_EX_OK);
 418     }
 419 
 420     return 0;
 421 }
 422 
 423 static int
 424 generate_params(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 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, "cts-exec-helper", 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 = crm_str_table_new();
 486     meta = crm_str_table_new();
 487 
 488     get_rsc_attributes(params, rsc, NULL, data_set);
 489     get_meta_attributes(meta, rsc, NULL, data_set);
 490 
 491     if (params) {
 492         char *key = NULL;
 493         char *value = NULL;
 494 
 495         g_hash_table_iter_init(&iter, params);
 496         while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
 497             options.params = lrmd_key_value_add(options.params, key, value);
 498         }
 499         g_hash_table_destroy(params);
 500     }
 501 
 502     if (meta) {
 503         char *key = NULL;
 504         char *value = NULL;
 505 
 506         g_hash_table_iter_init(&iter, meta);
 507         while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
 508             char *crm_name = crm_meta_name(key);
 509 
 510             options.params = lrmd_key_value_add(options.params, crm_name, value);
 511             free(crm_name);
 512         }
 513         g_hash_table_destroy(meta);
 514     }
 515 
 516   param_gen_bail:
 517     pe_free_working_set(data_set);
 518     return rc;
 519 }
 520 
 521 int
 522 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 523 {
 524     int option_index = 0;
 525     int argerr = 0;
 526     int flag;
 527     char *key = NULL;
 528     char *val = NULL;
 529     gboolean use_tls = FALSE;
 530     crm_trigger_t *trig;
 531 
 532     crm_log_cli_init("cts-exec-helper");
 533     pcmk__set_cli_options(NULL, "<mode> [options]", long_options,
 534                           "inject commands into the Pacemaker executor, "
 535                           "and watch for events");
 536 
 537     while (1) {
 538         flag = pcmk__next_cli_option(argc, argv, &option_index, NULL);
 539         if (flag == -1)
 540             break;
 541 
 542         switch (flag) {
 543             case '?':
 544                 pcmk__cli_help(flag, CRM_EX_OK);
 545                 break;
 546             case 'V':
 547                 ++options.verbose;
 548                 crm_bump_log_level(argc, argv);
 549                 break;
 550             case 'Q':
 551                 options.quiet = 1;
 552                 options.verbose = 0;
 553                 break;
 554             case 'l':
 555                 options.listen = optarg;
 556                 break;
 557             case 'w':
 558                 options.no_wait = 1;
 559                 break;
 560             case 'R':
 561                 options.is_running = 1;
 562                 break;
 563             case 'n':
 564                 exec_call_opts = lrmd_opt_notify_orig_only;
 565                 break;
 566             case 'o':
 567                 exec_call_opts = lrmd_opt_notify_changes_only;
 568                 break;
 569             case 'c':
 570                 options.api_call = optarg;
 571                 break;
 572             case 'a':
 573                 options.action = optarg;
 574                 break;
 575             case 'r':
 576                 options.rsc_id = optarg;
 577                 break;
 578             case 'x':
 579                 if(optarg) {
 580                     options.cancel_call_id = atoi(optarg);
 581                 }
 582                 break;
 583             case 'P':
 584                 options.provider = optarg;
 585                 break;
 586             case 'C':
 587                 options.class = optarg;
 588                 break;
 589             case 'T':
 590                 options.type = optarg;
 591                 break;
 592             case 'i':
 593                 if(optarg) {
 594                     options.interval_ms = crm_parse_interval_spec(optarg);
 595                 }
 596                 break;
 597             case 't':
 598                 if(optarg) {
 599                     options.timeout = atoi(optarg);
 600                 }
 601                 break;
 602             case 's':
 603                 if(optarg) {
 604                     options.start_delay = atoi(optarg);
 605                 }
 606                 break;
 607             case 'k':
 608                 key = optarg;
 609                 if (key && val) {
 610                     options.params = lrmd_key_value_add(options.params, key, val);
 611                     key = val = NULL;
 612                 }
 613                 break;
 614             case 'v':
 615                 val = optarg;
 616                 if (key && val) {
 617                     options.params = lrmd_key_value_add(options.params, key, val);
 618                     key = val = NULL;
 619                 }
 620                 break;
 621             case 'S':
 622                 use_tls = TRUE;
 623                 break;
 624             default:
 625                 ++argerr;
 626                 break;
 627         }
 628     }
 629 
 630     if (argerr) {
 631         pcmk__cli_help('?', CRM_EX_USAGE);
 632     }
 633     if (optind > argc) {
 634         ++argerr;
 635     }
 636 
 637     if (!options.listen && pcmk__strcase_any_of(options.api_call, "metadata", "list_agents",
 638                                                 "list_standards", "list_ocf_providers", NULL)) {
 639         options.no_connect = 1;
 640     }
 641 
 642     crm_log_init(NULL, LOG_INFO, TRUE, (options.verbose? TRUE : FALSE),
 643                  argc, argv, FALSE);
 644 
 645     if (options.is_running) {
 646         if (!options.timeout) {
 647             options.timeout = 30000;
 648         }
 649         options.interval_ms = 0;
 650         if (!options.rsc_id) {
 651             crm_err("rsc-id must be given when is-running is used");
 652             test_exit(CRM_EX_ERROR);
 653         }
 654 
 655         if (generate_params()) {
 656             print_result(printf
 657                          ("Failed to retrieve rsc parameters from cib, can not determine if rsc is running.\n"));
 658             test_exit(CRM_EX_ERROR);
 659         }
 660         options.api_call = "exec";
 661         options.action = "monitor";
 662         exec_call_opts = lrmd_opt_notify_orig_only;
 663     }
 664 
 665     /* if we can't perform an api_call or listen for events, 
 666      * there is nothing to do */
 667     if (!options.api_call && !options.listen) {
 668         crm_err("Nothing to be done.  Please specify 'api-call' and/or 'listen'");
 669         return CRM_EX_OK;
 670     }
 671 
 672     if (use_tls) {
 673         lrmd_conn = lrmd_remote_api_new(NULL, "localhost", 0);
 674     } else {
 675         lrmd_conn = lrmd_api_new();
 676     }
 677     trig = mainloop_add_trigger(G_PRIORITY_HIGH, start_test, NULL);
 678     mainloop_set_trigger(trig);
 679     mainloop_add_signal(SIGTERM, test_shutdown);
 680 
 681     crm_info("Starting");
 682     mainloop = g_main_loop_new(NULL, FALSE);
 683     g_main_loop_run(mainloop);
 684 
 685     if (cib_conn != NULL) {
 686         cib_conn->cmds->signoff(cib_conn);
 687         cib_delete(cib_conn);
 688     }
 689 
 690     test_exit(CRM_EX_OK);
 691     return CRM_EX_OK;
 692 }

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