root/lib/pacemaker/pcmk_cluster_queries.c

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

DEFINITIONS

This source file includes following definitions.
  1. quit_main_loop
  2. admin_message_timeout
  3. start_main_loop
  4. event_done
  5. controld_event_reply
  6. controller_status_event_cb
  7. designated_controller_event_cb
  8. pacemakerd_event_cb
  9. ipc_connect
  10. pcmk__controller_status
  11. pcmk_controller_status
  12. pcmk__designated_controller
  13. pcmk_designated_controller
  14. pcmk__pacemakerd_status
  15. pcmk_pacemakerd_status
  16. remote_node_print_helper
  17. pcmk__list_nodes
  18. pcmk_list_nodes

   1 /*
   2  * Copyright 2020-2021 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>               // gboolean, GMainLoop, etc.
  13 #include <libxml/tree.h>        // xmlNode
  14 
  15 #include <pacemaker.h>
  16 #include <pacemaker-internal.h>
  17 
  18 #include <crm/crm.h>
  19 #include <crm/cib.h>
  20 #include <crm/cib/internal.h>
  21 #include <crm/msg_xml.h>
  22 #include <crm/common/output_internal.h>
  23 #include <crm/common/xml.h>
  24 #include <crm/common/xml_internal.h>
  25 #include <crm/common/iso8601.h>
  26 #include <crm/common/ipc_controld.h>
  27 #include <crm/common/ipc_pacemakerd.h>
  28 #include <crm/common/mainloop.h>
  29 
  30 #define DEFAULT_MESSAGE_TIMEOUT_MS 30000
  31 
  32 
  33 typedef struct {
  34     pcmk__output_t *out;
  35     GMainLoop *mainloop;
  36     int rc;
  37     guint message_timer_id;
  38     guint message_timeout_ms;
  39 } data_t;
  40 
  41 static void
  42 quit_main_loop(data_t *data)
     /* [previous][next][first][last][top][bottom][index][help] */
  43 {
  44     if (data->mainloop != NULL) {
  45         GMainLoop *mloop = data->mainloop;
  46 
  47         data->mainloop = NULL; // Don't re-enter this block
  48         pcmk_quit_main_loop(mloop, 10);
  49         g_main_loop_unref(mloop);
  50     }
  51 }
  52 
  53 static gboolean
  54 admin_message_timeout(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
  55 {
  56     data_t *data = user_data;
  57     pcmk__output_t *out = data->out;
  58 
  59     out->err(out, "error: No reply received from controller before timeout (%dms)",
  60             data->message_timeout_ms);
  61     data->message_timer_id = 0;
  62     data->rc = ETIMEDOUT;
  63     quit_main_loop(data);
  64     return FALSE; // Tells glib to remove source
  65 }
  66 
  67 static void
  68 start_main_loop(data_t *data)
     /* [previous][next][first][last][top][bottom][index][help] */
  69 {
  70     if (data->message_timeout_ms < 1) {
  71         data->message_timeout_ms = DEFAULT_MESSAGE_TIMEOUT_MS;
  72     }
  73 
  74     data->rc = ECONNRESET; // For unexpected disconnects
  75     data->mainloop = g_main_loop_new(NULL, FALSE);
  76     data->message_timer_id = g_timeout_add(data->message_timeout_ms,
  77                                      admin_message_timeout,
  78                                      data);
  79     g_main_loop_run(data->mainloop);
  80 }
  81 
  82 static void
  83 event_done(data_t *data, pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
  84 {
  85     pcmk_disconnect_ipc(api);
  86     quit_main_loop(data);
  87 }
  88 
  89 static pcmk_controld_api_reply_t *
  90 controld_event_reply(data_t *data, pcmk_ipc_api_t *controld_api, enum pcmk_ipc_event event_type, crm_exit_t status, void *event_data)
     /* [previous][next][first][last][top][bottom][index][help] */
  91 {
  92     pcmk__output_t *out = data->out;
  93     pcmk_controld_api_reply_t *reply = event_data;
  94 
  95     switch (event_type) {
  96         case pcmk_ipc_event_disconnect:
  97             if (data->rc == ECONNRESET) { // Unexpected
  98                 out->err(out, "error: Lost connection to controller");
  99             }
 100             event_done(data, controld_api);
 101             return NULL;
 102 
 103         case pcmk_ipc_event_reply:
 104             break;
 105 
 106         default:
 107             return NULL;
 108     }
 109 
 110     if (data->message_timer_id != 0) {
 111         g_source_remove(data->message_timer_id);
 112         data->message_timer_id = 0;
 113     }
 114 
 115     if (status != CRM_EX_OK) {
 116         out->err(out, "error: Bad reply from controller: %s",
 117                 crm_exit_str(status));
 118         data->rc = EBADMSG;
 119         event_done(data, controld_api);
 120         return NULL;
 121     }
 122 
 123     if (reply->reply_type != pcmk_controld_reply_ping) {
 124         out->err(out, "error: Unknown reply type %d from controller",
 125                 reply->reply_type);
 126         data->rc = EBADMSG;
 127         event_done(data, controld_api);
 128         return NULL;
 129     }
 130 
 131     return reply;
 132 }
 133 
 134 static void
 135 controller_status_event_cb(pcmk_ipc_api_t *controld_api,
     /* [previous][next][first][last][top][bottom][index][help] */
 136                     enum pcmk_ipc_event event_type, crm_exit_t status,
 137                     void *event_data, void *user_data)
 138 {
 139     data_t *data = user_data;
 140     pcmk__output_t *out = data->out;
 141     pcmk_controld_api_reply_t *reply = controld_event_reply(data, controld_api,
 142         event_type, status, event_data);
 143 
 144     if (reply != NULL) {
 145         out->message(out, "health",
 146                reply->data.ping.sys_from,
 147                reply->host_from,
 148                reply->data.ping.fsa_state,
 149                reply->data.ping.result);
 150         data->rc = pcmk_rc_ok;
 151     }
 152 
 153     event_done(data, controld_api);
 154 }
 155 
 156 static void
 157 designated_controller_event_cb(pcmk_ipc_api_t *controld_api,
     /* [previous][next][first][last][top][bottom][index][help] */
 158                     enum pcmk_ipc_event event_type, crm_exit_t status,
 159                     void *event_data, void *user_data)
 160 {
 161     data_t *data = user_data;
 162     pcmk__output_t *out = data->out;
 163     pcmk_controld_api_reply_t *reply = controld_event_reply(data, controld_api,
 164         event_type, status, event_data);
 165 
 166     if (reply != NULL) {
 167         out->message(out, "dc", reply->host_from);
 168         data->rc = pcmk_rc_ok;
 169     }
 170 
 171     event_done(data, controld_api);
 172 }
 173 
 174 static void
 175 pacemakerd_event_cb(pcmk_ipc_api_t *pacemakerd_api,
     /* [previous][next][first][last][top][bottom][index][help] */
 176                     enum pcmk_ipc_event event_type, crm_exit_t status,
 177                     void *event_data, void *user_data)
 178 {
 179     data_t *data = user_data;
 180     pcmk__output_t *out = data->out;
 181     pcmk_pacemakerd_api_reply_t *reply = event_data;
 182 
 183     crm_time_t *crm_when;
 184     char *pinged_buf = NULL;
 185 
 186     switch (event_type) {
 187         case pcmk_ipc_event_disconnect:
 188             if (data->rc == ECONNRESET) { // Unexpected
 189                 out->err(out, "error: Lost connection to pacemakerd");
 190             }
 191             event_done(data, pacemakerd_api);
 192             return;
 193 
 194         case pcmk_ipc_event_reply:
 195             break;
 196 
 197         default:
 198             return;
 199     }
 200 
 201     if (data->message_timer_id != 0) {
 202         g_source_remove(data->message_timer_id);
 203         data->message_timer_id = 0;
 204     }
 205 
 206     if (status != CRM_EX_OK) {
 207         out->err(out, "error: Bad reply from pacemakerd: %s",
 208                 crm_exit_str(status));
 209         event_done(data, pacemakerd_api);
 210         return;
 211     }
 212 
 213     if (reply->reply_type != pcmk_pacemakerd_reply_ping) {
 214         out->err(out, "error: Unknown reply type %d from pacemakerd",
 215                 reply->reply_type);
 216         event_done(data, pacemakerd_api);
 217         return;
 218     }
 219 
 220     // Parse desired information from reply
 221     crm_when = crm_time_new(NULL);
 222     crm_time_set_timet(crm_when, &reply->data.ping.last_good);
 223     pinged_buf = crm_time_as_string(crm_when,
 224         crm_time_log_date | crm_time_log_timeofday |
 225             crm_time_log_with_timezone);
 226 
 227     out->message(out, "pacemakerd-health",
 228         reply->data.ping.sys_from,
 229         (reply->data.ping.status == pcmk_rc_ok)?
 230             pcmk_pacemakerd_api_daemon_state_enum2text(
 231                 reply->data.ping.state):"query failed",
 232         (reply->data.ping.status == pcmk_rc_ok)?pinged_buf:"");
 233     data->rc = pcmk_rc_ok;
 234     crm_time_free(crm_when);
 235     free(pinged_buf);
 236 
 237     event_done(data, pacemakerd_api);
 238 }
 239 
 240 static pcmk_ipc_api_t *
 241 ipc_connect(data_t *data, enum pcmk_ipc_server server, pcmk_ipc_callback_t cb)
     /* [previous][next][first][last][top][bottom][index][help] */
 242 {
 243     int rc;
 244     pcmk__output_t *out = data->out;
 245     pcmk_ipc_api_t *api = NULL;
 246 
 247 
 248     rc = pcmk_new_ipc_api(&api, server);
 249     if (api == NULL) {
 250         out->err(out, "error: Could not connect to %s: %s",
 251                 pcmk_ipc_name(api, true),
 252                 pcmk_rc_str(rc));
 253         data->rc = rc;
 254         return NULL;
 255     }
 256     if (cb != NULL) {
 257         pcmk_register_ipc_callback(api, cb, data);
 258     }
 259     rc = pcmk_connect_ipc(api, pcmk_ipc_dispatch_main);
 260     if (rc != pcmk_rc_ok) {
 261         out->err(out, "error: Could not connect to %s: %s",
 262                 pcmk_ipc_name(api, true),
 263                 pcmk_rc_str(rc));
 264         data->rc = rc;
 265         return NULL;
 266     }
 267 
 268     return api;
 269 }
 270 
 271 int
 272 pcmk__controller_status(pcmk__output_t *out, char *dest_node, guint message_timeout_ms)
     /* [previous][next][first][last][top][bottom][index][help] */
 273 {
 274     data_t data = {
 275         .out = out,
 276         .mainloop = NULL,
 277         .rc = pcmk_rc_ok,
 278         .message_timer_id = 0,
 279         .message_timeout_ms = message_timeout_ms
 280     };
 281     pcmk_ipc_api_t *controld_api = ipc_connect(&data, pcmk_ipc_controld, controller_status_event_cb);
 282 
 283     if (controld_api != NULL) {
 284         int rc = pcmk_controld_api_ping(controld_api, dest_node);
 285         if (rc != pcmk_rc_ok) {
 286             out->err(out, "error: Command failed: %s", pcmk_rc_str(rc));
 287             data.rc = rc;
 288         }
 289 
 290         start_main_loop(&data);
 291 
 292         pcmk_free_ipc_api(controld_api);
 293     }
 294 
 295     return data.rc;
 296 }
 297 
 298 int
 299 pcmk_controller_status(xmlNodePtr *xml, char *dest_node, unsigned int message_timeout_ms)
     /* [previous][next][first][last][top][bottom][index][help] */
 300 {
 301     pcmk__output_t *out = NULL;
 302     int rc = pcmk_rc_ok;
 303 
 304     rc = pcmk__out_prologue(&out, xml);
 305     if (rc != pcmk_rc_ok) {
 306         return rc;
 307     }
 308 
 309     pcmk__register_lib_messages(out);
 310 
 311     rc = pcmk__controller_status(out, dest_node, (guint) message_timeout_ms);
 312     pcmk__out_epilogue(out, xml, rc);
 313     return rc;
 314 }
 315 
 316 int
 317 pcmk__designated_controller(pcmk__output_t *out, guint message_timeout_ms)
     /* [previous][next][first][last][top][bottom][index][help] */
 318 {
 319     data_t data = {
 320         .out = out,
 321         .mainloop = NULL,
 322         .rc = pcmk_rc_ok,
 323         .message_timer_id = 0,
 324         .message_timeout_ms = message_timeout_ms
 325     };
 326     pcmk_ipc_api_t *controld_api = ipc_connect(&data, pcmk_ipc_controld, designated_controller_event_cb);
 327 
 328     if (controld_api != NULL) {
 329         int rc = pcmk_controld_api_ping(controld_api, NULL);
 330         if (rc != pcmk_rc_ok) {
 331             out->err(out, "error: Command failed: %s", pcmk_rc_str(rc));
 332             data.rc = rc;
 333         }
 334 
 335         start_main_loop(&data);
 336 
 337         pcmk_free_ipc_api(controld_api);
 338     }
 339 
 340     return data.rc;
 341 }
 342 
 343 int
 344 pcmk_designated_controller(xmlNodePtr *xml, unsigned int message_timeout_ms)
     /* [previous][next][first][last][top][bottom][index][help] */
 345 {
 346     pcmk__output_t *out = NULL;
 347     int rc = pcmk_rc_ok;
 348 
 349     rc = pcmk__out_prologue(&out, xml);
 350     if (rc != pcmk_rc_ok) {
 351         return rc;
 352     }
 353 
 354     pcmk__register_lib_messages(out);
 355 
 356     rc = pcmk__designated_controller(out, (guint) message_timeout_ms);
 357     pcmk__out_epilogue(out, xml, rc);
 358     return rc;
 359 }
 360 
 361 int
 362 pcmk__pacemakerd_status(pcmk__output_t *out, char *ipc_name, guint message_timeout_ms)
     /* [previous][next][first][last][top][bottom][index][help] */
 363 {
 364     data_t data = {
 365         .out = out,
 366         .mainloop = NULL,
 367         .rc = pcmk_rc_ok,
 368         .message_timer_id = 0,
 369         .message_timeout_ms = message_timeout_ms
 370     };
 371     pcmk_ipc_api_t *pacemakerd_api = ipc_connect(&data, pcmk_ipc_pacemakerd, pacemakerd_event_cb);
 372 
 373     if (pacemakerd_api != NULL) {
 374         int rc = pcmk_pacemakerd_api_ping(pacemakerd_api, ipc_name);
 375         if (rc != pcmk_rc_ok) {
 376             out->err(out, "error: Command failed: %s", pcmk_rc_str(rc));
 377             data.rc = rc;
 378         }
 379 
 380         start_main_loop(&data);
 381 
 382         pcmk_free_ipc_api(pacemakerd_api);
 383     }
 384 
 385     return data.rc;
 386 }
 387 
 388 int
 389 pcmk_pacemakerd_status(xmlNodePtr *xml, char *ipc_name, unsigned int message_timeout_ms)
     /* [previous][next][first][last][top][bottom][index][help] */
 390 {
 391     pcmk__output_t *out = NULL;
 392     int rc = pcmk_rc_ok;
 393 
 394     rc = pcmk__out_prologue(&out, xml);
 395     if (rc != pcmk_rc_ok) {
 396         return rc;
 397     }
 398 
 399     pcmk__register_lib_messages(out);
 400 
 401     rc = pcmk__pacemakerd_status(out, ipc_name, (guint) message_timeout_ms);
 402     pcmk__out_epilogue(out, xml, rc);
 403     return rc;
 404 }
 405 
 406 /* user data for looping through remote node xpath searches */
 407 struct node_data {
 408     pcmk__output_t *out;
 409     int found;
 410     const char *field;  /* XML attribute to check for node name */
 411     const char *type;
 412     gboolean BASH_EXPORT;
 413 };
 414 
 415 static void
 416 remote_node_print_helper(xmlNode *result, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 417 {
 418     struct node_data *data = user_data;
 419     pcmk__output_t *out = data->out;
 420     const char *name = crm_element_value(result, XML_ATTR_UNAME);
 421     const char *id = crm_element_value(result, data->field);
 422 
 423     // node name and node id are the same for remote/guest nodes
 424     out->message(out, "crmadmin-node", data->type,
 425                  name ? name : id,
 426                  id,
 427                  data->BASH_EXPORT);
 428     data->found++;
 429 }
 430 
 431 // \return Standard Pacemaker return code
 432 int
 433 pcmk__list_nodes(pcmk__output_t *out, char *node_types, gboolean BASH_EXPORT)
     /* [previous][next][first][last][top][bottom][index][help] */
 434 {
 435     xmlNode *xml_node = NULL;
 436     int rc;
 437 
 438     rc = cib__signon_query(NULL, &xml_node);
 439 
 440     if (rc == pcmk_rc_ok) {
 441         struct node_data data = {
 442             .out = out,
 443             .found = 0,
 444             .BASH_EXPORT = BASH_EXPORT
 445         };
 446 
 447         out->begin_list(out, NULL, NULL, "nodes");
 448 
 449         if (!pcmk__str_empty(node_types) && strstr(node_types, "all")) {
 450             node_types = NULL;
 451         }
 452 
 453         if (pcmk__str_empty(node_types) || strstr(node_types, "cluster")) {
 454             data.field = "id";
 455             data.type = "cluster";
 456             crm_foreach_xpath_result(xml_node, PCMK__XP_MEMBER_NODE_CONFIG,
 457                                      remote_node_print_helper, &data);
 458         }
 459 
 460         if (pcmk__str_empty(node_types) || strstr(node_types, "guest")) {
 461             data.field = "value";
 462             data.type = "guest";
 463             crm_foreach_xpath_result(xml_node, PCMK__XP_GUEST_NODE_CONFIG,
 464                                      remote_node_print_helper, &data);
 465         }
 466 
 467         if (pcmk__str_empty(node_types) || !pcmk__strcmp(node_types, ",|^remote", pcmk__str_regex)) {
 468             data.field = "id";
 469             data.type = "remote";
 470             crm_foreach_xpath_result(xml_node, PCMK__XP_REMOTE_NODE_CONFIG,
 471                                      remote_node_print_helper, &data);
 472         }
 473 
 474         out->end_list(out);
 475 
 476         if (data.found == 0) {
 477             out->info(out, "No nodes configured");
 478         }
 479 
 480         free_xml(xml_node);
 481     }
 482 
 483     return rc;
 484 }
 485 
 486 int
 487 pcmk_list_nodes(xmlNodePtr *xml, char *node_types)
     /* [previous][next][first][last][top][bottom][index][help] */
 488 {
 489     pcmk__output_t *out = NULL;
 490     int rc = pcmk_rc_ok;
 491 
 492     rc = pcmk__out_prologue(&out, xml);
 493     if (rc != pcmk_rc_ok) {
 494         return rc;
 495     }
 496 
 497     pcmk__register_lib_messages(out);
 498 
 499     rc = pcmk__list_nodes(out, node_types, FALSE);
 500     pcmk__out_epilogue(out, xml, rc);
 501     return rc;
 502 }

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