pacemaker  2.1.4-dc6eb4362
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>
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)
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,
49  rc = pcmk_legacy2rc(rc);
50 
51  return rc;
52 }
53 
54 static stonith_t *
55 fencing_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 
73 static void
74 pacemakerd_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 
89  if (reply->reply_type == pcmk_pacemakerd_reply_ping &&
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 
96 static int
97 pacemakerd_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 
138 int
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;
147  pe_working_set_t *data_set = NULL;
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 
205 int
206 pcmk_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 
238 int
239 pcmk__status(pcmk__output_t *out, cib_t *cib, enum pcmk__fence_history fence_history,
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 
279 done:
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  */
295 int
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 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:226
Control output from tools.
void stonith__register_messages(pcmk__output_t *out)
Definition: st_output.c:481
cib_t * cib_new(void)
Definition: cib_client.c:292
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
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(* message)(pcmk__output_t *out, const char *message_id,...)
GList * pe__build_rsc_list(pe_working_set_t *data_set, const char *s)
Definition: utils.c:2537
Launcher.
Definition: ipc.h:75
pcmk__fence_history
Control how much of the fencing history is output.
Definition: pcmki_fence.h:18
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
pe_working_set_t * pe_new_working_set(void)
Create a new working set.
Definition: status.c:34
#define pe_flag_no_compat
Definition: pe_types.h:132
crm_exit_t pcmk_rc2exitc(int rc)
Map a function return code to the most similar exit code.
Definition: results.c:602
struct pcmk_pacemakerd_api_reply_t::@4::@5 ping
#define EREMOTEIO
Definition: portability.h:135
High Level API.
char * crm_system_name
Definition: utils.c:54
enum crm_exit_e crm_exit_t
int(* info)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:370
void cib_delete(cib_t *cib)
Free all memory used by CIB connection.
Definition: cib_client.c:451
stonith_t * stonith_api_new(void)
Definition: st_client.c:1762
GList * nodes
Definition: pe_types.h:164
int pcmk__out_prologue(pcmk__output_t **out, xmlNodePtr *xml)
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:830
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
enum pcmk_pacemakerd_api_reply reply_type
union pcmk_pacemakerd_api_reply_t::@4 data
stonith_t * st
Definition: pcmk_fence.c:27
cib_api_operations_t * cmds
Definition: cib_types.h:147
enum stonith_state state
Definition: stonith-ng.h:431
int(* signon)(cib_t *cib, const char *name, enum cib_conn_type type)
Definition: cib_types.h:73
#define pcmk_section_all
Definition: output.h:49
#define crm_trace(fmt, args...)
Definition: logging.h:364
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
struct pe_node_shared_s * details
Definition: pe_types.h:252
int(*) void(* err)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
const char * uname
Definition: pe_types.h:216
void pcmk__register_lib_messages(pcmk__output_t *out)
Definition: pcmk_output.c:1920
pe_working_set_t * data_set
void pcmk__unpack_constraints(pe_working_set_t *data_set)
int(* query)(cib_t *cib, const char *section, xmlNode **output_data, int call_options)
Definition: cib_types.h:92
int(* disconnect)(stonith_t *st)
Disconnect from the local stonith daemon.
Definition: stonith-ng.h:169
int pcmk__output_simple_status(pcmk__output_t *out, pe_working_set_t *data_set)
Definition: pcmk_status.c:296
Success.
Definition: results.h:239
int pcmk_legacy2rc(int legacy_rc)
Definition: results.c:428
gboolean standby
Definition: pe_types.h:221
void pe__register_messages(pcmk__output_t *out)
Definition: pe_output.c:2923
int(* connect)(stonith_t *st, const char *name, int *stonith_fd)
Connect to the local stonith daemon.
Definition: stonith-ng.h:162
xmlNode * input
Definition: pe_types.h:144
void pcmk__out_epilogue(pcmk__output_t *out, xmlNodePtr *xml, int retval)
int cib__clean_up_connection(cib_t **cib)
Definition: cib_utils.c:752
Function and executable result codes.
int pcmk_pacemakerd_api_ping(pcmk_ipc_api_t *api, const char *ipc_name)
pcmk_pacemakerd_state
GList * pe__build_node_name_list(pe_working_set_t *data_set, const char *s)
Definition: utils.c:2505
pe_node_t * dc_node
Definition: pe_types.h:149
pcmk_ipc_event
Possible event types that an IPC event callback can be called for.
Definition: ipc.h:80
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
void stonith_api_delete(stonith_t *st)
Definition: st_client.c:1676
#define CRM_ASSERT(expr)
Definition: results.h:42
Sending a command will wait for any reply.
Definition: ipc.h:91
stonith_api_operations_t * cmds
Definition: stonith-ng.h:437
gboolean cluster_status(pe_working_set_t *data_set)
Definition: status.c:71
void pcmk_free_ipc_api(pcmk_ipc_api_t *api)
Free the contents of an IPC API object.
Definition: ipc_client.c:201
void stonith_history_free(stonith_history_t *history)
Definition: st_client.c:737
Fencing aka. STONITH.
This structure contains everything that makes up a single output formatter.
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__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
enum cib_variant variant
Definition: cib_types.h:137
#define pe__set_working_set_flags(working_set, flags_to_set)
Definition: internal.h:37
#define pcmk__plural_s(i)
gboolean maintenance
Definition: pe_types.h:229
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
Daemon&#39;s reply to client IPC request.
Definition: ipc.h:83
gboolean cli_config_update(xmlNode **xml, int *best_version, gboolean to_logs)
Definition: schemas.c:1188
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
enum cib_state state
Definition: cib_types.h:135
gboolean online
Definition: pe_types.h:220