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

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