LCOV - code coverage report
Current view: top level - pacemaker - pcmk_status.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 0 147 0.0 %
Date: 2024-05-07 11:09:47 Functions: 0 5 0.0 %

          Line data    Source code
       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           0 : fencing_connect(void)
      27             : {
      28           0 :     stonith_t *st = stonith_api_new();
      29           0 :     int rc = pcmk_rc_ok;
      30             : 
      31           0 :     if (st == NULL) {
      32           0 :         return NULL;
      33             :     }
      34             : 
      35           0 :     rc = st->cmds->connect(st, crm_system_name, NULL);
      36           0 :     if (rc == pcmk_rc_ok) {
      37           0 :         return st;
      38             :     } else {
      39           0 :         stonith_api_delete(st);
      40           0 :         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           0 : pcmk__output_cluster_status(pcmk__output_t *out, stonith_t *stonith, cib_t *cib,
      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           0 :     xmlNode *cib_copy = pcmk__xml_copy(NULL, current_cib);
      81           0 :     stonith_history_t *stonith_history = NULL;
      82           0 :     int history_rc = 0;
      83           0 :     pcmk_scheduler_t *scheduler = NULL;
      84           0 :     GList *unames = NULL;
      85           0 :     GList *resources = NULL;
      86             : 
      87           0 :     int rc = pcmk_rc_ok;
      88             : 
      89           0 :     if (!pcmk__update_configured_schema(&cib_copy, false)) {
      90           0 :         cib__clean_up_connection(&cib);
      91           0 :         free_xml(cib_copy);
      92           0 :         rc = pcmk_rc_schema_validation;
      93           0 :         out->err(out, "Upgrade failed: %s", pcmk_rc_str(rc));
      94           0 :         return rc;
      95             :     }
      96             : 
      97             :     /* get the stonith-history if there is evidence we need it */
      98           0 :     if (fence_history != pcmk__fence_history_none) {
      99           0 :         history_rc = pcmk__get_fencing_history(stonith, &stonith_history,
     100             :                                                fence_history);
     101             :     }
     102             : 
     103           0 :     scheduler = pe_new_working_set();
     104           0 :     pcmk__mem_assert(scheduler);
     105           0 :     pcmk__set_scheduler_flags(scheduler, pcmk_sched_no_compat);
     106             : 
     107           0 :     scheduler->input = cib_copy;
     108           0 :     scheduler->priv = out;
     109           0 :     cluster_status(scheduler);
     110             : 
     111           0 :     if ((cib->variant == cib_native) && pcmk_is_set(show, pcmk_section_times)) {
     112           0 :         if (pcmk__our_nodename == NULL) {
     113             :             // Currently used only in the times section
     114           0 :             pcmk__query_node_name(out, 0, &pcmk__our_nodename, 0);
     115             :         }
     116           0 :         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           0 :     if (pcmk_is_set(show, pcmk_section_bans)
     123           0 :         || pcmk_is_set(show, pcmk_section_tickets)) {
     124           0 :         pcmk__unpack_constraints(scheduler);
     125             :     }
     126             : 
     127           0 :     unames = pe__build_node_name_list(scheduler, only_node);
     128           0 :     resources = pe__build_rsc_list(scheduler, only_rsc);
     129             : 
     130             :     /* Always print DC if NULL. */
     131           0 :     if (scheduler->dc_node == NULL) {
     132           0 :         show |= pcmk_section_dc;
     133             :     }
     134             : 
     135           0 :     if (simple_output) {
     136           0 :         rc = pcmk__output_simple_status(out, scheduler);
     137             :     } else {
     138           0 :         out->message(out, "cluster-status",
     139           0 :                      scheduler, pcmkd_state, pcmk_rc2exitc(history_rc),
     140             :                      stonith_history, fence_history, show, show_opts,
     141             :                      neg_location_prefix, unames, resources);
     142             :     }
     143             : 
     144           0 :     g_list_free_full(unames, free);
     145           0 :     g_list_free_full(resources, free);
     146             : 
     147           0 :     stonith_history_free(stonith_history);
     148           0 :     stonith_history = NULL;
     149           0 :     pe_free_working_set(scheduler);
     150           0 :     return rc;
     151             : }
     152             : 
     153             : int
     154           0 : pcmk_status(xmlNodePtr *xml)
     155             : {
     156           0 :     cib_t *cib = NULL;
     157           0 :     pcmk__output_t *out = NULL;
     158           0 :     int rc = pcmk_rc_ok;
     159             : 
     160           0 :     uint32_t show_opts = pcmk_show_pending
     161             :                          |pcmk_show_inactive_rscs
     162             :                          |pcmk_show_timing;
     163             : 
     164           0 :     cib = cib_new();
     165             : 
     166           0 :     if (cib == NULL) {
     167           0 :         return pcmk_rc_cib_corrupt;
     168             :     }
     169             : 
     170           0 :     rc = pcmk__xml_output_new(&out, xml);
     171           0 :     if (rc != pcmk_rc_ok) {
     172           0 :         cib_delete(cib);
     173           0 :         return rc;
     174             :     }
     175             : 
     176           0 :     pcmk__register_lib_messages(out);
     177           0 :     pe__register_messages(out);
     178           0 :     stonith__register_messages(out);
     179             : 
     180           0 :     rc = pcmk__status(out, cib, pcmk__fence_history_full, pcmk_section_all,
     181             :                       show_opts, NULL, NULL, NULL, false, 0);
     182           0 :     pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
     183             : 
     184           0 :     cib_delete(cib);
     185           0 :     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           0 : pcmk__status(pcmk__output_t *out, cib_t *cib,
     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           0 :     xmlNode *current_cib = NULL;
     231           0 :     int rc = pcmk_rc_ok;
     232           0 :     stonith_t *stonith = NULL;
     233           0 :     enum pcmk_pacemakerd_state pcmkd_state = pcmk_pacemakerd_state_invalid;
     234           0 :     time_t last_updated = 0;
     235             : 
     236           0 :     if (cib == NULL) {
     237           0 :         return ENOTCONN;
     238             :     }
     239             : 
     240           0 :     if (cib->variant == cib_native) {
     241           0 :         rc = pcmk__pacemakerd_status(out, crm_system_name, timeout_ms, false,
     242             :                                      &pcmkd_state);
     243           0 :         if (rc != pcmk_rc_ok) {
     244           0 :             return rc;
     245             :         }
     246             : 
     247           0 :         last_updated = time(NULL);
     248             : 
     249           0 :         switch (pcmkd_state) {
     250           0 :             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           0 :                 break;
     257           0 :             default:
     258             :                 // Fencer and CIB are definitely unavailable
     259           0 :                 out->message(out, "pacemakerd-health",
     260             :                              NULL, pcmkd_state, NULL, last_updated);
     261           0 :                 return rc;
     262             :         }
     263             : 
     264           0 :         if (fence_history != pcmk__fence_history_none) {
     265           0 :             stonith = fencing_connect();
     266             :         }
     267             :     }
     268             : 
     269           0 :     rc = cib__signon_query(out, &cib, &current_cib);
     270           0 :     if (rc != pcmk_rc_ok) {
     271           0 :         if (pcmkd_state != pcmk_pacemakerd_state_invalid) {
     272             :             // Invalid at this point means we didn't query the pcmkd state
     273           0 :             out->message(out, "pacemakerd-health",
     274             :                          NULL, pcmkd_state, NULL, last_updated);
     275             :         }
     276           0 :         goto done;
     277             :     }
     278             : 
     279           0 :     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           0 :     if (rc != pcmk_rc_ok) {
     284           0 :         out->err(out, "Error outputting status info from the fencer or CIB");
     285             :     }
     286             : 
     287           0 : done:
     288           0 :     stonith_api_delete(stonith);
     289           0 :     free_xml(current_cib);
     290           0 :     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           0 : pcmk__output_simple_status(pcmk__output_t *out,
     306             :                            const pcmk_scheduler_t *scheduler)
     307             : {
     308           0 :     int nodes_online = 0;
     309           0 :     int nodes_standby = 0;
     310           0 :     int nodes_maint = 0;
     311           0 :     GString *offline_nodes = NULL;
     312           0 :     bool no_dc = false;
     313           0 :     bool offline = false;
     314           0 :     bool has_warnings = false;
     315             : 
     316           0 :     if (scheduler->dc_node == NULL) {
     317           0 :         has_warnings = true;
     318           0 :         no_dc = true;
     319             :     }
     320             : 
     321           0 :     for (GList *iter = scheduler->nodes; iter != NULL; iter = iter->next) {
     322           0 :         pcmk_node_t *node = (pcmk_node_t *) iter->data;
     323             : 
     324           0 :         if (node->details->standby && node->details->online) {
     325           0 :             nodes_standby++;
     326           0 :         } else if (node->details->maintenance && node->details->online) {
     327           0 :             nodes_maint++;
     328           0 :         } else if (node->details->online) {
     329           0 :             nodes_online++;
     330             :         } else {
     331           0 :             pcmk__add_word(&offline_nodes, 1024, "offline node:");
     332           0 :             pcmk__add_word(&offline_nodes, 0, pcmk__node_name(node));
     333           0 :             has_warnings = true;
     334           0 :             offline = true;
     335             :         }
     336             :     }
     337             : 
     338           0 :     if (has_warnings) {
     339           0 :         out->info(out, "CLUSTER WARN: %s%s%s",
     340             :                   no_dc ? "No DC" : "",
     341           0 :                   no_dc && offline ? ", " : "",
     342           0 :                   (offline? (const char *) offline_nodes->str : ""));
     343             : 
     344           0 :         if (offline_nodes != NULL) {
     345           0 :             g_string_free(offline_nodes, TRUE);
     346             :         }
     347             : 
     348             :     } else {
     349           0 :         char *nodes_standby_s = NULL;
     350           0 :         char *nodes_maint_s = NULL;
     351             : 
     352           0 :         if (nodes_standby > 0) {
     353           0 :             nodes_standby_s = crm_strdup_printf(", %d standby node%s",
     354             :                                                 nodes_standby,
     355             :                                                 pcmk__plural_s(nodes_standby));
     356             :         }
     357             : 
     358           0 :         if (nodes_maint > 0) {
     359           0 :             nodes_maint_s = crm_strdup_printf(", %d maintenance node%s",
     360             :                                               nodes_maint,
     361             :                                               pcmk__plural_s(nodes_maint));
     362             :         }
     363             : 
     364           0 :         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           0 :                   scheduler->ninstances, pcmk__plural_s(scheduler->ninstances));
     370             : 
     371           0 :         free(nodes_standby_s);
     372           0 :         free(nodes_maint_s);
     373             :     }
     374             : 
     375           0 :     if (has_warnings) {
     376           0 :         return pcmk_rc_error;
     377             :     } else {
     378           0 :         return pcmk_rc_ok;
     379             :     }
     380             :     /* coverity[leaked_storage] False positive */
     381             : }

Generated by: LCOV version 1.14