root/lib/pacemaker/pcmk_status.c

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

DEFINITIONS

This source file includes following definitions.
  1. fencing_connect
  2. pcmk__output_cluster_status
  3. pcmk_status
  4. pcmk__status
  5. pcmk__output_simple_status

   1 /*
   2  * Copyright 2004-2024 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 General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <stdbool.h>
  13 #include <stddef.h>
  14 #include <stdint.h>
  15 
  16 #include <crm/cib/internal.h>
  17 #include <crm/common/output.h>
  18 #include <crm/common/results.h>
  19 #include <crm/fencing/internal.h>
  20 #include <crm/pengine/internal.h>
  21 #include <crm/stonith-ng.h> // stonith__register_messages()
  22 #include <pacemaker.h>
  23 #include <pacemaker-internal.h>
  24 
  25 static stonith_t *
  26 fencing_connect(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  27 {
  28     stonith_t *st = stonith_api_new();
  29     int rc = pcmk_rc_ok;
  30 
  31     if (st == NULL) {
  32         return NULL;
  33     }
  34 
  35     rc = st->cmds->connect(st, crm_system_name, NULL);
  36     if (rc == pcmk_rc_ok) {
  37         return st;
  38     } else {
  39         stonith_api_delete(st);
  40         return NULL;
  41     }
  42 }
  43 
  44 /*!
  45  * \internal
  46  * \brief Output the cluster status given a fencer and CIB connection
  47  *
  48  * \param[in,out] out                  Output object
  49  * \param[in,out] stonith              Fencer connection
  50  * \param[in,out] cib                  CIB connection
  51  * \param[in]     current_cib          Current CIB XML
  52  * \param[in]     pcmkd_state          \p pacemakerd state
  53  * \param[in]     fence_history        How much of the fencing history to output
  54  * \param[in]     show                 Group of \p pcmk_section_e flags
  55  * \param[in]     show_opts            Group of \p pcmk_show_opt_e flags
  56  * \param[in]     only_node            If a node name or tag, include only the
  57  *                                     matching node(s) (if any) in the output.
  58  *                                     If \p "*" or \p NULL, include all nodes
  59  *                                     in the output.
  60  * \param[in]     only_rsc             If a resource ID or tag, include only the
  61  *                                     matching resource(s) (if any) in the
  62  *                                     output. If \p "*" or \p NULL, include all
  63  *                                     resources in the output.
  64  * \param[in]     neg_location_prefix  Prefix denoting a ban in a constraint ID
  65  * \param[in]     simple_output        Whether to use a simple output format.
  66  *                                     Note: This is for use by \p crm_mon only
  67  *                                     and is planned to be deprecated.
  68  *
  69  * \return Standard Pacemaker return code
  70  */
  71 int
  72 pcmk__output_cluster_status(pcmk__output_t *out, stonith_t *stonith, cib_t *cib,
     /* [previous][next][first][last][top][bottom][index][help] */
  73                             xmlNode *current_cib,
  74                             enum pcmk_pacemakerd_state pcmkd_state,
  75                             enum pcmk__fence_history fence_history,
  76                             uint32_t show, uint32_t show_opts,
  77                             const char *only_node, const char *only_rsc,
  78                             const char *neg_location_prefix, bool simple_output)
  79 {
  80     xmlNode *cib_copy = pcmk__xml_copy(NULL, current_cib);
  81     stonith_history_t *stonith_history = NULL;
  82     int history_rc = 0;
  83     pcmk_scheduler_t *scheduler = NULL;
  84     GList *unames = NULL;
  85     GList *resources = NULL;
  86 
  87     int rc = pcmk_rc_ok;
  88 
  89     rc = pcmk__update_configured_schema(&cib_copy, false);
  90     if (rc != pcmk_rc_ok) {
  91         cib__clean_up_connection(&cib);
  92         free_xml(cib_copy);
  93         out->err(out, "Upgrade failed: %s", pcmk_rc_str(rc));
  94         return rc;
  95     }
  96 
  97     /* get the stonith-history if there is evidence we need it */
  98     if (fence_history != pcmk__fence_history_none) {
  99         history_rc = pcmk__get_fencing_history(stonith, &stonith_history,
 100                                                fence_history);
 101     }
 102 
 103     scheduler = pe_new_working_set();
 104     pcmk__mem_assert(scheduler);
 105     pcmk__set_scheduler_flags(scheduler, pcmk_sched_no_compat);
 106 
 107     scheduler->input = cib_copy;
 108     scheduler->priv = out;
 109     cluster_status(scheduler);
 110 
 111     if ((cib->variant == cib_native) && pcmk_is_set(show, pcmk_section_times)) {
 112         if (pcmk__our_nodename == NULL) {
 113             // Currently used only in the times section
 114             pcmk__query_node_name(out, 0, &pcmk__our_nodename, 0);
 115         }
 116         scheduler->localhost = pcmk__our_nodename;
 117     }
 118 
 119     /* Unpack constraints if any section will need them
 120      * (tickets may be referenced in constraints but not granted yet,
 121      * and bans need negative location constraints) */
 122     if (pcmk_is_set(show, pcmk_section_bans)
 123         || pcmk_is_set(show, pcmk_section_tickets)) {
 124         pcmk__unpack_constraints(scheduler);
 125     }
 126 
 127     unames = pe__build_node_name_list(scheduler, only_node);
 128     resources = pe__build_rsc_list(scheduler, only_rsc);
 129 
 130     /* Always print DC if NULL. */
 131     if (scheduler->dc_node == NULL) {
 132         show |= pcmk_section_dc;
 133     }
 134 
 135     if (simple_output) {
 136         rc = pcmk__output_simple_status(out, scheduler);
 137     } else {
 138         out->message(out, "cluster-status",
 139                      scheduler, pcmkd_state, pcmk_rc2exitc(history_rc),
 140                      stonith_history, fence_history, show, show_opts,
 141                      neg_location_prefix, unames, resources);
 142     }
 143 
 144     g_list_free_full(unames, free);
 145     g_list_free_full(resources, free);
 146 
 147     stonith_history_free(stonith_history);
 148     stonith_history = NULL;
 149     pe_free_working_set(scheduler);
 150     return rc;
 151 }
 152 
 153 int
 154 pcmk_status(xmlNodePtr *xml)
     /* [previous][next][first][last][top][bottom][index][help] */
 155 {
 156     cib_t *cib = NULL;
 157     pcmk__output_t *out = NULL;
 158     int rc = pcmk_rc_ok;
 159 
 160     uint32_t show_opts = pcmk_show_pending
 161                          |pcmk_show_inactive_rscs
 162                          |pcmk_show_timing;
 163 
 164     cib = cib_new();
 165 
 166     if (cib == NULL) {
 167         return pcmk_rc_cib_corrupt;
 168     }
 169 
 170     rc = pcmk__xml_output_new(&out, xml);
 171     if (rc != pcmk_rc_ok) {
 172         cib_delete(cib);
 173         return rc;
 174     }
 175 
 176     pcmk__register_lib_messages(out);
 177     pe__register_messages(out);
 178     stonith__register_messages(out);
 179 
 180     rc = pcmk__status(out, cib, pcmk__fence_history_full, pcmk_section_all,
 181                       show_opts, NULL, NULL, NULL, false, 0);
 182     pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
 183 
 184     cib_delete(cib);
 185     return rc;
 186 }
 187 
 188 /*!
 189  * \internal
 190  * \brief Query and output the cluster status
 191  *
 192  * The operation is considered a success if we're able to get the \p pacemakerd
 193  * state. If possible, we'll also try to connect to the fencer and CIB and
 194  * output their respective status information.
 195  *
 196  * \param[in,out] out                  Output object
 197  * \param[in,out] cib                  CIB connection
 198  * \param[in]     fence_history        How much of the fencing history to output
 199  * \param[in]     show                 Group of \p pcmk_section_e flags
 200  * \param[in]     show_opts            Group of \p pcmk_show_opt_e flags
 201  * \param[in]     only_node            If a node name or tag, include only the
 202  *                                     matching node(s) (if any) in the output.
 203  *                                     If \p "*" or \p NULL, include all nodes
 204  *                                     in the output.
 205  * \param[in]     only_rsc             If a resource ID or tag, include only the
 206  *                                     matching resource(s) (if any) in the
 207  *                                     output. If \p "*" or \p NULL, include all
 208  *                                     resources in the output.
 209  * \param[in]     neg_location_prefix  Prefix denoting a ban in a constraint ID
 210  * \param[in]     simple_output        Whether to use a simple output format.
 211  *                                     Note: This is for use by \p crm_mon only
 212  *                                     and is planned to be deprecated.
 213  * \param[in]     timeout_ms           How long to wait for a reply from the
 214  *                                     \p pacemakerd API. If 0,
 215  *                                     \p pcmk_ipc_dispatch_sync will be used.
 216  *                                     If positive, \p pcmk_ipc_dispatch_main
 217  *                                     will be used, and a new mainloop will be
 218  *                                     created for this purpose (freed before
 219  *                                     return).
 220  *
 221  * \return Standard Pacemaker return code
 222  */
 223 int
 224 pcmk__status(pcmk__output_t *out, cib_t *cib,
     /* [previous][next][first][last][top][bottom][index][help] */
 225              enum pcmk__fence_history fence_history, uint32_t show,
 226              uint32_t show_opts, const char *only_node, const char *only_rsc,
 227              const char *neg_location_prefix, bool simple_output,
 228              unsigned int timeout_ms)
 229 {
 230     xmlNode *current_cib = NULL;
 231     int rc = pcmk_rc_ok;
 232     stonith_t *stonith = NULL;
 233     enum pcmk_pacemakerd_state pcmkd_state = pcmk_pacemakerd_state_invalid;
 234     time_t last_updated = 0;
 235 
 236     if (cib == NULL) {
 237         return ENOTCONN;
 238     }
 239 
 240     if (cib->variant == cib_native) {
 241         rc = pcmk__pacemakerd_status(out, crm_system_name, timeout_ms, false,
 242                                      &pcmkd_state);
 243         if (rc != pcmk_rc_ok) {
 244             return rc;
 245         }
 246 
 247         last_updated = time(NULL);
 248 
 249         switch (pcmkd_state) {
 250             case pcmk_pacemakerd_state_running:
 251             case pcmk_pacemakerd_state_shutting_down:
 252             case pcmk_pacemakerd_state_remote:
 253                 /* Fencer and CIB may still be available while shutting down or
 254                  * running on a Pacemaker Remote node
 255                  */
 256                 break;
 257             default:
 258                 // Fencer and CIB are definitely unavailable
 259                 out->message(out, "pacemakerd-health",
 260                              NULL, pcmkd_state, NULL, last_updated);
 261                 return rc;
 262         }
 263 
 264         if (fence_history != pcmk__fence_history_none) {
 265             stonith = fencing_connect();
 266         }
 267     }
 268 
 269     rc = cib__signon_query(out, &cib, &current_cib);
 270     if (rc != pcmk_rc_ok) {
 271         if (pcmkd_state != pcmk_pacemakerd_state_invalid) {
 272             // Invalid at this point means we didn't query the pcmkd state
 273             out->message(out, "pacemakerd-health",
 274                          NULL, pcmkd_state, NULL, last_updated);
 275         }
 276         goto done;
 277     }
 278 
 279     rc = pcmk__output_cluster_status(out, stonith, cib, current_cib,
 280                                      pcmkd_state, fence_history, show,
 281                                      show_opts, only_node, only_rsc,
 282                                      neg_location_prefix, simple_output);
 283     if (rc != pcmk_rc_ok) {
 284         out->err(out, "Error outputting status info from the fencer or CIB");
 285     }
 286 
 287 done:
 288     stonith_api_delete(stonith);
 289     free_xml(current_cib);
 290     return pcmk_rc_ok;
 291 }
 292 
 293 /*!
 294  * \internal
 295  * \brief Output cluster status in Nagios Plugin format
 296  *
 297  * \param[in,out] out        Output object
 298  * \param[in]     scheduler  Scheduler data
 299  *
 300  * \return Standard Pacemaker return code
 301  * \note This is for a deprecated crm_mon option and should be called only for
 302  *       that.
 303  */
 304 int
 305 pcmk__output_simple_status(pcmk__output_t *out,
     /* [previous][next][first][last][top][bottom][index][help] */
 306                            const pcmk_scheduler_t *scheduler)
 307 {
 308     int nodes_online = 0;
 309     int nodes_standby = 0;
 310     int nodes_maint = 0;
 311     GString *offline_nodes = NULL;
 312     bool no_dc = false;
 313     bool offline = false;
 314     bool has_warnings = false;
 315 
 316     if (scheduler->dc_node == NULL) {
 317         has_warnings = true;
 318         no_dc = true;
 319     }
 320 
 321     for (GList *iter = scheduler->nodes; iter != NULL; iter = iter->next) {
 322         pcmk_node_t *node = (pcmk_node_t *) iter->data;
 323 
 324         if (node->details->standby && node->details->online) {
 325             nodes_standby++;
 326         } else if (node->details->maintenance && node->details->online) {
 327             nodes_maint++;
 328         } else if (node->details->online) {
 329             nodes_online++;
 330         } else {
 331             pcmk__add_word(&offline_nodes, 1024, "offline node:");
 332             pcmk__add_word(&offline_nodes, 0, pcmk__node_name(node));
 333             has_warnings = true;
 334             offline = true;
 335         }
 336     }
 337 
 338     if (has_warnings) {
 339         out->info(out, "CLUSTER WARN: %s%s%s",
 340                   no_dc ? "No DC" : "",
 341                   no_dc && offline ? ", " : "",
 342                   (offline? (const char *) offline_nodes->str : ""));
 343 
 344         if (offline_nodes != NULL) {
 345             g_string_free(offline_nodes, TRUE);
 346         }
 347 
 348     } else {
 349         char *nodes_standby_s = NULL;
 350         char *nodes_maint_s = NULL;
 351 
 352         if (nodes_standby > 0) {
 353             nodes_standby_s = crm_strdup_printf(", %d standby node%s",
 354                                                 nodes_standby,
 355                                                 pcmk__plural_s(nodes_standby));
 356         }
 357 
 358         if (nodes_maint > 0) {
 359             nodes_maint_s = crm_strdup_printf(", %d maintenance node%s",
 360                                               nodes_maint,
 361                                               pcmk__plural_s(nodes_maint));
 362         }
 363 
 364         out->info(out, "CLUSTER OK: %d node%s online%s%s, "
 365                        "%d resource instance%s configured",
 366                   nodes_online, pcmk__plural_s(nodes_online),
 367                   nodes_standby_s != NULL ? nodes_standby_s : "",
 368                   nodes_maint_s != NULL ? nodes_maint_s : "",
 369                   scheduler->ninstances, pcmk__plural_s(scheduler->ninstances));
 370 
 371         free(nodes_standby_s);
 372         free(nodes_maint_s);
 373     }
 374 
 375     if (has_warnings) {
 376         return pcmk_rc_error;
 377     } else {
 378         return pcmk_rc_ok;
 379     }
 380     /* coverity[leaked_storage] False positive */
 381 }

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