root/lib/pacemaker/pcmk_status.c

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

DEFINITIONS

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

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

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