pacemaker 2.1.4-dc6eb4362e
Scalable High-Availability cluster resource manager
pcmk_status.c
Go to the documentation of this file.
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>
20#include <crm/stonith-ng.h>
21#include <pacemaker.h>
22#include <pacemaker-internal.h>
23
24static int
25cib_connect(pcmk__output_t *out, cib_t *cib, xmlNode **current_cib)
26{
27 int rc = pcmk_rc_ok;
28
29 CRM_CHECK(cib != NULL, return EINVAL);
30
31 if (cib->state == cib_connected_query ||
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,
49 rc = pcmk_legacy2rc(rc);
50
51 return rc;
52}
53
54static stonith_t *
55fencing_connect(void)
56{
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 {
69 return NULL;
70 }
71}
72
73static void
74pacemakerd_event_cb(pcmk_ipc_api_t *pacemakerd_api,
75 enum pcmk_ipc_event event_type, crm_exit_t status,
76 void *event_data, void *user_data)
77{
78 pcmk_pacemakerd_api_reply_t *reply = event_data;
79 enum pcmk_pacemakerd_state *state =
80 (enum pcmk_pacemakerd_state *) user_data;
81
82 /* we are just interested in the latest reply */
84
85 if (event_type != pcmk_ipc_event_reply || status != CRM_EX_OK) {
86 return;
87 }
88
90 reply->data.ping.last_good != (time_t) 0 &&
91 reply->data.ping.status == pcmk_rc_ok) {
92 *state = reply->data.ping.state;
93 }
94}
95
96static int
97pacemakerd_status(pcmk__output_t *out)
98{
99 int rc = pcmk_rc_ok;
100 pcmk_ipc_api_t *pacemakerd_api = NULL;
102
103 rc = pcmk_new_ipc_api(&pacemakerd_api, pcmk_ipc_pacemakerd);
104 if (pacemakerd_api == NULL) {
105 out->err(out, "Could not connect to pacemakerd: %s",
106 pcmk_rc_str(rc));
107 return rc;
108 }
109
110 pcmk_register_ipc_callback(pacemakerd_api, pacemakerd_event_cb, (void *) &state);
111
112 rc = pcmk_connect_ipc(pacemakerd_api, pcmk_ipc_dispatch_sync);
113 if (rc == EREMOTEIO) {
114 return pcmk_rc_ok;
115 } else if (rc != pcmk_rc_ok) {
116 out->err(out, "Could not connect to pacemakerd: %s",
117 pcmk_rc_str(rc));
118 pcmk_free_ipc_api(pacemakerd_api);
119 return rc;
120 }
121
122 rc = pcmk_pacemakerd_api_ping(pacemakerd_api, crm_system_name);
123
124 if (rc != pcmk_rc_ok) {
125 /* Got some error from pcmk_pacemakerd_api_ping, so return it. */
126 } else if (state == pcmk_pacemakerd_state_running) {
127 rc = pcmk_rc_ok;
128 } else if (state == pcmk_pacemakerd_state_shutting_down) {
129 rc = ENOTCONN;
130 } else {
131 rc = EAGAIN;
132 }
133
134 pcmk_free_ipc_api(pacemakerd_api);
135 return rc;
136}
137
138int
140 xmlNode *current_cib, enum pcmk__fence_history fence_history,
141 uint32_t show, uint32_t show_opts, char *only_node,
142 char *only_rsc, char *neg_location_prefix, bool simple_output)
143{
144 xmlNode *cib_copy = copy_xml(current_cib);
145 stonith_history_t *stonith_history = NULL;
146 int history_rc = 0;
148 GList *unames = NULL;
149 GList *resources = NULL;
150
151 int rc = pcmk_rc_ok;
152
153 if (cli_config_update(&cib_copy, NULL, FALSE) == FALSE) {
156 out->err(out, "Upgrade failed: %s", pcmk_rc_str(rc));
157 return rc;
158 }
159
160 /* get the stonith-history if there is evidence we need it */
161 if (fence_history != pcmk__fence_history_none) {
162 history_rc = pcmk__get_fencing_history(st, &stonith_history, fence_history);
163 }
164
166 CRM_ASSERT(data_set != NULL);
168
169 data_set->input = cib_copy;
170 data_set->priv = out;
172
173 /* Unpack constraints if any section will need them
174 * (tickets may be referenced in constraints but not granted yet,
175 * and bans need negative location constraints) */
178 }
179
180 unames = pe__build_node_name_list(data_set, only_node);
181 resources = pe__build_rsc_list(data_set, only_rsc);
182
183 /* Always print DC if NULL. */
184 if (data_set->dc_node == NULL) {
185 show |= pcmk_section_dc;
186 }
187
188 if (simple_output) {
190 } else {
191 out->message(out, "cluster-status", data_set, pcmk_rc2exitc(history_rc),
192 stonith_history, fence_history, show, show_opts,
193 neg_location_prefix, unames, resources);
194 }
195
196 g_list_free_full(unames, free);
197 g_list_free_full(resources, free);
198
199 stonith_history_free(stonith_history);
200 stonith_history = NULL;
202 return rc;
203}
204
205int
206pcmk_status(xmlNodePtr *xml)
207{
208 cib_t *cib = NULL;
209 pcmk__output_t *out = NULL;
210 int rc = pcmk_rc_ok;
211
213
214 cib = cib_new();
215
216 if (cib == NULL) {
217 return pcmk_rc_cib_corrupt;
218 }
219
220 rc = pcmk__out_prologue(&out, xml);
221 if (rc != pcmk_rc_ok) {
222 cib_delete(cib);
223 return rc;
224 }
225
229
231 show_opts, NULL, NULL, NULL, false);
232 pcmk__out_epilogue(out, xml, rc);
233
234 cib_delete(cib);
235 return rc;
236}
237
238int
240 uint32_t show, uint32_t show_opts, char *only_node, char *only_rsc,
241 char *neg_location_prefix, bool simple_output)
242{
243 xmlNode *current_cib = NULL;
244 int rc = pcmk_rc_ok;
245 stonith_t *st = NULL;
246
247 if (cib == NULL) {
248 return ENOTCONN;
249 }
250
251 if (cib->variant == cib_native) {
252 if (cib->state == cib_connected_query || cib->state == cib_connected_command) {
253 rc = pcmk_rc_ok;
254 } else {
255 rc = pacemakerd_status(out);
256 }
257 }
258
259 if (rc != pcmk_rc_ok) {
260 return rc;
261 }
262
263 if (fence_history != pcmk__fence_history_none && cib->variant == cib_native) {
264 st = fencing_connect();
265
266 if (st == NULL) {
267 return ENOTCONN;
268 }
269 }
270
271 rc = cib_connect(out, cib, &current_cib);
272 if (rc != pcmk_rc_ok) {
273 goto done;
274 }
275
276 rc = pcmk__output_cluster_status(out, st, cib, current_cib, fence_history, show, show_opts,
277 only_node, only_rsc, neg_location_prefix, simple_output);
278
279done:
280 if (st != NULL) {
281 if (st->state != stonith_disconnected) {
282 st->cmds->remove_notification(st, NULL);
283 st->cmds->disconnect(st);
284 }
285
287 }
288
289 return rc;
290}
291
292/* This is an internal-only function that is planned to be deprecated and removed.
293 * It should only ever be called from crm_mon.
294 */
295int
297{
298 int nodes_online = 0;
299 int nodes_standby = 0;
300 int nodes_maintenance = 0;
301 char *offline_nodes = NULL;
302 size_t offline_nodes_len = 0;
303 bool no_dc = false;
304 bool offline = false;
305 bool has_warnings = false;
306
307 if (data_set->dc_node == NULL) {
308 has_warnings = true;
309 no_dc = true;
310 }
311
312 for (GList *iter = data_set->nodes; iter != NULL; iter = iter->next) {
313 pe_node_t *node = (pe_node_t *) iter->data;
314
315 if (node->details->standby && node->details->online) {
316 nodes_standby++;
317 } else if (node->details->maintenance && node->details->online) {
318 nodes_maintenance++;
319 } else if (node->details->online) {
320 nodes_online++;
321 } else {
322 char *s = crm_strdup_printf("offline node: %s", node->details->uname);
323 /* coverity[leaked_storage] False positive */
324 pcmk__add_word(&offline_nodes, &offline_nodes_len, s);
325 free(s);
326 has_warnings = true;
327 offline = true;
328 }
329 }
330
331 if (has_warnings) {
332 out->info(out, "CLUSTER WARN: %s%s%s",
333 no_dc ? "No DC" : "",
334 no_dc && offline ? ", " : "",
335 (offline? offline_nodes : ""));
336 free(offline_nodes);
337 } else {
338 char *nodes_standby_s = NULL;
339 char *nodes_maint_s = NULL;
340
341 if (nodes_standby > 0) {
342 nodes_standby_s = crm_strdup_printf(", %d standby node%s", nodes_standby,
343 pcmk__plural_s(nodes_standby));
344 }
345
346 if (nodes_maintenance > 0) {
347 nodes_maint_s = crm_strdup_printf(", %d maintenance node%s",
348 nodes_maintenance,
349 pcmk__plural_s(nodes_maintenance));
350 }
351
352 out->info(out, "CLUSTER OK: %d node%s online%s%s, "
353 "%d resource instance%s configured",
354 nodes_online, pcmk__plural_s(nodes_online),
355 nodes_standby_s != NULL ? nodes_standby_s : "",
356 nodes_maint_s != NULL ? nodes_maint_s : "",
358
359 free(nodes_standby_s);
360 free(nodes_maint_s);
361 }
362
363 if (has_warnings) {
364 return pcmk_rc_error;
365 } else {
366 return pcmk_rc_ok;
367 }
368 /* coverity[leaked_storage] False positive */
369}
int cib__clean_up_connection(cib_t **cib)
Definition: cib_utils.c:752
void cib_delete(cib_t *cib)
Free all memory used by CIB connection.
Definition: cib_client.c:451
cib_t * cib_new(void)
Definition: cib_client.c:292
@ cib_query
Definition: cib_types.h:44
@ cib_scope_local
Definition: cib_types.h:59
@ cib_sync_call
Definition: cib_types.h:61
@ cib_native
Definition: cib_types.h:30
@ cib_connected_command
Definition: cib_types.h:37
@ cib_connected_query
Definition: cib_types.h:38
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:122
char * crm_system_name
Definition: utils.c:54
void stonith__register_messages(pcmk__output_t *out)
Definition: st_output.c:481
int pcmk_connect_ipc(pcmk_ipc_api_t *api, enum pcmk_ipc_dispatch dispatch_type)
Connect to a Pacemaker daemon via IPC.
Definition: ipc_client.c:484
pcmk_ipc_event
Possible event types that an IPC event callback can be called for.
Definition: ipc.h:80
@ pcmk_ipc_event_reply
Daemon's reply to client IPC request.
Definition: ipc.h:83
@ pcmk_ipc_pacemakerd
Launcher.
Definition: ipc.h:75
void pcmk_free_ipc_api(pcmk_ipc_api_t *api)
Free the contents of an IPC API object.
Definition: ipc_client.c:201
@ pcmk_ipc_dispatch_sync
Sending a command will wait for any reply.
Definition: ipc.h:91
int pcmk_new_ipc_api(pcmk_ipc_api_t **api, enum pcmk_ipc_server server)
Create a new object for using Pacemaker daemon IPC.
Definition: ipc_client.c:47
void pcmk_register_ipc_callback(pcmk_ipc_api_t *api, pcmk_ipc_callback_t cb, void *user_data)
Register a callback for IPC API events.
Definition: ipc_client.c:593
@ pcmk_pacemakerd_reply_ping
pcmk_pacemakerd_state
@ pcmk_pacemakerd_state_invalid
@ pcmk_pacemakerd_state_running
@ pcmk_pacemakerd_state_shutting_down
int pcmk_pacemakerd_api_ping(pcmk_ipc_api_t *api, const char *ipc_name)
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:226
#define crm_trace(fmt, args...)
Definition: logging.h:364
pe_working_set_t * data_set
Control output from tools.
@ pcmk_show_timing
Definition: output.h:62
@ pcmk_show_pending
Definition: output.h:65
@ pcmk_show_inactive_rscs
Definition: output.h:63
#define pcmk_section_all
Definition: output.h:49
@ pcmk_section_bans
Definition: output.h:41
@ pcmk_section_tickets
Definition: output.h:40
@ pcmk_section_dc
Definition: output.h:28
High Level API.
stonith_t * st
Definition: pcmk_fence.c:27
int pcmk__output_cluster_status(pcmk__output_t *out, stonith_t *st, cib_t *cib, xmlNode *current_cib, enum pcmk__fence_history fence_history, uint32_t show, uint32_t show_opts, char *only_node, char *only_rsc, char *neg_location_prefix, bool simple_output)
Definition: pcmk_status.c:139
int pcmk__output_simple_status(pcmk__output_t *out, pe_working_set_t *data_set)
Definition: pcmk_status.c:296
int pcmk_status(xmlNodePtr *xml)
Output the current status of the cluster, formatted in the same way that crm_mon --output-as=xml woul...
Definition: pcmk_status.c:206
int pcmk__status(pcmk__output_t *out, cib_t *cib, enum pcmk__fence_history fence_history, uint32_t show, uint32_t show_opts, char *only_node, char *only_rsc, char *neg_location_prefix, bool simple_output)
Definition: pcmk_status.c:239
int pcmk__get_fencing_history(stonith_t *st, stonith_history_t **stonith_history, enum pcmk__fence_history fence_history)
Fetch STONITH history, optionally reducing it.
Definition: pcmk_fence.c:578
pcmk__fence_history
Control how much of the fencing history is output.
Definition: pcmki_fence.h:18
@ pcmk__fence_history_none
Definition: pcmki_fence.h:19
@ pcmk__fence_history_full
Definition: pcmki_fence.h:21
int pcmk__out_prologue(pcmk__output_t **out, xmlNodePtr *xml)
void pcmk__register_lib_messages(pcmk__output_t *out)
Definition: pcmk_output.c:1920
void pcmk__out_epilogue(pcmk__output_t *out, xmlNodePtr *xml, int retval)
void pcmk__unpack_constraints(pe_working_set_t *data_set)
#define pe_flag_no_compat
Definition: pe_types.h:132
GList * pe__build_rsc_list(pe_working_set_t *data_set, const char *s)
Definition: utils.c:2537
GList * pe__build_node_name_list(pe_working_set_t *data_set, const char *s)
Definition: utils.c:2505
void pe__register_messages(pcmk__output_t *out)
Definition: pe_output.c:2923
#define pe__set_working_set_flags(working_set, flags_to_set)
Definition: internal.h:37
#define EREMOTEIO
Definition: portability.h:135
Function and executable result codes.
#define CRM_ASSERT(expr)
Definition: results.h:42
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:370
@ CRM_EX_OK
Success.
Definition: results.h:239
@ pcmk_rc_ok
Definition: results.h:146
@ pcmk_rc_schema_validation
Definition: results.h:126
@ pcmk_rc_error
Definition: results.h:142
@ pcmk_rc_cib_corrupt
Definition: results.h:135
int pcmk_legacy2rc(int legacy_rc)
Definition: results.c:428
enum crm_exit_e crm_exit_t
crm_exit_t pcmk_rc2exitc(int rc)
Map a function return code to the most similar exit code.
Definition: results.c:602
gboolean cluster_status(pe_working_set_t *data_set)
Definition: status.c:71
pe_working_set_t * pe_new_working_set(void)
Create a new working set.
Definition: status.c:34
void pe_reset_working_set(pe_working_set_t *data_set)
Reset a working set to default state without freeing it.
Definition: status.c:338
Fencing aka. STONITH.
void stonith_history_free(stonith_history_t *history)
Definition: st_client.c:737
@ stonith_disconnected
Definition: stonith-ng.h:44
void stonith_api_delete(stonith_t *st)
Definition: st_client.c:1676
stonith_t * stonith_api_new(void)
Definition: st_client.c:1762
#define pcmk__plural_s(i)
int(* signon)(cib_t *cib, const char *name, enum cib_conn_type type)
Definition: cib_types.h:73
int(* query)(cib_t *cib, const char *section, xmlNode **output_data, int call_options)
Definition: cib_types.h:92
enum cib_state state
Definition: cib_types.h:135
cib_api_operations_t * cmds
Definition: cib_types.h:147
enum cib_variant variant
Definition: cib_types.h:137
This structure contains everything that makes up a single output formatter.
int(* message)(pcmk__output_t *out, const char *message_id,...)
int(*) void(* err)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
int(* info)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
enum pcmk_pacemakerd_api_reply reply_type
enum pcmk_pacemakerd_state state
union pcmk_pacemakerd_api_reply_t::@4 data
struct pcmk_pacemakerd_api_reply_t::@4::@5 ping
struct pe_node_shared_s * details
Definition: pe_types.h:252
gboolean online
Definition: pe_types.h:220
const char * uname
Definition: pe_types.h:216
gboolean standby
Definition: pe_types.h:221
gboolean maintenance
Definition: pe_types.h:229
xmlNode * input
Definition: pe_types.h:144
pe_node_t * dc_node
Definition: pe_types.h:149
GList * nodes
Definition: pe_types.h:164
int(* connect)(stonith_t *st, const char *name, int *stonith_fd)
Connect to the local stonith daemon.
Definition: stonith-ng.h:162
int(* disconnect)(stonith_t *st)
Disconnect from the local stonith daemon.
Definition: stonith-ng.h:169
int(* remove_notification)(stonith_t *st, const char *event)
Remove a previously registered notification for event, or all notifications if NULL.
Definition: stonith-ng.h:311
enum stonith_state state
Definition: stonith-ng.h:431
stonith_api_operations_t * cmds
Definition: stonith-ng.h:437
gboolean cli_config_update(xmlNode **xml, int *best_version, gboolean to_logs)
Definition: schemas.c:1188
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:830