Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4149405
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
17 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/fencing/main.c b/fencing/main.c
index 6ac9fbcee7..56b6e708b6 100644
--- a/fencing/main.c
+++ b/fencing/main.c
@@ -1,639 +1,641 @@
/*
* Copyright (C) 2009 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.1 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <crm_internal.h>
#include <sys/param.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <crm/crm.h>
#include <crm/msg_xml.h>
#include <crm/common/ipc.h>
#include <crm/common/cluster.h>
#include <crm/stonith-ng.h>
#include <crm/common/xml.h>
#include <crm/common/msg.h>
#include <internal.h>
char *channel1 = NULL;
char *channel2 = NULL;
char *stonith_our_uname = NULL;
GMainLoop *mainloop = NULL;
GHashTable *client_list = NULL;
gboolean stonith_shutdown_flag = FALSE;
#if SUPPORT_HEARTBEAT
ll_cluster_t *hb_conn = NULL;
#endif
static gboolean
stonith_client_disconnect(
IPC_Channel *channel, stonith_client_t *stonith_client)
{
if (channel == NULL) {
CRM_DEV_ASSERT(stonith_client == NULL);
} else if (stonith_client == NULL) {
crm_err("No client");
} else {
CRM_DEV_ASSERT(channel->ch_status != IPC_CONNECT);
crm_debug_2("Cleaning up after client disconnect: %s/%s/%s",
crm_str(stonith_client->name),
stonith_client->channel_name,
stonith_client->id);
if(stonith_client->id != NULL) {
if(!g_hash_table_remove(client_list, stonith_client->id)) {
crm_err("Client %s not found in the hashtable",
stonith_client->name);
}
}
}
return FALSE;
}
static gboolean
stonith_client_callback(IPC_Channel *channel, gpointer user_data)
{
int lpc = 0;
const char *value = NULL;
xmlNode *request = NULL;
gboolean keep_channel = TRUE;
stonith_client_t *stonith_client = user_data;
CRM_CHECK(stonith_client != NULL, crm_err("Invalid client"); return FALSE);
CRM_CHECK(stonith_client->id != NULL,
crm_err("Invalid client: %p", stonith_client); return FALSE);
if(IPC_ISRCONN(channel) && channel->ops->is_message_pending(channel)) {
lpc++;
request = xmlfromIPC(channel, MAX_IPC_DELAY);
if (request == NULL) {
goto bail;
}
if(stonith_client->name == NULL) {
value = crm_element_value(request, F_STONITH_CLIENTNAME);
if(value == NULL) {
stonith_client->name = crm_itoa(channel->farside_pid);
} else {
stonith_client->name = crm_strdup(value);
}
}
crm_xml_add(request, F_STONITH_CLIENTID, stonith_client->id);
crm_xml_add(request, F_STONITH_CLIENTNAME, stonith_client->name);
if(stonith_client->callback_id == NULL) {
value = crm_element_value(request, F_STONITH_CALLBACK_TOKEN);
if(value != NULL) {
stonith_client->callback_id = crm_strdup(value);
} else {
stonith_client->callback_id = crm_strdup(stonith_client->id);
}
}
crm_log_xml(LOG_MSG, "Client[inbound]", request);
stonith_command(stonith_client, request, NULL);
free_xml(request);
}
bail:
if(channel->ch_status != IPC_CONNECT) {
crm_debug_2("Client disconnected");
keep_channel = stonith_client_disconnect(channel, stonith_client);
}
return keep_channel;
}
static void
stonith_client_destroy(gpointer user_data)
{
stonith_client_t *stonith_client = user_data;
if(stonith_client == NULL) {
crm_debug_4("Destroying %p", user_data);
return;
}
if(stonith_client->source != NULL) {
crm_debug_4("Deleting %s (%p) from mainloop",
stonith_client->name, stonith_client->source);
G_main_del_IPC_Channel(stonith_client->source);
stonith_client->source = NULL;
}
crm_debug_3("Destroying %s (%p)", stonith_client->name, user_data);
crm_free(stonith_client->name);
crm_free(stonith_client->callback_id);
crm_free(stonith_client->id);
crm_free(stonith_client);
crm_debug_4("Freed the cib client");
return;
}
static gboolean
stonith_client_connect(IPC_Channel *channel, gpointer user_data)
{
cl_uuid_t client_id;
xmlNode *reg_msg = NULL;
stonith_client_t *new_client = NULL;
char uuid_str[UU_UNPARSE_SIZEOF];
const char *channel_name = user_data;
crm_debug_3("Connecting channel");
CRM_CHECK(channel_name != NULL, return FALSE);
if (channel == NULL) {
crm_err("Channel was NULL");
return FALSE;
} else if (channel->ch_status != IPC_CONNECT) {
crm_err("Channel was disconnected");
return FALSE;
} else if(stonith_shutdown_flag) {
crm_info("Ignoring new client [%d] during shutdown",
channel->farside_pid);
return FALSE;
}
crm_malloc0(new_client, sizeof(stonith_client_t));
new_client->channel = channel;
new_client->channel_name = channel_name;
crm_debug_3("Created channel %p for channel %s",
new_client, new_client->channel_name);
channel->ops->set_recv_qlen(channel, 1024);
channel->ops->set_send_qlen(channel, 1024);
new_client->source = G_main_add_IPC_Channel(
G_PRIORITY_DEFAULT, channel, FALSE, stonith_client_callback,
new_client, stonith_client_destroy);
crm_debug_3("Channel %s connected for client %s",
new_client->channel_name, new_client->id);
cl_uuid_generate(&client_id);
cl_uuid_unparse(&client_id, uuid_str);
CRM_CHECK(new_client->id == NULL, crm_free(new_client->id));
new_client->id = crm_strdup(uuid_str);
/* make sure we can find ourselves later for sync calls
* redirected to the master instance
*/
g_hash_table_insert(client_list, new_client->id, new_client);
reg_msg = create_xml_node(NULL, "callback");
crm_xml_add(reg_msg, F_STONITH_OPERATION, CRM_OP_REGISTER);
crm_xml_add(reg_msg, F_STONITH_CLIENTID, new_client->id);
send_ipc_message(channel, reg_msg);
free_xml(reg_msg);
return TRUE;
}
static void
stonith_peer_callback(xmlNode * msg, void* private_data)
{
const char *remote = crm_element_value(msg, F_ORIG);
crm_log_xml(LOG_MSG, "Peer[inbound]", msg);
stonith_command(NULL, msg, remote);
}
static void
stonith_peer_hb_callback(HA_Message * msg, void* private_data)
{
xmlNode *xml = convert_ha_message(NULL, msg, __FUNCTION__);
stonith_peer_callback(xml, private_data);
free_xml(xml);
}
#if SUPPORT_AIS
static gboolean stonith_peer_ais_callback(
AIS_Message *wrapper, char *data, int sender)
{
xmlNode *xml = NULL;
if(wrapper->header.id == crm_class_cluster) {
xml = string2xml(data);
if(xml == NULL) {
goto bail;
}
crm_xml_add(xml, F_ORIG, wrapper->sender.uname);
crm_xml_add_int(xml, F_SEQ, wrapper->id);
stonith_peer_callback(xml, NULL);
}
free_xml(xml);
return TRUE;
bail:
crm_err("Invalid XML: '%.120s'", data);
return TRUE;
}
static void
stonith_peer_ais_destroy(gpointer user_data)
{
crm_err("AIS connection terminated");
ais_fd_sync = -1;
exit(1);
}
#endif
static void
stonith_peer_hb_destroy(gpointer user_data)
{
if(stonith_shutdown_flag) {
crm_info("Heartbeat disconnection complete... exiting");
} else {
crm_err("Heartbeat connection lost! Exiting.");
}
crm_info("Exiting...");
if (mainloop != NULL && g_main_is_running(mainloop)) {
g_main_quit(mainloop);
} else {
exit(LSB_EXIT_OK);
}
}
static int
send_via_callback_channel(xmlNode *msg, const char *token)
{
stonith_client_t *hash_client = NULL;
enum stonith_errors rc = stonith_ok;
crm_debug_3("Delivering msg %p to client %s", msg, token);
if(token == NULL) {
crm_err("No client id token, cant send message");
if(rc == stonith_ok) {
rc = -1;
}
} else if(msg == NULL) {
crm_err("No message to send");
rc = -1;
} else {
/* A client that left before we could reply is not really
* _our_ error. Warn instead.
*/
hash_client = g_hash_table_lookup(client_list, token);
if(hash_client == NULL) {
crm_warn("Cannot find client for token %s", token);
rc = -1;
} else if (crm_str_eq(hash_client->channel_name, "remote", FALSE)) {
/* just hope it's alive */
} else if(hash_client->channel == NULL) {
crm_err("Cannot find channel for client %s", token);
rc = -1;
}
}
if(rc == stonith_ok) {
crm_debug_3("Delivering reply to client %s (%s)",
token, hash_client->channel_name);
if(send_ipc_message(hash_client->channel, msg) == FALSE) {
crm_warn("Delivery of reply to client %s/%s failed",
hash_client->name, token);
rc = -1;
}
}
return rc;
}
void do_local_reply(xmlNode *notify_src, const char *client_id,
gboolean sync_reply, gboolean from_peer)
{
/* send callback to originating child */
stonith_client_t *client_obj = NULL;
enum stonith_errors local_rc = stonith_ok;
crm_debug_2("Sending response");
if(client_id != NULL) {
client_obj = g_hash_table_lookup(client_list, client_id);
} else {
crm_debug_2("No client to sent the response to."
" F_STONITH_CLIENTID not set.");
}
crm_debug_3("Sending callback to request originator");
if(client_obj == NULL) {
local_rc = -1;
} else {
const char *client_id = client_obj->callback_id;
crm_debug_2("Sending %ssync response to %s %s",
sync_reply?"":"an a-",
client_obj->name,
from_peer?"(originator of delegated request)":"");
if(sync_reply) {
client_id = client_obj->id;
}
local_rc = send_via_callback_channel(notify_src, client_id);
}
if(local_rc != stonith_ok && client_obj != NULL) {
crm_warn("%sSync reply to %s failed: %s",
sync_reply?"":"A-",
client_obj?client_obj->name:"<unknown>", stonith_error2string(local_rc));
}
}
long long get_stonith_flag(const char *name)
{
if(safe_str_eq(name, STONITH_OP_FENCE)) {
return 0x01;
} else if(safe_str_eq(name, STONITH_OP_DEVICE_ADD)) {
return 0x04;
} else if(safe_str_eq(name, STONITH_OP_DEVICE_DEL)) {
return 0x10;
}
return 0;
}
static void
stonith_notify_client(gpointer key, gpointer value, gpointer user_data)
{
IPC_Channel *ipc_client = NULL;
xmlNode *update_msg = user_data;
stonith_client_t *client = value;
const char *type = NULL;
CRM_CHECK(client != NULL, return);
CRM_CHECK(update_msg != NULL, return);
type = crm_element_value(update_msg, F_SUBTYPE);
CRM_CHECK(type != NULL, crm_log_xml_err(update_msg, "notify"); return);
if(client == NULL) {
crm_warn("Skipping NULL client");
return;
} else if(client->channel == NULL) {
crm_warn("Skipping client with NULL channel");
return;
} else if(client->name == NULL) {
crm_debug_2("Skipping unnammed client / comamnd channel");
return;
}
ipc_client = client->channel;
if(client->flags & get_stonith_flag(type)) {
crm_info("Sending %s-notification to client %s/%s", type, client->name, client->id);
if(ipc_client->send_queue->current_qlen >= ipc_client->send_queue->max_qlen) {
/* We never want the STONITH to exit because our client is slow */
crm_crit("%s-notification of client %s/%s failed - queue saturated",
type, client->name, client->id);
} else if(send_ipc_message(ipc_client, update_msg) == FALSE) {
crm_warn("%s-Notification of client %s/%s failed",
type, client->name, client->id);
}
}
}
void
do_stonith_notify(
int options, const char *type, enum stonith_errors result, xmlNode *data,
const char *remote)
{
/* TODO: Standardize the contents of data */
xmlNode *update_msg = create_xml_node(NULL, "notify");
CRM_CHECK_AND_STORE(type != NULL, ;);
crm_xml_add(update_msg, F_TYPE, T_STONITH_NOTIFY);
crm_xml_add(update_msg, F_SUBTYPE, type);
crm_xml_add(update_msg, F_STONITH_OPERATION, type);
crm_xml_add_int(update_msg, F_STONITH_RC, result);
if(data != NULL) {
add_message_xml(update_msg, F_STONITH_CALLDATA, data);
}
crm_debug_3("Notifying clients");
g_hash_table_foreach(client_list, stonith_notify_client, update_msg);
free_xml(update_msg);
crm_debug_3("Notify complete");
}
static void
stonith_shutdown(int nsig)
{
stonith_shutdown_flag = TRUE;
crm_info("Terminating with %d clients", g_hash_table_size(client_list));
stonith_client_disconnect(NULL, NULL);
exit(0);
}
static void
stonith_cleanup(void)
{
crm_peer_destroy();
g_hash_table_destroy(client_list);
crm_free(stonith_our_uname);
#if HAVE_LIBXML2
xmlCleanupParser();
#endif
crm_free(channel1);
}
static struct crm_option long_options[] = {
{"stand-alone", 0, 0, 's'},
{"verbose", 0, 0, 'V'},
{"version", 0, 0, '$'},
{"help", 0, 0, '?'},
{0, 0, 0, 0}
};
int
main(int argc, char ** argv)
{
int flag;
int rc = 0;
int argerr = 0;
int option_index = 0;
gboolean stand_alone = FALSE;
- crm_log_init("stonith-ng", LOG_INFO, TRUE, TRUE, argc, argv);
+ set_crm_log_level(LOG_INFO);
+ crm_system_name = "stonith-ng";
crm_set_options("V?s$", "mode [options]", long_options,
"Provides a summary of cluster's current state."
"\n\nOutputs varying levels of detail in a number of different formats.\n");
while (1) {
flag = crm_get_option(argc, argv, &option_index);
if (flag == -1)
break;
switch(flag) {
case 'V':
alter_debug(DEBUG_INC);
cl_log_enable_stderr(1);
break;
case 's':
stand_alone = TRUE;
cl_log_enable_stderr(1);
break;
case '$':
case '?':
crm_help(flag, LSB_EXIT_OK);
break;
default:
++argerr;
break;
}
}
if(argc - optind == 1 && safe_str_eq("metadata", argv[optind])) {
/* TODO: Cleanup */;
printf("<?xml version=\"1.0\"?><!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n");
printf("<resource-agent name=\"stonithd\">\n");
printf("<version>1.0</version>\n");
printf("<longdesc lang=\"en\">This is a fake resource that details the instance attributes handled by stonithd.</longdesc>\n");
printf("<shortdesc lang=\"en\">stonithd Options</shortdesc>\n");
printf("<parameters>\n");
printf("<parameter name=\"stonith-timeout\" unique=\"0\">\n");
printf("<shortdesc lang=\"en\">How long to wait for the STONITH action to complete. Overrides the stonith-timeout cluster property</shortdesc>\n");
printf("<content type=\"time\" default=\"60s\"/>\n");
printf("<longdesc lang=\"en\">How long to wait for the STONITH action to complete. Overrides the stonith-timeout cluster property</longdesc>\n");
printf("</parameter>\n");
printf("<parameter name=\"priority\" unique=\"0\">\n");
printf("<shortdesc lang=\"en\">The priority of the stonith resource. The lower the number, the higher the priority.</shortdesc>\n");
printf("<content type=\"integer\" default=\"0\"/>\n");
printf("<longdesc lang=\"en\">The priority of the stonith resource. The lower the number, the higher the priority.</longdesc>\n");
printf("</parameter>\n");
printf("</parameters>\n");
printf("</resource-agent>\n");
return 0;
}
- if (optind > argc) {
+ if (optind != argc) {
++argerr;
}
if (argerr) {
crm_help('?', LSB_EXIT_GENERIC);
}
+ crm_log_init("stonith-ng", crm_log_level, TRUE, TRUE, argc, argv);
mainloop_add_signal(SIGTERM, stonith_shutdown);
/* EnableProcLogging(); */
set_sigchld_proctrack(G_PRIORITY_HIGH,DEFAULT_MAXDISPATCHTIME);
crm_peer_init();
client_list = g_hash_table_new(g_str_hash, g_str_equal);
if(stand_alone == FALSE) {
void *dispatch = stonith_peer_hb_callback;
void *destroy = stonith_peer_hb_destroy;
if(is_openais_cluster()) {
#if SUPPORT_AIS
destroy = stonith_peer_ais_destroy;
dispatch = stonith_peer_ais_callback;
#endif
}
if(crm_cluster_connect(&stonith_our_uname, NULL, dispatch, destroy,
#if SUPPORT_HEARTBEAT
&hb_conn
#else
NULL
#endif
) == FALSE){
crm_crit("Cannot sign in to the cluster... terminating");
exit(100);
}
} else {
stonith_our_uname = crm_strdup("localhost");
}
channel1 = crm_strdup(stonith_channel);
rc = init_server_ipc_comms(
channel1, stonith_client_connect,
default_ipc_connection_destroy);
channel2 = crm_strdup(stonith_channel_callback);
rc = init_server_ipc_comms(
channel2, stonith_client_connect,
default_ipc_connection_destroy);
if(rc == 0) {
/* Create the mainloop and run it... */
mainloop = g_main_new(FALSE);
crm_info("Starting %s mainloop", crm_system_name);
g_main_run(mainloop);
} else {
crm_err("Couldnt start all communication channels, exiting.");
}
stonith_cleanup();
#if SUPPORT_HEARTBEAT
if(hb_conn) {
hb_conn->llc_ops->delete(hb_conn);
}
#endif
crm_info("Done");
return rc;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Wed, Jun 4, 6:18 AM (6 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1842381
Default Alt Text
(17 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment