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

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

DEFINITIONS

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

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

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