2020#include <crm/cib.h>
2121#include <crm/msg_xml.h>
2222#include <crm/common/xml.h>
23+ #include <crm/common/iso8601.h>
2324#include <crm/common/ipc_controld.h>
25+ #include <crm/common/ipc_pacemakerd.h>
2426#include <crm/common/mainloop.h>
2527
2628#define DEFAULT_MESSAGE_TIMEOUT_MS 30000
@@ -31,6 +33,8 @@ static GMainLoop *mainloop = NULL;
3133
3234bool do_work (pcmk_ipc_api_t * api );
3335void do_find_node_list (xmlNode * xml_node );
36+ static char * ipc_name = NULL ;
37+
3438gboolean admin_message_timeout (gpointer data );
3539
3640static enum {
@@ -40,6 +44,7 @@ static enum {
4044 cmd_elect_dc ,
4145 cmd_whois_dc ,
4246 cmd_list_nodes ,
47+ cmd_pacemakerd_health ,
4348} command = cmd_none ;
4449
4550static gboolean BE_VERBOSE = FALSE;
@@ -81,6 +86,15 @@ static pcmk__cli_option_t long_options[] = {
8186 "can be useful for debugging\n" ,
8287 pcmk__option_default
8388 },
89+ {
90+ "pacemakerd" , no_argument , NULL , 'P' ,
91+ "Display the status of local pacemakerd." , pcmk__option_default
92+ },
93+ {
94+ "-spacer-" , no_argument , NULL , '-' ,
95+ "\n\tResult is the state of the sub-daemons watched by pacemakerd.\n" ,
96+ pcmk__option_default
97+ },
8498 {
8599 "dc_lookup" , no_argument , NULL , 'D' ,
86100 "Display the uname of the node co-ordinating the cluster." ,
@@ -122,16 +136,20 @@ static pcmk__cli_option_t long_options[] = {
122136 {
123137 "bash-export" , no_argument , NULL , 'B' ,
124138 "Display nodes as shell commands of the form 'export uname=uuid' "
125- "(valid with -N/--nodes)'\n " ,
139+ "(valid with -N/--nodes)" ,
126140 pcmk__option_default
127141 },
142+ {
143+ "ipc-name" , required_argument , NULL , 'i' ,
144+ "Name to use for ipc instead of 'crmadmin'." , pcmk__option_default
145+ },
128146 {
129147 "-spacer-" , no_argument , NULL , '-' ,
130- "Notes :" , pcmk__option_default
148+ "\nNotes :" , pcmk__option_default
131149 },
132150 {
133151 "-spacer-" , no_argument , NULL , '-' ,
134- "The -K and -E commands do not work and may be removed in a future "
152+ "\nThe -K and -E commands do not work and may be removed in a future "
135153 "version." ,
136154 pcmk__option_default
137155 },
@@ -223,6 +241,88 @@ controller_event_cb(pcmk_ipc_api_t *controld_api,
223241 quit_main_loop (exit_code );
224242}
225243
244+ static void
245+ pacemakerd_event_cb (pcmk_ipc_api_t * pacemakerd_api ,
246+ enum pcmk_ipc_event event_type , crm_exit_t status ,
247+ void * event_data , void * user_data )
248+ {
249+ pcmk_pacemakerd_api_reply_t * reply = event_data ;
250+
251+ switch (event_type ) {
252+ case pcmk_ipc_event_disconnect :
253+ if (exit_code == CRM_EX_DISCONNECT ) { // Unexpected
254+ fprintf (stderr , "error: Lost connection to pacemakerd\n" );
255+ }
256+ goto done ;
257+ break ;
258+
259+ case pcmk_ipc_event_reply :
260+ break ;
261+
262+ default :
263+ return ;
264+ }
265+
266+ if (message_timer_id != 0 ) {
267+ g_source_remove (message_timer_id );
268+ message_timer_id = 0 ;
269+ }
270+
271+ if (status != CRM_EX_OK ) {
272+ fprintf (stderr , "error: Bad reply from pacemakerd: %s" ,
273+ crm_exit_str (status ));
274+ exit_code = status ;
275+ goto done ;
276+ }
277+
278+ if (reply -> reply_type != pcmk_pacemakerd_reply_ping ) {
279+ fprintf (stderr , "error: Unknown reply type %d from pacemakerd\n" ,
280+ reply -> reply_type );
281+ goto done ;
282+ }
283+
284+ // Parse desired information from reply
285+ switch (command ) {
286+ case cmd_pacemakerd_health :
287+ {
288+ crm_time_t * crm_when = crm_time_new (NULL );
289+ char * pinged_buf = NULL ;
290+
291+ crm_time_set_timet (crm_when , & reply -> data .ping .last_good );
292+ pinged_buf = crm_time_as_string (crm_when ,
293+ crm_time_log_date | crm_time_log_timeofday |
294+ crm_time_log_with_timezone );
295+
296+ printf ("Status of %s: '%s' %s %s\n" ,
297+ reply -> data .ping .sys_from ,
298+ (reply -> data .ping .status == pcmk_rc_ok )?
299+ pcmk_pacemakerd_api_pacemakerd_state_enum2text (
300+ reply -> data .ping .state ):"query failed" ,
301+ (reply -> data .ping .status == pcmk_rc_ok )?"last updated" :"" ,
302+ (reply -> data .ping .status == pcmk_rc_ok )?pinged_buf :"" );
303+ if (BE_SILENT &&
304+ (reply -> data .ping .state != pcmk_pacemakerd_state_invalid )) {
305+ fprintf (stderr , "%s\n" ,
306+ (reply -> data .ping .status == pcmk_rc_ok )?
307+ pcmk_pacemakerd_api_pacemakerd_state_enum2text (
308+ reply -> data .ping .state ):
309+ "query failed" );
310+ }
311+ exit_code = CRM_EX_OK ;
312+ free (pinged_buf );
313+ }
314+ break ;
315+
316+ default : // Not really possible here
317+ exit_code = CRM_EX_SOFTWARE ;
318+ break ;
319+ }
320+
321+ done :
322+ pcmk_disconnect_ipc (pacemakerd_api );
323+ quit_main_loop (exit_code );
324+ }
325+
226326// \return Standard Pacemaker return code
227327static int
228328list_nodes ()
@@ -257,7 +357,9 @@ main(int argc, char **argv)
257357 int flag ;
258358 int rc ;
259359 pcmk_ipc_api_t * controld_api = NULL ;
360+ pcmk_ipc_api_t * pacemakerd_api = NULL ;
260361 bool need_controld_api = true;
362+ bool need_pacemakerd_api = false;
261363
262364 crm_log_cli_init ("crmadmin" );
263365 pcmk__set_cli_options (NULL , "<command> [options]" , long_options ,
@@ -282,7 +384,9 @@ main(int argc, char **argv)
282384 message_timeout_ms = DEFAULT_MESSAGE_TIMEOUT_MS ;
283385 }
284386 break ;
285-
387+ case 'i' :
388+ ipc_name = strdup (optarg );
389+ break ;
286390 case '$' :
287391 case '?' :
288392 pcmk__cli_help (flag , CRM_EX_OK );
@@ -304,6 +408,11 @@ main(int argc, char **argv)
304408 case 'q' :
305409 BE_SILENT = TRUE;
306410 break ;
411+ case 'P' :
412+ command = cmd_pacemakerd_health ;
413+ need_pacemakerd_api = true;
414+ need_controld_api = false;
415+ break ;
307416 case 'S' :
308417 command = cmd_health ;
309418 crm_trace ("Option %c => %s" , flag , optarg );
@@ -369,7 +478,26 @@ main(int argc, char **argv)
369478 }
370479 }
371480
372- if (do_work (controld_api )) {
481+ // Connect to pacemakerd if needed
482+ if (need_pacemakerd_api ) {
483+ rc = pcmk_new_ipc_api (& pacemakerd_api , pcmk_ipc_pacemakerd );
484+ if (pacemakerd_api == NULL ) {
485+ fprintf (stderr , "error: Could not connect to pacemakerd: %s\n" ,
486+ pcmk_rc_str (rc ));
487+ exit_code = pcmk_rc2exitc (rc );
488+ goto done ;
489+ }
490+ pcmk_register_ipc_callback (pacemakerd_api , pacemakerd_event_cb , NULL );
491+ rc = pcmk_connect_ipc (pacemakerd_api , pcmk_ipc_dispatch_main );
492+ if (rc != pcmk_rc_ok ) {
493+ fprintf (stderr , "error: Could not connect to pacemakerd: %s\n" ,
494+ pcmk_rc_str (rc ));
495+ exit_code = pcmk_rc2exitc (rc );
496+ goto done ;
497+ }
498+ }
499+
500+ if (do_work (controld_api ?controld_api :pacemakerd_api )) {
373501 // A reply is needed from controller, so run main loop to get it
374502 exit_code = CRM_EX_DISCONNECT ; // For unexpected disconnects
375503 mainloop = g_main_loop_new (NULL , FALSE);
@@ -379,12 +507,19 @@ main(int argc, char **argv)
379507 }
380508
381509done :
510+
382511 if (controld_api != NULL ) {
383512 pcmk_ipc_api_t * capi = controld_api ;
384-
385513 controld_api = NULL ; // Ensure we can't free this twice
386514 pcmk_free_ipc_api (capi );
387515 }
516+
517+ if (pacemakerd_api != NULL ) {
518+ pcmk_ipc_api_t * capi = pacemakerd_api ;
519+ pacemakerd_api = NULL ; // Ensure we can't free this twice
520+ pcmk_free_ipc_api (capi );
521+ }
522+
388523 if (mainloop != NULL ) {
389524 g_main_loop_unref (mainloop );
390525 mainloop = NULL ;
@@ -394,30 +529,35 @@ main(int argc, char **argv)
394529
395530// \return True if reply from controller is needed
396531bool
397- do_work (pcmk_ipc_api_t * controld_api )
532+ do_work (pcmk_ipc_api_t * api )
398533{
399534 bool need_reply = false;
400535 int rc = pcmk_rc_ok ;
401536
402537 switch (command ) {
403538 case cmd_shutdown :
404- rc = pcmk_controld_api_shutdown (controld_api , dest_node );
539+ rc = pcmk_controld_api_shutdown (api , dest_node );
405540 break ;
406541
407542 case cmd_health : // dest_node != NULL
408543 case cmd_whois_dc : // dest_node == NULL
409- rc = pcmk_controld_api_ping (controld_api , dest_node );
544+ rc = pcmk_controld_api_ping (api , dest_node );
410545 need_reply = true;
411546 break ;
412547
413548 case cmd_elect_dc :
414- rc = pcmk_controld_api_start_election (controld_api );
549+ rc = pcmk_controld_api_start_election (api );
415550 break ;
416551
417552 case cmd_list_nodes :
418553 rc = list_nodes ();
419554 break ;
420555
556+ case cmd_pacemakerd_health :
557+ rc = pcmk_pacemakerd_api_ping (api , ipc_name );
558+ need_reply = true;
559+ break ;
560+
421561 case cmd_none : // not actually possible here
422562 break ;
423563 }
0 commit comments