Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F3687514
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
242 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/crm/cib/callbacks.c b/crm/cib/callbacks.c
index 745770b130..0e5572ece2 100644
--- a/crm/cib/callbacks.c
+++ b/crm/cib/callbacks.c
@@ -1,1393 +1,1393 @@
-/* $Id: callbacks.c,v 1.71 2005/06/28 08:11:07 andrew Exp $ */
+/* $Id: callbacks.c,v 1.72 2005/07/03 22:15:49 alan Exp $ */
/*
* 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.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 <portability.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 <hb_api.h>
#include <clplumbing/uids.h>
#include <clplumbing/cl_uuid.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/ipc.h>
#include <crm/common/ctrl.h>
#include <crm/common/xml.h>
#include <crm/common/msg.h>
#include <cibio.h>
#include <callbacks.h>
#include <cibmessages.h>
#include <notify.h>
#include <crm/dmalloc_wrapper.h>
gint cib_GCompareFunc(gconstpointer a, gconstpointer b);
gboolean cib_msg_timeout(gpointer data);
void cib_GHFunc(gpointer key, gpointer value, gpointer user_data);
gboolean ghash_str_clfree(gpointer key, gpointer value, gpointer user_data);
gboolean can_write(int flags);
HA_Message *cib_msg_copy(const HA_Message *msg, gboolean with_data);
gboolean ccm_manual_check(gpointer data);
extern enum cib_errors revision_check(crm_data_t *cib_update, crm_data_t *cib_copy, int flags);
void send_cib_replace(const HA_Message *sync_request, const char *host);
void cib_process_request(const HA_Message *request, gboolean privileged,
gboolean from_peer, cib_client_t *cib_client);
gboolean syncd_once = FALSE;
GHashTable *peer_hash = NULL;
int next_client_id = 0;
gboolean cib_is_master = FALSE;
gboolean cib_have_quorum = FALSE;
char * ccm_transition_id = NULL;
GHashTable *client_list = NULL;
GHashTable *ccm_membership = NULL;
extern const char *cib_our_uname;
extern ll_cluster_t *hb_conn;
extern int set_connected_peers(crm_data_t *xml_obj);
/*
typedef struct cib_operation_s
{
const char* operation;
gboolean modifies_cib;
gboolean needs_privileges;
gboolean needs_quorum;
gboolean needs_section;
gboolean needs_data;
enum cib_errors (*fn)(
const char *, int, const char *,
crm_data_t*, crm_data_t*, crm_data_t**, crm_data_t**);
} cib_operation_t;
*/
/* technically bump does modify the cib...
* but we want to split the "bump" from the "sync"
*/
cib_operation_t cib_server_ops[] = {
{NULL, FALSE,FALSE,FALSE,FALSE,FALSE,cib_process_default},
{CRM_OP_NOOP, FALSE,FALSE,FALSE,FALSE,FALSE,cib_process_default},
{CIB_OP_APPLY_DIFF,TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_diff},
{CIB_OP_SLAVE, FALSE,TRUE, FALSE,FALSE,FALSE,cib_process_readwrite},
{CIB_OP_SLAVEALL, TRUE, TRUE, FALSE,FALSE,FALSE,cib_process_readwrite},
{CIB_OP_SYNC_ONE, FALSE,TRUE, FALSE,TRUE, FALSE,cib_process_sync_one},
{CIB_OP_MASTER, FALSE,TRUE, FALSE,FALSE,FALSE,cib_process_readwrite},
{CIB_OP_ISMASTER, FALSE,TRUE, FALSE,FALSE,FALSE,cib_process_readwrite},
{CIB_OP_BUMP, TRUE, TRUE, TRUE, TRUE, FALSE,cib_process_bump},
{CIB_OP_REPLACE, TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_replace},
{CIB_OP_CREATE, TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_modify},
{CIB_OP_UPDATE, TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_modify},
{CIB_OP_DELETE, TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_delete},
{CIB_OP_DELETE_ALT,TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_modify},
{CIB_OP_QUERY, FALSE,FALSE,FALSE,TRUE, FALSE,cib_process_query},
{CIB_OP_SYNC, FALSE,TRUE, FALSE,TRUE, FALSE,cib_process_sync},
{CRM_OP_QUIT, FALSE,TRUE, FALSE,FALSE,FALSE,cib_process_quit},
{CRM_OP_PING, FALSE,FALSE,FALSE,FALSE,FALSE,cib_process_ping},
{CIB_OP_ERASE, TRUE, TRUE, TRUE, TRUE, FALSE,cib_process_erase}
};
int send_via_callback_channel(HA_Message *msg, const char *token);
enum cib_errors cib_process_command(
const HA_Message *request, HA_Message **reply,
crm_data_t **cib_diff, gboolean privileged);
gboolean cib_common_callback(
IPC_Channel *channel, gpointer user_data, gboolean privileged);
enum cib_errors cib_get_operation_id(const HA_Message * msg, int *operation);
gboolean cib_process_disconnect(IPC_Channel *channel, cib_client_t *cib_client);
gboolean
cib_client_connect(IPC_Channel *channel, gpointer user_data)
{
gboolean auth_failed = FALSE;
gboolean can_connect = TRUE;
gboolean (*client_callback)(IPC_Channel *channel, gpointer user_data) = NULL;
cib_client_t *new_client = NULL;
crm_debug_3("Connecting channel");
if (channel == NULL) {
crm_err("Channel was NULL");
can_connect = FALSE;
} else if (channel->ch_status == IPC_DISCONNECT) {
crm_err("Channel was disconnected");
can_connect = FALSE;
} else if(user_data == NULL) {
crm_err("user_data must contain channel name");
can_connect = FALSE;
} else {
crm_malloc0(new_client, sizeof(cib_client_t));
new_client->id = NULL;
new_client->callback_id = NULL;
new_client->source = NULL;
new_client->channel = channel;
new_client->channel_name = user_data;
new_client->delegated_calls = NULL;
crm_debug_3("Created channel %p for channel %s",
new_client, new_client->channel_name);
client_callback = NULL;
/* choose callback and do auth based on channel_name */
if(safe_str_eq(new_client->channel_name, cib_channel_callback)) {
client_callback = cib_null_callback;
} else {
cl_uuid_t client_id;
cl_uuid_generate(&client_id);
crm_malloc0(new_client->id, sizeof(char)*36);
cl_uuid_unparse(&client_id, new_client->id);
new_client->id[35] = EOS;
cl_uuid_generate(&client_id);
crm_malloc0(new_client->callback_id, sizeof(char)*36);
cl_uuid_unparse(&client_id, new_client->callback_id);
new_client->callback_id[35] = EOS;
client_callback = cib_ro_callback;
if(safe_str_eq(new_client->channel_name, cib_channel_rw)) {
client_callback = cib_rw_callback;
}
}
}
if(auth_failed) {
crm_err("Connection to %s channel failed authentication",
(char *)user_data);
can_connect = FALSE;
}
if(can_connect == FALSE) {
if(new_client) {
crm_free(new_client->id);
crm_free(new_client->callback_id);
}
crm_free(new_client);
return FALSE;
}
channel->ops->set_recv_qlen(channel, 100);
if(safe_str_eq(new_client->channel_name, cib_channel_callback)) {
channel->ops->set_send_qlen(channel, 400);
} else {
channel->ops->set_send_qlen(channel, 100);
}
if(client_callback != NULL) {
new_client->source = G_main_add_IPC_Channel(
G_PRIORITY_LOW, channel, FALSE, client_callback,
new_client, default_ipc_connection_destroy);
}
if(client_callback != cib_null_callback) {
/* send msg to client with uuid to use when signing up for
* callback channel
*/
HA_Message *reg_msg = ha_msg_new(3);
ha_msg_add(reg_msg, F_CIB_OPERATION, CRM_OP_REGISTER);
ha_msg_add(reg_msg, F_CIB_CLIENTID, new_client->id);
ha_msg_add(
reg_msg, F_CIB_CALLBACK_TOKEN, new_client->callback_id);
send_ipc_message(channel, reg_msg);
/* 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);
}
crm_debug_3("Channel %s connected for client %s",
new_client->channel_name, new_client->id);
return TRUE;
}
gboolean
cib_rw_callback(IPC_Channel *channel, gpointer user_data)
{
return cib_common_callback(channel, user_data, TRUE);
}
gboolean
cib_ro_callback(IPC_Channel *channel, gpointer user_data)
{
return cib_common_callback(channel, user_data, FALSE);
}
gboolean
cib_null_callback(IPC_Channel *channel, gpointer user_data)
{
gboolean did_disconnect = TRUE;
HA_Message *op_request = NULL;
cib_client_t *cib_client = user_data;
cib_client_t *hash_client = NULL;
const char *type = NULL;
const char *uuid_ticket = NULL;
const char *client_name = NULL;
gboolean register_failed = FALSE;
if(cib_client == NULL) {
crm_err("Discarding IPC message from unknown source"
" on callback channel.");
return FALSE;
}
while(channel->ops->is_message_pending(channel)) {
if (channel->ch_status != IPC_CONNECT) {
/* The message which was pending for us is that
* the channel is no longer fully connected.
*
* Dont read requests from disconnected clients
*/
break;
}
op_request = msgfromIPC_noauth(channel);
type = cl_get_string(op_request, F_CIB_OPERATION);
if(safe_str_eq(type, T_CIB_NOTIFY) ) {
/* Update the notify filters for this client */
int on_off = 0;
ha_msg_value_int(
op_request, F_CIB_NOTIFY_ACTIVATE, &on_off);
type = cl_get_string(op_request, F_CIB_NOTIFY_TYPE);
if(safe_str_eq(type, T_CIB_POST_NOTIFY)) {
cib_client->post_notify = on_off;
} else if(safe_str_eq(type, T_CIB_PRE_NOTIFY)) {
cib_client->pre_notify = on_off;
} else if(safe_str_eq(type, T_CIB_UPDATE_CONFIRM)) {
cib_client->confirmations = on_off;
} else if(safe_str_eq(type, T_CIB_DIFF_NOTIFY)) {
cib_client->diffs = on_off;
}
continue;
} else if(safe_str_neq(type, CRM_OP_REGISTER) ) {
crm_warn("Discarding IPC message from %s on callback channel",
cib_client->id);
crm_msg_del(op_request);
continue;
}
uuid_ticket = cl_get_string(op_request, F_CIB_CALLBACK_TOKEN);
client_name = cl_get_string(op_request, F_CIB_CLIENTNAME);
CRM_DEV_ASSERT(uuid_ticket != NULL);
if(crm_assert_failed) {
register_failed = crm_assert_failed;
}
CRM_DEV_ASSERT(client_name != NULL);
if(crm_assert_failed) {
register_failed = crm_assert_failed;
}
if(register_failed == FALSE) {
hash_client = g_hash_table_lookup(client_list, uuid_ticket);
if(hash_client != NULL) {
crm_err("Duplicate registration request..."
" disconnecting");
register_failed = TRUE;
}
}
if(register_failed) {
crm_err("Registration request failed... disconnecting");
crm_msg_del(op_request);
return FALSE;
}
cib_client->id = crm_strdup(uuid_ticket);
cib_client->name = crm_strdup(client_name);
g_hash_table_insert(client_list, cib_client->id, cib_client);
crm_debug_2("Registered %s on %s channel",
cib_client->id, cib_client->channel_name);
crm_msg_del(op_request);
op_request = ha_msg_new(2);
ha_msg_add(op_request, F_CIB_OPERATION, CRM_OP_REGISTER);
ha_msg_add(op_request, F_CIB_CLIENTID, cib_client->id);
send_ipc_message(channel, op_request);
}
did_disconnect = cib_process_disconnect(channel, cib_client);
if(did_disconnect) {
crm_debug_2("Client disconnected");
}
return did_disconnect;
}
gboolean
cib_common_callback(
IPC_Channel *channel, gpointer user_data, gboolean privileged)
{
int rc = cib_ok;
int lpc = 0;
HA_Message *op_request = NULL;
cib_client_t *cib_client = user_data;
if(cib_client == NULL) {
crm_err("Receieved call from unknown source. Discarding.");
return FALSE;
}
crm_debug_2("Callback for %s on %s channel",
cib_client->id, cib_client->channel_name);
while(channel->ops->is_message_pending(channel)) {
if (channel->ch_status != IPC_CONNECT) {
/* The message which was pending for us is that
* the channel is no longer fully connected.
*
* Dont read requests from disconnected clients
*/
break;
}
op_request = msgfromIPC(channel, 0);
if (op_request == NULL) {
perror("Receive failure:");
break;
}
crm_debug_2("Processing IPC message from %s on %s channel",
cib_client->id, cib_client->channel_name);
crm_log_message_adv(LOG_MSG, "Client[inbound]", op_request);
lpc++;
rc = cib_ok;
CRM_DEV_ASSERT(
ha_msg_add(op_request, F_CIB_CLIENTID, cib_client->id) == HA_OK);
if(crm_assert_failed == FALSE) {
cib_process_request(
op_request, privileged, FALSE, cib_client);
}
crm_debug_3("Cleaning up request");
crm_msg_del(op_request);
op_request = NULL;
}
crm_debug_2("Processed %d messages", lpc);
return cib_process_disconnect(channel, cib_client);
}
void
cib_process_request(const HA_Message *request, gboolean privileged,
gboolean from_peer, cib_client_t *cib_client)
{
int call_type = 0;
int call_options = 0;
gboolean process = TRUE;
gboolean needs_reply = TRUE;
gboolean local_notify = FALSE;
gboolean needs_forward = FALSE;
crm_data_t *result_diff = NULL;
enum cib_errors rc = cib_ok;
HA_Message *op_reply = NULL;
const char *op = cl_get_string(request, F_CIB_OPERATION);
const char *originator = cl_get_string(request, F_ORIG);
const char *host = cl_get_string(request, F_CIB_HOST);
const char *reply_to = cl_get_string(request, F_CIB_ISREPLY);
const char *update = cl_get_string(request, F_CIB_GLOBAL_UPDATE);
const char *delegated = cl_get_string(request, F_CIB_DELEGATED);
const char *client_id = NULL;
crm_debug_4("%s Processing msg %s",
cib_our_uname, cl_get_string(request, F_SEQ));
if(host != NULL && strlen(host) == 0) {
host = NULL;
}
ha_msg_value_int(request, F_CIB_CALLOPTS, &call_options);
crm_debug_4("Retrieved call options: %d", call_options);
crm_debug_2("Processing %s message (%s) to %s...",
from_peer?"peer":"local",originator, host?host:"master");
rc = cib_get_operation_id(request, &call_type);
if(rc != cib_ok) {
/* TODO: construct error reply */
crm_err("Pre-processing of command failed: %s",
cib_error2string(rc));
} else if(from_peer == FALSE) {
needs_reply = FALSE;
if(host == NULL && (call_options & cib_scope_local)) {
crm_debug("Processing locally scoped %s op from %s",
op, cib_client->name);
local_notify = TRUE;
} else if(host == NULL && cib_is_master) {
crm_debug("Processing master %s op locally from %s",
op, cib_client->name);
local_notify = TRUE;
} else if(safe_str_eq(host, cib_our_uname)) {
crm_debug("Processing locally addressed %s op from %s",
op, cib_client->name);
local_notify = TRUE;
} else {
crm_debug("%s op from %s needs to be forwarded to %s",
op, cib_client->name,
host?host:"the master instance");
needs_forward = TRUE;
process = FALSE;
}
} else if(crm_is_true(update) && safe_str_eq(reply_to, cib_our_uname)) {
crm_debug("Processing global/peer update from %s"
" that originated from us", originator);
needs_reply = FALSE;
local_notify = TRUE;
} else if(crm_is_true(update)) {
crm_debug("Processing global/peer update from %s", originator);
needs_reply = FALSE;
} else if(host != NULL && safe_str_eq(host, cib_our_uname)) {
crm_debug("Processing request sent to us from %s", originator);
} else if(delegated != NULL && cib_is_master == TRUE) {
crm_debug("Processing request sent to master instance from %s",
originator);
} else if(reply_to != NULL && safe_str_eq(reply_to, cib_our_uname)) {
crm_debug("Forward reply sent from %s to local clients",
originator);
process = FALSE;
needs_reply = FALSE;
local_notify = TRUE;
} else if(delegated != NULL) {
crm_debug_2("Ignoring msg for master instance");
return;
} else if(host != NULL) {
/* this is for a specific instance and we're not it */
crm_debug_2("Ignoring msg for instance on %s", crm_str(host));
return;
} else if(reply_to == NULL && cib_is_master == FALSE) {
/* this is for the master instance and we're not it */
crm_debug_2("Ignoring reply to %s", crm_str(reply_to));
return;
} else {
crm_err("Nothing for us to do?");
crm_log_message_adv(LOG_ERR, "Peer[inbound]", request);
return;
}
crm_debug_3("Finished determining processing actions");
if(call_options & cib_discard_reply) {
needs_reply = cib_server_ops[call_type].modifies_cib;
local_notify = FALSE;
}
if(needs_forward) {
HA_Message *forward_msg = cib_msg_copy(request, TRUE);
ha_msg_add(forward_msg, F_CIB_DELEGATED, cib_our_uname);
crm_log_message(LOG_MSG, forward_msg);
if(host != NULL) {
crm_debug("Forwarding %s op to %s", op, host);
send_ha_message(hb_conn, forward_msg, host);
} else {
crm_debug("Forwarding %s op to master instance", op);
send_ha_message(hb_conn, forward_msg, NULL);
}
if(call_options & cib_discard_reply) {
crm_debug_2("Client not interested in reply");
crm_msg_del(forward_msg);
} else if(call_options & cib_sync_call) {
/* keep track of the request so we can time it
* out if required
*/
crm_debug("Registering delegated call from %s",
cib_client->id);
cib_client->delegated_calls = g_list_append(
cib_client->delegated_calls, forward_msg);
} else {
crm_msg_del(forward_msg);
}
return;
}
if(process) {
crm_debug_3("Performing local processing:"
" op=%s origin=%s/%s,%s (update=%s)",
cl_get_string(request, F_CIB_OPERATION), originator,
cl_get_string(request, F_CIB_CLIENTID),
cl_get_string(request, F_CIB_CALLID), update);
rc = cib_process_command(request, &op_reply, &result_diff, TRUE);
crm_debug_3("Processing complete");
if(rc == cib_diff_resync || rc == cib_diff_failed
|| rc == cib_old_data) {
crm_warn("%s operation failed: %s",
crm_str(op), cib_error2string(rc));
} else if(rc != cib_ok) {
crm_err("%s operation failed: %s",
crm_str(op), cib_error2string(rc));
crm_log_message_adv(LOG_DEBUG, "CIB[output]", op_reply);
crm_debug("Input message");
crm_log_message(LOG_DEBUG, request);
}
if(op_reply == NULL && (needs_reply || local_notify)) {
crm_err("Unexpected NULL reply to message");
crm_log_message(LOG_ERR, request);
needs_reply = FALSE;
local_notify = FALSE;
}
}
crm_debug_3("processing response cases");
if(local_notify) {
/* send callback to originating child */
cib_client_t *client_obj = NULL;
HA_Message *client_reply = NULL;
enum cib_errors local_rc = cib_ok;
crm_debug_4("find the client");
if(process == FALSE) {
client_reply = cib_msg_copy(request, TRUE);
} else {
client_reply = cib_msg_copy(op_reply, TRUE);
}
client_id = cl_get_string(request, F_CIB_CLIENTID);
if(client_id != NULL) {
client_obj = g_hash_table_lookup(
client_list, client_id);
} else {
crm_debug("No client to sent the response to."
" F_CIB_CLIENTID not set.");
}
crm_debug_3("Sending callback to request originator");
if(client_obj != NULL) {
crm_debug_2("Sending %ssync response to %s %s",
(call_options & cib_sync_call)?"":"an a-",
client_obj->id,
from_peer?"(originator of delegated request)":"");
if(call_options & cib_sync_call) {
send_via_callback_channel(
client_reply, client_obj->id);
} else {
send_via_callback_channel(
client_reply, client_obj->callback_id);
}
} else {
crm_warn("Client %s may have left us",
crm_str(client_id));
crm_msg_del(client_reply);
}
if(local_rc != cib_ok) {
crm_warn("%sSync reply failed: %s",
(call_options & cib_sync_call)?"":"A-",
cib_error2string(local_rc));
crm_log_message(LOG_DEBUG, op_reply);
}
}
if(needs_reply == FALSE) {
/* nothing more to do...
* this was a non-originating slave update
*/
crm_debug_3("Completed slave update");
crm_msg_del(op_reply);
free_xml(result_diff);
return;
}
crm_debug_4("add the originator to message");
CRM_DEV_ASSERT(op_reply != NULL);
CRM_DEV_ASSERT(cib_server_ops[call_type].modifies_cib == FALSE
|| result_diff != NULL || rc != cib_ok);
/* from now on we are the server */
if(rc == cib_ok
&& result_diff != NULL
&& cib_server_ops[call_type].modifies_cib
&& !(call_options & cib_inhibit_bcast)) {
/* this (successful) call modified the CIB _and_ the
* change needs to be broadcast...
* send via HA to other nodes
*/
HA_Message *op_bcast = cib_msg_copy(request, FALSE);
crm_debug_2("Sending update diff to everyone");
ha_msg_add(op_bcast, F_CIB_ISREPLY, originator);
ha_msg_add(op_bcast, F_CIB_GLOBAL_UPDATE, XML_BOOLEAN_TRUE);
ha_msg_mod(op_bcast, F_CIB_OPERATION, CIB_OP_APPLY_DIFF);
add_message_xml(op_bcast, F_CIB_UPDATE_DIFF, result_diff);
crm_log_message(LOG_DEBUG_3, op_bcast);
send_ha_message(hb_conn, op_bcast, NULL);
crm_msg_del(op_bcast);
} else if((call_options & cib_discard_reply) == 0) {
if(from_peer && originator != NULL) {
/* send reply via HA to originating node */
crm_debug("Sending request result to originator only");
ha_msg_add(op_reply, F_CIB_ISREPLY, originator);
send_ha_message(hb_conn, op_reply, originator);
}
if(call_options & cib_inhibit_bcast ) {
crm_debug("Request not broadcast: inhibited");
}
if(cib_server_ops[call_type].modifies_cib == FALSE) {
crm_debug_2("Request not broadcast: R/O call");
}
if(rc != cib_ok) {
crm_warn("Request not broadcast: call failed: %s",
cib_error2string(rc));
}
}
crm_msg_del(op_reply);
free_xml(result_diff);
return;
}
enum cib_errors
cib_process_command(const HA_Message *request, HA_Message **reply,
crm_data_t **cib_diff, gboolean privileged)
{
crm_data_t *output = NULL;
crm_data_t *input = NULL;
crm_data_t *input_fragment = NULL;
crm_data_t *current_cib = the_cib;
crm_data_t *result_cib = NULL;
crm_data_t *local_diff = NULL;
int call_type = 0;
int call_options = 0;
enum cib_errors rc = cib_ok;
const char *op = NULL;
const char *call_id = NULL;
const char *section = NULL;
const char *tmp = NULL;
gboolean global_update = crm_is_true(
cl_get_string(request, F_CIB_GLOBAL_UPDATE));
CRM_DEV_ASSERT(reply != NULL);
if(reply) { *reply = NULL; }
/* Start processing the request... */
op = cl_get_string(request, F_CIB_OPERATION);
call_id = cl_get_string(request, F_CIB_CALLID);
ha_msg_value_int(request, F_CIB_CALLOPTS, &call_options);
crm_debug_4("Processing call id: %s", call_id);
rc = cib_get_operation_id(request, &call_type);
if(rc == cib_ok &&
cib_server_ops[call_type].needs_privileges
&& privileged == FALSE) {
/* abort */
rc = cib_not_authorized;
}
if(rc == cib_ok
&& global_update == FALSE
&& cib_server_ops[call_type].needs_quorum
&& can_write(call_options) == FALSE) {
rc = cib_no_quorum;
}
/* prevent NUMUPDATES from being incrimented - apply the change as-is */
if(global_update) {
call_options |= cib_inhibit_bcast;
}
if(rc == cib_ok && cib_server_ops[call_type].needs_section) {
section = cl_get_string(request, F_CIB_SECTION);
}
if(rc == cib_ok && safe_str_eq(op, CIB_OP_APPLY_DIFF)) {
crm_debug_4("Unpacking diff data in %s", F_CIB_UPDATE_DIFF);
input_fragment = get_message_xml(request, F_CIB_UPDATE_DIFF);
if(global_update) {
call_options |= cib_force_diff;
}
} else if(rc == cib_ok && safe_str_eq(op, CIB_OP_SYNC)) {
input_fragment = ha_msg_copy(request);
} else if(rc == cib_ok && safe_str_eq(op, CIB_OP_SYNC_ONE)) {
input_fragment = ha_msg_copy(request);
} else if(rc == cib_ok && cib_server_ops[call_type].needs_data) {
crm_debug_4("Unpacking data in %s", F_CIB_CALLDATA);
input_fragment = get_message_xml(request, F_CIB_CALLDATA);
}
/* extract the CIB from the fragment */
if(input_fragment != NULL
&& safe_str_eq(crm_element_name(input_fragment), XML_TAG_FRAGMENT)) {
input = find_xml_node(input_fragment, XML_TAG_CIB, TRUE);
} else {
input = input_fragment;
}
/* grab the section specified for the command */
if(input != NULL && safe_str_eq(crm_element_name(input), XML_TAG_CIB)){
rc = revision_check(input, current_cib, call_options);
if(rc == cib_ok) {
input = get_object_root(section, input);
}
}
if(cib_server_ops[call_type].modifies_cib) {
cib_pre_notify(
call_options, op,
get_object_root(section, current_cib), input);
}
if(rc == cib_ok) {
rc = cib_server_ops[call_type].fn(
op, call_options, section, input,
current_cib, &result_cib, &output);
}
if(cib_server_ops[call_type].modifies_cib) {
if(safe_str_eq(op, CIB_OP_APPLY_DIFF)) {
local_diff = copy_xml(input);
} else if(result_cib != NULL && current_cib != result_cib) {
local_diff = diff_cib_object(
current_cib, result_cib, FALSE);
}
if(rc != cib_ok) {
free_xml(result_cib);
} else if(activateCibXml(result_cib,CIB_FILENAME) < 0){
crm_warn("Activation failed");
rc = cib_ACTIVATION;
}
cib_post_notify(call_options, op, input, rc, the_cib);
cib_diff_notify(call_options, op, input, rc, local_diff);
} else if(result_cib != NULL) {
crm_err("%s call modified the CIB", op);
free_xml(result_cib);
}
crm_debug_4("Processing reply cases");
if((call_options & cib_discard_reply)
&& cib_server_ops[call_type].modifies_cib == FALSE) {
crm_debug_3("No reply needed for call %s", call_id);
return rc;
} else if(reply == NULL) {
crm_debug("No reply possible for call %s", call_id);
return rc;
}
crm_debug_4("Creating a basic reply");
*reply = ha_msg_new(8);
ha_msg_add(*reply, F_TYPE, T_CIB);
ha_msg_add(*reply, F_CIB_OPERATION, op);
ha_msg_add(*reply, F_CIB_CALLID, call_id);
ha_msg_add_int(*reply, F_CIB_RC, rc);
tmp = cl_get_string(request, F_CIB_CLIENTID);
ha_msg_add(*reply, F_CIB_CLIENTID, tmp);
tmp = cl_get_string(request, F_CIB_CALLOPTS);
ha_msg_add(*reply, F_CIB_CALLOPTS, tmp);
crm_debug_4("Attaching output if necessary");
if(output != NULL) {
add_message_xml(*reply, F_CIB_CALLDATA, output);
} else {
crm_debug_3("No output for call %s", call_id);
}
crm_debug_4("Cleaning up");
if(cib_diff != NULL) {
*cib_diff = local_diff;
} else {
free_xml(local_diff);
}
free_xml(output);
free_xml(input_fragment);
return rc;
}
int
send_via_callback_channel(HA_Message *msg, const char *token)
{
cib_client_t *hash_client = NULL;
GList *list_item = NULL;
enum cib_errors rc = cib_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 == cib_ok) {
rc = cib_missing;
}
} 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 = cib_client_gone;
} else if(hash_client->channel == NULL) {
crm_err("Cannot find channel for client %s", token);
rc = cib_client_corrupt;
} else if(hash_client->channel->ops->get_chan_status(
hash_client->channel) != IPC_CONNECT) {
crm_warn("Client %s has disconnected", token);
rc = cib_client_gone;
}
}
/* this is a more important error so overwriting rc is warrented */
if(msg == NULL) {
crm_err("No message to send");
rc = cib_reply_failed;
}
if(rc == cib_ok) {
list_item = g_list_find_custom(
hash_client->delegated_calls, msg, cib_GCompareFunc);
}
if(list_item != NULL) {
/* remove it - no need to time it out */
HA_Message *orig_msg = list_item->data;
crm_debug_3("Removing msg from delegated list");
hash_client->delegated_calls = g_list_remove(
hash_client->delegated_calls, orig_msg);
CRM_DEV_ASSERT(orig_msg != msg);
crm_msg_del(orig_msg);
}
if(rc == cib_ok) {
crm_debug_3("Delivering reply to client %s", token);
if(send_ipc_message(hash_client->channel, msg) == FALSE) {
crm_warn("Delivery of reply to client %s/%s failed",
hash_client->name, token);
rc = cib_reply_failed;
}
} else {
/* be consistent...
* send_ipc_message() will free the message, so we should do
* so manually if we dont try to send it.
*/
crm_msg_del(msg);
}
return rc;
}
gint cib_GCompareFunc(gconstpointer a, gconstpointer b)
{
const HA_Message *a_msg = a;
const HA_Message *b_msg = b;
int msg_a_id = 0;
int msg_b_id = 0;
ha_msg_value_int(a_msg, F_CIB_CALLID, &msg_a_id);
ha_msg_value_int(b_msg, F_CIB_CALLID, &msg_b_id);
if(msg_a_id == msg_b_id) {
return 0;
} else if(msg_a_id < msg_b_id) {
return -1;
}
return 1;
}
gboolean
cib_msg_timeout(gpointer data)
{
crm_debug_4("Checking if any clients have timed out messages");
g_hash_table_foreach(client_list, cib_GHFunc, NULL);
return TRUE;
}
void
cib_GHFunc(gpointer key, gpointer value, gpointer user_data)
{
cib_client_t *client = value;
GListPtr list = client->delegated_calls;
HA_Message *msg = NULL;
while(list != NULL) {
int seen = 0;
int timeout = 5; /* 1 iteration == 1 seconds */
HA_Message *reply = NULL;
const char *host_to = NULL;
msg = list->data;
ha_msg_value_int(msg, F_CIB_SEENCOUNT, &seen);
ha_msg_value_int(msg, F_CIB_TIMEOUT, &timeout);
host_to = cl_get_string(msg, F_CIB_HOST);
crm_debug_4("Timeout %d, seen %d", timeout, seen);
if(timeout > 0 && seen < timeout) {
int seen2 = 0;
crm_debug_4("Updating seen count for msg from client %s",
client->id);
seen++;
ha_msg_mod_int(msg, F_CIB_SEENCOUNT, seen);
ha_msg_value_int(msg, F_CIB_SEENCOUNT, &seen2);
list = list->next;
continue;
}
crm_warn("Sending operation timeout msg to client %s",
client->id);
reply = ha_msg_new(4);
ha_msg_add(reply, F_TYPE, T_CIB);
ha_msg_add(reply, F_CIB_OPERATION,
cl_get_string(msg, F_CIB_OPERATION));
ha_msg_add(reply, F_CIB_CALLID,
cl_get_string(msg, F_CIB_CALLID));
if(host_to == NULL) {
ha_msg_add_int(reply, F_CIB_RC, cib_master_timeout);
} else {
ha_msg_add_int(reply, F_CIB_RC, cib_remote_timeout);
}
send_ipc_message(client->channel, reply);
list = list->next;
client->delegated_calls = g_list_remove(
client->delegated_calls, msg);
crm_msg_del(msg);
}
}
gboolean
cib_process_disconnect(IPC_Channel *channel, cib_client_t *cib_client)
{
if (channel->ch_status != IPC_CONNECT && cib_client != NULL) {
crm_info("Cleaning up after %s channel disconnect from client (%p) %s/%s",
cib_client->channel_name, cib_client,
crm_str(cib_client->id), crm_str(cib_client->name));
if(cib_client->id != NULL) {
g_hash_table_remove(client_list, cib_client->id);
}
if(cib_client->source != NULL) {
crm_debug_3("deleting the IPC Channel");
G_main_del_IPC_Channel(cib_client->source);
cib_client->source = NULL;
}
crm_debug_3("Freeing the cib client %s", crm_str(cib_client->id));
#if 0
/* todo - put this back in once i recheck its safe */
crm_free(cib_client->callback_id);
crm_free(cib_client->name);
crm_free(cib_client->id);
#endif
crm_free(cib_client);
crm_debug_3("Freed the cib client");
return FALSE;
} else if (channel->ch_status != IPC_CONNECT) {
crm_warn("Unknown client disconnected");
return FALSE;
}
return TRUE;
}
gboolean
cib_ha_dispatch(IPC_Channel *channel, gpointer user_data)
{
int lpc = 0;
ll_cluster_t *hb_cluster = (ll_cluster_t*)user_data;
while(lpc < 2 && hb_cluster->llc_ops->msgready(hb_cluster)) {
lpc++;
/* invoke the callbacks but dont block */
hb_cluster->llc_ops->rcvmsg(hb_cluster, 0);
}
crm_debug_4("%d HA messages dispatched", lpc);
if (channel && (channel->ch_status != IPC_CONNECT)) {
crm_crit("Lost connection to heartbeat service... exiting");
exit(100);
return FALSE;
}
return TRUE;
}
void
cib_peer_callback(const HA_Message * msg, void* private_data)
{
int call_type = 0;
const char *originator = cl_get_string(msg, F_ORIG);
if(originator == NULL || safe_str_eq(originator, cib_our_uname)) {
crm_debug_3("Discarding message %s/%s from ourselves",
cl_get_string(msg, F_CIB_CLIENTID),
cl_get_string(msg, F_CIB_CALLID));
return;
} else if(ccm_membership == NULL) {
crm_debug_3("Discarding message %s/%s: membership not established",
originator, cl_get_string(msg, F_SEQ));
return;
} else if(g_hash_table_lookup(ccm_membership, originator) == NULL) {
crm_debug_3("Discarding message %s/%s: not in our membership",
originator, cl_get_string(msg, F_CIB_CALLID));
return;
} else if(cib_get_operation_id(msg, &call_type) != cib_ok) {
crm_err("Invalid operation... discarding msg %s",
cl_get_string(msg, F_SEQ));
return;
}
crm_debug_4("%s Processing msg %s",
cib_our_uname, cl_get_string(msg, F_SEQ));
cib_process_request(msg, TRUE, TRUE, NULL);
return;
}
HA_Message *
cib_msg_copy(const HA_Message *msg, gboolean with_data)
{
int lpc = 0;
const char *field = NULL;
const char *value = NULL;
const HA_Message *value_struct = NULL;
const char *field_list[] = {
F_TYPE ,
F_CIB_CLIENTID ,
F_CIB_CALLOPTS ,
F_CIB_CALLID ,
F_CIB_OPERATION ,
F_CIB_ISREPLY ,
F_CIB_SECTION ,
F_CIB_HOST ,
F_CIB_RC ,
F_CIB_DELEGATED ,
F_CIB_OBJID ,
F_CIB_OBJTYPE ,
F_CIB_EXISTING ,
F_CIB_SEENCOUNT ,
F_CIB_TIMEOUT ,
F_CIB_CALLBACK_TOKEN ,
F_CIB_GLOBAL_UPDATE ,
F_CIB_CLIENTNAME ,
F_CIB_NOTIFY_TYPE ,
F_CIB_NOTIFY_ACTIVATE
};
const char *data_list[] = {
F_CIB_CALLDATA ,
F_CIB_UPDATE ,
F_CIB_UPDATE_RESULT
};
HA_Message *copy = ha_msg_new(10);
if(copy == NULL) {
return copy;
}
for(lpc = 0; lpc < DIMOF(field_list); lpc++) {
field = field_list[lpc];
value = cl_get_string(msg, field);
if(value != NULL) {
ha_msg_add(copy, field, value);
}
}
for(lpc = 0; with_data && lpc < DIMOF(data_list); lpc++) {
field = data_list[lpc];
value_struct = cl_get_struct(msg, field);
if(value_struct != NULL) {
ha_msg_addstruct(copy, field, value_struct);
}
}
return copy;
}
enum cib_errors
cib_get_operation_id(const HA_Message * msg, int *operation)
{
int lpc = 0;
int max_msg_types = DIMOF(cib_server_ops);
const char *op = cl_get_string(msg, F_CIB_OPERATION);
for (lpc = 0; lpc < max_msg_types; lpc++) {
if (safe_str_eq(op, cib_server_ops[lpc].operation)) {
*operation = lpc;
return cib_ok;
}
}
crm_err("Operation %s is not valid", op);
*operation = -1;
return cib_operation;
}
void
cib_client_status_callback(const char * node, const char * client,
const char * status, void * private)
{
if(safe_str_eq(client, CRM_SYSTEM_CIB)) {
crm_debug_2("Status update: Client %s/%s now has status [%s]",
node, client, status);
g_hash_table_replace(peer_hash, crm_strdup(node), crm_strdup(status));
set_connected_peers(the_cib);
}
return;
}
extern oc_ev_t *cib_ev_token;
gboolean
ccm_manual_check(gpointer data)
{
int rc = 0;
oc_ev_t *ccm_token = cib_ev_token;
crm_debug("manual check");
rc = oc_ev_handle_event(ccm_token);
if(0 == rc) {
return TRUE;
} else {
crm_err("CCM connection appears to have failed: rc=%d.", rc);
return FALSE;
}
}
gboolean cib_ccm_dispatch(int fd, gpointer user_data)
{
int rc = 0;
oc_ev_t *ccm_token = (oc_ev_t*)user_data;
crm_debug("received callback");
rc = oc_ev_handle_event(ccm_token);
if(0 == rc) {
return TRUE;
} else {
crm_err("CCM connection appears to have failed: rc=%d.", rc);
return FALSE;
}
}
void
cib_ccm_msg_callback(
oc_ed_t event, void *cookie, size_t size, const void *data)
{
int instance = -1;
gboolean update_id = FALSE;
gboolean update_quorum = FALSE;
const oc_ev_membership_t *membership = data;
if(membership != NULL) {
instance = membership->m_instance;
}
crm_info("Process CCM event=%s (id=%d)",
ccm_event_name(event), instance);
switch(event) {
case OC_EV_MS_NEW_MEMBERSHIP:
case OC_EV_MS_INVALID:
update_id = TRUE;
update_quorum = TRUE;
break;
case OC_EV_MS_PRIMARY_RESTORED:
update_id = TRUE;
break;
case OC_EV_MS_NOT_PRIMARY:
crm_debug("Ignoring transitional CCM event: %s",
ccm_event_name(event));
break;
case OC_EV_MS_EVICTED:
crm_err("Evicted from CCM: %s", ccm_event_name(event));
update_quorum = TRUE;
break;
default:
crm_err("Unknown CCM event: %d", event);
}
if(update_id) {
CRM_DEV_ASSERT(membership != NULL);
if(crm_assert_failed) { return; }
if(ccm_transition_id != NULL) {
crm_free(ccm_transition_id);
ccm_transition_id = NULL;
}
ccm_transition_id = crm_itoa(instance);
set_transition(the_cib);
}
if(update_quorum) {
- int members = 0;
+ unsigned int members = 0;
int offset = 0;
- unsigned lpc = 0;
+ unsigned int lpc = 0;
cib_have_quorum = ccm_have_quorum(event);
if(cib_have_quorum) {
crm_xml_add(
the_cib,XML_ATTR_HAVE_QUORUM,XML_BOOLEAN_TRUE);
} else {
crm_xml_add(
the_cib,XML_ATTR_HAVE_QUORUM,XML_BOOLEAN_FALSE);
}
crm_info("Quorum %s after event=%s (id=%d)",
cib_have_quorum?"(re)attained":"lost",
ccm_event_name(event), instance);
if(ccm_membership != NULL) {
g_hash_table_foreach_remove(
ccm_membership, ghash_str_clfree, NULL);
}
ccm_membership = g_hash_table_new(g_str_hash, g_str_equal);
if(membership != NULL) {
members = membership->m_n_member;
offset = membership->m_memb_idx;
}
for(lpc = 0; lpc < members; lpc++) {
oc_node_t a_node = membership->m_array[lpc+offset];
char *uname = crm_strdup(a_node.node_uname);
g_hash_table_insert(
ccm_membership, uname, uname);
}
}
oc_ev_callback_done(cookie);
return;
}
gboolean
ghash_str_clfree(gpointer key, gpointer value, gpointer user_data)
{
if(key != NULL) {
crm_free(key);
}
return TRUE;
}
gboolean
can_write(int flags)
{
const char *value = NULL;
if(cib_have_quorum) {
return TRUE;
}
value = get_crm_option(the_cib, "no_quorum_policy", TRUE);
if(safe_str_eq(value, "ignore")) {
return TRUE;
}
if((flags & cib_quorum_override) != 0) {
crm_debug_2("Overriding \"no quorum\" condition");
return TRUE;
}
return FALSE;
}
diff --git a/crm/cib/cibmon.c b/crm/cib/cibmon.c
index e6c3c1304e..18cd66a7e4 100644
--- a/crm/cib/cibmon.c
+++ b/crm/cib/cibmon.c
@@ -1,473 +1,473 @@
-/* $Id: cibmon.c,v 1.27 2005/06/17 11:08:19 andrew Exp $ */
+/* $Id: cibmon.c,v 1.28 2005/07/03 22:15:49 alan Exp $ */
/*
* 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.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 <portability.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <hb_api.h>
#include <clplumbing/coredumps.h>
#include <clplumbing/uids.h>
#include <clplumbing/Gmain_timeout.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/ctrl.h>
#include <crm/common/ipc.h>
#include <crm/cib.h>
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#endif
#include <ha_msg.h> /* someone complaining about _ha_msg_mod not being found */
#include <crm/dmalloc_wrapper.h>
#define UPDATE_PREFIX "cib.updates:"
int exit_code = cib_ok;
int got_signal = 0;
GMainLoop *mainloop = NULL;
const char *crm_system_name = "cibmon";
void usage(const char *cmd, int exit_status);
void cib_connection_destroy(gpointer user_data);
void cibmon_pre_notify(const char *event, HA_Message *msg);
void cibmon_update_confirm(const char *event, HA_Message *msg);
gboolean cibmon_shutdown(int nsig, gpointer unused);
void cibmon_diff(const char *event, HA_Message *msg);
cib_t *the_cib = NULL;
#define OPTARGS "V?pPdam:"
gboolean pre_notify = FALSE;
gboolean post_notify = FALSE;
gboolean log_diffs = FALSE;
int max_failures = 30;
int
main(int argc, char **argv)
{
int argerr = 0;
int flag;
int level = 0;
int attempts = 0;
#ifdef HAVE_GETOPT_H
int option_index = 0;
static struct option long_options[] = {
/* Top-level Options */
{"verbose", 0, 0, 'V'},
{"help", 0, 0, '?'},
{"pre", 0, 0, 'p'},
{"post", 0, 0, 'P'},
{"all", 0, 0, 'a'},
{"diffs", 0, 0, 'd'},
{"max-conn-fail",1, 0, 'm'},
{0, 0, 0, 0}
};
#endif
crm_log_init(crm_system_name);
G_main_add_SignalHandler(
G_PRIORITY_HIGH, SIGTERM, cibmon_shutdown, NULL, NULL);
cl_set_corerootdir(HA_COREDIR);
cl_cdtocoredir();
while (1) {
#ifdef HAVE_GETOPT_H
flag = getopt_long(argc, argv, OPTARGS,
long_options, &option_index);
#else
flag = getopt(argc, argv, OPTARGS);
#endif
if (flag == -1)
break;
switch(flag) {
#ifdef HAVE_GETOPT_H
case 0:
printf("option %s",
long_options[option_index].name);
if (optarg) {
printf(" with arg %s", optarg);
}
printf("\n");
printf("Long option (--%s) is not"
" (yet?) properly supported\n",
long_options[option_index].name);
++argerr;
break;
#endif
case 'V':
level = get_crm_log_level();
cl_log_enable_stderr(TRUE);
set_crm_log_level(level+1);
break;
case '?':
usage(crm_system_name, LSB_EXIT_OK);
break;
case 'm':
max_failures = crm_atoi(optarg, "30");
break;
case 'a':
pre_notify = TRUE;
post_notify = TRUE;
log_diffs = TRUE;
break;
case 'd':
log_diffs = TRUE;
break;
case 'p':
pre_notify = TRUE;
break;
case 'P':
post_notify = TRUE;
break;
default:
printf("Argument code 0%o (%c)"
" is not (?yet?) supported\n",
flag, flag);
++argerr;
break;
}
}
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc)
printf("%s ", argv[optind++]);
printf("\n");
}
if (optind > argc) {
++argerr;
}
if (argerr) {
usage(crm_system_name, LSB_EXIT_GENERIC);
}
the_cib = cib_new();
do {
if(attempts != 0) {
sleep(1);
}
exit_code = the_cib->cmds->signon(
the_cib, crm_system_name, cib_query);
} while(exit_code == cib_connection && attempts++ < max_failures);
if(exit_code != cib_ok) {
crm_err("Signon to CIB failed: %s",
cib_error2string(exit_code));
}
if(exit_code == cib_ok) {
crm_debug("Setting dnotify");
exit_code = the_cib->cmds->set_connection_dnotify(
the_cib, cib_connection_destroy);
}
if(exit_code == cib_ok && pre_notify) {
crm_debug("Setting pre-notify callback");
exit_code = the_cib->cmds->add_notify_callback(
the_cib, T_CIB_PRE_NOTIFY, cibmon_pre_notify);
if(exit_code != cib_ok) {
crm_err("Failed to set %s callback: %s",
T_CIB_PRE_NOTIFY, cib_error2string(exit_code));
}
}
if(exit_code == cib_ok && post_notify) {
crm_debug("Setting post-notify callback");
exit_code = the_cib->cmds->add_notify_callback(
the_cib, T_CIB_UPDATE_CONFIRM, cibmon_update_confirm);
if(exit_code != cib_ok) {
crm_err("Failed to set %s callback: %s",
T_CIB_UPDATE_CONFIRM, cib_error2string(exit_code));
}
}
if(exit_code == cib_ok && log_diffs) {
crm_debug("Setting diff callback");
exit_code = the_cib->cmds->add_notify_callback(
the_cib, T_CIB_DIFF_NOTIFY, cibmon_diff);
if(exit_code != cib_ok) {
crm_err("Failed to set %s callback: %s",
T_CIB_DIFF_NOTIFY, cib_error2string(exit_code));
}
}
if(exit_code != cib_ok) {
crm_err("Setup failed, could not monitor CIB actions");
return -exit_code;
}
mainloop = g_main_new(FALSE);
crm_info("Starting mainloop");
g_main_run(mainloop);
crm_debug_3("%s exiting normally", crm_system_name);
fflush(stderr);
return -exit_code;
}
void
usage(const char *cmd, int exit_status)
{
FILE *stream;
stream = exit_status != 0 ? stderr : stdout;
#if 0
fprintf(stream, "usage: %s [-?Vio] command\n"
"\twhere necessary, XML data will be expected using -X"
" or on STDIN if -X isnt specified\n", cmd);
fprintf(stream, "Options\n");
fprintf(stream, "\t--%s (-%c) <id>\tid of the object being operated on\n",
XML_ATTR_ID, 'i');
fprintf(stream, "\t--%s (-%c) <type>\tobject type being operated on\n",
"obj_type", 'o');
fprintf(stream, "\t--%s (-%c)\tturn on debug info."
" additional instance increase verbosity\n", "verbose", 'V');
fprintf(stream, "\t--%s (-%c)\tthis help message\n", "help", '?');
fprintf(stream, "\nCommands\n");
fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_ERASE, 'E');
fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_QUERY, 'Q');
fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_CREATE, 'C');
fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_REPLACE,'R');
fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_UPDATE, 'U');
fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_DELETE, 'D');
fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_BUMP, 'B');
fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_ISMASTER,'M');
fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_SYNC, 'S');
fprintf(stream, "\nXML data\n");
fprintf(stream, "\t--%s (-%c) <string>\t\n", F_CRM_DATA, 'X');
fprintf(stream, "\nAdvanced Options\n");
fprintf(stream, "\t--%s (-%c)\tsend command to specified host."
" Applies to %s and %s commands only\n", "host", 'h',
CIB_OP_QUERY, CRM_OP_CIB_SYNC);
fprintf(stream, "\t--%s (-%c)\tcommand only takes effect locally"
" on the specified host\n", "local", 'l');
fprintf(stream, "\t--%s (-%c)\twait for call to complete before"
" returning\n", "sync-call", 's');
#endif
fflush(stream);
exit(exit_status);
}
void
cib_connection_destroy(gpointer user_data)
{
crm_err("Connection to the CIB terminated... exiting");
g_main_quit(mainloop);
return;
}
int update_depth = 0;
gboolean last_notify_pre = TRUE;
void
cibmon_pre_notify(const char *event, HA_Message *msg)
{
int rc = -1;
const char *op = NULL;
const char *id = NULL;
const char *type = NULL;
crm_data_t *update = NULL;
crm_data_t *pre_update = NULL;
if(msg == NULL) {
crm_err("NULL update");
return;
}
op = cl_get_string(msg, F_CIB_OPERATION);
id = cl_get_string(msg, F_CIB_OBJID);
type = cl_get_string(msg, F_CIB_OBJTYPE);
ha_msg_value_int(msg, F_CIB_RC, &rc);
update_depth++;
last_notify_pre = TRUE;
update = get_message_xml(msg, F_CIB_UPDATE);
pre_update = get_message_xml(msg, F_CIB_EXISTING);
if(update != NULL) {
crm_debug_3(UPDATE_PREFIX"[%s] Performing %s on <%s%s%s>",
event, op, type, id?" id=":"", id?id:"");
print_xml_formatted(LOG_DEBUG_5, UPDATE_PREFIX,
update, "Update");
} else if(update == NULL) {
crm_info(UPDATE_PREFIX"[%s] Performing operation %s (on section=%s)",
event, op, crm_str(type));
}
print_xml_formatted(LOG_DEBUG_3, UPDATE_PREFIX,
pre_update, "Existing Object");
free_xml(update);
free_xml(pre_update);
}
void
cibmon_update_confirm(const char *event, HA_Message *msg)
{
int rc = -1;
const char *op = NULL;
const char *id = NULL;
const char *type = NULL;
crm_data_t *update = NULL;
crm_data_t *output = NULL;
crm_data_t *generation = NULL;
if(msg == NULL) {
crm_err("NULL update");
return;
}
op = cl_get_string(msg, F_CIB_OPERATION);
id = cl_get_string(msg, F_CIB_OBJID);
type = cl_get_string(msg, F_CIB_OBJTYPE);
update_depth--;
last_notify_pre = FALSE;
ha_msg_value_int(msg, F_CIB_RC, &rc);
update = get_message_xml(msg, F_CIB_UPDATE);
output = get_message_xml(msg, F_CIB_UPDATE_RESULT);
generation = get_message_xml(msg, "cib_generation");
if(update == NULL) {
if(rc == cib_ok) {
crm_debug_2(UPDATE_PREFIX"[%s] %s (to %s) confirmed",
event, op, crm_str(type));
} else {
crm_warn(UPDATE_PREFIX"[%s] %s (to %s) ABORTED: (%d) %s",
event, op, crm_str(type), rc,
cib_error2string(rc));
}
} else {
if(rc == cib_ok) {
crm_debug_2(UPDATE_PREFIX"[%s] Operation %s to <%s%s%s> confirmed.",
event, op, crm_str(type),
id?" id=":"", id?id:"");
} else {
crm_warn(UPDATE_PREFIX"[%s] Operation %s to <%s %s%s> ABORTED: (%d) %s",
event, op, crm_str(type), id?" id=":"", id?id:"",
rc, cib_error2string(rc));
}
}
if(update != NULL) {
print_xml_formatted(
rc==cib_ok?LOG_DEBUG:LOG_WARNING, UPDATE_PREFIX,
update, "Update");
}
print_xml_formatted(
rc==cib_ok?LOG_DEBUG_3:LOG_WARNING, UPDATE_PREFIX,
output, "Resulting Object");
if(update_depth == 0) {
print_xml_formatted(
rc==cib_ok?LOG_DEBUG:LOG_WARNING, UPDATE_PREFIX,
generation, "CIB Generation");
}
free_xml(update);
free_xml(output);
free_xml(generation);
}
void
cibmon_diff(const char *event, HA_Message *msg)
{
int rc = -1;
const char *op = NULL;
crm_data_t *diff = NULL;
crm_data_t *update = get_message_xml(msg, F_CIB_UPDATE);
- int log_level = LOG_INFO;
+ unsigned int log_level = LOG_INFO;
if(msg == NULL) {
crm_err("NULL update");
return;
}
ha_msg_value_int(msg, F_CIB_RC, &rc);
op = cl_get_string(msg, F_CIB_OPERATION);
diff = get_message_xml(msg, F_CIB_UPDATE_RESULT);
if(rc < cib_ok) {
log_level = LOG_WARNING;
crm_log_maybe(log_level, "[%s] %s ABORTED: %s",
event, op, cib_error2string(rc));
} else {
crm_log_maybe(log_level, "[%s] %s confirmed", event, op);
}
log_cib_diff(log_level, diff, op);
if(update != NULL) {
print_xml_formatted(
log_level+2, "raw_update", update, NULL);
}
free_xml(diff);
free_xml(update);
}
gboolean
cibmon_shutdown(int nsig, gpointer unused)
{
got_signal = 1;
if (mainloop != NULL && g_main_is_running(mainloop)) {
g_main_quit(mainloop);
} else {
exit(LSB_EXIT_OK);
}
return TRUE;
}
diff --git a/crm/cib/messages.c b/crm/cib/messages.c
index 772cfd8b4a..1a604bd976 100644
--- a/crm/cib/messages.c
+++ b/crm/cib/messages.c
@@ -1,898 +1,898 @@
-/* $Id: messages.c,v 1.47 2005/06/27 08:17:06 andrew Exp $ */
+/* $Id: messages.c,v 1.48 2005/07/03 22:15:49 alan Exp $ */
/*
* 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.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 <portability.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 <heartbeat.h>
#include <clplumbing/cl_log.h>
#include <time.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/msg.h>
#include <crm/common/xml.h>
#include <cibio.h>
#include <cibmessages.h>
#include <cibprimatives.h>
#include <callbacks.h>
#include <crm/dmalloc_wrapper.h>
extern const char *cib_our_uname;
extern gboolean syncd_once;
enum cib_errors revision_check(crm_data_t *cib_update, crm_data_t *cib_copy, int flags);
int get_revision(crm_data_t *xml_obj, int cur_revision);
enum cib_errors updateList(
crm_data_t *local_cib, crm_data_t *update_command, crm_data_t *failed,
int operation, const char *section);
crm_data_t *createCibFragmentAnswer(const char *section, crm_data_t *failed);
enum cib_errors replace_section(
const char *section, crm_data_t *tmpCib, crm_data_t *command);
gboolean check_generation(crm_data_t *newCib, crm_data_t *oldCib);
gboolean update_results(
crm_data_t *failed, crm_data_t *target, int operation, int return_code);
enum cib_errors cib_update_counter(
crm_data_t *xml_obj, const char *field, gboolean reset);
enum cib_errors sync_our_cib(HA_Message *request, gboolean all);
enum cib_errors
cib_process_default(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event", op);
if(answer != NULL) { *answer = NULL; }
if(op == NULL) {
result = cib_operation;
crm_err("No operation specified");
} else if(strcmp(CRM_OP_NOOP, op) == 0) {
;
} else {
result = cib_NOTSUPPORTED;
crm_err("Action [%s] is not supported by the CIB", op);
}
return result;
}
enum cib_errors
cib_process_quit(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event", op);
crm_warn("The CRMd has asked us to exit... complying");
exit(0);
return result;
}
enum cib_errors
cib_process_readwrite(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event", op);
if(safe_str_eq(op, CIB_OP_ISMASTER)) {
if(cib_is_master == TRUE) {
result = cib_ok;
} else {
result = cib_not_master;
}
return result;
}
if(safe_str_eq(op, CIB_OP_MASTER)) {
if(cib_is_master == FALSE) {
crm_info("We are now in R/W mode");
cib_is_master = TRUE;
syncd_once = TRUE;
} else {
crm_debug("We are still in R/W mode");
}
} else if(cib_is_master) {
crm_info("We are now in R/O mode");
cib_is_master = FALSE;
}
return result;
}
enum cib_errors
cib_process_ping(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event", op);
if(answer != NULL) {
*answer = createPingAnswerFragment(CRM_SYSTEM_CIB, "ok");
}
return result;
}
enum cib_errors
cib_process_query(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
crm_data_t *obj_root = NULL;
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event for section=%s",
op, crm_str(section));
if(answer != NULL) { *answer = NULL; }
else { return cib_output_ptr; }
if (safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
section = NULL;
}
*answer = create_xml_node(NULL, XML_TAG_FRAGMENT);
/* crm_xml_add(*answer, XML_ATTR_SECTION, section); */
obj_root = get_object_root(section, existing_cib);
if(obj_root == NULL) {
result = cib_NOTEXISTS;
} else if(obj_root == existing_cib) {
crm_xml_add(obj_root, "origin", cib_our_uname);
add_node_copy(*answer, obj_root);
} else {
crm_data_t *cib = createEmptyCib();
crm_data_t *query_obj_root = get_object_root(section, cib);
copy_in_properties(cib, existing_cib);
crm_xml_add(cib, "origin", cib_our_uname);
xml_child_iter(
obj_root, an_obj, NULL,
add_node_copy(query_obj_root, an_obj);
);
add_node_copy(*answer, cib);
free_xml(cib);
}
if(result == cib_ok && *answer == NULL) {
crm_err("Error creating query response");
result = cib_output_data;
}
return result;
}
enum cib_errors
cib_process_erase(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event", op);
if(answer != NULL) { *answer = NULL; }
*result_cib = createEmptyCib();
result = revision_check(existing_cib, *result_cib, options);
copy_in_properties(*result_cib, existing_cib);
if(result == cib_ok && !(options & cib_inhibit_bcast)) {
cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, TRUE);
}
if(answer != NULL) {
*answer = createCibFragmentAnswer(NULL, NULL);
}
return result;
}
enum cib_errors
cib_process_bump(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event for epoche=%s",
op, crm_str(crm_element_value(the_cib, XML_ATTR_GENERATION)));
if(answer != NULL) { *answer = NULL; }
*result_cib = copy_xml(the_cib);
cib_update_counter(*result_cib, XML_ATTR_GENERATION, FALSE);
cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, FALSE);
if(answer != NULL) {
*answer = createCibFragmentAnswer(NULL, NULL);
}
return result;
}
extern ll_cluster_t *hb_conn;
extern HA_Message *cib_msg_copy(const HA_Message *msg, gboolean with_data);
enum cib_errors
cib_process_sync(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
return sync_our_cib(input, TRUE);
}
enum cib_errors
cib_process_sync_one(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
return sync_our_cib(input, FALSE);
}
enum cib_errors
cib_update_counter(crm_data_t *xml_obj, const char *field, gboolean reset)
{
char *new_value = NULL;
char *old_value = NULL;
int int_value = -1;
/* modify the timestamp */
set_node_tstamp(xml_obj);
if(reset == FALSE && crm_element_value(xml_obj, field) != NULL) {
old_value = crm_element_value_copy(xml_obj, field);
}
if(old_value != NULL) {
crm_malloc0(new_value, 128*(sizeof(char)));
int_value = atoi(old_value);
sprintf(new_value, "%d", ++int_value);
} else {
new_value = crm_strdup("1");
}
crm_debug_4("%s %d(%s)->%s",
field, int_value, crm_str(old_value), crm_str(new_value));
crm_xml_add(xml_obj, field, new_value);
crm_free(new_value);
crm_free(old_value);
return cib_ok;
}
enum cib_errors
cib_process_diff(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
- int log_level = LOG_DEBUG;
+ unsigned int log_level = LOG_DEBUG;
const char *value = NULL;
const char *reason = NULL;
gboolean apply_diff = TRUE;
gboolean do_resync = FALSE;
enum cib_errors result = cib_ok;
int this_updates = 0;
int this_epoche = 0;
int this_admin_epoche = 0;
int diff_add_updates = 0;
int diff_add_epoche = 0;
int diff_add_admin_epoche = 0;
int diff_del_updates = 0;
int diff_del_epoche = 0;
int diff_del_admin_epoche = 0;
crm_debug_2("Processing \"%s\" event", op);
value = crm_element_value(existing_cib, XML_ATTR_GENERATION);
this_epoche = atoi(value?value:"0");
value = crm_element_value(existing_cib, XML_ATTR_NUMUPDATES);
this_updates = atoi(value?value:"0");
value = crm_element_value(existing_cib, XML_ATTR_GENERATION_ADMIN);
this_admin_epoche = atoi(value?value:"0");
cib_diff_version_details(
input,
&diff_add_admin_epoche, &diff_add_epoche, &diff_add_updates,
&diff_del_admin_epoche, &diff_del_epoche, &diff_del_updates);
if(diff_del_admin_epoche == diff_add_admin_epoche
&& diff_del_epoche == diff_add_epoche
&& diff_del_updates == diff_add_updates) {
apply_diff = FALSE;
log_level = LOG_ERR;
reason = "+ and - versions in the diff did not change";
log_cib_diff(LOG_ERR, input, __FUNCTION__);
}
if(apply_diff && diff_del_admin_epoche > this_admin_epoche) {
do_resync = TRUE;
apply_diff = FALSE;
log_level = LOG_INFO;
reason = "current \""XML_ATTR_GENERATION_ADMIN"\" is less than required";
} else if(apply_diff && diff_del_admin_epoche < this_admin_epoche) {
apply_diff = FALSE;
log_level = LOG_WARNING;
reason = "current \""XML_ATTR_GENERATION_ADMIN"\" is greater than required";
}
if(apply_diff && diff_del_epoche > this_epoche) {
do_resync = TRUE;
apply_diff = FALSE;
log_level = LOG_INFO;
reason = "current \""XML_ATTR_GENERATION"\" is less than required";
} else if(apply_diff && diff_del_epoche < this_epoche) {
apply_diff = FALSE;
log_level = LOG_WARNING;
reason = "current \""XML_ATTR_GENERATION"\" is greater than required";
}
if(apply_diff && diff_del_updates > this_updates) {
do_resync = TRUE;
apply_diff = FALSE;
log_level = LOG_INFO;
reason = "current \""XML_ATTR_NUMUPDATES"\" is less than required";
} else if(apply_diff && diff_del_updates < this_updates) {
apply_diff = FALSE;
log_level = LOG_WARNING;
reason = "current \""XML_ATTR_NUMUPDATES"\" is greater than required";
}
if(apply_diff
&& apply_cib_diff(existing_cib, input, result_cib) == FALSE) {
log_level = LOG_WARNING;
reason = "Failed application of an update diff";
if(options & cib_force_diff && cib_is_master == FALSE) {
log_level = LOG_INFO;
reason = "Failed application of a global update. Requesting full refresh.";
do_resync = TRUE;
} else if(options & cib_force_diff) {
reason = "Failed application of a global update. Not requesting full refresh.";
}
}
if(reason != NULL) {
crm_log_maybe(
log_level,
"Diff %d.%d.%d -> %d.%d.%d not applied to %d.%d.%d: %s",
diff_del_admin_epoche,diff_del_epoche,diff_del_updates,
diff_add_admin_epoche,diff_add_epoche,diff_add_updates,
this_admin_epoche,this_epoche,this_updates, reason);
result = cib_diff_failed;
}
if(do_resync && cib_is_master == FALSE) {
HA_Message *sync_me = ha_msg_new(2);
free_xml(*result_cib);
*result_cib = NULL;
result = cib_diff_resync;
crm_info("Requesting re-sync from peer: %s", reason);
ha_msg_add(sync_me, F_TYPE, "cib");
ha_msg_add(sync_me, F_CIB_OPERATION, CIB_OP_SYNC_ONE);
ha_msg_add(sync_me, F_CIB_DELEGATED, cib_our_uname);
if(send_ha_message(hb_conn, sync_me, NULL) == FALSE) {
result = cib_not_connected;
}
ha_msg_del(sync_me);
} else if(do_resync) {
crm_err("Not resyncing in master mode");
}
return result;
}
enum cib_errors
cib_process_replace(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
gboolean verbose = FALSE;
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event for section=%s", op, crm_str(section));
if(answer != NULL) { *answer = NULL; }
if (options & cib_verbose) {
verbose = TRUE;
}
if(safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
section = NULL;
}
if (input == NULL) {
result = cib_NOOBJECT;
} else if(section == NULL) {
int updates = 0;
int epoche = 0;
int admin_epoche = 0;
int replace_updates = 0;
int replace_epoche = 0;
int replace_admin_epoche = 0;
const char *reason = NULL;
cib_version_details(
existing_cib, &admin_epoche, &epoche, &updates);
cib_version_details(input, &replace_admin_epoche,
&replace_epoche, &replace_updates);
if(replace_admin_epoche < admin_epoche) {
reason = XML_ATTR_GENERATION_ADMIN;
} else if(replace_admin_epoche > admin_epoche) {
/* no more checks */
} else if(replace_epoche < epoche) {
reason = XML_ATTR_GENERATION;
} else if(replace_epoche > epoche) {
/* no more checks */
} else if(replace_updates < updates) {
reason = XML_ATTR_NUMUPDATES;
}
if(reason != NULL) {
crm_warn("Replacement %d.%d.%d not applied to %d.%d.%d:"
" current %s is greater than the replacement",
replace_admin_epoche, replace_epoche,
replace_updates, admin_epoche, epoche, updates,
reason);
result = cib_old_data;
}
*result_cib = copy_xml(input);
} else {
*result_cib = copy_xml(existing_cib);
result = replace_section(section, *result_cib, input);
}
if(result == cib_ok && section != NULL) {
cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, FALSE);
}
if (answer != NULL && (verbose || result != cib_ok)) {
*answer = createCibFragmentAnswer(section, NULL);
}
return result;
}
enum cib_errors
cib_process_delete(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
crm_debug_2("Processing \"%s\" event", op);
if(input == NULL) {
crm_err("Cannot perform modification with no data");
return cib_NOOBJECT;
}
*result_cib = copy_xml(existing_cib);
crm_validate_data(input);
crm_validate_data(*result_cib);
if(delete_xml_child(NULL, *result_cib, input) == FALSE) {
return cib_NOTEXISTS;
}
return cib_ok;
}
enum cib_errors
cib_process_modify(
const char *op, int options, const char *section, crm_data_t *input,
crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
gboolean verbose = FALSE;
crm_data_t *failed = NULL;
enum cib_errors result = cib_ok;
int cib_update_op = CIB_UPDATE_OP_NONE;
crm_debug_2("Processing \"%s\" event for section=%s", op, crm_str(section));
failed = create_xml_node(NULL, XML_TAG_FAILED);
if (strcmp(CIB_OP_CREATE, op) == 0) {
cib_update_op = CIB_UPDATE_OP_ADD;
} else if (strcmp(CIB_OP_UPDATE, op) == 0) {
cib_update_op = CIB_UPDATE_OP_MODIFY;
} else if (strcmp(CIB_OP_DELETE_ALT, op) == 0) {
cib_update_op = CIB_UPDATE_OP_DELETE;
} else {
crm_err("Incorrect request handler invoked for \"%s\" op",
crm_str(op));
return cib_operation;
}
result = cib_ok;
if (options & cib_verbose) {
verbose = TRUE;
}
if(safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
section = NULL;
}
if(input == NULL) {
crm_err("Cannot perform modification with no data");
return cib_NOOBJECT;
}
*result_cib = copy_xml(existing_cib);
crm_validate_data(input);
crm_validate_data(*result_cib);
/* make changes to a temp copy then activate */
if(section == NULL) {
crm_data_t *sub_input = NULL;
copy_in_properties(*result_cib, input);
/* order is no longer important here */
if(result == cib_ok) {
sub_input = get_object_root(XML_CIB_TAG_NODES, input);
result = updateList(
*result_cib, sub_input, failed, cib_update_op,
XML_CIB_TAG_NODES);
}
if(result == cib_ok) {
sub_input = get_object_root(XML_CIB_TAG_NODES, input);
result = updateList(
*result_cib, sub_input, failed, cib_update_op,
XML_CIB_TAG_RESOURCES);
}
if(result == cib_ok) {
sub_input = get_object_root(XML_CIB_TAG_NODES, input);
result = updateList(
*result_cib, sub_input, failed, cib_update_op,
XML_CIB_TAG_CONSTRAINTS);
}
if(result == cib_ok) {
sub_input = get_object_root(XML_CIB_TAG_NODES, input);
result = updateList(
*result_cib, sub_input, failed, cib_update_op,
XML_CIB_TAG_STATUS);
}
} else {
result = updateList(
*result_cib, input, failed, cib_update_op, section);
}
if(result == cib_ok && !(options & cib_inhibit_bcast)) {
cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, FALSE);
}
if (result != cib_ok || xml_has_children(failed)) {
if(result == cib_ok) {
result = cib_unknown;
}
crm_log_xml_err(failed, "CIB Update failures");
}
if (verbose || xml_has_children(failed) || result != cib_ok) {
*answer = createCibFragmentAnswer(section, failed);
}
free_xml(failed);
return result;
}
enum cib_errors
replace_section(
const char *section, crm_data_t *tmpCib, crm_data_t *new_section)
{
crm_data_t *old_section = NULL;
/* find the old and new versions of the section */
old_section = get_object_root(section, tmpCib);
if(old_section == NULL) {
crm_err("The CIB is corrupt, cannot replace missing section %s",
section);
return cib_NOSECTION;
} else if(new_section == NULL) {
crm_err("The CIB is corrupt, cannot set section %s to nothing",
section);
return cib_NOSECTION;
}
xml_child_iter(
old_section, a_child, NULL,
free_xml_from_parent(old_section, a_child);
);
copy_in_properties(old_section, new_section);
xml_child_iter(
new_section, a_child, NULL,
add_node_copy(old_section, a_child);
);
return cib_ok;
}
enum cib_errors
updateList(crm_data_t *local_cib, crm_data_t *xml_section, crm_data_t *failed,
int operation, const char *section)
{
int rc = cib_ok;
crm_data_t *this_section = get_object_root(section, local_cib);
if (section == NULL || xml_section == NULL) {
crm_err("Section %s not found in message."
" CIB update is corrupt, ignoring.",
crm_str(section));
return cib_NOSECTION;
}
if((CIB_UPDATE_OP_NONE > operation) || (operation > CIB_UPDATE_OP_MAX)){
crm_err("Invalid operation on section %s", crm_str(section));
return cib_operation;
}
set_node_tstamp(this_section);
xml_child_iter(
xml_section, a_child, NULL,
rc = cib_ok;
if(operation == CIB_UPDATE_OP_DELETE) {
rc = delete_cib_object(this_section, a_child);
update_results(failed, a_child, operation, rc);
} else if(operation == CIB_UPDATE_OP_MODIFY) {
rc = update_cib_object(this_section, a_child);
update_results(failed, a_child, operation, rc);
} else {
rc = add_cib_object(this_section, a_child);
update_results(failed, a_child, operation, rc);
}
);
if(rc == cib_ok && xml_has_children(failed)) {
rc = cib_unknown;
}
return rc;
}
crm_data_t*
createCibFragmentAnswer(const char *section, crm_data_t *failed)
{
crm_data_t *cib = NULL;
crm_data_t *fragment = NULL;
fragment = create_xml_node(NULL, XML_TAG_FRAGMENT);
if (section == NULL
|| strlen(section) == 0
|| strcmp(XML_CIB_TAG_SECTION_ALL, section) == 0) {
cib = get_the_CIB();
if(cib != NULL) {
add_node_copy(fragment, get_the_CIB());
}
} else {
crm_data_t *obj_root = get_object_root(section, get_the_CIB());
if(obj_root != NULL) {
cib = create_xml_node(fragment, XML_TAG_CIB);
add_node_copy(cib, obj_root);
copy_in_properties(cib, get_the_CIB());
}
}
if (failed != NULL && xml_has_children(failed)) {
add_node_copy(fragment, failed);
}
crm_xml_add(fragment, XML_ATTR_SECTION, section);
crm_xml_add(fragment, "generated_on", cib_our_uname);
return fragment;
}
gboolean
check_generation(crm_data_t *newCib, crm_data_t *oldCib)
{
if(cib_compare_generation(newCib, oldCib) >= 0) {
return TRUE;
}
crm_warn("Generation from update is older than the existing one");
return FALSE;
}
gboolean
update_results(
crm_data_t *failed, crm_data_t *target, int operation, int return_code)
{
gboolean was_error = FALSE;
const char *error_msg = NULL;
const char *operation_msg = NULL;
crm_data_t *xml_node = NULL;
operation_msg = cib_op2string(operation);
if (return_code != cib_ok) {
error_msg = cib_error2string(return_code);
xml_node = create_xml_node(failed, XML_FAIL_TAG_CIB);
was_error = TRUE;
add_node_copy(xml_node, target);
crm_xml_add(xml_node, XML_FAILCIB_ATTR_ID, ID(target));
crm_xml_add(xml_node, XML_FAILCIB_ATTR_OBJTYPE, TYPE(target));
crm_xml_add(xml_node, XML_FAILCIB_ATTR_OP, operation_msg);
crm_xml_add(xml_node, XML_FAILCIB_ATTR_REASON, error_msg);
crm_warn("Action %s failed: %s (cde=%d)",
operation_msg, error_msg, return_code);
} else {
crm_debug_3("CIB %s passed", operation_msg);
}
return was_error;
}
enum cib_errors
revision_check(crm_data_t *cib_update, crm_data_t *cib_copy, int flags)
{
enum cib_errors rc = cib_ok;
char *revision = crm_element_value_copy(
cib_update, XML_ATTR_CIB_REVISION);
const char *cur_revision = crm_element_value(
cib_copy, XML_ATTR_CIB_REVISION);
crm_validate_data(cib_update);
crm_validate_data(cib_copy);
if(revision == NULL) {
return cib_ok;
} else if(cur_revision == NULL
|| strcmp(revision, cur_revision) > 0) {
crm_info("Updating CIB revision to %s", revision);
crm_xml_add(
cib_copy, XML_ATTR_CIB_REVISION, revision);
} else {
/* make sure we end up with the right value in the end */
crm_xml_add(
cib_update, XML_ATTR_CIB_REVISION, cur_revision);
}
if(strcmp(revision, cib_feature_revision_s) > 0) {
CRM_DEV_ASSERT(cib_is_master == FALSE);
CRM_DEV_ASSERT((flags & cib_scope_local) == 0);
if(cib_is_master) {
crm_err("Update uses an unsupported tag/feature:"
" %s vs %s",
revision, cib_feature_revision_s);
rc = cib_revision_unsupported;
} else if(flags & cib_scope_local) {
/* an admin has forced a local change using a tag we
* dont understand... ERROR
*/
crm_err("Local update uses an unsupported tag/feature:"
" %s vs %s",
revision, cib_feature_revision_s);
rc = cib_revision_unsupported;
}
}
crm_free(revision);
return rc;
}
enum cib_errors
sync_our_cib(HA_Message *request, gboolean all)
{
enum cib_errors result = cib_ok;
const char *host = cl_get_string(request, F_ORIG);
const char *op = cl_get_string(request, F_CIB_OPERATION);
crm_data_t *sync_data = create_cib_fragment(the_cib, NULL);
HA_Message *replace_request = cib_msg_copy(request, FALSE);
CRM_DEV_ASSERT(sync_data != NULL);
CRM_DEV_ASSERT(replace_request != NULL);
crm_info("Syncing CIB to %s", all?"all peers":host);
if(all == FALSE && host == NULL) {
crm_log_message(LOG_ERR, request);
}
if(all == FALSE && host != NULL) {
ha_msg_add(replace_request, F_CIB_ISREPLY, host);
}
ha_msg_mod(replace_request, F_CIB_OPERATION, CIB_OP_REPLACE);
ha_msg_add(replace_request, "original_"F_CIB_OPERATION, op);
ha_msg_add(replace_request, F_CIB_GLOBAL_UPDATE, XML_BOOLEAN_TRUE);
ha_msg_addstruct(replace_request, F_CIB_CALLDATA, sync_data);
if(send_ha_message(hb_conn, replace_request, all?NULL:host) == FALSE) {
result = cib_not_connected;
}
ha_msg_del(replace_request);
free_xml(sync_data);
return result;
}
diff --git a/crm/crmd/ccm.c b/crm/crmd/ccm.c
index a9f468d462..f8b1e7330a 100644
--- a/crm/crmd/ccm.c
+++ b/crm/crmd/ccm.c
@@ -1,655 +1,656 @@
-/* $Id: ccm.c,v 1.85 2005/06/17 18:44:57 andrew Exp $ */
+/* $Id: ccm.c,v 1.86 2005/07/03 22:15:49 alan Exp $ */
/*
* 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.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
*/
/* put these first so that uuid_t is defined without conflicts */
#include <portability.h>
#include <ocf/oc_event.h>
#include <ocf/oc_membership.h>
#include <clplumbing/GSource.h>
#include <string.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crmd_messages.h>
#include <crmd_fsa.h>
#include <fsa_proto.h>
#include <crmd_callbacks.h>
#include <crm/dmalloc_wrapper.h>
void oc_ev_special(const oc_ev_t *, oc_ev_class_t , int );
int register_with_ccm(ll_cluster_t *hb_cluster);
void msg_ccm_join(const HA_Message *msg, void *foo);
void crmd_ccm_msg_callback(oc_ed_t event,
void *cookie,
size_t size,
const void *data);
gboolean ghash_node_clfree(gpointer key, gpointer value, gpointer user_data);
void ghash_update_cib_node(gpointer key, gpointer value, gpointer user_data);
#define CCM_EVENT_DETAIL 0
#define CCM_EVENT_DETAIL_PARTIAL 1
oc_ev_t *fsa_ev_token;
int num_ccm_register_fails = 0;
int max_ccm_register_fails = 30;
/* A_CCM_CONNECT */
enum crmd_fsa_input
do_ccm_control(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
fsa_data_t *msg_data)
{
int ret;
int fsa_ev_fd;
gboolean did_fail = FALSE;
if(action & A_CCM_DISCONNECT){
oc_ev_unregister(fsa_ev_token);
}
if(action & A_CCM_CONNECT) {
crm_debug_3("Registering with CCM");
ret = oc_ev_register(&fsa_ev_token);
if (ret != 0) {
crm_warn("CCM registration failed");
did_fail = TRUE;
}
if(did_fail == FALSE) {
crm_debug_3("Setting up CCM callbacks");
ret = oc_ev_set_callback(fsa_ev_token, OC_EV_MEMB_CLASS,
crmd_ccm_msg_callback, NULL);
if (ret != 0) {
crm_warn("CCM callback not set");
did_fail = TRUE;
}
}
if(did_fail == FALSE) {
oc_ev_special(fsa_ev_token, OC_EV_MEMB_CLASS, 0/*don't care*/);
crm_debug_3("Activating CCM token");
ret = oc_ev_activate(fsa_ev_token, &fsa_ev_fd);
if (ret != 0){
crm_warn("CCM Activation failed");
did_fail = TRUE;
}
}
if(did_fail) {
num_ccm_register_fails++;
oc_ev_unregister(fsa_ev_token);
if(num_ccm_register_fails < max_ccm_register_fails) {
crm_warn("CCM Connection failed"
" %d times (%d max)",
num_ccm_register_fails,
max_ccm_register_fails);
crm_timer_start(wait_timer);
crmd_fsa_stall(NULL);
return I_NULL;
} else {
crm_err("CCM Activation failed %d (max) times",
num_ccm_register_fails);
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
return I_NULL;
}
}
crm_info("CCM Activation passed... all set to go!");
G_main_add_fd(G_PRIORITY_HIGH, fsa_ev_fd, FALSE, ccm_dispatch,
fsa_ev_token, default_ipc_connection_destroy);
}
if(action & ~(A_CCM_CONNECT|A_CCM_DISCONNECT)) {
crm_err("Unexpected action %s in %s",
fsa_action2string(action), __FUNCTION__);
}
return I_NULL;
}
/* A_CCM_EVENT */
enum crmd_fsa_input
do_ccm_event(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
fsa_data_t *msg_data)
{
enum crmd_fsa_input return_input = I_NULL;
oc_ed_t event;
const oc_ev_membership_t *oc = NULL;
struct crmd_ccm_data_s *ccm_data = fsa_typed_data(fsa_dt_ccm);
if(ccm_data == NULL) {
crm_err("No data provided to FSA function");
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
return I_NULL;
} else if(msg_data->fsa_cause != C_CCM_CALLBACK) {
crm_err("FSA function called in response to incorect input");
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
return I_NULL;
}
event = ccm_data->event;
oc = ccm_data->oc;
ccm_event_detail(oc, event);
if (OC_EV_MS_EVICTED == event) {
/* todo: drop back to S_PENDING instead */
/* get out... NOW!
*
* go via the error recovery process so that HA will
* restart us if required
*/
register_fsa_error(cause, I_ERROR, msg_data->data);
return I_NULL;
}
CRM_DEV_ASSERT(oc->m_n_in != 0 || oc->m_n_out != 0);
if(AM_I_DC) {
/* Membership changed, remind everyone we're here.
* This will aid detection of duplicate DCs
*/
HA_Message *no_op = create_request(
CRM_OP_NOOP, NULL, NULL,
CRM_SYSTEM_DC, CRM_SYSTEM_CRMD, NULL);
send_msg_via_ha(fsa_cluster_conn, no_op);
} else if(oc->m_n_out != 0) {
/* Possibly move this logic to ghash_update_cib_node() */
unsigned lpc = 0;
int offset = oc->m_out_idx;
for(lpc=0; lpc < oc->m_n_out; lpc++) {
const char *uname = oc->m_array[offset+lpc].node_uname;
if(uname == NULL) {
crm_err("CCM node had no name");
continue;
} else if(safe_str_eq(uname, fsa_our_dc)) {
crm_warn("Our DC node (%s) left the cluster",
uname);
register_fsa_input(cause, I_ELECTION, NULL);
}
}
}
return return_input;
}
/* A_CCM_UPDATE_CACHE */
/*
* Take the opportunity to update the node status in the CIB as well
*/
enum crmd_fsa_input
do_ccm_update_cache(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
fsa_data_t *msg_data)
{
enum crmd_fsa_input next_input = I_NULL;
- int lpc, offset;
+ unsigned int lpc;
+ int offset;
GHashTable *members = NULL;
oc_ed_t event;
const oc_ev_membership_t *oc = NULL;
oc_node_list_t *tmp = NULL, *membership_copy = NULL;
struct crmd_ccm_data_s *ccm_data = fsa_typed_data(fsa_dt_ccm);
if(ccm_data == NULL) {
crm_err("No data provided to FSA function");
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
return I_NULL;
}
event = ccm_data->event;
oc = ccm_data->oc;
crm_debug_2("Updating CCM cache after a \"%s\" event.",
ccm_event_name(event));
crm_debug_2("instance=%d, nodes=%d, new=%d, lost=%d n_idx=%d, "
"new_idx=%d, old_idx=%d",
oc->m_instance,
oc->m_n_member,
oc->m_n_in,
oc->m_n_out,
oc->m_memb_idx,
oc->m_in_idx,
oc->m_out_idx);
#define ALAN_DEBUG 1
#ifdef ALAN_DEBUG
{
/*
* Size (Size + 2) / 2
*
* 3 (3+2)/2 = 5 / 2 = 2
* 4 (4+2)/2 = 6 / 2 = 3
* 5 (5+2)/2 = 7 / 2 = 3
* 6 (6+2)/2 = 8 / 2 = 4
* 7 (7+2)/2 = 9 / 2 = 4
*/
- int clsize = (oc->m_out_idx - oc->m_n_member);
- int plsize = (clsize + 2)/2;
+ unsigned int clsize = (oc->m_out_idx - oc->m_n_member);
+ unsigned int plsize = (clsize + 2)/2;
gboolean plurality = (oc->m_n_member >= plsize);
gboolean Q = ccm_have_quorum(event);
if(clsize == 2) {
if (!Q) {
crm_err("2 nodes w/o quorum");
}
} else if(Q && !plurality) {
crm_err("Quorum w/o plurality (%d/%d nodes)",
oc->m_n_member, clsize);
} else if(plurality && !Q) {
crm_err("Plurality w/o Quorum (%d/%d nodes)",
oc->m_n_member, clsize);
} else {
crm_debug_2("Quorum(%s) and plurality (%d/%d) agree.",
Q?"true":"false", oc->m_n_member, clsize);
}
}
#endif
crm_malloc0(membership_copy, sizeof(oc_node_list_t));
if(membership_copy == NULL) {
crm_crit("Couldnt create membership copy - out of memory");
register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
return I_NULL;
}
membership_copy->id = oc->m_instance;
membership_copy->last_event = event;
crm_debug_3("Copying members");
/*--*-- All Member Nodes --*--*/
offset = oc->m_memb_idx;
membership_copy->members_size = oc->m_n_member;
if(membership_copy->members_size > 0) {
membership_copy->members =
g_hash_table_new(g_str_hash, g_str_equal);
members = membership_copy->members;
for(lpc=0; lpc < membership_copy->members_size; lpc++) {
oc_node_t *member = NULL;
crm_debug_3("Copying member %d", lpc);
crm_malloc0(member, sizeof(oc_node_t));
if(member == NULL) {
continue;
}
member->node_id =
oc->m_array[offset+lpc].node_id;
member->node_born_on =
oc->m_array[offset+lpc].node_born_on;
member->node_uname = NULL;
if(oc->m_array[offset+lpc].node_uname != NULL) {
member->node_uname =
crm_strdup(oc->m_array[offset+lpc].node_uname);
} else {
crm_err("Node %d had a NULL uname",
member->node_id);
}
g_hash_table_insert(
members, member->node_uname, member);
}
} else {
membership_copy->members = NULL;
}
crm_debug_3("Copying new members");
/*--*-- New Member Nodes --*--*/
offset = oc->m_in_idx;
membership_copy->new_members_size = oc->m_n_in;
if(membership_copy->new_members_size > 0) {
membership_copy->new_members =
g_hash_table_new(g_str_hash, g_str_equal);
members = membership_copy->new_members;
for(lpc=0; lpc < membership_copy->new_members_size; lpc++) {
oc_node_t *member = NULL;
crm_malloc0(member, sizeof(oc_node_t));
if(member == NULL) {
continue;
}
member->node_uname = NULL;
member->node_id = oc->m_array[offset+lpc].node_id;
member->node_born_on =
oc->m_array[offset+lpc].node_born_on;
if(oc->m_array[offset+lpc].node_uname != NULL) {
member->node_uname =
crm_strdup(oc->m_array[offset+lpc].node_uname);
} else {
crm_err("Node %d had a NULL uname",
member->node_id);
}
g_hash_table_insert(
members, member->node_uname, member);
g_hash_table_insert(members, member->node_uname, member);
}
} else {
membership_copy->new_members = NULL;
}
crm_debug_3("Copying dead members");
/*--*-- Recently Dead Member Nodes --*--*/
offset = oc->m_out_idx;
membership_copy->dead_members_size = oc->m_n_out;
if(membership_copy->dead_members_size > 0) {
membership_copy->dead_members =
g_hash_table_new(g_str_hash, g_str_equal);
members = membership_copy->dead_members;
for(lpc=0; lpc < membership_copy->dead_members_size; lpc++) {
oc_node_t *member = NULL;
crm_malloc0(member, sizeof(oc_node_t));
if(member == NULL) {
continue;
}
member->node_id =
oc->m_array[offset+lpc].node_id;
member->node_born_on =
oc->m_array[offset+lpc].node_born_on;
member->node_uname = NULL;
CRM_DEV_ASSERT(oc->m_array[offset+lpc].node_uname != NULL);
if(oc->m_array[offset+lpc].node_uname == NULL) {
continue;
}
member->node_uname =
crm_strdup(oc->m_array[offset+lpc].node_uname);
g_hash_table_insert(
members, member->node_uname, member);
g_hash_table_insert(members, member->node_uname, member);
}
} else {
membership_copy->dead_members = NULL;
}
tmp = fsa_membership_copy;
fsa_membership_copy = membership_copy;
crm_debug_2("Updated membership cache with %d (%d new, %d lost) members",
g_hash_table_size(fsa_membership_copy->members),
g_hash_table_size(fsa_membership_copy->new_members),
g_hash_table_size(fsa_membership_copy->dead_members));
/* Free the old copy */
if(tmp != NULL) {
if(tmp->members != NULL)
g_hash_table_foreach_remove(
tmp->members, ghash_node_clfree, NULL);
if(tmp->new_members != NULL)
g_hash_table_foreach_remove(
tmp->new_members, ghash_node_clfree, NULL);
if(tmp->dead_members != NULL)
g_hash_table_foreach_remove(
tmp->dead_members, ghash_node_clfree, NULL);
crm_free(tmp);
}
crm_debug_3("Free'd old copies");
set_bit_inplace(fsa_input_register, R_CCM_DATA);
if(cur_state != S_STARTING && cur_state != S_STOPPING) {
crm_debug_3("Updating the CIB from CCM cache");
do_update_cib_nodes(NULL, FALSE);
}
return next_input;
}
void
ccm_event_detail(const oc_ev_membership_t *oc, oc_ed_t event)
{
int lpc;
gboolean member = FALSE;
member = FALSE;
crm_debug_2("-----------------------");
crm_info("%s: trans=%d, nodes=%d, new=%d, lost=%d n_idx=%d, "
"new_idx=%d, old_idx=%d",
ccm_event_name(event),
oc->m_instance,
oc->m_n_member,
oc->m_n_in,
oc->m_n_out,
oc->m_memb_idx,
oc->m_in_idx,
oc->m_out_idx);
#if !CCM_EVENT_DETAIL_PARTIAL
for(lpc=0; lpc < oc->m_n_member; lpc++) {
crm_info("\tCURRENT: %s [nodeid=%d, born=%d]",
oc->m_array[oc->m_memb_idx+lpc].node_uname,
oc->m_array[oc->m_memb_idx+lpc].node_id,
oc->m_array[oc->m_memb_idx+lpc].node_born_on);
if(safe_str_eq(fsa_our_uname,
oc->m_array[oc->m_memb_idx+lpc].node_uname)) {
member = TRUE;
}
}
if (member == FALSE) {
crm_warn("MY NODE IS NOT IN CCM THE MEMBERSHIP LIST");
}
#endif
for(lpc=0; lpc<(int)oc->m_n_in; lpc++) {
crm_info("\tNEW: %s [nodeid=%d, born=%d]",
oc->m_array[oc->m_in_idx+lpc].node_uname,
oc->m_array[oc->m_in_idx+lpc].node_id,
oc->m_array[oc->m_in_idx+lpc].node_born_on);
}
for(lpc=0; lpc<(int)oc->m_n_out; lpc++) {
crm_info("\tLOST: %s [nodeid=%d, born=%d]",
oc->m_array[oc->m_out_idx+lpc].node_uname,
oc->m_array[oc->m_out_idx+lpc].node_id,
oc->m_array[oc->m_out_idx+lpc].node_born_on);
if(fsa_our_uname != NULL
&& 0 == strcmp(fsa_our_uname,
oc->m_array[oc->m_out_idx+lpc].node_uname)) {
crm_err("We're not part of the cluster anymore");
}
}
crm_debug_2("-----------------------");
}
int
register_with_ccm(ll_cluster_t *hb_cluster)
{
return 0;
}
void
msg_ccm_join(const HA_Message *msg, void *foo)
{
crm_debug_2("###### Received ccm_join message...");
if (msg != NULL)
{
crm_debug_2("[type=%s]",
ha_msg_value(msg, F_TYPE));
crm_debug_2("[orig=%s]",
ha_msg_value(msg, F_ORIG));
crm_debug_2("[to=%s]",
ha_msg_value(msg, F_TO));
crm_debug_2("[status=%s]",
ha_msg_value(msg, F_STATUS));
crm_debug_2("[info=%s]",
ha_msg_value(msg, F_COMMENT));
crm_debug_2("[rsc_hold=%s]",
ha_msg_value(msg, F_RESOURCES));
crm_debug_2("[stable=%s]",
ha_msg_value(msg, F_ISSTABLE));
crm_debug_2("[rtype=%s]",
ha_msg_value(msg, F_RTYPE));
crm_debug_2("[ts=%s]",
ha_msg_value(msg, F_TIME));
crm_debug_2("[seq=%s]",
ha_msg_value(msg, F_SEQ));
crm_debug_2("[generation=%s]",
ha_msg_value(msg, F_HBGENERATION));
/* crm_debug_2("[=%s]", ha_msg_value(msg, F_)); */
}
return;
}
struct update_data_s
{
crm_data_t *updates;
const char *state;
const char *join;
};
crm_data_t*
do_update_cib_nodes(crm_data_t *updates, gboolean overwrite)
{
int call_options = cib_scope_local|cib_quorum_override;
struct update_data_s update_data;
crm_data_t *fragment = updates;
crm_data_t *tmp = NULL;
if(updates == NULL) {
fragment = create_cib_fragment(NULL, NULL);
crm_xml_add(fragment, XML_ATTR_SECTION, XML_CIB_TAG_STATUS);
}
tmp = find_xml_node(fragment, XML_TAG_CIB, TRUE);
tmp = get_object_root(XML_CIB_TAG_STATUS, tmp);
CRM_DEV_ASSERT(tmp != NULL);
update_data.updates = tmp;
update_data.state = XML_BOOLEAN_YES;
update_data.join = NULL;
if(overwrite) {
crm_debug_2("Performing a join update based on CCM data");
update_data.join = CRMD_JOINSTATE_PENDING;
if(fsa_membership_copy->members != NULL) {
g_hash_table_foreach(fsa_membership_copy->members,
ghash_update_cib_node, &update_data);
}
} else {
call_options = call_options|cib_inhibit_bcast;
crm_debug_2("Inhibiting bcast for CCM updates");
if(fsa_membership_copy->members != NULL) {
g_hash_table_foreach(fsa_membership_copy->new_members,
ghash_update_cib_node, &update_data);
}
update_data.state = XML_BOOLEAN_NO;
update_data.join = CRMD_JOINSTATE_DOWN;
if(fsa_membership_copy->dead_members != NULL) {
g_hash_table_foreach(fsa_membership_copy->dead_members,
ghash_update_cib_node, &update_data);
}
}
if(update_data.updates != NULL) {
fsa_cib_conn->cmds->modify(fsa_cib_conn, XML_CIB_TAG_STATUS,
fragment, NULL, call_options);
free_xml(fragment);
}
return NULL;
}
void
ghash_update_cib_node(gpointer key, gpointer value, gpointer user_data)
{
crm_data_t *tmp1 = NULL;
const char *node_uname = (const char*)key;
struct update_data_s* data = (struct update_data_s*)user_data;
crm_debug_2("%s processing %s (%s)",
__FUNCTION__, node_uname, data->state);
tmp1 = create_node_state(node_uname, node_uname,
NULL, data->state, NULL, data->join,
NULL, __FUNCTION__);
add_node_copy(data->updates, tmp1);
free_xml(tmp1);
}
gboolean
ghash_node_clfree(gpointer key, gpointer value, gpointer user_data)
{
/* value->node_uname is free'd as "key" */
if(key != NULL) {
crm_free(key);
}
if(value != NULL) {
crm_free(value);
}
return TRUE;
}
diff --git a/crm/crmd/pengine.c b/crm/crmd/pengine.c
index 9bc4c709e2..217bdd0d3e 100644
--- a/crm/crmd/pengine.c
+++ b/crm/crmd/pengine.c
@@ -1,212 +1,212 @@
/*
* 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.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 <portability.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <crmd_fsa.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h> /* for access */
#include <clplumbing/cl_signal.h>
#include <clplumbing/realtime.h>
#include <clplumbing/timers.h>
#include <sys/types.h> /* for calls to open */
#include <sys/stat.h> /* for calls to open */
#include <fcntl.h> /* for calls to open */
#include <pwd.h> /* for getpwuid */
#include <grp.h> /* for initgroups */
#include <sys/time.h> /* for getrlimit */
#include <sys/resource.h>/* for getrlimit */
#include <errno.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crmd_messages.h>
#include <crmd_callbacks.h>
#include <crm/cib.h>
#include <crmd.h>
#include <crm/dmalloc_wrapper.h>
#define CLIENT_EXIT_WAIT 30
struct crm_subsystem_s *pe_subsystem = NULL;
void do_pe_invoke_callback(const HA_Message *msg, int call_id, int rc,
crm_data_t *output, void *user_data);
/* A_PE_START, A_PE_STOP, A_TE_RESTART */
enum crmd_fsa_input
do_pe_control(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
fsa_data_t *msg_data)
{
enum crmd_fsa_input result = I_NULL;
struct crm_subsystem_s *this_subsys = pe_subsystem;
long long stop_actions = A_PE_STOP;
long long start_actions = A_PE_START;
if(action & stop_actions) {
if(stop_subsystem(this_subsys) == FALSE) {
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
}
}
if(action & start_actions) {
if(cur_state != S_STOPPING) {
if(start_subsystem(this_subsys) == FALSE) {
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
}
} else {
crm_info("Ignoring request to start %s while shutting down",
this_subsys->name);
}
}
return result;
}
char *fsa_pe_ref = NULL;
/* A_PE_INVOKE */
enum crmd_fsa_input
do_pe_invoke(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
fsa_data_t *msg_data)
{
int call_id = 0;
if(is_set(fsa_input_register, R_PE_CONNECTED) == FALSE){
if(pe_subsystem->pid > 0) {
int pid_status = -1;
int rc = waitpid(
pe_subsystem->pid, &pid_status, WNOHANG);
if(rc > 0 && WIFEXITED(pid_status)) {
clear_bit_inplace(fsa_input_register,
pe_subsystem->flag_connected);
if(is_set(fsa_input_register,
pe_subsystem->flag_required)) {
/* this wasnt supposed to happen */
crm_err("%s[%d] terminated during start",
pe_subsystem->name,
pe_subsystem->pid);
register_fsa_error(
C_FSA_INTERNAL, I_ERROR, NULL);
}
pe_subsystem->pid = -1;
return I_NULL;
}
}
crm_info("Waiting for the PE to connect");
crmd_fsa_stall(NULL);
return I_NULL;
}
if(is_set(fsa_input_register, R_HAVE_CIB) == FALSE) {
crm_err("Attempted to invoke the PE without a consistent"
" copy of the CIB!");
/* start the join from scratch */
register_fsa_input_before(C_FSA_INTERNAL, I_ELECTION, NULL);
return I_NULL;
}
crm_debug("Requesting the current CIB");
call_id = fsa_cib_conn->cmds->query(
fsa_cib_conn, NULL, NULL, cib_scope_local);
if(FALSE == add_cib_op_callback(
call_id, TRUE, NULL, do_pe_invoke_callback)) {
crm_err("Cant retrieve the CIB to invoke the %s subsystem with",
pe_subsystem->name);
register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
}
return I_NULL;
}
void
do_pe_invoke_callback(const HA_Message *msg, int call_id, int rc,
crm_data_t *output, void *user_data)
{
HA_Message *cmd = NULL;
int ccm_transition_id = -1;
gboolean cib_has_quorum = FALSE;
crm_data_t *local_cib = find_xml_node(output, XML_TAG_CIB, TRUE);
if(AM_I_DC == FALSE
|| is_set(fsa_input_register, R_PE_CONNECTED) == FALSE
|| fsa_state != S_POLICY_ENGINE) {
crm_debug("No need to invoke the PE anymore");
return;
}
crm_debug_2("Invoking %s with %p", CRM_SYSTEM_PENGINE, local_cib);
CRM_DEV_ASSERT(local_cib != NULL);
CRM_DEV_ASSERT(crm_element_value(local_cib, XML_ATTR_DC_UUID) != NULL);
cib_has_quorum = crm_is_true(
crm_element_value(local_cib, XML_ATTR_HAVE_QUORUM));
ccm_transition_id = crm_atoi(
crm_element_value(local_cib, XML_ATTR_CCM_TRANSITION), "-1");
- if(ccm_transition_id < fsa_membership_copy->id) {
+ if(ccm_transition_id < (int)fsa_membership_copy->id) {
/* the cib is behind */
crm_debug("Re-asking for the CIB until membership/quorum"
" matches: CIB=%d < CRM=%d",
ccm_transition_id, fsa_membership_copy->id);
mssleep(500);
register_fsa_action(A_PE_INVOKE);
return;
- } else if(ccm_transition_id > fsa_membership_copy->id) {
+ } else if(ccm_transition_id > (int)fsa_membership_copy->id) {
/* we are behind */
crm_info("Waiting for another CCM event before proceeding:"
" CIB=%d > CRM=%d",
ccm_transition_id, fsa_membership_copy->id);
return;
}
if(fsa_pe_ref) {
crm_free(fsa_pe_ref);
fsa_pe_ref = NULL;
}
cmd = create_request(
CRM_OP_PECALC, local_cib, NULL,
CRM_SYSTEM_PENGINE, CRM_SYSTEM_DC, NULL);
send_request(cmd, &fsa_pe_ref);
crm_debug("Invoking the PE: %s", fsa_pe_ref);
}
diff --git a/crm/crmd/utils.c b/crm/crmd/utils.c
index 626238388d..f66b36ba4c 100644
--- a/crm/crmd/utils.c
+++ b/crm/crmd/utils.c
@@ -1,1381 +1,1381 @@
/*
* 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.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 <portability.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crmd_fsa.h>
#include <clplumbing/Gmain_timeout.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <heartbeat.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/msg.h>
#include <crmd_messages.h>
#include <crmd_utils.h>
#include <crm/dmalloc_wrapper.h>
void copy_ccm_node(oc_node_t a_node, oc_node_t *a_node_copy);
/* A_DC_TIMER_STOP, A_DC_TIMER_START,
* A_FINALIZE_TIMER_STOP, A_FINALIZE_TIMER_START
* A_INTEGRATE_TIMER_STOP, A_INTEGRATE_TIMER_START
*/
enum crmd_fsa_input
do_timer_control(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
fsa_data_t *msg_data)
{
gboolean timer_op_ok = TRUE;
enum crmd_fsa_input result = I_NULL;
if(action & A_DC_TIMER_STOP) {
timer_op_ok = crm_timer_stop(election_trigger);
} else if(action & A_FINALIZE_TIMER_STOP) {
timer_op_ok = crm_timer_stop(finalization_timer);
} else if(action & A_INTEGRATE_TIMER_STOP) {
timer_op_ok = crm_timer_stop(integration_timer);
/* } else if(action & A_ELECTION_TIMEOUT_STOP) { */
/* timer_op_ok = crm_timer_stop(election_timeout); */
}
/* dont start a timer that wasnt already running */
if(action & A_DC_TIMER_START && timer_op_ok) {
crm_timer_start(election_trigger);
if(AM_I_DC) {
/* there can be only one */
result = I_ELECTION;
}
} else if(action & A_FINALIZE_TIMER_START) {
crm_timer_start(finalization_timer);
} else if(action & A_INTEGRATE_TIMER_START) {
crm_timer_start(integration_timer);
/* } else if(action & A_ELECTION_TIMEOUT_START) { */
/* crm_timer_start(election_timeout); */
}
return I_NULL;
}
gboolean
crm_timer_popped(gpointer data)
{
fsa_timer_t *timer = (fsa_timer_t *)data;
if(timer == election_trigger) {
crm_info("Election Trigger (%s) just popped!",
fsa_input2string(timer->fsa_input));
} else if(timer == election_timeout) {
crm_info("Election Timeout (%s) just popped!",
fsa_input2string(timer->fsa_input));
} else {
crm_info("Timer %s just popped!",
fsa_input2string(timer->fsa_input));
}
if(timer->repeat == FALSE) {
crm_timer_stop(timer); /* make it _not_ go off again */
}
if(timer->fsa_input == I_INTEGRATED) {
register_fsa_input_before(
C_TIMER_POPPED, timer->fsa_input, NULL);
} else if(timer->fsa_input == I_FINALIZED
&& fsa_state != S_FINALIZE_JOIN) {
crm_debug("Discarding I_FINALIZED event in state: %s",
fsa_state2string(fsa_state));
} else if(timer->fsa_input != I_NULL) {
register_fsa_input(C_TIMER_POPPED, timer->fsa_input, NULL);
}
G_main_set_trigger(fsa_source);
return TRUE;
}
gboolean
crm_timer_start(fsa_timer_t *timer)
{
const char *timer_desc = NULL;
if(timer == election_trigger) {
timer_desc = "Election Trigger";
} else if(timer == election_timeout) {
timer_desc = "Election Timeout";
} else {
timer_desc = "Timer";
}
if((timer->source_id == (guint)-1 || timer->source_id == (guint)-2)
&& timer->period_ms > 0) {
timer->source_id = Gmain_timeout_add(
timer->period_ms, timer->callback, (void*)timer);
crm_debug("Started %s (%s:%dms), src=%d",
timer_desc, fsa_input2string(timer->fsa_input),
timer->period_ms, timer->source_id);
} else if(timer->period_ms < 0) {
crm_err("Tried to start %s (%s:%dms) with a -ve period",
timer_desc, fsa_input2string(timer->fsa_input),
timer->period_ms);
} else {
crm_debug("%s (%s:%dms) already running: src=%d",
timer_desc, fsa_input2string(timer->fsa_input),
timer->period_ms, timer->source_id);
return FALSE;
}
return TRUE;
}
gboolean
crm_timer_stop(fsa_timer_t *timer)
{
const char *timer_desc = NULL;
if(timer == election_trigger) {
timer_desc = "Election Trigger";
} else if(timer == election_timeout) {
timer_desc = "Election Timeout";
} else if(timer == wait_timer) {
timer_desc = "Stall Timeout";
} else {
timer_desc = "Timer";
}
if(timer == NULL) {
crm_err("Attempted to stop NULL timer");
return FALSE;
} else if(timer->source_id != (guint)-1
&& timer->source_id != (guint)-2) {
crm_debug("Stopping %s (%s:%dms), src=%d",
timer_desc, fsa_input2string(timer->fsa_input),
timer->period_ms, timer->source_id);
g_source_remove(timer->source_id);
timer->source_id = -2;
} else {
crm_debug_2("%s (%s:%dms) already stopped",
timer_desc, fsa_input2string(timer->fsa_input),
timer->period_ms);
timer->source_id = -2;
return FALSE;
}
return TRUE;
}
long long
toggle_bit(long long action_list, long long action)
{
crm_debug_5("Toggling bit %.16llx", action);
action_list ^= action;
crm_debug_5("Result %.16llx", action_list & action);
return action_list;
}
long long
clear_bit(long long action_list, long long action)
{
- int level = LOG_DEBUG_5;
+ unsigned int level = LOG_DEBUG_5;
crm_log_maybe(level, "Clearing bit\t%.16llx", action);
/* ensure its set */
action_list |= action;
/* then toggle */
action_list = action_list ^ action;
return action_list;
}
long long
set_bit(long long action_list, long long action)
{
- int level = LOG_DEBUG_5;
+ unsigned int level = LOG_DEBUG_5;
crm_log_maybe(level, "Setting bit\t%.16llx", action);
action_list |= action;
return action_list;
}
gboolean
is_set(long long action_list, long long action)
{
crm_debug_5("Checking bit\t%.16llx in %.16llx", action, action_list);
return ((action_list & action) == action);
}
gboolean
is_set_any(long long action_list, long long action)
{
crm_debug_5("Checking bit\t%.16llx in %.16llx", action, action_list);
return ((action_list & action) != 0);
}
const char *
fsa_input2string(enum crmd_fsa_input input)
{
const char *inputAsText = NULL;
switch(input){
case I_NULL:
inputAsText = "I_NULL";
break;
case I_CCM_EVENT:
inputAsText = "I_CCM_EVENT";
break;
case I_CIB_OP:
inputAsText = "I_CIB_OP";
break;
case I_CIB_UPDATE:
inputAsText = "I_CIB_UPDATE";
break;
case I_DC_TIMEOUT:
inputAsText = "I_DC_TIMEOUT";
break;
case I_ELECTION:
inputAsText = "I_ELECTION";
break;
case I_PE_CALC:
inputAsText = "I_PE_CALC";
break;
case I_RELEASE_DC:
inputAsText = "I_RELEASE_DC";
break;
case I_ELECTION_DC:
inputAsText = "I_ELECTION_DC";
break;
case I_ERROR:
inputAsText = "I_ERROR";
break;
case I_FAIL:
inputAsText = "I_FAIL";
break;
case I_INTEGRATED:
inputAsText = "I_INTEGRATED";
break;
case I_FINALIZED:
inputAsText = "I_FINALIZED";
break;
case I_NODE_JOIN:
inputAsText = "I_NODE_JOIN";
break;
case I_JOIN_OFFER:
inputAsText = "I_JOIN_OFFER";
break;
case I_JOIN_REQUEST:
inputAsText = "I_JOIN_REQUEST";
break;
case I_JOIN_RESULT:
inputAsText = "I_JOIN_RESULT";
break;
case I_NOT_DC:
inputAsText = "I_NOT_DC";
break;
case I_RECOVERED:
inputAsText = "I_RECOVERED";
break;
case I_RELEASE_FAIL:
inputAsText = "I_RELEASE_FAIL";
break;
case I_RELEASE_SUCCESS:
inputAsText = "I_RELEASE_SUCCESS";
break;
case I_RESTART:
inputAsText = "I_RESTART";
break;
case I_PE_SUCCESS:
inputAsText = "I_PE_SUCCESS";
break;
case I_ROUTER:
inputAsText = "I_ROUTER";
break;
case I_SHUTDOWN:
inputAsText = "I_SHUTDOWN";
break;
case I_STARTUP:
inputAsText = "I_STARTUP";
break;
case I_TE_SUCCESS:
inputAsText = "I_TE_SUCCESS";
break;
case I_STOP:
inputAsText = "I_STOP";
break;
case I_DC_HEARTBEAT:
inputAsText = "I_DC_HEARTBEAT";
break;
case I_WAIT_FOR_EVENT:
inputAsText = "I_WAIT_FOR_EVENT";
break;
case I_LRM_EVENT:
inputAsText = "I_LRM_EVENT";
break;
case I_PENDING:
inputAsText = "I_PENDING";
break;
case I_HALT:
inputAsText = "I_HALT";
break;
case I_TERMINATE:
inputAsText = "I_TERMINATE";
break;
case I_ILLEGAL:
inputAsText = "I_ILLEGAL";
break;
}
if(inputAsText == NULL) {
crm_err("Input %d is unknown", input);
inputAsText = "<UNKNOWN_INPUT>";
}
return inputAsText;
}
const char *
fsa_state2string(enum crmd_fsa_state state)
{
const char *stateAsText = NULL;
switch(state){
case S_IDLE:
stateAsText = "S_IDLE";
break;
case S_ELECTION:
stateAsText = "S_ELECTION";
break;
case S_INTEGRATION:
stateAsText = "S_INTEGRATION";
break;
case S_FINALIZE_JOIN:
stateAsText = "S_FINALIZE_JOIN";
break;
case S_NOT_DC:
stateAsText = "S_NOT_DC";
break;
case S_POLICY_ENGINE:
stateAsText = "S_POLICY_ENGINE";
break;
case S_RECOVERY:
stateAsText = "S_RECOVERY";
break;
case S_RELEASE_DC:
stateAsText = "S_RELEASE_DC";
break;
case S_PENDING:
stateAsText = "S_PENDING";
break;
case S_STOPPING:
stateAsText = "S_STOPPING";
break;
case S_TERMINATE:
stateAsText = "S_TERMINATE";
break;
case S_TRANSITION_ENGINE:
stateAsText = "S_TRANSITION_ENGINE";
break;
case S_STARTING:
stateAsText = "S_STARTING";
break;
case S_HALT:
stateAsText = "S_HALT";
break;
case S_ILLEGAL:
stateAsText = "S_ILLEGAL";
break;
}
if(stateAsText == NULL) {
crm_err("State %d is unknown", state);
stateAsText = "<UNKNOWN_STATE>";
}
return stateAsText;
}
const char *
fsa_cause2string(enum crmd_fsa_cause cause)
{
const char *causeAsText = NULL;
switch(cause){
case C_UNKNOWN:
causeAsText = "C_UNKNOWN";
break;
case C_STARTUP:
causeAsText = "C_STARTUP";
break;
case C_IPC_MESSAGE:
causeAsText = "C_IPC_MESSAGE";
break;
case C_HA_MESSAGE:
causeAsText = "C_HA_MESSAGE";
break;
case C_CCM_CALLBACK:
causeAsText = "C_CCM_CALLBACK";
break;
case C_TIMER_POPPED:
causeAsText = "C_TIMER_POPPED";
break;
case C_SHUTDOWN:
causeAsText = "C_SHUTDOWN";
break;
case C_HEARTBEAT_FAILED:
causeAsText = "C_HEARTBEAT_FAILED";
break;
case C_SUBSYSTEM_CONNECT:
causeAsText = "C_SUBSYSTEM_CONNECT";
break;
case C_LRM_OP_CALLBACK:
causeAsText = "C_LRM_OP_CALLBACK";
break;
case C_LRM_MONITOR_CALLBACK:
causeAsText = "C_LRM_MONITOR_CALLBACK";
break;
case C_CRMD_STATUS_CALLBACK:
causeAsText = "C_CRMD_STATUS_CALLBACK";
break;
case C_HA_DISCONNECT:
causeAsText = "C_HA_DISCONNECT";
break;
case C_FSA_INTERNAL:
causeAsText = "C_FSA_INTERNAL";
break;
case C_ILLEGAL:
causeAsText = "C_ILLEGAL";
break;
}
if(causeAsText == NULL) {
crm_err("Cause %d is unknown", cause);
causeAsText = "<UNKNOWN_CAUSE>";
}
return causeAsText;
}
const char *
fsa_action2string(long long action)
{
const char *actionAsText = NULL;
switch(action){
case A_NOTHING:
actionAsText = "A_NOTHING";
break;
case A_ELECTION_START:
actionAsText = "A_ELECTION_START";
break;
case A_READCONFIG:
actionAsText = "A_READCONFIG";
break;
case O_RELEASE:
actionAsText = "O_RELEASE";
break;
case A_STARTUP:
actionAsText = "A_STARTUP";
break;
case A_STARTED:
actionAsText = "A_STARTED";
break;
case A_HA_CONNECT:
actionAsText = "A_HA_CONNECT";
break;
case A_HA_DISCONNECT:
actionAsText = "A_HA_DISCONNECT";
break;
case A_LRM_CONNECT:
actionAsText = "A_LRM_CONNECT";
break;
case A_LRM_EVENT:
actionAsText = "A_LRM_EVENT";
break;
case A_LRM_INVOKE:
actionAsText = "A_LRM_INVOKE";
break;
case A_LRM_DISCONNECT:
actionAsText = "A_LRM_DISCONNECT";
break;
case A_CL_JOIN_QUERY:
actionAsText = "A_CL_JOIN_QUERY";
break;
case A_DC_TIMER_STOP:
actionAsText = "A_DC_TIMER_STOP";
break;
case A_DC_TIMER_START:
actionAsText = "A_DC_TIMER_START";
break;
case A_INTEGRATE_TIMER_START:
actionAsText = "A_INTEGRATE_TIMER_START";
break;
case A_INTEGRATE_TIMER_STOP:
actionAsText = "A_INTEGRATE_TIMER_STOP";
break;
case A_FINALIZE_TIMER_START:
actionAsText = "A_FINALIZE_TIMER_START";
break;
case A_FINALIZE_TIMER_STOP:
actionAsText = "A_FINALIZE_TIMER_STOP";
break;
case A_ELECTION_COUNT:
actionAsText = "A_ELECTION_COUNT";
break;
case A_ELECTION_VOTE:
actionAsText = "A_ELECTION_VOTE";
break;
case A_CL_JOIN_ANNOUNCE:
actionAsText = "A_CL_JOIN_ANNOUNCE";
break;
case A_CL_JOIN_REQUEST:
actionAsText = "A_CL_JOIN_REQUEST";
break;
case A_CL_JOIN_RESULT:
actionAsText = "A_CL_JOIN_RESULT";
break;
case A_DC_JOIN_OFFER_ALL:
actionAsText = "A_DC_JOIN_OFFER_ALL";
break;
case A_DC_JOIN_OFFER_ONE:
actionAsText = "A_DC_JOIN_OFFER_ONE";
break;
case A_DC_JOIN_PROCESS_REQ:
actionAsText = "A_DC_JOIN_PROCESS_REQ";
break;
case A_DC_JOIN_PROCESS_ACK:
actionAsText = "A_DC_JOIN_PROCESS_ACK";
break;
case A_DC_JOIN_FINALIZE:
actionAsText = "A_DC_JOIN_FINALIZE";
break;
case A_MSG_PROCESS:
actionAsText = "A_MSG_PROCESS";
break;
case A_MSG_ROUTE:
actionAsText = "A_MSG_ROUTE";
break;
case A_RECOVER:
actionAsText = "A_RECOVER";
break;
case A_DC_RELEASE:
actionAsText = "A_DC_RELEASE";
break;
case A_DC_RELEASED:
actionAsText = "A_DC_RELEASED";
break;
case A_DC_TAKEOVER:
actionAsText = "A_DC_TAKEOVER";
break;
case A_SHUTDOWN:
actionAsText = "A_SHUTDOWN";
break;
case A_SHUTDOWN_REQ:
actionAsText = "A_SHUTDOWN_REQ";
break;
case A_STOP:
actionAsText = "A_STOP ";
break;
case A_EXIT_0:
actionAsText = "A_EXIT_0";
break;
case A_EXIT_1:
actionAsText = "A_EXIT_1";
break;
case A_CCM_CONNECT:
actionAsText = "A_CCM_CONNECT";
break;
case A_CCM_DISCONNECT:
actionAsText = "A_CCM_DISCONNECT";
break;
case A_CCM_EVENT:
actionAsText = "A_CCM_EVENT";
break;
case A_CCM_UPDATE_CACHE:
actionAsText = "A_CCM_UPDATE_CACHE";
break;
case A_CIB_BUMPGEN:
actionAsText = "A_CIB_BUMPGEN";
break;
case A_CIB_INVOKE:
actionAsText = "A_CIB_INVOKE";
break;
case O_CIB_RESTART:
actionAsText = "O_CIB_RESTART";
break;
case A_CIB_START:
actionAsText = "A_CIB_START";
break;
case A_CIB_STOP:
actionAsText = "A_CIB_STOP";
break;
case A_TE_INVOKE:
actionAsText = "A_TE_INVOKE";
break;
case O_TE_RESTART:
actionAsText = "O_TE_RESTART";
break;
case A_TE_START:
actionAsText = "A_TE_START";
break;
case A_TE_STOP:
actionAsText = "A_TE_STOP";
break;
case A_TE_CANCEL:
actionAsText = "A_TE_CANCEL";
break;
case A_PE_INVOKE:
actionAsText = "A_PE_INVOKE";
break;
case O_PE_RESTART:
actionAsText = "O_PE_RESTART";
break;
case A_PE_START:
actionAsText = "A_PE_START";
break;
case A_PE_STOP:
actionAsText = "A_PE_STOP";
break;
case A_NODE_BLOCK:
actionAsText = "A_NODE_BLOCK";
break;
case A_UPDATE_NODESTATUS:
actionAsText = "A_UPDATE_NODESTATUS";
break;
case A_LOG:
actionAsText = "A_LOG ";
break;
case A_ERROR:
actionAsText = "A_ERROR ";
break;
case A_WARN:
actionAsText = "A_WARN ";
break;
}
if(actionAsText == NULL) {
crm_err("Action %.16llx is unknown", action);
actionAsText = "<UNKNOWN_ACTION>";
}
return actionAsText;
}
void
fsa_dump_inputs(int log_level, const char *text, long long input_register)
{
if(input_register == A_NOTHING) {
return;
}
if(text == NULL) {
text = "Input register contents:";
}
if(is_set(input_register, R_THE_DC)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_THE_DC)", text, R_THE_DC);
}
if(is_set(input_register, R_STARTING)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_STARTING)", text, R_STARTING);
}
if(is_set(input_register, R_SHUTDOWN)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_SHUTDOWN)", text, R_SHUTDOWN);
}
if(is_set(input_register, R_STAYDOWN)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_STAYDOWN)", text, R_STAYDOWN);
}
if(is_set(input_register, R_JOIN_OK)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_JOIN_OK)", text, R_JOIN_OK);
}
if(is_set(input_register, R_HAVE_RES)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_HAVE_RES)", text, R_HAVE_RES);
}
if(is_set(input_register, R_INVOKE_PE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_INVOKE_PE)", text, R_INVOKE_PE);
}
if(is_set(input_register, R_CIB_CONNECTED)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_CIB_CONNECTED)", text, R_CIB_CONNECTED);
}
if(is_set(input_register, R_PE_CONNECTED)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_PE_CONNECTED)", text, R_PE_CONNECTED);
}
if(is_set(input_register, R_TE_CONNECTED)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_TE_CONNECTED)", text, R_TE_CONNECTED);
}
if(is_set(input_register, R_LRM_CONNECTED)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_LRM_CONNECTED)", text, R_LRM_CONNECTED);
}
if(is_set(input_register, R_CIB_REQUIRED)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_CIB_REQUIRED)", text, R_CIB_REQUIRED);
}
if(is_set(input_register, R_PE_REQUIRED)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_PE_REQUIRED)", text, R_PE_REQUIRED);
}
if(is_set(input_register, R_TE_REQUIRED)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_TE_REQUIRED)", text, R_TE_REQUIRED);
}
if(is_set(input_register, R_REQ_PEND)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_REQ_PEND)", text, R_REQ_PEND);
}
if(is_set(input_register, R_PE_PEND)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_PE_PEND)", text, R_PE_PEND);
}
if(is_set(input_register, R_TE_PEND)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_TE_PEND)", text, R_TE_PEND);
}
if(is_set(input_register, R_RESP_PEND)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_RESP_PEND)", text, R_RESP_PEND);
}
if(is_set(input_register, R_CIB_DONE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_CIB_DONE)", text, R_CIB_DONE);
}
if(is_set(input_register, R_HAVE_CIB)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_HAVE_CIB)", text, R_HAVE_CIB);
}
if(is_set(input_register, R_CIB_ASKED)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_CIB_ASKED)", text, R_CIB_ASKED);
}
if(is_set(input_register, R_CCM_DATA)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_CCM_DATA)", text, R_CCM_DATA);
}
if(is_set(input_register, R_PEER_DATA)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_PEER_DATA)", text, R_PEER_DATA);
}
if(is_set(input_register, R_IN_RECOVERY)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_IN_RECOVERY)", text, R_IN_RECOVERY);
}
}
void
fsa_dump_actions(long long action, const char *text)
{
int log_level = LOG_DEBUG_3;
if(is_set(action, A_READCONFIG)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_READCONFIG) %s", A_READCONFIG, text);
}
if(is_set(action, A_STARTUP)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_STARTUP) %s", A_STARTUP, text);
}
if(is_set(action, A_STARTED)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_STARTED) %s", A_STARTED, text);
}
if(is_set(action, A_HA_CONNECT)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CONNECT) %s", A_HA_CONNECT, text);
}
if(is_set(action, A_HA_DISCONNECT)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_DISCONNECT) %s",
A_HA_DISCONNECT, text);
}
if(is_set(action, A_LRM_CONNECT)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_LRM_CONNECT) %s",
A_LRM_CONNECT, text);
}
if(is_set(action, A_LRM_EVENT)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_LRM_EVENT) %s",
A_LRM_EVENT, text);
}
if(is_set(action, A_LRM_INVOKE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_LRM_INVOKE) %s",
A_LRM_INVOKE, text);
}
if(is_set(action, A_LRM_DISCONNECT)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_LRM_DISCONNECT) %s",
A_LRM_DISCONNECT, text);
}
if(is_set(action, A_DC_TIMER_STOP)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_DC_TIMER_STOP) %s",
A_DC_TIMER_STOP, text);
}
if(is_set(action, A_DC_TIMER_START)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_DC_TIMER_START) %s",
A_DC_TIMER_START, text);
}
if(is_set(action, A_INTEGRATE_TIMER_START)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_INTEGRATE_TIMER_START) %s",
A_INTEGRATE_TIMER_START, text);
}
if(is_set(action, A_INTEGRATE_TIMER_STOP)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_INTEGRATE_TIMER_STOP) %s",
A_INTEGRATE_TIMER_STOP, text);
}
if(is_set(action, A_FINALIZE_TIMER_START)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_FINALIZE_TIMER_START) %s",
A_FINALIZE_TIMER_START, text);
}
if(is_set(action, A_FINALIZE_TIMER_STOP)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_FINALIZE_TIMER_STOP) %s",
A_FINALIZE_TIMER_STOP, text);
}
if(is_set(action, A_ELECTION_COUNT)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_ELECTION_COUNT) %s",
A_ELECTION_COUNT, text);
}
if(is_set(action, A_ELECTION_VOTE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_ELECTION_VOTE) %s",
A_ELECTION_VOTE, text);
}
if(is_set(action, A_CL_JOIN_ANNOUNCE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CL_JOIN_ANNOUNCE) %s",
A_CL_JOIN_ANNOUNCE, text);
}
if(is_set(action, A_CL_JOIN_REQUEST)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CL_JOIN_REQUEST) %s",
A_CL_JOIN_REQUEST, text);
}
if(is_set(action, A_CL_JOIN_RESULT)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CL_JOIN_RESULT) %s",
A_CL_JOIN_RESULT, text);
}
if(is_set(action, A_DC_JOIN_OFFER_ALL)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_DC_JOIN_OFFER_ALL) %s",
A_DC_JOIN_OFFER_ALL, text);
}
if(is_set(action, A_DC_JOIN_OFFER_ONE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_DC_JOIN_OFFER_ONE) %s",
A_DC_JOIN_OFFER_ONE, text);
}
if(is_set(action, A_DC_JOIN_PROCESS_REQ)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_DC_JOIN_PROCESS_REQ) %s",
A_DC_JOIN_PROCESS_REQ, text);
}
if(is_set(action, A_DC_JOIN_PROCESS_ACK)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_DC_JOIN_PROCESS_ACK) %s",
A_DC_JOIN_PROCESS_ACK, text);
}
if(is_set(action, A_DC_JOIN_FINALIZE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_DC_JOIN_FINALIZE) %s",
A_DC_JOIN_FINALIZE, text);
}
if(is_set(action, A_MSG_PROCESS)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_MSG_PROCESS) %s",
A_MSG_PROCESS, text);
}
if(is_set(action, A_MSG_ROUTE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_MSG_ROUTE) %s",
A_MSG_ROUTE, text);
}
if(is_set(action, A_RECOVER)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_RECOVER) %s",
A_RECOVER, text);
}
if(is_set(action, A_DC_RELEASE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_DC_RELEASE) %s",
A_DC_RELEASE, text);
}
if(is_set(action, A_DC_RELEASED)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_DC_RELEASED) %s",
A_DC_RELEASED, text);
}
if(is_set(action, A_DC_TAKEOVER)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_DC_TAKEOVER) %s",
A_DC_TAKEOVER, text);
}
if(is_set(action, A_SHUTDOWN)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_SHUTDOWN) %s", A_SHUTDOWN, text);
}
if(is_set(action, A_SHUTDOWN_REQ)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_SHUTDOWN_REQ) %s",
A_SHUTDOWN_REQ, text);
}
if(is_set(action, A_STOP)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_STOP ) %s", A_STOP , text);
}
if(is_set(action, A_EXIT_0)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_EXIT_0) %s", A_EXIT_0, text);
}
if(is_set(action, A_EXIT_1)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_EXIT_1) %s", A_EXIT_1, text);
}
if(is_set(action, A_CCM_CONNECT)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CCM_CONNECT) %s",
A_CCM_CONNECT, text);
}
if(is_set(action, A_CCM_DISCONNECT)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CCM_DISCONNECT) %s",
A_CCM_DISCONNECT, text);
}
if(is_set(action, A_CCM_EVENT)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CCM_EVENT) %s",
A_CCM_EVENT, text);
}
if(is_set(action, A_CCM_UPDATE_CACHE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CCM_UPDATE_CACHE) %s",
A_CCM_UPDATE_CACHE, text);
}
if(is_set(action, A_CIB_BUMPGEN)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CIB_BUMPGEN) %s",
A_CIB_BUMPGEN, text);
}
if(is_set(action, A_CIB_INVOKE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CIB_INVOKE) %s",
A_CIB_INVOKE, text);
}
if(is_set(action, A_CIB_START)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CIB_START) %s",
A_CIB_START, text);
}
if(is_set(action, A_CIB_STOP)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CIB_STOP) %s", A_CIB_STOP, text);
}
if(is_set(action, A_TE_INVOKE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_TE_INVOKE) %s", A_TE_INVOKE, text);
}
if(is_set(action, A_TE_START)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_TE_START) %s",
A_TE_START, text);
}
if(is_set(action, A_TE_STOP)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_TE_STOP) %s", A_TE_STOP, text);
}
if(is_set(action, A_TE_CANCEL)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_TE_CANCEL) %s",
A_TE_CANCEL, text);
}
if(is_set(action, A_PE_INVOKE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_PE_INVOKE) %s",
A_PE_INVOKE, text);
}
if(is_set(action, A_PE_START)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_PE_START) %s", A_PE_START, text);
}
if(is_set(action, A_PE_STOP)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_PE_STOP) %s", A_PE_STOP, text);
}
if(is_set(action, A_NODE_BLOCK)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_NODE_BLOCK) %s",
A_NODE_BLOCK, text);
}
if(is_set(action, A_UPDATE_NODESTATUS)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_UPDATE_NODESTATUS) %s",
A_UPDATE_NODESTATUS, text);
}
if(is_set(action, A_LOG)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_LOG ) %s", A_LOG, text);
}
if(is_set(action, A_ERROR)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_ERROR ) %s", A_ERROR, text);
}
if(is_set(action, A_WARN)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_WARN ) %s", A_WARN, text);
}
}
void
create_node_entry(const char *uuid, const char *uname, const char *type)
{
/* make sure a node entry exists for the new node
*
* this will add anyone except the first ever node in the cluster
* since it will also be the DC which doesnt go through the
* join process (with itself). We can include a special case
* later if desired.
*/
crm_data_t *tmp1 = create_xml_node(NULL, XML_CIB_TAG_NODE);
crm_debug_3("Creating node entry for %s", uname);
set_uuid(fsa_cluster_conn, tmp1, XML_ATTR_UUID, uname);
crm_xml_add(tmp1, XML_ATTR_UNAME, uname);
crm_xml_add(tmp1, XML_ATTR_TYPE, type);
update_local_cib(create_cib_fragment(tmp1, NULL));
free_xml(tmp1);
}
struct crmd_ccm_data_s *
copy_ccm_data(const struct crmd_ccm_data_s *ccm_input)
{
const oc_ev_membership_t *oc_in =
(const oc_ev_membership_t *)ccm_input->oc;
struct crmd_ccm_data_s *ccm_input_copy = NULL;
crm_malloc0(ccm_input_copy, sizeof(struct crmd_ccm_data_s));
ccm_input_copy->oc = copy_ccm_oc_data(oc_in);
ccm_input_copy->event = ccm_input->event;
return ccm_input_copy;
}
oc_ev_membership_t *
copy_ccm_oc_data(const oc_ev_membership_t *oc_in)
{
unsigned lpc = 0;
int size = 0;
int offset = 0;
unsigned num_nodes = 0;
oc_ev_membership_t *oc_copy = NULL;
if(oc_in->m_n_member > 0
&& num_nodes < oc_in->m_n_member + oc_in->m_memb_idx) {
num_nodes = oc_in->m_n_member + oc_in->m_memb_idx;
crm_debug_3("Updated ccm nodes to %d - 1", num_nodes);
}
if(oc_in->m_n_in > 0
&& num_nodes < oc_in->m_n_in + oc_in->m_in_idx) {
num_nodes = oc_in->m_n_in + oc_in->m_in_idx;
crm_debug_3("Updated ccm nodes to %d - 2", num_nodes);
}
if(oc_in->m_n_out > 0
&& num_nodes < oc_in->m_n_out + oc_in->m_out_idx) {
num_nodes = oc_in->m_n_out + oc_in->m_out_idx;
crm_debug_3("Updated ccm nodes to %d - 3", num_nodes);
}
/* why 2*??
* ccm code does it like this so i guess its right...
*/
size = sizeof(oc_ev_membership_t)
+ sizeof(int)
+ 2*num_nodes*sizeof(oc_node_t);
crm_debug_3("Copying %d ccm nodes", num_nodes);
crm_malloc0(oc_copy, size);
oc_copy->m_instance = oc_in->m_instance;
oc_copy->m_n_member = oc_in->m_n_member;
oc_copy->m_memb_idx = oc_in->m_memb_idx;
oc_copy->m_n_out = oc_in->m_n_out;
oc_copy->m_out_idx = oc_in->m_out_idx;
oc_copy->m_n_in = oc_in->m_n_in;
oc_copy->m_in_idx = oc_in->m_in_idx;
crm_debug_3("instance=%d, nodes=%d (idx=%d), new=%d (idx=%d), lost=%d (idx=%d)",
oc_in->m_instance,
oc_in->m_n_member,
oc_in->m_memb_idx,
oc_in->m_n_in,
oc_in->m_in_idx,
oc_in->m_n_out,
oc_in->m_out_idx);
offset = oc_in->m_memb_idx;
for(lpc = 0; lpc < oc_in->m_n_member; lpc++) {
oc_node_t a_node = oc_in->m_array[lpc+offset];
oc_node_t *a_node_copy = &(oc_copy->m_array[lpc+offset]);
crm_debug_3("Copying ccm member node %d", lpc);
copy_ccm_node(a_node, a_node_copy);
}
offset = oc_in->m_in_idx;
for(lpc = 0; lpc < oc_in->m_n_in; lpc++) {
oc_node_t a_node = oc_in->m_array[lpc+offset];
oc_node_t *a_node_copy = &(oc_copy->m_array[lpc+offset]);
crm_debug_3("Copying ccm new node %d", lpc);
copy_ccm_node(a_node, a_node_copy);
}
offset = oc_in->m_out_idx;
for(lpc = 0; lpc < oc_in->m_n_out; lpc++) {
oc_node_t a_node = oc_in->m_array[lpc+offset];
oc_node_t *a_node_copy = &(oc_copy->m_array[lpc+offset]);
crm_debug_3("Copying ccm lost node %d", lpc);
copy_ccm_node(a_node, a_node_copy);
}
return oc_copy;
}
void
copy_ccm_node(oc_node_t a_node, oc_node_t *a_node_copy)
{
crm_debug_3("Copying ccm node: id=%d, born=%d, uname=%s",
a_node.node_id, a_node.node_born_on,
a_node.node_uname);
a_node_copy->node_id = a_node.node_id;
a_node_copy->node_born_on = a_node.node_born_on;
a_node_copy->node_uname = NULL;
if(a_node.node_uname != NULL) {
a_node_copy->node_uname =
crm_strdup(a_node.node_uname);
} else {
crm_err("Node Id %d had a NULL uname!",
a_node.node_id);
}
crm_debug_3("Copied ccm node: id=%d, born=%d, uname=%s",
a_node_copy->node_id, a_node_copy->node_born_on,
a_node_copy->node_uname);
}
lrm_op_t *
copy_lrm_op(const lrm_op_t *op)
{
lrm_op_t *op_copy = NULL;
crm_malloc0(op_copy, sizeof(lrm_op_t));
op_copy->op_type = crm_strdup(op->op_type);
/* input fields */
/* GHashTable* params; */
op_copy->params = NULL;
op_copy->timeout = op->timeout;
op_copy->interval = op->interval;
op_copy->target_rc = op->target_rc;
/* in the CRM, this is always an int */
if(op->user_data != NULL) {
op_copy->user_data = crm_strdup(op->user_data);
}
/* output fields */
op_copy->op_status = op->op_status;
op_copy->rc = op->rc;
op_copy->call_id = op->call_id;
op_copy->output = NULL;
op_copy->rsc_id = crm_strdup(op->rsc_id);
op_copy->app_name = crm_strdup(op->app_name);
if(op->output!= NULL) {
op_copy->output = crm_strdup(op->output);
}
return op_copy;
}
lrm_rsc_t *
copy_lrm_rsc(const lrm_rsc_t *rsc)
{
lrm_rsc_t *rsc_copy = NULL;
if(rsc == NULL) {
return NULL;
}
crm_malloc0(rsc_copy, sizeof(lrm_rsc_t));
rsc_copy->id = crm_strdup(rsc->id);
rsc_copy->type = crm_strdup(rsc->type);
rsc_copy->class = NULL;
rsc_copy->provider = NULL;
if(rsc->class != NULL) {
rsc_copy->class = crm_strdup(rsc->class);
}
if(rsc->provider != NULL) {
rsc_copy->provider = crm_strdup(rsc->provider);
}
/* GHashTable* params; */
rsc_copy->params = NULL;
rsc_copy->ops = NULL;
return rsc_copy;
}
crm_data_t*
create_node_state(
const char *uuid, const char *uname,
const char *ha_state, const char *ccm_state,
const char *crmd_state, const char *join_state, const char *exp_state,
const char *src)
{
crm_data_t *node_state = create_xml_node(NULL, XML_CIB_TAG_STATE);
crm_debug_2("%s Creating node state entry for %s", src, uname);
set_uuid(fsa_cluster_conn, node_state, XML_ATTR_UUID, uname);
crm_xml_add(node_state, XML_ATTR_UNAME, uname);
crm_xml_add(node_state, XML_CIB_ATTR_HASTATE, ha_state);
crm_xml_add(node_state, XML_CIB_ATTR_INCCM, ccm_state);
crm_xml_add(node_state, XML_CIB_ATTR_CRMDSTATE, crmd_state);
crm_xml_add(node_state, XML_CIB_ATTR_JOINSTATE, join_state);
crm_xml_add(node_state, XML_CIB_ATTR_EXPSTATE, exp_state);
crm_xml_add(node_state, "origin", src);
crm_log_xml_debug_3(node_state, "created");
return node_state;
}
gboolean
need_transition(enum crmd_fsa_state state)
{
if(state == S_POLICY_ENGINE
|| state == S_TRANSITION_ENGINE
|| state == S_IDLE) {
return TRUE;
}
return FALSE;
}
extern GHashTable *ipc_clients;
void
process_client_disconnect(crmd_client_t *curr_client)
{
struct crm_subsystem_s *the_subsystem = NULL;
CRM_DEV_ASSERT(curr_client != NULL);
if(crm_assert_failed) { return; }
crm_debug_2("received HUP from %s", curr_client->table_key);
if (curr_client->sub_sys == NULL) {
crm_debug("Client hadn't registered with us yet");
} else if (strcmp(CRM_SYSTEM_PENGINE, curr_client->sub_sys) == 0) {
the_subsystem = pe_subsystem;
} else if (strcmp(CRM_SYSTEM_TENGINE, curr_client->sub_sys) == 0) {
the_subsystem = te_subsystem;
} else if (strcmp(CRM_SYSTEM_CIB, curr_client->sub_sys) == 0){
the_subsystem = cib_subsystem;
}
if(the_subsystem != NULL) {
the_subsystem->ipc = NULL;
} /* else that was a transient client */
if (curr_client->table_key != NULL) {
/*
* Key is destroyed below:
* curr_client->table_key
* Value is cleaned up by:
* G_main_del_IPC_Channel
*/
g_hash_table_remove(ipc_clients, curr_client->table_key);
}
crm_free(curr_client->table_key);
crm_free(curr_client->sub_sys);
crm_free(curr_client->uuid);
crm_free(curr_client);
}
diff --git a/crm/pengine/pe_utils.h b/crm/pengine/pe_utils.h
index 3e45f49b48..ee04868e1e 100644
--- a/crm/pengine/pe_utils.h
+++ b/crm/pengine/pe_utils.h
@@ -1,151 +1,151 @@
-/* $Id: pe_utils.h,v 1.27 2005/06/16 12:36:20 andrew Exp $ */
+/* $Id: pe_utils.h,v 1.28 2005/07/03 22:15:49 alan Exp $ */
/*
* 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.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
*/
#ifndef PE_UTILS__H
#define PE_UTILS__H
/* General utilities */
extern resource_t *pe_find_resource(GListPtr rsc_list, const char *id_rh);
extern float merge_weights(float w1, float w2);
/* Constraint helper functions */
extern rsc_colocation_t *invert_constraint(rsc_colocation_t *constraint);
extern rsc_to_node_t *copy_constraint(rsc_to_node_t *constraint);
/* Color helper functions */
extern void add_color_to_rsc(resource_t *rsc, color_t *color);
extern color_t *find_color(GListPtr candidate_colors, color_t *other_color);
extern color_t *create_color(
pe_working_set_t *data_set, resource_t *resource, GListPtr resources);
extern color_t *copy_color(color_t *a_color);
/* Node helper functions */
extern node_t *pe_find_node(GListPtr node_list, const char *uname);
extern node_t *pe_find_node_id(GListPtr node_list, const char *id);
extern node_t *node_copy(node_t *this_node) ;
/* Binary like operators for lists of nodes */
extern GListPtr node_list_dup(GListPtr list1, gboolean filter);
extern GListPtr node_list_and(GListPtr list1, GListPtr list2, gboolean filter);
extern GListPtr node_list_xor(GListPtr list1, GListPtr list2, gboolean filter);
extern GListPtr node_list_minus(GListPtr list1,GListPtr list2,gboolean filter);
extern gboolean node_list_eq(GListPtr list1, GListPtr list2, gboolean filter);
extern GListPtr node_list_or(GListPtr list1, GListPtr list2, gboolean filter);
/* For creating the transition graph */
extern crm_data_t *action2xml(action_t *action, gboolean as_input);
/* Printing functions for debug */
extern void print_node(
const char *pre_text, node_t *node, gboolean details);
extern void print_resource(
const char *pre_text, resource_t *rsc, gboolean details);
extern void print_rsc_to_node(
const char *pre_text, rsc_to_node_t *cons, gboolean details);
extern void print_rsc_colocation(
const char *pre_text, rsc_colocation_t *cons, gboolean details);
extern void print_color(
const char *pre_text, color_t *color, gboolean details);
extern void print_color_details(
const char *pre_text, struct color_shared_s *color, gboolean details);
extern void print_action(
const char *pre_text, action_t *action, gboolean details);
extern void log_action(
- int log_level, const char *pre_text, action_t *action, gboolean details);
+ unsigned int log_level, const char *pre_text, action_t *action, gboolean details);
/* Sorting functions */
extern gint sort_rsc_priority(gconstpointer a, gconstpointer b);
extern gint sort_cons_strength(gconstpointer a, gconstpointer b);
extern gint sort_color_weight(gconstpointer a, gconstpointer b);
extern gint sort_node_weight(gconstpointer a, gconstpointer b);
extern gint sort_action_id(gconstpointer a, gconstpointer b);
/* enum 2 text functions (mostly used by print_*) */
extern const char *contype2text(enum con_type type);
extern const char *strength2text(enum con_strength strength);
/*extern const char *modifier2text(enum con_modifier modifier); */
extern const char *task2text(enum action_tasks task);
extern enum action_tasks text2task(const char *task);
extern crm_data_t *find_rsc_op_entry(resource_t *rsc, const char *key);
extern action_t *custom_action(
resource_t *rsc, char *key, const char *task,
node_t *on_node, gboolean optional, pe_working_set_t *data_set);
#define stop_action(rsc, node, optional) custom_action( \
rsc, stop_key(rsc), CRMD_ACTION_STOP, node, optional, data_set);
#define stopped_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_STOPPED, 0)
#define stop_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_STOP, 0)
#define start_action(rsc, node, optional) custom_action( \
rsc, start_key(rsc), CRMD_ACTION_START, node, optional, data_set)
#define started_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_STARTED, 0)
#define start_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_START, 0)
extern GListPtr find_actions(GListPtr input, const char *key, node_t *on_node);
extern void set_id(crm_data_t *xml_obj, const char *prefix, int child);
extern const char *ordering_type2text(enum pe_ordering type);
/* free the various structures */
extern void pe_free_nodes(GListPtr nodes);
extern void pe_free_colors(GListPtr colors);
extern void pe_free_rsc_colocation(rsc_colocation_t *cons);
extern void pe_free_rsc_to_node(rsc_to_node_t *cons);
extern void pe_free_shallow(GListPtr alist);
extern void pe_free_shallow_adv(GListPtr alist, gboolean with_data);
extern void pe_free_resources(GListPtr resources);
extern void pe_free_actions(GListPtr actions);
extern void pe_free_ordering(GListPtr constraints);
/* Helper macros to avoid NULL pointers */
#define safe_val(def, x,y) (x?x->y:def)
#define safe_val3(def, t,u,v) (t?t->u?t->u->v:def:def)
#define safe_val4(def, t,u,v,w) (t?t->u?t->u->v?t->u->v->w:def:def:def)
#define safe_val5(def, t,u,v,w,x) (t?t->u?t->u->v?t->u->v->w?t->u->v->w->x:def:def:def:def)
#define safe_val6(def, t,u,v,w,x,y) (t?t->u?t->u->v?t->u->v->w?t->u->v->w->x?t->u->v->w->x->y:def:def:def:def:def)
#define safe_val7(def, t,u,v,w,x,y,z) (t?t->u?t->u->v?t->u->v->w?t->u->v->w->x?t->u->v->w->x->y?t->u->v->w->x->y->z:def:def:def:def:def:def)
#endif
diff --git a/crm/pengine/utils.c b/crm/pengine/utils.c
index f8fdcf3b87..655c9a16a4 100644
--- a/crm/pengine/utils.c
+++ b/crm/pengine/utils.c
@@ -1,1466 +1,1466 @@
-/* $Id: utils.c,v 1.88 2005/06/27 11:21:23 andrew Exp $ */
+/* $Id: utils.c,v 1.89 2005/07/03 22:15:49 alan Exp $ */
/*
* 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.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 <portability.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/util.h>
#include <glib.h>
#include <pengine.h>
#include <pe_utils.h>
void print_str_str(gpointer key, gpointer value, gpointer user_data);
gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data);
void unpack_operation(
action_t *action, crm_data_t *xml_obj, pe_working_set_t* data_set);
/* only for rsc_colocation constraints */
rsc_colocation_t *
invert_constraint(rsc_colocation_t *constraint)
{
rsc_colocation_t *inverted_con = NULL;
crm_debug_3("Inverting constraint");
if(constraint == NULL) {
pe_err("Cannot invert NULL constraint");
return NULL;
}
crm_malloc0(inverted_con, sizeof(rsc_colocation_t));
if(inverted_con == NULL) {
return NULL;
}
inverted_con->id = constraint->id;
inverted_con->strength = constraint->strength;
/* swap the direction */
inverted_con->rsc_lh = constraint->rsc_rh;
inverted_con->rsc_rh = constraint->rsc_lh;
crm_action_debug_3(
print_rsc_colocation("Inverted constraint", inverted_con, FALSE));
return inverted_con;
}
/* are the contents of list1 and list2 equal
* nodes with weight < 0 are ignored if filter == TRUE
*
* slow but linear
*
*/
gboolean
node_list_eq(GListPtr list1, GListPtr list2, gboolean filter)
{
node_t *other_node;
GListPtr lhs = list1;
GListPtr rhs = list2;
slist_iter(
node, node_t, lhs, lpc,
if(node == NULL || (filter && node->weight < 0)) {
continue;
}
other_node = (node_t*)
pe_find_node(rhs, node->details->uname);
if(other_node == NULL || other_node->weight < 0) {
return FALSE;
}
);
lhs = list2;
rhs = list1;
slist_iter(
node, node_t, lhs, lpc,
if(node == NULL || (filter && node->weight < 0)) {
continue;
}
other_node = (node_t*)
pe_find_node(rhs, node->details->uname);
if(other_node == NULL || other_node->weight < 0) {
return FALSE;
}
);
return TRUE;
}
/* the intersection of list1 and list2
*/
GListPtr
node_list_and(GListPtr list1, GListPtr list2, gboolean filter)
{
GListPtr result = NULL;
unsigned lpc = 0;
for(lpc = 0; lpc < g_list_length(list1); lpc++) {
node_t *node = (node_t*)g_list_nth_data(list1, lpc);
node_t *other_node = pe_find_node(list2, node->details->uname);
node_t *new_node = NULL;
if(other_node != NULL) {
new_node = node_copy(node);
}
if(new_node != NULL) {
new_node->weight = merge_weights(
new_node->weight, other_node->weight);
if(filter && new_node->weight < 0) {
crm_free(new_node);
new_node = NULL;
}
}
if(new_node != NULL) {
result = g_list_append(result, new_node);
}
}
return result;
}
/* list1 - list2 */
GListPtr
node_list_minus(GListPtr list1, GListPtr list2, gboolean filter)
{
GListPtr result = NULL;
slist_iter(
node, node_t, list1, lpc,
node_t *other_node = pe_find_node(list2, node->details->uname);
node_t *new_node = NULL;
if(node == NULL || other_node != NULL
|| (filter && node->weight < 0)) {
continue;
}
new_node = node_copy(node);
result = g_list_append(result, new_node);
);
crm_debug_3("Minus result len: %d", g_list_length(result));
return result;
}
/* list1 + list2 - (intersection of list1 and list2) */
GListPtr
node_list_xor(GListPtr list1, GListPtr list2, gboolean filter)
{
GListPtr result = NULL;
slist_iter(
node, node_t, list1, lpc,
node_t *new_node = NULL;
node_t *other_node = (node_t*)
pe_find_node(list2, node->details->uname);
if(node == NULL || other_node != NULL
|| (filter && node->weight < 0)) {
continue;
}
new_node = node_copy(node);
result = g_list_append(result, new_node);
);
slist_iter(
node, node_t, list2, lpc,
node_t *new_node = NULL;
node_t *other_node = (node_t*)
pe_find_node(list1, node->details->uname);
if(node == NULL || other_node != NULL
|| (filter && node->weight < 0)) {
continue;
}
new_node = node_copy(node);
result = g_list_append(result, new_node);
);
crm_debug_3("Xor result len: %d", g_list_length(result));
return result;
}
GListPtr
node_list_or(GListPtr list1, GListPtr list2, gboolean filter)
{
node_t *other_node = NULL;
GListPtr result = NULL;
gboolean needs_filter = FALSE;
result = node_list_dup(list1, filter);
slist_iter(
node, node_t, list2, lpc,
if(node == NULL) {
continue;
}
other_node = (node_t*)pe_find_node(
result, node->details->uname);
if(other_node != NULL) {
other_node->weight = merge_weights(
other_node->weight, node->weight);
if(filter && node->weight < 0) {
needs_filter = TRUE;
}
} else if(filter == FALSE || node->weight >= 0) {
node_t *new_node = node_copy(node);
result = g_list_append(result, new_node);
}
);
/* not the neatest way, but the most expedient for now */
if(filter && needs_filter) {
GListPtr old_result = result;
result = node_list_dup(old_result, filter);
pe_free_shallow_adv(old_result, TRUE);
}
return result;
}
GListPtr
node_list_dup(GListPtr list1, gboolean filter)
{
GListPtr result = NULL;
slist_iter(
this_node, node_t, list1, lpc,
node_t *new_node = NULL;
if(filter && this_node->weight < 0) {
continue;
}
new_node = node_copy(this_node);
if(new_node != NULL) {
result = g_list_append(result, new_node);
}
);
return result;
}
node_t *
node_copy(node_t *this_node)
{
node_t *new_node = NULL;
CRM_DEV_ASSERT(this_node != NULL);
if(this_node == NULL) {
pe_err("Failed copy of <null> node.");
return NULL;
}
crm_malloc0(new_node, sizeof(node_t));
CRM_DEV_ASSERT(new_node != NULL);
if(new_node == NULL) {
return NULL;
}
crm_debug_5("Copying %p (%s) to %p",
this_node, this_node->details->uname, new_node);
new_node->weight = this_node->weight;
new_node->fixed = this_node->fixed;
new_node->details = this_node->details;
return new_node;
}
/*
* Create a new color with the contents of "nodes" as the list of
* possible nodes that resources with this color can be run on.
*
* Typically, when creating a color you will provide the node list from
* the resource you will first assign the color to.
*
* If "colors" != NULL, it will be added to that list
* If "resources" != NULL, it will be added to every provisional resource
* in that list
*/
color_t *
create_color(
pe_working_set_t *data_set, resource_t *resource, GListPtr node_list)
{
color_t *new_color = NULL;
crm_debug_5("Creating color");
crm_malloc0(new_color, sizeof(color_t));
if(new_color == NULL) {
return NULL;
}
new_color->id = data_set->color_id++;
new_color->local_weight = 1.0;
crm_debug_5("Creating color details");
crm_malloc0(new_color->details, sizeof(struct color_shared_s));
if(new_color->details == NULL) {
crm_free(new_color);
return NULL;
}
new_color->details->id = new_color->id;
new_color->details->highest_priority = -1;
new_color->details->chosen_node = NULL;
new_color->details->candidate_nodes = NULL;
new_color->details->allocated_resources = NULL;
new_color->details->pending = TRUE;
if(resource != NULL) {
crm_debug_5("populating node list");
new_color->details->highest_priority = resource->priority;
new_color->details->candidate_nodes =
node_list_dup(node_list, TRUE);
}
crm_action_debug_3(print_color("Created color", new_color, TRUE));
CRM_DEV_ASSERT(data_set != NULL);
if(crm_assert_failed == FALSE) {
data_set->colors = g_list_append(data_set->colors, new_color);
}
return new_color;
}
color_t *
copy_color(color_t *a_color)
{
color_t *color_copy = NULL;
if(a_color == NULL) {
pe_err("Cannot copy NULL");
return NULL;
}
crm_malloc0(color_copy, sizeof(color_t));
if(color_copy != NULL) {
color_copy->id = a_color->id;
color_copy->details = a_color->details;
color_copy->local_weight = 1.0;
}
return color_copy;
}
resource_t *
pe_find_resource(GListPtr rsc_list, const char *id)
{
unsigned lpc = 0;
resource_t *rsc = NULL;
resource_t *child_rsc = NULL;
crm_debug_4("Looking for %s in %d objects", id, g_list_length(rsc_list));
for(lpc = 0; lpc < g_list_length(rsc_list); lpc++) {
rsc = g_list_nth_data(rsc_list, lpc);
if(rsc != NULL && safe_str_eq(rsc->id, id)){
crm_debug_4("Found a match for %s", id);
return rsc;
}
}
for(lpc = 0; lpc < g_list_length(rsc_list); lpc++) {
rsc = g_list_nth_data(rsc_list, lpc);
child_rsc = rsc->fns->find_child(rsc, id);
if(child_rsc != NULL) {
crm_debug_4("Found a match for %s in %s",
id, rsc->id);
return child_rsc;
}
}
/* error */
return NULL;
}
node_t *
pe_find_node(GListPtr nodes, const char *uname)
{
unsigned lpc = 0;
node_t *node = NULL;
for(lpc = 0; lpc < g_list_length(nodes); lpc++) {
node = g_list_nth_data(nodes, lpc);
if(node != NULL && safe_str_eq(node->details->uname, uname)) {
return node;
}
}
/* error */
return NULL;
}
node_t *
pe_find_node_id(GListPtr nodes, const char *id)
{
unsigned lpc = 0;
node_t *node = NULL;
for(lpc = 0; lpc < g_list_length(nodes); lpc++) {
node = g_list_nth_data(nodes, lpc);
if(safe_str_eq(node->details->id, id)) {
return node;
}
}
/* error */
return NULL;
}
gint gslist_color_compare(gconstpointer a, gconstpointer b);
color_t *
find_color(GListPtr candidate_colors, color_t *other_color)
{
GListPtr tmp = g_list_find_custom(candidate_colors, other_color,
gslist_color_compare);
if(tmp != NULL) {
return (color_t *)tmp->data;
}
return NULL;
}
gint gslist_color_compare(gconstpointer a, gconstpointer b)
{
const color_t *color_a = (const color_t*)a;
const color_t *color_b = (const color_t*)b;
/* crm_debug_5("%d vs. %d", a?color_a->id:-2, b?color_b->id:-2); */
if(a == b) {
return 0;
} else if(a == NULL || b == NULL) {
return 1;
} else if(color_a->id == color_b->id) {
return 0;
}
return 1;
}
gint sort_rsc_priority(gconstpointer a, gconstpointer b)
{
const resource_t *resource1 = (const resource_t*)a;
const resource_t *resource2 = (const resource_t*)b;
if(a == NULL && b == NULL) { return 0; }
if(a == NULL) { return 1; }
if(b == NULL) { return -1; }
if(resource1->priority > resource2->priority) {
return -1;
}
if(resource1->priority < resource2->priority) {
return 1;
}
return 0;
}
/* lowest to highest */
gint sort_action_id(gconstpointer a, gconstpointer b)
{
const action_wrapper_t *action_wrapper2 = (const action_wrapper_t*)a;
const action_wrapper_t *action_wrapper1 = (const action_wrapper_t*)b;
if(a == NULL) { return 1; }
if(b == NULL) { return -1; }
if(action_wrapper1->action->id > action_wrapper2->action->id) {
return -1;
}
if(action_wrapper1->action->id < action_wrapper2->action->id) {
return 1;
}
return 0;
}
gint sort_cons_strength(gconstpointer a, gconstpointer b)
{
const rsc_colocation_t *rsc_constraint1 = (const rsc_colocation_t*)a;
const rsc_colocation_t *rsc_constraint2 = (const rsc_colocation_t*)b;
if(a == NULL) { return 1; }
if(b == NULL) { return -1; }
if(rsc_constraint1->strength > rsc_constraint2->strength) {
return 1;
}
if(rsc_constraint1->strength < rsc_constraint2->strength) {
return -1;
}
return 0;
}
gint sort_color_weight(gconstpointer a, gconstpointer b)
{
const color_t *color1 = (const color_t*)a;
const color_t *color2 = (const color_t*)b;
if(a == NULL) { return 1; }
if(b == NULL) { return -1; }
if(color1->local_weight > color2->local_weight) {
return -1;
}
if(color1->local_weight < color2->local_weight) {
return 1;
}
return 0;
}
/* return -1 if 'a' is more preferred
* return 1 if 'b' is more preferred
*/
gint sort_node_weight(gconstpointer a, gconstpointer b)
{
const node_t *node1 = (const node_t*)a;
const node_t *node2 = (const node_t*)b;
float node1_weight = 0;
float node2_weight = 0;
if(a == NULL) { return 1; }
if(b == NULL) { return -1; }
node1_weight = node1->weight;
node2_weight = node2->weight;
if(node1->details->unclean || node1->details->shutdown) {
node1_weight = -INFINITY;
}
if(node2->details->unclean || node2->details->shutdown) {
node2_weight = -INFINITY;
}
if(node1_weight > node2_weight) {
crm_debug_4("%s (%f) > %s (%f) : weight",
node1->details->id, node1_weight,
node2->details->id, node2_weight);
return -1;
}
if(node1_weight < node2_weight) {
crm_debug_4("%s (%f) < %s (%f) : weight",
node1->details->id, node1_weight,
node2->details->id, node2_weight);
return 1;
}
/* now try to balance resources across the cluster */
if(node1->details->num_resources
< node2->details->num_resources) {
crm_debug_4("%s (%d) < %s (%d) : resources",
node1->details->id, node1->details->num_resources,
node2->details->id, node2->details->num_resources);
return -1;
} else if(node1->details->num_resources
> node2->details->num_resources) {
crm_debug_4("%s (%d) > %s (%d) : resources",
node1->details->id, node1->details->num_resources,
node2->details->id, node2->details->num_resources);
return 1;
}
crm_debug_4("%s = %s", node1->details->id, node2->details->id);
return 0;
}
action_t *
custom_action(resource_t *rsc, char *key, const char *task, node_t *on_node,
gboolean optional, pe_working_set_t *data_set)
{
action_t *action = NULL;
GListPtr possible_matches = NULL;
CRM_DEV_ASSERT(key != NULL);
if(crm_assert_failed) { return NULL; }
CRM_DEV_ASSERT(task != NULL);
if(crm_assert_failed) { return NULL; }
if(rsc != NULL) {
possible_matches = find_actions(rsc->actions, key, on_node);
}
if(possible_matches != NULL) {
crm_free(key);
if(g_list_length(possible_matches) > 1) {
pe_warn("Action %s for %s on %s exists %d times",
task, rsc?rsc->id:"<NULL>",
on_node?on_node->details->uname:"<NULL>",
g_list_length(possible_matches));
}
action = g_list_nth_data(possible_matches, 0);
crm_debug_4("Found existing action (%d) %s for %s on %s",
action->id, task, rsc?rsc->id:"<NULL>",
on_node?on_node->details->uname:"<NULL>");
}
if(action == NULL) {
crm_debug_4("Creating action %s for %s on %s",
task, rsc?rsc->id:"<NULL>",
on_node?on_node->details->uname:"<NULL>");
crm_malloc0(action, sizeof(action_t));
if(action != NULL) {
action->id = data_set->action_id++;
action->rsc = rsc;
action->task = task;
action->node = on_node;
action->actions_before = NULL;
action->actions_after = NULL;
action->failure_is_fatal = TRUE;
action->pseudo = FALSE;
action->dumped = FALSE;
action->runnable = TRUE;
action->processed = FALSE;
action->optional = TRUE;
action->seen_count = 0;
action->extra = g_hash_table_new_full(
g_str_hash, g_str_equal,
g_hash_destroy_str, g_hash_destroy_str);
data_set->actions = g_list_append(
data_set->actions, action);
action->uuid = key;
if(rsc != NULL) {
action->op_entry = find_rsc_op_entry(rsc, key);
unpack_operation(
action, action->op_entry, data_set);
rsc->actions = g_list_append(
rsc->actions, action);
}
crm_debug_4("Action %d created", action->id);
}
}
if(optional == FALSE) {
crm_debug_2("Action %d marked manditory", action->id);
action->optional = FALSE;
}
if(rsc != NULL) {
if(action->node == NULL) {
action->runnable = FALSE;
} else if(action->node->details->online == FALSE) {
pe_warn("Action %d %s for %s on %s is unrunnable",
action->id,
task, rsc?rsc->id:"<NULL>",
action->node?action->node->details->uname:"<none>");
action->runnable = FALSE;
} else if(action->needs == rsc_req_nothing) {
action->runnable = TRUE;
} else if(data_set->have_quorum == FALSE
&& data_set->no_quorum_policy == no_quorum_stop) {
action->runnable = FALSE;
} else {
action->runnable = TRUE;
}
switch(text2task(action->task)) {
case stop_rsc:
rsc->stopping = TRUE;
break;
case start_rsc:
rsc->starting = FALSE;
if(action->runnable) {
rsc->starting = TRUE;
}
break;
default:
break;
}
}
return action;
}
void
unpack_operation(
action_t *action, crm_data_t *xml_obj, pe_working_set_t* data_set)
{
int lpc = 0;
const char *value = NULL;
const char *fields[] = {
"interval",
"timeout",
"start_delay",
};
if(xml_obj != NULL) {
value = crm_element_value(xml_obj, "prereq");
}
if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_START)) {
value = crm_element_value(action->rsc->xml, "start_prereq");
}
if(value == NULL && safe_str_neq(action->task, CRMD_ACTION_START)) {
/* todo: integrate stop as an option? */
action->needs = rsc_req_nothing;
value = "nothing (default)";
} else if(safe_str_eq(value, "nothing")) {
action->needs = rsc_req_nothing;
} else if(safe_str_eq(value, "quorum")) {
action->needs = rsc_req_quorum;
} else if(safe_str_eq(value, "fencing")) {
action->needs = rsc_req_stonith;
} else if(data_set->no_quorum_policy == no_quorum_ignore) {
action->needs = rsc_req_nothing;
value = "nothing (default)";
} else if(data_set->no_quorum_policy == no_quorum_freeze
&& data_set->stonith_enabled) {
action->needs = rsc_req_stonith;
value = "fencing (default)";
} else {
action->needs = rsc_req_quorum;
value = "quorum (default)";
}
crm_debug_2("\tAction %s requires: %s", action->task, value);
value = NULL;
if(xml_obj != NULL) {
value = crm_element_value(xml_obj, "on_fail");
}
if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_STOP)) {
value = crm_element_value(action->rsc->xml, "on_stopfail");
}
if(value == NULL) {
} else if(safe_str_eq(value, "fence")) {
action->on_fail = action_fail_fence;
value = "node fencing";
} else if(safe_str_eq(value, "stop")) {
action->on_fail = action_fail_stop;
value = "resource nothing";
} else if(safe_str_eq(value, "nothing")) {
action->on_fail = action_fail_nothing;
value = "nothing";
} else if(safe_str_eq(value, "ignore")) {
action->on_fail = action_fail_nothing;
value = "nothing";
} else {
pe_err("Resource %s: Unknown failure type (%s)",
action->rsc->id, value);
value = NULL;
}
/* defaults */
if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_STOP)) {
if(data_set->stonith_enabled) {
action->on_fail = action_fail_fence;
value = "resource fence (default)";
} else {
action->on_fail = action_fail_block;
value = "resource block (default)";
}
} else if(value == NULL) {
action->on_fail = action_fail_stop;
value = "resource stop (default)";
}
crm_debug_2("\t%s failure results in: %s", action->task, value);
if(xml_obj == NULL) {
return;
}
for(;lpc < DIMOF(fields); lpc++) {
value = crm_element_value(xml_obj, fields[lpc]);
add_hash_param(action->extra, fields[lpc], value);
}
unpack_instance_attributes(xml_obj, action->extra);
/* if(safe_str_eq(native_data->agent->class, "stonith")) { */
/* if(rsc->start_needs == rsc_req_stonith) { */
/* pe_err("Stonith resources (eg. %s) cannot require" */
/* " fencing to start", rsc->id); */
/* } */
/* rsc->start_needs = rsc_req_quorum; */
/* } */
}
crm_data_t *
find_rsc_op_entry(resource_t *rsc, const char *key)
{
const char *name = NULL;
const char *interval = NULL;
char *match_key = NULL;
crm_data_t *op = NULL;
xml_child_iter(
rsc->ops_xml, operation, "op",
name = crm_element_value(operation, "name");
interval = crm_element_value(operation, "interval");
match_key = generate_op_key(rsc->id,name,crm_get_msec(interval));
crm_debug_2("Matching %s with %s", key, match_key);
if(safe_str_eq(key, match_key)) {
op = operation;
}
crm_free(match_key);
if(op != NULL) {
break;
}
);
crm_debug_2("No matching for %s", key);
return op;
}
const char *
strength2text(enum con_strength strength)
{
const char *result = "<unknown>";
switch(strength)
{
case pecs_ignore:
result = "ignore";
break;
case pecs_must:
result = XML_STRENGTH_VAL_MUST;
break;
case pecs_must_not:
result = XML_STRENGTH_VAL_MUSTNOT;
break;
case pecs_startstop:
result = "start/stop";
break;
}
return result;
}
const char *
ordering_type2text(enum pe_ordering type)
{
const char *result = "<unknown>";
switch(type)
{
case pe_ordering_manditory:
result = "manditory";
break;
case pe_ordering_restart:
result = "restart";
break;
case pe_ordering_recover:
result = "recover";
break;
case pe_ordering_optional:
result = "optional";
break;
}
return result;
}
enum action_tasks
text2task(const char *task)
{
if(safe_str_eq(task, CRMD_ACTION_STOP)) {
return stop_rsc;
} else if(safe_str_eq(task, CRMD_ACTION_STOPPED)) {
return stopped_rsc;
} else if(safe_str_eq(task, CRMD_ACTION_START)) {
return start_rsc;
} else if(safe_str_eq(task, CRMD_ACTION_STARTED)) {
return started_rsc;
} else if(safe_str_eq(task, CRM_OP_SHUTDOWN)) {
return shutdown_crm;
} else if(safe_str_eq(task, CRM_OP_FENCE)) {
return stonith_node;
} else if(safe_str_eq(task, CRMD_ACTION_MON)) {
return monitor_rsc;
}
pe_err("Unsupported action: %s", task);
return no_action;
}
const char *
task2text(enum action_tasks task)
{
const char *result = "<unknown>";
switch(task)
{
case no_action:
result = "no_action";
break;
case stop_rsc:
result = CRMD_ACTION_STOP;
break;
case stopped_rsc:
result = CRMD_ACTION_STOPPED;
break;
case start_rsc:
result = CRMD_ACTION_START;
break;
case started_rsc:
result = CRMD_ACTION_STARTED;
break;
case shutdown_crm:
result = CRM_OP_SHUTDOWN;
break;
case stonith_node:
result = CRM_OP_FENCE;
break;
case monitor_rsc:
result = CRMD_ACTION_MON;
break;
}
return result;
}
void
print_node(const char *pre_text, node_t *node, gboolean details)
{
if(node == NULL) {
crm_debug_4("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
crm_debug_4("%s%s%sNode %s: (weight=%f, fixed=%s)",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
node->details==NULL?"error ":node->details->online?"":"Unavailable/Unclean ",
node->details->uname,
node->weight,
node->fixed?"True":"False");
if(details && node != NULL && node->details != NULL) {
char *pe_mutable = crm_strdup("\t\t");
crm_debug_4("\t\t===Node Attributes");
g_hash_table_foreach(node->details->attrs,
print_str_str, pe_mutable);
crm_free(pe_mutable);
crm_debug_4("\t\t=== Resources");
slist_iter(
rsc, resource_t, node->details->running_rsc, lpc,
print_resource("\t\t", rsc, FALSE);
);
}
}
/*
* Used by the HashTable for-loop
*/
void print_str_str(gpointer key, gpointer value, gpointer user_data)
{
crm_debug_4("%s%s %s ==> %s",
user_data==NULL?"":(char*)user_data,
user_data==NULL?"":": ",
(char*)key,
(char*)value);
}
void
print_color_details(const char *pre_text,
struct color_shared_s *color,
gboolean details)
{
if(color == NULL) {
crm_debug_4("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
crm_debug_4("%s%sColor %d: node=%s (from %d candidates)",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
color->id,
color->chosen_node==NULL?"<unset>":color->chosen_node->details->uname,
g_list_length(color->candidate_nodes));
if(details) {
slist_iter(node, node_t, color->candidate_nodes, lpc,
print_node("\t", node, FALSE));
}
}
void
print_color(const char *pre_text, color_t *color, gboolean details)
{
if(color == NULL) {
crm_debug_4("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
crm_debug_4("%s%sColor %d: (weight=%f, node=%s, possible=%d)",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
color->id,
color->local_weight,
safe_val5("<unset>",color,details,chosen_node,details,uname),
g_list_length(color->details->candidate_nodes));
if(details) {
print_color_details("\t", color->details, details);
}
}
void
print_rsc_to_node(const char *pre_text, rsc_to_node_t *cons, gboolean details)
{
if(cons == NULL) {
crm_debug_4("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
crm_debug_4("%s%s%s Constraint %s (%p) - %d nodes:",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
"rsc_to_node",
cons->id, cons,
g_list_length(cons->node_list_rh));
if(details == FALSE) {
crm_debug_4("\t%s (score=%f : node placement rule)",
safe_val3(NULL, cons, rsc_lh, id),
cons->weight);
slist_iter(
node, node_t, cons->node_list_rh, lpc,
print_node("\t\t-->", node, FALSE)
);
}
}
void
print_rsc_colocation(const char *pre_text, rsc_colocation_t *cons, gboolean details)
{
if(cons == NULL) {
crm_debug_4("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
crm_debug_4("%s%s%s Constraint %s (%p):",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
XML_CONS_TAG_RSC_DEPEND, cons->id, cons);
if(details == FALSE) {
crm_debug_4("\t%s --> %s, %s",
safe_val3(NULL, cons, rsc_lh, id),
safe_val3(NULL, cons, rsc_rh, id),
strength2text(cons->strength));
}
}
void
print_resource(const char *pre_text, resource_t *rsc, gboolean details)
{
if(rsc == NULL) {
crm_debug_4("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
rsc->fns->dump(rsc, pre_text, details);
}
void
print_action(const char *pre_text, action_t *action, gboolean details)
{
log_action(LOG_DEBUG_3, pre_text, action, details);
}
#define util_log(fmt...) do_crm_log(log_level, __FILE__, __FUNCTION__, fmt)
void
-log_action(int log_level, const char *pre_text, action_t *action, gboolean details)
+log_action(unsigned int log_level, const char *pre_text, action_t *action, gboolean details)
{
if(action == NULL) {
util_log("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
switch(text2task(action->task)) {
case stonith_node:
case shutdown_crm:
crm_log_maybe(log_level, "%s%s%sAction %d: %s @ %s",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
action->pseudo?"Pseduo ":action->optional?"Optional ":action->runnable?action->processed?"":"(Provisional) ":"!!Non-Startable!! ",
action->id, action->task,
safe_val4(NULL, action, node, details, uname));
break;
default:
crm_log_maybe(log_level, "%s%s%sAction %d: %s %s @ %s",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
action->optional?"Optional ":action->pseudo?"Pseduo ":action->runnable?action->processed?"":"(Provisional) ":"!!Non-Startable!! ",
action->id, action->task,
safe_val3(NULL, action, rsc, id),
safe_val4(NULL, action, node, details, uname));
break;
}
if(details) {
crm_log_maybe(log_level+1, "\t\t====== Preceeding Actions");
slist_iter(
other, action_wrapper_t, action->actions_before, lpc,
log_action(log_level+1, "\t\t", other->action, FALSE);
);
#if 1
crm_log_maybe(log_level+1, "\t\t====== Subsequent Actions");
slist_iter(
other, action_wrapper_t, action->actions_after, lpc,
log_action(log_level+1, "\t\t", other->action, FALSE);
);
#endif
crm_log_maybe(log_level+1, "\t\t====== End");
} else {
crm_log_maybe(log_level, "\t\t(seen=%d, before=%d, after=%d)",
action->seen_count,
g_list_length(action->actions_before),
g_list_length(action->actions_after));
}
}
void
pe_free_nodes(GListPtr nodes)
{
GListPtr iterator = nodes;
while(iterator != NULL) {
node_t *node = (node_t*)iterator->data;
struct node_shared_s *details = node->details;
iterator = iterator->next;
crm_debug_5("deleting node");
crm_debug_5("%s is being deleted", details->uname);
print_node("delete", node, FALSE);
if(details != NULL) {
if(details->attrs != NULL) {
g_hash_table_destroy(details->attrs);
}
pe_free_shallow_adv(details->running_rsc, FALSE);
crm_free(details);
}
crm_free(node);
}
if(nodes != NULL) {
g_list_free(nodes);
}
}
void
pe_free_colors(GListPtr colors)
{
GListPtr iterator = colors;
while(iterator != NULL) {
color_t *color = (color_t *)iterator->data;
struct color_shared_s *details = color->details;
iterator = iterator->next;
if(details != NULL) {
pe_free_shallow(details->candidate_nodes);
pe_free_shallow_adv(details->allocated_resources, FALSE);
crm_free(details->chosen_node);
crm_free(details);
}
crm_free(color);
}
if(colors != NULL) {
g_list_free(colors);
}
}
void
pe_free_shallow(GListPtr alist)
{
pe_free_shallow_adv(alist, TRUE);
}
void
pe_free_shallow_adv(GListPtr alist, gboolean with_data)
{
GListPtr item;
GListPtr item_next = alist;
while(item_next != NULL) {
item = item_next;
item_next = item_next->next;
if(with_data) {
/* crm_debug_5("freeing %p", item->data); */
crm_free(item->data);
}
item->data = NULL;
item->next = NULL;
g_list_free(item);
}
}
void
pe_free_resources(GListPtr resources)
{
resource_t *rsc = NULL;
GListPtr iterator = resources;
while(iterator != NULL) {
iterator = iterator;
rsc = (resource_t *)iterator->data;
iterator = iterator->next;
rsc->fns->free(rsc);
}
if(resources != NULL) {
g_list_free(resources);
}
}
void
pe_free_actions(GListPtr actions)
{
GListPtr iterator = actions;
while(iterator != NULL) {
action_t *action = (action_t *)iterator->data;
iterator = iterator->next;
pe_free_shallow(action->actions_before);/* action_warpper_t* */
pe_free_shallow(action->actions_after); /* action_warpper_t* */
g_hash_table_destroy(action->extra);
crm_free(action->uuid);
crm_free(action);
}
if(actions != NULL) {
g_list_free(actions);
}
}
void
pe_free_ordering(GListPtr constraints)
{
GListPtr iterator = constraints;
while(iterator != NULL) {
order_constraint_t *order = iterator->data;
iterator = iterator->next;
crm_free(order->lh_action_task);
crm_free(order->rh_action_task);
crm_free(order);
}
if(constraints != NULL) {
g_list_free(constraints);
}
}
void
pe_free_rsc_colocation(rsc_colocation_t *cons)
{
if(cons != NULL) {
crm_debug_4("Freeing constraint %s (%p)", cons->id, cons);
crm_free(cons);
}
}
void
pe_free_rsc_to_node(rsc_to_node_t *cons)
{
if(cons != NULL) {
pe_free_shallow(cons->node_list_rh);
crm_free(cons);
}
}
GListPtr
find_actions(GListPtr input, const char *key, node_t *on_node)
{
GListPtr result = NULL;
CRM_DEV_ASSERT(key != NULL);
slist_iter(
action, action_t, input, lpc,
crm_debug_5("Matching %s against %s", key, action->uuid);
if(safe_str_neq(key, action->uuid)) {
continue;
} else if(on_node == NULL) {
result = g_list_append(result, action);
} else if(action->node == NULL) {
/* skip */
crm_debug_2("While looking for %s action on %s, "
"found an unallocated one. Assigning"
" it to the requested node...",
key, on_node->details->uname);
action->node = on_node;
result = g_list_append(result, action);
} else if(safe_str_eq(on_node->details->id,
action->node->details->id)) {
result = g_list_append(result, action);
}
);
return result;
}
void
set_id(crm_data_t * xml_obj, const char *prefix, int child)
{
int id_len = 0;
gboolean use_prefix = TRUE;
gboolean use_child = TRUE;
char *new_id = NULL;
const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
id_len = 1 + strlen(id);
if(child > 999) {
pe_err("Are you insane?!?"
" The CRM does not support > 1000 children per resource");
return;
} else if(child < 0) {
use_child = FALSE;
} else {
id_len += 4; /* child */
}
if(prefix == NULL || safe_str_eq(id, prefix)) {
use_prefix = FALSE;
} else {
id_len += (1 + strlen(prefix));
}
crm_malloc0(new_id, id_len);
if(use_child) {
snprintf(new_id, id_len, "%s%s%s:%d",
use_prefix?prefix:"", use_prefix?":":"", id, child);
} else {
snprintf(new_id, id_len, "%s%s%s",
use_prefix?prefix:"", use_prefix?":":"", id);
}
crm_xml_add(xml_obj, XML_ATTR_ID, new_id);
crm_free(new_id);
}
float
merge_weights(float w1, float w2)
{
float result = w1 + w2;
if(w1 <= -INFINITY || w2 <= -INFINITY) {
if(w1 == INFINITY || w2 == INFINITY) {
pe_warn("-INFINITY + INFINITY == -INFINITY");
}
return -INFINITY;
} else if(w1 >= INFINITY || w2 >= INFINITY) {
return INFINITY;
}
/* detect wrap-around */
if(result > 0) {
if(w1 <= 0 && w2 < 0) {
result = -INFINITY;
}
} else if(w1 > 0 && w2 > 0) {
result = INFINITY;
}
/* detect +/- INFINITY */
if(result >= INFINITY) {
result = INFINITY;
} else if(result <= -INFINITY) {
result = -INFINITY;
}
return result;
}
diff --git a/crm/tengine/tengine.h b/crm/tengine/tengine.h
index 0eeb47e8c9..b27076574a 100644
--- a/crm/tengine/tengine.h
+++ b/crm/tengine/tengine.h
@@ -1,163 +1,163 @@
-/* $Id: tengine.h,v 1.24 2005/06/27 11:13:05 andrew Exp $ */
+/* $Id: tengine.h,v 1.25 2005/07/03 22:15:49 alan Exp $ */
/*
* 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.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
*/
#ifndef TENGINE__H
#define TENGINE__H
#include <clplumbing/ipc.h>
#include <fencing/stonithd_api.h>
extern IPC_Channel *crm_ch;
extern GListPtr graph;
extern GMainLoop* mainloop;
extern gboolean in_transition;
typedef enum {
action_type_pseudo,
action_type_rsc,
action_type_crm
} action_type_e;
typedef enum te_reason_e {
te_update,
te_done,
te_halt,
te_abort,
te_abort_confirmed,
te_failed,
te_timeout,
} te_reason_t;
typedef enum te_fsa_states_e {
s_idle,
s_in_transition,
s_abort_pending,
s_invalid
} te_fsa_state_t;
typedef enum te_fsa_inputs_e {
i_transition,
i_cancel,
i_complete,
i_cib_complete,
i_cib_confirm,
i_cib_notify,
i_invalid
} te_fsa_input_t;
extern const te_fsa_state_t te_state_matrix[i_invalid][s_invalid];
extern te_fsa_state_t te_fsa_state;
typedef struct synapse_s {
int id;
gboolean triggers_complete;
gboolean complete;
gboolean confirmed;
GListPtr actions; /* action_t* */
GListPtr inputs; /* action_t* */
} synapse_t;
typedef struct te_timer_s te_timer_t;
typedef struct action_s {
int id;
int timeout;
int interval;
te_timer_t *timer;
action_type_e type;
gboolean invoked;
gboolean complete;
gboolean can_fail;
crm_data_t *xml;
} action_t;
enum timer_reason {
timeout_action,
timeout_action_warn,
timeout_timeout,
};
struct te_timer_s
{
int source_id;
int timeout;
enum timer_reason reason;
action_t *action;
};
/* tengine */
extern gboolean initialize_graph(void);
extern gboolean process_graph_event(crm_data_t *event, const char *event_node);
/* const char *event_node, const char *event_rsc, const char *rsc_state,
* const char *event_action, const char *event_rc, const char *op_status); */
extern int match_graph_event(
action_t *action, crm_data_t *event, const char *event_node);
extern int match_down_event(const char *target, const char *filter, int rc);
extern gboolean initiate_transition(void);
extern gboolean cib_action_update(action_t *action, int status);
/* utils */
-extern void print_state(int log_level);
+extern void print_state(unsigned int log_level);
extern void send_complete(const char *text, crm_data_t *msg,
te_reason_t reason, te_fsa_input_t input);
extern gboolean stop_te_timer(te_timer_t *timer);
extern gboolean start_te_timer(te_timer_t *timer);
extern const char *get_rsc_state(const char *task, op_status_t status);
/* unpack */
extern gboolean unpack_graph(crm_data_t *xml_graph);
extern gboolean extract_event(crm_data_t *msg);
extern gboolean process_te_message(
HA_Message * msg, crm_data_t *xml_data, IPC_Channel *sender);
extern uint transition_idle_timeout;
extern uint default_transition_idle_timeout;
extern te_timer_t *transition_timer;
extern cib_t *te_cib_conn;
extern const char *actiontype2text(action_type_e type);
extern void tengine_stonith_callback(stonith_ops_t * op, void * private_data);
extern void tengine_stonith_connection_destroy(gpointer user_data);
extern gboolean tengine_stonith_dispatch(IPC_Channel *sender, void *user_data);
extern void check_for_completion(void);
void process_trigger(int action_id);
#ifdef TESTING
# define te_log_action(log_level, fmt...) { \
do_crm_log(log_level, __FILE__, __FUNCTION__, fmt); \
fprintf(stderr, fmt); \
fprintf(stderr, "\n"); \
}
#else
# define te_log_action(log_level, fmt...) do_crm_log(log_level, __FILE__, __FUNCTION__, fmt)
#endif
#endif
diff --git a/crm/tengine/utils.c b/crm/tengine/utils.c
index f4be0f4489..f37d641b70 100644
--- a/crm/tengine/utils.c
+++ b/crm/tengine/utils.c
@@ -1,437 +1,437 @@
-/* $Id: utils.c,v 1.36 2005/06/16 12:42:54 andrew Exp $ */
+/* $Id: utils.c,v 1.37 2005/07/03 22:15:49 alan Exp $ */
/*
* 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.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 <portability.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/msg.h>
#include <crm/common/xml.h>
#include <tengine.h>
#include <heartbeat.h>
#include <clplumbing/Gmain_timeout.h>
#include <lrm/lrm_api.h>
extern cib_t *te_cib_conn;
extern int global_transition_timer;
void print_input(const char *prefix, action_t *input, gboolean to_file);
void print_action(const char *prefix, action_t *action, gboolean to_file);
gboolean timer_callback(gpointer data);
void
send_complete(const char *text, crm_data_t *msg,
te_reason_t reason, te_fsa_input_t input)
{
HA_Message *cmd = NULL;
const char *op = CRM_OP_TEABORT;
static te_reason_t last_reason = te_done;
static crm_data_t *last_msg = NULL;
static const char *last_text = NULL;
te_fsa_state_t last_state = te_fsa_state;
te_fsa_state = te_state_matrix[input][te_fsa_state];
if(te_fsa_state == s_abort_pending && num_cib_op_callbacks() == 0) {
te_fsa_state = te_state_matrix[i_cib_complete][te_fsa_state];
}
if(te_fsa_state != s_idle && input != i_cib_complete) {
if(last_msg) {
free_xml(last_msg);
}
last_msg = NULL;
if(msg != NULL) {
last_msg = copy_xml(msg);
}
last_text = text;
last_reason = reason;
crm_info("CIB updates are pending. Delay until they complete.");
return;
} else if(te_fsa_state != s_idle) {
crm_err("Delaying \"%s\" notification until we are idle.",text);
return;
} else if(input == i_cib_complete) {
msg = last_msg;
text = last_text;
reason = last_reason;
}
CRM_DEV_ASSERT(num_cib_op_callbacks() == 0);
switch(reason) {
case te_update:
te_log_action(LOG_DEBUG,
"Transition status: %s by CIB update: %s",
last_state!=s_idle?"Aborted":"Triggered",
text);
if(msg != NULL) {
if(safe_str_eq(crm_element_name(msg),
XML_TAG_CIB)) {
crm_data_t *status = get_object_root(XML_CIB_TAG_STATUS, msg);
crm_data_t *generation = create_xml_node(NULL, XML_TAG_CIB);
crm_debug("Cause:"
" full CIB replace/update");
copy_in_properties(generation, msg);
crm_log_xml_debug(generation, "[generation]");
crm_log_xml_debug(status, "[in ]");
free_xml(generation);
} else {
crm_log_xml_debug(msg, "Cause");
}
}
print_state(LOG_DEBUG);
break;
case te_halt:
te_log_action(LOG_INFO,"Transition status: Stopped%s%s",
text?": ":"", text?text:"");
print_state(LOG_DEBUG);
op = CRM_OP_TECOMPLETE;
break;
case te_abort_confirmed:
te_log_action(LOG_INFO,
"Transition status: Confirmed Stopped%s%s",
text?": ":"", text?text:"");
print_state(LOG_DEBUG);
op = CRM_OP_TEABORTED;
break;
case te_abort:
te_log_action(LOG_INFO,"Transition status: Stopped%s%s",
text?": ":"", text?text:"");
print_state(LOG_DEBUG);
break;
case te_done:
te_log_action(LOG_INFO,
"Transition status: Complete%s%s",
text?": ":"", text?text:"");
print_state(LOG_DEBUG);
op = CRM_OP_TECOMPLETE;
break;
case te_timeout:
te_log_action(LOG_ERR,
"Transition status: Timed out after %dms",
transition_timer->timeout);
print_state(LOG_WARNING);
op = CRM_OP_TETIMEOUT;
break;
case te_failed:
te_log_action(LOG_ERR, "Transition status: Aborted by failed action: %s", text);
crm_log_xml_debug(msg, "Cause");
print_state(LOG_WARNING);
break;
}
initialize_graph();
cmd = create_request(
op, NULL, NULL, CRM_SYSTEM_DC, CRM_SYSTEM_TENGINE, NULL);
if(text != NULL) {
ha_msg_add(cmd, "message", text);
}
free_xml(last_msg);
#ifdef TESTING
if(reason == te_done) {
crm_log_message(LOG_INFO, cmd);
} else {
crm_log_message(LOG_ERR, cmd);
}
g_main_quit(mainloop);
return;
#else
send_ipc_message(crm_ch, cmd);
#endif
#if 0
if(is_ipc_empty(crm_ch)
&& is_ipc_empty(te_cib_conn->cmds->channel(te_cib_conn)) ) {
static gboolean mem_needs_init = TRUE;
if(mem_needs_init) {
crm_debug("Reached a stable point:"
" reseting memory usage stats to zero");
crm_zero_mem_stats(NULL);
mem_needs_init = FALSE;
} else {
crm_err("Reached a stable point:"
" checking memory usage");
crm_mem_stats(NULL);
}
}
#endif
}
void
-print_state(int log_level)
+print_state(unsigned int log_level)
{
gboolean first_synapse = TRUE;
if(graph == NULL && log_level > LOG_DEBUG) {
crm_debug("## Empty transition graph ##");
return;
}
slist_iter(
synapse, synapse_t, graph, lpc,
first_synapse = FALSE;
crm_log_maybe(log_level, "Synapse %d %s", synapse->id,
synapse->confirmed?"was confirmed":synapse->complete?"was executed":"is pending");
if(synapse->confirmed == FALSE) {
slist_iter(
action, action_t, synapse->actions, lpc2,
print_action("\t", action, log_level);
);
}
if(synapse->complete == FALSE) {
slist_iter(
input, action_t, synapse->inputs, lpc2,
print_input("\t", input, log_level);
);
}
);
if(first_synapse && log_level > LOG_DEBUG) {
crm_debug("## Empty transition graph ##");
return;
}
}
void
print_input(const char *prefix, action_t *input, int log_level)
{
do_crm_log(log_level, __FILE__, __FUNCTION__, "%s[Input %d] %s (%s)",
prefix, input->id,
input->complete?"Satisfied":"Pending",
actiontype2text(input->type));
if(input->complete == FALSE) {
crm_log_xml((unsigned)log_level, "\t Raw input", input->xml);
}
}
void
print_action(const char *prefix, action_t *action, int log_level)
{
do_crm_log(log_level, __FILE__, __FUNCTION__, "%s[Action %d] %s (%s fail)",
prefix, action->id, action->complete?"Completed":
action->invoked?"In-flight":"Pending",
action->can_fail?"can":"cannot");
switch(action->type) {
case action_type_pseudo:
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s\tPseudo Op: %s", prefix,
crm_element_value(
action->xml, XML_LRM_ATTR_TASK));
break;
case action_type_rsc:
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s\tResource Op: %s/%s on %s", prefix,
crm_element_value(
action->xml, XML_LRM_ATTR_RSCID),
crm_element_value(
action->xml, XML_LRM_ATTR_TASK),
crm_element_value(
action->xml, XML_LRM_ATTR_TARGET));
break;
case action_type_crm:
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s\tCRM Op: %s on %s", prefix,
crm_element_value(
action->xml, XML_LRM_ATTR_TASK),
crm_element_value(
action->xml, XML_LRM_ATTR_TARGET));
break;
}
if(action->timeout > 0 || action->timer->source_id > 0) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s\ttimeout=%d, timer=%d", prefix,
action->timeout, action->timer->source_id);
}
if(action->complete == FALSE) {
crm_log_xml(LOG_DEBUG_2, "\tRaw action", action->xml);
}
}
gboolean
timer_callback(gpointer data)
{
te_timer_t *timer = NULL;
if(data == NULL) {
crm_err("Timer popped with no data");
return FALSE;
}
timer = (te_timer_t*)data;
if(timer->source_id > 0) {
g_source_remove(timer->source_id);
}
timer->source_id = -1;
crm_err("Timer popped in state=%d", te_fsa_state);
if(te_fsa_state != s_in_transition) {
crm_debug("Ignoring timeout while not in transition");
return TRUE;
} else if(timer->reason == timeout_timeout) {
/* global timeout - abort the transition */
crm_warn("Transition timeout reached..."
" marking transition complete.");
crm_warn("Some actions may not have been executed.");
send_complete(XML_ATTR_TIMEOUT, NULL, te_timeout, i_cancel);
return TRUE;
} else if(timer->action == NULL) {
crm_err("Action not present!");
return FALSE;
} else if(timer->reason == timeout_action_warn) {
crm_warn("Action %d is taking more than 2x its timeout (%d)",
timer->action->id, timer->action->timeout);
crm_log_xml_debug(timer->action->xml, "Slow action");
return TRUE;
} else {
/* fail the action
* - which may or may not abort the transition
*/
/* TODO: send a cancel notice to the LRM */
/* TODO: use the ack from above to update the CIB */
return cib_action_update(timer->action, LRM_OP_TIMEOUT);
}
}
gboolean
start_te_timer(te_timer_t *timer)
{
if(((int)timer->source_id) < 0 && timer->timeout > 0) {
timer->source_id = Gmain_timeout_add(
timer->timeout, timer_callback, (void*)timer);
return TRUE;
} else if(timer->timeout < 0) {
crm_err("Tried to start timer with -ve period");
} else {
crm_debug_3("#!!#!!# Timer already running (%d)",
timer->source_id);
}
return FALSE;
}
gboolean
stop_te_timer(te_timer_t *timer)
{
if(timer == NULL) {
return FALSE;
}
if(((int)timer->source_id) > 0) {
g_source_remove(timer->source_id);
timer->source_id = -2;
} else {
return FALSE;
}
return TRUE;
}
const char *
actiontype2text(action_type_e type)
{
switch(type) {
case action_type_pseudo:
return "pseduo";
case action_type_rsc:
return "rsc";
case action_type_crm:
return "crm";
}
return "<unknown>";
}
const char *
get_rsc_state(const char *task, op_status_t status)
{
if(safe_str_eq(CRMD_ACTION_START, task)) {
if(status == LRM_OP_PENDING) {
return CRMD_ACTION_START_PENDING;
} else if(status == LRM_OP_DONE) {
return CRMD_ACTION_STARTED;
} else {
return CRMD_ACTION_START_FAIL;
}
} else if(safe_str_eq(CRMD_ACTION_STOP, task)) {
if(status == LRM_OP_PENDING) {
return CRMD_ACTION_STOP_PENDING;
} else if(status == LRM_OP_DONE) {
return CRMD_ACTION_STOPPED;
} else {
return CRMD_ACTION_STOP_FAIL;
}
} else {
if(safe_str_eq(CRMD_ACTION_MON, task)) {
if(status == LRM_OP_PENDING) {
return CRMD_ACTION_MON_PENDING;
} else if(status == LRM_OP_DONE) {
return CRMD_ACTION_MON_OK;
} else {
return CRMD_ACTION_MON_FAIL;
}
} else {
const char *rsc_state = NULL;
if(status == LRM_OP_PENDING) {
rsc_state = CRMD_ACTION_GENERIC_PENDING;
} else if(status == LRM_OP_DONE) {
rsc_state = CRMD_ACTION_GENERIC_OK;
} else {
rsc_state = CRMD_ACTION_GENERIC_FAIL;
}
crm_warn("Using status \"%s\" for op \"%s\"..."
" this is still in the experimental stage.",
rsc_state, task);
return rsc_state;
}
}
}
diff --git a/include/crm/common/xml.h b/include/crm/common/xml.h
index def8882fee..429219b0ca 100644
--- a/include/crm/common/xml.h
+++ b/include/crm/common/xml.h
@@ -1,280 +1,280 @@
-/* $Id: xml.h,v 1.26 2005/06/16 12:44:31 andrew Exp $ */
+/* $Id: xml.h,v 1.27 2005/07/03 22:15:50 alan Exp $ */
/*
* 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.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
*/
#ifndef CRM_COMMON_XML__H
#define CRM_COMMON_XML__H
#include <portability.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <ha_msg.h>
#include <clplumbing/cl_log.h>
/* #define USE_LIBXML 1 */
#define XML_PARANOIA_CHECKS 1
#ifdef USE_LIBXML
# include <libxml/tree.h>
typedef xmlNode crm_data_t;
#else
typedef struct ha_msg crm_data_t;
#endif
extern gboolean add_message_xml(
HA_Message *msg, const char *field, const crm_data_t *xml);
extern crm_data_t *get_message_xml(const HA_Message *msg, const char *field);
/*
* Replacement function for xmlCopyPropList which at the very least,
* doesnt work the way *I* would expect it to.
*
* Copy all the attributes/properties from src into target.
*
* Not recursive, does not return anything.
*
*/
extern void copy_in_properties(crm_data_t *target, const crm_data_t *src);
/*
* Find a child named search_path[i] at level i in the XML fragment where i=0
* is an immediate child of <i>root</i>.
*
* Terminate with success if i == len, or search_path[i] == NULL.
*
* On success, returns the sub-fragment described by search_path.
* On failure, returns NULL.
*/
extern crm_data_t *find_xml_node_nested(
crm_data_t *root, const char **search_path, int len);
/*
* Find a child named search_path[i] at level i in the XML fragment where i=0
* is an immediate child of <i>root</i>.
*
* Once the last child specified by node_path is found, find the value
* of attr_name.
*
* If <i>error<i> is set to TRUE, then it is an error for the attribute not
* to be found and the function will log accordingly.
*
* On success, returns the value of attr_name.
* On failure, returns NULL.
*/
extern const char *get_xml_attr_nested(crm_data_t *parent,
const char **node_path, int length,
const char *attr_name, gboolean error);
/*
* Free the XML "stuff" associated with a_node
*
* If a_node is part of another XML blob, barf.
* (Should be using free_xml_from_parent)
*
* Otherwise, free everything recursivly
*
* Wont barf on NULL.
*
*/
extern void free_xml_fn(crm_data_t *a_node);
#if 1
# define free_xml(xml_obj) free_xml_fn(xml_obj); xml_obj = NULL
#else
# define free_xml(xml_obj) xml_obj = NULL
#endif
void free_xml_from_parent(crm_data_t *parent, crm_data_t *a_node);
#define zap_xml_from_parent(parent, xml_obj) free_xml_from_parent(parent, xml_obj); xml_obj = NULL
/*
* Create a node named "name" as a child of "parent"
* If parent is NULL, creates an unconnected node.
*
* Returns the created node
*
*/
extern crm_data_t *create_xml_node(crm_data_t *parent, const char *name);
/*
* Make a copy of name and value and use the copied memory to create
* an attribute for node.
*
* If node, name or value are NULL, nothing is done.
*
* If name or value are an empty string, nothing is done.
*
* Returns FALSE on failure and TRUE on success.
*
*/
extern const char *crm_xml_add(
crm_data_t *node, const char *name, const char *value);
extern const char *crm_xml_add_int(
crm_data_t* node, const char *name, int value);
/*
* Unlink the node and set its doc pointer to NULL so free_xml()
* will act appropriately
*/
extern void unlink_xml_node(crm_data_t *node);
/*
* Set a timestamp attribute on a_node
*/
extern void set_node_tstamp(crm_data_t *a_node);
/*
* Returns a deep copy of src_node
*
*/
extern crm_data_t *copy_xml(const crm_data_t *src_node);
/*
* Add a copy of xml_node to new_parent
*/
extern crm_data_t *add_node_copy(
crm_data_t *new_parent, const crm_data_t *xml_node);
/*
* XML I/O Functions
*
* Whitespace between tags is discarded.
*/
extern crm_data_t *file2xml(FILE *input);
extern crm_data_t *stdin2xml(void);
extern crm_data_t *string2xml(const char *input);
extern int write_xml_file(crm_data_t *xml_node, const char *filename);
extern char *dump_xml_formatted(const crm_data_t *msg);
extern char *dump_xml_unformatted(const crm_data_t *msg);
extern void print_xml_formatted(
int log_level, const char *function,
const crm_data_t *an_xml_node, const char *text);
/*
* Diff related Functions
*/
extern crm_data_t *diff_xml_object(
crm_data_t *left, crm_data_t *right, gboolean suppress);
-extern void log_xml_diff(int log_level, crm_data_t *diff, const char *function);
+extern void log_xml_diff(unsigned int log_level, crm_data_t *diff, const char *function);
extern gboolean apply_xml_diff(
crm_data_t *old, crm_data_t *diff, crm_data_t **new);
/*
* Searching & Modifying
*/
extern crm_data_t *find_xml_node(
crm_data_t *cib, const char * node_path, gboolean must_find);
extern crm_data_t *find_entity(
crm_data_t *parent, const char *node_name, const char *id);
extern crm_data_t *subtract_xml_object(
crm_data_t *left, crm_data_t *right, gboolean suppress);
extern int add_xml_object(
crm_data_t *parent, crm_data_t *target, const crm_data_t *update);
extern void xml_remove_prop(crm_data_t *obj, const char *name);
extern void crm_set_element_parent(crm_data_t *data, crm_data_t *parent);
extern gboolean delete_xml_child(
crm_data_t *parent, crm_data_t *child, crm_data_t *to_delete);
/*
*
*/
extern const char *crm_element_value(const crm_data_t *data, const char *name);
extern char *crm_element_value_copy(const crm_data_t *data, const char *name);
extern const char *crm_element_name(const crm_data_t *data);
extern void crm_validate_data(const crm_data_t *root);
extern void crm_update_parents(crm_data_t *root);
extern gboolean xml_has_children(crm_data_t *root);
# define xmlGetNodePath(data) crm_element_value(data, XML_ATTR_TAGNAME)
# define xml_child_iter(parent, child, filter, loop_code) \
if(parent != NULL) { \
int __counter = 0; \
crm_data_t *child = NULL; \
crm_validate_data(parent); \
for (__counter = 0; __counter < parent->nfields; __counter++) { \
if(parent->types[__counter] != FT_STRUCT) { \
continue; \
} \
child = parent->values[__counter]; \
if(child == NULL) { \
crm_debug_4("Skipping %s == NULL", \
parent->names[__counter]); \
} else if(filter == NULL \
|| safe_str_eq(filter, parent->names[__counter])) { \
loop_code; \
} else { \
crm_debug_4("Skipping <%s../>", \
parent->names[__counter]); \
} \
} \
} else { \
crm_debug_4("Parent of loop was NULL"); \
}
#define xml_prop_iter(parent, prop_name, prop_value, code) if(parent != NULL) { \
const char *prop_name = NULL; \
const char *prop_value = NULL; \
int __counter = 0; \
crm_validate_data(parent); \
crm_debug_5("Searching %d fields", parent->nfields); \
for (__counter = 0; __counter < parent->nfields; __counter++) { \
crm_debug_5("Searching field %d", __counter); \
if(parent->types[__counter] != FT_STRING) { \
continue; \
} else if(safe_str_eq(parent->names[__counter], F_XML_TAGNAME)) { \
continue; \
} else if(safe_str_eq(parent->names[__counter], F_XML_PARENT)) { \
continue; \
} \
prop_name = parent->names[__counter]; \
prop_value = parent->values[__counter]; \
code; \
} \
} else { \
crm_debug_4("Parent of loop was NULL"); \
}
#endif
diff --git a/lib/crm/common/xml.c b/lib/crm/common/xml.c
index 5f8f54e403..bb463c9c34 100644
--- a/lib/crm/common/xml.c
+++ b/lib/crm/common/xml.c
@@ -1,1791 +1,1791 @@
-/* $Id: xml.c,v 1.19 2005/06/30 14:13:07 andrew Exp $ */
+/* $Id: xml.c,v 1.20 2005/07/03 22:15:50 alan Exp $ */
/*
* 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.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 <portability.h>
#include <sys/param.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <clplumbing/ipc.h>
#include <clplumbing/cl_log.h>
#include <crm/crm.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/dmalloc_wrapper.h>
void dump_array(
int log_level, const char *message, const char **array, int depth);
int print_spaces(char *buffer, int spaces);
int log_data_element(const char *function, const char *prefix, int log_level,
int depth, const crm_data_t *data, gboolean formatted);
int dump_data_element(
int depth, char **buffer, const crm_data_t *data, gboolean formatted);
crm_data_t *parse_xml(const char *input, int *offset);
int get_tag_name(const char *input);
int get_attr_name(const char *input);
int get_attr_value(const char *input);
gboolean can_prune_leaf(crm_data_t *xml_node);
void diff_filter_context(int context, int upper_bound, int lower_bound,
crm_data_t *xml_node, crm_data_t *parent);
int in_upper_context(int depth, int context, crm_data_t *xml_node);
crm_data_t *
find_xml_node(crm_data_t *root, const char * search_path, gboolean must_find)
{
if(must_find || root != NULL) {
crm_validate_data(root);
}
if(search_path == NULL) {
crm_warn("Will never find <NULL>");
return NULL;
}
xml_child_iter(
root, a_child, search_path,
/* crm_debug_5("returning node (%s).", xmlGetNodePath(a_child)); */
crm_log_xml_debug_5(a_child, "contents\t%s");
crm_log_xml_debug_5(root, "found in\t%s");
crm_validate_data(a_child);
return a_child;
);
if(must_find) {
crm_warn("Could not find %s in %s.", search_path, xmlGetNodePath(root));
} else if(root != NULL) {
crm_debug_3("Could not find %s in %s.", search_path, xmlGetNodePath(root));
} else {
crm_debug_3("Could not find %s in <NULL>.", search_path);
}
return NULL;
}
crm_data_t*
find_xml_node_nested(crm_data_t *root, const char **search_path, int len)
{
int j;
gboolean is_found = TRUE;
crm_data_t *match = NULL;
crm_data_t *lastMatch = root;
crm_validate_data(root);
if(search_path == NULL || search_path[0] == NULL) {
crm_warn("Will never find NULL");
return NULL;
}
dump_array(LOG_DEBUG_5, "Looking for.", search_path, len);
for (j=0; j < len; ++j) {
if (search_path[j] == NULL) {
/* a NULL also means stop searching */
break;
}
match = find_xml_node(lastMatch, search_path[j], FALSE);
if(match == NULL) {
is_found = FALSE;
break;
} else {
lastMatch = match;
}
}
if (is_found) {
crm_debug_5("returning node (%s).",
xmlGetNodePath(lastMatch));
crm_log_xml_debug_5(lastMatch, "found\t%s");
crm_log_xml_debug_5(root, "in \t%s");
crm_validate_data(lastMatch);
return lastMatch;
}
dump_array(LOG_DEBUG_2,
"Could not find the full path to the node you specified.",
search_path, len);
crm_debug_2("Closest point was node (%s) starting from %s.",
xmlGetNodePath(lastMatch), crm_element_name(root));
return NULL;
}
const char *
get_xml_attr_nested(crm_data_t *parent,
const char **node_path, int length,
const char *attr_name, gboolean error)
{
const char *attr_value = NULL;
crm_data_t *attr_parent = NULL;
if(error || parent != NULL) {
crm_validate_data(parent);
}
if(parent == NULL) {
crm_debug_3("Can not find attribute %s in NULL parent",attr_name);
return NULL;
}
if(attr_name == NULL || strlen(attr_name) == 0) {
crm_err("Can not find attribute with no name in %s",
xmlGetNodePath(parent));
return NULL;
}
if(length == 0) {
attr_parent = parent;
} else {
attr_parent = find_xml_node_nested(parent, node_path, length);
if(attr_parent == NULL && error) {
crm_err("No node at the path you specified.");
return NULL;
}
}
attr_value = crm_element_value(attr_parent, attr_name);
if((attr_value == NULL || strlen(attr_value) == 0) && error) {
crm_err("No value present for %s at %s",
attr_name, xmlGetNodePath(attr_parent));
return NULL;
}
return attr_value;
}
crm_data_t*
find_entity(crm_data_t *parent, const char *node_name, const char *id)
{
crm_validate_data(parent);
xml_child_iter(
parent, a_child, node_name,
if(id == NULL
|| safe_str_eq(id,crm_element_value(a_child,XML_ATTR_ID))){
crm_debug_4("returning node (%s).",
xmlGetNodePath(a_child));
return a_child;
}
);
crm_debug_3("node <%s id=%s> not found in %s.",
node_name, id, xmlGetNodePath(parent));
return NULL;
}
void
copy_in_properties(crm_data_t* target, const crm_data_t *src)
{
crm_validate_data(src);
crm_validate_data(target);
if(src == NULL) {
crm_warn("No node to copy properties from");
} else if (target == NULL) {
crm_err("No node to copy properties into");
} else {
xml_prop_iter(
src, local_prop_name, local_prop_value,
crm_xml_add(target, local_prop_name, local_prop_value);
);
crm_validate_data(target);
}
return;
}
crm_data_t*
add_node_copy(crm_data_t *new_parent, const crm_data_t *xml_node)
{
crm_data_t *node_copy = NULL;
crm_validate_data(new_parent);
crm_validate_data(xml_node);
if(xml_node != NULL && new_parent != NULL) {
const char *name = crm_element_name(xml_node);
CRM_DEV_ASSERT(
HA_OK == ha_msg_addstruct(new_parent, name, xml_node));
node_copy = find_entity(
new_parent, crm_element_name(xml_node), ID(xml_node));
crm_validate_data(node_copy);
crm_update_parents(new_parent);
crm_validate_data(new_parent);
} else if(xml_node == NULL) {
crm_err("Could not add copy of NULL node");
} else {
crm_err("Could not add copy of node to NULL parent");
}
crm_validate_data(node_copy);
return node_copy;
}
const char *
crm_xml_add(crm_data_t* node, const char *name, const char *value)
{
const char *parent_name = NULL;
if(node != NULL) {
parent_name = crm_element_name(node);
}
crm_debug_5("[%s] Setting %s to %s", crm_str(parent_name), name, value);
if (name == NULL || strlen(name) <= 0) {
} else if(node == NULL) {
} else if(parent_name == NULL && strcmp(name, F_XML_TAGNAME) != 0) {
} else if (value == NULL || strlen(value) <= 0) {
xml_remove_prop(node, name);
return NULL;
} else {
crm_validate_data(node);
ha_msg_mod(node, name, value);
return crm_element_value(node, name);
}
return NULL;
}
const char *
crm_xml_add_int(crm_data_t* node, const char *name, int value)
{
const char *parent_name = NULL;
if(node != NULL) {
parent_name = crm_element_name(node);
}
crm_debug_5("[%s] Setting %s to %d", crm_str(parent_name), name, value);
if (name == NULL || strlen(name) <= 0) {
} else if(node == NULL) {
} else if(parent_name == NULL && strcmp(name, F_XML_TAGNAME) != 0) {
} else {
crm_validate_data(node);
ha_msg_mod_int(node, name, value);
return crm_element_value(node, name);
}
return NULL;
}
crm_data_t*
create_xml_node(crm_data_t *parent, const char *name)
{
const char *local_name = NULL;
const char *parent_name = NULL;
crm_data_t *ret_value = NULL;
if (name == NULL || strlen(name) < 1) {
ret_value = NULL;
} else {
local_name = name;
ret_value = ha_msg_new(1);
CRM_DEV_ASSERT(ret_value != NULL);
crm_xml_add(ret_value, F_XML_TAGNAME, name);
crm_validate_data(ret_value);
if(parent) {
crm_validate_data(parent);
parent_name = crm_element_name(parent);
crm_debug_5("Attaching %s to parent %s",
local_name, parent_name);
CRM_DEV_ASSERT(HA_OK == ha_msg_addstruct(
parent, name, ret_value));
crm_msg_del(ret_value);
crm_update_parents(parent);
crm_validate_data(parent);
ret_value = parent->values[parent->nfields-1];
crm_validate_data(ret_value);
}
}
crm_debug_5("Created node [%s [%s]]",
crm_str(parent_name), crm_str(local_name));
/* set_node_tstamp(ret_value); */
return ret_value;
}
void
free_xml_from_parent(crm_data_t *parent, crm_data_t *a_node)
{
CRM_DEV_ASSERT(parent != NULL);
if(parent == NULL) {
return;
} else if(a_node == NULL) {
return;
}
crm_validate_data(parent);
cl_msg_remove_value(parent, a_node);
crm_validate_data(parent);
}
void
free_xml_fn(crm_data_t *a_node)
{
if(a_node == NULL) {
; /* nothing to do */
} else {
int has_parent = 0;
crm_validate_data(a_node);
ha_msg_value_int(a_node, F_XML_PARENT, &has_parent);
/* there is no way in hell we should be deleting anything
* with a parent and without the parent knowning
*/
CRM_DEV_ASSERT(has_parent == 0);
if(has_parent == 0) {
crm_validate_data(a_node);
crm_msg_del(a_node);
}
}
return;
}
void
set_node_tstamp(crm_data_t *a_node)
{
#if 0
char *since_epoch = NULL;
time_t a_time = time(NULL);
crm_validate_data(a_node);
if(a_time == (time_t)-1) {
cl_perror("set_node_tstamp(): Invalid time returned");
return;
}
crm_malloc0(since_epoch, 128*(sizeof(char)));
if(since_epoch != NULL) {
sprintf(since_epoch, "%ld", (unsigned long)a_time);
ha_msg_mod(a_node, XML_ATTR_TSTAMP, since_epoch);
crm_validate_data(a_node);
crm_free(since_epoch);
}
#endif
}
crm_data_t*
copy_xml(const crm_data_t *src_node)
{
crm_data_t *new_xml = NULL;
CRM_DEV_ASSERT(src_node != NULL);
CRM_DEV_ASSERT(crm_element_name(src_node) != NULL);
if(src_node == NULL) {
crm_warn("Attempt to dup NULL XML");
return NULL;
} else if(crm_element_name(src_node) == NULL) {
crm_log_xml_err(src_node, "Attempt to dup XML with no name");
return NULL;
}
crm_validate_data(src_node);
new_xml = ha_msg_copy(src_node);
crm_set_element_parent(new_xml, NULL);
crm_update_parents(new_xml);
crm_validate_data(new_xml);
return new_xml;
}
crm_data_t*
string2xml(const char *input)
{
crm_data_t *output = parse_xml(input, NULL);
if(output != NULL) {
crm_update_parents(output);
crm_validate_data(output);
}
return output;
}
crm_data_t *
stdin2xml(void)
{
int lpc = 0;
int MAX_XML_BUFFER = 20000;
int ch = 0;
gboolean more = TRUE;
gboolean inTag = FALSE;
FILE *input = stdin;
char *xml_buffer = NULL;
crm_data_t *xml_obj = NULL;
crm_malloc0(xml_buffer, sizeof(char)*(MAX_XML_BUFFER+1));
while (more && lpc < MAX_XML_BUFFER) {
ch = fgetc(input);
/* crm_debug_3("Got [%c]", ch); */
switch(ch) {
case EOF:
case 0:
ch = 0;
more = FALSE;
xml_buffer[lpc++] = ch;
break;
case '>':
case '<':
inTag = TRUE;
if(ch == '>') { inTag = FALSE; }
xml_buffer[lpc++] = ch;
break;
case '\n':
case '\t':
case ' ':
ch = ' ';
if(inTag) {
xml_buffer[lpc++] = ch;
}
break;
default:
xml_buffer[lpc++] = ch;
break;
}
}
xml_buffer[MAX_XML_BUFFER] = 0;
xml_obj = string2xml(xml_buffer);
crm_free(xml_buffer);
crm_log_xml_debug_3(xml_obj, "Created fragment");
return xml_obj;
}
crm_data_t*
file2xml(FILE *input)
{
char *buffer = NULL;
crm_data_t *new_obj = NULL;
int start = 0, length = 0, read_len = 0;
/* see how big the file is */
start = ftell(input);
fseek(input, 0L, SEEK_END);
length = ftell(input);
fseek(input, 0L, start);
if(start != ftell(input)) {
crm_err("fseek not behaving");
return NULL;
}
crm_debug_3("Reading %d bytes from file", length);
crm_malloc0(buffer, sizeof(char) * (length+1));
read_len = fread(buffer, sizeof(char), length, input);
if(read_len != length) {
crm_err("Calculated and read bytes differ: %d vs. %d",
length, read_len);
} else if(length > 0) {
new_obj = string2xml(buffer);
} else {
crm_warn("File contained no XML");
}
crm_free(buffer);
return new_obj;
}
void
dump_array(int log_level, const char *message, const char **array, int depth)
{
int j;
if(message != NULL) {
do_crm_log(log_level, __FILE__, __FUNCTION__, "%s", message);
}
do_crm_log(log_level, __FILE__, __FUNCTION__, "Contents of the array:");
if(array == NULL || array[0] == NULL || depth == 0) {
do_crm_log(log_level, __FILE__, __FUNCTION__, "\t<empty>");
return;
}
for (j=0; j < depth && array[j] != NULL; j++) {
if (array[j] == NULL) { break; }
do_crm_log(log_level, __FILE__, __FUNCTION__, "\t--> (%s).", array[j]);
}
}
int
write_xml_file(crm_data_t *xml_node, const char *filename)
{
int res = 0;
char *now_str = NULL;
time_t now;
crm_debug_3("Writing XML out to %s", filename);
crm_validate_data(xml_node);
if (xml_node == NULL) {
return -1;
}
crm_validate_data(xml_node);
crm_log_xml_debug_4(xml_node, "Writing out");
crm_validate_data(xml_node);
now = time(NULL);
now_str = ctime(&now);
now_str[24] = EOS; /* replace the newline */
crm_xml_add(xml_node, "last_written", now_str);
crm_validate_data(xml_node);
{
FILE *file_output_strm = fopen(filename, "w");
char *buffer = dump_xml_formatted(xml_node);
CRM_DEV_ASSERT(buffer != NULL && strlen(buffer) > 0);
if(file_output_strm == NULL) {
res = -1;
crm_err("Cannot write to %s", filename);
} else if(buffer != NULL && strlen(buffer) > 0) {
res = fprintf(file_output_strm, "%s", buffer);
}
if(file_output_strm != NULL) {
fflush(file_output_strm);
fclose(file_output_strm);
}
crm_free(buffer);
}
crm_debug_3("Saved %d bytes to the Cib as XML", res);
return res;
}
void
print_xml_formatted(int log_level, const char *function,
const crm_data_t *msg, const char *text)
{
if(msg == NULL) {
do_crm_log(log_level,NULL,function, "%s: NULL", crm_str(text));
return;
}
crm_validate_data(msg);
do_crm_log(log_level, NULL, function, "%s:", crm_str(text));
log_data_element(function, NULL, log_level, 0, msg, TRUE);
return;
}
crm_data_t *
get_message_xml(const HA_Message *msg, const char *field)
{
crm_data_t *xml_node = NULL;
crm_data_t *tmp_node = NULL;
crm_validate_data(msg);
tmp_node = cl_get_struct(msg, field);
if(tmp_node != NULL) {
xml_node = copy_xml(tmp_node);
}
return xml_node;
}
gboolean
add_message_xml(HA_Message *msg, const char *field, const crm_data_t *xml)
{
crm_validate_data(xml);
crm_validate_data(msg);
ha_msg_addstruct(msg, field, xml);
crm_update_parents(msg);
return TRUE;
}
char *
dump_xml_formatted(const crm_data_t *an_xml_node)
{
char *buffer = NULL;
char *mutable_ptr = NULL;
#if 0
crm_malloc0(buffer, 3*get_stringlen(an_xml_node));
#else
crm_malloc0(buffer, sizeof(char)*60000);
#endif
mutable_ptr = buffer;
crm_validate_data(an_xml_node);
CRM_DEV_ASSERT(dump_data_element(
0, &mutable_ptr, an_xml_node, TRUE) >= 0);
if(crm_assert_failed) {
crm_crit("Could not dump the whole message");
}
crm_debug_4("Dumped: %s", buffer);
return buffer;
}
char *
dump_xml_unformatted(const crm_data_t *an_xml_node)
{
char *buffer = NULL;
char *mutable_ptr = NULL;
#if 0
crm_malloc0(buffer, 2*get_stringlen(an_xml_node));
#else
crm_malloc0(buffer, sizeof(char)*20000);
#endif
mutable_ptr = buffer;
crm_validate_data(an_xml_node);
CRM_DEV_ASSERT(dump_data_element(
0, &mutable_ptr, an_xml_node, TRUE) >= 0);
if(crm_assert_failed) {
crm_crit("Could not dump the whole message");
}
crm_debug_4("Dumped: %s", buffer);
return buffer;
}
#define update_buffer_head(buffer, len) if(len < 0) { \
(*buffer) = EOS; return -1; \
} else { \
buffer += len; \
}
int
print_spaces(char *buffer, int depth)
{
int lpc = 0;
int spaces = 2*depth;
/* <= so that we always print 1 space - prevents problems with syslog */
for(lpc = 0; lpc <= spaces; lpc++) {
if(sprintf(buffer, "%c", ' ') < 1) {
return -1;
}
buffer += 1;
}
return lpc;
}
int
log_data_element(
const char *function, const char *prefix, int log_level, int depth,
const crm_data_t *data, gboolean formatted)
{
int printed = 0;
int child_result = 0;
int has_children = 0;
char print_buffer[1000];
char *buffer = print_buffer;
const char *name = crm_element_name(data);
crm_debug_5("Dumping %s...", name);
crm_validate_data(data);
if(data == NULL) {
crm_warn("No data to dump as XML");
return 0;
} else if(name == NULL && depth == 0) {
xml_child_iter(
data, a_child, NULL,
child_result = log_data_element(
function, prefix, log_level, depth, a_child, formatted);
if(child_result < 0) {
return child_result;
}
);
return 0;
} else if(name == NULL) {
crm_err("Cannot dump NULL element at depth %d", depth);
return -1;
}
if(formatted) {
printed = print_spaces(buffer, depth);
update_buffer_head(buffer, printed);
}
printed = sprintf(buffer, "<%s", name);
update_buffer_head(buffer, printed);
xml_prop_iter(
data, prop_name, prop_value,
if(safe_str_eq(F_XML_TAGNAME, prop_name)) {
continue;
} else if(safe_str_eq(F_XML_PARENT, prop_name)) {
continue;
}
crm_debug_5("Dumping <%s %s=\"%s\"...",
name, prop_name, prop_value);
printed = sprintf(buffer, " %s=\"%s\"", prop_name, prop_value);
update_buffer_head(buffer, printed);
);
xml_child_iter(
data, child, NULL,
if(child != NULL) {
has_children++;
break;
}
);
printed = sprintf(buffer, "%s>", has_children==0?"/":"");
update_buffer_head(buffer, printed);
do_crm_log(log_level, function, NULL, "%s%s",
prefix?prefix:"", print_buffer);
buffer = print_buffer;
if(has_children == 0) {
return 0;
}
xml_child_iter(
data, a_child, NULL,
child_result = log_data_element(
function, prefix, log_level, depth+1, a_child, formatted);
if(child_result < 0) { return -1; }
);
if(formatted) {
printed = print_spaces(buffer, depth);
update_buffer_head(buffer, printed);
}
do_crm_log(log_level, function, NULL, "%s%s</%s>",
prefix?prefix:"", print_buffer, name);
crm_debug_5("Dumped %s...", name);
return has_children;
}
int
dump_data_element(
int depth, char **buffer, const crm_data_t *data, gboolean formatted)
{
int printed = 0;
int child_result = 0;
int has_children = 0;
const char *name = crm_element_name(data);
crm_debug_5("Dumping %s...", name);
crm_validate_data(data);
if(buffer == NULL || *buffer == NULL) {
crm_err("No buffer supplied to dump XML into");
return -1;
} else if(data == NULL) {
crm_warn("No data to dump as XML");
(*buffer)[0] = EOS;
return 0;
} else if(name == NULL && depth == 0) {
xml_child_iter(
data, a_child, NULL,
child_result = dump_data_element(
depth, buffer, a_child, formatted);
if(child_result < 0) {
return child_result;
}
);
return 0;
} else if(name == NULL) {
crm_err("Cannot dump NULL element at depth %d", depth);
return -1;
}
if(formatted) {
printed = print_spaces(*buffer, depth);
update_buffer_head(*buffer, printed);
}
printed = sprintf(*buffer, "<%s", name);
update_buffer_head(*buffer, printed);
xml_prop_iter(data, prop_name, prop_value,
if(safe_str_eq(F_XML_TAGNAME, prop_name)) {
continue;
} else if(safe_str_eq(F_XML_PARENT, prop_name)) {
continue;
}
crm_debug_5("Dumping <%s %s=\"%s\"...",
name, prop_name, prop_value);
printed = sprintf(*buffer, " %s=\"%s\"", prop_name, prop_value);
update_buffer_head(*buffer, printed);
);
xml_child_iter(
data, child, NULL,
if(child != NULL) {
has_children++;
break;
}
);
printed = sprintf(*buffer, "%s>%s",
has_children==0?"/":"", formatted?"\n":"");
update_buffer_head(*buffer, printed);
if(has_children == 0) {
return 0;
}
xml_child_iter(
data, child, NULL,
child_result = dump_data_element(
depth+1, buffer, child, formatted);
if(child_result < 0) { return -1; }
);
if(formatted) {
printed = print_spaces(*buffer, depth);
update_buffer_head(*buffer, printed);
}
printed = sprintf(*buffer, "</%s>%s", name, formatted?"\n":"");
update_buffer_head(*buffer, printed);
crm_debug_5("Dumped %s...", name);
return has_children;
}
gboolean
xml_has_children(crm_data_t *xml_root)
{
crm_validate_data(xml_root);
xml_child_iter(
xml_root, a_child, NULL,
return TRUE;
);
return FALSE;
}
void
crm_validate_data(const crm_data_t *xml_root)
{
#ifndef XML_PARANOIA_CHECKS
CRM_DEV_ASSERT(xml_root != NULL);
#else
int lpc = 0;
CRM_ASSERT(xml_root != NULL);
CRM_ASSERT(crm_is_allocated(xml_root) == 1);
CRM_ASSERT(xml_root->nfields < 500);
for (lpc = 0; lpc < xml_root->nfields; lpc++) {
void *child = xml_root->values[lpc];
CRM_ASSERT(crm_is_allocated(xml_root->names[lpc]) == 1);
if(child == NULL) {
} else if(xml_root->types[lpc] == FT_STRUCT) {
crm_validate_data(child);
} else if(xml_root->types[lpc] == FT_STRING) {
CRM_ASSERT(crm_is_allocated(child) == 1);
/* } else { */
/* CRM_DEV_ASSERT(FALSE); */
}
}
#endif
}
void
crm_set_element_parent(crm_data_t *data, crm_data_t *parent)
{
crm_validate_data(data);
if(parent != NULL) {
ha_msg_mod_int(data, F_XML_PARENT, 1);
} else {
ha_msg_mod_int(data, F_XML_PARENT, 0);
}
}
const char *
crm_element_value(const crm_data_t *data, const char *name)
{
const char *value = NULL;
crm_validate_data(data);
value = cl_get_string(data, name);
if(value != NULL) {
CRM_DEV_ASSERT(crm_is_allocated(value) == 1);
}
return value;
}
char *
crm_element_value_copy(const crm_data_t *data, const char *name)
{
const char *value = NULL;
char *value_copy = NULL;
crm_validate_data(data);
value = cl_get_string(data, name);
if(value != NULL) {
CRM_DEV_ASSERT(crm_is_allocated(value) == 1);
}
CRM_DEV_ASSERT(value != NULL);
if(value != NULL) {
value_copy = crm_strdup(value);
}
return value_copy;
}
const char *
crm_element_name(const crm_data_t *data)
{
crm_validate_data(data);
return cl_get_string(data, F_XML_TAGNAME);
}
void
xml_remove_prop(crm_data_t *obj, const char *name)
{
if(crm_element_value(obj, name) != NULL) {
cl_msg_remove(obj, name);
}
}
void
crm_update_parents(crm_data_t *xml_root)
{
crm_validate_data(xml_root);
xml_child_iter(
xml_root, a_child, NULL,
crm_set_element_parent(a_child, xml_root);
crm_update_parents(a_child);
);
}
int
get_tag_name(const char *input)
{
int lpc = 0;
char ch = 0;
const char *error = NULL;
gboolean do_special = FALSE;
for(lpc = 0; error == NULL && lpc < (ssize_t)strlen(input); lpc++) {
ch = input[lpc];
crm_debug_5("Processing char %c [%d]", ch, lpc);
switch(ch) {
case 0:
error = "unexpected EOS";
break;
case '?':
if(lpc == 0) {
/* weird xml tag that we dont care about */
do_special = TRUE;
} else {
return lpc;
}
break;
case '/':
case '>':
case '\t':
case '\n':
case ' ':
if(!do_special) {
return lpc;
}
break;
default:
if(do_special) {
} else if('a' <= ch && ch <= 'z') {
} else if('A' <= ch && ch <= 'Z') {
} else if(ch == '_') {
} else if(ch == '-') {
} else {
error = "bad character, not in [a-zA-Z_-]";
}
break;
}
}
crm_err("Error parsing token near %.15s: %s", input, crm_str(error));
return -1;
}
int
get_attr_name(const char *input)
{
int lpc = 0;
char ch = 0;
const char *error = NULL;
for(lpc = 0; error == NULL && lpc < (ssize_t)strlen(input); lpc++) {
ch = input[lpc];
crm_debug_5("Processing char %c[%d]", ch, lpc);
switch(ch) {
case 0:
error = "unexpected EOS";
break;
case '\t':
case '\n':
case ' ':
error = "unexpected whitespace";
break;
case '=':
return lpc;
default:
if('a' <= ch && ch <= 'z') {
} else if('A' <= ch && ch <= 'Z') {
} else if(ch == '_') {
} else if(ch == '-') {
} else {
error = "bad character, not in [a-zA-Z_-]";
}
break;
}
}
crm_err("Error parsing token near %.15s: %s", input, crm_str(error));
return -1;
}
int
get_attr_value(const char *input)
{
int lpc = 0;
char ch = 0;
const char *error = NULL;
for(lpc = 0; error == NULL && lpc < (ssize_t)strlen(input); lpc++) {
ch = input[lpc];
crm_debug_5("Processing char %c [%d]", ch, lpc);
switch(ch) {
case 0:
error = "unexpected EOS";
break;
case '\\':
if(input[lpc+1] == '"') {
/* skip over the next char */
lpc++;
break;
}
/*fall through*/
case '"':
return lpc;
default:
break;
}
}
crm_err("Error parsing token near %.15s: %s", input, crm_str(error));
return -1;
}
crm_data_t*
parse_xml(const char *input, int *offset)
{
int len = 0, lpc = 0;
char ch = 0;
char *tag_name = NULL;
char *attr_name = NULL;
char *attr_value = NULL;
gboolean more = TRUE;
const char *error = NULL;
const char *our_input = input;
crm_data_t *new_obj = NULL;
if(input == NULL) {
return NULL;
}
if(offset != NULL) {
our_input = input + (*offset);
}
len = strlen(our_input);
while(lpc < len) {
if(our_input[lpc] != '<') {
} else if(our_input[lpc+1] == '!') {
crm_warn("XML Comments are not supported");
crm_debug_5("Skipping char %c", our_input[lpc]);
lpc++;
} else if(our_input[lpc+1] == '?') {
crm_debug_5("Skipping char %c", our_input[lpc]);
lpc++;
} else {
lpc++;
our_input += lpc;
break;
}
crm_debug_5("Skipping char %c", our_input[lpc]);
lpc++;
}
len = get_tag_name(our_input);
if(len < 0) {
return NULL;
}
crm_malloc0(tag_name, len+1);
strncpy(tag_name, our_input, len+1);
tag_name[len] = EOS;
crm_debug_4("Processing tag %s", tag_name);
new_obj = ha_msg_new(1);
CRM_DEV_ASSERT(crm_is_allocated(new_obj) == 1);
ha_msg_add(new_obj, F_XML_TAGNAME, tag_name);
lpc = len;
for(; more && error == NULL && lpc < (ssize_t)strlen(input); lpc++) {
ch = our_input[lpc];
crm_debug_5("Processing char %c[%d]", ch, lpc);
switch(ch) {
case 0:
error = "unexpected EOS";
break;
case '/':
if(our_input[lpc+1] == '>') {
more = FALSE;
}
break;
case '<':
if(our_input[lpc+1] != '/') {
crm_data_t *child = NULL;
crm_debug_4("Start parsing child...");
child = parse_xml(our_input, &lpc);
if(child == NULL) {
error = "error parsing child";
} else {
CRM_DEV_ASSERT(crm_is_allocated(child) == 1);
ha_msg_addstruct(
new_obj, crm_element_name(child), child);
crm_debug_4("Finished parsing child: %s",
crm_element_name(child));
ha_msg_del(child);
/* lpc++; /\* > *\/ */
}
} else {
lpc += 2; /* </ */
len = get_tag_name(our_input+lpc);
if(len < 0) {
error = "couldnt find tag";
} else if(strncmp(our_input+lpc, tag_name, len) == 0) {
more = FALSE;
lpc += len;
/* lpc++; /\* > *\/ */
if(our_input[lpc] != '>') {
error = "clase tag cannot contain attrs";
}
crm_debug_4("Finished parsing ourselves: %s",
crm_element_name(new_obj));
} else {
error = "Mismatching close tag";
crm_err("Expected: %s", tag_name);
}
}
break;
case '=':
lpc++; /* = */
/*fall through*/
case '"':
lpc++; /* " */
len = get_attr_value(our_input+lpc);
if(len < 0) {
error = "couldnt find attr_value";
} else {
crm_malloc0(attr_value, len+1);
strncpy(attr_value, our_input+lpc, len+1);
attr_value[len] = EOS;
lpc += len;
/* lpc++; /\* " *\/ */
crm_debug_4("creating nvpair: <%s %s=\"%s\"...",
tag_name,
crm_str(attr_name),
crm_str(attr_value));
ha_msg_add(new_obj, attr_name, attr_value);
crm_free(attr_name);
crm_free(attr_value);
}
break;
case '>':
case ' ':
case '\t':
case '\n':
break;
default:
len = get_attr_name(our_input+lpc);
if(len < 0) {
error = "couldnt find attr_name";
} else {
crm_malloc0(attr_name, len+1);
strncpy(attr_name, our_input+lpc, len+1);
attr_name[len] = EOS;
lpc += len;
crm_debug_4("found attr name: %s", attr_name);
lpc--; /* make sure the '=' is seen next time around */
}
break;
}
}
if(error) {
crm_err("Error parsing token: %s", error);
crm_err("Error at or before: %s", our_input+lpc-3);
return NULL;
}
crm_debug_4("Finished processing %s tag", tag_name);
crm_free(tag_name);
if(offset != NULL) {
(*offset) += lpc;
}
CRM_DEV_ASSERT(crm_is_allocated(new_obj) == 1);
return new_obj;
}
void
-log_xml_diff(int log_level, crm_data_t *diff, const char *function)
+log_xml_diff(unsigned int log_level, crm_data_t *diff, const char *function)
{
crm_data_t *added = find_xml_node(diff, "diff-added", FALSE);
crm_data_t *removed = find_xml_node(diff, "diff-removed", FALSE);
gboolean is_first = TRUE;
xml_child_iter(
removed, child, NULL,
log_data_element(function, "-", log_level, 0, child, TRUE);
if(is_first) {
is_first = FALSE;
} else {
crm_log_maybe(log_level, " --- ");
}
);
/* crm_log_maybe(log_level, " === "); */
is_first = TRUE;
xml_child_iter(
added, child, NULL,
log_data_element(function, "+", log_level, 0, child, TRUE);
if(is_first) {
is_first = FALSE;
} else {
crm_log_maybe(log_level, " --- ");
}
);
}
gboolean
apply_xml_diff(crm_data_t *old, crm_data_t *diff, crm_data_t **new)
{
gboolean result = TRUE;
crm_data_t *added = find_xml_node(diff, "diff-added", FALSE);
crm_data_t *removed = find_xml_node(diff, "diff-removed", FALSE);
crm_data_t *intermediate = NULL;
crm_data_t *diff_of_diff = NULL;
int root_nodes_seen = 0;
CRM_DEV_ASSERT(new != NULL);
if(crm_assert_failed) { return FALSE; }
crm_debug_2("Substraction Phase");
xml_child_iter(removed, child_diff, NULL,
CRM_DEV_ASSERT(root_nodes_seen == 0);
if(root_nodes_seen == 0) {
*new = subtract_xml_object(old, child_diff, FALSE);
}
root_nodes_seen++;
);
if(root_nodes_seen == 0) {
*new = copy_xml(old);
} else if(root_nodes_seen > 1) {
crm_err("(-) Diffs cannot contain more than one change set..."
" saw %d", root_nodes_seen);
result = FALSE;
}
root_nodes_seen = 0;
crm_debug_2("Addition Phase");
if(result) {
xml_child_iter(added, child_diff, NULL,
CRM_DEV_ASSERT(root_nodes_seen == 0);
if(root_nodes_seen == 0) {
add_xml_object(NULL, *new, child_diff);
}
root_nodes_seen++;
);
}
if(root_nodes_seen > 1) {
crm_err("(+) Diffs cannot contain more than one change set..."
" saw %d", root_nodes_seen);
result = FALSE;
#if CRM_DEV_BUILD
} else if(result) {
crm_debug_2("Verification Phase");
intermediate = diff_xml_object(old, *new, FALSE);
diff_of_diff = diff_xml_object(intermediate, diff, TRUE);
if(diff_of_diff != NULL) {
crm_warn("Diff application failed!");
/* log_xml_diff(LOG_DEBUG, diff_of_diff, "diff:diff_of_diff"); */
log_xml_diff(LOG_DEBUG, intermediate, "diff:actual_diff");
result = FALSE;
}
crm_free(diff_of_diff);
crm_free(intermediate);
#endif
diff_of_diff = NULL;
intermediate = NULL;
}
if(result == FALSE) {
log_xml_diff(LOG_DEBUG, diff, "diff:input_diff");
log_data_element("diff:input", NULL, LOG_DEBUG_2, 0, old, TRUE);
/* CRM_DEV_ASSERT(diff_of_diff != NULL); */
result = FALSE;
}
return result;
}
crm_data_t *
diff_xml_object(crm_data_t *old, crm_data_t *new, gboolean suppress)
{
crm_data_t *diff = NULL;
crm_data_t *tmp1 = NULL;
crm_data_t *added = NULL;
crm_data_t *removed = NULL;
tmp1 = subtract_xml_object(old, new, suppress);
if(tmp1 != NULL) {
diff = create_xml_node(NULL, "diff");
if(can_prune_leaf(tmp1)) {
ha_msg_del(tmp1);
tmp1 = NULL;
} else {
removed = create_xml_node(diff, "diff-removed");
added = create_xml_node(diff, "diff-added");
add_node_copy(removed, tmp1);
}
free_xml(tmp1);
}
tmp1 = subtract_xml_object(new, old, suppress);
if(tmp1 != NULL) {
if(diff == NULL) {
diff = create_xml_node(NULL, "diff");
}
if(can_prune_leaf(tmp1)) {
ha_msg_del(tmp1);
tmp1 = NULL;
} else {
if(removed == NULL) {
removed = create_xml_node(diff, "diff-removed");
}
if(added == NULL) {
added = create_xml_node(diff, "diff-added");
}
add_node_copy(added, tmp1);
}
free_xml(tmp1);
}
return diff;
}
gboolean
can_prune_leaf(crm_data_t *xml_node)
{
gboolean can_prune = TRUE;
/* return FALSE; */
xml_prop_iter(xml_node, prop_name, prop_value,
if(safe_str_eq(prop_name, XML_ATTR_ID)) {
continue;
} else if(safe_str_eq(prop_name, XML_ATTR_TSTAMP)) {
continue;
}
can_prune = FALSE;
);
xml_child_iter(xml_node, child, NULL,
if(can_prune_leaf(child)) {
cl_msg_remove_value(xml_node, child);
__counter--;
} else {
can_prune = FALSE;
}
);
return can_prune;
}
void
diff_filter_context(int context, int upper_bound, int lower_bound,
crm_data_t *xml_node, crm_data_t *parent)
{
crm_data_t *us = NULL;
crm_data_t *new_parent = parent;
const char *name = crm_element_name(xml_node);
CRM_DEV_ASSERT(xml_node != NULL && name != NULL);
if(crm_assert_failed) { return; }
us = create_xml_node(parent, name);
xml_prop_iter(xml_node, prop_name, prop_value,
lower_bound = context;
crm_xml_add(us, prop_name, prop_value);
);
if(lower_bound >= 0 || upper_bound >= 0) {
crm_xml_add(us, XML_ATTR_ID, ID(xml_node));
new_parent = us;
} else {
upper_bound = in_upper_context(0, context, xml_node);
if(upper_bound >= 0) {
crm_xml_add(us, XML_ATTR_ID, ID(xml_node));
new_parent = us;
} else {
free_xml(us);
us = NULL;
}
}
xml_child_iter(us, child, NULL,
diff_filter_context(
context, upper_bound-1, lower_bound-1,
child, new_parent);
);
}
int
in_upper_context(int depth, int context, crm_data_t *xml_node)
{
gboolean has_attributes = FALSE;
if(context == 0) {
return 0;
}
xml_prop_iter(xml_node, prop_name, prop_value,
has_attributes = TRUE;
break;
);
if(has_attributes) {
return depth;
} else if(depth < context) {
xml_child_iter(xml_node, child, NULL,
if(in_upper_context(depth+1, context, child)) {
return depth;
}
);
}
return 0;
}
crm_data_t *
subtract_xml_object(crm_data_t *left, crm_data_t *right, gboolean suppress)
{
gboolean skip = FALSE;
gboolean differences = FALSE;
crm_data_t *diff = NULL;
crm_data_t *child_diff = NULL;
crm_data_t *right_child = NULL;
const char *right_val = NULL;
const char *name = NULL;
int lpc = 0;
const char *filter[] = {
XML_ATTR_TSTAMP,
"last_written",
"debug_source",
"origin"
};
if(left == NULL) {
return NULL;
} else if(right == NULL) {
crm_debug_2("Processing <%s id=%s> (complete copy)",
crm_element_name(left), ID(left));
return copy_xml(left);
}
name = crm_element_name(left);
/* sanity check */
CRM_DEV_ASSERT(name != NULL);
if(crm_assert_failed) { return NULL; }
CRM_DEV_ASSERT(safe_str_eq(crm_element_name(left),
crm_element_name(right)));
if(crm_assert_failed) { return NULL; }
CRM_DEV_ASSERT(safe_str_eq(ID(left), ID(right)));
if(crm_assert_failed) { return NULL; }
diff = create_xml_node(NULL, name);
/* changes to name/value pairs */
crm_debug_2("Processing <%s id=%s>", crm_str(name), ID(left));
xml_prop_iter(left, prop_name, left_value,
skip = FALSE;
if(safe_str_eq(prop_name, XML_ATTR_ID)) {
skip = TRUE;
}
for(lpc = 0;
skip == FALSE && suppress && lpc < DIMOF(filter);
lpc++) {
if(safe_str_eq(prop_name, filter[lpc])) {
skip = TRUE;
}
}
if(skip) { continue; }
right_val = crm_element_value(right, prop_name);
if(right_val == NULL) {
differences = TRUE;
crm_xml_add(diff, prop_name, left_value);
crm_debug_3("\t%s: %s", crm_str(prop_name),
crm_str(left_value));
} else if(safe_str_eq(left_value, right_val)) {
crm_debug_2("\t%s: %s (removed)",
crm_str(prop_name),
crm_str(left_value));
} else {
differences = TRUE;
crm_xml_add(diff, prop_name, left_value);
crm_debug_2("\t%s: %s->%s",
crm_str(prop_name),
crm_str(left_value),
right_val);
}
);
/* changes to child objects */
xml_child_iter(
left, left_child, NULL,
right_child = find_entity(
right, crm_element_name(left_child), ID(left_child));
child_diff = subtract_xml_object(
left_child, right_child, suppress);
if(child_diff != NULL) {
differences = TRUE;
add_node_copy(diff, child_diff);
free_xml(child_diff);
}
);
if(differences == FALSE) {
free_xml(diff);
crm_debug_2("\tNo changes");
return NULL;
}
crm_xml_add(diff, XML_ATTR_ID, ID(left));
return diff;
}
int
add_xml_object(crm_data_t *parent, crm_data_t *target, const crm_data_t *update)
{
const char *object_id = NULL;
const char *object_name = NULL;
const char *right_val = NULL;
int result = 0;
CRM_DEV_ASSERT(update != NULL);
if(crm_assert_failed) { return 0; }
object_name = crm_element_name(update);
object_id = ID(update);
CRM_DEV_ASSERT(object_name != NULL);
if(crm_assert_failed) { return 0; }
if(target == NULL && object_id == NULL) {
/* placeholder object */
target = find_xml_node(parent, object_name, FALSE);
} else if(target == NULL) {
target = find_entity(parent, object_name, object_id);
}
if(target == NULL) {
target = add_node_copy(parent, update);
crm_debug_2("Added <%s id=%s>",
crm_str(object_name), crm_str(object_id));
CRM_DEV_ASSERT(target != NULL);
return 0;
}
crm_debug_2("Found node <%s id=%s> to update",
crm_str(object_name), crm_str(object_id));
xml_prop_iter(update, prop_name, left_value,
right_val = crm_element_value(target, prop_name);
if(right_val == NULL) {
crm_xml_add(target, prop_name, left_value);
crm_debug_2("\t%s: %s (added)",
crm_str(prop_name),
crm_str(left_value));
} else if(safe_str_neq(left_value, right_val)) {
crm_xml_add(target, prop_name, left_value);
crm_debug_2("\t%s: %s->%s",
crm_str(prop_name),
crm_str(left_value),
right_val);
}
);
CRM_DEV_ASSERT(cl_is_allocated(object_name));
if(object_id != NULL) {
CRM_DEV_ASSERT(cl_is_allocated(object_id));
}
crm_debug_3("Processing children of <%s id=%s>",
crm_str(object_name), crm_str(object_id));
xml_child_iter(
update, a_child, NULL,
int tmp_result = 0;
crm_debug_3("Updating child <%s id=%s>",
crm_element_name(a_child), ID(a_child));
tmp_result = add_xml_object(target, NULL, a_child);
if(tmp_result < 0) {
crm_err("Error updating child <%s id=%s>",
crm_element_name(a_child), ID(a_child));
/* only the first error is likely to be interesting */
if(result >= 0) {
result = tmp_result;
}
}
);
crm_debug_3("Finished with <%s id=%s>",
crm_str(object_name), crm_str(object_id));
return result;
}
gboolean
delete_xml_child(crm_data_t *parent, crm_data_t *child, crm_data_t *to_delete)
{
gboolean can_delete = FALSE;
const char *right_val = NULL;
CRM_DEV_ASSERT(child != NULL);
if(crm_assert_failed) { return FALSE; }
CRM_DEV_ASSERT(to_delete != NULL);
if(crm_assert_failed) { return FALSE; }
if(safe_str_eq(crm_element_name(to_delete), crm_element_name(child))) {
can_delete = TRUE;
}
xml_prop_iter(to_delete, prop_name, left_value,
if(can_delete == FALSE) {
break;
}
right_val = crm_element_value(child, prop_name);
if(safe_str_neq(left_value, right_val)) {
can_delete = FALSE;
}
);
if(can_delete && parent != NULL) {
crm_log_xml_debug(child, "Delete match found...");
cl_msg_remove_value(parent, child);
child = NULL;
} else if(can_delete) {
crm_log_xml_debug(child, "Cannot delete the search root");
}
xml_child_iter(
child, child_of_child, NULL,
/* only delete the first one */
if(can_delete) {
break;
}
can_delete = delete_xml_child(child, child_of_child, to_delete);
);
return can_delete;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Apr 21, 7:39 PM (10 h, 19 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1663188
Default Alt Text
(242 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment