Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F2825472
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
28 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 8b83f26f1c..deb5c4a167 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,156 +1,157 @@
#
# Copyright 2004-2019 the Pacemaker project contributors
#
# The version control history for this file may have further details.
#
# This source code is licensed under the GNU General Public License version 2
# or later (GPLv2+) WITHOUT ANY WARRANTY.
#
include $(top_srcdir)/Makefile.common
if BUILD_SYSTEMD
systemdsystemunit_DATA = crm_mon.service
endif
noinst_HEADERS = crm_mon.h crm_resource.h
pcmkdir = $(datadir)/$(PACKAGE)
pcmk_DATA = report.common report.collector
sbin_SCRIPTS = crm_report crm_standby crm_master crm_failcount
if BUILD_CIBSECRETS
sbin_SCRIPTS += cibsecret
endif
EXTRA_DIST = crm_mon.sysconfig \
crm_mon.8.inc \
+ crm_node.8.inc \
stonith_admin.8.inc
sbin_PROGRAMS = attrd_updater \
cibadmin \
crmadmin \
crm_simulate \
crm_attribute \
crm_diff \
crm_error \
crm_mon \
crm_node \
crm_resource \
crm_rule \
crm_shadow \
crm_verify \
crm_ticket \
iso8601 \
stonith_admin
if BUILD_SERVICELOG
sbin_PROGRAMS += notifyServicelogEvent
endif
if BUILD_OPENIPMI_SERVICELOG
sbin_PROGRAMS += ipmiservicelogd
endif
## SOURCES
# A few tools are just thin wrappers around crm_attribute.
# This makes their help get updated when crm_attribute changes
# (see Makefile.common).
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
crm_error_SOURCES = crm_error.c
crm_error_LDADD = $(top_builddir)/lib/common/libcrmcommon.la
cibadmin_SOURCES = cibadmin.c
cibadmin_LDADD = $(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/common/libcrmcommon.la
crm_shadow_SOURCES = crm_shadow.c
crm_shadow_LDADD = $(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/common/libcrmcommon.la
crm_node_SOURCES = crm_node.c
crm_node_LDADD = $(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/common/libcrmcommon.la
crm_simulate_SOURCES = crm_simulate.c
crm_simulate_LDADD = $(top_builddir)/lib/pengine/libpe_status.la \
$(top_builddir)/lib/pacemaker/libpacemaker.la \
$(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/common/libcrmcommon.la
crm_diff_SOURCES = crm_diff.c
crm_diff_LDADD = $(top_builddir)/lib/common/libcrmcommon.la
crm_mon_SOURCES = crm_mon.c crm_mon_curses.c crm_mon_print.c crm_mon_runtime.c
crm_mon_LDADD = $(top_builddir)/lib/pengine/libpe_status.la \
$(top_builddir)/lib/fencing/libstonithd.la \
$(top_builddir)/lib/pacemaker/libpacemaker.la \
$(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/common/libcrmcommon.la \
$(CURSESLIBS)
crm_verify_SOURCES = crm_verify.c
crm_verify_LDADD = $(top_builddir)/lib/pengine/libpe_status.la \
$(top_builddir)/lib/pacemaker/libpacemaker.la \
$(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/common/libcrmcommon.la
crm_attribute_SOURCES = crm_attribute.c
crm_attribute_LDADD = $(top_builddir)/lib/cluster/libcrmcluster.la \
$(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/common/libcrmcommon.la
crm_resource_SOURCES = crm_resource.c crm_resource_ban.c crm_resource_runtime.c crm_resource_print.c
crm_resource_LDADD = $(top_builddir)/lib/pengine/libpe_rules.la \
$(top_builddir)/lib/fencing/libstonithd.la \
$(top_builddir)/lib/lrmd/liblrmd.la \
$(top_builddir)/lib/services/libcrmservice.la \
$(top_builddir)/lib/pengine/libpe_status.la \
$(top_builddir)/lib/pacemaker/libpacemaker.la \
$(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/common/libcrmcommon.la
crm_rule_SOURCES = crm_rule.c
crm_rule_LDADD = $(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/pengine/libpe_rules.la \
$(top_builddir)/lib/pengine/libpe_status.la \
$(top_builddir)/lib/common/libcrmcommon.la
iso8601_SOURCES = iso8601.c
iso8601_LDADD = $(top_builddir)/lib/common/libcrmcommon.la
attrd_updater_SOURCES = attrd_updater.c
attrd_updater_LDADD = $(top_builddir)/lib/common/libcrmcommon.la
crm_ticket_SOURCES = crm_ticket.c
crm_ticket_LDADD = $(top_builddir)/lib/pengine/libpe_rules.la \
$(top_builddir)/lib/pengine/libpe_status.la \
$(top_builddir)/lib/pacemaker/libpacemaker.la \
$(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/common/libcrmcommon.la
stonith_admin_SOURCES = stonith_admin.c
stonith_admin_LDADD = $(top_builddir)/lib/common/libcrmcommon.la \
$(top_builddir)/lib/cib/libcib.la \
$(top_builddir)/lib/pengine/libpe_status.la \
$(top_builddir)/lib/fencing/libstonithd.la
if BUILD_SERVICELOG
notifyServicelogEvent_SOURCES = notifyServicelogEvent.c
notifyServicelogEvent_CFLAGS = $(SERVICELOG_CFLAGS)
notifyServicelogEvent_LDADD = $(top_builddir)/lib/common/libcrmcommon.la $(SERVICELOG_LIBS)
endif
if BUILD_OPENIPMI_SERVICELOG
ipmiservicelogd_SOURCES = ipmiservicelogd.c
ipmiservicelogd_CFLAGS = $(OPENIPMI_SERVICELOG_CFLAGS) $(SERVICELOG_CFLAGS)
ipmiservicelogd_LDFLAGS = $(top_builddir)/lib/common/libcrmcommon.la $(OPENIPMI_SERVICELOG_LIBS) $(SERVICELOG_LIBS)
endif
CLEANFILES = $(man8_MANS)
diff --git a/tools/crm_node.8.inc b/tools/crm_node.8.inc
new file mode 100644
index 0000000000..84cef12190
--- /dev/null
+++ b/tools/crm_node.8.inc
@@ -0,0 +1,5 @@
+[synopsis]
+crm_node [command] [options]
+
+/level node information/
+.SH OPTIONS
diff --git a/tools/crm_node.c b/tools/crm_node.c
index ffbde6407a..b74c1533a0 100644
--- a/tools/crm_node.c
+++ b/tools/crm_node.c
@@ -1,590 +1,661 @@
/*
* Copyright 2004-2019 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <crm/crm.h>
+#include <crm/common/cmdline_internal.h>
#include <crm/common/mainloop.h>
#include <crm/msg_xml.h>
#include <crm/cib.h>
#include <crm/attrd.h>
-static int command = 0;
+#define SUMMARY "crm_node - Tool for displaying low-level node information"
+
+struct {
+ gboolean corosync;
+ gboolean dangerous_cmd;
+ gboolean force_flag;
+ char command;
+ int nodeid;
+ const char *target_uname;
+} options = {
+ .command = '\0',
+ .force_flag = FALSE
+};
+
+gboolean command_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
+gboolean name_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
+gboolean remove_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
+
static char *pid_s = NULL;
static GMainLoop *mainloop = NULL;
static crm_exit_t exit_code = CRM_EX_OK;
-static struct crm_option long_options[] = {
- /* Top-level Options */
- {"help", 0, 0, '?', "\tThis text"},
- {"version", 0, 0, '$', "\tVersion information" },
- {"verbose", 0, 0, 'V', "\tIncrease debug output"},
- {"quiet", 0, 0, 'Q', "\tEssential output only"},
-
- {"-spacer-", 1, 0, '-', "\nCommands:"},
- {"name", 0, 0, 'n', "\tDisplay the name used by the cluster for this node"},
- {"name-for-id", 1, 0, 'N', "\tDisplay the name used by the cluster for the node with the specified id"},
- {"quorum", 0, 0, 'q', "\tDisplay a 1 if our partition has quorum, 0 if not"},
- {"list", 0, 0, 'l', "\tDisplay all known members (past and present) of this cluster"},
- {"partition", 0, 0, 'p', "Display the members of this partition"},
- {"cluster-id", 0, 0, 'i', "Display this node's cluster id"},
- {"remove", 1, 0, 'R', "(Advanced) Remove the (stopped) node with the specified name from Pacemaker's configuration and caches"},
- {"-spacer-", 1, 0, '-', "(the node must already have been removed from the underlying cluster stack configuration)"},
-
- {"-spacer-", 1, 0, '-', "\nAdditional Options:"},
- {"force", 0, 0, 'f'},
+#define INDENT " "
+
+static GOptionEntry command_entries[] = {
+ { "cluster-id", 'i', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
+ "Display this node's cluster id",
+ NULL },
+ { "list", 'l', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
+ "Display all known members (past and present) of this cluster",
+ NULL },
+ { "name", 'n', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
+ "Display the name used by the cluster for this node",
+ NULL },
+ { "partition", 'p', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
+ "Display the members of this partition",
+ NULL },
+ { "quorum", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
+ "Display a 1 if our partition has quorum, 0 if not",
+ NULL },
+ { "name-for-id", 'N', 0, G_OPTION_ARG_CALLBACK, name_cb,
+ "Display the name used by the cluster for the node with the specified ID",
+ "ID" },
+ { "remove", 'R', 0, G_OPTION_ARG_CALLBACK, remove_cb,
+ "(Advanced) Remove the (stopped) node with the specified name from Pacemaker's\n"
+ INDENT "configuration and caches (the node must already have been removed from\n"
+ INDENT "the underlying cluster stack configuration",
+ "NAME" },
+
+ { NULL }
+};
+
+static GOptionEntry addl_entries[] = {
+ { "force", 'f', 0, G_OPTION_ARG_NONE, &options.force_flag,
+ NULL,
+ NULL },
#if SUPPORT_COROSYNC
- { "corosync", 0, 0, 'C', NULL, pcmk_option_hidden },
+ /* Unused and deprecated */
+ { "corosync", 'C', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &options.corosync,
+ NULL,
+ NULL },
#endif
// @TODO add timeout option for when IPC replies are needed
- {0, 0, 0, 0}
+ { NULL }
};
+gboolean
+command_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
+ if (safe_str_eq("-i", option_name) || safe_str_eq("--cluster-id", option_name)) {
+ options.command = 'i';
+ } else if (safe_str_eq("-l", option_name) || safe_str_eq("--list", option_name)) {
+ options.command = 'l';
+ } else if (safe_str_eq("-n", option_name) || safe_str_eq("--name", option_name)) {
+ options.command = 'n';
+ } else if (safe_str_eq("-p", option_name) || safe_str_eq("--partition", option_name)) {
+ options.command = 'p';
+ } else if (safe_str_eq("-q", option_name) || safe_str_eq("--quorum", option_name)) {
+ options.command = 'q';
+ } else {
+ g_set_error(error, G_OPTION_ERROR, CRM_EX_INVALID_PARAM, "Unknown param passed to command_cb: %s\n", option_name);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+name_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
+ options.command = 'N';
+ options.nodeid = crm_parse_int(optarg, NULL);
+ return TRUE;
+}
+
+gboolean
+remove_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
+ if (optarg == NULL) {
+ crm_err("-R option requires an argument");
+ g_set_error(error, G_OPTION_ERROR, CRM_EX_INVALID_PARAM, "-R option requires an argument");
+ return FALSE;
+ }
+
+ options.command = 'R';
+ options.dangerous_cmd = TRUE;
+ options.target_uname = optarg;
+ return TRUE;
+}
+
/*!
* \internal
* \brief Exit crm_node
* Clean up memory, and either quit mainloop (if running) or exit
*
* \param[in] value Exit status
*/
static void
crm_node_exit(crm_exit_t value)
{
if (pid_s) {
free(pid_s);
pid_s = NULL;
}
exit_code = value;
if (mainloop && g_main_loop_is_running(mainloop)) {
g_main_loop_quit(mainloop);
} else {
crm_exit(exit_code);
}
}
static void
exit_disconnect(gpointer user_data)
{
fprintf(stderr, "error: Lost connection to cluster\n");
crm_node_exit(CRM_EX_DISCONNECT);
}
typedef int (*ipc_dispatch_fn) (const char *buffer, ssize_t length,
gpointer userdata);
static crm_ipc_t *
new_mainloop_for_ipc(const char *system, ipc_dispatch_fn dispatch)
{
mainloop_io_t *source = NULL;
crm_ipc_t *ipc = NULL;
struct ipc_client_callbacks ipc_callbacks = {
.dispatch = dispatch,
.destroy = exit_disconnect
};
mainloop = g_main_loop_new(NULL, FALSE);
source = mainloop_add_ipc_client(system, G_PRIORITY_DEFAULT, 0,
NULL, &ipc_callbacks);
ipc = mainloop_get_ipc_client(source);
if (ipc == NULL) {
fprintf(stderr,
"error: Could not connect to cluster (is it running?)\n");
crm_node_exit(CRM_EX_DISCONNECT);
}
return ipc;
}
static void
run_mainloop_and_exit()
{
g_main_loop_run(mainloop);
g_main_loop_unref(mainloop);
mainloop = NULL;
crm_node_exit(exit_code);
}
static int
send_controller_hello(crm_ipc_t *controller)
{
xmlNode *hello = NULL;
int rc;
pid_s = crm_getpid_s();
hello = create_hello_message(pid_s, crm_system_name, "1", "0");
rc = crm_ipc_send(controller, hello, 0, 0, NULL);
free_xml(hello);
return (rc < 0)? rc : 0;
}
static int
send_node_info_request(crm_ipc_t *controller, uint32_t nodeid)
{
xmlNode *ping = NULL;
int rc;
ping = create_request(CRM_OP_NODE_INFO, NULL, NULL, CRM_SYSTEM_CRMD,
crm_system_name, pid_s);
if (nodeid > 0) {
crm_xml_add_int(ping, XML_ATTR_ID, nodeid);
}
rc = crm_ipc_send(controller, ping, 0, 0, NULL);
free_xml(ping);
return (rc < 0)? rc : 0;
}
static int
dispatch_controller(const char *buffer, ssize_t length, gpointer userdata)
{
xmlNode *message = string2xml(buffer);
xmlNode *data = NULL;
const char *value = NULL;
if (message == NULL) {
fprintf(stderr, "error: Could not understand reply from controller\n");
crm_node_exit(CRM_EX_PROTOCOL);
return 0;
}
crm_log_xml_trace(message, "controller reply");
exit_code = CRM_EX_PROTOCOL;
// Validate reply
value = crm_element_value(message, F_CRM_MSG_TYPE);
if (safe_str_neq(value, XML_ATTR_RESPONSE)) {
fprintf(stderr, "error: Message from controller was not a reply\n");
goto done;
}
value = crm_element_value(message, XML_ATTR_REFERENCE);
if (value == NULL) {
fprintf(stderr, "error: Controller reply did not specify original message\n");
goto done;
}
data = get_message_xml(message, F_CRM_DATA);
if (data == NULL) {
fprintf(stderr, "error: Controller reply did not contain any data\n");
goto done;
}
- switch (command) {
+ switch (options.command) {
case 'i':
value = crm_element_value(data, XML_ATTR_ID);
if (value == NULL) {
fprintf(stderr, "error: Controller reply did not contain node ID\n");
} else {
printf("%s\n", value);
exit_code = CRM_EX_OK;
}
break;
case 'n':
case 'N':
value = crm_element_value(data, XML_ATTR_UNAME);
if (value == NULL) {
fprintf(stderr, "Node is not known to cluster\n");
exit_code = CRM_EX_NOHOST;
} else {
printf("%s\n", value);
exit_code = CRM_EX_OK;
}
break;
case 'q':
value = crm_element_value(data, XML_ATTR_HAVE_QUORUM);
if (value == NULL) {
fprintf(stderr, "error: Controller reply did not contain quorum status\n");
} else {
bool quorum = crm_is_true(value);
printf("%d\n", quorum);
exit_code = quorum? CRM_EX_OK : CRM_EX_QUORUM;
}
break;
default:
fprintf(stderr, "internal error: Controller reply not expected\n");
exit_code = CRM_EX_SOFTWARE;
break;
}
done:
free_xml(message);
crm_node_exit(exit_code);
return 0;
}
static void
run_controller_mainloop(uint32_t nodeid)
{
crm_ipc_t *controller = NULL;
int rc;
controller = new_mainloop_for_ipc(CRM_SYSTEM_CRMD, dispatch_controller);
rc = send_controller_hello(controller);
if (rc < 0) {
fprintf(stderr, "error: Could not register with controller: %s\n",
pcmk_strerror(rc));
crm_node_exit(crm_errno2exit(rc));
}
rc = send_node_info_request(controller, nodeid);
if (rc < 0) {
fprintf(stderr, "error: Could not ping controller: %s\n",
pcmk_strerror(rc));
crm_node_exit(crm_errno2exit(rc));
}
// Run main loop to get controller reply via dispatch_controller()
run_mainloop_and_exit();
}
static void
print_node_name()
{
// Check environment first (i.e. when called by resource agent)
const char *name = getenv("OCF_RESKEY_" CRM_META "_" XML_LRM_ATTR_TARGET);
if (name != NULL) {
printf("%s\n", name);
crm_node_exit(CRM_EX_OK);
} else {
// Otherwise ask the controller
run_controller_mainloop(0);
}
}
static int
cib_remove_node(long id, const char *name)
{
int rc;
cib_t *cib = NULL;
xmlNode *node = NULL;
xmlNode *node_state = NULL;
crm_trace("Removing %s from the CIB", name);
if(name == NULL && id == 0) {
return -ENOTUNIQ;
}
node = create_xml_node(NULL, XML_CIB_TAG_NODE);
node_state = create_xml_node(NULL, XML_CIB_TAG_STATE);
crm_xml_add(node, XML_ATTR_UNAME, name);
crm_xml_add(node_state, XML_ATTR_UNAME, name);
if (id > 0) {
crm_xml_set_id(node, "%ld", id);
crm_xml_add(node_state, XML_ATTR_ID, ID(node));
}
cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
rc = cib->cmds->remove(cib, XML_CIB_TAG_NODES, node, cib_sync_call);
if (rc != pcmk_ok) {
printf("Could not remove %s[%ld] from " XML_CIB_TAG_NODES ": %s",
name, id, pcmk_strerror(rc));
}
rc = cib->cmds->remove(cib, XML_CIB_TAG_STATUS, node_state, cib_sync_call);
if (rc != pcmk_ok) {
printf("Could not remove %s[%ld] from " XML_CIB_TAG_STATUS ": %s",
name, id, pcmk_strerror(rc));
}
cib->cmds->signoff(cib);
cib_delete(cib);
return rc;
}
static int
tools_remove_node_cache(const char *node_name, long nodeid, const char *target)
{
int rc = -1;
crm_ipc_t *conn = crm_ipc_new(target, 0);
xmlNode *cmd = NULL;
if (!conn) {
return -ENOTCONN;
}
if (!crm_ipc_connect(conn)) {
crm_perror(LOG_ERR, "Connection to %s failed", target);
crm_ipc_destroy(conn);
return -ENOTCONN;
}
if(safe_str_eq(target, CRM_SYSTEM_CRMD)) {
// The controller requires a hello message before sending a request
rc = send_controller_hello(conn);
if (rc < 0) {
fprintf(stderr, "error: Could not register with controller: %s\n",
pcmk_strerror(rc));
return rc;
}
}
crm_trace("Removing %s[%ld] from the %s membership cache",
node_name, nodeid, target);
if(safe_str_eq(target, T_ATTRD)) {
cmd = create_xml_node(NULL, __FUNCTION__);
crm_xml_add(cmd, F_TYPE, T_ATTRD);
crm_xml_add(cmd, F_ORIG, crm_system_name);
crm_xml_add(cmd, F_ATTRD_TASK, ATTRD_OP_PEER_REMOVE);
crm_xml_add(cmd, F_ATTRD_HOST, node_name);
if (nodeid > 0) {
crm_xml_add_int(cmd, F_ATTRD_HOST_ID, (int) nodeid);
}
} else {
cmd = create_request(CRM_OP_RM_NODE_CACHE,
NULL, NULL, target, crm_system_name, pid_s);
if (nodeid > 0) {
crm_xml_set_id(cmd, "%ld", nodeid);
}
crm_xml_add(cmd, XML_ATTR_UNAME, node_name);
}
rc = crm_ipc_send(conn, cmd, 0, 0, NULL);
crm_debug("%s peer cache cleanup for %s (%ld): %d",
target, node_name, nodeid, rc);
if (rc > 0) {
rc = cib_remove_node(nodeid, node_name);
}
if (conn) {
crm_ipc_close(conn);
crm_ipc_destroy(conn);
}
free_xml(cmd);
return rc > 0 ? 0 : rc;
}
static void
remove_node(const char *target_uname)
{
int d = 0;
long nodeid = 0;
const char *node_name = NULL;
char *endptr = NULL;
const char *daemons[] = {
CRM_SYSTEM_CRMD,
"stonith-ng",
T_ATTRD,
CRM_SYSTEM_MCP,
};
// Check whether node was specified by name or numeric ID
errno = 0;
nodeid = strtol(target_uname, &endptr, 10);
if ((errno != 0) || (endptr == target_uname) || (*endptr != '\0')
|| (nodeid <= 0)) {
// It's not a positive integer, so assume it's a node name
nodeid = 0;
node_name = target_uname;
}
for (d = 0; d < DIMOF(daemons); d++) {
if (tools_remove_node_cache(node_name, nodeid, daemons[d])) {
crm_err("Failed to connect to %s to remove node '%s'",
daemons[d], target_uname);
crm_node_exit(CRM_EX_ERROR);
return;
}
}
crm_node_exit(CRM_EX_OK);
}
static gint
compare_node_xml(gconstpointer a, gconstpointer b)
{
const char *a_name = crm_element_value((xmlNode*) a, "uname");
const char *b_name = crm_element_value((xmlNode*) b, "uname");
return strcmp((a_name? a_name : ""), (b_name? b_name : ""));
}
static int
node_mcp_dispatch(const char *buffer, ssize_t length, gpointer userdata)
{
GList *nodes = NULL;
xmlNode *node = NULL;
xmlNode *msg = string2xml(buffer);
const char *uname;
const char *state;
if (msg == NULL) {
fprintf(stderr, "error: Could not understand pacemakerd response\n");
crm_node_exit(CRM_EX_PROTOCOL);
return 0;
}
crm_log_xml_trace(msg, "message");
for (node = __xml_first_child(msg); node != NULL; node = __xml_next(node)) {
nodes = g_list_insert_sorted(nodes, node, compare_node_xml);
}
for (GList *iter = nodes; iter; iter = iter->next) {
node = (xmlNode*) iter->data;
uname = crm_element_value(node, "uname");
state = crm_element_value(node, "state");
- if (command == 'l') {
+ if (options.command == 'l') {
int id = 0;
crm_element_value_int(node, "id", &id);
printf("%d %s %s\n", id, (uname? uname : ""), (state? state : ""));
// This is CRM_NODE_MEMBER but we don't want to include cluster header
- } else if ((command == 'p') && safe_str_eq(state, "member")) {
+ } else if ((options.command == 'p') && safe_str_eq(state, "member")) {
printf("%s ", (uname? uname : ""));
}
}
- if (command == 'p') {
+ if (options.command == 'p') {
fprintf(stdout, "\n");
}
free_xml(msg);
crm_node_exit(CRM_EX_OK);
return 0;
}
static void
run_pacemakerd_mainloop()
{
crm_ipc_t *ipc = NULL;
xmlNode *poke = NULL;
ipc = new_mainloop_for_ipc(CRM_SYSTEM_MCP, node_mcp_dispatch);
// Sending anything will get us a list of nodes
poke = create_xml_node(NULL, "poke");
crm_ipc_send(ipc, poke, 0, 0, NULL);
free_xml(poke);
// Handle reply via node_mcp_dispatch()
run_mainloop_and_exit();
}
+static GOptionContext *
+build_arg_context(pcmk__common_args_t *args) {
+ GOptionContext *context = NULL;
+
+ GOptionEntry extra_prog_entries[] = {
+ { "quiet", 'Q', 0, G_OPTION_ARG_NONE, &(args->quiet),
+ "Be less descriptive in output.",
+ NULL },
+
+ { NULL }
+ };
+
+ context = pcmk__build_arg_context(args, NULL);
+
+ /* Add the -q option, which cannot be part of the globally supported options
+ * because some tools use that flag for something else.
+ */
+ pcmk__add_main_args(context, extra_prog_entries);
+
+ pcmk__add_arg_group(context, "commands", "Commands:",
+ "Show command help", command_entries);
+ pcmk__add_arg_group(context, "additional", "Additional Options:",
+ "Show additional options", addl_entries);
+ return context;
+}
+
int
main(int argc, char **argv)
{
- int flag = 0;
- int argerr = 0;
- uint32_t nodeid = 0;
- gboolean force_flag = FALSE;
- gboolean dangerous_cmd = FALSE;
- int option_index = 0;
- const char *target_uname = NULL;
+ pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
+
+ GError *error = NULL;
+ GOptionContext *context = NULL;
+ gchar **processed_args = NULL;
+
+ context = build_arg_context(args);
crm_log_cli_init("crm_node");
- crm_set_options(NULL, "command [options]", long_options,
- "Tool for displaying low-level node information");
-
- while (flag >= 0) {
- flag = crm_get_option(argc, argv, &option_index);
- switch (flag) {
- case -1:
- break;
- case 'V':
- crm_bump_log_level(argc, argv);
- break;
- case '$':
- case '?':
- crm_help(flag, CRM_EX_OK);
- break;
- case 'Q':
- // currently unused
- break;
- case 'C':
- // unused and deprecated
- break;
- case 'f':
- force_flag = TRUE;
- break;
- case 'R':
- command = flag;
- dangerous_cmd = TRUE;
- target_uname = optarg;
- if (optarg == NULL) {
- ++argerr;
- }
- break;
- case 'N':
- command = flag;
- nodeid = crm_parse_int(optarg, NULL);
- break;
- case 'p':
- case 'q':
- case 'i':
- case 'l':
- case 'n':
- command = flag;
- break;
- default:
- ++argerr;
- break;
- }
+
+ processed_args = pcmk__cmdline_preproc(argc, argv, "NR");
+
+ if (!g_option_context_parse_strv(context, &processed_args, &error)) {
+ fprintf(stderr, "%s: %s\n", g_get_prgname(), error->message);
+ }
+
+ for (int i = 0; i < args->verbosity; i++) {
+ crm_bump_log_level(argc, argv);
}
- if (optind > argc) {
- ++argerr;
+ if (args->version) {
+ /* FIXME: When crm_node is converted to use formatted output, this can go. */
+ crm_help('v', CRM_EX_USAGE);
}
- if (argerr) {
- crm_help('?', CRM_EX_USAGE);
+ if (optind > argc || options.command == 0) {
+ fprintf(stderr, "%s", g_option_context_get_help(context, TRUE, NULL));
+ exit_code = CRM_EX_USAGE;
+ goto done;
}
- if (dangerous_cmd && force_flag == FALSE) {
+ if (options.dangerous_cmd && options.force_flag == FALSE) {
fprintf(stderr, "The supplied command is considered dangerous."
" To prevent accidental destruction of the cluster,"
" the --force flag is required in order to proceed.\n");
- crm_node_exit(CRM_EX_USAGE);
+ exit_code = CRM_EX_USAGE;
+ goto done;
}
- switch (command) {
+ switch (options.command) {
case 'n':
print_node_name();
break;
case 'R':
- remove_node(target_uname);
+ remove_node(options.target_uname);
break;
case 'i':
case 'q':
case 'N':
- run_controller_mainloop(nodeid);
+ run_controller_mainloop(options.nodeid);
break;
case 'l':
case 'p':
run_pacemakerd_mainloop();
break;
default:
break;
}
- fprintf(stderr, "error: Must specify a command option\n");
- crm_node_exit(CRM_EX_USAGE);
- return CRM_EX_USAGE;
+done:
+ g_strfreev(processed_args);
+ g_option_context_free(context);
+ crm_node_exit(exit_code);
+ return exit_code;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Jan 25, 12:39 PM (13 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1319013
Default Alt Text
(28 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment