root/daemons/fenced/cts-fence-helper.c

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

DEFINITIONS

This source file includes following definitions.
  1. mainloop_test_done
  2. dispatch_helper
  3. st_callback
  4. st_global_callback
  5. passive_test
  6. run_fence_failure_test
  7. run_fence_failure_rollover_test
  8. run_standard_test
  9. sanity_tests
  10. standard_dev_test
  11. mainloop_callback
  12. register_callback_helper
  13. test_async_fence_pass
  14. test_async_fence_custom_timeout
  15. test_async_fence_timeout
  16. test_async_monitor
  17. test_register_async_devices
  18. try_mainloop_connect
  19. iterate_mainloop_tests
  20. trigger_iterate_mainloop_tests
  21. test_shutdown
  22. mainloop_tests
  23. main

   1 /*
   2  * Copyright 2009-2022 the Pacemaker project contributors
   3  *
   4  * This source code is licensed under the GNU General Public License version 2
   5  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   6  */
   7 
   8 #include <crm_internal.h>
   9 
  10 #include <sys/param.h>
  11 #include <stdio.h>
  12 #include <sys/time.h>
  13 #include <sys/types.h>
  14 #include <sys/stat.h>
  15 #include <unistd.h>
  16 #include <sys/utsname.h>
  17 
  18 #include <stdlib.h>
  19 #include <errno.h>
  20 #include <fcntl.h>
  21 
  22 #include <crm/crm.h>
  23 #include <crm/msg_xml.h>
  24 #include <crm/common/ipc.h>
  25 #include <crm/cluster/internal.h>
  26 
  27 #include <crm/stonith-ng.h>
  28 #include <crm/fencing/internal.h>
  29 #include <crm/common/agents.h>
  30 #include <crm/common/xml.h>
  31 
  32 #include <crm/common/mainloop.h>
  33 
  34 static GMainLoop *mainloop = NULL;
  35 static crm_trigger_t *trig = NULL;
  36 static int mainloop_iter = 0;
  37 static pcmk__action_result_t result = PCMK__UNKNOWN_RESULT;
  38 
  39 typedef void (*mainloop_test_iteration_cb) (int check_event);
  40 
  41 #define MAINLOOP_DEFAULT_TIMEOUT 2
  42 
  43 enum test_modes {
  44     test_standard = 0,  // test using a specific developer environment
  45     test_passive,       // watch notifications only
  46     test_api_sanity,    // sanity-test stonith client API using fence_dummy
  47     test_api_mainloop,  // sanity-test mainloop code with async responses
  48 };
  49 
  50 static pcmk__cli_option_t long_options[] = {
  51     // long option, argument type, storage, short option, description, flags
  52     {
  53         "verbose", no_argument, NULL, 'V',
  54         NULL, pcmk__option_default
  55     },
  56     {
  57         "version", no_argument, NULL, '$',
  58         NULL, pcmk__option_default
  59     },
  60     {
  61         "help", no_argument, NULL, '?',
  62         NULL, pcmk__option_default
  63     },
  64     {
  65         "passive", no_argument, NULL, 'p',
  66         NULL, pcmk__option_default
  67     },
  68     {
  69         "api_test", no_argument, NULL, 't',
  70         NULL, pcmk__option_default
  71     },
  72     {
  73         "mainloop_api_test", no_argument, NULL, 'm',
  74         NULL, pcmk__option_default
  75     },
  76     { 0, 0, 0, 0 }
  77 };
  78 
  79 static stonith_t *st = NULL;
  80 static struct pollfd pollfd;
  81 static const int st_opts = st_opt_sync_call;
  82 static int expected_notifications = 0;
  83 static int verbose = 0;
  84 
  85 static void
  86 mainloop_test_done(const char *origin, bool pass)
     /* [previous][next][first][last][top][bottom][index][help] */
  87 {
  88     if (pass) {
  89         crm_info("SUCCESS - %s", origin);
  90         mainloop_iter++;
  91         mainloop_set_trigger(trig);
  92         result.execution_status = PCMK_EXEC_DONE;
  93         result.exit_status = CRM_EX_OK;
  94     } else {
  95         crm_err("FAILURE - %s (%d: %s)", origin, result.exit_status,
  96                 pcmk_exec_status_str(result.execution_status));
  97         crm_exit(CRM_EX_ERROR);
  98     }
  99 }
 100 
 101 
 102 static void
 103 dispatch_helper(int timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 104 {
 105     int rc;
 106 
 107     crm_debug("Looking for notification");
 108     pollfd.events = POLLIN;
 109     while (true) {
 110         rc = poll(&pollfd, 1, timeout); /* wait 10 minutes, -1 forever */
 111         if (rc > 0) {
 112             if (!stonith_dispatch(st)) {
 113                 break;
 114             }
 115         } else {
 116             break;
 117         }
 118     }
 119 }
 120 
 121 static void
 122 st_callback(stonith_t * st, stonith_event_t * e)
     /* [previous][next][first][last][top][bottom][index][help] */
 123 {
 124     if (st->state == stonith_disconnected) {
 125         crm_exit(CRM_EX_DISCONNECT);
 126     }
 127 
 128     crm_notice("Operation '%s' targeting %s by %s for %s: %s (exit=%d, ref=%s)",
 129                ((e->operation == NULL)? "unknown" : e->operation),
 130                ((e->target == NULL)? "no node" : e->target),
 131                ((e->executioner == NULL)? "any node" : e->executioner),
 132                ((e->origin == NULL)? "unknown client" : e->origin),
 133                pcmk_exec_status_str(stonith__event_execution_status(e)),
 134                stonith__event_exit_status(e),
 135                ((e->id == NULL)? "none" : e->id));
 136 
 137     if (expected_notifications) {
 138         expected_notifications--;
 139     }
 140 }
 141 
 142 static void
 143 st_global_callback(stonith_t * stonith, stonith_callback_data_t * data)
     /* [previous][next][first][last][top][bottom][index][help] */
 144 {
 145     crm_notice("Call %d exited %d: %s (%s)",
 146                data->call_id, stonith__exit_status(data),
 147                stonith__execution_status(data),
 148                crm_str(stonith__exit_reason(data)));
 149 }
 150 
 151 static void
 152 passive_test(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 153 {
 154     int rc = 0;
 155 
 156     rc = st->cmds->connect(st, crm_system_name, &pollfd.fd);
 157     if (rc != pcmk_ok) {
 158         stonith_api_delete(st);
 159         crm_exit(CRM_EX_DISCONNECT);
 160     }
 161     st->cmds->register_notification(st, T_STONITH_NOTIFY_DISCONNECT, st_callback);
 162     st->cmds->register_notification(st, T_STONITH_NOTIFY_FENCE, st_callback);
 163     st->cmds->register_notification(st, STONITH_OP_DEVICE_ADD, st_callback);
 164     st->cmds->register_notification(st, STONITH_OP_DEVICE_DEL, st_callback);
 165     st->cmds->register_callback(st, 0, 120, st_opt_timeout_updates, NULL, "st_global_callback",
 166                                 st_global_callback);
 167 
 168     dispatch_helper(600 * 1000);
 169 }
 170 
 171 #define single_test(cmd, str, num_notifications, expected_rc) \
 172 { \
 173     int rc = 0; \
 174     rc = cmd; \
 175     expected_notifications = 0;  \
 176     if (num_notifications) { \
 177         expected_notifications = num_notifications; \
 178         dispatch_helper(500);  \
 179     } \
 180     if (rc != expected_rc) { \
 181         crm_err("FAILURE - expected rc %d != %d(%s) for cmd - %s", expected_rc, rc, pcmk_strerror(rc), str); \
 182         crm_exit(CRM_EX_ERROR); \
 183     } else if (expected_notifications) { \
 184         crm_err("FAILURE - expected %d notifications, got only %d for cmd - %s", \
 185             num_notifications, num_notifications - expected_notifications, str); \
 186         crm_exit(CRM_EX_ERROR); \
 187     } else { \
 188         if (verbose) {                   \
 189             crm_info("SUCCESS - %s: %d", str, rc);    \
 190         } else {   \
 191             crm_debug("SUCCESS - %s: %d", str, rc);    \
 192         }                          \
 193     } \
 194 }\
 195 
 196 static void
 197 run_fence_failure_test(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 198 {
 199     stonith_key_value_t *params = NULL;
 200 
 201     params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP,
 202                                    "false_1_node1=1,2 false_1_node2=3,4");
 203     params = stonith_key_value_add(params, "mode", "fail");
 204 
 205     single_test(st->
 206                 cmds->register_device(st, st_opts, "test-id1", "stonith-ng", "fence_dummy", params),
 207                 "Register device1 for failure test", 1, 0);
 208 
 209     single_test(st->cmds->fence(st, st_opts, "false_1_node2", "off", 3, 0),
 210                 "Fence failure results off", 1, -ENODATA);
 211 
 212     single_test(st->cmds->fence(st, st_opts, "false_1_node2", "reboot", 3, 0),
 213                 "Fence failure results reboot", 1, -ENODATA);
 214 
 215     single_test(st->cmds->remove_device(st, st_opts, "test-id1"),
 216                 "Remove device1 for failure test", 1, 0);
 217 
 218     stonith_key_value_freeall(params, 1, 1);
 219 }
 220 
 221 static void
 222 run_fence_failure_rollover_test(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 223 {
 224     stonith_key_value_t *params = NULL;
 225 
 226     params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP,
 227                                    "false_1_node1=1,2 false_1_node2=3,4");
 228     params = stonith_key_value_add(params, "mode", "fail");
 229 
 230     single_test(st->
 231                 cmds->register_device(st, st_opts, "test-id1", "stonith-ng", "fence_dummy", params),
 232                 "Register device1 for rollover test", 1, 0);
 233     stonith_key_value_freeall(params, 1, 1);
 234     params = NULL;
 235     params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP,
 236                                    "false_1_node1=1,2 false_1_node2=3,4");
 237     params = stonith_key_value_add(params, "mode", "pass");
 238 
 239     single_test(st->
 240                 cmds->register_device(st, st_opts, "test-id2", "stonith-ng", "fence_dummy", params),
 241                 "Register device2 for rollover test", 1, 0);
 242 
 243     single_test(st->cmds->fence(st, st_opts, "false_1_node2", "off", 3, 0),
 244                 "Fence rollover results off", 1, 0);
 245 
 246     /* Expect -ENODEV because fence_dummy requires 'on' to be executed on target */
 247     single_test(st->cmds->fence(st, st_opts, "false_1_node2", "on", 3, 0),
 248                 "Fence rollover results on", 1, -ENODEV);
 249 
 250     single_test(st->cmds->remove_device(st, st_opts, "test-id1"),
 251                 "Remove device1 for rollover tests", 1, 0);
 252 
 253     single_test(st->cmds->remove_device(st, st_opts, "test-id2"),
 254                 "Remove device2 for rollover tests", 1, 0);
 255 
 256     stonith_key_value_freeall(params, 1, 1);
 257 }
 258 
 259 static void
 260 run_standard_test(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 261 {
 262     stonith_key_value_t *params = NULL;
 263 
 264     params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP,
 265                                    "false_1_node1=1,2 false_1_node2=3,4");
 266     params = stonith_key_value_add(params, "mode", "pass");
 267     params = stonith_key_value_add(params, "mock_dynamic_hosts", "false_1_node1 false_1_node2");
 268 
 269     single_test(st->
 270                 cmds->register_device(st, st_opts, "test-id", "stonith-ng", "fence_dummy", params),
 271                 "Register", 1, 0);
 272     stonith_key_value_freeall(params, 1, 1);
 273     params = NULL;
 274 
 275     single_test(st->cmds->list(st, st_opts, "test-id", NULL, 1), "list", 1, 0);
 276 
 277     single_test(st->cmds->monitor(st, st_opts, "test-id", 1), "Monitor", 1, 0);
 278 
 279     single_test(st->cmds->status(st, st_opts, "test-id", "false_1_node2", 1),
 280                 "Status false_1_node2", 1, 0);
 281 
 282     single_test(st->cmds->status(st, st_opts, "test-id", "false_1_node1", 1),
 283                 "Status false_1_node1", 1, 0);
 284 
 285     single_test(st->cmds->fence(st, st_opts, "unknown-host", "off", 1, 0),
 286                 "Fence unknown-host (expected failure)", 0, -ENODEV);
 287 
 288     single_test(st->cmds->fence(st, st_opts, "false_1_node1", "off", 1, 0),
 289                 "Fence false_1_node1", 1, 0);
 290 
 291     /* Expect -ENODEV because fence_dummy requires 'on' to be executed on target */
 292     single_test(st->cmds->fence(st, st_opts, "false_1_node1", "on", 1, 0),
 293                 "Unfence false_1_node1", 1, -ENODEV);
 294 
 295     /* Confirm that an invalid level index is rejected */
 296     single_test(st->cmds->register_level(st, st_opts, "node1", 999, params),
 297                 "Attempt to register an invalid level index", 0, -EINVAL);
 298 
 299     single_test(st->cmds->remove_device(st, st_opts, "test-id"), "Remove test-id", 1, 0);
 300 
 301     stonith_key_value_freeall(params, 1, 1);
 302 }
 303 
 304 static void
 305 sanity_tests(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 306 {
 307     int rc = 0;
 308 
 309     rc = st->cmds->connect(st, crm_system_name, &pollfd.fd);
 310     if (rc != pcmk_ok) {
 311         stonith_api_delete(st);
 312         crm_exit(CRM_EX_DISCONNECT);
 313     }
 314     st->cmds->register_notification(st, T_STONITH_NOTIFY_DISCONNECT, st_callback);
 315     st->cmds->register_notification(st, T_STONITH_NOTIFY_FENCE, st_callback);
 316     st->cmds->register_notification(st, STONITH_OP_DEVICE_ADD, st_callback);
 317     st->cmds->register_notification(st, STONITH_OP_DEVICE_DEL, st_callback);
 318     st->cmds->register_callback(st, 0, 120, st_opt_timeout_updates, NULL, "st_global_callback",
 319                                 st_global_callback);
 320 
 321     crm_info("Starting API Sanity Tests");
 322     run_standard_test();
 323     run_fence_failure_test();
 324     run_fence_failure_rollover_test();
 325     crm_info("Sanity Tests Passed");
 326 }
 327 
 328 static void
 329 standard_dev_test(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 330 {
 331     int rc = 0;
 332     char *tmp = NULL;
 333     stonith_key_value_t *params = NULL;
 334 
 335     rc = st->cmds->connect(st, crm_system_name, &pollfd.fd);
 336     if (rc != pcmk_ok) {
 337         stonith_api_delete(st);
 338         crm_exit(CRM_EX_DISCONNECT);
 339     }
 340 
 341     params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP,
 342                                    "some-host=pcmk-7 true_1_node1=3,4");
 343 
 344     rc = st->cmds->register_device(st, st_opts, "test-id", "stonith-ng", "fence_xvm", params);
 345     crm_debug("Register: %d", rc);
 346 
 347     rc = st->cmds->list(st, st_opts, "test-id", &tmp, 10);
 348     crm_debug("List: %d output: %s", rc, tmp ? tmp : "<none>");
 349 
 350     rc = st->cmds->monitor(st, st_opts, "test-id", 10);
 351     crm_debug("Monitor: %d", rc);
 352 
 353     rc = st->cmds->status(st, st_opts, "test-id", "false_1_node2", 10);
 354     crm_debug("Status false_1_node2: %d", rc);
 355 
 356     rc = st->cmds->status(st, st_opts, "test-id", "false_1_node1", 10);
 357     crm_debug("Status false_1_node1: %d", rc);
 358 
 359     rc = st->cmds->fence(st, st_opts, "unknown-host", "off", 60, 0);
 360     crm_debug("Fence unknown-host: %d", rc);
 361 
 362     rc = st->cmds->status(st, st_opts, "test-id", "false_1_node1", 10);
 363     crm_debug("Status false_1_node1: %d", rc);
 364 
 365     rc = st->cmds->fence(st, st_opts, "false_1_node1", "off", 60, 0);
 366     crm_debug("Fence false_1_node1: %d", rc);
 367 
 368     rc = st->cmds->status(st, st_opts, "test-id", "false_1_node1", 10);
 369     crm_debug("Status false_1_node1: %d", rc);
 370 
 371     rc = st->cmds->fence(st, st_opts, "false_1_node1", "on", 10, 0);
 372     crm_debug("Unfence false_1_node1: %d", rc);
 373 
 374     rc = st->cmds->status(st, st_opts, "test-id", "false_1_node1", 10);
 375     crm_debug("Status false_1_node1: %d", rc);
 376 
 377     rc = st->cmds->fence(st, st_opts, "some-host", "off", 10, 0);
 378     crm_debug("Fence alias: %d", rc);
 379 
 380     rc = st->cmds->status(st, st_opts, "test-id", "some-host", 10);
 381     crm_debug("Status alias: %d", rc);
 382 
 383     rc = st->cmds->fence(st, st_opts, "false_1_node1", "on", 10, 0);
 384     crm_debug("Unfence false_1_node1: %d", rc);
 385 
 386     rc = st->cmds->remove_device(st, st_opts, "test-id");
 387     crm_debug("Remove test-id: %d", rc);
 388 
 389     stonith_key_value_freeall(params, 1, 1);
 390 }
 391 
 392 static void
 393  iterate_mainloop_tests(gboolean event_ready);
 394 
 395 static void
 396 mainloop_callback(stonith_t * stonith, stonith_callback_data_t * data)
     /* [previous][next][first][last][top][bottom][index][help] */
 397 {
 398     pcmk__set_result(&result, stonith__exit_status(data),
 399                      stonith__execution_status(data),
 400                      stonith__exit_reason(data));
 401     iterate_mainloop_tests(TRUE);
 402 }
 403 
 404 static int
 405 register_callback_helper(int callid)
     /* [previous][next][first][last][top][bottom][index][help] */
 406 {
 407     return st->cmds->register_callback(st,
 408                                        callid,
 409                                        MAINLOOP_DEFAULT_TIMEOUT,
 410                                        st_opt_timeout_updates, NULL, "callback", mainloop_callback);
 411 }
 412 
 413 static void
 414 test_async_fence_pass(int check_event)
     /* [previous][next][first][last][top][bottom][index][help] */
 415 {
 416     int rc = 0;
 417 
 418     if (check_event) {
 419         mainloop_test_done(__func__, (result.exit_status == CRM_EX_OK));
 420         return;
 421     }
 422 
 423     rc = st->cmds->fence(st, 0, "true_1_node1", "off", MAINLOOP_DEFAULT_TIMEOUT, 0);
 424     if (rc < 0) {
 425         crm_err("fence failed with rc %d", rc);
 426         mainloop_test_done(__func__, false);
 427     }
 428     register_callback_helper(rc);
 429     /* wait for event */
 430 }
 431 
 432 #define CUSTOM_TIMEOUT_ADDITION 10
 433 static void
 434 test_async_fence_custom_timeout(int check_event)
     /* [previous][next][first][last][top][bottom][index][help] */
 435 {
 436     int rc = 0;
 437     static time_t begin = 0;
 438 
 439     if (check_event) {
 440         uint32_t diff = (time(NULL) - begin);
 441 
 442         if (result.execution_status != PCMK_EXEC_TIMEOUT) {
 443             mainloop_test_done(__func__, false);
 444         } else if (diff < CUSTOM_TIMEOUT_ADDITION + MAINLOOP_DEFAULT_TIMEOUT) {
 445             crm_err
 446                 ("Custom timeout test failed, callback expiration should be updated to %d, actual timeout was %d",
 447                  CUSTOM_TIMEOUT_ADDITION + MAINLOOP_DEFAULT_TIMEOUT, diff);
 448             mainloop_test_done(__func__, false);
 449         } else {
 450             mainloop_test_done(__func__, true);
 451         }
 452         return;
 453     }
 454     begin = time(NULL);
 455 
 456     rc = st->cmds->fence(st, 0, "custom_timeout_node1", "off", MAINLOOP_DEFAULT_TIMEOUT, 0);
 457     if (rc < 0) {
 458         crm_err("fence failed with rc %d", rc);
 459         mainloop_test_done(__func__, false);
 460     }
 461     register_callback_helper(rc);
 462     /* wait for event */
 463 }
 464 
 465 static void
 466 test_async_fence_timeout(int check_event)
     /* [previous][next][first][last][top][bottom][index][help] */
 467 {
 468     int rc = 0;
 469 
 470     if (check_event) {
 471         mainloop_test_done(__func__,
 472                            (result.execution_status == PCMK_EXEC_NO_FENCE_DEVICE));
 473         return;
 474     }
 475 
 476     rc = st->cmds->fence(st, 0, "false_1_node2", "off", MAINLOOP_DEFAULT_TIMEOUT, 0);
 477     if (rc < 0) {
 478         crm_err("fence failed with rc %d", rc);
 479         mainloop_test_done(__func__, false);
 480     }
 481     register_callback_helper(rc);
 482     /* wait for event */
 483 }
 484 
 485 static void
 486 test_async_monitor(int check_event)
     /* [previous][next][first][last][top][bottom][index][help] */
 487 {
 488     int rc = 0;
 489 
 490     if (check_event) {
 491         mainloop_test_done(__func__, (result.exit_status == CRM_EX_OK));
 492         return;
 493     }
 494 
 495     rc = st->cmds->monitor(st, 0, "false_1", MAINLOOP_DEFAULT_TIMEOUT);
 496     if (rc < 0) {
 497         crm_err("monitor failed with rc %d", rc);
 498         mainloop_test_done(__func__, false);
 499     }
 500 
 501     register_callback_helper(rc);
 502     /* wait for event */
 503 }
 504 
 505 static void
 506 test_register_async_devices(int check_event)
     /* [previous][next][first][last][top][bottom][index][help] */
 507 {
 508     char buf[16] = { 0, };
 509     stonith_key_value_t *params = NULL;
 510 
 511     params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP,
 512                                    "false_1_node1=1,2");
 513     params = stonith_key_value_add(params, "mode", "fail");
 514     st->cmds->register_device(st, st_opts, "false_1", "stonith-ng", "fence_dummy", params);
 515     stonith_key_value_freeall(params, 1, 1);
 516 
 517     params = NULL;
 518     params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP,
 519                                    "true_1_node1=1,2");
 520     params = stonith_key_value_add(params, "mode", "pass");
 521     st->cmds->register_device(st, st_opts, "true_1", "stonith-ng", "fence_dummy", params);
 522     stonith_key_value_freeall(params, 1, 1);
 523 
 524     params = NULL;
 525     params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP,
 526                                    "custom_timeout_node1=1,2");
 527     params = stonith_key_value_add(params, "mode", "fail");
 528     params = stonith_key_value_add(params, "delay", "1000");
 529     snprintf(buf, sizeof(buf) - 1, "%d", MAINLOOP_DEFAULT_TIMEOUT + CUSTOM_TIMEOUT_ADDITION);
 530     params = stonith_key_value_add(params, "pcmk_off_timeout", buf);
 531     st->cmds->register_device(st, st_opts, "false_custom_timeout", "stonith-ng", "fence_dummy",
 532                               params);
 533     stonith_key_value_freeall(params, 1, 1);
 534 
 535     mainloop_test_done(__func__, true);
 536 }
 537 
 538 static void
 539 try_mainloop_connect(int check_event)
     /* [previous][next][first][last][top][bottom][index][help] */
 540 {
 541     int rc = stonith_api_connect_retry(st, crm_system_name, 10);
 542 
 543     if (rc == pcmk_ok) {
 544         mainloop_test_done(__func__, true);
 545         return;
 546     }
 547     crm_err("API CONNECTION FAILURE");
 548     mainloop_test_done(__func__, false);
 549 }
 550 
 551 static void
 552 iterate_mainloop_tests(gboolean event_ready)
     /* [previous][next][first][last][top][bottom][index][help] */
 553 {
 554     static mainloop_test_iteration_cb callbacks[] = {
 555         try_mainloop_connect,
 556         test_register_async_devices,
 557         test_async_monitor,
 558         test_async_fence_pass,
 559         test_async_fence_timeout,
 560         test_async_fence_custom_timeout,
 561     };
 562 
 563     if (mainloop_iter == (sizeof(callbacks) / sizeof(mainloop_test_iteration_cb))) {
 564         /* all tests ran, everything passed */
 565         crm_info("ALL MAINLOOP TESTS PASSED!");
 566         crm_exit(CRM_EX_OK);
 567     }
 568 
 569     callbacks[mainloop_iter] (event_ready);
 570 }
 571 
 572 static gboolean
 573 trigger_iterate_mainloop_tests(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 574 {
 575     iterate_mainloop_tests(FALSE);
 576     return TRUE;
 577 }
 578 
 579 static void
 580 test_shutdown(int nsig)
     /* [previous][next][first][last][top][bottom][index][help] */
 581 {
 582     int rc = 0;
 583 
 584     if (st) {
 585         rc = st->cmds->disconnect(st);
 586         crm_info("Disconnect: %d", rc);
 587 
 588         crm_debug("Destroy");
 589         stonith_api_delete(st);
 590     }
 591 
 592     if (rc) {
 593         crm_exit(CRM_EX_ERROR);
 594     }
 595 }
 596 
 597 static void
 598 mainloop_tests(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 599 {
 600     trig = mainloop_add_trigger(G_PRIORITY_HIGH, trigger_iterate_mainloop_tests, NULL);
 601     mainloop_set_trigger(trig);
 602     mainloop_add_signal(SIGTERM, test_shutdown);
 603 
 604     crm_info("Starting");
 605     mainloop = g_main_loop_new(NULL, FALSE);
 606     g_main_loop_run(mainloop);
 607 }
 608 
 609 int
 610 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 611 {
 612     int argerr = 0;
 613     int flag;
 614     int option_index = 0;
 615 
 616     enum test_modes mode = test_standard;
 617 
 618     pcmk__cli_init_logging("cts-fence-helper", 0);
 619     pcmk__set_cli_options(NULL, "<mode> [options]", long_options,
 620                           "inject commands into the Pacemaker fencer, "
 621                           "and watch for events");
 622 
 623     while (1) {
 624         flag = pcmk__next_cli_option(argc, argv, &option_index, NULL);
 625         if (flag == -1) {
 626             break;
 627         }
 628 
 629         switch (flag) {
 630             case 'V':
 631                 verbose = 1;
 632                 break;
 633             case '$':
 634             case '?':
 635                 pcmk__cli_help(flag, CRM_EX_OK);
 636                 break;
 637             case 'p':
 638                 mode = test_passive;
 639                 break;
 640             case 't':
 641                 mode = test_api_sanity;
 642                 break;
 643             case 'm':
 644                 mode = test_api_mainloop;
 645                 break;
 646             default:
 647                 ++argerr;
 648                 break;
 649         }
 650     }
 651 
 652     crm_log_init(NULL, LOG_INFO, TRUE, (verbose? TRUE : FALSE), argc, argv,
 653                  FALSE);
 654 
 655     if (optind > argc) {
 656         ++argerr;
 657     }
 658 
 659     if (argerr) {
 660         pcmk__cli_help('?', CRM_EX_USAGE);
 661     }
 662 
 663     st = stonith_api_new();
 664     if (st == NULL) {
 665         crm_err("Could not connect to fencer: API memory allocation failed");
 666         crm_exit(CRM_EX_DISCONNECT);
 667     }
 668 
 669     switch (mode) {
 670         case test_standard:
 671             standard_dev_test();
 672             break;
 673         case test_passive:
 674             passive_test();
 675             break;
 676         case test_api_sanity:
 677             sanity_tests();
 678             break;
 679         case test_api_mainloop:
 680             mainloop_tests();
 681             break;
 682     }
 683 
 684     test_shutdown(0);
 685     return CRM_EX_OK;
 686 }

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