1901 lines
58 KiB
Diff
1901 lines
58 KiB
Diff
|
From ea78f9a90e35be15482129e1bdb9c6d86a9a5015 Mon Sep 17 00:00:00 2001
|
||
|
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
|
||
|
Date: Thu, 29 Oct 2020 13:41:41 +0100
|
||
|
Subject: [PATCH 1/2] Refactor: crmadmin: prepare functions to move to
|
||
|
libpacemaker
|
||
|
|
||
|
---
|
||
|
tools/crmadmin.c | 321 +++++++++++++++++++++++++++++++++----------------------
|
||
|
1 file changed, 196 insertions(+), 125 deletions(-)
|
||
|
|
||
|
diff --git a/tools/crmadmin.c b/tools/crmadmin.c
|
||
|
index e61dbf4..ec902df 100644
|
||
|
--- a/tools/crmadmin.c
|
||
|
+++ b/tools/crmadmin.c
|
||
|
@@ -36,7 +36,6 @@ static guint message_timeout_ms = DEFAULT_MESSAGE_TIMEOUT_MS;
|
||
|
static GMainLoop *mainloop = NULL;
|
||
|
|
||
|
bool need_controld_api = true;
|
||
|
-bool need_pacemakerd_api = false;
|
||
|
|
||
|
bool do_work(pcmk_ipc_api_t *api);
|
||
|
static char *ipc_name = NULL;
|
||
|
@@ -135,8 +134,6 @@ command_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError
|
||
|
|
||
|
if (!strcmp(option_name, "--pacemakerd") || !strcmp(option_name, "-P")) {
|
||
|
command = cmd_pacemakerd_health;
|
||
|
- need_pacemakerd_api = true;
|
||
|
- need_controld_api = false;
|
||
|
}
|
||
|
|
||
|
if (!strcmp(option_name, "--dc_lookup") || !strcmp(option_name, "-D")) {
|
||
|
@@ -145,7 +142,6 @@ command_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError
|
||
|
|
||
|
if (!strcmp(option_name, "--nodes") || !strcmp(option_name, "-N")) {
|
||
|
command = cmd_list_nodes;
|
||
|
- need_controld_api = false;
|
||
|
}
|
||
|
|
||
|
if (!strcmp(option_name, "--election") || !strcmp(option_name, "-E")) {
|
||
|
@@ -353,6 +349,16 @@ static pcmk__supported_format_t formats[] = {
|
||
|
};
|
||
|
|
||
|
static void
|
||
|
+start_main_loop()
|
||
|
+{
|
||
|
+ exit_code = CRM_EX_DISCONNECT; // For unexpected disconnects
|
||
|
+ mainloop = g_main_loop_new(NULL, FALSE);
|
||
|
+ message_timer_id = g_timeout_add(message_timeout_ms,
|
||
|
+ admin_message_timeout, NULL);
|
||
|
+ g_main_loop_run(mainloop);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
quit_main_loop(crm_exit_t ec)
|
||
|
{
|
||
|
exit_code = ec;
|
||
|
@@ -366,9 +372,14 @@ quit_main_loop(crm_exit_t ec)
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
-controller_event_cb(pcmk_ipc_api_t *controld_api,
|
||
|
- enum pcmk_ipc_event event_type, crm_exit_t status,
|
||
|
- void *event_data, void *user_data)
|
||
|
+event_done(pcmk_ipc_api_t *api)
|
||
|
+{
|
||
|
+ pcmk_disconnect_ipc(api);
|
||
|
+ quit_main_loop(exit_code);
|
||
|
+}
|
||
|
+
|
||
|
+static pcmk_controld_api_reply_t *
|
||
|
+controld_event_reply(pcmk_ipc_api_t *controld_api, enum pcmk_ipc_event event_type, crm_exit_t status, void *event_data)
|
||
|
{
|
||
|
pcmk_controld_api_reply_t *reply = event_data;
|
||
|
|
||
|
@@ -377,14 +388,14 @@ controller_event_cb(pcmk_ipc_api_t *controld_api,
|
||
|
if (exit_code == CRM_EX_DISCONNECT) { // Unexpected
|
||
|
out->err(out, "error: Lost connection to controller");
|
||
|
}
|
||
|
- goto done;
|
||
|
- break;
|
||
|
+ event_done(controld_api);
|
||
|
+ return NULL;
|
||
|
|
||
|
case pcmk_ipc_event_reply:
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
- return;
|
||
|
+ return NULL;
|
||
|
}
|
||
|
|
||
|
if (message_timer_id != 0) {
|
||
|
@@ -396,39 +407,54 @@ controller_event_cb(pcmk_ipc_api_t *controld_api,
|
||
|
out->err(out, "error: Bad reply from controller: %s",
|
||
|
crm_exit_str(status));
|
||
|
exit_code = status;
|
||
|
- goto done;
|
||
|
+ event_done(controld_api);
|
||
|
+ return NULL;
|
||
|
}
|
||
|
|
||
|
if (reply->reply_type != pcmk_controld_reply_ping) {
|
||
|
out->err(out, "error: Unknown reply type %d from controller",
|
||
|
reply->reply_type);
|
||
|
- goto done;
|
||
|
+ event_done(controld_api);
|
||
|
+ return NULL;
|
||
|
}
|
||
|
|
||
|
- // Parse desired information from reply
|
||
|
- switch (command) {
|
||
|
- case cmd_health:
|
||
|
- out->message(out, "health",
|
||
|
- reply->data.ping.sys_from,
|
||
|
- reply->host_from,
|
||
|
- reply->data.ping.fsa_state,
|
||
|
- reply->data.ping.result);
|
||
|
- exit_code = CRM_EX_OK;
|
||
|
- break;
|
||
|
+ return reply;
|
||
|
+}
|
||
|
|
||
|
- case cmd_whois_dc:
|
||
|
- out->message(out, "dc", reply->host_from);
|
||
|
- exit_code = CRM_EX_OK;
|
||
|
- break;
|
||
|
+static void
|
||
|
+controller_status_event_cb(pcmk_ipc_api_t *controld_api,
|
||
|
+ enum pcmk_ipc_event event_type, crm_exit_t status,
|
||
|
+ void *event_data, void *user_data)
|
||
|
+{
|
||
|
+ pcmk_controld_api_reply_t *reply = controld_event_reply(controld_api,
|
||
|
+ event_type, status, event_data);
|
||
|
|
||
|
- default: // Not really possible here
|
||
|
- exit_code = CRM_EX_SOFTWARE;
|
||
|
- break;
|
||
|
+ if (reply != NULL) {
|
||
|
+ out->message(out, "health",
|
||
|
+ reply->data.ping.sys_from,
|
||
|
+ reply->host_from,
|
||
|
+ reply->data.ping.fsa_state,
|
||
|
+ reply->data.ping.result);
|
||
|
+ exit_code = CRM_EX_OK;
|
||
|
}
|
||
|
|
||
|
-done:
|
||
|
- pcmk_disconnect_ipc(controld_api);
|
||
|
- quit_main_loop(exit_code);
|
||
|
+ event_done(controld_api);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+designated_controller_event_cb(pcmk_ipc_api_t *controld_api,
|
||
|
+ enum pcmk_ipc_event event_type, crm_exit_t status,
|
||
|
+ void *event_data, void *user_data)
|
||
|
+{
|
||
|
+ pcmk_controld_api_reply_t *reply = controld_event_reply(controld_api,
|
||
|
+ event_type, status, event_data);
|
||
|
+
|
||
|
+ if (reply != NULL) {
|
||
|
+ out->message(out, "dc", reply->host_from);
|
||
|
+ exit_code = CRM_EX_OK;
|
||
|
+ }
|
||
|
+
|
||
|
+ event_done(controld_api);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
@@ -438,13 +464,16 @@ pacemakerd_event_cb(pcmk_ipc_api_t *pacemakerd_api,
|
||
|
{
|
||
|
pcmk_pacemakerd_api_reply_t *reply = event_data;
|
||
|
|
||
|
+ crm_time_t *crm_when = crm_time_new(NULL);
|
||
|
+ char *pinged_buf = NULL;
|
||
|
+
|
||
|
switch (event_type) {
|
||
|
case pcmk_ipc_event_disconnect:
|
||
|
if (exit_code == CRM_EX_DISCONNECT) { // Unexpected
|
||
|
out->err(out, "error: Lost connection to pacemakerd");
|
||
|
}
|
||
|
- goto done;
|
||
|
- break;
|
||
|
+ event_done(pacemakerd_api);
|
||
|
+ return;
|
||
|
|
||
|
case pcmk_ipc_event_reply:
|
||
|
break;
|
||
|
@@ -461,52 +490,119 @@ pacemakerd_event_cb(pcmk_ipc_api_t *pacemakerd_api,
|
||
|
if (status != CRM_EX_OK) {
|
||
|
out->err(out, "error: Bad reply from pacemakerd: %s",
|
||
|
crm_exit_str(status));
|
||
|
- exit_code = status;
|
||
|
- goto done;
|
||
|
+ event_done(pacemakerd_api);
|
||
|
+ return;
|
||
|
}
|
||
|
|
||
|
if (reply->reply_type != pcmk_pacemakerd_reply_ping) {
|
||
|
out->err(out, "error: Unknown reply type %d from pacemakerd",
|
||
|
reply->reply_type);
|
||
|
- goto done;
|
||
|
+ event_done(pacemakerd_api);
|
||
|
+ return;
|
||
|
}
|
||
|
|
||
|
// Parse desired information from reply
|
||
|
- switch (command) {
|
||
|
- case cmd_pacemakerd_health:
|
||
|
- {
|
||
|
- crm_time_t *crm_when = crm_time_new(NULL);
|
||
|
- char *pinged_buf = NULL;
|
||
|
-
|
||
|
- crm_time_set_timet(crm_when, &reply->data.ping.last_good);
|
||
|
- pinged_buf = crm_time_as_string(crm_when,
|
||
|
- crm_time_log_date | crm_time_log_timeofday |
|
||
|
- crm_time_log_with_timezone);
|
||
|
-
|
||
|
- out->message(out, "pacemakerd-health",
|
||
|
- reply->data.ping.sys_from,
|
||
|
- (reply->data.ping.status == pcmk_rc_ok)?
|
||
|
- pcmk_pacemakerd_api_daemon_state_enum2text(
|
||
|
- reply->data.ping.state):"query failed",
|
||
|
- (reply->data.ping.status == pcmk_rc_ok)?pinged_buf:"");
|
||
|
- exit_code = CRM_EX_OK;
|
||
|
- free(pinged_buf);
|
||
|
- }
|
||
|
- break;
|
||
|
+ crm_time_set_timet(crm_when, &reply->data.ping.last_good);
|
||
|
+ pinged_buf = crm_time_as_string(crm_when,
|
||
|
+ crm_time_log_date | crm_time_log_timeofday |
|
||
|
+ crm_time_log_with_timezone);
|
||
|
+
|
||
|
+ out->message(out, "pacemakerd-health",
|
||
|
+ reply->data.ping.sys_from,
|
||
|
+ (reply->data.ping.status == pcmk_rc_ok)?
|
||
|
+ pcmk_pacemakerd_api_daemon_state_enum2text(
|
||
|
+ reply->data.ping.state):"query failed",
|
||
|
+ (reply->data.ping.status == pcmk_rc_ok)?pinged_buf:"");
|
||
|
+ exit_code = CRM_EX_OK;
|
||
|
+ free(pinged_buf);
|
||
|
+
|
||
|
+ event_done(pacemakerd_api);
|
||
|
+}
|
||
|
|
||
|
- default: // Not really possible here
|
||
|
- exit_code = CRM_EX_SOFTWARE;
|
||
|
- break;
|
||
|
+static pcmk_ipc_api_t *
|
||
|
+ipc_connect(enum pcmk_ipc_server server, pcmk_ipc_callback_t cb)
|
||
|
+{
|
||
|
+ int rc;
|
||
|
+ pcmk_ipc_api_t *api = NULL;
|
||
|
+
|
||
|
+ rc = pcmk_new_ipc_api(&api, server);
|
||
|
+ if (api == NULL) {
|
||
|
+ out->err(out, "error: Could not connect to %s: %s",
|
||
|
+ (server == pcmk_ipc_controld) ? "controller" : "pacemakerd",
|
||
|
+ pcmk_rc_str(rc));
|
||
|
+ exit_code = pcmk_rc2exitc(rc);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+ pcmk_register_ipc_callback(api, cb, NULL);
|
||
|
+ rc = pcmk_connect_ipc(api, pcmk_ipc_dispatch_main);
|
||
|
+ if (rc != pcmk_rc_ok) {
|
||
|
+ out->err(out, "error: Could not connect to %s: %s",
|
||
|
+ (server == pcmk_ipc_controld) ? "controller" : "pacemakerd",
|
||
|
+ pcmk_rc_str(rc));
|
||
|
+ exit_code = pcmk_rc2exitc(rc);
|
||
|
+ return NULL;
|
||
|
}
|
||
|
|
||
|
-done:
|
||
|
- pcmk_disconnect_ipc(pacemakerd_api);
|
||
|
- quit_main_loop(exit_code);
|
||
|
+ return api;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+pcmk__controller_status()
|
||
|
+{
|
||
|
+ pcmk_ipc_api_t *controld_api = ipc_connect(pcmk_ipc_controld, controller_status_event_cb);
|
||
|
+
|
||
|
+ if (controld_api != NULL) {
|
||
|
+ int rc = pcmk_controld_api_ping(controld_api, dest_node);
|
||
|
+ if (rc != pcmk_rc_ok) {
|
||
|
+ out->err(out, "error: Command failed: %s", pcmk_rc_str(rc));
|
||
|
+ exit_code = pcmk_rc2exitc(rc);
|
||
|
+ }
|
||
|
+
|
||
|
+ start_main_loop();
|
||
|
+
|
||
|
+ pcmk_free_ipc_api(controld_api);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+pcmk__designated_controller()
|
||
|
+{
|
||
|
+ pcmk_ipc_api_t *controld_api = ipc_connect(pcmk_ipc_controld, designated_controller_event_cb);
|
||
|
+
|
||
|
+ if (controld_api != NULL) {
|
||
|
+ int rc = pcmk_controld_api_ping(controld_api, dest_node);
|
||
|
+ if (rc != pcmk_rc_ok) {
|
||
|
+ out->err(out, "error: Command failed: %s", pcmk_rc_str(rc));
|
||
|
+ exit_code = pcmk_rc2exitc(rc);
|
||
|
+ }
|
||
|
+
|
||
|
+ start_main_loop();
|
||
|
+
|
||
|
+ pcmk_free_ipc_api(controld_api);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+pcmk__pacemakerd_status()
|
||
|
+{
|
||
|
+ pcmk_ipc_api_t *pacemakerd_api = ipc_connect(pcmk_ipc_pacemakerd, pacemakerd_event_cb);
|
||
|
+
|
||
|
+ if (pacemakerd_api != NULL) {
|
||
|
+ int rc = pcmk_pacemakerd_api_ping(pacemakerd_api, ipc_name);
|
||
|
+ if (rc != pcmk_rc_ok) {
|
||
|
+ out->err(out, "error: Command failed: %s", pcmk_rc_str(rc));
|
||
|
+ exit_code = pcmk_rc2exitc(rc);
|
||
|
+ }
|
||
|
+
|
||
|
+ start_main_loop();
|
||
|
+
|
||
|
+ pcmk_free_ipc_api(pacemakerd_api);
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
// \return Standard Pacemaker return code
|
||
|
static int
|
||
|
-list_nodes()
|
||
|
+pcmk__list_nodes()
|
||
|
{
|
||
|
cib_t *the_cib = cib_new();
|
||
|
xmlNode *output = NULL;
|
||
|
@@ -565,7 +661,6 @@ main(int argc, char **argv)
|
||
|
int argerr = 0;
|
||
|
int rc;
|
||
|
pcmk_ipc_api_t *controld_api = NULL;
|
||
|
- pcmk_ipc_api_t *pacemakerd_api = NULL;
|
||
|
|
||
|
pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
|
||
|
|
||
|
@@ -643,51 +738,45 @@ main(int argc, char **argv)
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
- // Connect to the controller if needed
|
||
|
- if (need_controld_api) {
|
||
|
- rc = pcmk_new_ipc_api(&controld_api, pcmk_ipc_controld);
|
||
|
- if (controld_api == NULL) {
|
||
|
- out->err(out, "error: Could not connect to controller: %s",
|
||
|
- pcmk_rc_str(rc));
|
||
|
- exit_code = pcmk_rc2exitc(rc);
|
||
|
- goto done;
|
||
|
- }
|
||
|
- pcmk_register_ipc_callback(controld_api, controller_event_cb, NULL);
|
||
|
- rc = pcmk_connect_ipc(controld_api, pcmk_ipc_dispatch_main);
|
||
|
- if (rc != pcmk_rc_ok) {
|
||
|
- out->err(out, "error: Could not connect to controller: %s",
|
||
|
- pcmk_rc_str(rc));
|
||
|
- exit_code = pcmk_rc2exitc(rc);
|
||
|
+ switch (command) {
|
||
|
+ case cmd_health:
|
||
|
+ pcmk__controller_status();
|
||
|
goto done;
|
||
|
- }
|
||
|
- }
|
||
|
-
|
||
|
- // Connect to pacemakerd if needed
|
||
|
- if (need_pacemakerd_api) {
|
||
|
- rc = pcmk_new_ipc_api(&pacemakerd_api, pcmk_ipc_pacemakerd);
|
||
|
- if (pacemakerd_api == NULL) {
|
||
|
- out->err(out, "error: Could not connect to pacemakerd: %s",
|
||
|
- pcmk_rc_str(rc));
|
||
|
- exit_code = pcmk_rc2exitc(rc);
|
||
|
+ case cmd_pacemakerd_health:
|
||
|
+ pcmk__pacemakerd_status();
|
||
|
goto done;
|
||
|
- }
|
||
|
- pcmk_register_ipc_callback(pacemakerd_api, pacemakerd_event_cb, NULL);
|
||
|
- rc = pcmk_connect_ipc(pacemakerd_api, pcmk_ipc_dispatch_main);
|
||
|
- if (rc != pcmk_rc_ok) {
|
||
|
- out->err(out, "error: Could not connect to pacemakerd: %s",
|
||
|
- pcmk_rc_str(rc));
|
||
|
- exit_code = pcmk_rc2exitc(rc);
|
||
|
+ case cmd_list_nodes:
|
||
|
+ rc = pcmk__list_nodes();
|
||
|
+ // might need movink
|
||
|
+ if (rc != pcmk_rc_ok) {
|
||
|
+ out->err(out, "error: Command failed: %s", pcmk_rc_str(rc));
|
||
|
+ exit_code = pcmk_rc2exitc(rc);
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ case cmd_whois_dc:
|
||
|
+ pcmk__designated_controller();
|
||
|
goto done;
|
||
|
- }
|
||
|
+ default:
|
||
|
+ rc = pcmk_new_ipc_api(&controld_api, pcmk_ipc_controld);
|
||
|
+ if (controld_api == NULL) {
|
||
|
+ out->err(out, "error: Could not connect to controller: %s",
|
||
|
+ pcmk_rc_str(rc));
|
||
|
+ exit_code = pcmk_rc2exitc(rc);
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ rc = pcmk_connect_ipc(controld_api, pcmk_ipc_dispatch_main);
|
||
|
+ if (rc != pcmk_rc_ok) {
|
||
|
+ out->err(out, "error: Could not connect to controller: %s",
|
||
|
+ pcmk_rc_str(rc));
|
||
|
+ exit_code = pcmk_rc2exitc(rc);
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ break;
|
||
|
}
|
||
|
|
||
|
- if (do_work(controld_api?controld_api:pacemakerd_api)) {
|
||
|
+ if (do_work(controld_api?controld_api:NULL)) {
|
||
|
// A reply is needed from controller, so run main loop to get it
|
||
|
- exit_code = CRM_EX_DISCONNECT; // For unexpected disconnects
|
||
|
- mainloop = g_main_loop_new(NULL, FALSE);
|
||
|
- message_timer_id = g_timeout_add(message_timeout_ms,
|
||
|
- admin_message_timeout, NULL);
|
||
|
- g_main_loop_run(mainloop);
|
||
|
+ start_main_loop();
|
||
|
}
|
||
|
|
||
|
done:
|
||
|
@@ -698,12 +787,6 @@ done:
|
||
|
pcmk_free_ipc_api(capi);
|
||
|
}
|
||
|
|
||
|
- if (pacemakerd_api != NULL) {
|
||
|
- pcmk_ipc_api_t *capi = pacemakerd_api;
|
||
|
- pacemakerd_api = NULL; // Ensure we can't free this twice
|
||
|
- pcmk_free_ipc_api(capi);
|
||
|
- }
|
||
|
-
|
||
|
if (mainloop != NULL) {
|
||
|
g_main_loop_unref(mainloop);
|
||
|
mainloop = NULL;
|
||
|
@@ -731,26 +814,14 @@ do_work(pcmk_ipc_api_t *api)
|
||
|
rc = pcmk_controld_api_shutdown(api, dest_node);
|
||
|
break;
|
||
|
|
||
|
- case cmd_health: // dest_node != NULL
|
||
|
- case cmd_whois_dc: // dest_node == NULL
|
||
|
- rc = pcmk_controld_api_ping(api, dest_node);
|
||
|
- need_reply = true;
|
||
|
- break;
|
||
|
-
|
||
|
case cmd_elect_dc:
|
||
|
rc = pcmk_controld_api_start_election(api);
|
||
|
break;
|
||
|
|
||
|
- case cmd_list_nodes:
|
||
|
- rc = list_nodes();
|
||
|
- break;
|
||
|
-
|
||
|
- case cmd_pacemakerd_health:
|
||
|
- rc = pcmk_pacemakerd_api_ping(api, ipc_name);
|
||
|
- need_reply = true;
|
||
|
+ case cmd_none: // not actually possible here
|
||
|
break;
|
||
|
|
||
|
- case cmd_none: // not actually possible here
|
||
|
+ default:
|
||
|
break;
|
||
|
}
|
||
|
if (rc != pcmk_rc_ok) {
|
||
|
--
|
||
|
1.8.3.1
|
||
|
|
||
|
|
||
|
From ac241aec979938175103624f07c8e90c6b550c48 Mon Sep 17 00:00:00 2001
|
||
|
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
|
||
|
Date: Fri, 30 Oct 2020 13:09:48 +0100
|
||
|
Subject: [PATCH 2/2] Refactor: crmadmin: move guts to libpacemaker
|
||
|
|
||
|
---
|
||
|
include/pacemaker-internal.h | 1 +
|
||
|
include/pcmki/Makefile.am | 1 +
|
||
|
include/pcmki/pcmki_cluster_queries.h | 15 +
|
||
|
lib/pacemaker/Makefile.am | 1 +
|
||
|
lib/pacemaker/pcmk_cluster_queries.c | 408 +++++++++++++++++++++++
|
||
|
lib/pacemaker/pcmk_output.c | 177 ++++++++++
|
||
|
tools/Makefile.am | 3 +-
|
||
|
tools/crmadmin.c | 612 ++--------------------------------
|
||
|
8 files changed, 642 insertions(+), 576 deletions(-)
|
||
|
create mode 100644 include/pcmki/pcmki_cluster_queries.h
|
||
|
create mode 100644 lib/pacemaker/pcmk_cluster_queries.c
|
||
|
|
||
|
diff --git a/include/pacemaker-internal.h b/include/pacemaker-internal.h
|
||
|
index 37399e7..2e75d09 100644
|
||
|
--- a/include/pacemaker-internal.h
|
||
|
+++ b/include/pacemaker-internal.h
|
||
|
@@ -11,6 +11,7 @@
|
||
|
# define PACEMAKER_INTERNAL__H
|
||
|
|
||
|
# include <pcmki/pcmki_error.h>
|
||
|
+# include <pcmki/pcmki_cluster_queries.h>
|
||
|
# include <pcmki/pcmki_fence.h>
|
||
|
# include <pcmki/pcmki_output.h>
|
||
|
# include <pcmki/pcmki_sched_allocate.h>
|
||
|
diff --git a/include/pcmki/Makefile.am b/include/pcmki/Makefile.am
|
||
|
index 647f2dc..7aa64c7 100644
|
||
|
--- a/include/pcmki/Makefile.am
|
||
|
+++ b/include/pcmki/Makefile.am
|
||
|
@@ -10,6 +10,7 @@
|
||
|
MAINTAINERCLEANFILES = Makefile.in
|
||
|
|
||
|
noinst_HEADERS = pcmki_error.h \
|
||
|
+ pcmki_cluster_queries.h \
|
||
|
pcmki_fence.h \
|
||
|
pcmki_output.h \
|
||
|
pcmki_sched_allocate.h \
|
||
|
diff --git a/include/pcmki/pcmki_cluster_queries.h b/include/pcmki/pcmki_cluster_queries.h
|
||
|
new file mode 100644
|
||
|
index 0000000..eb3b51c
|
||
|
--- /dev/null
|
||
|
+++ b/include/pcmki/pcmki_cluster_queries.h
|
||
|
@@ -0,0 +1,15 @@
|
||
|
+#include <glib.h> // gboolean, GMainLoop, etc.
|
||
|
+
|
||
|
+#include <crm/crm.h>
|
||
|
+#include <crm/common/output_internal.h>
|
||
|
+#include <crm/common/ipc_controld.h>
|
||
|
+#include <crm/common/ipc_pacemakerd.h>
|
||
|
+
|
||
|
+int pcmk__controller_status(pcmk__output_t *out, char *dest_node, guint message_timeout_ms);
|
||
|
+int pcmk__designated_controller(pcmk__output_t *out, guint message_timeout_ms);
|
||
|
+int pcmk__pacemakerd_status(pcmk__output_t *out, char *ipc_name, guint message_timeout_ms);
|
||
|
+int pcmk__list_nodes(pcmk__output_t *out, gboolean BASH_EXPORT);
|
||
|
+
|
||
|
+// remove when parameters removed from tools/crmadmin.c
|
||
|
+int pcmk__shutdown_controller(pcmk__output_t *out, char *dest_node);
|
||
|
+int pcmk__start_election(pcmk__output_t *out);
|
||
|
diff --git a/lib/pacemaker/Makefile.am b/lib/pacemaker/Makefile.am
|
||
|
index 51a811a..4129ade 100644
|
||
|
--- a/lib/pacemaker/Makefile.am
|
||
|
+++ b/lib/pacemaker/Makefile.am
|
||
|
@@ -28,6 +28,7 @@ libpacemaker_la_LIBADD = $(top_builddir)/lib/pengine/libpe_status.la \
|
||
|
# -L$(top_builddir)/lib/pils -lpils -export-dynamic -module -avoid-version
|
||
|
# Use += rather than backlashed continuation lines for parsing by bumplibs.sh
|
||
|
libpacemaker_la_SOURCES =
|
||
|
+libpacemaker_la_SOURCES += pcmk_cluster_queries.c
|
||
|
libpacemaker_la_SOURCES += pcmk_fence.c
|
||
|
libpacemaker_la_SOURCES += pcmk_output.c
|
||
|
libpacemaker_la_SOURCES += pcmk_sched_allocate.c
|
||
|
diff --git a/lib/pacemaker/pcmk_cluster_queries.c b/lib/pacemaker/pcmk_cluster_queries.c
|
||
|
new file mode 100644
|
||
|
index 0000000..8d729eb
|
||
|
--- /dev/null
|
||
|
+++ b/lib/pacemaker/pcmk_cluster_queries.c
|
||
|
@@ -0,0 +1,408 @@
|
||
|
+#include <glib.h> // gboolean, GMainLoop, etc.
|
||
|
+#include <libxml/tree.h> // xmlNode
|
||
|
+
|
||
|
+#include <pacemaker-internal.h>
|
||
|
+
|
||
|
+#include <crm/crm.h>
|
||
|
+#include <crm/cib.h>
|
||
|
+#include <crm/msg_xml.h>
|
||
|
+#include <crm/common/output_internal.h>
|
||
|
+#include <crm/common/xml.h>
|
||
|
+#include <crm/common/iso8601.h>
|
||
|
+#include <crm/common/ipc_controld.h>
|
||
|
+#include <crm/common/ipc_pacemakerd.h>
|
||
|
+#include <crm/common/mainloop.h>
|
||
|
+
|
||
|
+#define DEFAULT_MESSAGE_TIMEOUT_MS 30000
|
||
|
+
|
||
|
+
|
||
|
+typedef struct {
|
||
|
+ pcmk__output_t *out;
|
||
|
+ GMainLoop *mainloop;
|
||
|
+ int rc;
|
||
|
+ guint message_timer_id;
|
||
|
+ guint message_timeout_ms;
|
||
|
+} data_t;
|
||
|
+
|
||
|
+static void
|
||
|
+quit_main_loop(data_t *data)
|
||
|
+{
|
||
|
+ if (data->mainloop != NULL) {
|
||
|
+ GMainLoop *mloop = data->mainloop;
|
||
|
+
|
||
|
+ data->mainloop = NULL; // Don't re-enter this block
|
||
|
+ pcmk_quit_main_loop(mloop, 10);
|
||
|
+ g_main_loop_unref(mloop);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static gboolean
|
||
|
+admin_message_timeout(gpointer user_data)
|
||
|
+{
|
||
|
+ data_t *data = user_data;
|
||
|
+ pcmk__output_t *out = data->out;
|
||
|
+
|
||
|
+ out->err(out, "error: No reply received from controller before timeout (%dms)",
|
||
|
+ data->message_timeout_ms);
|
||
|
+ data->message_timer_id = 0;
|
||
|
+ data->rc = ETIMEDOUT;
|
||
|
+ quit_main_loop(data);
|
||
|
+ return FALSE; // Tells glib to remove source
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+start_main_loop(data_t *data)
|
||
|
+{
|
||
|
+ if (data->message_timeout_ms < 1) {
|
||
|
+ data->message_timeout_ms = DEFAULT_MESSAGE_TIMEOUT_MS;
|
||
|
+ }
|
||
|
+
|
||
|
+ data->rc = ECONNRESET; // For unexpected disconnects
|
||
|
+ data->mainloop = g_main_loop_new(NULL, FALSE);
|
||
|
+ data->message_timer_id = g_timeout_add(data->message_timeout_ms,
|
||
|
+ admin_message_timeout,
|
||
|
+ data);
|
||
|
+ g_main_loop_run(data->mainloop);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+event_done(data_t *data, pcmk_ipc_api_t *api)
|
||
|
+{
|
||
|
+ pcmk_disconnect_ipc(api);
|
||
|
+ quit_main_loop(data);
|
||
|
+}
|
||
|
+
|
||
|
+static pcmk_controld_api_reply_t *
|
||
|
+controld_event_reply(data_t *data, pcmk_ipc_api_t *controld_api, enum pcmk_ipc_event event_type, crm_exit_t status, void *event_data)
|
||
|
+{
|
||
|
+ pcmk__output_t *out = data->out;
|
||
|
+ pcmk_controld_api_reply_t *reply = event_data;
|
||
|
+
|
||
|
+ switch (event_type) {
|
||
|
+ case pcmk_ipc_event_disconnect:
|
||
|
+ if (data->rc == ECONNRESET) { // Unexpected
|
||
|
+ out->err(out, "error: Lost connection to controller");
|
||
|
+ }
|
||
|
+ event_done(data, controld_api);
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ case pcmk_ipc_event_reply:
|
||
|
+ break;
|
||
|
+
|
||
|
+ default:
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (data->message_timer_id != 0) {
|
||
|
+ g_source_remove(data->message_timer_id);
|
||
|
+ data->message_timer_id = 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (status != CRM_EX_OK) {
|
||
|
+ out->err(out, "error: Bad reply from controller: %s",
|
||
|
+ crm_exit_str(status));
|
||
|
+ data->rc = EBADMSG;
|
||
|
+ event_done(data, controld_api);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (reply->reply_type != pcmk_controld_reply_ping) {
|
||
|
+ out->err(out, "error: Unknown reply type %d from controller",
|
||
|
+ reply->reply_type);
|
||
|
+ data->rc = EBADMSG;
|
||
|
+ event_done(data, controld_api);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ return reply;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+controller_status_event_cb(pcmk_ipc_api_t *controld_api,
|
||
|
+ enum pcmk_ipc_event event_type, crm_exit_t status,
|
||
|
+ void *event_data, void *user_data)
|
||
|
+{
|
||
|
+ data_t *data = user_data;
|
||
|
+ pcmk__output_t *out = data->out;
|
||
|
+ pcmk_controld_api_reply_t *reply = controld_event_reply(data, controld_api,
|
||
|
+ event_type, status, event_data);
|
||
|
+
|
||
|
+ if (reply != NULL) {
|
||
|
+ out->message(out, "health",
|
||
|
+ reply->data.ping.sys_from,
|
||
|
+ reply->host_from,
|
||
|
+ reply->data.ping.fsa_state,
|
||
|
+ reply->data.ping.result);
|
||
|
+ data->rc = pcmk_rc_ok;
|
||
|
+ }
|
||
|
+
|
||
|
+ event_done(data, controld_api);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+designated_controller_event_cb(pcmk_ipc_api_t *controld_api,
|
||
|
+ enum pcmk_ipc_event event_type, crm_exit_t status,
|
||
|
+ void *event_data, void *user_data)
|
||
|
+{
|
||
|
+ data_t *data = user_data;
|
||
|
+ pcmk__output_t *out = data->out;
|
||
|
+ pcmk_controld_api_reply_t *reply = controld_event_reply(data, controld_api,
|
||
|
+ event_type, status, event_data);
|
||
|
+
|
||
|
+ if (reply != NULL) {
|
||
|
+ out->message(out, "dc", reply->host_from);
|
||
|
+ data->rc = pcmk_rc_ok;
|
||
|
+ }
|
||
|
+
|
||
|
+ event_done(data, controld_api);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+pacemakerd_event_cb(pcmk_ipc_api_t *pacemakerd_api,
|
||
|
+ enum pcmk_ipc_event event_type, crm_exit_t status,
|
||
|
+ void *event_data, void *user_data)
|
||
|
+{
|
||
|
+ data_t *data = user_data;
|
||
|
+ pcmk__output_t *out = data->out;
|
||
|
+ pcmk_pacemakerd_api_reply_t *reply = event_data;
|
||
|
+
|
||
|
+ crm_time_t *crm_when;
|
||
|
+ char *pinged_buf = NULL;
|
||
|
+
|
||
|
+ switch (event_type) {
|
||
|
+ case pcmk_ipc_event_disconnect:
|
||
|
+ if (data->rc == ECONNRESET) { // Unexpected
|
||
|
+ out->err(out, "error: Lost connection to pacemakerd");
|
||
|
+ }
|
||
|
+ event_done(data, pacemakerd_api);
|
||
|
+ return;
|
||
|
+
|
||
|
+ case pcmk_ipc_event_reply:
|
||
|
+ break;
|
||
|
+
|
||
|
+ default:
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (data->message_timer_id != 0) {
|
||
|
+ g_source_remove(data->message_timer_id);
|
||
|
+ data->message_timer_id = 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (status != CRM_EX_OK) {
|
||
|
+ out->err(out, "error: Bad reply from pacemakerd: %s",
|
||
|
+ crm_exit_str(status));
|
||
|
+ event_done(data, pacemakerd_api);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (reply->reply_type != pcmk_pacemakerd_reply_ping) {
|
||
|
+ out->err(out, "error: Unknown reply type %d from pacemakerd",
|
||
|
+ reply->reply_type);
|
||
|
+ event_done(data, pacemakerd_api);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ // Parse desired information from reply
|
||
|
+ crm_when = crm_time_new(NULL);
|
||
|
+ crm_time_set_timet(crm_when, &reply->data.ping.last_good);
|
||
|
+ pinged_buf = crm_time_as_string(crm_when,
|
||
|
+ crm_time_log_date | crm_time_log_timeofday |
|
||
|
+ crm_time_log_with_timezone);
|
||
|
+
|
||
|
+ out->message(out, "pacemakerd-health",
|
||
|
+ reply->data.ping.sys_from,
|
||
|
+ (reply->data.ping.status == pcmk_rc_ok)?
|
||
|
+ pcmk_pacemakerd_api_daemon_state_enum2text(
|
||
|
+ reply->data.ping.state):"query failed",
|
||
|
+ (reply->data.ping.status == pcmk_rc_ok)?pinged_buf:"");
|
||
|
+ data->rc = pcmk_rc_ok;
|
||
|
+ crm_time_free(crm_when);
|
||
|
+ free(pinged_buf);
|
||
|
+
|
||
|
+ event_done(data, pacemakerd_api);
|
||
|
+}
|
||
|
+
|
||
|
+static pcmk_ipc_api_t *
|
||
|
+ipc_connect(data_t *data, enum pcmk_ipc_server server, pcmk_ipc_callback_t cb)
|
||
|
+{
|
||
|
+ int rc;
|
||
|
+ pcmk__output_t *out = data->out;
|
||
|
+ pcmk_ipc_api_t *api = NULL;
|
||
|
+
|
||
|
+
|
||
|
+ rc = pcmk_new_ipc_api(&api, server);
|
||
|
+ if (api == NULL) {
|
||
|
+ out->err(out, "error: Could not connect to %s: %s",
|
||
|
+ pcmk_ipc_name(api, true),
|
||
|
+ pcmk_rc_str(rc));
|
||
|
+ data->rc = rc;
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+ if (cb != NULL) {
|
||
|
+ pcmk_register_ipc_callback(api, cb, data);
|
||
|
+ }
|
||
|
+ rc = pcmk_connect_ipc(api, pcmk_ipc_dispatch_main);
|
||
|
+ if (rc != pcmk_rc_ok) {
|
||
|
+ out->err(out, "error: Could not connect to %s: %s",
|
||
|
+ pcmk_ipc_name(api, true),
|
||
|
+ pcmk_rc_str(rc));
|
||
|
+ data->rc = rc;
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ return api;
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+pcmk__controller_status(pcmk__output_t *out, char *dest_node, guint message_timeout_ms)
|
||
|
+{
|
||
|
+ data_t data = {
|
||
|
+ .out = out,
|
||
|
+ .mainloop = NULL,
|
||
|
+ .rc = pcmk_rc_ok,
|
||
|
+ .message_timer_id = 0,
|
||
|
+ .message_timeout_ms = message_timeout_ms
|
||
|
+ };
|
||
|
+ pcmk_ipc_api_t *controld_api = ipc_connect(&data, pcmk_ipc_controld, controller_status_event_cb);
|
||
|
+
|
||
|
+ if (controld_api != NULL) {
|
||
|
+ int rc = pcmk_controld_api_ping(controld_api, dest_node);
|
||
|
+ if (rc != pcmk_rc_ok) {
|
||
|
+ out->err(out, "error: Command failed: %s", pcmk_rc_str(rc));
|
||
|
+ data.rc = rc;
|
||
|
+ }
|
||
|
+
|
||
|
+ start_main_loop(&data);
|
||
|
+
|
||
|
+ pcmk_free_ipc_api(controld_api);
|
||
|
+ }
|
||
|
+
|
||
|
+ return data.rc;
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+pcmk__designated_controller(pcmk__output_t *out, guint message_timeout_ms)
|
||
|
+{
|
||
|
+ data_t data = {
|
||
|
+ .out = out,
|
||
|
+ .mainloop = NULL,
|
||
|
+ .rc = pcmk_rc_ok,
|
||
|
+ .message_timer_id = 0,
|
||
|
+ .message_timeout_ms = message_timeout_ms
|
||
|
+ };
|
||
|
+ pcmk_ipc_api_t *controld_api = ipc_connect(&data, pcmk_ipc_controld, designated_controller_event_cb);
|
||
|
+
|
||
|
+ if (controld_api != NULL) {
|
||
|
+ int rc = pcmk_controld_api_ping(controld_api, NULL);
|
||
|
+ if (rc != pcmk_rc_ok) {
|
||
|
+ out->err(out, "error: Command failed: %s", pcmk_rc_str(rc));
|
||
|
+ data.rc = rc;
|
||
|
+ }
|
||
|
+
|
||
|
+ start_main_loop(&data);
|
||
|
+
|
||
|
+ pcmk_free_ipc_api(controld_api);
|
||
|
+ }
|
||
|
+
|
||
|
+ return data.rc;
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+pcmk__pacemakerd_status(pcmk__output_t *out, char *ipc_name, guint message_timeout_ms)
|
||
|
+{
|
||
|
+ data_t data = {
|
||
|
+ .out = out,
|
||
|
+ .mainloop = NULL,
|
||
|
+ .rc = pcmk_rc_ok,
|
||
|
+ .message_timer_id = 0,
|
||
|
+ .message_timeout_ms = message_timeout_ms
|
||
|
+ };
|
||
|
+ pcmk_ipc_api_t *pacemakerd_api = ipc_connect(&data, pcmk_ipc_pacemakerd, pacemakerd_event_cb);
|
||
|
+
|
||
|
+ if (pacemakerd_api != NULL) {
|
||
|
+ int rc = pcmk_pacemakerd_api_ping(pacemakerd_api, ipc_name);
|
||
|
+ if (rc != pcmk_rc_ok) {
|
||
|
+ out->err(out, "error: Command failed: %s", pcmk_rc_str(rc));
|
||
|
+ data.rc = rc;
|
||
|
+ }
|
||
|
+
|
||
|
+ start_main_loop(&data);
|
||
|
+
|
||
|
+ pcmk_free_ipc_api(pacemakerd_api);
|
||
|
+ }
|
||
|
+
|
||
|
+ return data.rc;
|
||
|
+}
|
||
|
+
|
||
|
+// \return Standard Pacemaker return code
|
||
|
+int
|
||
|
+pcmk__list_nodes(pcmk__output_t *out, gboolean BASH_EXPORT)
|
||
|
+{
|
||
|
+ cib_t *the_cib = cib_new();
|
||
|
+ xmlNode *output = NULL;
|
||
|
+ int rc;
|
||
|
+
|
||
|
+ if (the_cib == NULL) {
|
||
|
+ return ENOMEM;
|
||
|
+ }
|
||
|
+ rc = the_cib->cmds->signon(the_cib, crm_system_name, cib_command);
|
||
|
+ if (rc != pcmk_ok) {
|
||
|
+ return pcmk_legacy2rc(rc);
|
||
|
+ }
|
||
|
+
|
||
|
+ rc = the_cib->cmds->query(the_cib, NULL, &output,
|
||
|
+ cib_scope_local | cib_sync_call);
|
||
|
+ if (rc == pcmk_ok) {
|
||
|
+ out->message(out, "crmadmin-node-list", output, BASH_EXPORT);
|
||
|
+ free_xml(output);
|
||
|
+ }
|
||
|
+ the_cib->cmds->signoff(the_cib);
|
||
|
+ return pcmk_legacy2rc(rc);
|
||
|
+}
|
||
|
+
|
||
|
+// remove when parameters removed from tools/crmadmin.c
|
||
|
+int
|
||
|
+pcmk__shutdown_controller(pcmk__output_t *out, char *dest_node)
|
||
|
+{
|
||
|
+ data_t data = {
|
||
|
+ .out = out,
|
||
|
+ .mainloop = NULL,
|
||
|
+ .rc = pcmk_rc_ok,
|
||
|
+ };
|
||
|
+ pcmk_ipc_api_t *controld_api = ipc_connect(&data, pcmk_ipc_controld, NULL);
|
||
|
+
|
||
|
+ if (controld_api != NULL) {
|
||
|
+ int rc = pcmk_controld_api_shutdown(controld_api, dest_node);
|
||
|
+ if (rc != pcmk_rc_ok) {
|
||
|
+ out->err(out, "error: Command failed: %s", pcmk_rc_str(rc));
|
||
|
+ data.rc = rc;
|
||
|
+ }
|
||
|
+ pcmk_free_ipc_api(controld_api);
|
||
|
+ }
|
||
|
+
|
||
|
+ return data.rc;
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+pcmk__start_election(pcmk__output_t *out)
|
||
|
+{
|
||
|
+ data_t data = {
|
||
|
+ .out = out,
|
||
|
+ .mainloop = NULL,
|
||
|
+ .rc = pcmk_rc_ok,
|
||
|
+ };
|
||
|
+ pcmk_ipc_api_t *controld_api = ipc_connect(&data, pcmk_ipc_controld, NULL);
|
||
|
+
|
||
|
+ if (controld_api != NULL) {
|
||
|
+ int rc = pcmk_controld_api_start_election(controld_api);
|
||
|
+ if (rc != pcmk_rc_ok) {
|
||
|
+ out->err(out, "error: Command failed: %s", pcmk_rc_str(rc));
|
||
|
+ data.rc = rc;
|
||
|
+ }
|
||
|
+
|
||
|
+ pcmk_free_ipc_api(controld_api);
|
||
|
+ }
|
||
|
+
|
||
|
+ return data.rc;
|
||
|
+}
|
||
|
diff --git a/lib/pacemaker/pcmk_output.c b/lib/pacemaker/pcmk_output.c
|
||
|
index 306e561..fd577c6 100644
|
||
|
--- a/lib/pacemaker/pcmk_output.c
|
||
|
+++ b/lib/pacemaker/pcmk_output.c
|
||
|
@@ -357,6 +357,174 @@ stacks_and_constraints_xml(pcmk__output_t *out, va_list args) {
|
||
|
return pcmk_rc_ok;
|
||
|
}
|
||
|
|
||
|
+PCMK__OUTPUT_ARGS("health", "char *", "char *", "char *", "char *")
|
||
|
+static int
|
||
|
+health_text(pcmk__output_t *out, va_list args)
|
||
|
+{
|
||
|
+ char *sys_from = va_arg(args, char *);
|
||
|
+ char *host_from = va_arg(args, char *);
|
||
|
+ char *fsa_state = va_arg(args, char *);
|
||
|
+ char *result = va_arg(args, char *);
|
||
|
+
|
||
|
+ if (!out->is_quiet(out)) {
|
||
|
+ out->info(out, "Status of %s@%s: %s (%s)", crm_str(sys_from),
|
||
|
+ crm_str(host_from), crm_str(fsa_state), crm_str(result));
|
||
|
+ } else if (fsa_state != NULL) {
|
||
|
+ out->info(out, "%s", fsa_state);
|
||
|
+ }
|
||
|
+
|
||
|
+ return pcmk_rc_ok;
|
||
|
+}
|
||
|
+
|
||
|
+PCMK__OUTPUT_ARGS("health", "char *", "char *", "char *", "char *")
|
||
|
+static int
|
||
|
+health_xml(pcmk__output_t *out, va_list args)
|
||
|
+{
|
||
|
+ char *sys_from = va_arg(args, char *);
|
||
|
+ char *host_from = va_arg(args, char *);
|
||
|
+ char *fsa_state = va_arg(args, char *);
|
||
|
+ char *result = va_arg(args, char *);
|
||
|
+
|
||
|
+ xmlNodePtr node = pcmk__output_create_xml_node(out, crm_str(sys_from));
|
||
|
+ xmlSetProp(node, (pcmkXmlStr) "node_name", (pcmkXmlStr) crm_str(host_from));
|
||
|
+ xmlSetProp(node, (pcmkXmlStr) "state", (pcmkXmlStr) crm_str(fsa_state));
|
||
|
+ xmlSetProp(node, (pcmkXmlStr) "result", (pcmkXmlStr) crm_str(result));
|
||
|
+
|
||
|
+ return pcmk_rc_ok;
|
||
|
+}
|
||
|
+
|
||
|
+PCMK__OUTPUT_ARGS("pacemakerd-health", "char *", "char *", "char *")
|
||
|
+static int
|
||
|
+pacemakerd_health_text(pcmk__output_t *out, va_list args)
|
||
|
+{
|
||
|
+ char *sys_from = va_arg(args, char *);
|
||
|
+ char *state = va_arg(args, char *);
|
||
|
+ char *last_updated = va_arg(args, char *);
|
||
|
+
|
||
|
+ if (!out->is_quiet(out)) {
|
||
|
+ out->info(out, "Status of %s: '%s' %s %s", crm_str(sys_from),
|
||
|
+ crm_str(state), (!pcmk__str_empty(last_updated))?
|
||
|
+ "last updated":"", crm_str(last_updated));
|
||
|
+ } else {
|
||
|
+ out->info(out, "%s", crm_str(state));
|
||
|
+ }
|
||
|
+
|
||
|
+ return pcmk_rc_ok;
|
||
|
+}
|
||
|
+
|
||
|
+PCMK__OUTPUT_ARGS("pacemakerd-health", "char *", "char *", "char *")
|
||
|
+static int
|
||
|
+pacemakerd_health_xml(pcmk__output_t *out, va_list args)
|
||
|
+{
|
||
|
+ char *sys_from = va_arg(args, char *);
|
||
|
+ char *state = va_arg(args, char *);
|
||
|
+ char *last_updated = va_arg(args, char *);
|
||
|
+
|
||
|
+
|
||
|
+ xmlNodePtr node = pcmk__output_create_xml_node(out, crm_str(sys_from));
|
||
|
+ xmlSetProp(node, (pcmkXmlStr) "state", (pcmkXmlStr) crm_str(state));
|
||
|
+ xmlSetProp(node, (pcmkXmlStr) "last_updated", (pcmkXmlStr) crm_str(last_updated));
|
||
|
+
|
||
|
+ return pcmk_rc_ok;
|
||
|
+}
|
||
|
+
|
||
|
+PCMK__OUTPUT_ARGS("dc", "char *")
|
||
|
+static int
|
||
|
+dc_text(pcmk__output_t *out, va_list args)
|
||
|
+{
|
||
|
+ char *dc = va_arg(args, char *);
|
||
|
+
|
||
|
+ if (!out->is_quiet(out)) {
|
||
|
+ out->info(out, "Designated Controller is: %s", crm_str(dc));
|
||
|
+ } else if (dc != NULL) {
|
||
|
+ out->info(out, "%s", dc);
|
||
|
+ }
|
||
|
+
|
||
|
+ return pcmk_rc_ok;
|
||
|
+}
|
||
|
+
|
||
|
+PCMK__OUTPUT_ARGS("dc", "char *")
|
||
|
+static int
|
||
|
+dc_xml(pcmk__output_t *out, va_list args)
|
||
|
+{
|
||
|
+ char *dc = va_arg(args, char *);
|
||
|
+
|
||
|
+ xmlNodePtr node = pcmk__output_create_xml_node(out, "dc");
|
||
|
+ xmlSetProp(node, (pcmkXmlStr) "node_name", (pcmkXmlStr) crm_str(dc));
|
||
|
+
|
||
|
+ return pcmk_rc_ok;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+PCMK__OUTPUT_ARGS("crmadmin-node-list", "pcmk__output_t *", "xmlNode *")
|
||
|
+static int
|
||
|
+crmadmin_node_list(pcmk__output_t *out, va_list args)
|
||
|
+{
|
||
|
+ xmlNode *xml_node = va_arg(args, xmlNode *);
|
||
|
+ int found = 0;
|
||
|
+ xmlNode *node = NULL;
|
||
|
+ xmlNode *nodes = get_object_root(XML_CIB_TAG_NODES, xml_node);
|
||
|
+ gboolean BASH_EXPORT = va_arg(args, gboolean);
|
||
|
+
|
||
|
+ out->begin_list(out, NULL, NULL, "nodes");
|
||
|
+
|
||
|
+ for (node = first_named_child(nodes, XML_CIB_TAG_NODE); node != NULL;
|
||
|
+ node = crm_next_same_xml(node)) {
|
||
|
+ const char *node_type = BASH_EXPORT ? NULL :
|
||
|
+ crm_element_value(node, XML_ATTR_TYPE);
|
||
|
+ out->message(out, "crmadmin-node", node_type,
|
||
|
+ crm_str(crm_element_value(node, XML_ATTR_UNAME)),
|
||
|
+ crm_str(crm_element_value(node, XML_ATTR_ID)),
|
||
|
+ BASH_EXPORT);
|
||
|
+
|
||
|
+ found++;
|
||
|
+ }
|
||
|
+ // @TODO List Pacemaker Remote nodes that don't have a <node> entry
|
||
|
+
|
||
|
+ out->end_list(out);
|
||
|
+
|
||
|
+ if (found == 0) {
|
||
|
+ out->info(out, "No nodes configured");
|
||
|
+ }
|
||
|
+
|
||
|
+ return pcmk_rc_ok;
|
||
|
+}
|
||
|
+
|
||
|
+PCMK__OUTPUT_ARGS("crmadmin-node", "char *", "char *", "char *", "gboolean")
|
||
|
+static int
|
||
|
+crmadmin_node_text(pcmk__output_t *out, va_list args)
|
||
|
+{
|
||
|
+ char *type = va_arg(args, char *);
|
||
|
+ char *name = va_arg(args, char *);
|
||
|
+ char *id = va_arg(args, char *);
|
||
|
+ gboolean BASH_EXPORT = va_arg(args, gboolean);
|
||
|
+
|
||
|
+ if (BASH_EXPORT) {
|
||
|
+ out->info(out, "export %s=%s", crm_str(name), crm_str(id));
|
||
|
+ } else {
|
||
|
+ out->info(out, "%s node: %s (%s)", type ? type : "member",
|
||
|
+ crm_str(name), crm_str(id));
|
||
|
+ }
|
||
|
+
|
||
|
+ return pcmk_rc_ok;
|
||
|
+}
|
||
|
+
|
||
|
+PCMK__OUTPUT_ARGS("crmadmin-node", "char *", "char *", "char *", "gboolean")
|
||
|
+static int
|
||
|
+crmadmin_node_xml(pcmk__output_t *out, va_list args)
|
||
|
+{
|
||
|
+ char *type = va_arg(args, char *);
|
||
|
+ char *name = va_arg(args, char *);
|
||
|
+ char *id = va_arg(args, char *);
|
||
|
+
|
||
|
+ xmlNodePtr node = pcmk__output_create_xml_node(out, "node");
|
||
|
+ xmlSetProp(node, (pcmkXmlStr) "type", (pcmkXmlStr) (type ? type : "member"));
|
||
|
+ xmlSetProp(node, (pcmkXmlStr) "name", (pcmkXmlStr) crm_str(name));
|
||
|
+ xmlSetProp(node, (pcmkXmlStr) "id", (pcmkXmlStr) crm_str(id));
|
||
|
+
|
||
|
+ return pcmk_rc_ok;
|
||
|
+}
|
||
|
+
|
||
|
static pcmk__message_entry_t fmt_functions[] = {
|
||
|
{ "colocations-list", "default", colocations_list },
|
||
|
{ "colocations-list", "xml", colocations_list_xml },
|
||
|
@@ -364,6 +532,15 @@ static pcmk__message_entry_t fmt_functions[] = {
|
||
|
{ "locations-list", "xml", locations_list_xml },
|
||
|
{ "stacks-constraints", "default", stacks_and_constraints },
|
||
|
{ "stacks-constraints", "xml", stacks_and_constraints_xml },
|
||
|
+ { "health", "default", health_text },
|
||
|
+ { "health", "xml", health_xml },
|
||
|
+ { "pacemakerd-health", "default", pacemakerd_health_text },
|
||
|
+ { "pacemakerd-health", "xml", pacemakerd_health_xml },
|
||
|
+ { "dc", "default", dc_text },
|
||
|
+ { "dc", "xml", dc_xml },
|
||
|
+ { "crmadmin-node-list", "default", crmadmin_node_list },
|
||
|
+ { "crmadmin-node", "default", crmadmin_node_text },
|
||
|
+ { "crmadmin-node", "xml", crmadmin_node_xml },
|
||
|
|
||
|
{ NULL, NULL, NULL }
|
||
|
};
|
||
|
diff --git a/tools/Makefile.am b/tools/Makefile.am
|
||
|
index a278fa3..de64c93 100644
|
||
|
--- a/tools/Makefile.am
|
||
|
+++ b/tools/Makefile.am
|
||
|
@@ -69,7 +69,8 @@ MAN8DEPS = crm_attribute
|
||
|
crmadmin_SOURCES = crmadmin.c
|
||
|
crmadmin_LDADD = $(top_builddir)/lib/pengine/libpe_status.la \
|
||
|
$(top_builddir)/lib/cib/libcib.la \
|
||
|
- $(top_builddir)/lib/common/libcrmcommon.la
|
||
|
+ $(top_builddir)/lib/common/libcrmcommon.la \
|
||
|
+ $(top_builddir)/lib/pacemaker/libpacemaker.la
|
||
|
|
||
|
crm_error_SOURCES = crm_error.c
|
||
|
crm_error_LDADD = $(top_builddir)/lib/common/libcrmcommon.la
|
||
|
diff --git a/tools/crmadmin.c b/tools/crmadmin.c
|
||
|
index ec902df..2d9d663 100644
|
||
|
--- a/tools/crmadmin.c
|
||
|
+++ b/tools/crmadmin.c
|
||
|
@@ -16,32 +16,13 @@
|
||
|
#include <glib.h> // gboolean, GMainLoop, etc.
|
||
|
#include <libxml/tree.h> // xmlNode
|
||
|
|
||
|
-#include <crm/crm.h>
|
||
|
-#include <crm/cib.h>
|
||
|
-#include <crm/msg_xml.h>
|
||
|
+#include <pacemaker-internal.h>
|
||
|
+
|
||
|
#include <crm/common/cmdline_internal.h>
|
||
|
#include <crm/common/output_internal.h>
|
||
|
-#include <crm/common/xml.h>
|
||
|
-#include <crm/common/iso8601.h>
|
||
|
-#include <crm/common/ipc_controld.h>
|
||
|
-#include <crm/common/ipc_pacemakerd.h>
|
||
|
-#include <crm/common/mainloop.h>
|
||
|
|
||
|
#define SUMMARY "query and manage the Pacemaker controller"
|
||
|
|
||
|
-#define DEFAULT_MESSAGE_TIMEOUT_MS 30000
|
||
|
-
|
||
|
-static guint message_timer_id = 0;
|
||
|
-static guint message_timeout_ms = DEFAULT_MESSAGE_TIMEOUT_MS;
|
||
|
-static GMainLoop *mainloop = NULL;
|
||
|
-
|
||
|
-bool need_controld_api = true;
|
||
|
-
|
||
|
-bool do_work(pcmk_ipc_api_t *api);
|
||
|
-static char *ipc_name = NULL;
|
||
|
-
|
||
|
-gboolean admin_message_timeout(gpointer data);
|
||
|
-
|
||
|
static enum {
|
||
|
cmd_none,
|
||
|
cmd_shutdown,
|
||
|
@@ -52,17 +33,17 @@ static enum {
|
||
|
cmd_pacemakerd_health,
|
||
|
} command = cmd_none;
|
||
|
|
||
|
-static gboolean BE_VERBOSE = FALSE;
|
||
|
-static gboolean BASH_EXPORT = FALSE;
|
||
|
-static char *dest_node = NULL;
|
||
|
-static crm_exit_t exit_code = CRM_EX_OK;
|
||
|
-pcmk__output_t *out = NULL;
|
||
|
-
|
||
|
-
|
||
|
struct {
|
||
|
gboolean health;
|
||
|
gint timeout;
|
||
|
-} options;
|
||
|
+ char *dest_node;
|
||
|
+ char *ipc_name;
|
||
|
+ gboolean BASH_EXPORT;
|
||
|
+} options = {
|
||
|
+ .dest_node = NULL,
|
||
|
+ .ipc_name = NULL,
|
||
|
+ .BASH_EXPORT = FALSE
|
||
|
+};
|
||
|
|
||
|
gboolean command_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
|
||
|
|
||
|
@@ -112,11 +93,11 @@ static GOptionEntry additional_options[] = {
|
||
|
"\n operation failed",
|
||
|
NULL
|
||
|
},
|
||
|
- { "bash-export", 'B', 0, G_OPTION_ARG_NONE, &BASH_EXPORT,
|
||
|
+ { "bash-export", 'B', 0, G_OPTION_ARG_NONE, &options.BASH_EXPORT,
|
||
|
"Display nodes as shell commands of the form 'export uname=uuid'"
|
||
|
"\n (valid with -N/--nodes)",
|
||
|
},
|
||
|
- { "ipc-name", 'i', 0, G_OPTION_ARG_STRING, &ipc_name,
|
||
|
+ { "ipc-name", 'i', 0, G_OPTION_ARG_STRING, &options.ipc_name,
|
||
|
"Name to use for ipc instead of 'crmadmin' (with -P/--pacemakerd).",
|
||
|
NULL
|
||
|
},
|
||
|
@@ -154,478 +135,21 @@ command_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError
|
||
|
}
|
||
|
|
||
|
if (optarg) {
|
||
|
- if (dest_node != NULL) {
|
||
|
- free(dest_node);
|
||
|
+ if (options.dest_node != NULL) {
|
||
|
+ free(options.dest_node);
|
||
|
}
|
||
|
- dest_node = strdup(optarg);
|
||
|
+ options.dest_node = strdup(optarg);
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
-PCMK__OUTPUT_ARGS("health", "const char *", "const char *", "const char *", "const char *")
|
||
|
-static int
|
||
|
-health_text(pcmk__output_t *out, va_list args)
|
||
|
-{
|
||
|
- const char *sys_from = va_arg(args, const char *);
|
||
|
- const char *host_from = va_arg(args, const char *);
|
||
|
- const char *fsa_state = va_arg(args, const char *);
|
||
|
- const char *result = va_arg(args, const char *);
|
||
|
-
|
||
|
- if (!out->is_quiet(out)) {
|
||
|
- out->info(out, "Status of %s@%s: %s (%s)", crm_str(sys_from),
|
||
|
- crm_str(host_from), crm_str(fsa_state), crm_str(result));
|
||
|
- } else if (fsa_state != NULL) {
|
||
|
- out->info(out, "%s", fsa_state);
|
||
|
- }
|
||
|
-
|
||
|
- return pcmk_rc_ok;
|
||
|
-}
|
||
|
-
|
||
|
-PCMK__OUTPUT_ARGS("health", "const char *", "const char *", "const char *", "const char *")
|
||
|
-static int
|
||
|
-health_xml(pcmk__output_t *out, va_list args)
|
||
|
-{
|
||
|
- const char *sys_from = va_arg(args, const char *);
|
||
|
- const char *host_from = va_arg(args, const char *);
|
||
|
- const char *fsa_state = va_arg(args, const char *);
|
||
|
- const char *result = va_arg(args, const char *);
|
||
|
-
|
||
|
- xmlNodePtr node = pcmk__output_create_xml_node(out, crm_str(sys_from));
|
||
|
- xmlSetProp(node, (pcmkXmlStr) "node_name", (pcmkXmlStr) crm_str(host_from));
|
||
|
- xmlSetProp(node, (pcmkXmlStr) "state", (pcmkXmlStr) crm_str(fsa_state));
|
||
|
- xmlSetProp(node, (pcmkXmlStr) "result", (pcmkXmlStr) crm_str(result));
|
||
|
-
|
||
|
- return pcmk_rc_ok;
|
||
|
-}
|
||
|
-
|
||
|
-PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *", "const char *", "const char *")
|
||
|
-static int
|
||
|
-pacemakerd_health_text(pcmk__output_t *out, va_list args)
|
||
|
-{
|
||
|
- const char *sys_from = va_arg(args, const char *);
|
||
|
- const char *state = va_arg(args, const char *);
|
||
|
- const char *last_updated = va_arg(args, const char *);
|
||
|
-
|
||
|
- if (!out->is_quiet(out)) {
|
||
|
- out->info(out, "Status of %s: '%s' %s %s", crm_str(sys_from),
|
||
|
- crm_str(state), (!pcmk__str_empty(last_updated))?
|
||
|
- "last updated":"", crm_str(last_updated));
|
||
|
- } else {
|
||
|
- out->info(out, "%s", crm_str(state));
|
||
|
- }
|
||
|
-
|
||
|
- return pcmk_rc_ok;
|
||
|
-}
|
||
|
-
|
||
|
-PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *", "const char *", "const char *")
|
||
|
-static int
|
||
|
-pacemakerd_health_xml(pcmk__output_t *out, va_list args)
|
||
|
-{
|
||
|
- const char *sys_from = va_arg(args, const char *);
|
||
|
- const char *state = va_arg(args, const char *);
|
||
|
- const char *last_updated = va_arg(args, const char *);
|
||
|
-
|
||
|
-
|
||
|
- xmlNodePtr node = pcmk__output_create_xml_node(out, crm_str(sys_from));
|
||
|
- xmlSetProp(node, (pcmkXmlStr) "state", (pcmkXmlStr) crm_str(state));
|
||
|
- xmlSetProp(node, (pcmkXmlStr) "last_updated", (pcmkXmlStr) crm_str(last_updated));
|
||
|
-
|
||
|
- return pcmk_rc_ok;
|
||
|
-}
|
||
|
-
|
||
|
-PCMK__OUTPUT_ARGS("dc", "const char *")
|
||
|
-static int
|
||
|
-dc_text(pcmk__output_t *out, va_list args)
|
||
|
-{
|
||
|
- const char *dc = va_arg(args, const char *);
|
||
|
-
|
||
|
- if (!out->is_quiet(out)) {
|
||
|
- out->info(out, "Designated Controller is: %s", crm_str(dc));
|
||
|
- } else if (dc != NULL) {
|
||
|
- out->info(out, "%s", dc);
|
||
|
- }
|
||
|
-
|
||
|
- return pcmk_rc_ok;
|
||
|
-}
|
||
|
-
|
||
|
-PCMK__OUTPUT_ARGS("dc", "const char *")
|
||
|
-static int
|
||
|
-dc_xml(pcmk__output_t *out, va_list args)
|
||
|
-{
|
||
|
- const char *dc = va_arg(args, const char *);
|
||
|
-
|
||
|
- xmlNodePtr node = pcmk__output_create_xml_node(out, "dc");
|
||
|
- xmlSetProp(node, (pcmkXmlStr) "node_name", (pcmkXmlStr) crm_str(dc));
|
||
|
-
|
||
|
- return pcmk_rc_ok;
|
||
|
-}
|
||
|
-
|
||
|
-
|
||
|
-PCMK__OUTPUT_ARGS("crmadmin-node-list", "struct xmlNode *")
|
||
|
-static int
|
||
|
-crmadmin_node_list(pcmk__output_t *out, va_list args)
|
||
|
-{
|
||
|
- xmlNode *xml_node = va_arg(args, xmlNode *);
|
||
|
- int found = 0;
|
||
|
- xmlNode *node = NULL;
|
||
|
- xmlNode *nodes = get_object_root(XML_CIB_TAG_NODES, xml_node);
|
||
|
-
|
||
|
- out->begin_list(out, NULL, NULL, "nodes");
|
||
|
-
|
||
|
- for (node = first_named_child(nodes, XML_CIB_TAG_NODE); node != NULL;
|
||
|
- node = crm_next_same_xml(node)) {
|
||
|
- const char *node_type = BASH_EXPORT ? NULL :
|
||
|
- crm_element_value(node, XML_ATTR_TYPE);
|
||
|
- out->message(out, "crmadmin-node", node_type,
|
||
|
- crm_str(crm_element_value(node, XML_ATTR_UNAME)),
|
||
|
- crm_str(crm_element_value(node, XML_ATTR_ID)));
|
||
|
-
|
||
|
- found++;
|
||
|
- }
|
||
|
- // @TODO List Pacemaker Remote nodes that don't have a <node> entry
|
||
|
-
|
||
|
- out->end_list(out);
|
||
|
-
|
||
|
- if (found == 0) {
|
||
|
- out->info(out, "No nodes configured");
|
||
|
- }
|
||
|
-
|
||
|
- return pcmk_rc_ok;
|
||
|
-}
|
||
|
-
|
||
|
-PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *", "const char *")
|
||
|
-static int
|
||
|
-crmadmin_node_text(pcmk__output_t *out, va_list args)
|
||
|
-{
|
||
|
- const char *type = va_arg(args, const char *);
|
||
|
- const char *name = va_arg(args, const char *);
|
||
|
- const char *id = va_arg(args, const char *);
|
||
|
-
|
||
|
- if (BASH_EXPORT) {
|
||
|
- out->info(out, "export %s=%s", crm_str(name), crm_str(id));
|
||
|
- } else {
|
||
|
- out->info(out, "%s node: %s (%s)", type ? type : "member",
|
||
|
- crm_str(name), crm_str(id));
|
||
|
- }
|
||
|
-
|
||
|
- return pcmk_rc_ok;
|
||
|
-}
|
||
|
-
|
||
|
-PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *", "const char *")
|
||
|
-static int
|
||
|
-crmadmin_node_xml(pcmk__output_t *out, va_list args)
|
||
|
-{
|
||
|
- const char *type = va_arg(args, const char *);
|
||
|
- const char *name = va_arg(args, const char *);
|
||
|
- const char *id = va_arg(args, const char *);
|
||
|
-
|
||
|
- xmlNodePtr node = pcmk__output_create_xml_node(out, "node");
|
||
|
- xmlSetProp(node, (pcmkXmlStr) "type", (pcmkXmlStr) (type ? type : "member"));
|
||
|
- xmlSetProp(node, (pcmkXmlStr) "name", (pcmkXmlStr) crm_str(name));
|
||
|
- xmlSetProp(node, (pcmkXmlStr) "id", (pcmkXmlStr) crm_str(id));
|
||
|
-
|
||
|
- return pcmk_rc_ok;
|
||
|
-}
|
||
|
-
|
||
|
-static pcmk__message_entry_t fmt_functions[] = {
|
||
|
- {"health", "default", health_text },
|
||
|
- {"health", "xml", health_xml },
|
||
|
- {"pacemakerd-health", "default", pacemakerd_health_text },
|
||
|
- {"pacemakerd-health", "xml", pacemakerd_health_xml },
|
||
|
- {"dc", "default", dc_text },
|
||
|
- {"dc", "xml", dc_xml },
|
||
|
- {"crmadmin-node-list", "default", crmadmin_node_list },
|
||
|
- {"crmadmin-node", "default", crmadmin_node_text },
|
||
|
- {"crmadmin-node", "xml", crmadmin_node_xml },
|
||
|
-
|
||
|
- { NULL, NULL, NULL }
|
||
|
-};
|
||
|
-
|
||
|
static pcmk__supported_format_t formats[] = {
|
||
|
PCMK__SUPPORTED_FORMAT_TEXT,
|
||
|
PCMK__SUPPORTED_FORMAT_XML,
|
||
|
{ NULL, NULL, NULL }
|
||
|
};
|
||
|
|
||
|
-static void
|
||
|
-start_main_loop()
|
||
|
-{
|
||
|
- exit_code = CRM_EX_DISCONNECT; // For unexpected disconnects
|
||
|
- mainloop = g_main_loop_new(NULL, FALSE);
|
||
|
- message_timer_id = g_timeout_add(message_timeout_ms,
|
||
|
- admin_message_timeout, NULL);
|
||
|
- g_main_loop_run(mainloop);
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-quit_main_loop(crm_exit_t ec)
|
||
|
-{
|
||
|
- exit_code = ec;
|
||
|
- if (mainloop != NULL) {
|
||
|
- GMainLoop *mloop = mainloop;
|
||
|
-
|
||
|
- mainloop = NULL; // Don't re-enter this block
|
||
|
- pcmk_quit_main_loop(mloop, 10);
|
||
|
- g_main_loop_unref(mloop);
|
||
|
- }
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-event_done(pcmk_ipc_api_t *api)
|
||
|
-{
|
||
|
- pcmk_disconnect_ipc(api);
|
||
|
- quit_main_loop(exit_code);
|
||
|
-}
|
||
|
-
|
||
|
-static pcmk_controld_api_reply_t *
|
||
|
-controld_event_reply(pcmk_ipc_api_t *controld_api, enum pcmk_ipc_event event_type, crm_exit_t status, void *event_data)
|
||
|
-{
|
||
|
- pcmk_controld_api_reply_t *reply = event_data;
|
||
|
-
|
||
|
- switch (event_type) {
|
||
|
- case pcmk_ipc_event_disconnect:
|
||
|
- if (exit_code == CRM_EX_DISCONNECT) { // Unexpected
|
||
|
- out->err(out, "error: Lost connection to controller");
|
||
|
- }
|
||
|
- event_done(controld_api);
|
||
|
- return NULL;
|
||
|
-
|
||
|
- case pcmk_ipc_event_reply:
|
||
|
- break;
|
||
|
-
|
||
|
- default:
|
||
|
- return NULL;
|
||
|
- }
|
||
|
-
|
||
|
- if (message_timer_id != 0) {
|
||
|
- g_source_remove(message_timer_id);
|
||
|
- message_timer_id = 0;
|
||
|
- }
|
||
|
-
|
||
|
- if (status != CRM_EX_OK) {
|
||
|
- out->err(out, "error: Bad reply from controller: %s",
|
||
|
- crm_exit_str(status));
|
||
|
- exit_code = status;
|
||
|
- event_done(controld_api);
|
||
|
- return NULL;
|
||
|
- }
|
||
|
-
|
||
|
- if (reply->reply_type != pcmk_controld_reply_ping) {
|
||
|
- out->err(out, "error: Unknown reply type %d from controller",
|
||
|
- reply->reply_type);
|
||
|
- event_done(controld_api);
|
||
|
- return NULL;
|
||
|
- }
|
||
|
-
|
||
|
- return reply;
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-controller_status_event_cb(pcmk_ipc_api_t *controld_api,
|
||
|
- enum pcmk_ipc_event event_type, crm_exit_t status,
|
||
|
- void *event_data, void *user_data)
|
||
|
-{
|
||
|
- pcmk_controld_api_reply_t *reply = controld_event_reply(controld_api,
|
||
|
- event_type, status, event_data);
|
||
|
-
|
||
|
- if (reply != NULL) {
|
||
|
- out->message(out, "health",
|
||
|
- reply->data.ping.sys_from,
|
||
|
- reply->host_from,
|
||
|
- reply->data.ping.fsa_state,
|
||
|
- reply->data.ping.result);
|
||
|
- exit_code = CRM_EX_OK;
|
||
|
- }
|
||
|
-
|
||
|
- event_done(controld_api);
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-designated_controller_event_cb(pcmk_ipc_api_t *controld_api,
|
||
|
- enum pcmk_ipc_event event_type, crm_exit_t status,
|
||
|
- void *event_data, void *user_data)
|
||
|
-{
|
||
|
- pcmk_controld_api_reply_t *reply = controld_event_reply(controld_api,
|
||
|
- event_type, status, event_data);
|
||
|
-
|
||
|
- if (reply != NULL) {
|
||
|
- out->message(out, "dc", reply->host_from);
|
||
|
- exit_code = CRM_EX_OK;
|
||
|
- }
|
||
|
-
|
||
|
- event_done(controld_api);
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-pacemakerd_event_cb(pcmk_ipc_api_t *pacemakerd_api,
|
||
|
- enum pcmk_ipc_event event_type, crm_exit_t status,
|
||
|
- void *event_data, void *user_data)
|
||
|
-{
|
||
|
- pcmk_pacemakerd_api_reply_t *reply = event_data;
|
||
|
-
|
||
|
- crm_time_t *crm_when = crm_time_new(NULL);
|
||
|
- char *pinged_buf = NULL;
|
||
|
-
|
||
|
- switch (event_type) {
|
||
|
- case pcmk_ipc_event_disconnect:
|
||
|
- if (exit_code == CRM_EX_DISCONNECT) { // Unexpected
|
||
|
- out->err(out, "error: Lost connection to pacemakerd");
|
||
|
- }
|
||
|
- event_done(pacemakerd_api);
|
||
|
- return;
|
||
|
-
|
||
|
- case pcmk_ipc_event_reply:
|
||
|
- break;
|
||
|
-
|
||
|
- default:
|
||
|
- return;
|
||
|
- }
|
||
|
-
|
||
|
- if (message_timer_id != 0) {
|
||
|
- g_source_remove(message_timer_id);
|
||
|
- message_timer_id = 0;
|
||
|
- }
|
||
|
-
|
||
|
- if (status != CRM_EX_OK) {
|
||
|
- out->err(out, "error: Bad reply from pacemakerd: %s",
|
||
|
- crm_exit_str(status));
|
||
|
- event_done(pacemakerd_api);
|
||
|
- return;
|
||
|
- }
|
||
|
-
|
||
|
- if (reply->reply_type != pcmk_pacemakerd_reply_ping) {
|
||
|
- out->err(out, "error: Unknown reply type %d from pacemakerd",
|
||
|
- reply->reply_type);
|
||
|
- event_done(pacemakerd_api);
|
||
|
- return;
|
||
|
- }
|
||
|
-
|
||
|
- // Parse desired information from reply
|
||
|
- crm_time_set_timet(crm_when, &reply->data.ping.last_good);
|
||
|
- pinged_buf = crm_time_as_string(crm_when,
|
||
|
- crm_time_log_date | crm_time_log_timeofday |
|
||
|
- crm_time_log_with_timezone);
|
||
|
-
|
||
|
- out->message(out, "pacemakerd-health",
|
||
|
- reply->data.ping.sys_from,
|
||
|
- (reply->data.ping.status == pcmk_rc_ok)?
|
||
|
- pcmk_pacemakerd_api_daemon_state_enum2text(
|
||
|
- reply->data.ping.state):"query failed",
|
||
|
- (reply->data.ping.status == pcmk_rc_ok)?pinged_buf:"");
|
||
|
- exit_code = CRM_EX_OK;
|
||
|
- free(pinged_buf);
|
||
|
-
|
||
|
- event_done(pacemakerd_api);
|
||
|
-}
|
||
|
-
|
||
|
-static pcmk_ipc_api_t *
|
||
|
-ipc_connect(enum pcmk_ipc_server server, pcmk_ipc_callback_t cb)
|
||
|
-{
|
||
|
- int rc;
|
||
|
- pcmk_ipc_api_t *api = NULL;
|
||
|
-
|
||
|
- rc = pcmk_new_ipc_api(&api, server);
|
||
|
- if (api == NULL) {
|
||
|
- out->err(out, "error: Could not connect to %s: %s",
|
||
|
- (server == pcmk_ipc_controld) ? "controller" : "pacemakerd",
|
||
|
- pcmk_rc_str(rc));
|
||
|
- exit_code = pcmk_rc2exitc(rc);
|
||
|
- return NULL;
|
||
|
- }
|
||
|
- pcmk_register_ipc_callback(api, cb, NULL);
|
||
|
- rc = pcmk_connect_ipc(api, pcmk_ipc_dispatch_main);
|
||
|
- if (rc != pcmk_rc_ok) {
|
||
|
- out->err(out, "error: Could not connect to %s: %s",
|
||
|
- (server == pcmk_ipc_controld) ? "controller" : "pacemakerd",
|
||
|
- pcmk_rc_str(rc));
|
||
|
- exit_code = pcmk_rc2exitc(rc);
|
||
|
- return NULL;
|
||
|
- }
|
||
|
-
|
||
|
- return api;
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-pcmk__controller_status()
|
||
|
-{
|
||
|
- pcmk_ipc_api_t *controld_api = ipc_connect(pcmk_ipc_controld, controller_status_event_cb);
|
||
|
-
|
||
|
- if (controld_api != NULL) {
|
||
|
- int rc = pcmk_controld_api_ping(controld_api, dest_node);
|
||
|
- if (rc != pcmk_rc_ok) {
|
||
|
- out->err(out, "error: Command failed: %s", pcmk_rc_str(rc));
|
||
|
- exit_code = pcmk_rc2exitc(rc);
|
||
|
- }
|
||
|
-
|
||
|
- start_main_loop();
|
||
|
-
|
||
|
- pcmk_free_ipc_api(controld_api);
|
||
|
- }
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-pcmk__designated_controller()
|
||
|
-{
|
||
|
- pcmk_ipc_api_t *controld_api = ipc_connect(pcmk_ipc_controld, designated_controller_event_cb);
|
||
|
-
|
||
|
- if (controld_api != NULL) {
|
||
|
- int rc = pcmk_controld_api_ping(controld_api, dest_node);
|
||
|
- if (rc != pcmk_rc_ok) {
|
||
|
- out->err(out, "error: Command failed: %s", pcmk_rc_str(rc));
|
||
|
- exit_code = pcmk_rc2exitc(rc);
|
||
|
- }
|
||
|
-
|
||
|
- start_main_loop();
|
||
|
-
|
||
|
- pcmk_free_ipc_api(controld_api);
|
||
|
- }
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-pcmk__pacemakerd_status()
|
||
|
-{
|
||
|
- pcmk_ipc_api_t *pacemakerd_api = ipc_connect(pcmk_ipc_pacemakerd, pacemakerd_event_cb);
|
||
|
-
|
||
|
- if (pacemakerd_api != NULL) {
|
||
|
- int rc = pcmk_pacemakerd_api_ping(pacemakerd_api, ipc_name);
|
||
|
- if (rc != pcmk_rc_ok) {
|
||
|
- out->err(out, "error: Command failed: %s", pcmk_rc_str(rc));
|
||
|
- exit_code = pcmk_rc2exitc(rc);
|
||
|
- }
|
||
|
-
|
||
|
- start_main_loop();
|
||
|
-
|
||
|
- pcmk_free_ipc_api(pacemakerd_api);
|
||
|
- }
|
||
|
-}
|
||
|
-
|
||
|
-// \return Standard Pacemaker return code
|
||
|
-static int
|
||
|
-pcmk__list_nodes()
|
||
|
-{
|
||
|
- cib_t *the_cib = cib_new();
|
||
|
- xmlNode *output = NULL;
|
||
|
- int rc;
|
||
|
-
|
||
|
- if (the_cib == NULL) {
|
||
|
- return ENOMEM;
|
||
|
- }
|
||
|
- rc = the_cib->cmds->signon(the_cib, crm_system_name, cib_command);
|
||
|
- if (rc != pcmk_ok) {
|
||
|
- return pcmk_legacy2rc(rc);
|
||
|
- }
|
||
|
-
|
||
|
- rc = the_cib->cmds->query(the_cib, NULL, &output,
|
||
|
- cib_scope_local | cib_sync_call);
|
||
|
- if (rc == pcmk_ok) {
|
||
|
- out->message(out, "crmadmin-node-list", output);
|
||
|
- free_xml(output);
|
||
|
- }
|
||
|
- the_cib->cmds->signoff(the_cib);
|
||
|
- return pcmk_legacy2rc(rc);
|
||
|
-}
|
||
|
-
|
||
|
static GOptionContext *
|
||
|
build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
|
||
|
GOptionContext *context = NULL;
|
||
|
@@ -658,8 +182,10 @@ build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
|
||
|
int
|
||
|
main(int argc, char **argv)
|
||
|
{
|
||
|
- int argerr = 0;
|
||
|
+ pcmk__output_t *out = NULL;
|
||
|
+ crm_exit_t exit_code = CRM_EX_OK;
|
||
|
int rc;
|
||
|
+ int argerr = 0;
|
||
|
pcmk_ipc_api_t *controld_api = NULL;
|
||
|
|
||
|
pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
|
||
|
@@ -683,7 +209,6 @@ main(int argc, char **argv)
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < args->verbosity; i++) {
|
||
|
- BE_VERBOSE = TRUE;
|
||
|
crm_bump_log_level(argc, argv);
|
||
|
}
|
||
|
|
||
|
@@ -697,7 +222,7 @@ main(int argc, char **argv)
|
||
|
|
||
|
out->quiet = args->quiet;
|
||
|
|
||
|
- pcmk__register_messages(out, fmt_functions);
|
||
|
+ pcmk__register_lib_messages(out);
|
||
|
|
||
|
if (!pcmk__force_args(context, &error, "%s --xml-simple-list --xml-substitute", g_get_prgname())) {
|
||
|
goto done;
|
||
|
@@ -708,13 +233,6 @@ main(int argc, char **argv)
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
- if (options.timeout) {
|
||
|
- message_timeout_ms = (guint) options.timeout;
|
||
|
- if (message_timeout_ms < 1) {
|
||
|
- message_timeout_ms = DEFAULT_MESSAGE_TIMEOUT_MS;
|
||
|
- }
|
||
|
- }
|
||
|
-
|
||
|
if (options.health) {
|
||
|
out->err(out, "Cluster-wide health option not supported");
|
||
|
++argerr;
|
||
|
@@ -740,43 +258,31 @@ main(int argc, char **argv)
|
||
|
|
||
|
switch (command) {
|
||
|
case cmd_health:
|
||
|
- pcmk__controller_status();
|
||
|
- goto done;
|
||
|
+ rc = pcmk__controller_status(out, options.dest_node, options.timeout);
|
||
|
+ break;
|
||
|
case cmd_pacemakerd_health:
|
||
|
- pcmk__pacemakerd_status();
|
||
|
- goto done;
|
||
|
+ rc = pcmk__pacemakerd_status(out, options.ipc_name, options.timeout);
|
||
|
+ break;
|
||
|
case cmd_list_nodes:
|
||
|
- rc = pcmk__list_nodes();
|
||
|
- // might need movink
|
||
|
- if (rc != pcmk_rc_ok) {
|
||
|
- out->err(out, "error: Command failed: %s", pcmk_rc_str(rc));
|
||
|
- exit_code = pcmk_rc2exitc(rc);
|
||
|
- }
|
||
|
+ rc = pcmk__list_nodes(out, options.BASH_EXPORT);
|
||
|
break;
|
||
|
case cmd_whois_dc:
|
||
|
- pcmk__designated_controller();
|
||
|
- goto done;
|
||
|
- default:
|
||
|
- rc = pcmk_new_ipc_api(&controld_api, pcmk_ipc_controld);
|
||
|
- if (controld_api == NULL) {
|
||
|
- out->err(out, "error: Could not connect to controller: %s",
|
||
|
- pcmk_rc_str(rc));
|
||
|
- exit_code = pcmk_rc2exitc(rc);
|
||
|
- goto done;
|
||
|
- }
|
||
|
- rc = pcmk_connect_ipc(controld_api, pcmk_ipc_dispatch_main);
|
||
|
- if (rc != pcmk_rc_ok) {
|
||
|
- out->err(out, "error: Could not connect to controller: %s",
|
||
|
- pcmk_rc_str(rc));
|
||
|
- exit_code = pcmk_rc2exitc(rc);
|
||
|
- goto done;
|
||
|
- }
|
||
|
+ rc = pcmk__designated_controller(out, options.timeout);
|
||
|
+ break;
|
||
|
+ case cmd_shutdown:
|
||
|
+ rc = pcmk__shutdown_controller(out, options.dest_node);
|
||
|
+ break;
|
||
|
+ case cmd_elect_dc:
|
||
|
+ rc = pcmk__start_election(out);
|
||
|
+ break;
|
||
|
+ case cmd_none:
|
||
|
+ rc = pcmk_rc_error;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
- if (do_work(controld_api?controld_api:NULL)) {
|
||
|
- // A reply is needed from controller, so run main loop to get it
|
||
|
- start_main_loop();
|
||
|
+ if (rc != pcmk_rc_ok) {
|
||
|
+ out->err(out, "error: Command failed: %s", pcmk_rc_str(rc));
|
||
|
+ exit_code = pcmk_rc2exitc(rc);
|
||
|
}
|
||
|
|
||
|
done:
|
||
|
@@ -787,10 +293,6 @@ done:
|
||
|
pcmk_free_ipc_api(capi);
|
||
|
}
|
||
|
|
||
|
- if (mainloop != NULL) {
|
||
|
- g_main_loop_unref(mainloop);
|
||
|
- mainloop = NULL;
|
||
|
- }
|
||
|
g_strfreev(processed_args);
|
||
|
g_clear_error(&error);
|
||
|
pcmk__free_arg_context(context);
|
||
|
@@ -801,43 +303,3 @@ done:
|
||
|
return crm_exit(exit_code);
|
||
|
|
||
|
}
|
||
|
-
|
||
|
-// \return True if reply from controller is needed
|
||
|
-bool
|
||
|
-do_work(pcmk_ipc_api_t *api)
|
||
|
-{
|
||
|
- bool need_reply = false;
|
||
|
- int rc = pcmk_rc_ok;
|
||
|
-
|
||
|
- switch (command) {
|
||
|
- case cmd_shutdown:
|
||
|
- rc = pcmk_controld_api_shutdown(api, dest_node);
|
||
|
- break;
|
||
|
-
|
||
|
- case cmd_elect_dc:
|
||
|
- rc = pcmk_controld_api_start_election(api);
|
||
|
- break;
|
||
|
-
|
||
|
- case cmd_none: // not actually possible here
|
||
|
- break;
|
||
|
-
|
||
|
- default:
|
||
|
- break;
|
||
|
- }
|
||
|
- if (rc != pcmk_rc_ok) {
|
||
|
- out->err(out, "error: Command failed: %s", pcmk_rc_str(rc));
|
||
|
- exit_code = pcmk_rc2exitc(rc);
|
||
|
- }
|
||
|
- return need_reply;
|
||
|
-}
|
||
|
-
|
||
|
-gboolean
|
||
|
-admin_message_timeout(gpointer data)
|
||
|
-{
|
||
|
- out->err(out,
|
||
|
- "error: No reply received from controller before timeout (%dms)",
|
||
|
- message_timeout_ms);
|
||
|
- message_timer_id = 0;
|
||
|
- quit_main_loop(CRM_EX_TIMEOUT);
|
||
|
- return FALSE; // Tells glib to remove source
|
||
|
-}
|
||
|
--
|
||
|
1.8.3.1
|
||
|
|