Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/attrd/legacy.c b/attrd/legacy.c
index aea43dbe65..4aae4c4ed1 100644
--- a/attrd/legacy.c
+++ b/attrd/legacy.c
@@ -1,898 +1,898 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <crm_internal.h>
#include <sys/param.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <crm/crm.h>
#include <crm/cib/internal.h>
#include <crm/msg_xml.h>
#include <crm/common/ipc.h>
#include <crm/common/ipcs.h>
#include <crm/cluster/internal.h>
#include <crm/common/mainloop.h>
#include <crm/common/xml.h>
#include <crm/attrd.h>
#define OPTARGS "hV"
#if SUPPORT_HEARTBEAT
ll_cluster_t *attrd_cluster_conn;
#endif
GMainLoop *mainloop = NULL;
char *attrd_uname = NULL;
char *attrd_uuid = NULL;
gboolean need_shutdown = FALSE;
GHashTable *attr_hash = NULL;
cib_t *cib_conn = NULL;
typedef struct attr_hash_entry_s {
char *uuid;
char *id;
char *set;
char *section;
char *value;
char *stored_value;
int timeout;
char *dampen;
guint timer_id;
char *user;
} attr_hash_entry_t;
void attrd_local_callback(xmlNode * msg);
gboolean attrd_timer_callback(void *user_data);
gboolean attrd_trigger_update(attr_hash_entry_t * hash_entry);
void attrd_perform_update(attr_hash_entry_t * hash_entry);
static void
free_hash_entry(gpointer data)
{
attr_hash_entry_t *entry = data;
if (entry == NULL) {
return;
}
free(entry->id);
free(entry->set);
free(entry->dampen);
free(entry->section);
free(entry->uuid);
free(entry->value);
free(entry->stored_value);
free(entry->user);
free(entry);
}
static int32_t
attrd_ipc_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
{
crm_trace("Connection %p", c);
if (need_shutdown) {
crm_info("Ignoring new client [%d] during shutdown", crm_ipcs_client_pid(c));
return -EPERM;
}
if (crm_client_new(c, uid, gid) == NULL) {
return -EIO;
}
return 0;
}
static void
attrd_ipc_created(qb_ipcs_connection_t * c)
{
crm_trace("Connection %p", c);
}
/* Exit code means? */
static int32_t
attrd_ipc_dispatch(qb_ipcs_connection_t * c, void *data, size_t size)
{
uint32_t id = 0;
uint32_t flags = 0;
crm_client_t *client = crm_client_get(c);
xmlNode *msg = crm_ipcs_recv(client, data, size, &id, &flags);
crm_ipcs_send_ack(client, id, flags, "ack", __FUNCTION__, __LINE__);
if (msg == NULL) {
crm_debug("No msg from %d (%p)", crm_ipcs_client_pid(c), c);
return 0;
}
#if ENABLE_ACL
CRM_ASSERT(client->user != NULL);
crm_acl_get_set_user(msg, F_ATTRD_USER, client->user);
#endif
crm_trace("Processing msg from %d (%p)", crm_ipcs_client_pid(c), c);
crm_log_xml_trace(msg, __FUNCTION__);
attrd_local_callback(msg);
free_xml(msg);
return 0;
}
/* Error code means? */
static int32_t
attrd_ipc_closed(qb_ipcs_connection_t * c)
{
crm_client_t *client = crm_client_get(c);
if (client == NULL) {
return 0;
}
crm_trace("Connection %p", c);
crm_client_destroy(client);
return 0;
}
static void
attrd_ipc_destroy(qb_ipcs_connection_t * c)
{
crm_trace("Connection %p", c);
attrd_ipc_closed(c);
}
struct qb_ipcs_service_handlers ipc_callbacks = {
.connection_accept = attrd_ipc_accept,
.connection_created = attrd_ipc_created,
.msg_process = attrd_ipc_dispatch,
.connection_closed = attrd_ipc_closed,
.connection_destroyed = attrd_ipc_destroy
};
static void
attrd_shutdown(int nsig)
{
need_shutdown = TRUE;
crm_info("Exiting");
if (mainloop != NULL && g_main_is_running(mainloop)) {
g_main_quit(mainloop);
} else {
crm_exit(pcmk_ok);
}
}
static void
usage(const char *cmd, int exit_status)
{
FILE *stream;
stream = exit_status ? stderr : stdout;
fprintf(stream, "usage: %s [-srkh] [-c configure file]\n", cmd);
/* fprintf(stream, "\t-d\tsets debug level\n"); */
/* fprintf(stream, "\t-s\tgets daemon status\n"); */
/* fprintf(stream, "\t-r\trestarts daemon\n"); */
/* fprintf(stream, "\t-k\tstops daemon\n"); */
/* fprintf(stream, "\t-h\thelp message\n"); */
fflush(stream);
crm_exit(exit_status);
}
static void
stop_attrd_timer(attr_hash_entry_t * hash_entry)
{
if (hash_entry != NULL && hash_entry->timer_id != 0) {
crm_trace("Stopping %s timer", hash_entry->id);
g_source_remove(hash_entry->timer_id);
hash_entry->timer_id = 0;
}
}
static void
log_hash_entry(int level, attr_hash_entry_t * entry, const char *text)
{
do_crm_log(level, "%s: Set: %s, Name: %s, Value: %s, Timeout: %s",
text, entry->section, entry->id, entry->value, entry->dampen);
}
static attr_hash_entry_t *
find_hash_entry(xmlNode * msg)
{
const char *value = NULL;
const char *attr = crm_element_value(msg, F_ATTRD_ATTRIBUTE);
attr_hash_entry_t *hash_entry = NULL;
if (attr == NULL) {
crm_info("Ignoring message with no attribute name");
return NULL;
}
hash_entry = g_hash_table_lookup(attr_hash, attr);
if (hash_entry == NULL) {
/* create one and add it */
crm_info("Creating hash entry for %s", attr);
hash_entry = calloc(1, sizeof(attr_hash_entry_t));
hash_entry->id = strdup(attr);
g_hash_table_insert(attr_hash, hash_entry->id, hash_entry);
hash_entry = g_hash_table_lookup(attr_hash, attr);
CRM_CHECK(hash_entry != NULL, return NULL);
}
value = crm_element_value(msg, F_ATTRD_SET);
if (value != NULL) {
free(hash_entry->set);
hash_entry->set = strdup(value);
crm_debug("\t%s->set: %s", attr, value);
}
value = crm_element_value(msg, F_ATTRD_SECTION);
if (value == NULL) {
value = XML_CIB_TAG_STATUS;
}
free(hash_entry->section);
hash_entry->section = strdup(value);
crm_trace("\t%s->section: %s", attr, value);
value = crm_element_value(msg, F_ATTRD_DAMPEN);
if (value != NULL) {
free(hash_entry->dampen);
hash_entry->dampen = strdup(value);
hash_entry->timeout = crm_get_msec(value);
crm_trace("\t%s->timeout: %s", attr, value);
}
#if ENABLE_ACL
free(hash_entry->user);
hash_entry->user = NULL;
value = crm_element_value(msg, F_ATTRD_USER);
if (value != NULL) {
hash_entry->user = strdup(value);
crm_trace("\t%s->user: %s", attr, value);
}
#endif
log_hash_entry(LOG_DEBUG_2, hash_entry, "Found (and updated) entry:");
return hash_entry;
}
#if SUPPORT_HEARTBEAT
static void
attrd_ha_connection_destroy(gpointer user_data)
{
crm_trace("Invoked");
if (need_shutdown) {
/* we signed out, so this is expected */
crm_info("Heartbeat disconnection complete");
return;
}
crm_crit("Lost connection to heartbeat service!");
if (mainloop != NULL && g_main_is_running(mainloop)) {
g_main_quit(mainloop);
return;
}
crm_exit(pcmk_ok);
}
static void
attrd_ha_callback(HA_Message * msg, void *private_data)
{
attr_hash_entry_t *hash_entry = NULL;
xmlNode *xml = convert_ha_message(NULL, msg, __FUNCTION__);
const char *from = crm_element_value(xml, F_ORIG);
const char *op = crm_element_value(xml, F_ATTRD_TASK);
const char *host = crm_element_value(xml, F_ATTRD_HOST);
const char *ignore = crm_element_value(xml, F_ATTRD_IGNORE_LOCALLY);
if (host != NULL && safe_str_eq(host, attrd_uname)) {
crm_info("Update relayed from %s", from);
attrd_local_callback(xml);
} else if (ignore == NULL || safe_str_neq(from, attrd_uname)) {
crm_info("%s message from %s", op, from);
hash_entry = find_hash_entry(xml);
stop_attrd_timer(hash_entry);
attrd_perform_update(hash_entry);
}
free_xml(xml);
}
#endif
#if SUPPORT_COROSYNC
static void
attrd_cs_dispatch(cpg_handle_t handle,
const struct cpg_name *groupName,
uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
{
uint32_t kind = 0;
xmlNode *xml = NULL;
const char *from = NULL;
char *data = pcmk_message_common_cs(handle, nodeid, pid, msg, &kind, &from);
if(data == NULL) {
return;
}
if (kind == crm_class_cluster) {
xml = string2xml(data);
if (xml == NULL) {
crm_err("Bad message received: '%.120s'", data);
}
}
if (xml != NULL) {
attr_hash_entry_t *hash_entry = NULL;
const char *op = crm_element_value(xml, F_ATTRD_TASK);
const char *host = crm_element_value(xml, F_ATTRD_HOST);
const char *ignore = crm_element_value(xml, F_ATTRD_IGNORE_LOCALLY);
/* crm_xml_add_int(xml, F_SEQ, wrapper->id); */
crm_xml_add(xml, F_ORIG, from);
if (host != NULL && safe_str_eq(host, attrd_uname)) {
crm_notice("Update relayed from %s", from);
attrd_local_callback(xml);
} else if (ignore == NULL || safe_str_neq(from, attrd_uname)) {
crm_trace("%s message from %s", op, from);
hash_entry = find_hash_entry(xml);
stop_attrd_timer(hash_entry);
attrd_perform_update(hash_entry);
}
free_xml(xml);
}
free(data);
}
static void
attrd_cs_destroy(gpointer unused)
{
if (need_shutdown) {
/* we signed out, so this is expected */
crm_info("Corosync disconnection complete");
return;
}
crm_crit("Lost connection to Corosync service!");
if (mainloop != NULL && g_main_is_running(mainloop)) {
g_main_quit(mainloop);
return;
}
crm_exit(EINVAL);
}
#endif
static void
attrd_cib_connection_destroy(gpointer user_data)
{
cib_t *conn = user_data;
conn->cmds->signoff(conn); /* Ensure IPC is cleaned up */
if (need_shutdown) {
crm_info("Connection to the CIB terminated...");
} else {
/* eventually this will trigger a reconnect, not a shutdown */
crm_err("Connection to the CIB terminated...");
crm_exit(ENOTCONN);
}
return;
}
static void
update_for_hash_entry(gpointer key, gpointer value, gpointer user_data)
{
attr_hash_entry_t *entry = value;
if (entry->value != NULL || entry->stored_value != NULL) {
attrd_timer_callback(value);
}
}
static void
local_update_for_hash_entry(gpointer key, gpointer value, gpointer user_data)
{
attr_hash_entry_t *entry = value;
if (entry->timer_id == 0) {
crm_trace("Performing local-only update after replace for %s", entry->id);
attrd_perform_update(entry);
/* } else {
* just let the timer expire and attrd_timer_callback() will do the right thing
*/
}
}
static void
do_cib_replaced(const char *event, xmlNode * msg)
{
crm_info("Updating all attributes after %s event", event);
g_hash_table_foreach(attr_hash, local_update_for_hash_entry, NULL);
}
static gboolean
cib_connect(void *user_data)
{
static int attempts = 1;
static int max_retry = 20;
gboolean was_err = FALSE;
static cib_t *local_conn = NULL;
if (local_conn == NULL) {
local_conn = cib_new();
}
if (was_err == FALSE) {
int rc = -ENOTCONN;
if (attempts < max_retry) {
crm_debug("CIB signon attempt %d", attempts);
rc = local_conn->cmds->signon(local_conn, T_ATTRD, cib_command);
}
if (rc != pcmk_ok && attempts > max_retry) {
crm_err("Signon to CIB failed: %s", pcmk_strerror(rc));
was_err = TRUE;
} else if (rc != pcmk_ok) {
attempts++;
return TRUE;
}
}
crm_info("Connected to the CIB after %d signon attempts", attempts);
if (was_err == FALSE) {
int rc = local_conn->cmds->set_connection_dnotify(local_conn, attrd_cib_connection_destroy);
if (rc != pcmk_ok) {
crm_err("Could not set dnotify callback");
was_err = TRUE;
}
}
if (was_err == FALSE) {
if (pcmk_ok !=
local_conn->cmds->add_notify_callback(local_conn, T_CIB_REPLACE_NOTIFY,
do_cib_replaced)) {
crm_err("Could not set CIB notification callback");
was_err = TRUE;
}
}
if (was_err) {
crm_err("Aborting startup");
crm_exit(DAEMON_RESPAWN_STOP);
}
cib_conn = local_conn;
crm_info("Sending full refresh now that we're connected to the cib");
g_hash_table_foreach(attr_hash, local_update_for_hash_entry, NULL);
return FALSE;
}
int
main(int argc, char **argv)
{
int flag = 0;
int argerr = 0;
crm_cluster_t cluster;
gboolean was_err = FALSE;
qb_ipcs_connection_t *c = NULL;
qb_ipcs_service_t *ipcs = NULL;
crm_log_init(T_ATTRD, LOG_NOTICE, TRUE, FALSE, argc, argv, FALSE);
mainloop_add_signal(SIGTERM, attrd_shutdown);
while ((flag = getopt(argc, argv, OPTARGS)) != EOF) {
switch (flag) {
case 'V':
crm_bump_log_level(argc, argv);
break;
case 'h': /* Help message */
usage(T_ATTRD, EX_OK);
break;
default:
++argerr;
break;
}
}
if (optind > argc) {
++argerr;
}
if (argerr) {
usage(T_ATTRD, EX_USAGE);
}
attr_hash = g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, free_hash_entry);
crm_info("Starting up");
if (was_err == FALSE) {
#if SUPPORT_COROSYNC
if (is_openais_cluster()) {
cluster.destroy = attrd_cs_destroy;
cluster.cpg.cpg_deliver_fn = attrd_cs_dispatch;
cluster.cpg.cpg_confchg_fn = pcmk_cpg_membership;
}
#endif
#if SUPPORT_HEARTBEAT
if (is_heartbeat_cluster()) {
cluster.hb_conn = NULL;
cluster.hb_dispatch = attrd_ha_callback;
cluster.destroy = attrd_ha_connection_destroy;
}
#endif
if (FALSE == crm_cluster_connect(&cluster)) {
crm_err("HA Signon failed");
was_err = TRUE;
}
attrd_uname = cluster.uname;
attrd_uuid = cluster.uuid;
#if SUPPORT_HEARTBEAT
attrd_cluster_conn = cluster.hb_conn;
#endif
}
crm_info("Cluster connection active");
if (was_err == FALSE) {
attrd_ipc_server_init(&ipcs, &ipc_callbacks);
}
crm_info("Accepting attribute updates");
mainloop = g_main_new(FALSE);
if (0 == g_timeout_add_full(G_PRIORITY_LOW + 1, 5000, cib_connect, NULL, NULL)) {
crm_info("Adding timer failed");
was_err = TRUE;
}
if (was_err) {
crm_err("Aborting startup");
return 100;
}
crm_notice("Starting mainloop...");
g_main_run(mainloop);
crm_notice("Exiting...");
#if SUPPORT_HEARTBEAT
if (is_heartbeat_cluster()) {
attrd_cluster_conn->llc_ops->signoff(attrd_cluster_conn, TRUE);
attrd_cluster_conn->llc_ops->delete(attrd_cluster_conn);
}
#endif
c = qb_ipcs_connection_first_get(ipcs);
while (c != NULL) {
qb_ipcs_connection_t *last = c;
c = qb_ipcs_connection_next_get(ipcs, last);
/* There really shouldn't be anyone connected at this point */
crm_notice("Disconnecting client %p, pid=%d...", last, crm_ipcs_client_pid(last));
qb_ipcs_disconnect(last);
qb_ipcs_connection_unref(last);
}
qb_ipcs_destroy(ipcs);
if (cib_conn) {
cib_conn->cmds->signoff(cib_conn);
cib_delete(cib_conn);
}
g_hash_table_destroy(attr_hash);
free(attrd_uuid);
return crm_exit(pcmk_ok);
}
struct attrd_callback_s {
char *attr;
char *value;
};
static void
attrd_cib_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
{
attr_hash_entry_t *hash_entry = NULL;
struct attrd_callback_s *data = user_data;
if (data->value == NULL && rc == -ENXIO) {
rc = pcmk_ok;
} else if (call_id < 0) {
crm_warn("Update %s=%s failed: %s", data->attr, data->value, pcmk_strerror(call_id));
goto cleanup;
}
switch (rc) {
case pcmk_ok:
crm_debug("Update %d for %s=%s passed", call_id, data->attr, data->value);
hash_entry = g_hash_table_lookup(attr_hash, data->attr);
if (hash_entry) {
free(hash_entry->stored_value);
hash_entry->stored_value = NULL;
if (data->value != NULL) {
hash_entry->stored_value = strdup(data->value);
}
}
break;
case -pcmk_err_diff_failed: /* When an attr changes while the CIB is syncing */
case -ETIME: /* When an attr changes while there is a DC election */
case -ENXIO: /* When an attr changes while the CIB is syncing a
* newer config from a node that just came up
*/
crm_warn("Update %d for %s=%s failed: %s",
call_id, data->attr, data->value, pcmk_strerror(rc));
break;
default:
crm_err("Update %d for %s=%s failed: %s",
call_id, data->attr, data->value, pcmk_strerror(rc));
}
cleanup:
free(data->value);
free(data->attr);
free(data);
}
void
attrd_perform_update(attr_hash_entry_t * hash_entry)
{
int rc = pcmk_ok;
struct attrd_callback_s *data = NULL;
const char *user_name = NULL;
if (hash_entry == NULL) {
return;
} else if (cib_conn == NULL) {
crm_info("Delaying operation %s=%s: cib not connected", hash_entry->id,
crm_str(hash_entry->value));
return;
}
#if ENABLE_ACL
if (hash_entry->user) {
user_name = hash_entry->user;
crm_trace("Performing request from user '%s'", hash_entry->user);
}
#endif
if (hash_entry->value == NULL) {
/* delete the attr */
rc = delete_attr_delegate(cib_conn, cib_none, hash_entry->section, attrd_uuid, NULL,
hash_entry->set, hash_entry->uuid, hash_entry->id, NULL, FALSE,
user_name);
if (rc >= 0 && hash_entry->stored_value) {
crm_notice("Sent delete %d: node=%s, attr=%s, id=%s, set=%s, section=%s",
rc, attrd_uuid, hash_entry->id,
hash_entry->uuid ? hash_entry->uuid : "<n/a>", hash_entry->set,
hash_entry->section);
} else if (rc < 0 && rc != -ENXIO) {
crm_notice
("Delete operation failed: node=%s, attr=%s, id=%s, set=%s, section=%s: %s (%d)",
attrd_uuid, hash_entry->id, hash_entry->uuid ? hash_entry->uuid : "<n/a>",
hash_entry->set, hash_entry->section, pcmk_strerror(rc), rc);
} else {
crm_trace("Sent delete %d: node=%s, attr=%s, id=%s, set=%s, section=%s",
rc, attrd_uuid, hash_entry->id,
hash_entry->uuid ? hash_entry->uuid : "<n/a>", hash_entry->set,
hash_entry->section);
}
} else {
/* send update */
rc = update_attr_delegate(cib_conn, cib_none, hash_entry->section,
attrd_uuid, NULL, hash_entry->set, hash_entry->uuid,
hash_entry->id, hash_entry->value, FALSE, user_name, NULL);
if (rc < 0) {
crm_notice("Sent update %s=%s failed: %s", hash_entry->id, hash_entry->value,
pcmk_strerror(rc));
}
if (safe_str_neq(hash_entry->value, hash_entry->stored_value) || rc < 0) {
crm_notice("Sent update %d: %s=%s", rc, hash_entry->id, hash_entry->value);
} else {
crm_trace("Sent update %d: %s=%s", rc, hash_entry->id, hash_entry->value);
}
}
data = calloc(1, sizeof(struct attrd_callback_s));
data->attr = strdup(hash_entry->id);
if (hash_entry->value != NULL) {
data->value = strdup(hash_entry->value);
}
cib_conn->cmds->register_callback(cib_conn, rc, 120, FALSE, data, "attrd_cib_callback",
attrd_cib_callback);
return;
}
void
attrd_local_callback(xmlNode * msg)
{
static int plus_plus_len = 5;
attr_hash_entry_t *hash_entry = NULL;
const char *from = crm_element_value(msg, F_ORIG);
const char *op = crm_element_value(msg, F_ATTRD_TASK);
const char *attr = crm_element_value(msg, F_ATTRD_ATTRIBUTE);
const char *value = crm_element_value(msg, F_ATTRD_VALUE);
const char *host = crm_element_value(msg, F_ATTRD_HOST);
if (safe_str_eq(op, "refresh")) {
crm_notice("Sending full refresh (origin=%s)", from);
g_hash_table_foreach(attr_hash, update_for_hash_entry, NULL);
return;
- } else if(safe_str_eq(op, "peer-remove")) {
+ } else if (safe_str_eq(op, ATTRD_OP_PEER_REMOVE)) {
/* The legacy code didn't understand this command - swallow silently */
return;
}
if (host != NULL && safe_str_neq(host, attrd_uname)) {
send_cluster_message(crm_get_peer(0, host), crm_msg_attrd, msg, FALSE);
return;
}
crm_debug("%s message from %s: %s=%s", op, from, attr, crm_str(value));
hash_entry = find_hash_entry(msg);
if (hash_entry == NULL) {
return;
}
if (hash_entry->uuid == NULL) {
const char *key = crm_element_value(msg, F_ATTRD_KEY);
if (key) {
hash_entry->uuid = strdup(key);
}
}
crm_debug("Supplied: %s, Current: %s, Stored: %s",
value, hash_entry->value, hash_entry->stored_value);
if (safe_str_eq(value, hash_entry->value)
&& safe_str_eq(value, hash_entry->stored_value)) {
crm_trace("Ignoring non-change");
return;
} else if (value) {
int offset = 1;
int int_value = 0;
int value_len = strlen(value);
if (value_len < (plus_plus_len + 2)
|| value[plus_plus_len] != '+'
|| (value[plus_plus_len + 1] != '+' && value[plus_plus_len + 1] != '=')) {
goto set_unexpanded;
}
int_value = char2score(hash_entry->value);
if (value[plus_plus_len + 1] != '+') {
const char *offset_s = value + (plus_plus_len + 2);
offset = char2score(offset_s);
}
int_value += offset;
if (int_value > INFINITY) {
int_value = INFINITY;
}
crm_info("Expanded %s=%s to %d", attr, value, int_value);
crm_xml_add_int(msg, F_ATTRD_VALUE, int_value);
value = crm_element_value(msg, F_ATTRD_VALUE);
}
set_unexpanded:
if (safe_str_eq(value, hash_entry->value) && hash_entry->timer_id) {
/* We're already waiting to set this value */
return;
}
free(hash_entry->value);
hash_entry->value = NULL;
if (value != NULL) {
hash_entry->value = strdup(value);
crm_debug("New value of %s is %s", attr, value);
}
stop_attrd_timer(hash_entry);
if (hash_entry->timeout > 0) {
hash_entry->timer_id = g_timeout_add(hash_entry->timeout, attrd_timer_callback, hash_entry);
} else {
attrd_trigger_update(hash_entry);
}
return;
}
gboolean
attrd_timer_callback(void *user_data)
{
stop_attrd_timer(user_data);
attrd_trigger_update(user_data);
return TRUE; /* Always return true, removed cleanly by stop_attrd_timer() */
}
gboolean
attrd_trigger_update(attr_hash_entry_t * hash_entry)
{
xmlNode *msg = NULL;
/* send HA message to everyone */
crm_notice("Sending flush op to all hosts for: %s (%s)",
hash_entry->id, crm_str(hash_entry->value));
log_hash_entry(LOG_DEBUG_2, hash_entry, "Sending flush op to all hosts for:");
msg = create_xml_node(NULL, __FUNCTION__);
crm_xml_add(msg, F_TYPE, T_ATTRD);
crm_xml_add(msg, F_ORIG, attrd_uname);
crm_xml_add(msg, F_ATTRD_TASK, "flush");
crm_xml_add(msg, F_ATTRD_ATTRIBUTE, hash_entry->id);
crm_xml_add(msg, F_ATTRD_SET, hash_entry->set);
crm_xml_add(msg, F_ATTRD_SECTION, hash_entry->section);
crm_xml_add(msg, F_ATTRD_DAMPEN, hash_entry->dampen);
crm_xml_add(msg, F_ATTRD_VALUE, hash_entry->value);
#if ENABLE_ACL
if (hash_entry->user) {
crm_xml_add(msg, F_ATTRD_USER, hash_entry->user);
}
#endif
if (hash_entry->timeout <= 0) {
crm_xml_add(msg, F_ATTRD_IGNORE_LOCALLY, hash_entry->value);
attrd_perform_update(hash_entry);
}
send_cluster_message(NULL, crm_msg_attrd, msg, FALSE);
free_xml(msg);
return TRUE;
}
diff --git a/tools/crm_node.c b/tools/crm_node.c
index 5932f98303..bffd8ec4ee 100644
--- a/tools/crm_node.c
+++ b/tools/crm_node.c
@@ -1,945 +1,945 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <crm_internal.h>
#include <sys/param.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h> /* for basename() */
#include <crm/crm.h>
#include <crm/cluster/internal.h>
#include <crm/common/mainloop.h>
#include <crm/msg_xml.h>
#include <crm/cib.h>
#include <crm/attrd.h>
int command = 0;
int ccm_fd = 0;
gboolean do_quiet = FALSE;
char *target_uuid = NULL;
char *target_uname = NULL;
const char *standby_value = NULL;
const char *standby_scope = NULL;
/* *INDENT-OFF* */
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, '-', "\nStack:"},
#if SUPPORT_CMAN
{"cman", 0, 0, 'c', "\tOnly try connecting to a cman-based cluster"},
#endif
#if SUPPORT_COROSYNC
{"openais", 0, 0, 'A', "\tOnly try connecting to an OpenAIS-based cluster"},
#endif
#ifdef SUPPORT_HEARTBEAT
{"heartbeat", 0, 0, 'H', "Only try connecting to a Heartbeat-based cluster"},
#endif
{"-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"},
{"epoch", 0, 0, 'e', "\tDisplay the epoch during which this node joined the cluster"},
{"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 (Not available for heartbeat clusters)"},
{"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, '-', "In the case of Heartbeat, CMAN and Corosync 2.0, requires that the node has already been removed from the underlying cluster"},
{"-spacer-", 1, 0, '-', "\nAdditional Options:"},
{"force", 0, 0, 'f'},
{0, 0, 0, 0}
};
/* *INDENT-ON* */
static int
cib_remove_node(uint32_t 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);
/* TODO: Use 'id' instead */
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) {
char buffer[64];
if(snprintf(buffer, 63, "%u", id) > 0) {
crm_xml_add(node, XML_ATTR_ID, buffer);
crm_xml_add(node_state, XML_ATTR_ID, buffer);
}
}
cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
rc = cib->cmds->delete(cib, XML_CIB_TAG_NODES, node, cib_sync_call);
if (rc != pcmk_ok) {
printf("Could not remove %s/%u from " XML_CIB_TAG_NODES ": %s", name, id, pcmk_strerror(rc));
}
rc = cib->cmds->delete(cib, XML_CIB_TAG_STATUS, node_state, cib_sync_call);
if (rc != pcmk_ok) {
printf("Could not remove %s/%u from " XML_CIB_TAG_STATUS ": %s", name, id, pcmk_strerror(rc));
}
cib->cmds->signoff(cib);
cib_delete(cib);
return rc;
}
int tools_remove_node_cache(const char *node, const char *target);
int tools_remove_node_cache(const char *node, const char *target)
{
int n = 0;
int rc = -1;
char *name = NULL;
char *admin_uuid = NULL;
crm_ipc_t *conn = crm_ipc_new(target, 0);
xmlNode *cmd = NULL;
xmlNode *hello = NULL;
char *endptr = NULL;
if (!conn) {
return -ENOTCONN;
}
if (!crm_ipc_connect(conn)) {
crm_ipc_destroy(conn);
return -ENOTCONN;
}
if(safe_str_eq(target, CRM_SYSTEM_CRMD)) {
admin_uuid = calloc(1, 11);
snprintf(admin_uuid, 10, "%d", getpid());
admin_uuid[10] = '\0';
hello = create_hello_message(admin_uuid, "crm_node", "0", "1");
rc = crm_ipc_send(conn, hello, 0, 0, NULL);
free_xml(hello);
if (rc < 0) {
free(admin_uuid);
return rc;
}
}
errno = 0;
n = strtol(node, &endptr, 10);
if (errno != 0 || endptr == node || *endptr != '\0') {
/* Argument was not a nodeid */
n = 0;
name = strdup(node);
} else {
name = get_node_name(n);
}
crm_trace("Removing %s aka. %s (%u) from the membership cache", name, node, n);
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, "peer-remove");
+ crm_xml_add(cmd, F_ATTRD_TASK, ATTRD_OP_PEER_REMOVE);
crm_xml_add(cmd, F_ATTRD_HOST, name);
if (n) {
char buffer[64];
if(snprintf(buffer, 63, "%u", n) > 0) {
crm_xml_add(cmd, F_ATTRD_HOST_ID, buffer);
}
}
} else {
cmd = create_request(CRM_OP_RM_NODE_CACHE,
NULL, NULL, target, crm_system_name, admin_uuid);
if (n) {
char buffer[64];
if(snprintf(buffer, 63, "%u", n) > 0) {
crm_xml_add(cmd, XML_ATTR_ID, buffer);
}
}
crm_xml_add(cmd, XML_ATTR_UNAME, name);
}
rc = crm_ipc_send(conn, cmd, 0, 0, NULL);
crm_debug("%s peer cache cleanup for %s (%u): %d", target, name, n, rc);
if (rc > 0) {
rc = cib_remove_node(n, name);
}
if (conn) {
crm_ipc_close(conn);
crm_ipc_destroy(conn);
}
free(admin_uuid);
free_xml(cmd);
free(name);
return rc > 0 ? 0 : rc;
}
#if SUPPORT_HEARTBEAT
# include <ocf/oc_event.h>
# include <ocf/oc_membership.h>
# include <clplumbing/cl_uuid.h>
# define UUID_LEN 16
oc_ev_t *ccm_token = NULL;
static void *ccm_library = NULL;
void oc_ev_special(const oc_ev_t *, oc_ev_class_t, int);
static gboolean
read_local_hb_uuid(void)
{
cl_uuid_t uuid;
char *buffer = NULL;
long start = 0, read_len = 0;
FILE *input = fopen(UUID_FILE, "r");
if (input == NULL) {
crm_info("Could not open UUID file %s\n", UUID_FILE);
return FALSE;
}
/* see how big the file is */
start = ftell(input);
fseek(input, 0L, SEEK_END);
if (UUID_LEN != ftell(input)) {
fprintf(stderr, "%s must contain exactly %d bytes\n", UUID_FILE, UUID_LEN);
abort();
}
fseek(input, 0L, start);
if (start != ftell(input)) {
fprintf(stderr, "fseek not behaving: %ld vs. %ld\n", start, ftell(input));
crm_exit(pcmk_err_generic);
}
buffer = malloc(50);
read_len = fread(uuid.uuid, 1, UUID_LEN, input);
fclose(input);
if (read_len != UUID_LEN) {
fprintf(stderr, "Expected and read bytes differ: %d vs. %ld\n", UUID_LEN, read_len);
crm_exit(pcmk_err_generic);
} else if (buffer != NULL) {
cl_uuid_unparse(&uuid, buffer);
fprintf(stdout, "%s\n", buffer);
return TRUE;
} else {
fprintf(stderr, "No buffer to unparse\n");
crm_exit(ENODATA);
}
free(buffer);
return FALSE;
}
static void
ccm_age_callback(oc_ed_t event, void *cookie, size_t size, const void *data)
{
int lpc;
int node_list_size;
const oc_ev_membership_t *oc = (const oc_ev_membership_t *)data;
int (*ccm_api_callback_done) (void *cookie) =
find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_callback_done", 1);
node_list_size = oc->m_n_member;
if (command == 'q') {
crm_debug("Processing \"%s\" event.",
event == OC_EV_MS_NEW_MEMBERSHIP ? "NEW MEMBERSHIP" :
event == OC_EV_MS_NOT_PRIMARY ? "NOT PRIMARY" :
event == OC_EV_MS_PRIMARY_RESTORED ? "PRIMARY RESTORED" :
event == OC_EV_MS_EVICTED ? "EVICTED" : "NO QUORUM MEMBERSHIP");
if (ccm_have_quorum(event)) {
fprintf(stdout, "1\n");
} else {
fprintf(stdout, "0\n");
}
} else if (command == 'e') {
crm_debug("Searching %d members for our birth", oc->m_n_member);
}
for (lpc = 0; lpc < node_list_size; lpc++) {
if (command == 'p') {
fprintf(stdout, "%s ", oc->m_array[oc->m_memb_idx + lpc].node_uname);
} else if (command == 'e') {
int (*ccm_api_is_my_nodeid) (const oc_ev_t * token, const oc_node_t * node) =
find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_is_my_nodeid", 1);
if ((*ccm_api_is_my_nodeid) (ccm_token, &(oc->m_array[lpc]))) {
crm_debug("MATCH: nodeid=%d, uname=%s, born=%d",
oc->m_array[oc->m_memb_idx + lpc].node_id,
oc->m_array[oc->m_memb_idx + lpc].node_uname,
oc->m_array[oc->m_memb_idx + lpc].node_born_on);
fprintf(stdout, "%d\n", oc->m_array[oc->m_memb_idx + lpc].node_born_on);
}
}
}
(*ccm_api_callback_done) (cookie);
if (command == 'p') {
fprintf(stdout, "\n");
}
fflush(stdout);
crm_exit(pcmk_ok);
}
static gboolean
ccm_age_connect(int *ccm_fd)
{
gboolean did_fail = FALSE;
int ret = 0;
int (*ccm_api_register) (oc_ev_t ** token) =
find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_register", 1);
int (*ccm_api_set_callback) (const oc_ev_t * token,
oc_ev_class_t class,
oc_ev_callback_t * fn,
oc_ev_callback_t ** prev_fn) =
find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_set_callback", 1);
void (*ccm_api_special) (const oc_ev_t *, oc_ev_class_t, int) =
find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_special", 1);
int (*ccm_api_activate) (const oc_ev_t * token, int *fd) =
find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_activate", 1);
crm_debug("Registering with CCM");
ret = (*ccm_api_register) (&ccm_token);
if (ret != 0) {
crm_info("CCM registration failed: %d", ret);
did_fail = TRUE;
}
if (did_fail == FALSE) {
crm_debug("Setting up CCM callbacks");
ret = (*ccm_api_set_callback) (ccm_token, OC_EV_MEMB_CLASS, ccm_age_callback, NULL);
if (ret != 0) {
crm_warn("CCM callback not set: %d", ret);
did_fail = TRUE;
}
}
if (did_fail == FALSE) {
(*ccm_api_special) (ccm_token, OC_EV_MEMB_CLASS, 0 /*don't care */ );
crm_debug("Activating CCM token");
ret = (*ccm_api_activate) (ccm_token, ccm_fd);
if (ret != 0) {
crm_warn("CCM Activation failed: %d", ret);
did_fail = TRUE;
}
}
return !did_fail;
}
static gboolean
try_heartbeat(int command, enum cluster_type_e stack)
{
crm_debug("Attempting to process %c command", command);
if (command == 'i') {
if (read_local_hb_uuid()) {
crm_exit(pcmk_ok);
}
} else if (command == 'R') {
if (tools_remove_node_cache(target_uname, CRM_SYSTEM_CRMD)) {
crm_err("Failed to connect to "CRM_SYSTEM_CRMD" to remove node '%s'", target_uname);
crm_exit(pcmk_err_generic);
}
crm_exit(pcmk_ok);
} else if (ccm_age_connect(&ccm_fd)) {
int rc = 0;
fd_set rset;
int (*ccm_api_handle_event) (const oc_ev_t * token) =
find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_handle_event", 1);
while (1) {
sleep(1);
FD_ZERO(&rset);
FD_SET(ccm_fd, &rset);
errno = 0;
rc = select(ccm_fd + 1, &rset, NULL, NULL, NULL);
if (rc > 0 && (*ccm_api_handle_event) (ccm_token) != 0) {
crm_err("oc_ev_handle_event failed");
return FALSE;
} else if (rc < 0 && errno != EINTR) {
crm_perror(LOG_ERR, "select failed: %d", rc);
return FALSE;
}
}
}
return FALSE;
}
#endif
#if SUPPORT_CMAN
# include <libcman.h>
# define MAX_NODES 256
static gboolean
try_cman(int command, enum cluster_type_e stack)
{
int rc = -1, lpc = 0, node_count = 0;
cman_node_t node;
cman_cluster_t cluster;
cman_handle_t cman_handle = NULL;
cman_node_t cman_nodes[MAX_NODES];
memset(&cluster, 0, sizeof(cluster));
cman_handle = cman_init(NULL);
if (cman_handle == NULL || cman_is_active(cman_handle) == FALSE) {
crm_info("Couldn't connect to cman");
return FALSE;
}
switch (command) {
case 'R':
if (tools_remove_node_cache(target_uname, CRM_SYSTEM_CRMD)) {
crm_err("Failed to connect to "CRM_SYSTEM_CRMD" to remove node '%s'", target_uname);
}
break;
case 'e':
/* Age makes no sense (yet?) in a cman cluster */
fprintf(stdout, "1\n");
break;
case 'q':
fprintf(stdout, "%d\n", cman_is_quorate(cman_handle));
break;
case 'l':
case 'p':
rc = cman_get_nodes(cman_handle, MAX_NODES, &node_count, cman_nodes);
if (rc != 0) {
fprintf(stderr, "Couldn't query cman node list: %d %d", rc, errno);
goto cman_bail;
}
for (lpc = 0; lpc < node_count; lpc++) {
if (command == 'l') {
printf("%s ", cman_nodes[lpc].cn_name);
} else if (cman_nodes[lpc].cn_nodeid != 0 && cman_nodes[lpc].cn_member) {
/* Never allow node ID 0 to be considered a member #315711 */
printf("%s ", cman_nodes[lpc].cn_name);
}
}
printf("\n");
break;
case 'i':
rc = cman_get_node(cman_handle, CMAN_NODEID_US, &node);
if (rc != 0) {
fprintf(stderr, "Couldn't query cman node id: %d %d", rc, errno);
goto cman_bail;
}
fprintf(stdout, "%u\n", node.cn_nodeid);
break;
default:
fprintf(stderr, "Unknown option '%c'\n", command);
crm_help('?', EX_USAGE);
}
cman_finish(cman_handle);
crm_exit(pcmk_ok);
cman_bail:
cman_finish(cman_handle);
return crm_exit(EINVAL);
}
#endif
#if HAVE_CONFDB
static void
ais_membership_destroy(gpointer user_data)
{
crm_err("AIS connection terminated");
ais_fd_sync = -1;
crm_exit(ENOTCONN);
}
static gint
member_sort(gconstpointer a, gconstpointer b)
{
const crm_node_t *node_a = a;
const crm_node_t *node_b = b;
return strcmp(node_a->uname, node_b->uname);
}
static void
crm_add_member(gpointer key, gpointer value, gpointer user_data)
{
GList **list = user_data;
crm_node_t *node = value;
if (node->uname != NULL) {
*list = g_list_insert_sorted(*list, node, member_sort);
}
}
static void
ais_membership_dispatch(cpg_handle_t handle,
const struct cpg_name *groupName,
uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
{
uint32_t kind = 0;
const char *from = NULL;
char *data = pcmk_message_common_cs(handle, nodeid, pid, msg, &kind, &from);
switch (kind) {
case crm_class_members:
case crm_class_notify:
case crm_class_quorum:
break;
default:
free(data);
return;
break;
}
if (command == 'q') {
if (crm_have_quorum) {
fprintf(stdout, "1\n");
} else {
fprintf(stdout, "0\n");
}
} else if (command == 'l') {
GList *nodes = NULL;
GListPtr lpc = NULL;
g_hash_table_foreach(crm_peer_cache, crm_add_member, &nodes);
for (lpc = nodes; lpc != NULL; lpc = lpc->next) {
crm_node_t *node = (crm_node_t *) lpc->data;
fprintf(stdout, "%u %s %s\n", node->id, node->uname, node->state);
}
fprintf(stdout, "\n");
} else if (command == 'p') {
GList *nodes = NULL;
GListPtr lpc = NULL;
g_hash_table_foreach(crm_peer_cache, crm_add_member, &nodes);
for (lpc = nodes; lpc != NULL; lpc = lpc->next) {
crm_node_t *node = (crm_node_t *) lpc->data;
if (node->uname && safe_str_eq(node->state, CRM_NODE_MEMBER)) {
fprintf(stdout, "%s ", node->uname);
}
}
fprintf(stdout, "\n");
}
free(data);
crm_exit(pcmk_ok);
return;
}
#endif
#ifdef SUPPORT_CS_QUORUM
# include <corosync/quorum.h>
# include <corosync/cpg.h>
static gint
compare_node_uname(gconstpointer a, gconstpointer b)
{
const crm_node_t *a_node = a;
const crm_node_t *b_node = b;
return strcmp(a_node->uname?a_node->uname:"", b_node->uname?b_node->uname:"");
}
static int
node_mcp_dispatch(const char *buffer, ssize_t length, gpointer userdata)
{
xmlNode *msg = string2xml(buffer);
if (msg) {
xmlNode *node = NULL;
GListPtr nodes = NULL;
GListPtr iter = NULL;
crm_log_xml_trace(msg, "message");
for (node = __xml_first_child(msg); node != NULL; node = __xml_next(node)) {
crm_node_t *peer = calloc(1, sizeof(crm_node_t));
nodes = g_list_insert_sorted(nodes, peer, compare_node_uname);
peer->uname = (char*)crm_element_value_copy(node, "uname");
peer->state = (char*)crm_element_value_copy(node, "state");
crm_element_value_int(node, "id", (int*)&peer->id);
}
for(iter = nodes; iter; iter = iter->next) {
crm_node_t *peer = iter->data;
if (command == 'l') {
fprintf(stdout, "%u %s\n", peer->id, peer->uname);
} else if (command == 'p') {
if(safe_str_eq(peer->state, CRM_NODE_MEMBER)) {
fprintf(stdout, "%s ", peer->uname);
}
}
}
g_list_free_full(nodes, free);
free_xml(msg);
if (command == 'p') {
fprintf(stdout, "\n");
}
crm_exit(pcmk_ok);
}
return 0;
}
static void
node_mcp_destroy(gpointer user_data)
{
crm_exit(ENOTCONN);
}
static gboolean
try_corosync(int command, enum cluster_type_e stack)
{
int rc = 0;
int quorate = 0;
uint32_t quorum_type = 0;
unsigned int nodeid = 0;
cpg_handle_t c_handle = 0;
quorum_handle_t q_handle = 0;
mainloop_io_t *ipc = NULL;
GMainLoop *amainloop = NULL;
const char *daemons[] = {
CRM_SYSTEM_CRMD,
"stonith-ng",
T_ATTRD,
CRM_SYSTEM_MCP,
};
struct ipc_client_callbacks node_callbacks = {
.dispatch = node_mcp_dispatch,
.destroy = node_mcp_destroy
};
switch (command) {
case 'R':
for(rc = 0; rc < DIMOF(daemons); rc++) {
if (tools_remove_node_cache(target_uname, daemons[rc])) {
crm_err("Failed to connect to %s to remove node '%s'", daemons[rc], target_uname);
crm_exit(pcmk_err_generic);
}
}
crm_exit(pcmk_ok);
break;
case 'e':
/* Age makes no sense (yet) in an AIS cluster */
fprintf(stdout, "1\n");
crm_exit(pcmk_ok);
case 'q':
/* Go direct to the Quorum API */
rc = quorum_initialize(&q_handle, NULL, &quorum_type);
if (rc != CS_OK) {
crm_err("Could not connect to the Quorum API: %d\n", rc);
return FALSE;
}
rc = quorum_getquorate(q_handle, &quorate);
if (rc != CS_OK) {
crm_err("Could not obtain the current Quorum API state: %d\n", rc);
return FALSE;
}
if (quorate) {
fprintf(stdout, "1\n");
} else {
fprintf(stdout, "0\n");
}
quorum_finalize(q_handle);
crm_exit(pcmk_ok);
case 'i':
/* Go direct to the CPG API */
rc = cpg_initialize(&c_handle, NULL);
if (rc != CS_OK) {
crm_err("Could not connect to the Cluster Process Group API: %d\n", rc);
return FALSE;
}
rc = cpg_local_get(c_handle, &nodeid);
if (rc != CS_OK) {
crm_err("Could not get local node id from the CPG API");
return FALSE;
}
fprintf(stdout, "%u\n", nodeid);
cpg_finalize(c_handle);
crm_exit(pcmk_ok);
case 'l':
case 'p':
/* Go to pacemakerd */
amainloop = g_main_new(FALSE);
ipc =
mainloop_add_ipc_client(CRM_SYSTEM_MCP, G_PRIORITY_DEFAULT, 0, NULL,
&node_callbacks);
if (ipc != NULL) {
/* Sending anything will get us a list of nodes */
xmlNode *poke = create_xml_node(NULL, "poke");
crm_ipc_send(mainloop_get_ipc_client(ipc), poke, 0, 0, NULL);
free_xml(poke);
g_main_run(amainloop);
}
break;
}
return FALSE;
}
#endif
#if HAVE_CONFDB
static gboolean
try_openais(int command, enum cluster_type_e stack)
{
static crm_cluster_t cluster;
cluster.destroy = ais_membership_destroy;
cluster.cpg.cpg_deliver_fn = ais_membership_dispatch;
cluster.cpg.cpg_confchg_fn = NULL;
if (init_cs_connection_once(&cluster)) {
GMainLoop *amainloop = NULL;
switch (command) {
case 'R':
send_cluster_text(crm_class_rmpeer, target_uname, TRUE, NULL, crm_msg_ais);
cib_remove_node(0, target_uname);
crm_exit(pcmk_ok);
case 'e':
/* Age makes no sense (yet) in an AIS cluster */
fprintf(stdout, "1\n");
crm_exit(pcmk_ok);
case 'q':
send_cluster_text(crm_class_quorum, NULL, TRUE, NULL, crm_msg_ais);
break;
case 'l':
case 'p':
crm_info("Requesting the list of configured nodes");
send_cluster_text(crm_class_members, __FUNCTION__, TRUE, NULL, crm_msg_ais);
break;
case 'i':
printf("%u\n", cluster.nodeid);
crm_exit(pcmk_ok);
default:
fprintf(stderr, "Unknown option '%c'\n", command);
crm_help('?', EX_USAGE);
}
amainloop = g_main_new(FALSE);
g_main_run(amainloop);
}
return FALSE;
}
#endif
int set_cluster_type(enum cluster_type_e type);
int
main(int argc, char **argv)
{
int flag = 0;
int argerr = 0;
uint32_t nodeid = 0;
gboolean force_flag = FALSE;
gboolean dangerous_cmd = FALSE;
enum cluster_type_e try_stack = pcmk_cluster_unknown;
int option_index = 0;
crm_peer_init();
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, EX_OK);
break;
case 'Q':
do_quiet = TRUE;
break;
case 'H':
set_cluster_type(pcmk_cluster_heartbeat);
break;
case 'A':
set_cluster_type(pcmk_cluster_classic_ais);
break;
case 'C':
set_cluster_type(pcmk_cluster_corosync);
break;
case 'c':
set_cluster_type(pcmk_cluster_cman);
break;
case 'f':
force_flag = TRUE;
break;
case 'R':
command = flag;
dangerous_cmd = TRUE;
target_uname = optarg;
break;
case 'N':
command = flag;
nodeid = crm_parse_int(optarg, NULL);
break;
case 'p':
case 'e':
case 'q':
case 'i':
case 'l':
case 'n':
command = flag;
break;
default:
++argerr;
break;
}
}
if (optind > argc) {
++argerr;
}
if (argerr) {
crm_help('?', EX_USAGE);
}
if (command == 'n') {
fprintf(stdout, "%s\n", get_local_node_name());
crm_exit(pcmk_ok);
} else if (command == 'N') {
fprintf(stdout, "%s\n", get_node_name(nodeid));
crm_exit(pcmk_ok);
}
if (dangerous_cmd && 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");
fflush(stderr);
crm_exit(EINVAL);
}
try_stack = get_cluster_type();
crm_debug("Attempting to process -%c command for cluster type: %s", command,
name_for_cluster_type(try_stack));
#if SUPPORT_CMAN
if (try_stack == pcmk_cluster_cman) {
try_cman(command, try_stack);
}
#endif
#ifdef SUPPORT_CS_QUORUM
if (try_stack == pcmk_cluster_corosync) {
try_corosync(command, try_stack);
}
#endif
#if HAVE_CONFDB
/* Only an option if we're using the plugins */
if (try_stack == pcmk_cluster_classic_ais) {
try_openais(command, try_stack);
}
#endif
#if SUPPORT_HEARTBEAT
if (try_stack == pcmk_cluster_heartbeat) {
try_heartbeat(command, try_stack);
}
#endif
return (1);
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Jan 25, 12:29 PM (13 h, 22 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1322567
Default Alt Text
(53 KB)

Event Timeline