diff --git a/cib/callbacks.c b/cib/callbacks.c index 33125f4e53..b996000ef6 100644 --- a/cib/callbacks.c +++ b/cib/callbacks.c @@ -1,1815 +1,1605 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common.h" - extern GMainLoop* mainloop; extern gboolean cib_shutdown_flag; extern gboolean stand_alone; extern const char* cib_root; #if SUPPORT_HEARTBEAT extern ll_cluster_t *hb_conn; #endif extern void cib_ha_connection_destroy(gpointer user_data); extern enum cib_errors cib_update_counter( - crm_data_t *xml_obj, const char *field, gboolean reset); + xmlNode *xml_obj, const char *field, gboolean reset); extern void GHFunc_count_peers( gpointer key, gpointer value, gpointer user_data); extern enum cib_errors revision_check( - crm_data_t *cib_update, crm_data_t *cib_copy, int flags); + xmlNode *cib_update, xmlNode *cib_copy, int flags); void initiate_exit(void); void terminate_cib(const char *caller); gint cib_GCompareFunc(gconstpointer a, gconstpointer b); gboolean cib_msg_timeout(gpointer data); void cib_GHFunc(gpointer key, gpointer value, gpointer user_data); gboolean can_write(int flags); -void send_cib_replace(const HA_Message *sync_request, const char *host); +void send_cib_replace(const xmlNode *sync_request, const char *host); void cib_process_request( - HA_Message *request, gboolean privileged, gboolean force_synchronous, + xmlNode *request, gboolean privileged, gboolean force_synchronous, gboolean from_peer, cib_client_t *cib_client); -HA_Message *cib_construct_reply(HA_Message *request, HA_Message *output, int rc); extern GHashTable *client_list; int next_client_id = 0; extern const char *cib_our_uname; extern unsigned long cib_num_ops, cib_num_local, cib_num_updates, cib_num_fail; extern unsigned long cib_bad_connects, cib_num_timeouts; extern longclock_t cib_call_time; extern enum cib_errors cib_status; -static HA_Message * -cib_prepare_common(HA_Message *root, const char *section) -{ - HA_Message *data = NULL; - - /* extract the CIB from the fragment */ - if(root == NULL) { - return NULL; - - } else if(safe_str_eq(crm_element_name(root), XML_TAG_FRAGMENT) - || safe_str_eq(crm_element_name(root), F_CIB_CALLDATA)) { - data = find_xml_node(root, XML_TAG_CIB, TRUE); - if(data != NULL) { - crm_debug_3("Extracted CIB from %s", TYPE(root)); - } else { - crm_log_xml_debug_4(root, "No CIB"); - } - - } else { - data = root; - } - - /* grab the section specified for the command */ - if(section != NULL - && data != NULL - && safe_str_eq(crm_element_name(data), XML_TAG_CIB)){ - int rc = revision_check(data, the_cib, 0/* call_options */); - if(rc == cib_ok) { - data = get_object_root(section, data); - if(data != NULL) { - crm_debug_3("Extracted %s from CIB", section); - } else { - crm_log_xml_debug_4(root, "No Section"); - } - } else { - crm_debug_2("Revision check failed"); - } - - } - - crm_log_xml_debug_4(root, "cib:input"); - return copy_xml(data); -} - -static gboolean -verify_section(const char *section) -{ - if(section == NULL) { - return TRUE; - } else if(safe_str_eq(section, XML_TAG_CIB)) { - return TRUE; - } else if(safe_str_eq(section, XML_CIB_TAG_STATUS)) { - return TRUE; - } else if(safe_str_eq(section, XML_CIB_TAG_CRMCONFIG)) { - return TRUE; - } else if(safe_str_eq(section, XML_CIB_TAG_NODES)) { - return TRUE; - } else if(safe_str_eq(section, XML_CIB_TAG_RESOURCES)) { - return TRUE; - } else if(safe_str_eq(section, XML_CIB_TAG_CONSTRAINTS)) { - return TRUE; - } - return FALSE; -} - -static enum cib_errors -cib_prepare_none(HA_Message *request, HA_Message **data, const char **section) -{ - *data = NULL; - *section = cl_get_string(request, F_CIB_SECTION); - if(verify_section(*section) == FALSE) { - return cib_bad_section; - } - return cib_ok; -} - -static enum cib_errors -cib_prepare_data(HA_Message *request, HA_Message **data, const char **section) -{ - HA_Message *input_fragment = get_message_xml(request, F_CIB_CALLDATA); - *section = cl_get_string(request, F_CIB_SECTION); - *data = cib_prepare_common(input_fragment, *section); - free_xml(input_fragment); - if(verify_section(*section) == FALSE) { - return cib_bad_section; - } - return cib_ok; -} - -static enum cib_errors -cib_prepare_sync(HA_Message *request, HA_Message **data, const char **section) -{ - *section = cl_get_string(request, F_CIB_SECTION); - *data = request; - if(verify_section(*section) == FALSE) { - return cib_bad_section; - } - return cib_ok; -} - -static enum cib_errors -cib_prepare_diff(HA_Message *request, HA_Message **data, const char **section) -{ - HA_Message *input_fragment = NULL; - const char *update = cl_get_string(request, F_CIB_GLOBAL_UPDATE); - - *data = NULL; - *section = NULL; - - if(crm_is_true(update)) { - input_fragment = get_message_xml(request,F_CIB_UPDATE_DIFF); - - } else { - input_fragment = get_message_xml(request, F_CIB_CALLDATA); - } - - CRM_CHECK(input_fragment != NULL,crm_log_message(LOG_WARNING, request)); - *data = cib_prepare_common(input_fragment, NULL); - free_xml(input_fragment); - return cib_ok; -} - -static enum cib_errors -cib_cleanup_query(const char *op, HA_Message **data, HA_Message **output) -{ - CRM_DEV_ASSERT(*data == NULL); - return cib_ok; -} - -static enum cib_errors -cib_cleanup_data(const char *op, HA_Message **data, HA_Message **output) -{ - free_xml(*output); - free_xml(*data); - return cib_ok; -} - -static enum cib_errors -cib_cleanup_output(const char *op, HA_Message **data, HA_Message **output) -{ - free_xml(*output); - return cib_ok; -} - -static enum cib_errors -cib_cleanup_none(const char *op, HA_Message **data, HA_Message **output) -{ - CRM_DEV_ASSERT(*data == NULL); - CRM_DEV_ASSERT(*output == NULL); - return cib_ok; -} - -static enum cib_errors -cib_cleanup_sync(const char *op, HA_Message **data, HA_Message **output) -{ - /* data is non-NULL but doesnt need to be free'd */ - CRM_DEV_ASSERT(*output == NULL); - return cib_ok; -} - -/* -typedef struct cib_operation_s -{ - const char* operation; - gboolean modifies_cib; - gboolean needs_privileges; - gboolean needs_quorum; - enum cib_errors (*prepare)(HA_Message *, crm_data_t**, const char **); - enum cib_errors (*cleanup)(crm_data_t**, crm_data_t**); - 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, cib_prepare_none, cib_cleanup_none, cib_process_default}, - {CIB_OP_QUERY, FALSE, FALSE, FALSE, cib_prepare_none, cib_cleanup_query, cib_process_query}, - {CIB_OP_MODIFY, TRUE, TRUE, TRUE, cib_prepare_data, cib_cleanup_data, cib_process_modify}, - {CIB_OP_UPDATE, TRUE, TRUE, TRUE, cib_prepare_data, cib_cleanup_data, cib_process_change}, - {CIB_OP_APPLY_DIFF,TRUE, TRUE, TRUE, cib_prepare_diff, cib_cleanup_data, cib_process_diff}, - {CIB_OP_SLAVE, FALSE, TRUE, FALSE, cib_prepare_none, cib_cleanup_none, cib_process_readwrite}, - {CIB_OP_SLAVEALL, FALSE, TRUE, FALSE, cib_prepare_none, cib_cleanup_none, cib_process_readwrite}, - {CIB_OP_SYNC_ONE, FALSE, TRUE, FALSE, cib_prepare_sync, cib_cleanup_sync, cib_process_sync_one}, - {CIB_OP_MASTER, FALSE, TRUE, FALSE, cib_prepare_none, cib_cleanup_none, cib_process_readwrite}, - {CIB_OP_ISMASTER, FALSE, TRUE, FALSE, cib_prepare_none, cib_cleanup_none, cib_process_readwrite}, - {CIB_OP_BUMP, TRUE, TRUE, TRUE, cib_prepare_none, cib_cleanup_output, cib_process_bump}, - {CIB_OP_REPLACE, TRUE, TRUE, TRUE, cib_prepare_data, cib_cleanup_data, cib_process_replace}, - {CIB_OP_CREATE, TRUE, TRUE, TRUE, cib_prepare_data, cib_cleanup_data, cib_process_change}, - {CIB_OP_DELETE, TRUE, TRUE, TRUE, cib_prepare_data, cib_cleanup_data, cib_process_delete}, - {CIB_OP_DELETE_ALT,TRUE, TRUE, TRUE, cib_prepare_data, cib_cleanup_data, cib_process_change}, - {CIB_OP_SYNC, FALSE, TRUE, FALSE, cib_prepare_sync, cib_cleanup_sync, cib_process_sync}, - {CRM_OP_QUIT, FALSE, TRUE, FALSE, cib_prepare_none, cib_cleanup_none, cib_process_quit}, - {CRM_OP_PING, FALSE, FALSE, FALSE, cib_prepare_none, cib_cleanup_output, cib_process_ping}, - {CIB_OP_ERASE, TRUE, TRUE, TRUE, cib_prepare_none, cib_cleanup_output, cib_process_erase}, - {CRM_OP_NOOP, FALSE, FALSE, FALSE, cib_prepare_none, cib_cleanup_none, cib_process_default}, - {"cib_shutdown_req",FALSE, TRUE, FALSE, cib_prepare_sync, cib_cleanup_sync, cib_process_shutdown_req}, -}; - -int send_via_callback_channel(HA_Message *msg, const char *token); +int send_via_callback_channel(xmlNode *msg, const char *token); enum cib_errors cib_process_command( - HA_Message *request, HA_Message **reply, - crm_data_t **cib_diff, gboolean privileged); + xmlNode *request, xmlNode **reply, + xmlNode **cib_diff, gboolean privileged); gboolean cib_common_callback(IPC_Channel *channel, cib_client_t *cib_client, gboolean force_synchronous, gboolean privileged); gboolean cib_process_disconnect(IPC_Channel *channel, cib_client_t *cib_client); int num_clients = 0; static void cib_ipc_connection_destroy(gpointer user_data) { cib_client_t *cib_client = user_data; /* cib_process_disconnect */ if(cib_client == NULL) { crm_debug_4("Destroying %p", user_data); return; } if(cib_client->source != NULL) { crm_debug_4("Deleting %s (%p) from mainloop", cib_client->name, cib_client->source); G_main_del_IPC_Channel(cib_client->source); cib_client->source = NULL; } crm_debug_3("Destroying %s (%p)", cib_client->name, user_data); num_clients--; crm_debug_2("Num unfree'd clients: %d", num_clients); crm_free(cib_client->name); crm_free(cib_client->callback_id); crm_free(cib_client->id); crm_free(cib_client); crm_debug_4("Freed the cib client"); return; } static cib_client_t * cib_client_connect_common( IPC_Channel *channel, const char *channel_name, gboolean (*callback)(IPC_Channel *channel, gpointer user_data)) { gboolean can_connect = TRUE; cib_client_t *new_client = NULL; crm_debug_3("Connecting channel"); if (channel == NULL) { crm_err("Channel was NULL"); can_connect = FALSE; cib_bad_connects++; } else if (channel->ch_status != IPC_CONNECT) { crm_err("Channel was disconnected"); can_connect = FALSE; cib_bad_connects++; } else if(channel_name == NULL) { crm_err("user_data must contain channel name"); can_connect = FALSE; cib_bad_connects++; } else if(cib_shutdown_flag) { crm_info("Ignoring new client [%d] during shutdown", channel->farside_pid); return NULL; } else { crm_malloc0(new_client, sizeof(cib_client_t)); num_clients++; new_client->channel = channel; new_client->channel_name = channel_name; crm_debug_3("Created channel %p for channel %s", new_client, new_client->channel_name); channel->ops->set_recv_qlen(channel, 1024); channel->ops->set_send_qlen(channel, 1024); if(callback != NULL) { new_client->source = G_main_add_IPC_Channel( G_PRIORITY_DEFAULT, channel, FALSE, callback, new_client, cib_ipc_connection_destroy); } crm_debug_3("Channel %s connected for client %s", new_client->channel_name, new_client->id); } return new_client; } gboolean cib_client_connect_rw_synch(IPC_Channel *channel, gpointer user_data) { cib_client_t *new_client = NULL; new_client = cib_client_connect_common( channel, cib_channel_rw_synchronous, cib_rw_synchronous_callback); if(new_client == NULL) { return FALSE; } return TRUE; } gboolean cib_client_connect_ro_synch(IPC_Channel *channel, gpointer user_data) { cib_client_t *new_client = NULL; new_client = cib_client_connect_common( channel, cib_channel_ro_synchronous, cib_ro_synchronous_callback); if(new_client == NULL) { return FALSE; } return TRUE; } gboolean cib_client_connect_rw_ro(IPC_Channel *channel, gpointer user_data) { cl_uuid_t client_id; - HA_Message *reg_msg = NULL; + xmlNode *reg_msg = NULL; cib_client_t *new_client = NULL; char uuid_str[UU_UNPARSE_SIZEOF]; gboolean (*callback)(IPC_Channel *channel, gpointer user_data); callback = cib_ro_callback; if(safe_str_eq(user_data, cib_channel_rw)) { callback = cib_rw_callback; } new_client = cib_client_connect_common( channel, callback==cib_ro_callback?cib_channel_ro:cib_channel_rw, callback); if(new_client == NULL) { return FALSE; } cl_uuid_generate(&client_id); cl_uuid_unparse(&client_id, uuid_str); CRM_CHECK(new_client->id == NULL, crm_free(new_client->id)); new_client->id = crm_strdup(uuid_str); cl_uuid_generate(&client_id); cl_uuid_unparse(&client_id, uuid_str); CRM_CHECK(new_client->callback_id == NULL, crm_free(new_client->callback_id)); new_client->callback_id = crm_strdup(uuid_str); /* make sure we can find ourselves later for sync calls * redirected to the master instance */ g_hash_table_insert(client_list, new_client->id, new_client); - reg_msg = 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); + reg_msg = create_xml_node(NULL, "callback"); + crm_xml_add(reg_msg, F_CIB_OPERATION, CRM_OP_REGISTER); + crm_xml_add(reg_msg, F_CIB_CLIENTID, new_client->id); + crm_xml_add(reg_msg, F_CIB_CALLBACK_TOKEN, new_client->callback_id); send_ipc_message(channel, reg_msg); - crm_msg_del(reg_msg); + free_xml(reg_msg); return TRUE; } gboolean cib_client_connect_null(IPC_Channel *channel, gpointer user_data) { cib_client_t *new_client = NULL; new_client = cib_client_connect_common( channel, cib_channel_callback, cib_null_callback); if(new_client == NULL) { return FALSE; } return TRUE; } gboolean cib_rw_callback(IPC_Channel *channel, gpointer user_data) { gboolean result = FALSE; result = cib_common_callback(channel, user_data, FALSE, TRUE); return result; } gboolean cib_ro_synchronous_callback(IPC_Channel *channel, gpointer user_data) { gboolean result = FALSE; result = cib_common_callback(channel, user_data, TRUE, FALSE); return result; } gboolean cib_rw_synchronous_callback(IPC_Channel *channel, gpointer user_data) { gboolean result = FALSE; result = cib_common_callback(channel, user_data, TRUE, TRUE); return result; } gboolean cib_ro_callback(IPC_Channel *channel, gpointer user_data) { gboolean result = FALSE; result = cib_common_callback(channel, user_data, FALSE, FALSE); return result; } gboolean cib_null_callback(IPC_Channel *channel, gpointer user_data) { gboolean keep_connection = TRUE; - HA_Message *op_request = NULL; - HA_Message *registered = NULL; + xmlNode *op_request = NULL; + xmlNode *registered = 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(IPC_ISRCONN(channel)) { - crm_msg_del(op_request); + free_xml(op_request); op_request = NULL; if(channel->ops->is_message_pending(channel) == 0) { break; } - op_request = msgfromIPC_noauth(channel); + op_request = xmlfromIPC(channel, 0); if(op_request == NULL) { break; } - type = cl_get_string(op_request, F_CIB_OPERATION); + type = crm_element_value(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( + crm_element_value_int( op_request, F_CIB_NOTIFY_ACTIVATE, &on_off); - type = cl_get_string(op_request, F_CIB_NOTIFY_TYPE); + type = crm_element_value(op_request, F_CIB_NOTIFY_TYPE); crm_info("Setting %s callbacks for %s: %s", type, cib_client->name, on_off?"on":"off"); 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; } else if(safe_str_eq(type, T_CIB_REPLACE_NOTIFY)) { cib_client->replace = 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); continue; } - uuid_ticket = cl_get_string(op_request, F_CIB_CALLBACK_TOKEN); - client_name = cl_get_string(op_request, F_CIB_CLIENTNAME); + uuid_ticket = crm_element_value(op_request, F_CIB_CALLBACK_TOKEN); + client_name = crm_element_value(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); + free_xml(op_request); return FALSE; } CRM_CHECK(cib_client->id == NULL, crm_free(cib_client->id)); CRM_CHECK(cib_client->name == NULL, crm_free(cib_client->name)); 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); if(safe_str_eq(cib_client->name, CRM_SYSTEM_TENGINE)) { /* The TE is _always_ interested in these * Enable now to avoid timing issues */ cib_client->diffs = TRUE; } - registered = ha_msg_new(2); - ha_msg_add(registered, F_CIB_OPERATION, CRM_OP_REGISTER); - ha_msg_add(registered, F_CIB_CLIENTID, cib_client->id); + registered = create_xml_node(NULL, "registered"); + crm_xml_add(registered, F_CIB_OPERATION, CRM_OP_REGISTER); + crm_xml_add(registered, F_CIB_CLIENTID, cib_client->id); send_ipc_message(channel, registered); - crm_msg_del(registered); + free_xml(registered); if(channel->ch_status == IPC_CONNECT) { break; } } - crm_msg_del(op_request); + free_xml(op_request); if(channel->ch_status != IPC_CONNECT) { crm_debug_2("Client disconnected"); keep_connection = cib_process_disconnect(channel, cib_client); } return keep_connection; } void -cib_common_callback_worker(HA_Message *op_request, cib_client_t *cib_client, +cib_common_callback_worker(xmlNode *op_request, cib_client_t *cib_client, gboolean force_synchronous, gboolean privileged); void -cib_common_callback_worker(HA_Message *op_request, cib_client_t *cib_client, +cib_common_callback_worker(xmlNode *op_request, cib_client_t *cib_client, gboolean force_synchronous, gboolean privileged) { int rc = cib_ok; int call_type = 0; const char *op = NULL; longclock_t call_stop = 0; longclock_t call_start = 0; call_start = time_longclock(); cib_client->num_calls++; - op = cl_get_string(op_request, F_CIB_OPERATION); + op = crm_element_value(op_request, F_CIB_OPERATION); rc = cib_get_operation_id(op, &call_type); if(rc != cib_ok) { crm_debug("Invalid operation %s from %s/%s", op, cib_client->name, cib_client->channel_name); } else { crm_debug_2("Processing %s operation from %s/%s", op, cib_client->name, cib_client->channel_name); } if(rc == cib_ok) { cib_process_request( op_request, force_synchronous, privileged, FALSE, cib_client); } call_stop = time_longclock(); cib_call_time += (call_stop - call_start); } gboolean cib_common_callback(IPC_Channel *channel, cib_client_t *cib_client, gboolean force_synchronous, gboolean privileged) { int lpc = 0; - HA_Message *op_request = NULL; + xmlNode *op_request = NULL; gboolean keep_channel = TRUE; if(cib_client == NULL) { crm_err("Receieved call from unknown source. Discarding."); return FALSE; } if(cib_client->name == NULL) { cib_client->name = crm_itoa(channel->farside_pid); } if(cib_client->id == NULL) { cib_client->id = crm_strdup(cib_client->name); g_hash_table_insert(client_list, cib_client->id, cib_client); } crm_debug_2("Callback for %s on %s channel", cib_client->id, cib_client->channel_name); while(IPC_ISRCONN(channel)) { if(channel->ops->is_message_pending(channel) == 0) { break; } - op_request = msgfromIPC_noauth(channel); + op_request = xmlfromIPC(channel, 0); if (op_request == NULL) { perror("Receive failure:"); break; } lpc++; crm_assert_failed = FALSE; - crm_log_message_adv(LOG_MSG, "Client[inbound]", op_request); - ha_msg_add(op_request, F_CIB_CLIENTID, cib_client->id); - ha_msg_add(op_request, F_CIB_CLIENTNAME, cib_client->name); + crm_log_xml(LOG_MSG, "Client[inbound]", op_request); + crm_xml_add(op_request, F_CIB_CLIENTID, cib_client->id); + crm_xml_add(op_request, F_CIB_CLIENTNAME, cib_client->name); cib_common_callback_worker( op_request, cib_client, force_synchronous, privileged); - crm_msg_del(op_request); + free_xml(op_request); if(channel->ch_status == IPC_CONNECT) { break; } } crm_debug_2("Processed %d messages", lpc); if(channel->ch_status != IPC_CONNECT) { crm_debug_2("Client disconnected"); keep_channel = cib_process_disconnect(channel, cib_client); } return keep_channel; } -extern void cib_send_remote_msg(void *session, HA_Message *msg); +extern void cib_send_remote_msg(void *session, xmlNode *msg); static void -do_local_notify(HA_Message *notify_src, const char *client_id, gboolean sync_reply, gboolean from_peer) +do_local_notify(xmlNode *notify_src, const char *client_id, + gboolean sync_reply, gboolean from_peer) { /* send callback to originating child */ cib_client_t *client_obj = NULL; - HA_Message *client_reply = NULL; + xmlNode *client_reply = NULL; enum cib_errors local_rc = cib_ok; crm_debug_2("Performing notification"); - client_reply = cib_msg_copy(notify_src, TRUE); if(client_id != NULL) { client_obj = g_hash_table_lookup( client_list, client_id); } else { crm_debug_2("No client to sent the response to." " F_CIB_CLIENTID not set."); } crm_debug_3("Sending callback to request originator"); if(client_obj == NULL) { local_rc = cib_reply_failed; } else if (crm_str_eq(client_obj->channel_name, "remote", FALSE)) { crm_debug("Send message over TLS connection"); cib_send_remote_msg(client_obj->channel, client_reply); } else { const char *client_id = client_obj->callback_id; crm_debug_2("Sending %ssync response to %s %s", sync_reply?"":"an a-", client_obj->name, from_peer?"(originator of delegated request)":""); if(sync_reply) { client_id = client_obj->id; } local_rc = send_via_callback_channel(client_reply, client_id); } if(local_rc != cib_ok && client_obj != NULL) { crm_warn("%sSync reply to %s failed: %s", sync_reply?"":"A-", client_obj?client_obj->name:"", cib_error2string(local_rc)); } - ha_msg_del(client_reply); + free_xml(client_reply); } static void parse_local_options( cib_client_t *cib_client, int call_type, int call_options, const char *host, const char *op, gboolean *local_notify, gboolean *needs_reply, gboolean *process, gboolean *needs_forward) { - if(cib_server_ops[call_type].modifies_cib + if(cib_op_modifies(call_type) && !(call_options & cib_inhibit_bcast)) { /* we need to send an update anyway */ *needs_reply = TRUE; } else { *needs_reply = FALSE; } if(host == NULL && (call_options & cib_scope_local)) { crm_debug_2("Processing locally scoped %s op from %s", op, cib_client->name); *local_notify = TRUE; } else if(host == NULL && cib_is_master) { crm_debug_2("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_2("Processing locally addressed %s op from %s", op, cib_client->name); *local_notify = TRUE; } else if(stand_alone) { *needs_forward = FALSE; *local_notify = TRUE; *process = TRUE; } else { crm_debug_2("%s op from %s needs to be forwarded to %s", op, cib_client->name, host?host:"the master instance"); *needs_forward = TRUE; *process = FALSE; } } static gboolean parse_peer_options( - int call_type, HA_Message *request, + int call_type, xmlNode *request, gboolean *local_notify, gboolean *needs_reply, gboolean *process, gboolean *needs_forward) { - 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 *op = crm_element_value(request, F_CIB_OPERATION); + const char *originator = crm_element_value(request, F_ORIG); + const char *host = crm_element_value(request, F_CIB_HOST); + const char *reply_to = crm_element_value(request, F_CIB_ISREPLY); + const char *update = crm_element_value(request, F_CIB_GLOBAL_UPDATE); + const char *delegated = crm_element_value(request, F_CIB_DELEGATED); if(safe_str_eq(op, "cib_shutdown_req")) { if(reply_to != NULL) { crm_debug("Processing %s from %s", op, host); *needs_reply = FALSE; } else { crm_debug("Processing %s reply from %s", op, host); } return TRUE; } else if(crm_is_true(update) && safe_str_eq(reply_to, cib_our_uname)) { crm_debug_2("Processing global/peer update from %s" " that originated from us", originator); *needs_reply = FALSE; - if(cl_get_string(request, F_CIB_CLIENTID) != NULL) { + if(crm_element_value(request, F_CIB_CLIENTID) != NULL) { *local_notify = TRUE; } return TRUE; } else if(crm_is_true(update)) { crm_debug_2("Processing global/peer update from %s", originator); *needs_reply = FALSE; return TRUE; } else if(host != NULL && safe_str_eq(host, cib_our_uname)) { crm_debug_2("Processing request sent to us from %s", originator); return TRUE; } else if(delegated != NULL && cib_is_master == TRUE) { crm_debug_2("Processing request sent to master instance from %s", originator); return TRUE; } else if(reply_to != NULL && safe_str_eq(reply_to, cib_our_uname)) { crm_debug_2("Forward reply sent from %s to local clients", originator); *process = FALSE; *needs_reply = FALSE; *local_notify = TRUE; return TRUE; } else if(delegated != NULL) { crm_debug_2("Ignoring msg for master instance"); } 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)); } 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)); } else { crm_err("Nothing for us to do?"); - crm_log_message_adv(LOG_ERR, "Peer[inbound]", request); + crm_log_xml(LOG_ERR, "Peer[inbound]", request); } return FALSE; } static void -forward_request(HA_Message *request, cib_client_t *cib_client, int call_options) +forward_request(xmlNode *request, cib_client_t *cib_client, int call_options) { - HA_Message *forward_msg = NULL; - const char *op = cl_get_string(request, F_CIB_OPERATION); - const char *host = cl_get_string(request, F_CIB_HOST); + xmlNode *forward_msg = NULL; + const char *op = crm_element_value(request, F_CIB_OPERATION); + const char *host = crm_element_value(request, F_CIB_HOST); forward_msg = cib_msg_copy(request, TRUE); - ha_msg_add(forward_msg, F_CIB_DELEGATED, cib_our_uname); + crm_xml_add(forward_msg, F_CIB_DELEGATED, cib_our_uname); if(host != NULL) { crm_debug_2("Forwarding %s op to %s", op, host); send_cluster_message(host, crm_msg_cib, forward_msg, FALSE); } else { crm_debug_2("Forwarding %s op to master instance", op); send_cluster_message(NULL, crm_msg_cib, forward_msg, FALSE); } if(call_options & cib_discard_reply) { crm_debug_2("Client not interested in reply"); } else if(call_options & cib_sync_call) { /* keep track of the request so we can time it * out if required */ crm_debug_2("Registering delegated call from %s", cib_client->id); cib_client->delegated_calls = g_list_append( cib_client->delegated_calls, forward_msg); forward_msg = NULL; } - crm_msg_del(forward_msg); + free_xml(forward_msg); } static void send_peer_reply( - HA_Message *msg, crm_data_t *result_diff, const char *originator, gboolean broadcast) + xmlNode *msg, xmlNode *result_diff, const char *originator, gboolean broadcast) { - HA_Message *reply_copy = NULL; + xmlNode *reply_copy = NULL; CRM_ASSERT(msg != NULL); reply_copy = cib_msg_copy(msg, TRUE); if(broadcast) { /* this (successful) call modified the CIB _and_ the * change needs to be broadcast... * send via HA to other nodes */ int diff_add_updates = 0; int diff_add_epoch = 0; int diff_add_admin_epoch = 0; int diff_del_updates = 0; int diff_del_epoch = 0; int diff_del_admin_epoch = 0; char *digest = NULL; cib_diff_version_details( result_diff, &diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates, &diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates); crm_debug("Sending update diff %d.%d.%d -> %d.%d.%d", diff_del_admin_epoch,diff_del_epoch,diff_del_updates, diff_add_admin_epoch,diff_add_epoch,diff_add_updates); - ha_msg_add(reply_copy, F_CIB_ISREPLY, originator); - ha_msg_add(reply_copy, F_CIB_GLOBAL_UPDATE, XML_BOOLEAN_TRUE); - ha_msg_mod(reply_copy, F_CIB_OPERATION, CIB_OP_APPLY_DIFF); + crm_xml_add(reply_copy, F_CIB_ISREPLY, originator); + crm_xml_add(reply_copy, F_CIB_GLOBAL_UPDATE, XML_BOOLEAN_TRUE); + crm_xml_add(reply_copy, F_CIB_OPERATION, CIB_OP_APPLY_DIFF); digest = calculate_xml_digest(the_cib, FALSE, TRUE); - ha_msg_mod(result_diff, XML_ATTR_DIGEST, digest); + crm_xml_add(result_diff, XML_ATTR_DIGEST, digest); /* crm_log_xml_debug(the_cib, digest); */ crm_free(digest); add_message_xml(reply_copy, F_CIB_UPDATE_DIFF, result_diff); - crm_log_message(LOG_DEBUG_3, reply_copy); + crm_log_xml(LOG_DEBUG_3, "copy", reply_copy); send_cluster_message(NULL, crm_msg_cib, reply_copy, TRUE); } else if(originator != NULL) { /* send reply via HA to originating node */ crm_debug_2("Sending request result to originator only"); - ha_msg_add(reply_copy, F_CIB_ISREPLY, originator); + crm_xml_add(reply_copy, F_CIB_ISREPLY, originator); send_cluster_message(originator, crm_msg_cib, reply_copy, FALSE); } - crm_msg_del(reply_copy); + free_xml(reply_copy); } void cib_process_request( - HA_Message *request, gboolean force_synchronous, gboolean privileged, + xmlNode *request, gboolean force_synchronous, 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; + xmlNode *result_diff = NULL; enum cib_errors rc = cib_ok; - HA_Message *op_reply = NULL; + xmlNode *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 *update = cl_get_string(request, F_CIB_GLOBAL_UPDATE); + const char *op = crm_element_value(request, F_CIB_OPERATION); + const char *originator = crm_element_value(request, F_ORIG); + const char *host = crm_element_value(request, F_CIB_HOST); + const char *update = crm_element_value(request, F_CIB_GLOBAL_UPDATE); crm_debug_4("%s Processing msg %s", - cib_our_uname, cl_get_string(request, F_SEQ)); + cib_our_uname, crm_element_value(request, F_SEQ)); cib_num_ops++; if(cib_num_ops == 0) { cib_num_fail = 0; cib_num_local = 0; cib_num_updates = 0; crm_info("Stats wrapped around"); } if(host != NULL && strlen(host) == 0) { host = NULL; } - ha_msg_value_int(request, F_CIB_CALLOPTS, &call_options); + crm_element_value_int(request, F_CIB_CALLOPTS, &call_options); crm_debug_4("Retrieved call options: %d", call_options); if(force_synchronous) { call_options |= cib_sync_call; } crm_debug_2("Processing %s message (%s) for %s...", from_peer?"peer":"local", from_peer?originator:cib_our_uname, host?host:"master"); rc = cib_get_operation_id(op, &call_type); - if(cib_server_ops[call_type].modifies_cib) { + if(cib_op_modifies(call_type)) { cib_num_updates++; } if(rc != cib_ok) { /* TODO: construct error reply */ crm_err("Pre-processing of command failed: %s", cib_error2string(rc)); } else if(from_peer == FALSE) { parse_local_options(cib_client, call_type, call_options, host, op, &local_notify, &needs_reply, &process, &needs_forward); } else if(parse_peer_options(call_type, request, &local_notify, &needs_reply, &process, &needs_forward) == FALSE) { return; } crm_debug_3("Finished determining processing actions"); if(call_options & cib_discard_reply) { - needs_reply = cib_server_ops[call_type].modifies_cib; + needs_reply = cib_op_modifies(call_type); local_notify = FALSE; } if(needs_forward) { forward_request(request, cib_client, call_options); return; } if(cib_status != cib_ok) { rc = cib_status; crm_err("Operation ignored, cluster configuration is invalid." " Please repair and restart: %s", cib_error2string(cib_status)); op_reply = cib_construct_reply(request, the_cib, cib_status); } else if(process) { cib_num_local++; crm_debug_2("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); + crm_element_value(request, F_CIB_OPERATION), originator, + crm_element_value(request, F_CIB_CLIENTID), + crm_element_value(request, F_CIB_CALLID), update); rc = cib_process_command( request, &op_reply, &result_diff, privileged); crm_debug_2("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) { cib_num_fail++; crm_err("%s operation failed: %s", crm_str(op), cib_error2string(rc)); - crm_log_message_adv(LOG_DEBUG, "CIB[output]", op_reply); - crm_log_message_adv(LOG_INFO, "Input message", request); + crm_log_xml(LOG_DEBUG, "CIB[output]", op_reply); + crm_log_xml(LOG_INFO, "Input message", request); } if(op_reply == NULL && (needs_reply || local_notify)) { crm_err("Unexpected NULL reply to message"); - crm_log_message(LOG_ERR, request); + crm_log_xml(LOG_ERR, "null reply", request); needs_reply = FALSE; local_notify = FALSE; } } crm_debug_3("processing response cases"); - + crm_debug("Notify: %d", local_notify); + if(local_notify) { - const char *client_id = cl_get_string(request, F_CIB_CLIENTID); + const char *client_id = crm_element_value(request, F_CIB_CLIENTID); if(process == FALSE) { do_local_notify(request, client_id, call_options & cib_sync_call, from_peer); } else { do_local_notify(op_reply, client_id, call_options & cib_sync_call, from_peer); } } /* from now on we are the server */ if(needs_reply == FALSE || stand_alone) { /* nothing more to do... * this was a non-originating slave update */ crm_debug_2("Completed slave update"); } else if(rc == cib_ok && result_diff != NULL && !(call_options & cib_inhibit_bcast)) { send_peer_reply(request, result_diff, originator, TRUE); } else if(call_options & cib_discard_reply) { crm_debug_4("Caller isn't interested in reply"); } else if (from_peer) { crm_debug_2("Directing reply to %s", originator); if(call_options & cib_inhibit_bcast) { crm_debug_3("Request not broadcast: inhibited"); } - if(cib_server_ops[call_type].modifies_cib == FALSE || result_diff == NULL) { + if(cib_op_modifies(call_type) == FALSE || result_diff == NULL) { crm_debug_3("Request not broadcast: R/O call"); } if(rc != cib_ok) { crm_debug_3("Request not broadcast: call failed: %s", cib_error2string(rc)); } send_peer_reply(op_reply, result_diff, originator, FALSE); } - crm_msg_del(op_reply); + free_xml(op_reply); free_xml(result_diff); return; } -HA_Message * -cib_construct_reply(HA_Message *request, HA_Message *output, int rc) +xmlNode * +cib_construct_reply(xmlNode *request, xmlNode *output, int rc) { int lpc = 0; - HA_Message *reply = NULL; + xmlNode *reply = NULL; const char *name = NULL; const char *value = NULL; const char *names[] = { F_CIB_OPERATION, F_CIB_CALLID, F_CIB_CLIENTID, F_CIB_CALLOPTS }; crm_debug_4("Creating a basic reply"); - reply = ha_msg_new(8); - ha_msg_add(reply, F_TYPE, T_CIB); + reply = create_xml_node(NULL, "cib-reply"); + crm_xml_add(reply, F_TYPE, T_CIB); for(lpc = 0; lpc < DIMOF(names); lpc++) { name = names[lpc]; - value = cl_get_string(request, name); - ha_msg_add(reply, name, value); + value = crm_element_value(request, name); + crm_xml_add(reply, name, value); } - ha_msg_add_int(reply, F_CIB_RC, rc); + crm_xml_add_int(reply, F_CIB_RC, rc); if(output != NULL) { crm_debug_4("Attaching reply output"); add_message_xml(reply, F_CIB_CALLDATA, output); } return reply; } enum cib_errors -cib_process_command(HA_Message *request, HA_Message **reply, - crm_data_t **cib_diff, gboolean privileged) +cib_process_command(xmlNode *request, xmlNode **reply, + xmlNode **cib_diff, gboolean privileged) { gboolean send_r_notify = FALSE; - crm_data_t *output = NULL; - crm_data_t *input = NULL; + xmlNode *output = NULL; + xmlNode *input = NULL; - crm_data_t *current_cib = NULL; - crm_data_t *result_cib = NULL; + xmlNode *current_cib = NULL; + xmlNode *result_cib = NULL; int call_type = 0; int call_options = 0; enum cib_errors rc = cib_ok; enum cib_errors rc2 = cib_ok; int log_level = LOG_DEBUG_3; - crm_data_t *filtered = NULL; + xmlNode *filtered = NULL; const char *op = NULL; const char *section = NULL; gboolean config_changed = FALSE; - gboolean global_update = crm_is_true(cl_get_string(request, F_CIB_GLOBAL_UPDATE)); + gboolean global_update = crm_is_true(crm_element_value(request, F_CIB_GLOBAL_UPDATE)); CRM_ASSERT(cib_status == cib_ok); *reply = NULL; *cib_diff = NULL; if(per_action_cib) { CRM_CHECK(the_cib == NULL, free_xml(the_cib)); the_cib = readCibXmlFile(cib_root, "cib.xml", FALSE); CRM_CHECK(the_cib != NULL, return cib_NOOBJECT); } current_cib = the_cib; /* Start processing the request... */ - op = cl_get_string(request, F_CIB_OPERATION); - ha_msg_value_int(request, F_CIB_CALLOPTS, &call_options); + op = crm_element_value(request, F_CIB_OPERATION); + crm_element_value_int(request, F_CIB_CALLOPTS, &call_options); rc = cib_get_operation_id(op, &call_type); - if(rc == cib_ok && - cib_server_ops[call_type].needs_privileges - && privileged == FALSE) { - /* abort */ - rc = cib_not_authorized; + if(rc == cib_ok) { + rc = cib_op_can_run(call_type, call_options, privileged, global_update); } - if(rc == cib_ok - && stand_alone == FALSE - && 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; call_options |= cib_force_diff; } - rc2 = cib_server_ops[call_type].prepare(request, &input, §ion); + rc2 = cib_op_prepare(call_type, request, &input, §ion); if(rc == cib_ok) { rc = rc2; } if(rc != cib_ok) { crm_debug_2("Call setup failed: %s", cib_error2string(rc)); goto done; - } else if(cib_server_ops[call_type].modifies_cib == FALSE) { - rc = cib_perform_op(op, call_options, section, input, FALSE, &config_changed, + } else if(cib_op_modifies(call_type) == FALSE) { + rc = cib_perform_op(op, call_options, section, request, input, FALSE, &config_changed, current_cib, &result_cib, &output); CRM_CHECK(result_cib == NULL, free_xml(result_cib)); goto done; } /* Handle a valid write action */ if((call_options & cib_inhibit_notify) == 0) { cib_pre_notify(call_options, op, get_object_root(section, current_cib), input); } if(rc == cib_ok) { gboolean manage_counters = TRUE; if(global_update) { /* skip */ CRM_CHECK(call_type == 4 || call_type == 11, crm_err("Call type: %d", call_type); - crm_log_message(LOG_ERR, request)); + crm_log_xml(LOG_ERR, "bad op", request)); crm_debug_2("Skipping update: global replace"); manage_counters = FALSE; - } else if(cib_server_ops[call_type].fn == cib_process_change - && (call_options & cib_inhibit_bcast)) { + } else if(call_options & cib_inhibit_bcast) { /* skip */ crm_debug_2("Skipping update: inhibit broadcast"); manage_counters = FALSE; } rc = cib_perform_op( - op, call_options, section, input, manage_counters, &config_changed, + op, call_options, section, request, input, manage_counters, &config_changed, current_cib, &result_cib, &output); *cib_diff = diff_cib_object(current_cib, result_cib, FALSE); } if(rc != cib_ok) { free_xml(result_cib); } else { rc = activateCibXml(result_cib, config_changed); if(rc != cib_ok) { crm_warn("Activation failed"); } } if((call_options & cib_inhibit_notify) == 0) { - const char *call_id = cl_get_string(request, F_CIB_CALLID); - const char *client = cl_get_string(request, F_CIB_CLIENTNAME); + const char *call_id = crm_element_value(request, F_CIB_CALLID); + const char *client = crm_element_value(request, F_CIB_CLIENTNAME); cib_post_notify(call_options, op, input, rc, the_cib); cib_diff_notify(call_options, client, call_id, op, input, rc, *cib_diff); } if(rc == cib_ok && safe_str_eq(CIB_OP_ERASE, op)) { send_r_notify = TRUE; } else if(rc == cib_ok && safe_str_eq(CIB_OP_REPLACE, op)) { if(section == NULL) { send_r_notify = TRUE; } else if(safe_str_eq(section, XML_TAG_CIB)) { send_r_notify = TRUE; } else if(safe_str_eq(section, XML_CIB_TAG_NODES)) { send_r_notify = TRUE; } else if(safe_str_eq(section, XML_CIB_TAG_STATUS)) { send_r_notify = TRUE; } } if(send_r_notify) { cib_replace_notify(the_cib, rc, *cib_diff); } if(rc == cib_dtd_validation && global_update) { log_level = LOG_WARNING; crm_log_xml_info(input, "cib:global_update"); } else if(rc != cib_ok) { log_level = LOG_DEBUG_4; } else if(cib_is_master && config_changed) { log_level = LOG_INFO; } else if(cib_is_master) { log_level = LOG_DEBUG; log_xml_diff(LOG_DEBUG_2, filtered, "cib:diff:filtered"); } else if(config_changed) { log_level = LOG_DEBUG_2; } else { log_level = LOG_DEBUG_3; } log_xml_diff(log_level, *cib_diff, "cib:diff"); free_xml(filtered); done: if((call_options & cib_discard_reply) == 0) { *reply = cib_construct_reply(request, output, rc); + crm_log_xml_info(*reply, "cib:reply"); } if(call_type >= 0) { - cib_server_ops[call_type].cleanup(op, &input, &output); + cib_op_cleanup(call_type, op, &input, &output); } if(per_action_cib) { uninitializeCib(); } return rc; } int -send_via_callback_channel(HA_Message *msg, const char *token) +send_via_callback_channel(xmlNode *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_DISCONNECT) { crm_warn("Client %s has disconnected", token); rc = cib_client_gone; cib_num_timeouts++; } } /* 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; + xmlNode *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); + free_xml(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; } } return rc; } gint cib_GCompareFunc(gconstpointer a, gconstpointer b) { - const HA_Message *a_msg = a; - const HA_Message *b_msg = b; + const xmlNode *a_msg = a; + const xmlNode *b_msg = b; int msg_a_id = 0; int msg_b_id = 0; + const char *value = NULL; - ha_msg_value_int(a_msg, F_CIB_CALLID, &msg_a_id); - ha_msg_value_int(b_msg, F_CIB_CALLID, &msg_b_id); + value = crm_element_value_const(a_msg, F_CIB_CALLID); + msg_a_id = crm_parse_int(value, NULL); + + value = crm_element_value_const(b_msg, F_CIB_CALLID); + msg_b_id = crm_parse_int(value, NULL); 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) { int timeout = 0; /* 1 iteration == 10 seconds */ - HA_Message *msg = NULL; - HA_Message *reply = NULL; + xmlNode *msg = NULL; + xmlNode *reply = NULL; const char *host_to = NULL; cib_client_t *client = value; GListPtr list = client->delegated_calls; while(list != NULL) { msg = list->data; - ha_msg_value_int(msg, F_CIB_TIMEOUT, &timeout); + crm_element_value_int(msg, F_CIB_TIMEOUT, &timeout); if(timeout <= 0) { list = list->next; continue; } else { int seen = 0; - ha_msg_value_int(msg, F_CIB_SEENCOUNT, &seen); + crm_element_value_int(msg, F_CIB_SEENCOUNT, &seen); crm_debug_4("Timeout %d, seen %d", timeout, seen); if(seen < timeout) { crm_debug_4("Updating seen count for msg from client %s", client->id); seen += 10; - ha_msg_mod_int(msg, F_CIB_SEENCOUNT, seen); + crm_xml_add_int(msg, F_CIB_SEENCOUNT, seen); list = list->next; continue; } } cib_num_timeouts++; - host_to = cl_get_string(msg, F_CIB_HOST); + host_to = crm_element_value(msg, F_CIB_HOST); 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)); + reply = create_xml_node(NULL, "cib-reply"); + crm_xml_add(reply, F_TYPE, T_CIB); + crm_xml_add(reply, F_CIB_OPERATION, + crm_element_value(msg, F_CIB_OPERATION)); + crm_xml_add(reply, F_CIB_CALLID, + crm_element_value(msg, F_CIB_CALLID)); if(host_to == NULL) { - ha_msg_add_int(reply, F_CIB_RC, cib_master_timeout); + crm_xml_add_int(reply, F_CIB_RC, cib_master_timeout); } else { - ha_msg_add_int(reply, F_CIB_RC, cib_remote_timeout); + crm_xml_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); - crm_msg_del(reply); + free_xml(msg); + free_xml(reply); } } gboolean cib_process_disconnect(IPC_Channel *channel, cib_client_t *cib_client) { if (channel == NULL) { CRM_DEV_ASSERT(cib_client == NULL); } else if (cib_client == NULL) { crm_err("No client"); } else { CRM_DEV_ASSERT(channel->ch_status != IPC_CONNECT); crm_debug_2("Cleaning up after client disconnect: %s/%s/%s", crm_str(cib_client->name), cib_client->channel_name, cib_client->id); if(cib_client->id != NULL) { if(!g_hash_table_remove(client_list, cib_client->id)) { crm_err("Client %s not found in the hashtable", cib_client->name); } } } if(cib_shutdown_flag && g_hash_table_size(client_list) == 0) { crm_info("All clients disconnected..."); initiate_exit(); } return FALSE; } void -cib_peer_callback(HA_Message * msg, void* private_data) +cib_peer_callback(xmlNode * msg, void* private_data) { int call_type = 0; int call_options = 0; - const char *originator = cl_get_string(msg, F_ORIG); - const char *seq = cl_get_string(msg, F_SEQ); - const char *op = cl_get_string(msg, F_CIB_OPERATION); + const char *originator = crm_element_value(msg, F_ORIG); + const char *seq = crm_element_value(msg, F_SEQ); + const char *op = crm_element_value(msg, F_CIB_OPERATION); crm_node_t *node = NULL; - crm_log_message_adv(LOG_MSG, "Peer[inbound]", msg); + crm_log_xml(LOG_MSG, "Peer[inbound]", msg); crm_debug_2("Peer %s message (%s) from %s", op, seq, originator); if(originator == NULL || safe_str_eq(originator, cib_our_uname)) { crm_debug_2("Discarding %s message %s from ourselves", op, seq); return; } if(crm_peer_cache == NULL) { crm_info("Discarding %s message (%s) from %s:" " membership not established", op, seq, originator); return; } node = g_hash_table_lookup(crm_peer_cache, originator); if(node == NULL || crm_is_member_active(node) == FALSE) { crm_warn("Discarding %s message (%s) from %s:" " not in our membership", op, seq, originator); return; } if(cib_get_operation_id(op, &call_type) != cib_ok) { crm_debug("Discarding %s message (%s) from %s:" " Invalid operation", op, seq, originator); return; } crm_debug_2("Processing %s msg (%s) from %s",op, seq, originator); - ha_msg_value_int(msg, F_CIB_CALLOPTS, &call_options); + crm_element_value_int(msg, F_CIB_CALLOPTS, &call_options); crm_debug_4("Retrieved call options: %d", call_options); - if(cl_get_string(msg, F_CIB_CLIENTNAME) == NULL) { - ha_msg_add(msg, F_CIB_CLIENTNAME, originator); + if(crm_element_value(msg, F_CIB_CLIENTNAME) == NULL) { + crm_xml_add(msg, F_CIB_CLIENTNAME, originator); } cib_process_request(msg, FALSE, TRUE, TRUE, NULL); return; } void cib_client_status_callback(const char * node, const char * client, const char * status, void * private) { crm_node_t *member = NULL; if(safe_str_eq(client, CRM_SYSTEM_CIB)) { crm_info("Status update: Client %s/%s now has status [%s]", node, client, status); if(safe_str_eq(status, JOINSTATUS)){ status = ONLINESTATUS; } else if(safe_str_eq(status, LEAVESTATUS)){ status = OFFLINESTATUS; } member = g_hash_table_lookup(crm_peer_cache, node); if(member == NULL) { /* Make sure it gets created */ const char *uuid = get_uuid(node); member = crm_update_peer(0, 0, -1, 0, uuid, node, NULL, NULL); } crm_update_peer_proc(node, crm_proc_cib, status); set_connected_peers(the_cib); } return; } #if SUPPORT_HEARTBEAT extern oc_ev_t *cib_ev_token; gboolean cib_ccm_dispatch(int fd, gpointer user_data) { int rc = 0; oc_ev_t *ccm_token = (oc_ev_t*)user_data; crm_debug_2("received callback"); rc = oc_ev_handle_event(ccm_token); if(0 == rc) { return TRUE; } crm_err("CCM connection appears to have failed: rc=%d.", rc); /* eventually it might be nice to recover and reconnect... but until then... */ crm_err("Exiting to recover from CCM connection failure"); exit(2); return FALSE; } int current_instance = 0; void cib_ccm_msg_callback( oc_ed_t event, void *cookie, size_t size, const void *data) { gboolean update_id = FALSE; const oc_ev_membership_t *membership = data; CRM_ASSERT(membership != NULL); crm_info("Processing CCM event=%s (id=%d)", ccm_event_name(event), membership->m_instance); if(current_instance > membership->m_instance) { crm_err("Membership instance ID went backwards! %d->%d", current_instance, membership->m_instance); CRM_ASSERT(current_instance <= membership->m_instance); } switch(event) { case OC_EV_MS_NEW_MEMBERSHIP: case OC_EV_MS_INVALID: update_id = TRUE; break; case OC_EV_MS_PRIMARY_RESTORED: update_id = TRUE; break; case OC_EV_MS_NOT_PRIMARY: crm_debug_2("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)); break; default: crm_err("Unknown CCM event: %d", event); } if(update_id) { unsigned int lpc = 0; CRM_CHECK(membership != NULL, return); current_instance = membership->m_instance; for(lpc=0; lpc < membership->m_n_out; lpc++) { crm_update_ccm_node( membership, lpc+membership->m_out_idx, CRM_NODE_LOST); } for(lpc=0; lpc < membership->m_n_member; lpc++) { crm_update_ccm_node( membership, lpc+membership->m_memb_idx,CRM_NODE_ACTIVE); } } oc_ev_callback_done(cookie); set_connected_peers(the_cib); return; } #endif gboolean can_write(int flags) { return TRUE; } static gboolean cib_force_exit(gpointer data) { crm_notice("Forcing exit!"); terminate_cib(__FUNCTION__); return FALSE; } void initiate_exit(void) { int active = 0; - HA_Message *leaving = NULL; + xmlNode *leaving = NULL; active = crm_active_peers(crm_proc_cib); if(active < 2) { terminate_cib(__FUNCTION__); return; } crm_info("Sending disconnect notification to %d peers...", active); - leaving = ha_msg_new(3); - ha_msg_add(leaving, F_TYPE, "cib"); - ha_msg_add(leaving, F_CIB_OPERATION, "cib_shutdown_req"); + leaving = create_xml_node(NULL, "exit-notification"); + crm_xml_add(leaving, F_TYPE, "cib"); + crm_xml_add(leaving, F_CIB_OPERATION, "cib_shutdown_req"); send_cluster_message(NULL, crm_msg_cib, leaving, TRUE); - crm_msg_del(leaving); + free_xml(leaving); Gmain_timeout_add(crm_get_msec("5s"), cib_force_exit, NULL); } void terminate_cib(const char *caller) { #if SUPPORT_AIS if(is_openais_cluster()) { cib_ha_connection_destroy(NULL); return; } #endif #if SUPPORT_HEARTBEAT if(hb_conn != NULL) { crm_info("%s: Disconnecting heartbeat", caller); hb_conn->llc_ops->signoff(hb_conn, FALSE); } else { crm_err("%s: No heartbeat connection", caller); } #endif uninitializeCib(); crm_info("Exiting..."); if (mainloop != NULL && g_main_is_running(mainloop)) { g_main_quit(mainloop); } else { exit(LSB_EXIT_OK); } } diff --git a/cib/callbacks.h b/cib/callbacks.h index bde1e8b3bb..cde07f29dd 100644 --- a/cib/callbacks.h +++ b/cib/callbacks.h @@ -1,98 +1,98 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #if SUPPORT_HEARTBEAT # include # include #endif #include #include #include extern gboolean cib_is_master; extern GHashTable *client_list; extern GHashTable *peer_hash; typedef struct cib_client_s { char *id; char *name; char *callback_id; const char *channel_name; IPC_Channel *channel; GCHSource *source; unsigned long num_calls; int pre_notify; int post_notify; int confirmations; int replace; int diffs; GList *delegated_calls; } cib_client_t; typedef struct cib_operation_s { const char* operation; gboolean modifies_cib; gboolean needs_privileges; gboolean needs_quorum; - enum cib_errors (*prepare)(HA_Message *, crm_data_t**, const char **); - enum cib_errors (*cleanup)(const char *, crm_data_t**, crm_data_t**); + enum cib_errors (*prepare)(xmlNode *, xmlNode**, const char **); + enum cib_errors (*cleanup)(const char *, xmlNode**, xmlNode**); enum cib_errors (*fn)( - const char *, int, const char *, - crm_data_t*, crm_data_t*, crm_data_t**, crm_data_t**); + const char *, int, const char *, xmlNode *, + xmlNode*, xmlNode*, xmlNode**, xmlNode**); } cib_operation_t; extern gboolean cib_client_connect_null( IPC_Channel *channel, gpointer user_data); extern gboolean cib_client_connect_rw_ro( IPC_Channel *channel, gpointer user_data); extern gboolean cib_client_connect_rw_synch( IPC_Channel *channel, gpointer user_data); extern gboolean cib_client_connect_ro_synch( IPC_Channel *channel, gpointer user_data); extern gboolean cib_null_callback (IPC_Channel *channel, gpointer user_data); extern gboolean cib_rw_callback (IPC_Channel *channel, gpointer user_data); extern gboolean cib_ro_callback (IPC_Channel *channel, gpointer user_data); extern gboolean cib_rw_synchronous_callback( IPC_Channel *channel, gpointer user_data); extern gboolean cib_ro_synchronous_callback( IPC_Channel *channel, gpointer user_data); -extern void cib_peer_callback(HA_Message * msg, void* private_data); +extern void cib_peer_callback(xmlNode * msg, void* private_data); extern void cib_client_status_callback(const char * node, const char * client, const char * status, void * private); #if SUPPORT_HEARTBEAT extern gboolean cib_ccm_dispatch(int fd, gpointer user_data); extern void cib_ccm_msg_callback( oc_ed_t event, void *cookie, size_t size, const void *data); #endif diff --git a/cib/cibio.h b/cib/cibio.h index 1b526cc219..eefd50928d 100644 --- a/cib/cibio.h +++ b/cib/cibio.h @@ -1,61 +1,61 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 CIB_IO__H #define CIB_IO__H #include #include #include #include #include #include #include #include #include extern gboolean initialized; extern gboolean per_action_cib; -extern crm_data_t *the_cib; -extern crm_data_t *node_search; -extern crm_data_t *resource_search; -extern crm_data_t *constraint_search; -extern crm_data_t *status_search; +extern xmlNode *the_cib; +extern xmlNode *node_search; +extern xmlNode *resource_search; +extern xmlNode *constraint_search; +extern xmlNode *status_search; -extern crm_data_t *get_the_CIB(void); +extern xmlNode *get_the_CIB(void); -extern int initializeCib(crm_data_t *cib); +extern int initializeCib(xmlNode *cib); extern gboolean uninitializeCib(void); -extern crm_data_t *createEmptyCib(void); -extern gboolean verifyCibXml(crm_data_t *cib); -extern crm_data_t *readCibXml(char *buffer); -extern crm_data_t *readCibXmlFile( +extern xmlNode *createEmptyCib(void); +extern gboolean verifyCibXml(xmlNode *cib); +extern xmlNode *readCibXml(char *buffer); +extern xmlNode *readCibXmlFile( const char *dir, const char *file, gboolean discard_status); extern int activateCibBuffer(char *buffer, const char *filename); -extern int activateCibXml(crm_data_t *doc, gboolean to_disk); +extern int activateCibXml(xmlNode *doc, gboolean to_disk); -extern gboolean update_quorum(crm_data_t *xml_obj); -extern gboolean set_connected_peers(crm_data_t *xml_obj); +extern gboolean update_quorum(xmlNode *xml_obj); +extern gboolean set_connected_peers(xmlNode *xml_obj); extern gboolean update_counters( - const char *file, const char *fn, crm_data_t *xml_obj); + const char *file, const char *fn, xmlNode *xml_obj); -/* extern crm_data_t *server_get_cib_copy(void); */ +/* extern xmlNode *server_get_cib_copy(void); */ #endif diff --git a/cib/cibmessages.h b/cib/cibmessages.h index b9290692ff..ddbd60ef54 100644 --- a/cib/cibmessages.h +++ b/cib/cibmessages.h @@ -1,87 +1,87 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 CIB_MESSAGES__H #define CIB_MESSAGES__H -extern crm_data_t *createCibRequest( +extern xmlNode *createCibRequest( gboolean isLocal, const char *operation, const char *section, - const char *verbose, crm_data_t *data); + const char *verbose, xmlNode *data); extern enum cib_errors cib_process_shutdown_req( - 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); + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); extern 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); + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); extern 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); + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); extern 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); + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); extern 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); + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); extern 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); + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); extern 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); + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); extern 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); + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); extern 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); + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); extern 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); + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); extern 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); + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); extern 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); + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); extern 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); + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); extern 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); + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); extern enum cib_errors cib_process_change( - 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); + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); #endif diff --git a/cib/cibmon.c b/cib/cibmon.c index 9f09628052..f90a62b12e 100644 --- a/cib/cibmon.c +++ b/cib/cibmon.c @@ -1,466 +1,466 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_GETOPT_H # include #endif #include /* someone complaining about _ha_msg_mod not being found */ #define UPDATE_PREFIX "cib.updates:" int exit_code = cib_ok; int got_signal = 0; GMainLoop *mainloop = NULL; 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); +void cibmon_pre_notify(const char *event, xmlNode *msg); +void cibmon_update_confirm(const char *event, xmlNode *msg); gboolean cibmon_shutdown(int nsig, gpointer unused); -void cibmon_diff(const char *event, HA_Message *msg); +void cibmon_diff(const char *event, xmlNode *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("cibmon", LOG_INFO, FALSE, FALSE, 0, NULL); G_main_add_SignalHandler( G_PRIORITY_HIGH, SIGTERM, cibmon_shutdown, NULL, NULL); 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_parse_int(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) \tid of the object being operated on\n", XML_ATTR_ID, 'i'); fprintf(stream, "\t--%s (-%c) \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) \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) +cibmon_pre_notify(const char *event, xmlNode *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; + xmlNode *update = NULL; + xmlNode *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); + op = crm_element_value(msg, F_CIB_OPERATION); + id = crm_element_value(msg, F_CIB_OBJID); + type = crm_element_value(msg, F_CIB_OBJTYPE); - ha_msg_value_int(msg, F_CIB_RC, &rc); + crm_element_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) +cibmon_update_confirm(const char *event, xmlNode *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; + xmlNode *update = NULL; + xmlNode *output = NULL; + xmlNode *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); + op = crm_element_value(msg, F_CIB_OPERATION); + id = crm_element_value(msg, F_CIB_OBJID); + type = crm_element_value(msg, F_CIB_OBJTYPE); update_depth--; last_notify_pre = FALSE; - ha_msg_value_int(msg, F_CIB_RC, &rc); + crm_element_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) +cibmon_diff(const char *event, xmlNode *msg) { int rc = -1; const char *op = NULL; - crm_data_t *diff = NULL; - crm_data_t *update = get_message_xml(msg, F_CIB_UPDATE); + xmlNode *diff = NULL; + xmlNode *update = get_message_xml(msg, F_CIB_UPDATE); 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); + crm_element_value_int(msg, F_CIB_RC, &rc); + op = crm_element_value(msg, F_CIB_OPERATION); diff = get_message_xml(msg, F_CIB_UPDATE_RESULT); if(rc < cib_ok) { log_level = LOG_WARNING; do_crm_log(log_level, "[%s] %s ABORTED: %s", event, op, cib_error2string(rc)); } else { do_crm_log(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/cib/cibpipe.c b/cib/cibpipe.c index 1797a1ac40..20cc0f9de3 100644 --- a/cib/cibpipe.c +++ b/cib/cibpipe.c @@ -1,333 +1,333 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include "common.h" #ifdef HAVE_GETOPT_H # include #endif void usage(const char* cmd, int exit_status); #define OPTARGS "V?o:QDUCEX:t:MBfRx:P5S" int main(int argc, char ** argv) { int flag; int rc = 0; int argerr = 0; int command_options = 0; gboolean changed = FALSE; gboolean force_flag = FALSE; gboolean dangerous_cmd = FALSE; char *buffer = NULL; const char *section = NULL; const char *input_xml = NULL; const char *input_file = NULL; const char *output_file = NULL; const char *cib_action = NULL; - crm_data_t *input = NULL; - crm_data_t *output = NULL; - crm_data_t *result_cib = NULL; - crm_data_t *current_cib = NULL; + xmlNode *input = NULL; + xmlNode *output = NULL; + xmlNode *result_cib = NULL; + xmlNode *current_cib = NULL; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { {CIB_OP_ERASE, 0, 0, 'E'}, {CIB_OP_QUERY, 0, 0, 'Q'}, {CIB_OP_CREATE, 0, 0, 'C'}, {CIB_OP_REPLACE, 0, 0, 'R'}, {CIB_OP_UPDATE, 0, 0, 'U'}, {CIB_OP_MODIFY, 0, 0, 'M'}, {"patch", 0, 0, 'P'}, {CIB_OP_DELETE, 0, 0, 'D'}, {CIB_OP_BUMP, 0, 0, 'B'}, {"md5-sum", 0, 0, '5'}, {"force", 0, 0, 'f'}, {"xml-file", 1, 0, 'x'}, {"xml-text", 1, 0, 'X'}, {"xml-save", 1, 0, 'S'}, {"obj_type", 1, 0, 'o'}, {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {0, 0, 0, 0} }; #endif crm_log_init("cibpipe", LOG_ERR, FALSE, FALSE, argc, argv); 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) { case 'E': cib_action = CIB_OP_ERASE; dangerous_cmd = TRUE; break; case 'Q': cib_action = CIB_OP_QUERY; break; case 'P': cib_action = CIB_OP_APPLY_DIFF; break; case 'S': cib_action = CIB_OP_SYNC; break; case 'U': case 'M': cib_action = CIB_OP_MODIFY; break; case 'R': cib_action = CIB_OP_REPLACE; break; case 'C': cib_action = CIB_OP_CREATE; break; case 'D': cib_action = CIB_OP_DELETE; break; case '5': cib_action = "md5-sum"; break; case 'd': cib_action = CIB_OP_DELETE_ALT; break; case 'm': cib_action = CIB_OP_ISMASTER; command_options |= cib_scope_local; break; case 'B': cib_action = CIB_OP_BUMP; break; case 'o': crm_debug_2("Option %c => %s", flag, optarg); section = crm_strdup(optarg); break; case 'x': crm_debug_2("Option %c => %s", flag, optarg); input_file = crm_strdup(optarg); break; case 'X': crm_debug_2("Option %c => %s", flag, optarg); input_xml = crm_strdup(optarg); break; case 'f': force_flag = TRUE; command_options |= cib_quorum_override; break; case 'V': alter_debug(DEBUG_INC); cl_log_enable_stderr(1); break; case '?': /* Help message */ usage(crm_system_name, LSB_EXIT_OK); break; default: ++argerr; break; } } if (cib_action == NULL) { ++argerr; } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } if(dangerous_cmd && force_flag == FALSE) { fprintf(stderr, "The supplied command is considered dangerous." " To prevent accidental destruction of the cluster," " the --force flag is required in order to proceed.\n"); fflush(stderr); usage(crm_system_name, LSB_EXIT_GENERIC); } if(input_file != NULL) { FILE *xml_strm = fopen(input_file, "r"); input = file2xml(xml_strm, FALSE); if(input == NULL) { fprintf(stderr, "Couldn't parse input file: %s\n", input_file); return 1; } fclose(xml_strm); } else if(input_xml != NULL) { input = string2xml(input_xml); if(input == NULL) { fprintf(stderr, "Couldn't parse input string: %s\n", input_xml); return 1; } } if(input && safe_str_eq(cib_action, CIB_OP_QUERY)) { current_cib = copy_xml(input); } else { current_cib = stdin2xml(); if(current_cib == NULL && safe_str_neq(cib_action, CIB_OP_ERASE)) { fprintf(stderr, "Couldn't parse existing CIB from STDIN.\n"); return 1; } } if(current_cib == NULL) { current_cib = createEmptyCib(); } result_cib = copy_xml(current_cib); if(safe_str_eq(cib_action, "md5-sum")) { char *digest = NULL; digest = calculate_xml_digest(current_cib, FALSE, FALSE); fprintf(stdout, "%s\n", crm_str(digest)); crm_free(digest); return 0; } /* read local config file */ rc = cib_perform_op( - cib_action, command_options, section, input, TRUE, &changed, + cib_action, command_options, section, NULL, input, TRUE, &changed, current_cib, &result_cib, &output); if(rc != cib_ok) { fprintf(stderr, "Call failed: %s\n", cib_error2string(rc)); fprintf(stdout, "%c", 0); return -rc; } cl_log_args(argc, argv); if(output) { buffer = dump_xml_formatted(output); } else { buffer = dump_xml_formatted(result_cib); } fprintf(stdout, "%s\n", buffer); fflush(stdout); if(output_file != NULL) { FILE *output_strm = fopen(output_file, "w"); if(output_strm == NULL) { cl_perror("Could not open %s for writing", output_file); } else { if(fprintf(output_strm, "%s\n", buffer) < 0) { cl_perror("Write to %s failed", output_file); } fflush(output_strm); fclose(output_strm); } } crm_info("Done"); return 0; } void usage(const char* cmd, int exit_status) { FILE* stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s -Q -(x|X)\n", cmd); fprintf(stream, "usage: %s -Q -(x|X) | %s [-%s] | %s [-%s] | ...\n", cmd, cmd, OPTARGS, cmd, OPTARGS); fprintf(stream, "usage: cibadmin -Q | %s [-%s] | %s [-%s] | ...\n", cmd, OPTARGS, cmd, OPTARGS); fprintf(stream, "\nOptions\n"); fprintf(stream, "\t--%s (-%c) \tobject type being operated on\n", "obj_type", 'o'); fprintf(stream, "\t\tValid values are:" " nodes, resources, constraints, crm_config, status\n"); 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)\tErase the contents of the whole CIB\n", CIB_OP_ERASE, 'E'); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_QUERY, 'Q'); fprintf(stream, "\t--%s (-%c)\tCreate an object that does not yet exist\n", CIB_OP_CREATE, 'C'); fprintf(stream, "\t--%s (-%c)\tRecursivly update an object in the CIB\n", CIB_OP_UPDATE, 'U'); fprintf(stream, "\t--%s (-%c)\tFind the object somewhere in the CIB's XML tree and update it as --"CIB_OP_UPDATE" would\n", CIB_OP_MODIFY, 'M'); fprintf(stream, "\t--%s (-%c)\tRecursivly replace an object in the CIB\n", CIB_OP_REPLACE,'R'); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_DELETE, 'D'); fprintf(stream, "\t\t\tDelete the first object matching the supplied criteria\n"); fprintf(stream, "\t\t\tEg. \n"); fprintf(stream, "\t\t\tThe tagname and all attributes must match in order for the element to be deleted\n"); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_BUMP, 'B'); fprintf(stream, "\t--%s (-%c)\t\tCalculate the configuration's digest.\n", "md5-sum", '5'); fprintf(stream, "\nXML data\n"); fprintf(stream, "\t--%s (-%c) \tRetrieve XML from the named file\n", "xml-file", 'x'); fprintf(stream, "\t--%s (-%c) \tRetrieve XML from the supplied string\n", "xml-text", 'X'); fprintf(stream, "\t--%s (-%c) \tSave the XML output to the named file\n", "xml-save", 'S'); fprintf(stream, "\nNOTE: The current CIB is assumed to be passed in via stdin," " unless -Q is used in which case -x or -X are also acceptable\n"); fflush(stream); exit(exit_status); } diff --git a/cib/cibprimatives.h b/cib/cibprimatives.h index 1c20f23034..dc4499912f 100644 --- a/cib/cibprimatives.h +++ b/cib/cibprimatives.h @@ -1,77 +1,77 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 CIB_PRIMATIVES__H #define CIB_PRIMATIVES__H #include #include #include #include #include #include #include #include #include #define IS_DAEMON #define IPC_COMMS -typedef crm_data_t cibStatus; -typedef crm_data_t cibResource; -typedef crm_data_t cibConstraint; -typedef crm_data_t cibHaNode; +typedef xmlNode cibStatus; +typedef xmlNode cibResource; +typedef xmlNode cibConstraint; +typedef xmlNode cibHaNode; /* extern gboolean initialized; */ -/* extern crm_data_t *the_cib; */ -/* extern crm_data_t *node_search; */ -/* extern crm_data_t *resource_search; */ -/* extern crm_data_t *constraint_search; */ -/* extern crm_data_t *status_search; */ +/* extern xmlNode *the_cib; */ +/* extern xmlNode *node_search; */ +/* extern xmlNode *resource_search; */ +/* extern xmlNode *constraint_search; */ +/* extern xmlNode *status_search; */ /* extern const char* crm_system_name; */ -extern crm_data_t *get_the_CIB(void); +extern xmlNode *get_the_CIB(void); -extern int addResource (crm_data_t *cib, crm_data_t *anXmlNode); -extern int addConstraint(crm_data_t *cib, crm_data_t *anXmlNode); -extern int addHaNode (crm_data_t *cib, crm_data_t *anXmlNode); -extern int addStatus (crm_data_t *cib, crm_data_t *anXmlNode); +extern int addResource (xmlNode *cib, xmlNode *anXmlNode); +extern int addConstraint(xmlNode *cib, xmlNode *anXmlNode); +extern int addHaNode (xmlNode *cib, xmlNode *anXmlNode); +extern int addStatus (xmlNode *cib, xmlNode *anXmlNode); -extern crm_data_t *findResource (crm_data_t *cib, const char *id); -extern crm_data_t *findConstraint(crm_data_t *cib, const char *id); -extern crm_data_t *findHaNode (crm_data_t *cib, const char *id); -extern crm_data_t *findStatus (crm_data_t *cib, const char *id); +extern xmlNode *findResource (xmlNode *cib, const char *id); +extern xmlNode *findConstraint(xmlNode *cib, const char *id); +extern xmlNode *findHaNode (xmlNode *cib, const char *id); +extern xmlNode *findStatus (xmlNode *cib, const char *id); -extern int updateResource (crm_data_t *cib, crm_data_t *anXmlNode); -extern int updateConstraint(crm_data_t *cib, crm_data_t *anXmlNode); -extern int updateHaNode (crm_data_t *cib, crm_data_t *anXmlNode); -extern int updateStatus (crm_data_t *cib, crm_data_t *anXmlNode); +extern int updateResource (xmlNode *cib, xmlNode *anXmlNode); +extern int updateConstraint(xmlNode *cib, xmlNode *anXmlNode); +extern int updateHaNode (xmlNode *cib, xmlNode *anXmlNode); +extern int updateStatus (xmlNode *cib, xmlNode *anXmlNode); -extern int delResource (crm_data_t *cib, crm_data_t *delete_spec); -extern int delConstraint(crm_data_t *cib, crm_data_t *delete_spec); -extern int delHaNode (crm_data_t *cib, crm_data_t *delete_spec); -extern int delStatus (crm_data_t *cib, crm_data_t *delete_spec); +extern int delResource (xmlNode *cib, xmlNode *delete_spec); +extern int delConstraint(xmlNode *cib, xmlNode *delete_spec); +extern int delHaNode (xmlNode *cib, xmlNode *delete_spec); +extern int delStatus (xmlNode *cib, xmlNode *delete_spec); -extern int add_cib_object (crm_data_t *parent, crm_data_t *new_obj); -extern int delete_cib_object(crm_data_t *parent, crm_data_t *delete_spec); -extern int update_cib_object(crm_data_t *parent, crm_data_t *new_obj); +extern int add_cib_object (xmlNode *parent, xmlNode *new_obj); +extern int delete_cib_object(xmlNode *parent, xmlNode *delete_spec); +extern int update_cib_object(xmlNode *parent, xmlNode *new_obj); #endif diff --git a/cib/common.c b/cib/common.c index b9ea7773b6..e8ec25a857 100644 --- a/cib/common.c +++ b/cib/common.c @@ -1,396 +1,443 @@ /* * Copyright (C) 2008 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common.h" extern gboolean cib_is_master; extern const char* cib_root; -extern gboolean stand_alone; +gboolean stand_alone = FALSE; extern enum cib_errors cib_status; extern gboolean can_write(int flags); extern enum cib_errors cib_perform_command( - HA_Message *request, HA_Message **reply, crm_data_t **cib_diff, gboolean privileged); + xmlNode *request, xmlNode **reply, xmlNode **cib_diff, gboolean privileged); -static HA_Message * -cib_prepare_common(HA_Message *root, const char *section) +static xmlNode * +cib_prepare_common(xmlNode *root, const char *section) { - HA_Message *data = NULL; + xmlNode *data = NULL; /* extract the CIB from the fragment */ if(root == NULL) { return NULL; } else if(safe_str_eq(crm_element_name(root), XML_TAG_FRAGMENT) || safe_str_eq(crm_element_name(root), F_CIB_CALLDATA)) { data = find_xml_node(root, XML_TAG_CIB, TRUE); if(data != NULL) { crm_debug_3("Extracted CIB from %s", TYPE(root)); } else { crm_log_xml_debug_4(root, "No CIB"); } } else { data = root; } /* grab the section specified for the command */ if(section != NULL && data != NULL && safe_str_eq(crm_element_name(data), XML_TAG_CIB)){ int rc = revision_check(data, the_cib, 0/* call_options */); if(rc == cib_ok) { data = get_object_root(section, data); if(data != NULL) { crm_debug_3("Extracted %s from CIB", section); } else { crm_log_xml_debug_4(root, "No Section"); } } else { crm_debug_2("Revision check failed"); } } crm_log_xml_debug_4(root, "cib:input"); return copy_xml(data); } static gboolean verify_section(const char *section) { if(section == NULL) { return TRUE; } else if(safe_str_eq(section, XML_TAG_CIB)) { return TRUE; } else if(safe_str_eq(section, XML_CIB_TAG_STATUS)) { return TRUE; } else if(safe_str_eq(section, XML_CIB_TAG_CRMCONFIG)) { return TRUE; } else if(safe_str_eq(section, XML_CIB_TAG_NODES)) { return TRUE; } else if(safe_str_eq(section, XML_CIB_TAG_RESOURCES)) { return TRUE; } else if(safe_str_eq(section, XML_CIB_TAG_CONSTRAINTS)) { return TRUE; } return FALSE; } static enum cib_errors -cib_prepare_none(HA_Message *request, HA_Message **data, const char **section) +cib_prepare_none(xmlNode *request, xmlNode **data, const char **section) { *data = NULL; - *section = cl_get_string(request, F_CIB_SECTION); + *section = crm_element_value(request, F_CIB_SECTION); if(verify_section(*section) == FALSE) { return cib_bad_section; } return cib_ok; } static enum cib_errors -cib_prepare_data(HA_Message *request, HA_Message **data, const char **section) +cib_prepare_data(xmlNode *request, xmlNode **data, const char **section) { - HA_Message *input_fragment = get_message_xml(request, F_CIB_CALLDATA); - *section = cl_get_string(request, F_CIB_SECTION); + xmlNode *input_fragment = get_message_xml(request, F_CIB_CALLDATA); + *section = crm_element_value(request, F_CIB_SECTION); *data = cib_prepare_common(input_fragment, *section); + crm_log_xml_debug(*data, "data"); free_xml(input_fragment); if(verify_section(*section) == FALSE) { return cib_bad_section; } return cib_ok; } static enum cib_errors -cib_prepare_sync(HA_Message *request, HA_Message **data, const char **section) +cib_prepare_sync(xmlNode *request, xmlNode **data, const char **section) { - *section = cl_get_string(request, F_CIB_SECTION); - *data = request; + *section = crm_element_value(request, F_CIB_SECTION); + *data = NULL; if(verify_section(*section) == FALSE) { return cib_bad_section; } return cib_ok; } static enum cib_errors -cib_prepare_diff(HA_Message *request, HA_Message **data, const char **section) +cib_prepare_diff(xmlNode *request, xmlNode **data, const char **section) { - HA_Message *input_fragment = NULL; - const char *update = cl_get_string(request, F_CIB_GLOBAL_UPDATE); + xmlNode *input_fragment = NULL; + const char *update = crm_element_value(request, F_CIB_GLOBAL_UPDATE); *data = NULL; *section = NULL; if(crm_is_true(update)) { input_fragment = get_message_xml(request,F_CIB_UPDATE_DIFF); } else { input_fragment = get_message_xml(request, F_CIB_CALLDATA); } - CRM_CHECK(input_fragment != NULL,crm_log_message(LOG_WARNING, request)); + CRM_CHECK(input_fragment != NULL,crm_log_xml(LOG_WARNING, "no input", request)); *data = cib_prepare_common(input_fragment, NULL); free_xml(input_fragment); return cib_ok; } static enum cib_errors -cib_cleanup_query(const char *op, HA_Message **data, HA_Message **output) +cib_cleanup_query(const char *op, xmlNode **data, xmlNode **output) { CRM_DEV_ASSERT(*data == NULL); return cib_ok; } static enum cib_errors -cib_cleanup_data(const char *op, HA_Message **data, HA_Message **output) +cib_cleanup_data(const char *op, xmlNode **data, xmlNode **output) { free_xml(*output); free_xml(*data); return cib_ok; } static enum cib_errors -cib_cleanup_output(const char *op, HA_Message **data, HA_Message **output) +cib_cleanup_output(const char *op, xmlNode **data, xmlNode **output) { free_xml(*output); return cib_ok; } static enum cib_errors -cib_cleanup_none(const char *op, HA_Message **data, HA_Message **output) +cib_cleanup_none(const char *op, xmlNode **data, xmlNode **output) { CRM_DEV_ASSERT(*data == NULL); CRM_DEV_ASSERT(*output == NULL); return cib_ok; } static enum cib_errors -cib_cleanup_sync(const char *op, HA_Message **data, HA_Message **output) +cib_cleanup_sync(const char *op, xmlNode **data, xmlNode **output) { /* data is non-NULL but doesnt need to be free'd */ + CRM_DEV_ASSERT(*data == NULL); CRM_DEV_ASSERT(*output == NULL); return cib_ok; } /* typedef struct cib_operation_s { const char* operation; gboolean modifies_cib; gboolean needs_privileges; gboolean needs_quorum; - enum cib_errors (*prepare)(HA_Message *, crm_data_t**, const char **); - enum cib_errors (*cleanup)(crm_data_t**, crm_data_t**); + enum cib_errors (*prepare)(xmlNode *, xmlNode**, const char **); + enum cib_errors (*cleanup)(xmlNode**, xmlNode**); enum cib_errors (*fn)( const char *, int, const char *, - crm_data_t*, crm_data_t*, crm_data_t**, crm_data_t**); + xmlNode*, xmlNode*, xmlNode**, xmlNode**); } cib_operation_t; */ /* technically bump does modify the cib... * but we want to split the "bump" from the "sync" */ static cib_operation_t cib_server_ops[] = { {NULL, FALSE, FALSE, FALSE, cib_prepare_none, cib_cleanup_none, cib_process_default}, {CIB_OP_QUERY, FALSE, FALSE, FALSE, cib_prepare_none, cib_cleanup_query, cib_process_query}, {CIB_OP_MODIFY, TRUE, TRUE, TRUE, cib_prepare_data, cib_cleanup_data, cib_process_modify}, {CIB_OP_UPDATE, TRUE, TRUE, TRUE, cib_prepare_data, cib_cleanup_data, cib_process_change}, {CIB_OP_APPLY_DIFF,TRUE, TRUE, TRUE, cib_prepare_diff, cib_cleanup_data, cib_process_diff}, {CIB_OP_SLAVE, FALSE, TRUE, FALSE, cib_prepare_none, cib_cleanup_none, cib_process_readwrite}, {CIB_OP_SLAVEALL, FALSE, TRUE, FALSE, cib_prepare_none, cib_cleanup_none, cib_process_readwrite}, {CIB_OP_SYNC_ONE, FALSE, TRUE, FALSE, cib_prepare_sync, cib_cleanup_sync, cib_process_sync_one}, {CIB_OP_MASTER, FALSE, TRUE, FALSE, cib_prepare_none, cib_cleanup_none, cib_process_readwrite}, {CIB_OP_ISMASTER, FALSE, TRUE, FALSE, cib_prepare_none, cib_cleanup_none, cib_process_readwrite}, {CIB_OP_BUMP, TRUE, TRUE, TRUE, cib_prepare_none, cib_cleanup_output, cib_process_bump}, {CIB_OP_REPLACE, TRUE, TRUE, TRUE, cib_prepare_data, cib_cleanup_data, cib_process_replace}, {CIB_OP_CREATE, TRUE, TRUE, TRUE, cib_prepare_data, cib_cleanup_data, cib_process_change}, {CIB_OP_DELETE, TRUE, TRUE, TRUE, cib_prepare_data, cib_cleanup_data, cib_process_delete}, {CIB_OP_DELETE_ALT,TRUE, TRUE, TRUE, cib_prepare_data, cib_cleanup_data, cib_process_change}, {CIB_OP_SYNC, FALSE, TRUE, FALSE, cib_prepare_sync, cib_cleanup_sync, cib_process_sync}, {CRM_OP_QUIT, FALSE, TRUE, FALSE, cib_prepare_none, cib_cleanup_none, cib_process_quit}, {CRM_OP_PING, FALSE, FALSE, FALSE, cib_prepare_none, cib_cleanup_output, cib_process_ping}, {CIB_OP_ERASE, TRUE, TRUE, TRUE, cib_prepare_none, cib_cleanup_output, cib_process_erase}, {CRM_OP_NOOP, FALSE, FALSE, FALSE, cib_prepare_none, cib_cleanup_none, cib_process_default}, {"cib_shutdown_req",FALSE, TRUE, FALSE, cib_prepare_sync, cib_cleanup_sync, cib_process_shutdown_req}, }; enum cib_errors cib_get_operation_id(const char *op, int *operation) { int lpc = 0; int max_msg_types = DIMOF(cib_server_ops); 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; } -HA_Message * -cib_msg_copy(HA_Message *msg, gboolean with_data) +xmlNode * +cib_msg_copy(xmlNode *msg, gboolean with_data) { int lpc = 0; const char *field = NULL; const char *value = NULL; - HA_Message *value_struct = NULL; + xmlNode *value_struct = NULL; static const char *field_list[] = { F_XML_TAGNAME , 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 }; static const char *data_list[] = { F_CIB_CALLDATA , F_CIB_UPDATE , F_CIB_UPDATE_RESULT }; - HA_Message *copy = ha_msg_new(10); + xmlNode *copy = create_xml_node(NULL, "copy"); CRM_ASSERT(copy != NULL); for(lpc = 0; lpc < DIMOF(field_list); lpc++) { field = field_list[lpc]; - value = cl_get_string(msg, field); + value = crm_element_value(msg, field); if(value != NULL) { - ha_msg_add(copy, field, value); + crm_xml_add(copy, field, value); } } for(lpc = 0; with_data && lpc < DIMOF(data_list); lpc++) { field = data_list[lpc]; value_struct = get_message_xml(msg, field); if(value_struct != NULL) { add_message_xml(copy, field, value_struct); } free_xml(value_struct); } return copy; } enum cib_errors cib_perform_op( - const char *op, int call_options, const char *section, crm_data_t *input, + const char *op, int call_options, const char *section, xmlNode *req, xmlNode *input, gboolean manage_counters, gboolean *config_changed, - crm_data_t *current_cib, crm_data_t **result_cib, crm_data_t **output) + xmlNode *current_cib, xmlNode **result_cib, xmlNode **output) { int rc = cib_ok; int call_type = 0; - crm_data_t *scratch = NULL; + xmlNode *scratch = NULL; CRM_CHECK(output != NULL && result_cib != NULL && config_changed != NULL, return cib_output_data); *output = NULL; *result_cib = NULL; rc = cib_get_operation_id(op, &call_type); *config_changed = FALSE; if(rc != cib_ok) { return rc; } if(cib_server_ops[call_type].modifies_cib == FALSE) { - return cib_server_ops[call_type].fn( - op, call_options, section, input, current_cib, result_cib, output); + rc = cib_server_ops[call_type].fn( + op, call_options, section, req, input, current_cib, result_cib, output); + /* FIXME: Free scratch */ + return rc; } scratch = copy_xml(current_cib); rc = cib_server_ops[call_type].fn( - op, call_options, section, input, current_cib, &scratch, output); + op, call_options, section, req, input, current_cib, &scratch, output); + crm_log_xml_debug(*output, "output"); + CRM_CHECK(current_cib != scratch, return cib_unknown); if(rc == cib_ok) { CRM_CHECK(scratch != NULL, return cib_unknown); if(do_id_check(scratch, NULL, TRUE, FALSE)) { rc = cib_id_check; if(call_options & cib_force_diff) { crm_err("Global update introduces id collision!"); } } if(rc == cib_ok) { fix_plus_plus_recursive(scratch); *config_changed = cib_config_changed(current_cib, scratch, NULL); if(manage_counters && *config_changed) { cib_update_counter(scratch, XML_ATTR_NUMUPDATES, TRUE); cib_update_counter(scratch, XML_ATTR_GENERATION, FALSE); } else if(manage_counters) { cib_update_counter(scratch, XML_ATTR_NUMUPDATES, FALSE); } } } *result_cib = scratch; return rc; } + +gboolean cib_op_modifies(int call_type) +{ + return cib_server_ops[call_type].modifies_cib; +} + +int cib_op_can_run( + int call_type, int call_options, gboolean privileged, gboolean global_update) +{ + int rc = cib_ok; + + if(rc == cib_ok && + cib_server_ops[call_type].needs_privileges + && privileged == FALSE) { + /* abort */ + return cib_not_authorized; + } + + if(rc == cib_ok + && stand_alone == FALSE + && global_update == FALSE + && (call_options & cib_quorum_override) == 0 + && cib_server_ops[call_type].needs_quorum) { + return cib_no_quorum; + } + return cib_ok; +} + + +int cib_op_prepare( + int call_type, xmlNode *request, xmlNode **input, const char **section) +{ + return cib_server_ops[call_type].prepare(request, input, section); +} + +int cib_op_cleanup( + int call_type, const char *op, xmlNode **input, xmlNode **output) +{ + return cib_server_ops[call_type].cleanup(op, input, output); +} + diff --git a/cib/common.h b/cib/common.h index cd8e5acd7f..67b656b022 100644 --- a/cib/common.h +++ b/cib/common.h @@ -1,30 +1,39 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 */ -extern HA_Message *cib_msg_copy(HA_Message *msg, gboolean with_data); -extern HA_Message *cib_construct_reply(HA_Message *request, HA_Message *output, int rc); -extern enum cib_errors revision_check(crm_data_t *cib_update, crm_data_t *cib_copy, int flags); +extern xmlNode *cib_msg_copy(xmlNode *msg, gboolean with_data); +extern xmlNode *cib_construct_reply(xmlNode *request, xmlNode *output, int rc); +extern enum cib_errors revision_check(xmlNode *cib_update, xmlNode *cib_copy, int flags); extern enum cib_errors cib_get_operation_id(const char *op, int *operation); extern enum cib_errors cib_perform_op( - const char *op, int call_options, const char *section, crm_data_t *input, + const char *op, int call_options, const char *section, xmlNode *req, xmlNode *input, gboolean manage_counters, gboolean *config_changed, - crm_data_t *current_cib, crm_data_t **result_cib, crm_data_t **output); + xmlNode *current_cib, xmlNode **result_cib, xmlNode **output); extern enum cib_errors cib_update_counter( - crm_data_t *xml_obj, const char *field, gboolean reset); + xmlNode *xml_obj, const char *field, gboolean reset); + +extern gboolean cib_op_modifies(int call_type); +extern int cib_op_prepare( + int call_type, xmlNode *request, xmlNode **input, const char **section); +extern int cib_op_cleanup( + int call_type, const char *op, xmlNode **input, xmlNode **output); +extern int cib_op_can_run( + int call_type, int call_options, gboolean privileged, gboolean global_update); + diff --git a/cib/io.c b/cib/io.c index f8374d7c23..8c4d20fe08 100644 --- a/cib/io.c +++ b/cib/io.c @@ -1,840 +1,840 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int archive_file(const char *oldname, const char *newname, const char *ext, gboolean preserve); const char * local_resource_path[] = { XML_CIB_TAG_STATUS, }; const char * resource_path[] = { XML_CIB_TAG_RESOURCES, }; const char * node_path[] = { XML_CIB_TAG_NODES, }; const char * constraint_path[] = { XML_CIB_TAG_CONSTRAINTS, }; gboolean initialized = FALSE; -crm_data_t *node_search = NULL; -crm_data_t *resource_search = NULL; -crm_data_t *constraint_search = NULL; -crm_data_t *status_search = NULL; +xmlNode *node_search = NULL; +xmlNode *resource_search = NULL; +xmlNode *constraint_search = NULL; +xmlNode *status_search = NULL; extern gboolean cib_writes_enabled; extern GTRIGSource *cib_writer; extern enum cib_errors cib_status; -int set_connected_peers(crm_data_t *xml_obj); +int set_connected_peers(xmlNode *xml_obj); void GHFunc_count_peers(gpointer key, gpointer value, gpointer user_data); int write_cib_contents(gpointer p); extern void cib_cleanup(void); static gboolean -validate_cib_digest(crm_data_t *local_cib, const char *sigfile) +validate_cib_digest(xmlNode *local_cib, const char *sigfile) { int s_res = -1; struct stat buf; char *digest = NULL; char *expected = NULL; gboolean passed = FALSE; FILE *expected_strm = NULL; int start = 0, length = 0, read_len = 0; CRM_ASSERT(sigfile != NULL); s_res = stat(sigfile, &buf); if (s_res != 0) { crm_warn("No on-disk digest present"); return TRUE; } if(local_cib != NULL) { digest = calculate_xml_digest(local_cib, FALSE, FALSE); } expected_strm = fopen(sigfile, "r"); if(expected_strm == NULL) { cl_perror("Could not open signature file %s for reading", sigfile); goto bail; } start = ftell(expected_strm); fseek(expected_strm, 0L, SEEK_END); length = ftell(expected_strm); fseek(expected_strm, 0L, start); CRM_ASSERT(start == ftell(expected_strm)); crm_debug_3("Reading %d bytes from file", length); crm_malloc0(expected, (length+1)); read_len = fread(expected, 1, length, expected_strm); CRM_ASSERT(read_len == length); fclose(expected_strm); bail: if(expected == NULL) { crm_err("On-disk digest is empty"); } else if(safe_str_eq(expected, digest)) { crm_debug_2("Digest comparision passed: %s", digest); passed = TRUE; } else { crm_err("Digest comparision failed: expected %s (%s), calculated %s", expected, sigfile, digest); } crm_free(digest); crm_free(expected); return passed; } static int -write_cib_digest(crm_data_t *local_cib, char *digest) +write_cib_digest(xmlNode *local_cib, char *digest) { int rc = 0; char *local_digest = NULL; FILE *digest_strm = fopen(CIB_FILENAME ".sig", "w"); if(digest_strm == NULL) { cl_perror("Cannot open signature file "CIB_FILENAME ".sig for writing"); return -1; } if(digest == NULL) { local_digest = calculate_xml_digest(local_cib, FALSE, FALSE); CRM_ASSERT(digest != NULL); digest = local_digest; } rc = fprintf(digest_strm, "%s", digest); if(rc < 0) { cl_perror("Cannot write to signature file "CIB_FILENAME ".sig"); } CRM_ASSERT(digest_strm != NULL); if(fflush(digest_strm) != 0) { cl_perror("fflush for %s failed:", digest); rc = -1; } if(fsync(fileno(digest_strm)) < 0) { cl_perror("fsync for %s failed:", digest); rc = -1; } fclose(digest_strm); crm_free(local_digest); return rc; } static gboolean -validate_on_disk_cib(const char *filename, crm_data_t **on_disk_cib) +validate_on_disk_cib(const char *filename, xmlNode **on_disk_cib) { int s_res = -1; struct stat buf; FILE *cib_file = NULL; gboolean passed = TRUE; - crm_data_t *root = NULL; + xmlNode *root = NULL; CRM_ASSERT(filename != NULL); s_res = stat(filename, &buf); if (s_res == 0) { char *sigfile = NULL; size_t fnsize; cib_file = fopen(filename, "r"); if(cib_file == NULL) { cl_perror("Couldn't open config file %s for reading", filename); return FALSE; } crm_debug_2("Reading cluster configuration from: %s", filename); root = file2xml(cib_file, FALSE); fclose(cib_file); fnsize = strlen(filename) + 5; crm_malloc0(sigfile, fnsize); snprintf(sigfile, fnsize, "%s.sig", filename); if(validate_cib_digest(root, sigfile) == FALSE) { passed = FALSE; } crm_free(sigfile); } if(on_disk_cib != NULL) { *on_disk_cib = root; } else { free_xml(root); } return passed; } static int cib_unlink(const char *file) { int rc = unlink(file); if (rc < 0) { cl_perror("Could not unlink %s - Disabling disk writes and continuing", file); cib_writes_enabled = FALSE; } return rc; } /* * It is the callers responsibility to free the output of this function */ -static crm_data_t* +static xmlNode* retrieveCib(const char *filename, const char *sigfile, gboolean archive_invalid) { struct stat buf; FILE *cib_file = NULL; - crm_data_t *root = NULL; + xmlNode *root = NULL; crm_info("Reading cluster configuration from: %s (digest: %s)", filename, sigfile); if(stat(filename, &buf) != 0) { crm_warn("Cluster configuration not found: %s", filename); return NULL; } cib_file = fopen(filename, "r"); if(cib_file == NULL) { cl_perror("Could not open config file %s for reading", filename); } else { root = file2xml(cib_file, FALSE); fclose(cib_file); } if(root == NULL) { crm_err("%s exists but does NOT contain valid XML. ", filename); crm_warn("Continuing but %s will NOT used.", filename); } else if(validate_cib_digest(root, sigfile) == FALSE) { crm_err("Checksum of %s failed! Configuration contents ignored!", filename); crm_err("Usually this is caused by manually changes, " "please refer to http://linux-ha.org/v2/faq/cib_changes_detected"); crm_warn("Continuing but %s will NOT used.", filename); free_xml(root); root = NULL; if(archive_invalid) { int rc = 0; char *suffix = crm_itoa(getpid()); /* Archive the original files so the contents are not lost */ crm_err("Archiving corrupt or unusable configuration to %s.%s", filename, suffix); rc = archive_file(filename, NULL, suffix, TRUE); if(rc < 0) { crm_err("Archival of %s failed - Disabling disk writes and continuing", filename); cib_writes_enabled = FALSE; } rc = archive_file(sigfile, NULL, suffix, TRUE); if(rc < 0) { crm_err("Archival of %s failed - Disabling disk writes and continuing", sigfile); cib_writes_enabled = FALSE; } /* Unlink the original files so they dont get in the way later */ cib_unlink(filename); cib_unlink(sigfile); crm_free(suffix); } } return root; } -crm_data_t* +xmlNode* readCibXmlFile(const char *dir, const char *file, gboolean discard_status) { gboolean dtd_ok = TRUE; char *filename = NULL, *sigfile = NULL; const char *name = NULL; const char *value = NULL; const char *ignore_dtd = NULL; const char *use_valgrind = getenv("HA_VALGRIND_ENABLED"); - crm_data_t *root = NULL; - crm_data_t *status = NULL; + xmlNode *root = NULL; + xmlNode *status = NULL; if(!crm_is_writable(dir, file, HA_CCMUSER, NULL, FALSE)) { cib_status = cib_bad_permissions; return NULL; } filename = crm_concat(dir, file, '/'); sigfile = crm_concat(filename, "sig", '.'); cib_status = cib_ok; root = retrieveCib(filename, sigfile, TRUE); if(root == NULL) { char *tmp = NULL; /* Try the backups */ tmp = filename; filename = crm_concat(tmp, "last", '.'); crm_free(tmp); tmp = sigfile; sigfile = crm_concat(tmp, "last", '.'); crm_free(tmp); crm_warn("Primary configuration corrupt or unusable, trying backup..."); root = retrieveCib(filename, sigfile, FALSE); } if(root == NULL) { root = createEmptyCib(); crm_warn("Continuing with an empty configuration."); } else { crm_xml_add(root, "generated", XML_BOOLEAN_FALSE); } if(cib_writes_enabled && crm_is_true(use_valgrind)) { cib_writes_enabled = FALSE; crm_err("HA_VALGRIND_ENABLED: %s", getenv("HA_VALGRIND_ENABLED")); crm_err("*********************************************************"); crm_err("*** Disabling disk writes to avoid confusing Valgrind ***"); crm_err("*********************************************************"); } status = find_xml_node(root, XML_CIB_TAG_STATUS, FALSE); if(discard_status && status != NULL) { /* strip out the status section if there is one */ free_xml_from_parent(root, status); status = NULL; } if(status == NULL) { create_xml_node(root, XML_CIB_TAG_STATUS); } /* Do this before DTD validation happens */ /* fill in some defaults */ name = XML_ATTR_GENERATION_ADMIN; value = crm_element_value(root, name); if(value == NULL) { crm_warn("No value for %s was specified in the configuration.", name); crm_warn("The reccomended course of action is to shutdown," " run crm_verify and fix any errors it reports."); crm_warn("We will default to zero and continue but may get" " confused about which configuration to use if" " multiple nodes are powered up at the same time."); crm_xml_add_int(root, name, 0); } name = XML_ATTR_GENERATION; value = crm_element_value(root, name); if(value == NULL) { crm_xml_add_int(root, name, 0); } name = XML_ATTR_NUMUPDATES; value = crm_element_value(root, name); if(value == NULL) { crm_xml_add_int(root, name, 0); } /* unset these and require the DC/CCM to update as needed */ update_counters(__FILE__, __PRETTY_FUNCTION__, root); xml_remove_prop(root, XML_ATTR_DC_UUID); if(discard_status) { crm_log_xml_info(root, "[on-disk]"); } ignore_dtd = crm_element_value(root, "ignore_dtd"); dtd_ok = validate_with_dtd(root, TRUE, DTD_DIRECTORY"/crm.dtd"); if(dtd_ok == FALSE) { crm_err("CIB does not validate against "DTD_DIRECTORY"/crm.dtd"); if(ignore_dtd == NULL && crm_is_true(ignore_dtd) == FALSE) { cib_status = cib_dtd_validation; } } else if(ignore_dtd == NULL) { crm_notice("Enabling DTD validation on" " the existing (sane) configuration"); crm_xml_add(root, "ignore_dtd", XML_BOOLEAN_FALSE); } if(do_id_check(root, NULL, TRUE, FALSE)) { crm_err("%s does not contain a vaild configuration:" " ID check failed", filename); cib_status = cib_id_check; } if (verifyCibXml(root) == FALSE) { crm_err("%s does not contain a vaild configuration:" " structure test failed", filename); cib_status = cib_bad_config; } crm_free(filename); crm_free(sigfile); return root; } /* * The caller should never free the return value */ -crm_data_t* +xmlNode* get_the_CIB(void) { return the_cib; } gboolean uninitializeCib(void) { - crm_data_t *tmp_cib = the_cib; + xmlNode *tmp_cib = the_cib; if(tmp_cib == NULL) { crm_debug("The CIB has already been deallocated."); return FALSE; } initialized = FALSE; the_cib = NULL; node_search = NULL; resource_search = NULL; constraint_search = NULL; status_search = NULL; crm_debug("Deallocating the CIB."); free_xml(tmp_cib); crm_debug("The CIB has been deallocated."); return TRUE; } /* * This method will not free the old CIB pointer or the new one. * We rely on the caller to have saved a pointer to the old CIB * and to free the old/bad one depending on what is appropriate. */ gboolean -initializeCib(crm_data_t *new_cib) +initializeCib(xmlNode *new_cib) { gboolean is_valid = TRUE; - crm_data_t *tmp_node = NULL; + xmlNode *tmp_node = NULL; if(new_cib == NULL) { return FALSE; } xml_validate(new_cib); tmp_node = get_object_root(XML_CIB_TAG_NODES, new_cib); if (tmp_node == NULL) { is_valid = FALSE; } tmp_node = get_object_root(XML_CIB_TAG_RESOURCES, new_cib); if (tmp_node == NULL) { is_valid = FALSE; } tmp_node = get_object_root(XML_CIB_TAG_CONSTRAINTS, new_cib); if (tmp_node == NULL) { is_valid = FALSE; } tmp_node = get_object_root(XML_CIB_TAG_CRMCONFIG, new_cib); if (tmp_node == NULL) { is_valid = FALSE; } tmp_node = get_object_root(XML_CIB_TAG_STATUS, new_cib); if (is_valid && tmp_node == NULL) { create_xml_node(new_cib, XML_CIB_TAG_STATUS); } if(is_valid == FALSE) { crm_warn("CIB Verification failed"); return FALSE; } update_counters(__FILE__, __PRETTY_FUNCTION__, new_cib); the_cib = new_cib; initialized = TRUE; return TRUE; } int archive_file(const char *oldname, const char *newname, const char *ext, gboolean preserve) { /* move 'oldname' to 'newname' by creating a hard link to it * and then removing the original hard link */ int rc = 0; int res = 0; struct stat tmp; int s_res = 0; char *backup_file = NULL; static const char *back_ext = "bak"; /* calculate the backup name if required */ if(newname != NULL) { backup_file = crm_strdup(newname); } else { int max_name_len = 1024; crm_malloc0(backup_file, max_name_len); if (ext == NULL) { ext = back_ext; } snprintf(backup_file, max_name_len - 1, "%s.%s", oldname, ext); } if(backup_file == NULL || strlen(backup_file) == 0) { crm_err("%s backup filename was %s", newname == NULL?"calculated":"supplied", backup_file == NULL?"null":"empty"); rc = -4; } s_res = stat(backup_file, &tmp); /* move the old backup */ if (rc == 0 && s_res >= 0) { if(preserve == FALSE) { res = unlink(backup_file); if (res < 0) { cl_perror("Could not unlink %s", backup_file); rc = -1; } } else { crm_info("Archive file %s exists... backing it up first", backup_file); res = archive_file(backup_file, NULL, NULL, preserve); if (res < 0) { return res; } } } s_res = stat(oldname, &tmp); /* copy */ if (rc == 0 && s_res >= 0) { res = link(oldname, backup_file); if (res < 0) { cl_perror("Could not create backup %s from %s", backup_file, oldname); rc = -2; } else if(preserve) { crm_info("%s archived as %s", oldname, backup_file); } else { crm_debug("%s archived as %s", oldname, backup_file); } } crm_free(backup_file); return rc; } /* * This method will free the old CIB pointer on success and the new one * on failure. */ int -activateCibXml(crm_data_t *new_cib, gboolean to_disk) +activateCibXml(xmlNode *new_cib, gboolean to_disk) { int error_code = cib_ok; - crm_data_t *saved_cib = the_cib; + xmlNode *saved_cib = the_cib; const char *ignore_dtd = NULL; crm_debug("Activating new CIB"); crm_log_xml_debug_4(new_cib, "Attempting to activate CIB"); update_counters(__FILE__, __FUNCTION__, new_cib); CRM_ASSERT(new_cib != saved_cib); if(saved_cib != NULL) { crm_validate_data(saved_cib); } ignore_dtd = crm_element_value(new_cib, "ignore_dtd"); if( #if CRM_DEPRECATED_SINCE_2_0_4 ignore_dtd != NULL && #endif crm_is_true(ignore_dtd) == FALSE && validate_with_dtd( new_cib, TRUE, DTD_DIRECTORY"/crm.dtd") == FALSE) { crm_err("Updated CIB does not validate against "DTD_DIRECTORY"/crm.dtd... ignoring"); error_code = cib_dtd_validation; } if(error_code == cib_ok && initializeCib(new_cib) == FALSE) { error_code = cib_ACTIVATION; crm_err("Ignoring invalid or NULL CIB"); } if(error_code != cib_ok) { if(saved_cib != NULL) { crm_warn("Reverting to last known CIB"); if (initializeCib(saved_cib) == FALSE) { /* oh we are so dead */ crm_crit("Couldn't re-initialize the old CIB!"); cl_flush_logs(); exit(1); } } else { crm_crit("Could not write out new CIB and no saved" " version to revert to"); } } else if(per_action_cib && cib_writes_enabled && cib_status == cib_ok) { crm_err("Per-action CIB"); write_cib_contents(the_cib); } else if(cib_writes_enabled && cib_status == cib_ok && to_disk) { crm_debug("Triggering CIB write"); G_main_set_trigger(cib_writer); } else { crm_debug("disk: %d, writes: %d", to_disk, cib_writes_enabled); } if(the_cib != saved_cib && the_cib != new_cib) { CRM_DEV_ASSERT(error_code != cib_ok); CRM_DEV_ASSERT(the_cib == NULL); } if(the_cib != new_cib) { free_xml(new_cib); CRM_DEV_ASSERT(error_code != cib_ok); } if(the_cib != saved_cib) { free_xml(saved_cib); } return error_code; } int write_cib_contents(gpointer p) { int rc = 0; gboolean need_archive = FALSE; struct stat buf; char *digest = NULL; int exit_rc = LSB_EXIT_OK; - crm_data_t *cib_status_root = NULL; + xmlNode *cib_status_root = NULL; /* we can scribble on "the_cib" here and not affect the parent */ const char *epoch = crm_element_value(the_cib, XML_ATTR_GENERATION); const char *updates = crm_element_value(the_cib, XML_ATTR_NUMUPDATES); const char *admin_epoch = crm_element_value( the_cib, XML_ATTR_GENERATION_ADMIN); need_archive = (stat(CIB_FILENAME, &buf) == 0); if (need_archive) { crm_debug("Archiving current version"); /* check the admin didnt modify it underneath us */ if(validate_on_disk_cib(CIB_FILENAME, NULL) == FALSE) { crm_err("%s was manually modified while Heartbeat was active!", CIB_FILENAME); exit_rc = LSB_EXIT_GENERIC; goto cleanup; } /* These calls leak, but we're in a separate process that will exit * when the function does... so it's of no consequence */ CRM_ASSERT(retrieveCib(CIB_FILENAME, CIB_FILENAME".sig", FALSE) != NULL); rc = archive_file(CIB_FILENAME, NULL, "last", FALSE); if(rc != 0) { crm_err("Could not make backup of the existing CIB: %d", rc); exit_rc = LSB_EXIT_GENERIC; goto cleanup; } rc = archive_file(CIB_FILENAME".sig", NULL, "last", FALSE); if(rc != 0) { crm_warn("Could not make backup of the existing CIB digest: %d", rc); } CRM_ASSERT(retrieveCib(CIB_FILENAME, CIB_FILENAME".sig", FALSE) != NULL); CRM_ASSERT(retrieveCib(CIB_FILENAME".last", CIB_FILENAME".sig.last", FALSE) != NULL); crm_debug("Verified CIB archive"); } /* Given that we discard the status section on startup * there is no point writing it out in the first place * since users just get confused by it * * Although, it does help me once in a while * * So delete the status section before we write it out */ if(p == NULL) { cib_status_root = find_xml_node(the_cib, XML_CIB_TAG_STATUS, TRUE); CRM_DEV_ASSERT(cib_status_root != NULL); if(cib_status_root != NULL) { free_xml_from_parent(the_cib, cib_status_root); } } rc = write_xml_file(the_cib, CIB_FILENAME, FALSE); crm_debug("Wrote CIB to disk"); if(rc <= 0) { crm_err("Changes couldn't be written to disk"); exit_rc = LSB_EXIT_GENERIC; goto cleanup; } digest = calculate_xml_digest(the_cib, FALSE, FALSE); crm_info("Wrote version %s.%s.%s of the CIB to disk (digest: %s)", admin_epoch?admin_epoch:"0", epoch?epoch:"0", updates?updates:"0", digest); rc = write_cib_digest(the_cib, digest); crm_debug("Wrote digest to disk"); if(rc <= 0) { crm_err("Digest couldn't be written to disk"); exit_rc = LSB_EXIT_GENERIC; goto cleanup; } CRM_ASSERT(retrieveCib(CIB_FILENAME, CIB_FILENAME".sig", FALSE) != NULL); if(need_archive) { CRM_ASSERT(retrieveCib(CIB_FILENAME".last", CIB_FILENAME".sig.last", FALSE) != NULL); } crm_debug("Wrote and verified CIB"); cleanup: crm_free(digest); if(p == NULL) { /* fork-and-write mode */ exit(exit_rc); } /* stand-alone mode */ return exit_rc; } gboolean -set_connected_peers(crm_data_t *xml_obj) +set_connected_peers(xmlNode *xml_obj) { guint active = 0; int current = 0; char *peers_s = NULL; const char *current_s = NULL; if(xml_obj == NULL) { return FALSE; } current_s = crm_element_value(xml_obj, XML_ATTR_NUMPEERS); current = crm_parse_int(current_s, "0"); active = crm_active_peers(crm_proc_cib); if(current != active) { crm_malloc0(peers_s, 32); snprintf(peers_s, 32, "%u", active); crm_xml_add(xml_obj, XML_ATTR_NUMPEERS, peers_s); crm_debug("We now have %s (%u) active peers", peers_s, active); crm_free(peers_s); return TRUE; } return FALSE; } gboolean -update_counters(const char *file, const char *fn, crm_data_t *xml_obj) +update_counters(const char *file, const char *fn, xmlNode *xml_obj) { gboolean did_update = FALSE; did_update = did_update || set_connected_peers(xml_obj); if(did_update) { do_crm_log(LOG_DEBUG, "Counters updated by %s", fn); } return did_update; } void GHFunc_count_peers(gpointer key, gpointer value, gpointer user_data) { int *active = user_data; if(safe_str_eq(value, ONLINESTATUS)) { (*active)++; } else if(safe_str_eq(value, JOINSTATUS)) { (*active)++; } } diff --git a/cib/main.c b/cib/main.c index 8cdef526de..92dcda5565 100644 --- a/cib/main.c +++ b/cib/main.c @@ -1,645 +1,649 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_LIBXML2 # include #endif #ifdef HAVE_GETOPT_H # include #endif #if HAVE_BZLIB_H # include #endif extern int init_remote_listener(int port); +extern gboolean stand_alone; gboolean cib_shutdown_flag = FALSE; -gboolean stand_alone = FALSE; gboolean per_action_cib = FALSE; enum cib_errors cib_status = cib_ok; #if SUPPORT_HEARTBEAT oc_ev_t *cib_ev_token; ll_cluster_t *hb_conn = NULL; extern void oc_ev_special(const oc_ev_t *, oc_ev_class_t , int ); gboolean cib_register_ha(ll_cluster_t *hb_cluster, const char *client_name); #endif GMainLoop* mainloop = NULL; const char* cib_root = WORKING_DIR; char *cib_our_uname = NULL; gboolean preserve_status = FALSE; gboolean cib_writes_enabled = TRUE; void usage(const char* cmd, int exit_status); int cib_init(void); gboolean cib_shutdown(int nsig, gpointer unused); void cib_ha_connection_destroy(gpointer user_data); gboolean startCib(const char *filename); extern gboolean cib_msg_timeout(gpointer data); extern int write_cib_contents(gpointer p); GTRIGSource *cib_writer = NULL; GHashTable *client_list = NULL; char *channel1 = NULL; char *channel2 = NULL; char *channel3 = NULL; char *channel4 = NULL; char *channel5 = NULL; #define OPTARGS "aswr:V?" void cib_cleanup(void); static void cib_diskwrite_complete(gpointer userdata, int status, int signo, int exitcode) { if(exitcode != LSB_EXIT_OK || signo != 0 || status != 0) { crm_err("Disk write failed: status=%d, signo=%d, exitcode=%d", status, signo, exitcode); if(cib_writes_enabled) { crm_err("Disabling disk writes after write failure"); cib_writes_enabled = FALSE; } } else { crm_debug_2("Disk write passed"); } } int main(int argc, char ** argv) { int flag; int rc = 0; int argerr = 0; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { {"per-action-cib", 0, 0, 'a'}, {"stand-alone", 0, 0, 's'}, {"disk-writes", 0, 0, 'w'}, {"cib-root", 1, 0, 'r'}, {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {0, 0, 0, 0} }; #endif crm_log_init(CRM_SYSTEM_CIB, LOG_INFO, TRUE, TRUE, 0, NULL); G_main_add_SignalHandler( G_PRIORITY_HIGH, SIGTERM, cib_shutdown, NULL, NULL); cib_writer = G_main_add_tempproc_trigger( G_PRIORITY_LOW, write_cib_contents, "write_cib_contents", NULL, NULL, NULL, cib_diskwrite_complete); EnableProcLogging(); set_sigchld_proctrack(G_PRIORITY_HIGH,DEFAULT_MAXDISPATCHTIME); crm_peer_init(); client_list = g_hash_table_new(g_str_hash, g_str_equal); 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) { case 'V': alter_debug(DEBUG_INC); break; case 's': stand_alone = TRUE; preserve_status = TRUE; cib_writes_enabled = FALSE; cl_log_enable_stderr(1); break; case '?': /* Help message */ usage(crm_system_name, LSB_EXIT_OK); break; case 'f': per_action_cib = TRUE; break; case 'w': cib_writes_enabled = TRUE; break; case 'r': cib_root = optarg; break; default: ++argerr; break; } } crm_info("Retrieval of a per-action CIB: %s", per_action_cib?"enabled":"disabled"); if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name,LSB_EXIT_GENERIC); } /* read local config file */ rc = cib_init(); CRM_CHECK(g_hash_table_size(client_list) == 0, crm_warn("Not all clients gone at exit")); cib_cleanup(); #if SUPPORT_HEARTBEAT if(hb_conn) { hb_conn->llc_ops->delete(hb_conn); } #endif crm_info("Done"); return rc; } void cib_cleanup(void) { crm_peer_destroy(); g_hash_table_destroy(client_list); crm_free(cib_our_uname); #if HAVE_LIBXML2 xmlCleanupParser(); #endif crm_free(channel1); crm_free(channel2); crm_free(channel3); crm_free(channel4); crm_free(channel5); } unsigned long cib_num_ops = 0; const char *cib_stat_interval = "10min"; unsigned long cib_num_local = 0, cib_num_updates = 0, cib_num_fail = 0; unsigned long cib_bad_connects = 0, cib_num_timeouts = 0; longclock_t cib_call_time = 0; gboolean cib_stats(gpointer data); gboolean cib_stats(gpointer data) { int local_log_level = LOG_DEBUG; static unsigned long last_stat = 0; unsigned int cib_calls_ms = 0; static unsigned long cib_stat_interval_ms = 0; if(cib_stat_interval_ms == 0) { cib_stat_interval_ms = crm_get_msec(cib_stat_interval); } cib_calls_ms = longclockto_ms(cib_call_time); if((cib_num_ops - last_stat) > 0) { unsigned long calls_diff = cib_num_ops - last_stat; double stat_1 = (1000*cib_calls_ms)/calls_diff; local_log_level = LOG_INFO; do_crm_log(local_log_level, "Processed %lu operations" " (%.2fus average, %lu%% utilization) in the last %s", calls_diff, stat_1, (100*cib_calls_ms)/cib_stat_interval_ms, cib_stat_interval); } do_crm_log(local_log_level+1, "\tDetail: %lu operations (%ums total)" " (%lu local, %lu updates, %lu failures," " %lu timeouts, %lu bad connects)", cib_num_ops, cib_calls_ms, cib_num_local, cib_num_updates, cib_num_fail, cib_bad_connects, cib_num_timeouts); last_stat = cib_num_ops; cib_call_time = 0; return TRUE; } #if SUPPORT_HEARTBEAT gboolean ccm_connect(void); static void ccm_connection_destroy(gpointer user_data) { crm_err("CCM connection failed... blocking while we reconnect"); CRM_ASSERT(ccm_connect()); return; } gboolean ccm_connect(void) { gboolean did_fail = TRUE; int num_ccm_fails = 0; int max_ccm_fails = 30; int ret; int cib_ev_fd; while(did_fail) { did_fail = FALSE; crm_info("Registering with CCM..."); ret = oc_ev_register(&cib_ev_token); if (ret != 0) { did_fail = TRUE; } if(did_fail == FALSE) { crm_debug_3("Setting up CCM callbacks"); ret = oc_ev_set_callback( cib_ev_token, OC_EV_MEMB_CLASS, cib_ccm_msg_callback, NULL); if (ret != 0) { crm_warn("CCM callback not set"); did_fail = TRUE; } } if(did_fail == FALSE) { oc_ev_special(cib_ev_token, OC_EV_MEMB_CLASS, 0); crm_debug_3("Activating CCM token"); ret = oc_ev_activate(cib_ev_token, &cib_ev_fd); if (ret != 0){ crm_warn("CCM Activation failed"); did_fail = TRUE; } } if(did_fail) { num_ccm_fails++; oc_ev_unregister(cib_ev_token); if(num_ccm_fails < max_ccm_fails){ crm_warn("CCM Connection failed %d times (%d max)", num_ccm_fails, max_ccm_fails); sleep(3); } else { crm_err("CCM Activation failed %d (max) times", num_ccm_fails); return FALSE; } } } crm_debug("CCM Activation passed... all set to go!"); G_main_add_fd(G_PRIORITY_HIGH, cib_ev_fd, FALSE, cib_ccm_dispatch, cib_ev_token, ccm_connection_destroy); return TRUE; } #endif #if SUPPORT_AIS static gboolean cib_ais_dispatch(AIS_Message *wrapper, char *data, int sender) { - crm_data_t *xml = NULL; + xmlNode *xml = NULL; crm_debug_2("Message received: '%.80s'", data); switch(wrapper->header.id) { case crm_class_members: case crm_class_notify: update_counters(__FILE__, __PRETTY_FUNCTION__, the_cib); break; default: xml = string2xml(data); if(xml == NULL) { goto bail; } - ha_msg_add(xml, F_ORIG, wrapper->sender.uname); - ha_msg_add_int(xml, F_SEQ, wrapper->id); + crm_xml_add(xml, F_ORIG, wrapper->sender.uname); + crm_xml_add_int(xml, F_SEQ, wrapper->id); cib_peer_callback(xml, NULL); break; } free_xml(xml); return TRUE; bail: crm_err("Invalid XML: '%.120s'", data); return TRUE; } static void cib_ais_destroy(gpointer user_data) { crm_err("AIS connection terminated"); ais_fd_sync = -1; exit(1); } #endif int cib_init(void) { gboolean was_error = FALSE; if(startCib("cib.xml") == FALSE){ crm_crit("Cannot start CIB... terminating"); exit(1); } if(stand_alone == FALSE) { void *dispatch = cib_peer_callback; void *destroy = cib_ha_connection_destroy; if(is_openais_cluster()) { #if SUPPORT_AIS destroy = cib_ais_destroy; dispatch = cib_ais_dispatch; #endif } if(crm_cluster_connect(&cib_our_uname, NULL, dispatch, destroy, #if SUPPORT_HEARTBEAT &hb_conn #else NULL #endif ) == FALSE){ crm_crit("Cannot sign in to the cluster... terminating"); exit(100); } #if 0 if(is_openais_cluster()) { crm_info("Requesting the list of configured nodes"); send_ais_text( crm_class_members, __FUNCTION__, TRUE, NULL, crm_msg_ais); } #endif #if SUPPORT_HEARTBEAT if(is_heartbeat_cluster()) { if(was_error == FALSE) { if (HA_OK != hb_conn->llc_ops->set_cstatus_callback( hb_conn, cib_client_status_callback, hb_conn)) { crm_err("Cannot set cstatus callback: %s", hb_conn->llc_ops->errmsg(hb_conn)); was_error = TRUE; } } if(was_error == FALSE) { was_error = (ccm_connect() == FALSE); } if(was_error == FALSE) { /* Async get client status information in the cluster */ crm_info("Requesting the list of configured nodes"); hb_conn->llc_ops->client_status( hb_conn, NULL, CRM_SYSTEM_CIB, -1); } } #endif } else { cib_our_uname = crm_strdup("localhost"); } channel1 = crm_strdup(cib_channel_callback); was_error = init_server_ipc_comms( channel1, cib_client_connect_null, default_ipc_connection_destroy); channel2 = crm_strdup(cib_channel_ro); was_error = was_error || init_server_ipc_comms( channel2, cib_client_connect_rw_ro, default_ipc_connection_destroy); channel3 = crm_strdup(cib_channel_rw); was_error = was_error || init_server_ipc_comms( channel3, cib_client_connect_rw_ro, default_ipc_connection_destroy); channel4 = crm_strdup(cib_channel_rw_synchronous); was_error = was_error || init_server_ipc_comms( channel4, cib_client_connect_rw_synch, default_ipc_connection_destroy); channel5 = crm_strdup(cib_channel_ro_synchronous); was_error = was_error || init_server_ipc_comms( channel5, cib_client_connect_ro_synch, default_ipc_connection_destroy); if(stand_alone) { if(was_error) { crm_err("Couldnt start"); return 1; } cib_is_master = TRUE; /* Create the mainloop and run it... */ mainloop = g_main_new(FALSE); crm_info("Starting %s mainloop", crm_system_name); /* Gmain_timeout_add(crm_get_msec("10s"), cib_msg_timeout, NULL); */ /* Gmain_timeout_add( */ /* crm_get_msec(cib_stat_interval), cib_stats, NULL); */ g_main_run(mainloop); return_to_orig_privs(); return 0; } if(was_error == FALSE) { /* Create the mainloop and run it... */ mainloop = g_main_new(FALSE); crm_info("Starting %s mainloop", crm_system_name); Gmain_timeout_add(crm_get_msec("10s"), cib_msg_timeout, NULL); Gmain_timeout_add( crm_get_msec(cib_stat_interval), cib_stats, NULL); g_main_run(mainloop); return_to_orig_privs(); } else { crm_err("Couldnt start all communication channels, exiting."); } return 0; } void usage(const char* cmd, int exit_status) { FILE* stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-%s]\n", cmd, OPTARGS); fprintf(stream, "\t--%s (-%c)\t\tTurn on debug info." " Additional instances increase verbosity\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c)\t\tThis help message\n", "help", '?'); fprintf(stream, "\t--%s (-%c)\tAdvanced use only\n", "per-action-cib", 'a'); fprintf(stream, "\t--%s (-%c)\tAdvanced use only\n", "stand-alone", 's'); fprintf(stream, "\t--%s (-%c)\tAdvanced use only\n", "disk-writes", 'w'); fprintf(stream, "\t--%s (-%c)\t\tAdvanced use only\n", "cib-root", 'r'); fflush(stream); exit(exit_status); } void cib_ha_connection_destroy(gpointer user_data) { if(cib_shutdown_flag) { crm_info("Heartbeat disconnection complete... exiting"); } else { crm_err("Heartbeat connection lost! Exiting."); } uninitializeCib(); crm_info("Exiting..."); if (mainloop != NULL && g_main_is_running(mainloop)) { g_main_quit(mainloop); } else { exit(LSB_EXIT_OK); } } static void disconnect_cib_client(gpointer key, gpointer value, gpointer user_data) { cib_client_t *a_client = value; crm_debug_2("Processing client %s/%s... send=%d, recv=%d", crm_str(a_client->name), crm_str(a_client->channel_name), (int)a_client->channel->send_queue->current_qlen, (int)a_client->channel->recv_queue->current_qlen); if(a_client->channel->ch_status == IPC_CONNECT) { a_client->channel->ops->resume_io(a_client->channel); if(a_client->channel->send_queue->current_qlen != 0 || a_client->channel->recv_queue->current_qlen != 0) { crm_info("Flushed messages to/from %s/%s... send=%d, recv=%d", crm_str(a_client->name), crm_str(a_client->channel_name), (int)a_client->channel->send_queue->current_qlen, (int)a_client->channel->recv_queue->current_qlen); } } if(a_client->channel->ch_status == IPC_CONNECT) { crm_warn("Disconnecting %s/%s...", crm_str(a_client->name), crm_str(a_client->channel_name)); a_client->channel->ops->disconnect(a_client->channel); } } extern gboolean cib_process_disconnect( IPC_Channel *channel, cib_client_t *cib_client); gboolean cib_shutdown(int nsig, gpointer unused) { if(cib_shutdown_flag == FALSE) { cib_shutdown_flag = TRUE; crm_debug("Disconnecting %d clients", g_hash_table_size(client_list)); g_hash_table_foreach(client_list, disconnect_cib_client, NULL); crm_info("Disconnected %d clients", g_hash_table_size(client_list)); cib_process_disconnect(NULL, NULL); } else { crm_info("Waiting for %d clients to disconnect...", g_hash_table_size(client_list)); } return TRUE; } gboolean startCib(const char *filename) { gboolean active = FALSE; - crm_data_t *cib = readCibXmlFile(cib_root, filename, !preserve_status); + xmlNode *cib = readCibXmlFile(cib_root, filename, !preserve_status); CRM_ASSERT(cib != NULL); if(activateCibXml(cib, TRUE) == 0) { int port = 0; + const char *port_s = crm_element_value(cib, "remote_access_port"); active = TRUE; - ha_msg_value_int(cib, "remote_access_port", &port); - init_remote_listener(port); + if(port_s) { + port = crm_parse_int(port_s, NULL); + init_remote_listener(port); + } + crm_info("CIB Initialization completed successfully"); if(per_action_cib) { uninitializeCib(); } } return active; } diff --git a/cib/messages.c b/cib/messages.c index f4a3d98d41..4699cc1b3c 100644 --- a/cib/messages.c +++ b/cib/messages.c @@ -1,932 +1,932 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_DIFF_RETRY 5 #ifdef CIBPIPE gboolean cib_is_master = TRUE; #else gboolean cib_is_master = FALSE; #endif gboolean syncd_once = FALSE; -crm_data_t *the_cib = NULL; +xmlNode *the_cib = NULL; extern const char *cib_our_uname; -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 revision_check(xmlNode *cib_update, xmlNode *cib_copy, int flags); +int get_revision(xmlNode *xml_obj, int cur_revision); enum cib_errors updateList( - crm_data_t *local_cib, crm_data_t *update_command, crm_data_t *failed, + xmlNode *local_cib, xmlNode *update_command, xmlNode *failed, int operation, const char *section); -gboolean check_generation(crm_data_t *newCib, crm_data_t *oldCib); +gboolean check_generation(xmlNode *newCib, xmlNode *oldCib); gboolean update_results( - crm_data_t *failed, crm_data_t *target, int operation, int return_code); + xmlNode *failed, xmlNode *target, int operation, int return_code); enum cib_errors cib_update_counter( - crm_data_t *xml_obj, const char *field, gboolean reset); + xmlNode *xml_obj, const char *field, gboolean reset); -enum cib_errors sync_our_cib(HA_Message *request, gboolean all); +enum cib_errors sync_our_cib(xmlNode *request, gboolean all); -extern HA_Message *cib_msg_copy(const HA_Message *msg, gboolean with_data); +extern xmlNode *cib_msg_copy(const xmlNode *msg, gboolean with_data); extern gboolean cib_shutdown_flag; extern void terminate_cib(const char *caller); enum cib_errors cib_process_shutdown_req( - 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) + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer) { #ifdef CIBPIPE return cib_invalid_argument; #else enum cib_errors result = cib_ok; - const char *host = cl_get_string(input, F_ORIG); + const char *host = crm_element_value(req, F_ORIG); *answer = NULL; - if(cl_get_string(input, F_CIB_ISREPLY) == NULL) { + if(crm_element_value(req, F_CIB_ISREPLY) == NULL) { crm_info("Shutdown REQ from %s", host); return cib_ok; } else if(cib_shutdown_flag) { crm_info("Shutdown ACK from %s", host); terminate_cib(__FUNCTION__); return cib_ok; } else { crm_err("Shutdown ACK from %s - not shutting down",host); result = cib_unknown; } return result; #endif } 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) + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer) { enum cib_errors result = cib_ok; crm_debug_2("Processing \"%s\" event", op); *answer = NULL; if(op == NULL) { result = cib_operation; crm_err("No operation specified"); } else if(strcasecmp(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) + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **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) + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer) { #ifdef CIBPIPE return cib_invalid_argument; #else 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; #endif } 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) + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer) { #ifdef CIBPIPE return cib_invalid_argument; #else enum cib_errors result = cib_ok; crm_debug_2("Processing \"%s\" event", op); *answer = createPingAnswerFragment(CRM_SYSTEM_CIB, "ok"); return result; #endif } 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) + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer) { - crm_data_t *obj_root = NULL; + xmlNode *obj_root = NULL; enum cib_errors result = cib_ok; crm_debug_2("Processing \"%s\" event for section=%s", op, crm_str(section)); CRM_CHECK(*answer == NULL, free_xml(*answer)); *answer = NULL; if (safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) { section = NULL; } obj_root = get_object_root(section, existing_cib); if(obj_root == NULL) { result = cib_NOTEXISTS; } else { *answer = obj_root; } 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) + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer) { enum cib_errors result = cib_ok; crm_debug_2("Processing \"%s\" event", op); *answer = NULL; free_xml(*result_cib); *result_cib = createEmptyCib(); copy_in_properties(*result_cib, existing_cib); cib_update_counter(*result_cib, XML_ATTR_GENERATION, FALSE); 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) + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer) { enum cib_errors result = cib_ok; crm_debug_2("Processing \"%s\" event for epoch=%s", op, crm_str(crm_element_value(the_cib, XML_ATTR_GENERATION))); *answer = NULL; cib_update_counter(*result_cib, XML_ATTR_GENERATION, FALSE); return result; } 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) + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer) { #ifdef CIBPIPE return cib_invalid_argument; #else - return sync_our_cib(input, TRUE); + return sync_our_cib(req, TRUE); #endif } 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) + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer) { #ifdef CIBPIPE return cib_invalid_argument; #else - return sync_our_cib(input, FALSE); + return sync_our_cib(req, FALSE); #endif } enum cib_errors -cib_update_counter(crm_data_t *xml_obj, const char *field, gboolean reset) +cib_update_counter(xmlNode *xml_obj, const char *field, gboolean reset) { char *new_value = NULL; char *old_value = NULL; int int_value = -1; 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); 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; } int sync_in_progress = 0; 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) + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer) { 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_epoch = 0; int this_admin_epoch = 0; int diff_add_updates = 0; int diff_add_epoch = 0; int diff_add_admin_epoch = 0; int diff_del_updates = 0; int diff_del_epoch = 0; int diff_del_admin_epoch = 0; crm_debug_2("Processing \"%s\" event", op); if(cib_is_master) { /* the master is never waiting for a resync */ sync_in_progress = 0; } cib_diff_version_details( input, &diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates, &diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates); if(sync_in_progress > MAX_DIFF_RETRY) { /* request another full-sync, * the last request may have been lost */ sync_in_progress = 0; } if(sync_in_progress) { sync_in_progress++; crm_warn("Not applying diff %d.%d.%d -> %d.%d.%d (sync in progress)", diff_del_admin_epoch,diff_del_epoch,diff_del_updates, diff_add_admin_epoch,diff_add_epoch,diff_add_updates); return cib_diff_resync; } value = crm_element_value(existing_cib, XML_ATTR_GENERATION); this_epoch = 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_epoch = atoi(value?value:"0"); if(diff_del_admin_epoch == diff_add_admin_epoch && diff_del_epoch == diff_add_epoch && diff_del_updates == diff_add_updates) { if(diff_add_admin_epoch == -1 && diff_add_epoch == -1 && diff_add_updates == -1) { diff_add_epoch = this_epoch; diff_add_updates = this_updates + 1; diff_add_admin_epoch = this_admin_epoch; diff_del_epoch = this_epoch; diff_del_updates = this_updates; diff_del_admin_epoch = this_admin_epoch; } else { 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_epoch > this_admin_epoch) { 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_epoch < this_admin_epoch) { apply_diff = FALSE; log_level = LOG_WARNING; reason = "current \""XML_ATTR_GENERATION_ADMIN"\" is greater than required"; } if(apply_diff && diff_del_epoch > this_epoch) { 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_epoch < this_epoch) { 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) { free_xml(*result_cib); *result_cib = NULL; if(apply_xml_diff(existing_cib, input, result_cib) == FALSE) { log_level = LOG_WARNING; reason = "Failed application of an update diff"; if(options & cib_force_diff) { if(cib_is_master == FALSE) { log_level = LOG_INFO; reason = "Failed application of a global update." " Requesting full refresh."; do_resync = TRUE; } else { reason = "Failed application of a global update." " Not requesting full refresh."; } } } else if((options & cib_force_diff) && !validate_with_dtd( *result_cib, FALSE, DTD_DIRECTORY"/crm.dtd")) { if(cib_is_master == FALSE) { log_level = LOG_INFO; reason = "Failed DTD validation of a global update." " Requesting full refresh."; do_resync = TRUE; } else { log_level = LOG_WARNING; reason = "Failed DTD validation of a global update." " Not requesting full refresh."; } } } if(reason != NULL) { do_crm_log( log_level, "Diff %d.%d.%d -> %d.%d.%d not applied to %d.%d.%d: %s", diff_del_admin_epoch,diff_del_epoch,diff_del_updates, diff_add_admin_epoch,diff_add_epoch,diff_add_updates, this_admin_epoch,this_epoch,this_updates, reason); result = cib_diff_failed; } else if(apply_diff) { crm_debug_2("Diff %d.%d.%d -> %d.%d.%d was applied", diff_del_admin_epoch,diff_del_epoch,diff_del_updates, diff_add_admin_epoch,diff_add_epoch,diff_add_updates); } #ifdef CIBPIPE do_resync = FALSE; #else if(do_resync && cib_is_master == FALSE) { - HA_Message *sync_me = ha_msg_new(3); + xmlNode *sync_me = create_xml_node(NULL, "sync-me"); free_xml(*result_cib); *result_cib = NULL; result = cib_diff_resync; crm_info("Requesting re-sync from peer: %s", reason); sync_in_progress++; - 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); + crm_xml_add(sync_me, F_TYPE, "cib"); + crm_xml_add(sync_me, F_CIB_OPERATION, CIB_OP_SYNC_ONE); + crm_xml_add(sync_me, F_CIB_DELEGATED, cib_our_uname); if(send_cluster_message(NULL, crm_msg_cib, sync_me, FALSE) == FALSE) { result = cib_not_connected; } - ha_msg_del(sync_me); + free_xml(sync_me); } else if(do_resync) { crm_warn("Not resyncing in master mode"); } #endif 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) + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer) { const char *tag = NULL; gboolean verbose = FALSE; enum cib_errors result = cib_ok; crm_debug_2("Processing \"%s\" event for section=%s", op, crm_str(section)); *answer = NULL; if (input == NULL) { return cib_NOOBJECT; } tag = crm_element_name(input); if (options & cib_verbose) { verbose = TRUE; } if(safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) { section = NULL; } else if(safe_str_eq(tag, section)) { section = NULL; } if(safe_str_eq(tag, XML_TAG_CIB)) { int updates = 0; int epoch = 0; int admin_epoch = 0; int replace_updates = 0; int replace_epoch = 0; int replace_admin_epoch = 0; const char *reason = NULL; cib_version_details( existing_cib, &admin_epoch, &epoch, &updates); cib_version_details(input, &replace_admin_epoch, &replace_epoch, &replace_updates); if(replace_admin_epoch < admin_epoch) { reason = XML_ATTR_GENERATION_ADMIN; } else if(replace_admin_epoch > admin_epoch) { /* no more checks */ } else if(replace_epoch < epoch) { reason = XML_ATTR_GENERATION; } else if(replace_epoch > epoch) { /* 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_epoch, replace_epoch, replace_updates, admin_epoch, epoch, updates, reason); result = cib_old_data; } sync_in_progress = 0; free_xml(*result_cib); *result_cib = copy_xml(input); } else { - crm_data_t *obj_root = NULL; + xmlNode *obj_root = NULL; gboolean ok = TRUE; obj_root = get_object_root(section, *result_cib); ok = replace_xml_child(NULL, obj_root, input, FALSE); if(ok == FALSE) { crm_debug_2("No matching object to replace"); result = cib_NOTEXISTS; } } 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) + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer) { - crm_data_t *obj_root = NULL; + xmlNode *obj_root = NULL; crm_debug_2("Processing \"%s\" event", op); if(input == NULL) { crm_err("Cannot perform modification with no data"); return cib_NOOBJECT; } obj_root = get_object_root(section, *result_cib); crm_validate_data(input); crm_validate_data(*result_cib); if(replace_xml_child(NULL, obj_root, input, TRUE) == FALSE) { crm_debug_2("No matching object to delete"); } 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) + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer) { - crm_data_t *obj_root = NULL; + xmlNode *obj_root = NULL; crm_debug_2("Processing \"%s\" event", op); if(input == NULL) { crm_err("Cannot perform modification with no data"); return cib_NOOBJECT; } obj_root = get_object_root(section, *result_cib); crm_validate_data(input); crm_validate_data(*result_cib); if(update_xml_child(obj_root, input) == FALSE) { return cib_NOTEXISTS; } return cib_ok; } enum cib_errors cib_process_change( - 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) + const char *op, int options, const char *section, xmlNode *req, xmlNode *input, + xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer) { gboolean verbose = FALSE; - crm_data_t *failed = NULL; + xmlNode *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)); if (strcasecmp(CIB_OP_CREATE, op) == 0) { cib_update_op = CIB_UPDATE_OP_ADD; } else if (strcasecmp(CIB_OP_UPDATE, op) == 0) { cib_update_op = CIB_UPDATE_OP_MODIFY; } else if (strcasecmp(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; } else if(safe_str_eq(XML_TAG_CIB, section)) { section = NULL; } if(input == NULL) { crm_err("Cannot perform modification with no data"); return cib_NOOBJECT; } crm_validate_data(input); crm_validate_data(*result_cib); failed = create_xml_node(NULL, XML_TAG_FAILED); /* make changes to a temp copy then activate */ if(section == NULL) { int lpc = 0; const char *type = NULL; - crm_data_t *sub_input = NULL; + xmlNode *sub_input = NULL; /* order is no longer important here */ const char *type_list[] = { XML_CIB_TAG_NODES, XML_CIB_TAG_CONSTRAINTS, XML_CIB_TAG_RESOURCES, XML_CIB_TAG_STATUS, XML_CIB_TAG_CRMCONFIG }; copy_in_properties(*result_cib, input); for(lpc = 0; lpc < DIMOF(type_list); lpc++) { type = type_list[lpc]; if(result == cib_ok) { crm_debug_2("Processing section=%s", type); sub_input = get_object_root(type, input); if(sub_input) { result = updateList( *result_cib, sub_input, failed, cib_update_op, type); } } } } else { result = updateList( *result_cib, input, failed, cib_update_op, section); } if (result != cib_ok || xml_has_children(failed)) { if(result == cib_ok) { result = cib_unknown; } crm_log_xml_err(failed, "CIB Update failures"); *answer = failed; } else { free_xml(failed); } return result; } #define cib_update_xml_macro(parent, xml_update) \ if(operation == CIB_UPDATE_OP_DELETE) { \ rc = delete_cib_object(parent, xml_update); \ update_results(failed, xml_update, operation, rc); \ \ } else if(operation == CIB_UPDATE_OP_MODIFY) { \ rc = update_cib_object(parent, xml_update); \ update_results(failed, xml_update, operation, rc); \ \ } else { \ rc = add_cib_object(parent, xml_update); \ update_results(failed, xml_update, operation, rc); \ } \ enum cib_errors -updateList(crm_data_t *local_cib, crm_data_t *xml_section, crm_data_t *failed, +updateList(xmlNode *local_cib, xmlNode *xml_section, xmlNode *failed, int operation, const char *section) { int rc = cib_ok; - crm_data_t *this_section = get_object_root(section, local_cib); + xmlNode *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; } if(safe_str_eq(crm_element_name(xml_section), section)) { xml_child_iter(xml_section, a_child, rc = cib_ok; cib_update_xml_macro(this_section, a_child); ); } else { cib_update_xml_macro(this_section, xml_section); } if(rc == cib_ok && xml_has_children(failed)) { rc = cib_unknown; } return rc; } gboolean -check_generation(crm_data_t *newCib, crm_data_t *oldCib) +check_generation(xmlNode *newCib, xmlNode *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) + xmlNode *failed, xmlNode *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; + xmlNode *xml_node = NULL; if (return_code != cib_ok) { operation_msg = cib_op2string(operation); 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); } return was_error; } enum cib_errors -revision_check(crm_data_t *cib_update, crm_data_t *cib_copy, int flags) +revision_check(xmlNode *cib_update, xmlNode *cib_copy, int flags) { int cmp = 0; enum cib_errors rc = cib_ok; char *new_revision = NULL; const char *cur_revision = crm_element_value( cib_copy, XML_ATTR_CIB_REVISION); crm_validate_data(cib_update); crm_validate_data(cib_copy); if(crm_element_value(cib_update, XML_ATTR_CIB_REVISION) == NULL) { return cib_ok; } new_revision = crm_element_value_copy(cib_update,XML_ATTR_CIB_REVISION); cmp = compare_version(new_revision, CIB_FEATURE_SET); if(cmp > 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", new_revision,CIB_FEATURE_SET); 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", new_revision,CIB_FEATURE_SET); rc = cib_revision_unsupported; } } else if(cur_revision == NULL) { crm_info("Updating CIB revision to %s", new_revision); crm_xml_add(cib_copy, XML_ATTR_CIB_REVISION, new_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); } crm_free(new_revision); return rc; } #ifndef CIBPIPE enum cib_errors -sync_our_cib(HA_Message *request, gboolean all) +sync_our_cib(xmlNode *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); + const char *host = crm_element_value(request, F_ORIG); + const char *op = crm_element_value(request, F_CIB_OPERATION); - HA_Message *replace_request = cib_msg_copy(request, FALSE); + xmlNode *replace_request = cib_msg_copy(request, FALSE); CRM_CHECK(the_cib != NULL, ;); CRM_CHECK(replace_request != NULL, ;); crm_info("Syncing CIB to %s", all?"all peers":host); if(all == FALSE && host == NULL) { - crm_log_message(LOG_ERR, request); + crm_log_xml(LOG_ERR, "bad sync", request); } /* remove the "all == FALSE" condition * * sync_from was failing, the local client wasnt being notified * because it didnt know it was a reply * setting this does not prevent the other nodes from applying it * if all == TRUE */ if(host != NULL) { - ha_msg_add(replace_request, F_CIB_ISREPLY, host); + crm_xml_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); + crm_xml_add(replace_request, F_CIB_OPERATION, CIB_OP_REPLACE); + crm_xml_add(replace_request, "original_"F_CIB_OPERATION, op); + crm_xml_add(replace_request, F_CIB_GLOBAL_UPDATE, XML_BOOLEAN_TRUE); add_message_xml(replace_request, F_CIB_CALLDATA, the_cib); if(send_cluster_message(all?NULL:host, crm_msg_cib, replace_request, FALSE) == FALSE) { result = cib_not_connected; } - ha_msg_del(replace_request); + free_xml(replace_request); return result; } #endif diff --git a/cib/notify.c b/cib/notify.c index c637c67932..9f24cea386 100644 --- a/cib/notify.c +++ b/cib/notify.c @@ -1,415 +1,415 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern GHashTable *client_list; int pending_updates = 0; void cib_notify_client(gpointer key, gpointer value, gpointer user_data); -void attach_cib_generation(HA_Message *msg, const char *field, crm_data_t *a_cib); +void attach_cib_generation(xmlNode *msg, const char *field, xmlNode *a_cib); void do_cib_notify( - int options, const char *op, crm_data_t *update, - enum cib_errors result, crm_data_t *result_data, const char *msg_type); + int options, const char *op, xmlNode *update, + enum cib_errors result, xmlNode *result_data, const char *msg_type); void cib_notify_client(gpointer key, gpointer value, gpointer user_data) { IPC_Channel *ipc_client = NULL; - HA_Message *update_msg = user_data; + xmlNode *update_msg = user_data; cib_client_t *client = value; const char *type = NULL; gboolean is_pre = FALSE; gboolean is_post = FALSE; gboolean is_confirm = FALSE; gboolean is_replace = FALSE; gboolean is_diff = FALSE; gboolean do_send = FALSE; int qlen = 0; int max_qlen = 0; CRM_DEV_ASSERT(client != NULL); CRM_DEV_ASSERT(update_msg != NULL); - type = cl_get_string(update_msg, F_SUBTYPE); + type = crm_element_value(update_msg, F_SUBTYPE); CRM_DEV_ASSERT(type != NULL); if(client == NULL) { crm_warn("Skipping NULL client"); return; } else if(client->channel == NULL) { crm_warn("Skipping client with NULL channel"); return; } else if(client->name == NULL) { crm_debug_2("Skipping unnammed client / comamnd channel"); return; } if(safe_str_eq(type, T_CIB_PRE_NOTIFY)) { is_pre = TRUE; } else if(safe_str_eq(type, T_CIB_POST_NOTIFY)) { is_post = TRUE; } else if(safe_str_eq(type, T_CIB_UPDATE_CONFIRM)) { is_confirm = TRUE; } else if(safe_str_eq(type, T_CIB_DIFF_NOTIFY)) { is_diff = TRUE; } else if(safe_str_eq(type, T_CIB_REPLACE_NOTIFY)) { is_replace = TRUE; } ipc_client = client->channel; qlen = ipc_client->send_queue->current_qlen; max_qlen = ipc_client->send_queue->max_qlen; #if 1 /* get_chan_status() causes memory to be allocated that isnt free'd * until the message is read (which messes up the memory stats) */ if(ipc_client->ops->get_chan_status(ipc_client) != IPC_CONNECT) { crm_debug_2("Skipping notification to disconnected" " client %s/%s", client->name, client->id); } else if(client->pre_notify && is_pre) { if(qlen < (int)(0.4 * max_qlen)) { do_send = TRUE; } else { crm_warn("Throttling pre-notifications due to" " high load: queue=%d (max=%d)", qlen, max_qlen); } } else if(client->post_notify && is_post) { if(qlen < (int)(0.7 * max_qlen)) { do_send = TRUE; } else { crm_warn("Throttling post-notifications due to" " extreme load: queue=%d (max=%d)", qlen, max_qlen); } /* these are critical */ } else #endif if(client->diffs && is_diff) { do_send = TRUE; } else if(client->confirmations && is_confirm) { do_send = TRUE; } else if(client->replace && is_replace) { do_send = TRUE; } if(do_send) { crm_debug_2("Notifying client %s/%s of %s update (queue=%d)", client->name, client->channel_name, type, qlen); if(ipc_client->send_queue->current_qlen >= ipc_client->send_queue->max_qlen) { /* We never want the CIB to exit because our client is slow */ crm_crit("%s-notification of client %s/%s failed - queue saturated", is_confirm?"Confirmation":is_post?"Post":"Pre", client->name, client->id); } else if(send_ipc_message(ipc_client, update_msg) == FALSE) { crm_warn("Notification of client %s/%s failed", client->name, client->id); } } else { crm_debug_3("Client %s/%s not interested in %s notifications", client->name, client->channel_name, type); } } void cib_pre_notify( - int options, const char *op, crm_data_t *existing, crm_data_t *update) + int options, const char *op, xmlNode *existing, xmlNode *update) { - HA_Message *update_msg = NULL; + xmlNode *update_msg = NULL; const char *type = NULL; const char *id = NULL; - update_msg = ha_msg_new(6); + update_msg = create_xml_node(NULL, "pre-notify"); if(update != NULL) { id = crm_element_value(update, XML_ATTR_ID); } - ha_msg_add(update_msg, F_TYPE, T_CIB_NOTIFY); - ha_msg_add(update_msg, F_SUBTYPE, T_CIB_PRE_NOTIFY); - ha_msg_add(update_msg, F_CIB_OPERATION, op); + crm_xml_add(update_msg, F_TYPE, T_CIB_NOTIFY); + crm_xml_add(update_msg, F_SUBTYPE, T_CIB_PRE_NOTIFY); + crm_xml_add(update_msg, F_CIB_OPERATION, op); if(id != NULL) { - ha_msg_add(update_msg, F_CIB_OBJID, id); + crm_xml_add(update_msg, F_CIB_OBJID, id); } if(update != NULL) { - ha_msg_add(update_msg, F_CIB_OBJTYPE, crm_element_name(update)); + crm_xml_add(update_msg, F_CIB_OBJTYPE, crm_element_name(update)); } else if(existing != NULL) { - ha_msg_add(update_msg, F_CIB_OBJTYPE, crm_element_name(existing)); + crm_xml_add(update_msg, F_CIB_OBJTYPE, crm_element_name(existing)); } - type = cl_get_string(update_msg, F_CIB_OBJTYPE); + type = crm_element_value(update_msg, F_CIB_OBJTYPE); attach_cib_generation(update_msg, "cib_generation", the_cib); if(existing != NULL) { add_message_xml(update_msg, F_CIB_EXISTING, existing); } if(update != NULL) { add_message_xml(update_msg, F_CIB_UPDATE, update); } g_hash_table_foreach(client_list, cib_notify_client, update_msg); if(update == NULL) { crm_debug_2("Performing operation %s (on section=%s)", op, type); } else { crm_debug_2("Performing %s on <%s%s%s>", op, type, id?" id=":"", id?id:""); } - crm_msg_del(update_msg); + free_xml(update_msg); } void -cib_post_notify(int options, const char *op, crm_data_t *update, - enum cib_errors result, crm_data_t *new_obj) +cib_post_notify(int options, const char *op, xmlNode *update, + enum cib_errors result, xmlNode *new_obj) { do_cib_notify( options, op, update, result, new_obj, T_CIB_UPDATE_CONFIRM); } void cib_diff_notify( int options, const char *client, const char *call_id, const char *op, - crm_data_t *update, enum cib_errors result, crm_data_t *diff) + xmlNode *update, enum cib_errors result, xmlNode *diff) { int add_updates = 0; int add_epoch = 0; int add_admin_epoch = 0; int del_updates = 0; int del_epoch = 0; int del_admin_epoch = 0; int log_level = LOG_DEBUG_2; if(diff == NULL) { return; } if(result != cib_ok) { log_level = LOG_WARNING; } cib_diff_version_details( diff, &add_admin_epoch, &add_epoch, &add_updates, &del_admin_epoch, &del_epoch, &del_updates); if(add_updates != del_updates) { do_crm_log(log_level, "Update (client: %s%s%s): %d.%d.%d -> %d.%d.%d (%s)", client, call_id?", call:":"", call_id?call_id:"", del_admin_epoch, del_epoch, del_updates, add_admin_epoch, add_epoch, add_updates, cib_error2string(result)); } else if(diff != NULL) { do_crm_log(log_level, "Local-only Change (client:%s%s%s): %d.%d.%d (%s)", client, call_id?", call: ":"", call_id?call_id:"", add_admin_epoch, add_epoch, add_updates, cib_error2string(result)); } do_cib_notify(options, op, update, result, diff, T_CIB_DIFF_NOTIFY); } void do_cib_notify( - int options, const char *op, crm_data_t *update, - enum cib_errors result, crm_data_t *result_data, const char *msg_type) + int options, const char *op, xmlNode *update, + enum cib_errors result, xmlNode *result_data, const char *msg_type) { - HA_Message *update_msg = NULL; + xmlNode *update_msg = NULL; const char *type = NULL; const char *id = NULL; - update_msg = ha_msg_new(8); + update_msg = create_xml_node(NULL, "notify"); if(result_data != NULL) { id = crm_element_value(result_data, XML_ATTR_ID); } - ha_msg_add(update_msg, F_TYPE, T_CIB_NOTIFY); - ha_msg_add(update_msg, F_SUBTYPE, msg_type); - ha_msg_add(update_msg, F_CIB_OPERATION, op); - ha_msg_add_int(update_msg, F_CIB_RC, result); + crm_xml_add(update_msg, F_TYPE, T_CIB_NOTIFY); + crm_xml_add(update_msg, F_SUBTYPE, msg_type); + crm_xml_add(update_msg, F_CIB_OPERATION, op); + crm_xml_add_int(update_msg, F_CIB_RC, result); if(id != NULL) { - ha_msg_add(update_msg, F_CIB_OBJID, id); + crm_xml_add(update_msg, F_CIB_OBJID, id); } if(update != NULL) { crm_debug_4("Setting type to update->name: %s", crm_element_name(update)); - ha_msg_add(update_msg, F_CIB_OBJTYPE, crm_element_name(update)); + crm_xml_add(update_msg, F_CIB_OBJTYPE, crm_element_name(update)); type = crm_element_name(update); } else if(result_data != NULL) { crm_debug_4("Setting type to new_obj->name: %s", crm_element_name(result_data)); - ha_msg_add(update_msg, F_CIB_OBJTYPE, crm_element_name(result_data)); + crm_xml_add(update_msg, F_CIB_OBJTYPE, crm_element_name(result_data)); type = crm_element_name(result_data); } else { crm_debug_4("Not Setting type"); } attach_cib_generation(update_msg, "cib_generation", the_cib); if(update != NULL) { add_message_xml(update_msg, F_CIB_UPDATE, update); } if(result_data != NULL) { add_message_xml(update_msg, F_CIB_UPDATE_RESULT, result_data); } crm_debug_3("Notifying clients"); g_hash_table_foreach(client_list, cib_notify_client, update_msg); - crm_msg_del(update_msg); + free_xml(update_msg); if(update == NULL) { if(result == cib_ok) { crm_debug_2("Operation %s (on section=%s) completed", op, crm_str(type)); } else { crm_warn("Operation %s (on section=%s) FAILED: (%d) %s", op, crm_str(type), result, cib_error2string(result)); } } else { if(result == cib_ok) { crm_debug_2("Completed %s of <%s %s%s>", op, crm_str(type), id?"id=":"", id?id:""); } else { crm_warn("%s of <%s %s%s> FAILED: %s", op,crm_str(type), id?"id=":"", id?id:"", cib_error2string(result)); } } crm_debug_3("Notify complete"); } void -attach_cib_generation(HA_Message *msg, const char *field, crm_data_t *a_cib) +attach_cib_generation(xmlNode *msg, const char *field, xmlNode *a_cib) { - crm_data_t *generation = create_xml_node( + xmlNode *generation = create_xml_node( NULL, XML_CIB_TAG_GENERATION_TUPPLE); if(a_cib != NULL) { copy_in_properties(generation, a_cib); } add_message_xml(msg, field, generation); free_xml(generation); } void -cib_replace_notify(crm_data_t *update, enum cib_errors result, crm_data_t *diff) +cib_replace_notify(xmlNode *update, enum cib_errors result, xmlNode *diff) { const char *origin = NULL; - HA_Message *replace_msg = NULL; + xmlNode *replace_msg = NULL; int add_updates = 0; int add_epoch = 0; int add_admin_epoch = 0; int del_updates = 0; int del_epoch = 0; int del_admin_epoch = 0; if(diff == NULL) { return; } cib_diff_version_details( diff, &add_admin_epoch, &add_epoch, &add_updates, &del_admin_epoch, &del_epoch, &del_updates); origin = crm_element_value(update, F_CRM_ORIGIN); if(add_updates != del_updates) { crm_info("Replaced: %d.%d.%d -> %d.%d.%d from %s", del_admin_epoch, del_epoch, del_updates, add_admin_epoch, add_epoch, add_updates, crm_str(origin)); } else if(diff != NULL) { crm_info("Local-only Replace: %d.%d.%d from %s", add_admin_epoch, add_epoch, add_updates, crm_str(origin)); } - replace_msg = ha_msg_new(8); - ha_msg_add(replace_msg, F_TYPE, T_CIB_NOTIFY); - ha_msg_add(replace_msg, F_SUBTYPE, T_CIB_REPLACE_NOTIFY); - ha_msg_add(replace_msg, F_CIB_OPERATION, CIB_OP_REPLACE); - ha_msg_add_int(replace_msg, F_CIB_RC, result); + replace_msg = create_xml_node(NULL, "notify-replace"); + crm_xml_add(replace_msg, F_TYPE, T_CIB_NOTIFY); + crm_xml_add(replace_msg, F_SUBTYPE, T_CIB_REPLACE_NOTIFY); + crm_xml_add(replace_msg, F_CIB_OPERATION, CIB_OP_REPLACE); + crm_xml_add_int(replace_msg, F_CIB_RC, result); attach_cib_generation(replace_msg, "cib-replace-generation", update); - crm_log_message_adv(LOG_DEBUG_2,"CIB Replaced", replace_msg); + crm_log_xml(LOG_DEBUG_2,"CIB Replaced", replace_msg); g_hash_table_foreach(client_list, cib_notify_client, replace_msg); - crm_msg_del(replace_msg); + free_xml(replace_msg); } diff --git a/cib/notify.h b/cib/notify.h index 7188f046ac..355949b098 100644 --- a/cib/notify.h +++ b/cib/notify.h @@ -1,40 +1,40 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include extern FILE *msg_cib_strm; extern void cib_pre_notify( - int options, const char *op, crm_data_t *existing, crm_data_t *update); + int options, const char *op, xmlNode *existing, xmlNode *update); -extern void cib_post_notify(int options, const char *op, crm_data_t *update, - enum cib_errors result, crm_data_t *new_obj); +extern void cib_post_notify(int options, const char *op, xmlNode *update, + enum cib_errors result, xmlNode *new_obj); extern void cib_diff_notify( int options, const char *client, const char *call_id, const char *op, - crm_data_t *update, enum cib_errors result, crm_data_t *old_cib); + xmlNode *update, enum cib_errors result, xmlNode *old_cib); -extern void cib_replace_notify(crm_data_t *update, enum cib_errors result, crm_data_t *diff); +extern void cib_replace_notify(xmlNode *update, enum cib_errors result, xmlNode *diff); diff --git a/cib/primatives.c b/cib/primatives.c index 6902889fd1..8e4dd1d624 100644 --- a/cib/primatives.c +++ b/cib/primatives.c @@ -1,511 +1,511 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * In case of confusion, this is the memory management policy for * all functions in this file. * * All add/modify functions use copies of supplied data. * It is therefore appropriate that the callers free the supplied data * at some point after the function has finished. * * All delete functions will handle the freeing of deleted data * but not the function arguments. */ -void update_node_state(crm_data_t *existing_node, crm_data_t *update); +void update_node_state(xmlNode *existing_node, xmlNode *update); /* --- Resource */ int -addResource(crm_data_t *cib, crm_data_t *anXmlNode) +addResource(xmlNode *cib, xmlNode *anXmlNode) { const char *id = ID(anXmlNode); - crm_data_t *root; + xmlNode *root; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } crm_debug_2("Adding " XML_CIB_TAG_RESOURCE " (%s)...", id); root = get_object_root(XML_CIB_TAG_RESOURCES, cib); return add_cib_object(root, anXmlNode); } -crm_data_t* -findResource(crm_data_t *cib, const char *id) +xmlNode* +findResource(xmlNode *cib, const char *id) { - crm_data_t *root = NULL, *ret = NULL; + xmlNode *root = NULL, *ret = NULL; root = get_object_root(XML_CIB_TAG_RESOURCES, cib); ret = find_entity(root, XML_CIB_TAG_RESOURCE, id); return ret; } int -updateResource(crm_data_t *cib, crm_data_t *anXmlNode) +updateResource(xmlNode *cib, xmlNode *anXmlNode) { const char *id = ID(anXmlNode); - crm_data_t *root = NULL; + xmlNode *root = NULL; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } crm_debug_2("Updating " XML_CIB_TAG_RESOURCE " (%s)...", id); root = get_object_root(XML_CIB_TAG_RESOURCES, cib); return update_cib_object(root, anXmlNode); } int -delResource(crm_data_t *cib, crm_data_t *delete_spec) +delResource(xmlNode *cib, xmlNode *delete_spec) { const char *id = ID(delete_spec); - crm_data_t *root; + xmlNode *root; if(id == NULL || strlen(id) == 0) { return CIBRES_MISSING_ID; } crm_debug_2("Deleting " XML_CIB_TAG_RESOURCE " (%s)...", id); root = get_object_root(XML_CIB_TAG_RESOURCES, cib); return delete_cib_object(root, delete_spec); } /* --- Constraint */ int -addConstraint(crm_data_t *cib, crm_data_t *anXmlNode) +addConstraint(xmlNode *cib, xmlNode *anXmlNode) { const char *id = ID(anXmlNode); - crm_data_t *root; + xmlNode *root; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } crm_debug_2("Adding " XML_CIB_TAG_CONSTRAINT " (%s)...", id); root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); return add_cib_object(root, anXmlNode); } -crm_data_t* -findConstraint(crm_data_t *cib, const char *id) +xmlNode* +findConstraint(xmlNode *cib, const char *id) { - crm_data_t *root = NULL, *ret = NULL; + xmlNode *root = NULL, *ret = NULL; root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); ret = find_entity(root, XML_CIB_TAG_CONSTRAINT, id); return ret; } int -updateConstraint(crm_data_t *cib, crm_data_t *anXmlNode) +updateConstraint(xmlNode *cib, xmlNode *anXmlNode) { const char *id = ID(anXmlNode); - crm_data_t *root; + xmlNode *root; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } crm_debug_2("Updating " XML_CIB_TAG_CONSTRAINT " (%s)...", id); root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); return update_cib_object(root, anXmlNode); } int -delConstraint(crm_data_t *cib, crm_data_t *delete_spec) +delConstraint(xmlNode *cib, xmlNode *delete_spec) { const char *id = ID(delete_spec); - crm_data_t *root; + xmlNode *root; if(id == NULL || strlen(id) == 0) { return CIBRES_MISSING_ID; } crm_debug_2("Deleting " XML_CIB_TAG_CONSTRAINT " (%s)...", id); root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); return delete_cib_object(root, delete_spec); } /* --- HaNode */ int -addHaNode(crm_data_t *cib, crm_data_t *anXmlNode) +addHaNode(xmlNode *cib, xmlNode *anXmlNode) { const char *id = ID(anXmlNode); - crm_data_t *root; + xmlNode *root; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } crm_debug_2("Adding " XML_CIB_TAG_NODE " (%s)...", id); root = get_object_root(XML_CIB_TAG_NODES, cib); return add_cib_object(root, anXmlNode); } -crm_data_t* -findHaNode(crm_data_t *cib, const char *id) +xmlNode* +findHaNode(xmlNode *cib, const char *id) { - crm_data_t *root = NULL, *ret = NULL; + xmlNode *root = NULL, *ret = NULL; root = get_object_root(XML_CIB_TAG_NODES, cib); ret = find_entity(root, XML_CIB_TAG_NODE, id); return ret; } int -updateHaNode(crm_data_t *cib, cibHaNode *anXmlNode) +updateHaNode(xmlNode *cib, cibHaNode *anXmlNode) { const char *id = ID(anXmlNode); - crm_data_t *root; + xmlNode *root; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } crm_debug_2("Updating " XML_CIB_TAG_NODE " (%s)...", id); root = get_object_root(XML_CIB_TAG_NODES, cib); return update_cib_object(root, anXmlNode); } int -delHaNode(crm_data_t *cib, crm_data_t *delete_spec) +delHaNode(xmlNode *cib, xmlNode *delete_spec) { const char *id = ID(delete_spec); - crm_data_t *root; + xmlNode *root; if(id == NULL || strlen(id) == 0) { return CIBRES_MISSING_ID; } crm_debug_2("Deleting " XML_CIB_TAG_NODE " (%s)...", id); root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); return delete_cib_object(root, delete_spec); } /* --- Status */ int -addStatus(crm_data_t *cib, crm_data_t *anXmlNode) +addStatus(xmlNode *cib, xmlNode *anXmlNode) { const char *id = ID(anXmlNode); - crm_data_t *root; + xmlNode *root; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } crm_debug_2("Adding " XML_CIB_TAG_NODE " (%s)...", id); root = get_object_root(XML_CIB_TAG_STATUS, cib); return add_cib_object(root, anXmlNode); } -crm_data_t* -findStatus(crm_data_t *cib, const char *id) +xmlNode* +findStatus(xmlNode *cib, const char *id) { - crm_data_t *root = NULL, *ret = NULL; + xmlNode *root = NULL, *ret = NULL; root = get_object_root(XML_CIB_TAG_STATUS, cib); ret = find_entity(root, XML_CIB_TAG_STATE, id); return ret; } int -updateStatus(crm_data_t *cib, crm_data_t *anXmlNode) +updateStatus(xmlNode *cib, xmlNode *anXmlNode) { const char *id = ID(anXmlNode); - crm_data_t *root; + xmlNode *root; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } crm_debug_2("Updating " XML_CIB_TAG_NODE " (%s)...", id); root = get_object_root(XML_CIB_TAG_STATUS, cib); return update_cib_object(root, anXmlNode); } int -delStatus(crm_data_t *cib, crm_data_t *delete_spec) +delStatus(xmlNode *cib, xmlNode *delete_spec) { const char *id = ID(delete_spec); - crm_data_t *root; + xmlNode *root; if(id == NULL || strlen(id) == 0) { return CIBRES_MISSING_ID; } crm_debug_2("Deleting " XML_CIB_TAG_STATE " (%s)...", id); root = get_object_root(XML_CIB_TAG_STATUS, cib); return delete_cib_object(root, delete_spec); } int -delete_cib_object(crm_data_t *parent, crm_data_t *delete_spec) +delete_cib_object(xmlNode *parent, xmlNode *delete_spec) { const char *object_name = NULL; const char *object_id = NULL; - crm_data_t *equiv_node = NULL; + xmlNode *equiv_node = NULL; int result = cib_ok; if(delete_spec != NULL) { object_name = crm_element_name(delete_spec); } object_id = crm_element_value(delete_spec, XML_ATTR_ID); crm_debug_3("Processing: <%s id=%s>", crm_str(object_name), crm_str(object_id)); if(delete_spec == NULL) { result = cib_NOOBJECT; } else if(parent == NULL) { result = cib_NOPARENT; } else if(object_id == NULL) { /* placeholder object */ equiv_node = find_xml_node(parent, object_name, FALSE); } else { equiv_node = find_entity(parent, object_name, object_id); } if(result != cib_ok) { ; /* nothing */ } else if(equiv_node == NULL) { result = cib_ok; } else if(xml_has_children(delete_spec) == FALSE) { /* only leaves are deleted */ crm_debug("Removing leaf: <%s id=%s>", crm_str(object_name), crm_str(object_id)); zap_xml_from_parent(parent, equiv_node); } else { xml_child_iter( delete_spec, child, int tmp_result = delete_cib_object(equiv_node, child); /* only the first error is likely to be interesting */ if(tmp_result != cib_ok && result == cib_ok) { result = tmp_result; } ); } return result; } int -add_cib_object(crm_data_t *parent, crm_data_t *new_obj) +add_cib_object(xmlNode *parent, xmlNode *new_obj) { enum cib_errors result = cib_ok; const char *object_name = NULL; const char *object_id = NULL; - crm_data_t *equiv_node = NULL; + xmlNode *equiv_node = NULL; if(new_obj != NULL) { object_name = crm_element_name(new_obj); } object_id = crm_element_value(new_obj, XML_ATTR_ID); crm_debug_3("Processing: <%s id=%s>", crm_str(object_name), crm_str(object_id)); if(new_obj == NULL || object_name == NULL) { result = cib_NOOBJECT; } else if(parent == NULL) { result = cib_NOPARENT; } else if(object_id == NULL) { /* placeholder object */ equiv_node = find_xml_node(parent, object_name, FALSE); } else { equiv_node = find_entity(parent, object_name, object_id); } if(result != cib_ok) { ; /* do nothing */ } else if(equiv_node != NULL) { result = cib_EXISTS; } else { result = update_cib_object(parent, new_obj); } return result; } int -update_cib_object(crm_data_t *parent, crm_data_t *update) +update_cib_object(xmlNode *parent, xmlNode *update) { const char *replace = NULL; const char *object_name = NULL; const char *object_id = NULL; - crm_data_t *target = NULL; + xmlNode *target = NULL; int result = cib_ok; CRM_DEV_ASSERT(update != NULL); if(crm_assert_failed) { return cib_NOOBJECT; } CRM_DEV_ASSERT(parent != NULL); if(crm_assert_failed) { return cib_NOPARENT; } object_name = crm_element_name(update); object_id = ID(update); CRM_DEV_ASSERT(object_name != NULL); if(crm_assert_failed) { return cib_NOOBJECT; } crm_debug_3("Processing: <%s id=%s>", crm_str(object_name), crm_str(object_id)); if(object_id == NULL) { /* placeholder object */ target = find_xml_node(parent, object_name, FALSE); } else { target = find_entity(parent, object_name, object_id); } if(target == NULL) { target = create_xml_node(parent, object_name); } crm_debug_2("Found node <%s id=%s> to update", crm_str(object_name), crm_str(object_id)); replace = crm_element_value(update, XML_CIB_ATTR_REPLACE); if(replace != NULL) { - crm_data_t *remove = NULL; + xmlNode *remove = NULL; int last = 0, lpc = 0, len = 0; len = strlen(replace); while(lpc <= len) { if(replace[lpc] == ',' || replace[lpc] == 0) { char *replace_item = NULL; if ( last == lpc ) { /* nothing to do */ last = lpc+1; goto incr; } crm_malloc0(replace_item, lpc - last + 1); strncpy(replace_item, replace+last, lpc-last); remove = find_xml_node(target, replace_item, FALSE); if(remove != NULL) { crm_debug_3("Replacing node <%s> in <%s>", replace_item, crm_element_name(target)); zap_xml_from_parent(target, remove); } crm_free(replace_item); last = lpc+1; } incr: lpc++; } xml_remove_prop(update, XML_CIB_ATTR_REPLACE); xml_remove_prop(target, XML_CIB_ATTR_REPLACE); } copy_in_properties(target, update); crm_debug_3("Processing children of <%s id=%s>", crm_str(object_name), crm_str(object_id)); xml_child_iter( update, a_child, int tmp_result = 0; crm_debug_3("Updating child <%s id=%s>", crm_element_name(a_child), ID(a_child)); tmp_result = update_cib_object(target, a_child); /* only the first error is likely to be interesting */ if(tmp_result != cib_ok) { crm_err("Error updating child <%s id=%s>", crm_element_name(a_child), ID(a_child)); if(result == cib_ok) { result = tmp_result; } } ); crm_debug_3("Finished with <%s id=%s>", crm_str(object_name), crm_str(object_id)); return result; } diff --git a/cib/regression.sh b/cib/regression.sh index 66de7e0f4c..7bd69d91d6 100755 --- a/cib/regression.sh +++ b/cib/regression.sh @@ -1,157 +1,158 @@ #!/bin/bash num_errors=0 num_passed=0 assert() { rc=$1; shift target=$1; shift app=$1; shift msg=$1; shift exit_code=$1; shift if [ $rc -ne $target ]; then num_errors=`expr $num_errors + 1` printf "* Failed (rc=%.3d): %-14s - %s\n" $rc $app "$msg" cibadmin -Ql if [ ! -z $exit_code ]; then echo "Aborting tests" exit $exit_code fi + exit 1 else printf "* Passed: %-14s - %s\n" $app "$msg" num_passed=`expr $num_passed + 1` fi } done=0 cib_opts="" while test "$done" = "0"; do case "$1" in -v) verbose=1; shift;; -l) cib_opts="$cib_opts -l"; shift;; -x) set -x; shift;; -?) usage 0;; -*) echo "unknown option: $1"; usage 1;; *) done=1;; esac done printf " %-9s %-16s %s\n" Result App Test # Save backup cibadmin $cib_opts -Q > /tmp/$$.existing.xml assert $? 0 cibadmin "Query CIB" for section in crm_config nodes resources constraints status; do cibadmin $cib_opts -Q -o $section > /tmp/$$.$section.xml assert $? 0 cibadmin "Query CIB for $section" done # Create a combined backup echo '' > /tmp/$$.combined.xml echo '' >> /tmp/$$.combined.xml cat /tmp/$$.crm_config.xml >> /tmp/$$.combined.xml cat /tmp/$$.nodes.xml >> /tmp/$$.combined.xml cat /tmp/$$.resources.xml >> /tmp/$$.combined.xml cat /tmp/$$.constraints.xml >> /tmp/$$.combined.xml echo '' >> /tmp/$$.combined.xml cat /tmp/$$.status.xml >> /tmp/$$.combined.xml echo '' >> /tmp/$$.combined.xml # Test various tools and options cibadmin $cib_opts -E > /dev/null 2>&1 assert $? 1 cibadmin "Require --force for CIB erasure" cibadmin $cib_opts -E --force assert $? 0 cibadmin "Allow CIB erasure with --force" crm_attribute -n cluster-delay -v 60s assert $? 0 crm_attribute "Set cluster option" cibadmin $cib_opts -Q -o crm_config | grep cib-bootstrap-options-cluster-delay > /dev/null 2>&1 assert $? 0 cibadmin "Query new cluster option" cibadmin $cib_opts -Q -o crm_config > /tmp/$$.opt.xml assert $? 0 cibadmin "Query cluster options" cibadmin $cib_opts -D -o crm_config -X '' assert $? 0 cibadmin "Delete nvpair" cibadmin $cib_opts -C -o crm_config -x /tmp/$$.opt.xml > /dev/null 2>&1 assert $? 21 cibadmin "Create operaton should fail with: -21, The object already exists" cibadmin $cib_opts -M -o crm_config -x /tmp/$$.opt.xml assert $? 0 cibadmin "Modify cluster options section" cibadmin $cib_opts -Q -o crm_config | grep cib-bootstrap-options-cluster-delay > /dev/null 2>&1 assert $? 0 cibadmin "Query updated cluster option" crm_attribute -n cluster-delay -v 40s -s duplicate > /dev/null 2>&1 assert $? 0 crm_attribute "Set duplicate cluster option" crm_attribute -n cluster-delay -v 30s > /dev/null 2>&1 assert $? 216 crm_attribute "Setting multiply defined cluster option should fail with -216, Could not set cluster option" crm_attribute -n cluster-delay -v 30s -s duplicate assert $? 0 crm_attribute "Set cluster option with -s" crm_attribute -n cluster-delay -D -i cib-bootstrap-options-cluster-delay assert $? 0 crm_attribute "Delete cluster option with -i" cibadmin -C -o nodes -X '' assert $? 0 cibadmin "Create node entry" crm_attribute -n ram -v 1024M -U i-dont-exist-UNAME -t nodes assert $? 0 crm_attribute "Create node attribute" cibadmin $cib_opts -Q -o nodes | grep i-dont-exist-UUID-ram > /dev/null 2>&1 assert $? 0 cibadmin "Query new node attribute" cibadmin $cib_opts -Q | cibadmin -5 -p > /dev/null 2>&1 assert $? 0 cibadmin "Digest calculation" # This update will fail because it has version numbers cibadmin $cib_opts -R -x /tmp/$$.existing.xml > /dev/null 2>&1 assert $? 45 cibadmin "Replace operation should fail with: -45, Update was older than existing configuration" # Restore the existing config cibadmin $cib_opts -U -x /tmp/$$.combined.xml assert $? 0 cibadmin "Update complete CIB" #cibadmin $cib_opts -Q cibadmin $cib_opts -Q >> /tmp/$$.all.xml assert $? 0 cibadmin "Query complete CIB" cibadmin $cib_opts -R -x /tmp/$$.all.xml > /dev/null 2>&1 assert $? 0 cibadmin "Replace complete CIB" for section in crm_config nodes resources constraints status; do cibadmin $cib_opts -R -o $section -x /tmp/$$.$section.xml > /dev/null 2>&1 assert $? 0 cibadmin "Replace $section options" done # Cleanup set +x rm /tmp/$$.opt.xml rm /tmp/$$.all.xml rm /tmp/$$.combined.xml rm /tmp/$$.existing.xml for section in crm_config nodes resources constraints status; do rm /tmp/$$.$section.xml done if [ $num_errors -gt 0 ]; then echo Tests failed: $agent failed $num_errors tests exit 1 else echo All $num_passed tests completed successfully exit 0 fi diff --git a/cib/remote.c b/cib/remote.c index 397c54bd6a..851480164e 100644 --- a/cib/remote.c +++ b/cib/remote.c @@ -1,615 +1,613 @@ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "callbacks.h" /* #undef HAVE_PAM_PAM_APPL_H */ /* #undef HAVE_GNUTLS_GNUTLS_H */ #ifdef HAVE_GNUTLS_GNUTLS_H # undef KEYFILE # include #endif #include #include #if HAVE_SECURITY_PAM_APPL_H # include # define HAVE_PAM 1 #else # if HAVE_PAM_PAM_APPL_H # include # define HAVE_PAM 1 # endif #endif int init_remote_listener(int port); char *cib_recv_remote_msg(void *session); -void cib_send_remote_msg(void *session, HA_Message *msg); +void cib_send_remote_msg(void *session, xmlNode *msg); #ifdef HAVE_GNUTLS_GNUTLS_H # define DH_BITS 1024 const int tls_kx_order[] = { GNUTLS_KX_ANON_DH, GNUTLS_KX_DHE_RSA, GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, 0 }; gnutls_dh_params dh_params; gnutls_anon_server_credentials anon_cred; -char *cib_send_tls(gnutls_session *session, HA_Message *msg); +char *cib_send_tls(gnutls_session *session, xmlNode *msg); char *cib_recv_tls(gnutls_session *session); #endif extern int num_clients; int authenticate_user(const char* user, const char* passwd); gboolean cib_remote_listen(int ssock, gpointer data); gboolean cib_remote_msg(int csock, gpointer data); -char *cib_send_plaintext(int sock, HA_Message *msg); +char *cib_send_plaintext(int sock, xmlNode *msg); char *cib_recv_plaintext(int sock); extern void cib_process_request( - HA_Message *request, gboolean privileged, gboolean force_synchronous, + xmlNode *request, gboolean privileged, gboolean force_synchronous, gboolean from_peer, cib_client_t *cib_client); #ifdef HAVE_GNUTLS_GNUTLS_H static void debug_log(int level, const char *str) { fputs (str, stderr); } static gnutls_session * create_tls_session(int csock) { int rc = 0; gnutls_session *session; session = (gnutls_session*)gnutls_malloc(sizeof(gnutls_session)); gnutls_init(session, GNUTLS_SERVER); gnutls_set_default_priority(*session); gnutls_kx_set_priority (*session, tls_kx_order); gnutls_credentials_set(*session, GNUTLS_CRD_ANON, anon_cred); gnutls_transport_set_ptr(*session, (gnutls_transport_ptr) GINT_TO_POINTER(csock)); do { rc = gnutls_handshake (*session); } while (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN); if (rc < 0) { crm_err("Handshake failed: %s", gnutls_strerror(rc)); gnutls_deinit(*session); gnutls_free(session); return NULL; } return session; } char* -cib_send_tls(gnutls_session *session, HA_Message *msg) +cib_send_tls(gnutls_session *session, xmlNode *msg) { char *xml_text = NULL; - ha_msg_mod(msg, F_XML_TAGNAME, "cib_result"); - crm_log_xml(LOG_DEBUG_2, "Result: ", msg); + msg->name = xmlCharStrdup("cib_result"); xml_text = dump_xml_unformatted(msg); if(xml_text != NULL) { int len = strlen(xml_text); len++; /* null char */ crm_debug_3("Message size: %d", len); gnutls_record_send (*session, xml_text, len); } crm_free(xml_text); return NULL; } char* cib_recv_tls(gnutls_session *session) { int len = 0; char* buf = NULL; int chunk_size = 512; if (session == NULL) { return NULL; } crm_malloc0(buf, chunk_size); while(1) { int rc = gnutls_record_recv(*session, buf+len, chunk_size); if (rc == 0) { if(len == 0) { goto bail; } return buf; } else if(rc > 0 && rc < chunk_size) { return buf; } else if(rc == chunk_size) { len += chunk_size; crm_realloc(buf, len); CRM_ASSERT(buf != NULL); } if(rc < 0 && rc != GNUTLS_E_INTERRUPTED && rc != GNUTLS_E_AGAIN) { cl_perror("Error receiving message: %d", rc); goto bail; } } bail: crm_free(buf); return NULL; } #endif #define ERROR_SUFFIX " Shutting down remote listener" int init_remote_listener(int port) { int ssock; struct sockaddr_in saddr; int optval; if(port <= 0) { /* dont start it */ return 0; } #ifdef HAVE_GNUTLS_GNUTLS_H crm_notice("Starting a tls listener on port %d.", port); gnutls_global_init(); /* gnutls_global_set_log_level (10); */ gnutls_global_set_log_function (debug_log); gnutls_dh_params_init(&dh_params); gnutls_dh_params_generate2(dh_params, DH_BITS); gnutls_anon_allocate_server_credentials (&anon_cred); gnutls_anon_set_server_dh_params (anon_cred, dh_params); #else crm_warn("Starting a _plain_text_ listener on port %d.", port); #endif #ifndef HAVE_PAM crm_warn("PAM is _not_ enabled!"); #endif /* create server socket */ ssock = socket(AF_INET, SOCK_STREAM, 0); if (ssock == -1) { cl_perror("Can not create server socket."ERROR_SUFFIX); return -1; } /* reuse address */ optval = 1; setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); /* bind server socket*/ memset(&saddr, '\0', sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = INADDR_ANY; saddr.sin_port = htons(port); if (bind(ssock, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) { cl_perror("Can not bind server socket."ERROR_SUFFIX); return -2; } if (listen(ssock, 10) == -1) { cl_perror("Can not start listen."ERROR_SUFFIX); return -3; } G_main_add_fd(G_PRIORITY_HIGH, ssock, FALSE, cib_remote_listen, NULL, default_ipc_connection_destroy); return 0; } static int check_group_membership(const char* usr, const char* grp) { int index = 0; struct group *group = NULL; CRM_CHECK(usr != NULL, return FALSE); CRM_CHECK(grp != NULL, return FALSE); group = getgrnam(grp); if (group == NULL) { crm_err("No group named '%s' exists!", grp); return FALSE; } while (TRUE) { char* member = group->gr_mem[index++]; if(member == NULL) { break; } else if (crm_str_eq(usr, member, TRUE)) { return TRUE; } }; return FALSE; } #define WELCOME "" gboolean cib_remote_listen(int ssock, gpointer data) { int lpc = 0; int csock; unsigned laddr; char *msg = NULL; struct sockaddr_in addr; #ifdef HAVE_GNUTLS_GNUTLS_H gnutls_session *session = NULL; #endif cib_client_t *new_client = NULL; - crm_data_t *login = NULL; + xmlNode *login = NULL; const char *user = NULL; const char *pass = NULL; const char *tmp = NULL; cl_uuid_t client_id; char uuid_str[UU_UNPARSE_SIZEOF]; crm_debug("New connection"); /* accept the connection */ laddr = sizeof(addr); csock = accept(ssock, (struct sockaddr*)&addr, &laddr); if (csock == -1) { crm_err("accept socket failed"); return TRUE; } #ifdef HAVE_GNUTLS_GNUTLS_H /* create gnutls session for the server socket */ session = create_tls_session(csock); if (session == NULL) { crm_err("TLS session creation failed"); close(csock); return TRUE; } #endif do { crm_debug_2("Iter: %d", lpc++); #ifdef HAVE_GNUTLS_GNUTLS_H msg = cib_recv_remote_msg(session); #else msg = cib_recv_remote_msg(GINT_TO_POINTER(csock)); #endif sleep(1); } while(msg == NULL && lpc < 10); /* convert to xml */ login = string2xml(msg); crm_log_xml_info(login, "Login: "); if(login == NULL) { goto bail; } tmp = crm_element_name(login); if(safe_str_neq(tmp, "cib_command")) { crm_err("Wrong tag: %s", tmp); goto bail; } tmp = crm_element_value(login, "op"); if(safe_str_neq(tmp, "authenticate")) { crm_err("Wrong operation: %s", tmp); goto bail; } user = crm_element_value(login, "user"); pass = crm_element_value(login, "password"); if(check_group_membership(user, HA_APIGROUP) == FALSE) { crm_err("User is not a member of the required group"); goto bail; } else if (authenticate_user(user, pass) == FALSE) { crm_err("PAM auth failed"); goto bail; } /* send ACK */ crm_malloc0(new_client, sizeof(cib_client_t)); num_clients++; new_client->channel_name = "remote"; cl_uuid_generate(&client_id); cl_uuid_unparse(&client_id, uuid_str); CRM_CHECK(new_client->id == NULL, crm_free(new_client->id)); new_client->id = crm_strdup(uuid_str); new_client->callback_id = NULL; #ifdef HAVE_GNUTLS_GNUTLS_H new_client->channel = (void*)session; gnutls_record_send (*session, WELCOME, sizeof (WELCOME)); #else new_client->channel = GINT_TO_POINTER(csock); write(csock, WELCOME, sizeof (WELCOME)); #endif new_client->source = (void*)G_main_add_fd( G_PRIORITY_HIGH, csock, FALSE, cib_remote_msg, new_client, default_ipc_connection_destroy); g_hash_table_insert(client_list, new_client->id, new_client); return TRUE; bail: #ifdef HAVE_GNUTLS_GNUTLS_H gnutls_bye(*session, GNUTLS_SHUT_RDWR); gnutls_deinit(*session); gnutls_free(session); #endif close(csock); return TRUE; } gboolean cib_remote_msg(int csock, gpointer data) { cl_uuid_t call_id; char call_uuid[UU_UNPARSE_SIZEOF]; const char *value = NULL; - crm_data_t *command = NULL; + xmlNode *command = NULL; cib_client_t *client = data; char* msg = cib_recv_remote_msg(client->channel); if(msg == NULL) { return FALSE; } command = string2xml(msg); if(command == NULL) { crm_info("Could not parse command: %s", msg); goto bail; } crm_log_xml(LOG_MSG+1, "Command: ", command); value = crm_element_name(command); if(safe_str_neq(value, "cib_command")) { goto bail; } cl_uuid_generate(&call_id); cl_uuid_unparse(&call_id, call_uuid); crm_xml_add(command, F_TYPE, T_CIB); crm_xml_add(command, F_CIB_CLIENTID, client->id); crm_xml_add(command, F_CIB_CLIENTNAME, client->name); crm_xml_add(command, F_CIB_CALLID, call_uuid); if(crm_element_value(command, F_CIB_CALLOPTS) == NULL) { crm_xml_add_int(command, F_CIB_CALLOPTS, 0); } crm_log_xml(LOG_MSG, "Fixed Command: ", command); /* unset dangerous options */ xml_remove_prop(command, F_ORIG); xml_remove_prop(command, F_CIB_HOST); xml_remove_prop(command, F_CIB_GLOBAL_UPDATE); - value = cl_get_string(command, F_CIB_OPERATION); + value = crm_element_value(command, F_CIB_OPERATION); if(safe_str_eq(value, T_CIB_NOTIFY) ) { /* Update the notify filters for this client */ int on_off = 0; - ha_msg_value_int(command, F_CIB_NOTIFY_ACTIVATE, &on_off); - value = cl_get_string(command, F_CIB_NOTIFY_TYPE); + const char *on_off_s = crm_element_value(command, F_CIB_NOTIFY_ACTIVATE); + value = crm_element_value(command, F_CIB_NOTIFY_TYPE); + on_off = crm_parse_int(on_off_s, "0"); crm_info("Setting %s callbacks for %s: %s", value, client->name, on_off?"on":"off"); if(safe_str_eq(value, T_CIB_POST_NOTIFY)) { client->post_notify = on_off; } else if(safe_str_eq(value, T_CIB_PRE_NOTIFY)) { client->pre_notify = on_off; } else if(safe_str_eq(value, T_CIB_UPDATE_CONFIRM)) { client->confirmations = on_off; } else if(safe_str_eq(value, T_CIB_DIFF_NOTIFY)) { client->diffs = on_off; } else if(safe_str_eq(value, T_CIB_REPLACE_NOTIFY)) { client->replace = on_off; } goto bail; } - + cib_process_request(command, TRUE, TRUE, FALSE, client); - bail: free_xml(command); crm_free(msg); return TRUE; } #ifdef HAVE_PAM /* * Useful Examples: * http://www.kernel.org/pub/linux/libs/pam/Linux-PAM-html * http://developer.apple.com/samplecode/CryptNoMore/index.html */ static int construct_pam_passwd(int n, const struct pam_message **msg, struct pam_response **resp, void *data) { int i; char* passwd = (char*)data; struct pam_response *reply = NULL; crm_malloc0(reply, n * sizeof(*reply)); CRM_ASSERT(reply != NULL); /* Construct a PAM password message */ for (i = 0; i < n; ++i) { switch (msg[i]->msg_style) { case PAM_PROMPT_ECHO_OFF: case PAM_PROMPT_ECHO_ON: reply[i].resp = passwd; break; default: /* case PAM_ERROR_MSG: */ /* case PAM_TEXT_INFO: */ crm_err("Unhandled message type: %d", msg[i]->msg_style); goto bail; break; } } *resp = reply; return PAM_SUCCESS; bail: crm_free(reply); return PAM_CONV_ERR; } #endif int authenticate_user(const char* user, const char* passwd) { #ifndef HAVE_PAM gboolean pass = TRUE; #else gboolean pass = FALSE; int rc = 0; struct pam_handle *handle = NULL; struct pam_conv passwd_data; passwd_data.conv = construct_pam_passwd; passwd_data.appdata_ptr = strdup(passwd); rc = pam_start ("cib", user, &passwd_data, &handle); if (rc != PAM_SUCCESS) { goto bail; } rc = pam_authenticate (handle, 0); if(rc != PAM_SUCCESS) { crm_err("pam_authenticate: %s (%d)", pam_strerror(handle, rc), rc); goto bail; } rc = pam_acct_mgmt(handle, 0); /* permitted access? */ if(rc != PAM_SUCCESS) { crm_err("pam_acct: %s (%d)", pam_strerror(handle, rc), rc); goto bail; } pass = TRUE; bail: rc = pam_end (handle, rc); #endif return pass; } char* -cib_send_plaintext(int sock, HA_Message *msg) +cib_send_plaintext(int sock, xmlNode *msg) { char *xml_text = NULL; - ha_msg_mod(msg, F_XML_TAGNAME, "cib_result"); - crm_log_xml(LOG_DEBUG_2, "Result: ", msg); + msg->name = xmlCharStrdup("cib_result"); xml_text = dump_xml_unformatted(msg); if(xml_text != NULL) { int rc = 0; int len = strlen(xml_text); len++; /* null char */ crm_debug_3("Message size: %d", len); rc = write (sock, xml_text, len); CRM_CHECK(len == rc, crm_warn("Wrote %d of %d bytes", rc, len)); } crm_free(xml_text); return NULL; } char* cib_recv_plaintext(int sock) { int len = 0; char* buf = NULL; int chunk_size = 512; crm_malloc0(buf, chunk_size); while(1) { int rc = recv(sock, buf+len, chunk_size, 0); if (rc == 0) { if(len == 0) { goto bail; } return buf; } else if(rc > 0 && rc < chunk_size) { return buf; } else if(rc == chunk_size) { len += chunk_size; crm_realloc(buf, len); CRM_ASSERT(buf != NULL); } if(rc < 0 && errno != EINTR) { cl_perror("Error receiving message: %d", rc); goto bail; } } bail: crm_free(buf); return NULL; } void -cib_send_remote_msg(void *session, HA_Message *msg) +cib_send_remote_msg(void *session, xmlNode *msg) { #ifdef HAVE_GNUTLS_GNUTLS_H cib_send_tls(session, msg); #else cib_send_plaintext(GPOINTER_TO_INT(session), msg); #endif } char * cib_recv_remote_msg(void *session) { #ifdef HAVE_GNUTLS_GNUTLS_H return cib_recv_tls(session); #else return cib_recv_plaintext(GPOINTER_TO_INT(session)); #endif } diff --git a/crm/admin/cibadmin.c b/crm/admin/cibadmin.c index fe0e60c350..c7bd09d9b1 100644 --- a/crm/admin/cibadmin.c +++ b/crm/admin/cibadmin.c @@ -1,574 +1,572 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_GETOPT_H # include #endif #include /* someone complaining about _ha_msg_mod not being found */ int exit_code = cib_ok; int message_timer_id = -1; int message_timeout_ms = 30; GMainLoop *mainloop = NULL; IPC_Channel *crmd_channel = NULL; const char *host = NULL; void usage(const char *cmd, int exit_status); enum cib_errors do_init(void); -int do_work(crm_data_t *input, int command_options, crm_data_t **output); +int do_work(xmlNode *input, int command_options, xmlNode **output); gboolean admin_msg_callback(IPC_Channel * source_data, void *private_data); gboolean admin_message_timeout(gpointer data); void cib_connection_destroy(gpointer user_data); -void cibadmin_op_callback(const HA_Message *msg, int call_id, int rc, - crm_data_t *output, void *user_data); +void cibadmin_op_callback(xmlNode *msg, int call_id, int rc, + xmlNode *output, void *user_data); int command_options = 0; const char *cib_action = NULL; typedef struct str_list_s { int num_items; char *value; struct str_list_s *next; } str_list_t; char *this_msg_reference = NULL; char *obj_type = NULL; char *status = NULL; char *migrate_from = NULL; char *migrate_res = NULL; char *subtype = NULL; char *reset = NULL; int request_id = 0; int operation_status = 0; cib_t *the_cib = NULL; gboolean force_flag = FALSE; #define OPTARGS "V?o:QDUCEX:t:Srwlsh:MmBfbdRx:pP5" int main(int argc, char **argv) { int argerr = 0; int flag; char *admin_input_xml = NULL; char *admin_input_file = NULL; gboolean dangerous_cmd = FALSE; gboolean admin_input_stdin = FALSE; - crm_data_t *output = NULL; - crm_data_t *input = NULL; + xmlNode *output = NULL; + xmlNode *input = NULL; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {CIB_OP_ERASE, 0, 0, 'E'}, {CIB_OP_QUERY, 0, 0, 'Q'}, {CIB_OP_CREATE, 0, 0, 'C'}, {CIB_OP_REPLACE, 0, 0, 'R'}, {CIB_OP_UPDATE, 0, 0, 'U'}, {CIB_OP_MODIFY, 0, 0, 'M'}, {"patch", 0, 0, 'P'}, {CIB_OP_DELETE, 0, 0, 'D'}, {CIB_OP_DELETE_ALT, 0, 0, 'd'}, {CIB_OP_BUMP, 0, 0, 'B'}, {CIB_OP_SYNC, 0, 0, 'S'}, {CIB_OP_SLAVE, 0, 0, 'r'}, {CIB_OP_MASTER, 0, 0, 'w'}, {CIB_OP_ISMASTER,0, 0, 'm'}, {"md5-sum", 0, 0, '5'}, {"force-quorum",0, 0, 'f'}, {"force", 0, 0, 'f'}, {"local", 0, 0, 'l'}, {"sync-call", 0, 0, 's'}, {"no-bcast", 0, 0, 'b'}, {"host", 0, 0, 'h'}, {F_CRM_DATA, 1, 0, 'X'}, {"xml-file", 1, 0, 'x'}, {"xml-pipe", 0, 0, 'p'}, {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"reference", 1, 0, 0}, {"timeout", 1, 0, 't'}, /* common options */ {"obj_type", 1, 0, 'o'}, {0, 0, 0, 0} }; #endif crm_log_init("cibadmin", LOG_CRIT, FALSE, FALSE, argc, argv); if(argc < 2) { usage(crm_system_name, LSB_EXIT_EINVAL); } 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"); if (safe_str_eq("reference", long_options[option_index].name)) { this_msg_reference = crm_strdup(optarg); } else { printf("Long option (--%s) is not (yet?) properly supported\n", long_options[option_index].name); ++argerr; } break; #endif case 't': message_timeout_ms = atoi(optarg); if(message_timeout_ms < 1) { message_timeout_ms = 30; } break; case 'E': cib_action = CIB_OP_ERASE; dangerous_cmd = TRUE; break; case 'Q': cib_action = CIB_OP_QUERY; break; case 'P': cib_action = CIB_OP_APPLY_DIFF; break; case 'S': cib_action = CIB_OP_SYNC; break; case 'U': case 'M': cib_action = CIB_OP_MODIFY; break; case 'R': cib_action = CIB_OP_REPLACE; break; case 'C': cib_action = CIB_OP_CREATE; break; case 'D': cib_action = CIB_OP_DELETE; break; case '5': cib_action = "md5-sum"; break; case 'd': cib_action = CIB_OP_DELETE_ALT; break; case 'm': cib_action = CIB_OP_ISMASTER; command_options |= cib_scope_local; break; case 'B': cib_action = CIB_OP_BUMP; break; case 'r': dangerous_cmd = TRUE; cib_action = CIB_OP_SLAVE; break; case 'w': dangerous_cmd = TRUE; cib_action = CIB_OP_MASTER; command_options |= cib_scope_local; break; case 'V': command_options = command_options | cib_verbose; cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case '?': usage(crm_system_name, LSB_EXIT_OK); break; case 'o': crm_debug_2("Option %c => %s", flag, optarg); obj_type = crm_strdup(optarg); break; case 'X': crm_debug_2("Option %c => %s", flag, optarg); admin_input_xml = crm_strdup(optarg); break; case 'x': crm_debug_2("Option %c => %s", flag, optarg); admin_input_file = crm_strdup(optarg); break; case 'p': admin_input_stdin = TRUE; break; case 'h': host = crm_strdup(optarg); break; case 'l': command_options |= cib_scope_local; break; case 'b': dangerous_cmd = TRUE; command_options |= cib_inhibit_bcast; command_options |= cib_scope_local; break; case 's': command_options |= cib_sync_call; break; case 'f': force_flag = TRUE; command_options |= cib_quorum_override; 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"); usage(crm_system_name, LSB_EXIT_EINVAL); } if (optind > argc || cib_action == NULL) { ++argerr; } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } if(dangerous_cmd && force_flag == FALSE) { fprintf(stderr, "The supplied command is considered dangerous." " To prevent accidental destruction of the cluster," " the --force flag is required in order to proceed.\n"); fflush(stderr); usage(crm_system_name, LSB_EXIT_GENERIC); } if(admin_input_file != NULL) { FILE *xml_strm = fopen(admin_input_file, "r"); input = file2xml(xml_strm, FALSE); if(input == NULL) { fprintf(stderr, "Couldn't parse input file: %s\n", admin_input_file); return 1; } fclose(xml_strm); } else if(admin_input_xml != NULL) { input = string2xml(admin_input_xml); if(input == NULL) { fprintf(stderr, "Couldn't parse input string: %s\n", admin_input_xml); return 1; } } else if(admin_input_stdin) { input = stdin2xml(); if(input == NULL) { fprintf(stderr, "Couldn't parse input from STDIN.\n"); return 1; } } if(input != NULL) { crm_log_xml_debug(input, "[admin input]"); } if(safe_str_eq(cib_action, "md5-sum")) { char *digest = NULL; if(input == NULL) { fprintf(stderr, "Please supply XML to process with -X, -x or -p\n"); exit(1); } digest = calculate_xml_digest(input, FALSE, FALSE); fprintf(stderr, "Digest: "); fprintf(stdout, "%s\n", crm_str(digest)); crm_free(digest); exit(0); } exit_code = do_init(); if(exit_code != cib_ok) { crm_err("Init failed, could not perform requested operations"); fprintf(stderr, "Init failed, could not perform requested operations\n"); return -exit_code; } exit_code = do_work(input, command_options, &output); if (exit_code > 0) { /* wait for the reply by creating a mainloop and running it until * the callbacks are invoked... */ request_id = exit_code; add_cib_op_callback_timeout( request_id, message_timeout_ms, FALSE, NULL, cibadmin_op_callback); mainloop = g_main_new(FALSE); crm_debug_3("%s waiting for reply from the local CIB", crm_system_name); crm_info("Starting mainloop"); g_main_run(mainloop); } else if(exit_code < 0) { crm_err("Call failed: %s", cib_error2string(exit_code)); fprintf(stderr, "Call failed: %s\n", cib_error2string(exit_code)); operation_status = exit_code; } if(output != NULL) { char *buffer = dump_xml_formatted(output); fprintf(stdout, "%s", crm_str(buffer)); crm_free(buffer); } crm_debug_3("%s exiting normally", crm_system_name); return -exit_code; } int -do_work(crm_data_t *input, int call_options, crm_data_t **output) +do_work(xmlNode *input, int call_options, xmlNode **output) { /* construct the request */ the_cib->call_timeout = message_timeout_ms; if (strcasecmp(CIB_OP_SYNC, cib_action) == 0) { crm_debug_4("Performing %s op...", cib_action); return the_cib->cmds->sync_from( the_cib, host, obj_type, call_options); } else if (strcasecmp(CIB_OP_SLAVE, cib_action) == 0 && (call_options ^ cib_scope_local) ) { crm_debug_4("Performing %s op on all nodes...", cib_action); return the_cib->cmds->set_slave_all(the_cib, call_options); } else if (strcasecmp(CIB_OP_MASTER, cib_action) == 0) { crm_debug_4("Performing %s op on all nodes...", cib_action); return the_cib->cmds->set_master(the_cib, call_options); } else if(cib_action != NULL) { crm_debug_4("Passing \"%s\" to variant_op...", cib_action); if(strcasecmp(CIB_OP_APPLY_DIFF, cib_action) != 0 && input != NULL && do_id_check(input, NULL, TRUE, FALSE)) { crm_err("ID Check failed."); return cib_id_check; } return the_cib->cmds->variant_op( the_cib, cib_action, host, obj_type, input, output, call_options); } else { crm_err("You must specify an operation"); } return cib_operation; } enum cib_errors do_init(void) { enum cib_errors rc = cib_ok; the_cib = cib_new(); rc = the_cib->cmds->signon(the_cib, crm_system_name, cib_command); if(rc != cib_ok) { crm_err("Signon to CIB failed: %s", cib_error2string(rc)); fprintf(stderr, "Signon to CIB failed: %s\n", cib_error2string(rc)); } return rc; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status != 0 ? stderr : stdout; fprintf(stream, "usage: %s [%s] command\n" "\twhere necessary, XML data will be obtained using -X," " -x, or -p options\n", cmd, OPTARGS); fprintf(stream, "Options\n"); fprintf(stream, "\t--%s (-%c) \tobject type being operated on\n", "obj_type", 'o'); fprintf(stream, "\t\tValid values are: nodes, resources, constraints, crm_config, status\n"); 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)\tErase the contents of the whole CIB\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)\tCalculate an XML file's digest." " Requires either -X, -x or -p\n", "md5-sum", '5'); fprintf(stream, "\t--%s (-%c)\tRecursivly replace an object in the CIB\n", CIB_OP_REPLACE,'R'); fprintf(stream, "\t--%s (-%c)\tRecursivly update an object in the CIB\n", CIB_OP_UPDATE, 'U'); fprintf(stream, "\t--%s (-%c)\tFind the object somewhere in the CIB's XML tree and update is as --"CIB_OP_UPDATE" would\n", CIB_OP_MODIFY, 'M'); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_DELETE, 'D'); fprintf(stream, "\t\t\tDelete the first object matching the supplied criteria\n"); fprintf(stream, "\t\t\tEg. \n"); fprintf(stream, "\t\t\tThe tagname and all attributes must match in order for the element to be deleted\n"); fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_DELETE_ALT, 'd'); fprintf(stream, "\t\t\tDelete the object at specified fully qualified location\n"); fprintf(stream, "\t\t\tEg. ...\n"); fprintf(stream, "\t\t\tRequires -o\n"); 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) \t\tRetrieve XML from the supplied string\n", F_CRM_DATA, 'X'); fprintf(stream, "\t--%s (-%c) \tRetrieve XML from the named file\n", "xml-file", 'x'); fprintf(stream, "\t--%s (-%c)\t\t\tRetrieve XML from STDIN\n", "xml-pipe", 'p'); 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, CIB_OP_SYNC); fprintf(stream, "\t--%s (-%c)\tcommand takes effect locally" " on the specified host\n", "local", 'l'); fprintf(stream, "\t--%s (-%c)\tcommand will not be broadcast even if" " it altered the CIB\n", "no-bcast", 'b'); fprintf(stream, "\t--%s (-%c)\twait for call to complete before" " returning\n", "sync-call", 's'); 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; } void -cibadmin_op_callback(const HA_Message *msg, int call_id, int rc, - crm_data_t *output, void *user_data) +cibadmin_op_callback(xmlNode *msg, int call_id, int rc, + xmlNode *output, void *user_data) { char *admin_input_xml = NULL; - crm_info("our callback was invoked"); - crm_log_message(LOG_MSG, msg); exit_code = rc; if(output != NULL) { admin_input_xml = dump_xml_formatted(output); } if(safe_str_eq(cib_action, CIB_OP_ISMASTER) && rc != cib_ok) { crm_info("CIB on %s is _not_ the master instance", host?host:"localhost"); fprintf(stderr, "CIB on %s is _not_ the master instance\n", host?host:"localhost"); } else if(safe_str_eq(cib_action, CIB_OP_ISMASTER)) { crm_info("CIB on %s _is_ the master instance", host?host:"localhost"); fprintf(stderr, "CIB on %s _is_ the master instance\n", host?host:"localhost"); } else if(rc != 0) { crm_warn("Call %s failed (%d): %s", cib_action, rc, cib_error2string(rc)); fprintf(stderr, "Call %s failed (%d): %s\n", cib_action, rc, cib_error2string(rc)); fprintf(stdout, "%s\n", crm_str(admin_input_xml)); } else if(safe_str_eq(cib_action, CIB_OP_QUERY) && output==NULL) { crm_err("Output expected in query response"); - crm_log_message(LOG_ERR, msg); + crm_log_xml(LOG_ERR, "no output", msg); } else if(output == NULL) { crm_info("Call passed"); } else { crm_info("Call passed"); fprintf(stdout, "%s\n", crm_str(admin_input_xml)); } crm_free(admin_input_xml); if(call_id == request_id) { g_main_quit(mainloop); } else { crm_info("Message was not the response we were looking for (%d vs. %d", call_id, request_id); } } diff --git a/crm/admin/crm_mon.c b/crm/admin/crm_mon.c index 2fbdd94877..5eebd1cd95 100644 --- a/crm/admin/crm_mon.c +++ b/crm/admin/crm_mon.c @@ -1,830 +1,830 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_GETOPT_H # include #endif /* GMainLoop *mainloop = NULL; */ #define OPTARGS "V?i:nrh:cdp:s1wX:" void usage(const char *cmd, int exit_status); void blank_screen(void); -int print_status(crm_data_t *cib); +int print_status(xmlNode *cib); void print_warn(const char *descr); -int print_simple_status(crm_data_t *cib); +int print_simple_status(xmlNode *cib); /* #define printw_at(line, fmt...) move(line, 0); printw(fmt); line++ */ void wait_for_refresh(int offset, const char *prefix, int msec); -int print_html_status(crm_data_t *cib, const char *filename, gboolean web_cgi); +int print_html_status(xmlNode *cib, const char *filename, gboolean web_cgi); void make_daemon(gboolean daemonize, const char *pidfile); gboolean mon_timer_popped(gpointer data); -void mon_update(const HA_Message*, int, int, crm_data_t*,void*); +void mon_update(xmlNode*, int, int, xmlNode*,void*); char *xml_file = NULL; char *as_html_file = NULL; char *pid_file = NULL; gboolean as_console = FALSE; gboolean simple_status = FALSE; gboolean group_by_node = FALSE; gboolean inactive_resources = FALSE; gboolean web_cgi = FALSE; int interval = 15000; gboolean daemonize = FALSE; GMainLoop* mainloop = NULL; guint timer_id = 0; cib_t *cib_conn = NULL; int failed_connections = 0; gboolean one_shot = FALSE; gboolean has_warnings = FALSE; #if CURSES_ENABLED # define print_as(fmt...) if(as_console) { \ printw(fmt); \ } else { \ fprintf(stdout, fmt); \ } #else # define print_as(fmt...) fprintf(stdout, fmt); #endif int main(int argc, char **argv) { int argerr = 0; int flag; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"interval", 1, 0, 'i'}, {"group-by-node", 0, 0, 'n'}, {"inactive", 0, 0, 'r'}, {"as-html", 1, 0, 'h'}, {"web-cgi", 0, 0, 'w'}, {"simple-status", 0, 0, 's'}, {"as-console", 0, 0, 'c'}, {"one-shot", 0, 0, '1'}, {"daemonize", 0, 0, 'd'}, {"pid-file", 0, 0, 'p'}, {"xml-file", 1, 0, 'X'}, {0, 0, 0, 0} }; #endif pid_file = crm_strdup("/tmp/ClusterMon.pid"); crm_log_init(basename(argv[0]), LOG_ERR-1, FALSE, FALSE, 0, NULL); if (strcmp(crm_system_name, "crm_mon.cgi")==0) { web_cgi = TRUE; one_shot = TRUE; } 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) { case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case 'i': interval = crm_get_msec(optarg); break; case 'n': group_by_node = TRUE; break; case 'r': inactive_resources = TRUE; break; case 'd': daemonize = TRUE; break; case 'p': pid_file = crm_strdup(optarg); break; case 'X': xml_file = crm_strdup(optarg); one_shot = TRUE; break; case 'h': as_html_file = crm_strdup(optarg); break; case 'w': web_cgi = TRUE; one_shot = TRUE; break; case 'c': #if CURSES_ENABLED as_console = TRUE; #else printf("You need to have curses available at compile time to enable console mode\n"); argerr++; #endif break; case 's': simple_status = TRUE; one_shot = TRUE; break; case '1': one_shot = 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 (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } if(as_html_file == NULL && !web_cgi && !simple_status) { #if CURSES_ENABLED as_console = TRUE; #else printf("Defaulting to one-shot mode\n"); printf("You need to have curses available at compile time to enable console mode\n"); one_shot = TRUE; #endif } if(daemonize) { as_console = FALSE; } if(one_shot) { daemonize = FALSE; as_console = FALSE; } if(daemonize && as_html_file == NULL) { usage(crm_system_name, LSB_EXIT_GENERIC); } make_daemon(daemonize, pid_file); #if CURSES_ENABLED if(as_console) { initscr(); cbreak(); noecho(); } #endif crm_info("Starting %s", crm_system_name); mainloop = g_main_new(FALSE); if(one_shot == FALSE) { timer_id = Gmain_timeout_add( interval, mon_timer_popped, NULL); } else if(xml_file != NULL) { FILE *xml_strm = fopen(xml_file, "r"); - crm_data_t *cib_object = NULL; + xmlNode *cib_object = NULL; if(strstr(xml_file, ".bz2") != NULL) { cib_object = file2xml(xml_strm, TRUE); } else { cib_object = file2xml(xml_strm, FALSE); } if(xml_strm != NULL) { fclose(xml_strm); } one_shot = TRUE; mon_update(NULL, 0, cib_ok, cib_object, NULL); } mon_timer_popped(NULL); g_main_run(mainloop); return_to_orig_privs(); crm_info("Exiting %s", crm_system_name); #if CURSES_ENABLED if(as_console) { echo(); nocbreak(); endwin(); } #endif return 0; } gboolean mon_timer_popped(gpointer data) { int rc = cib_ok; int options = cib_scope_local; if(timer_id > 0) { Gmain_timeout_remove(timer_id); } if(as_console) { #if CURSES_ENABLED move(0, 0); printw("Updating...\n"); clrtoeol(); refresh(); #endif } else { crm_notice("Updating..."); } if(cib_conn == NULL) { crm_debug_4("Creating CIB connection"); cib_conn = cib_new(); } CRM_DEV_ASSERT(cib_conn != NULL); if(crm_assert_failed) { return FALSE; } else if(cib_conn->state != cib_connected_query){ crm_debug_4("Connecting to the CIB"); #if CURSES_ENABLED if(as_console) { printw("Signing on...\n"); clrtoeol(); refresh(); } #endif if(cib_ok == cib_conn->cmds->signon( cib_conn, crm_system_name, cib_query)) { failed_connections = 0; } else if (simple_status || one_shot) { fprintf(stdout, "Critical: Unable to connect to the CIB\n"); exit(2); } else { failed_connections++; CRM_DEV_ASSERT(cib_conn->cmds->signoff(cib_conn) == cib_ok); wait_for_refresh(0, "Not connected: ", 2*interval); return FALSE; } #if CURSES_ENABLED if(as_console) { printw("Querying...\n"); clrtoeol(); refresh(); } #endif } if(as_console) { blank_screen(); } rc = cib_conn->cmds->query(cib_conn, NULL, NULL, options); add_cib_op_callback(rc, FALSE, NULL, mon_update); return FALSE; } void -mon_update(const HA_Message *msg, int call_id, int rc, - crm_data_t *output, void*user_data) +mon_update(xmlNode *msg, int call_id, int rc, + xmlNode *output, void*user_data) { const char *prefix = NULL; if(rc == cib_ok) { - crm_data_t *cib = NULL; + xmlNode *cib = NULL; #if CRM_DEPRECATED_SINCE_2_0_4 if( safe_str_eq(crm_element_name(output), XML_TAG_CIB) ) { cib = output; } else { cib = find_xml_node(output,XML_TAG_CIB,TRUE); } #else cib = output; CRM_DEV_ASSERT(safe_str_eq(crm_element_name(cib), XML_TAG_CIB)); #endif if(as_html_file || web_cgi) { print_html_status(cib, as_html_file, web_cgi); } else if (simple_status) { print_simple_status(cib); if (has_warnings) { exit(1); } } else { print_status(cib); } if(one_shot) { exit(LSB_EXIT_OK); } } else if(simple_status) { fprintf(stderr, "Critical: query failed: %s", cib_error2string(rc)); exit(2); } else if(one_shot) { fprintf(stderr, "Query failed: %s", cib_error2string(rc)); exit(LSB_EXIT_OK); } else { CRM_DEV_ASSERT(cib_conn->cmds->signoff(cib_conn) == cib_ok); crm_err("Query failed: %s", cib_error2string(rc)); prefix = "Query failed! "; } wait_for_refresh(0, prefix, interval); } void wait_for_refresh(int offset, const char *prefix, int msec) { int lpc = msec / 1000; if(as_console == FALSE) { timer_id = Gmain_timeout_add(msec, mon_timer_popped, NULL); return; } crm_notice("%sRefresh in %ds...", prefix?prefix:"", lpc); while(lpc > 0) { #if CURSES_ENABLED move(0, 0); /* printw("%sRefresh in \033[01;32m%ds\033[00m...", prefix?prefix:"", lpc); */ printw("%sRefresh in %ds...\n", prefix?prefix:"", lpc); clrtoeol(); refresh(); #endif lpc--; if(lpc == 0) { timer_id = Gmain_timeout_add( 1000, mon_timer_popped, NULL); } else { sleep(1); } } } #define mon_warn(fmt...) do { \ if (!has_warnings) { \ print_as("Warning:"); \ } else { \ print_as(","); \ } \ print_as(fmt); \ has_warnings = TRUE; \ } while(0) int -print_simple_status(crm_data_t *cib) +print_simple_status(xmlNode *cib) { node_t *dc = NULL; int nodes_online = 0; int nodes_standby = 0; pe_working_set_t data_set; set_working_set_defaults(&data_set); data_set.input = cib; cluster_status(&data_set); dc = data_set.dc_node; if(dc == NULL) { mon_warn("No DC "); } slist_iter(node, node_t, data_set.nodes, lpc2, if(node->details->standby) { nodes_standby++; } else if(node->details->online) { nodes_online++; } else { mon_warn("offline node: %s", node->details->uname); } ); if (!has_warnings) { print_as("Ok: %d nodes online", nodes_online); if (nodes_standby > 0) { print_as(", %d standby nodes", nodes_standby); } print_as(", %d resources configured", g_list_length(data_set.resources)); } print_as("\n"); data_set.input = NULL; cleanup_calculations(&data_set); return 0; } int -print_status(crm_data_t *cib) +print_status(xmlNode *cib) { node_t *dc = NULL; static int updates = 0; pe_working_set_t data_set; char *since_epoch = NULL; time_t a_time = time(NULL); int configured_resources = 0; int print_opts = pe_print_ncurses; if(as_console) { blank_screen(); } else { print_opts = pe_print_printf; } updates++; set_working_set_defaults(&data_set); data_set.input = cib; cluster_status(&data_set); dc = data_set.dc_node; print_as("\n\n============\n"); if(a_time == (time_t)-1) { cl_perror("set_node_tstamp(): Invalid time returned"); return 1; } since_epoch = ctime(&a_time); if(since_epoch != NULL) { print_as("Last updated: %s", since_epoch); } if(dc == NULL) { print_as("Current DC: NONE\n"); } else { print_as("Current DC: %s (%s)\n", dc->details->uname, dc->details->id); } slist_iter(rsc, resource_t, data_set.resources, lpc, if(is_not_set(rsc->flags, pe_rsc_orphan)) { configured_resources++; } ); print_as("%d Nodes configured.\n", g_list_length(data_set.nodes)); print_as("%d Resources configured.\n", configured_resources); print_as("============\n\n"); slist_iter(node, node_t, data_set.nodes, lpc2, const char *node_mode = "OFFLINE"; if(node->details->standby && node->details->online) { node_mode = "standby"; } else if(node->details->standby) { node_mode = "OFFLINE(standby)"; } else if(node->details->online) { node_mode = "online"; } print_as("Node: %s (%s): %s\n", node->details->uname, node->details->id, node_mode); if(group_by_node) { slist_iter(rsc, resource_t, node->details->running_rsc, lpc2, rsc->fns->print( rsc, "\t", print_opts|pe_print_rsconly, stdout); ); } ); if(group_by_node == FALSE && inactive_resources) { print_as("\nFull list of resources:\n"); } else if(inactive_resources) { print_as("\nInactive resources:\n"); } if(group_by_node == FALSE || inactive_resources) { print_as("\n"); slist_iter(rsc, resource_t, data_set.resources, lpc2, gboolean is_active = rsc->fns->active(rsc, TRUE); gboolean partially_active = rsc->fns->active(rsc, FALSE); if(is_set(rsc->flags, pe_rsc_orphan) && is_active == FALSE) { continue; } else if(group_by_node == FALSE) { if(partially_active || inactive_resources) { rsc->fns->print(rsc, NULL, print_opts, stdout); } } else if(is_active == FALSE && inactive_resources) { rsc->fns->print(rsc, NULL, print_opts, stdout); } ); } if(xml_has_children(data_set.failed)) { print_as("\nFailed actions:\n"); xml_child_iter(data_set.failed, xml_op, const char *id = ID(xml_op); const char *rc = crm_element_value(xml_op, XML_LRM_ATTR_RC); const char *node = crm_element_value(xml_op, XML_ATTR_UNAME); const char *last = crm_element_value(xml_op, "last_run"); const char *call = crm_element_value(xml_op, XML_LRM_ATTR_CALLID); const char *status_s = crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS); int status = crm_parse_int(status_s, "0"); print_as(" %s (node=%s, call=%s, rc=%s", id, node, call, rc); if(last) { time_t run_at = crm_parse_int(last, "0"); print_as(", last-run=%s, queued=%sms, exec=%sms\n", ctime(&run_at), crm_element_value(xml_op, "exec_time"), crm_element_value(xml_op, "queue_time")); } print_as("): %s\n", op_status2text(status)); ); } #if CURSES_ENABLED if(as_console) { refresh(); } #endif data_set.input = NULL; cleanup_calculations(&data_set); return 0; } int -print_html_status(crm_data_t *cib, const char *filename, gboolean web_cgi) +print_html_status(xmlNode *cib, const char *filename, gboolean web_cgi) { FILE *stream; node_t *dc = NULL; static int updates = 0; pe_working_set_t data_set; char *filename_tmp = NULL; if (web_cgi) { stream=stdout; fprintf(stream, "Content-type: text/html\n\n"); } else { filename_tmp = crm_concat(filename, "tmp", '.'); stream = fopen(filename_tmp, "w"); cl_perror("Cannot open %s for writing", filename_tmp); if(stream == NULL) { crm_free(filename_tmp); return -1; } } updates++; set_working_set_defaults(&data_set); data_set.input = cib; cluster_status(&data_set); dc = data_set.dc_node; fprintf(stream, ""); fprintf(stream, ""); fprintf(stream, "Cluster status"); /* content="%d;url=http://webdesign.about.com" */ fprintf(stream, "", interval); fprintf(stream, ""); /*** SUMMARY ***/ fprintf(stream, "

Cluster summary

"); { char *now_str = NULL; time_t now = time(NULL); now_str = ctime(&now); now_str[24] = EOS; /* replace the newline */ fprintf(stream, "Last updated: %s
\n", now_str); } if(dc == NULL) { fprintf(stream, "Current DC: NONE
"); } else { fprintf(stream, "Current DC: %s (%s)
", dc->details->uname, dc->details->id); } fprintf(stream, "%d Nodes configured.
", g_list_length(data_set.nodes)); fprintf(stream, "%d Resources configured.
", g_list_length(data_set.resources)); /*** CONFIG ***/ fprintf(stream, "

Config Options

\n"); fprintf(stream, "\n"); fprintf(stream, "\n", data_set.default_resource_stickiness); fprintf(stream, "\n", data_set.stonith_enabled?"enabled":"disabled"); fprintf(stream, "\n", data_set.symmetric_cluster?"":"a-"); fprintf(stream, "\n
Default resource stickiness:%d
STONITH of failed nodes:%s
Cluster is:%ssymmetric
No Quorum Policy:"); switch (data_set.no_quorum_policy) { case no_quorum_freeze: fprintf(stream, "Freeze resources"); break; case no_quorum_stop: fprintf(stream, "Stop ALL resources"); break; case no_quorum_ignore: fprintf(stream, "Ignore"); break; } fprintf(stream, "\n
\n"); /*** NODE LIST ***/ fprintf(stream, "

Node List

\n"); fprintf(stream, "
    \n"); slist_iter(node, node_t, data_set.nodes, lpc2, fprintf(stream, "
  • "); fprintf(stream, "Node: %s (%s): %s", node->details->uname, node->details->id, node->details->online?"online\n":"OFFLINE\n"); if(group_by_node) { fprintf(stream, "
      \n"); slist_iter(rsc, resource_t, node->details->running_rsc, lpc2, fprintf(stream, "
    • "); rsc->fns->print(rsc, NULL, pe_print_html, stream); fprintf(stream, "
    • \n"); ); fprintf(stream, "
    \n"); } fprintf(stream, "
  • \n"); ); fprintf(stream, "
\n"); if(group_by_node && inactive_resources) { fprintf(stream, "

(Partially) Inactive Resources

\n"); } else if(group_by_node == FALSE) { fprintf(stream, "

Resource List

\n"); } if(group_by_node == FALSE || inactive_resources) { slist_iter(rsc, resource_t, data_set.resources, lpc2, if(group_by_node && rsc->fns->active(rsc, TRUE)) { continue; } rsc->fns->print(rsc, NULL, pe_print_html, stream); ); } data_set.input = NULL; cleanup_calculations(&data_set); fprintf(stream, ""); fflush(stream); fclose(stream); if (!web_cgi) { if(rename(filename_tmp, filename) != 0) { cl_perror("Unable to rename %s->%s", filename_tmp, filename); } crm_free(filename_tmp); } return 0; } void blank_screen(void) { #if CURSES_ENABLED int lpc = 0; for(lpc = 0; lpc < LINES; lpc++) { move(lpc, 0); clrtoeol(); } move(0, 0); #endif } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-%s]\n", cmd, OPTARGS); fprintf(stream, "\t--%s (-%c) \t: This text\n", "help", '?'); fprintf(stream, "\t--%s (-%c) \t: Increase the debug output\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c) \t: Update frequency\n", "interval", 'i'); fprintf(stream, "\t--%s (-%c) \t:Group resources by node\n", "group-by-node", 'n'); fprintf(stream, "\t--%s (-%c) \t:Display inactive resources\n", "inactive", 'r'); fprintf(stream, "\t--%s (-%c) \t: Display cluster status on the console\n", "as-console", 'c'); fprintf(stream, "\t--%s (-%c) \t: Display the cluster status once as " "a simple one line output (suitable for nagios)\n", "simple-status", 's'); fprintf(stream, "\t--%s (-%c) \t: Display the cluster status once on " "the console and exit (doesnt use ncurses)\n", "one-shot", '1'); fprintf(stream, "\t--%s (-%c) \t: Write cluster status to the named file\n", "as-html", 'h'); fprintf(stream, "\t--%s (-%c) \t: Web mode with output suitable for cgi\n", "web-cgi", 'w'); fprintf(stream, "\t--%s (-%c) \t: Run in the background as a daemon\n", "daemonize", 'd'); fprintf(stream, "\t--%s (-%c) \t: Daemon pid file location\n", "pid-file", 'p'); fflush(stream); exit(exit_status); } void make_daemon(gboolean daemonize, const char *pidfile) { long pid; const char *devnull = "/dev/null"; if (daemonize == FALSE){ return; } pid = fork(); if (pid < 0) { fprintf(stderr, "%s: could not start daemon\n", crm_system_name); perror("fork"); exit(LSB_EXIT_GENERIC); } else if (pid > 0) { exit(LSB_EXIT_OK); } if (cl_lock_pidfile(pidfile) < 0 ){ pid = cl_read_pidfile(pidfile); fprintf(stderr, "%s: already running [pid %ld].\n", crm_system_name, pid); exit(LSB_EXIT_OK); } umask(022); close(0); close(1); close(2); (void)open(devnull, O_RDONLY); /* Stdin: fd 0 */ (void)open(devnull, O_WRONLY); /* Stdout: fd 1 */ (void)open(devnull, O_WRONLY); /* Stderr: fd 2 */ } diff --git a/crm/admin/crm_resource.c b/crm/admin/crm_resource.c index 55cfcae7e8..6b8828b460 100644 --- a/crm/admin/crm_resource.c +++ b/crm/admin/crm_resource.c @@ -1,1381 +1,1365 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_GETOPT_H # include #endif void usage(const char *cmd, int exit_status); gboolean do_force = FALSE; gboolean BE_QUIET = FALSE; const char *attr_set_type = XML_TAG_ATTR_SETS; char *host_id = NULL; const char *rsc_id = NULL; const char *host_uname = NULL; const char *prop_name = NULL; const char *prop_value = NULL; const char *rsc_type = NULL; const char *prop_id = NULL; const char *prop_set = NULL; char *migrate_lifetime = NULL; char rsc_cmd = 'L'; char *our_pid = NULL; IPC_Channel *crmd_channel = NULL; char *xml_file = NULL; int cib_options = cib_sync_call; #define OPTARGS "V?LRQxDCPp:WMUr:H:v:t:p:g:d:i:s:G:S:fX:lmu:FOo" #define CMD_ERR(fmt, args...) do { \ crm_warn(fmt, ##args); \ fprintf(stderr, fmt, ##args); \ } while(0) static int do_find_resource(const char *rsc, pe_working_set_t *data_set) { int found = 0; resource_t *the_rsc = pe_find_resource(data_set->resources, rsc); if(the_rsc == NULL) { return cib_NOTEXISTS; } slist_iter(node, node_t, the_rsc->running_on, lpc, crm_debug_3("resource %s is running on: %s", rsc, node->details->uname); if(BE_QUIET) { fprintf(stdout, "%s\n", node->details->uname); } else { fprintf(stdout, "resource %s is running on: %s\n", rsc, node->details->uname); } found++; ); if(BE_QUIET == FALSE && found == 0) { fprintf(stderr, "resource %s is NOT running\n", rsc); } return 0; } static void print_raw_rsc(resource_t *rsc, int level) { int lpc = 0; GListPtr children = NULL; for(; lpc < level; lpc++) { printf(" "); } printf(" * %s\n", rsc->id); children = rsc->fns->children(rsc); slist_iter(child, resource_t, children, lpc, print_raw_rsc(child, level+1); ); } static int do_find_resource_list(pe_working_set_t *data_set, gboolean raw) { int found = 0; slist_iter( rsc, resource_t, data_set->resources, lpc, if(raw) { found++; print_raw_rsc(rsc, 0); continue; } else if(is_set(rsc->flags, pe_rsc_orphan) && rsc->fns->active(rsc, TRUE) == FALSE) { continue; } rsc->fns->print( rsc, NULL, pe_print_printf|pe_print_rsconly, stdout); found++; ); if(found == 0) { printf("NO resources configured\n"); return cib_NOTEXISTS; } return 0; } static int dump_resource(const char *rsc, pe_working_set_t *data_set) { char *rsc_xml = NULL; resource_t *the_rsc = pe_find_resource(data_set->resources, rsc); if(the_rsc == NULL) { return cib_NOTEXISTS; } the_rsc->fns->print(the_rsc, NULL, pe_print_printf, stdout); rsc_xml = dump_xml_formatted(the_rsc->xml); fprintf(stdout, "raw xml:\n%s", rsc_xml); crm_free(rsc_xml); return 0; } static int dump_resource_attr( const char *rsc, const char *attr, pe_working_set_t *data_set) { node_t *current = NULL; resource_t *the_rsc = pe_find_resource(data_set->resources, rsc); const char *value = NULL; if(the_rsc == NULL) { return cib_NOTEXISTS; } if(g_list_length(the_rsc->running_on) == 1) { current = the_rsc->running_on->data; } else if(g_list_length(the_rsc->running_on) > 1) { CMD_ERR("%s is active on more than one node," " returning the default value for %s\n", the_rsc->id, crm_str(value)); } unpack_instance_attributes( the_rsc->xml, attr_set_type, current?current->details->attrs:NULL, the_rsc->parameters, NULL, data_set->now); if(the_rsc->parameters != NULL) { crm_debug("Looking up %s in %s", attr, the_rsc->id); value = g_hash_table_lookup(the_rsc->parameters, attr); } if(value != NULL) { fprintf(stdout, "%s\n", value); return 0; } return cib_NOTEXISTS; } static int set_resource_attr(const char *rsc_id, const char *attr_set, const char *attr_id, const char *attr_name, const char *attr_value, cib_t *cib, pe_working_set_t *data_set) { int rc = cib_ok; int matches = 0; char *local_attr_id = NULL; char *local_attr_set = NULL; - crm_data_t *xml_top = NULL; - crm_data_t *xml_obj = NULL; - crm_data_t *nv_children = NULL; - crm_data_t *set_children = NULL; + xmlNode *xml_top = NULL; + xmlNode *xml_obj = NULL; + xmlNode *nv_children = NULL; + xmlNode *set_children = NULL; resource_t *rsc = pe_find_resource(data_set->resources, rsc_id); if(rsc == NULL) { return cib_NOTEXISTS; } /* filter by set and type */ matches = find_xml_children( &set_children, rsc->xml, attr_set_type, XML_ATTR_ID, attr_set, FALSE); crm_log_xml_debug(set_children, "search by set:"); crm_debug("%d objects matching tag=%s id=%s", matches, attr_set_type, attr_set?attr_set:""); if(matches == 0) { /* nothing more to search */ crm_debug("No objects matching tag=%s id=%s", attr_set_type, attr_set?attr_set:""); } else if(attr_id == NULL) { matches = find_xml_children( &nv_children, set_children, XML_CIB_TAG_NVPAIR, XML_NVPAIR_ATTR_NAME, attr_name, FALSE); crm_log_xml_debug(nv_children, "search by name:"); } else { matches = find_xml_children( &nv_children, set_children, XML_CIB_TAG_NVPAIR, XML_ATTR_ID, attr_id, FALSE); crm_log_xml_debug(nv_children, "search by id:"); } if(matches > 1) { CMD_ERR("Multiple attributes match name=%s for the resource %s:\n", attr_name, rsc->id); if(set_children == NULL) { free_xml(set_children); set_children = NULL; find_xml_children( &set_children, rsc->xml, attr_set_type, NULL, NULL, FALSE); xml_child_iter( set_children, set, free_xml(nv_children); nv_children = NULL; find_xml_children( &nv_children, set, XML_CIB_TAG_NVPAIR, XML_NVPAIR_ATTR_NAME, attr_name, FALSE); xml_child_iter( nv_children, child, fprintf(stderr," Set: %s,\tValue: %s,\tID: %s\n", ID(set), crm_element_value(child, XML_NVPAIR_ATTR_VALUE), ID(child)); ); ); } else { xml_child_iter( nv_children, child, fprintf(stderr," ID: %s, Value: %s\n", ID(child), crm_element_value(child, XML_NVPAIR_ATTR_VALUE)); ); } if(BE_QUIET == FALSE) { CMD_ERR("\nThe following text can be suppressed with the -Q option:\n"); if(attr_set == NULL) { CMD_ERR(" * To choose an existing entry to change, please supply one of the set names above using the -s option.\n"); } else { CMD_ERR(" * To choose an existing entry to change, please supply one of the IDs above using the -i option.\n"); } CMD_ERR(" * To create a new value with a default ID, please supply a different set name using the -s option.\n"); CMD_ERR("You can also use --query-xml to display the complete resource definition.\n"); } return cib_unknown; } else if(matches == 0) { if(attr_set == NULL) { if(safe_str_eq(attr_set_type, XML_TAG_META_SETS)) { local_attr_set = crm_concat(rsc->id, "meta-options", '-'); } else { local_attr_set = crm_strdup(rsc->id); } attr_set = local_attr_set; } if(attr_id == NULL) { local_attr_id = crm_concat(attr_set, attr_name, '-'); attr_id = local_attr_id; } xml_top = create_xml_node(NULL, crm_element_name(rsc->xml)); crm_xml_add(xml_top, XML_ATTR_ID, rsc->id); xml_obj = create_xml_node(xml_top, attr_set_type); crm_xml_add(xml_obj, XML_ATTR_ID, attr_set); xml_obj = create_xml_node(xml_obj, XML_TAG_ATTRS); xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_NVPAIR); } else { if(attr_id == NULL) { /* extract it */ xml_child_iter(nv_children, child, attr_id = ID(child)); } xml_obj = create_xml_node(NULL, XML_CIB_TAG_NVPAIR); xml_top = xml_obj; } crm_xml_add(xml_obj, XML_ATTR_ID, attr_id); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, attr_value); crm_log_xml_debug(xml_top, "Update"); rc = cib->cmds->modify(cib, XML_CIB_TAG_RESOURCES, xml_top, NULL, cib_options); free_xml(xml_top); crm_free(local_attr_id); crm_free(local_attr_set); return rc; } static int delete_resource_attr( const char *rsc_id, const char *attr_set, const char *attr_id, const char *attr_name, cib_t *cib, pe_working_set_t *data_set) { - crm_data_t *xml_obj = NULL; - crm_data_t *xml_match = NULL; + xmlNode *xml_obj = NULL; + xmlNode *xml_match = NULL; int rc = cib_ok; char *local_attr_id = NULL; resource_t *rsc = pe_find_resource(data_set->resources, rsc_id); if(rsc == NULL) { return cib_NOTEXISTS; } rc = find_attr_details( rsc->xml, NULL, attr_set, attr_id, attr_name, &xml_match, TRUE); if(rc == cib_NOTEXISTS) { return cib_ok; } if(rc != cib_ok) { return rc; } if(attr_id == NULL) { local_attr_id = crm_element_value_copy(xml_match, XML_ATTR_ID); attr_id = local_attr_id; } xml_obj = create_xml_node(NULL, XML_CIB_TAG_NVPAIR); crm_xml_add(xml_obj, XML_ATTR_ID, attr_id); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name); crm_log_xml_debug(xml_obj, "Delete"); rc = cib->cmds->delete(cib, XML_CIB_TAG_RESOURCES, xml_obj, NULL, cib_options); free_xml(xml_obj); free_xml(xml_match); crm_free(local_attr_id); return rc; } static int dump_resource_prop( const char *rsc, const char *attr, pe_working_set_t *data_set) { const char *value = NULL; resource_t *the_rsc = pe_find_resource(data_set->resources, rsc); if(the_rsc == NULL) { return cib_NOTEXISTS; } value = crm_element_value(the_rsc->xml, attr); if(value != NULL) { fprintf(stdout, "%s\n", value); return 0; } return cib_NOTEXISTS; } static void resource_ipc_connection_destroy(gpointer user_data) { crm_info("Connection to CRMd was terminated"); exit(1); } static gboolean crmd_msg_callback(IPC_Channel * server, void *private_data) { int lpc = 0; IPC_Message *msg = NULL; - ha_msg_input_t *new_input = NULL; gboolean hack_return_good = TRUE; while (server->ch_status != IPC_DISCONNECT && server->ops->is_message_pending(server) == TRUE) { - if(new_input != NULL) { - delete_ha_msg_input(new_input); - new_input = NULL; - } - if (server->ops->recv(server, &msg) != IPC_OK) { perror("Receive failure:"); return !hack_return_good; } if (msg == NULL) { crm_debug_4("No message this time"); continue; } lpc++; - new_input = new_ipc_msg_input(msg); - crm_log_message(LOG_MSG, new_input->msg); - msg->msg_done(msg); - - if (validate_crm_message( - new_input->msg, crm_system_name, our_pid, - XML_ATTR_RESPONSE) == FALSE) { - crm_info("Message was not a CRM response. Discarding."); - } - delete_ha_msg_input(new_input); - new_input = NULL; + msg->msg_done(msg); } if (server->ch_status == IPC_DISCONNECT) { crm_debug_2("admin_msg_callback: received HUP"); return !hack_return_good; } return hack_return_good; } static int send_lrm_rsc_op(IPC_Channel *crmd_channel, const char *op, const char *host_uname, const char *rsc_id, gboolean only_failed, pe_working_set_t *data_set) { char *key = NULL; int rc = cib_send_failed; - HA_Message *cmd = NULL; - crm_data_t *xml_rsc = NULL; + xmlNode *cmd = NULL; + xmlNode *xml_rsc = NULL; const char *value = NULL; - HA_Message *params = NULL; - crm_data_t *msg_data = NULL; + xmlNode *params = NULL; + xmlNode *msg_data = NULL; resource_t *rsc = pe_find_resource(data_set->resources, rsc_id); if(rsc == NULL) { CMD_ERR("Resource %s not found\n", rsc_id); return cib_NOTEXISTS; } else if(rsc->variant != pe_native) { CMD_ERR("We can only process primitive resources, not %s\n", rsc_id); return cib_invalid_argument; } else if(host_uname == NULL) { CMD_ERR("Please supply a hostname with -H\n"); return cib_invalid_argument; } key = crm_concat("0:0:crm-resource", our_pid, '-'); msg_data = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP); crm_xml_add(msg_data, XML_ATTR_TRANSITION_KEY, key); xml_rsc = create_xml_node(msg_data, XML_CIB_TAG_RESOURCE); crm_xml_add(xml_rsc, XML_ATTR_ID, rsc->id); crm_xml_add(xml_rsc, XML_ATTR_ID_LONG, rsc->long_name); value = crm_element_value(rsc->xml, XML_ATTR_TYPE); crm_xml_add(xml_rsc, XML_ATTR_TYPE, value); if(value == NULL) { CMD_ERR("%s has no type! Aborting...\n", rsc_id); return cib_NOTEXISTS; } value = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); crm_xml_add(xml_rsc, XML_AGENT_ATTR_CLASS, value); if(value == NULL) { CMD_ERR("%s has no class! Aborting...\n", rsc_id); return cib_NOTEXISTS; } value = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER); crm_xml_add(xml_rsc, XML_AGENT_ATTR_PROVIDER, value); params = create_xml_node(msg_data, XML_TAG_ATTRS); crm_xml_add(params, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET); crm_xml_add(params, CRM_META"_"XML_LRM_ATTR_INTERVAL, "60000"); /* 1 minute */ cmd = create_request(op, msg_data, host_uname, CRM_SYSTEM_CRMD, crm_system_name, our_pid); /* crm_log_xml_warn(cmd, "send_lrm_rsc_op"); */ free_xml(msg_data); crm_free(key); if(send_ipc_message(crmd_channel, cmd)) { rc = 0; sleep(1); /* dont exit striaght away, give the crmd time * to process our request */ } else { CMD_ERR("Could not send %s op to the crmd", op); } - crm_msg_del(cmd); + free_xml(cmd); return rc; } static int delete_lrm_rsc(IPC_Channel *crmd_channel, const char *host_uname, const char *rsc_id, pe_working_set_t *data_set) { return send_lrm_rsc_op(crmd_channel, CRM_OP_LRM_DELETE, host_uname, rsc_id, TRUE, data_set); } static int fail_lrm_rsc(IPC_Channel *crmd_channel, const char *host_uname, const char *rsc_id, pe_working_set_t *data_set) { crm_warn("Failing: %s", rsc_id); return send_lrm_rsc_op(crmd_channel, CRM_OP_LRM_FAIL, host_uname, rsc_id, FALSE, data_set); } static int refresh_lrm(IPC_Channel *crmd_channel, const char *host_uname) { - HA_Message *cmd = NULL; + xmlNode *cmd = NULL; int rc = cib_send_failed; cmd = create_request(CRM_OP_LRM_REFRESH, NULL, host_uname, CRM_SYSTEM_CRMD, crm_system_name, our_pid); if(send_ipc_message(crmd_channel, cmd)) { rc = 0; } - crm_msg_del(cmd); + free_xml(cmd); return rc; } static int migrate_resource( const char *rsc_id, const char *existing_node, const char *preferred_node, cib_t * cib_conn) { char *later_s = NULL; enum cib_errors rc = cib_ok; char *id = NULL; - crm_data_t *cib = NULL; - crm_data_t *rule = NULL; - crm_data_t *expr = NULL; - crm_data_t *constraints = NULL; - crm_data_t *fragment = NULL; - crm_data_t *lifetime = NULL; + xmlNode *cib = NULL; + xmlNode *rule = NULL; + xmlNode *expr = NULL; + xmlNode *constraints = NULL; + xmlNode *fragment = NULL; + xmlNode *lifetime = NULL; - crm_data_t *can_run = NULL; - crm_data_t *dont_run = NULL; + xmlNode *can_run = NULL; + xmlNode *dont_run = NULL; fragment = create_cib_fragment(NULL, NULL); cib = fragment; CRM_DEV_ASSERT(safe_str_eq(crm_element_name(cib), XML_TAG_CIB)); constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); id = crm_concat("cli-prefer", rsc_id, '-'); can_run = create_xml_node(NULL, XML_CONS_TAG_RSC_LOCATION); crm_xml_add(can_run, XML_ATTR_ID, id); crm_free(id); id = crm_concat("cli-standby", rsc_id, '-'); dont_run = create_xml_node(NULL, XML_CONS_TAG_RSC_LOCATION); crm_xml_add(dont_run, XML_ATTR_ID, id); crm_free(id); if(migrate_lifetime) { char *life = crm_strdup(migrate_lifetime); char *life_mutable = life; ha_time_t *now = NULL; ha_time_t *later = NULL; ha_time_t *duration = parse_time_duration(&life_mutable); if(duration == NULL) { CMD_ERR("Invalid duration specified: %s\n", migrate_lifetime); CMD_ERR("Please refer to" " http://en.wikipedia.org/wiki/ISO_8601#Duration" " for examples of valid durations\n"); crm_free(life); return cib_invalid_argument; } now = new_ha_date(TRUE); later = add_time(now, duration); log_date(LOG_INFO, "now ", now, ha_log_date|ha_log_time); log_date(LOG_INFO, "later ", later, ha_log_date|ha_log_time); log_date(LOG_INFO, "duration", duration, ha_log_date|ha_log_time|ha_log_local); later_s = date_to_string(later, ha_log_date|ha_log_time); printf("Migration will take effect until: %s\n", later_s); free_ha_date(duration); free_ha_date(later); free_ha_date(now); crm_free(life); } if(existing_node == NULL) { crm_log_xml_notice(can_run, "Deleting"); rc = cib_conn->cmds->delete(cib_conn, XML_CIB_TAG_CONSTRAINTS, dont_run, NULL, cib_options); if(rc == cib_NOTEXISTS) { rc = cib_ok; } else if(rc != cib_ok) { goto bail; } } else { if(BE_QUIET == FALSE) { fprintf(stderr, "WARNING: Creating rsc_location constraint '%s'" " with a score of -INFINITY for resource %s" " on %s.\n", ID(dont_run), rsc_id, existing_node); CMD_ERR("\tThis will prevent %s from running" " on %s until the constraint is removed using" " the 'crm_resource -U' command or manually" " with cibadmin\n", rsc_id, existing_node); CMD_ERR("\tThis will be the case even if %s is" " the last node in the cluster\n", existing_node); CMD_ERR("\tThis messgae can be disabled with -Q\n"); } crm_xml_add(dont_run, "rsc", rsc_id); if(later_s) { lifetime = create_xml_node(dont_run, "lifetime"); rule = create_xml_node(lifetime, XML_TAG_RULE); id = crm_concat("cli-standby-lifetime", rsc_id, '-'); crm_xml_add(rule, XML_ATTR_ID, id); crm_free(id); expr = create_xml_node(rule, "date_expression"); id = crm_concat("cli-standby-lifetime-end",rsc_id,'-'); crm_xml_add(expr, XML_ATTR_ID, id); crm_free(id); crm_xml_add(expr, "operation", "lt"); crm_xml_add(expr, "end", later_s); } rule = create_xml_node(dont_run, XML_TAG_RULE); expr = create_xml_node(rule, XML_TAG_EXPRESSION); id = crm_concat("cli-standby-rule", rsc_id, '-'); crm_xml_add(rule, XML_ATTR_ID, id); crm_free(id); crm_xml_add(rule, XML_RULE_ATTR_SCORE, MINUS_INFINITY_S); id = crm_concat("cli-standby-expr", rsc_id, '-'); crm_xml_add(expr, XML_ATTR_ID, id); crm_free(id); crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, "#uname"); crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq"); crm_xml_add(expr, XML_EXPR_ATTR_VALUE, existing_node); crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string"); add_node_copy(constraints, dont_run); } if(preferred_node == NULL) { crm_log_xml_notice(can_run, "Deleting"); rc = cib_conn->cmds->delete(cib_conn, XML_CIB_TAG_CONSTRAINTS, can_run, NULL, cib_options); if(rc == cib_NOTEXISTS) { rc = cib_ok; } else if(rc != cib_ok) { goto bail; } } else { crm_xml_add(can_run, "rsc", rsc_id); if(later_s) { lifetime = create_xml_node(can_run, "lifetime"); rule = create_xml_node(lifetime, XML_TAG_RULE); id = crm_concat("cli-prefer-lifetime", rsc_id, '-'); crm_xml_add(rule, XML_ATTR_ID, id); crm_free(id); expr = create_xml_node(rule, "date_expression"); id = crm_concat("cli-prefer-lifetime-end", rsc_id, '-'); crm_xml_add(expr, XML_ATTR_ID, id); crm_free(id); crm_xml_add(expr, "operation", "lt"); crm_xml_add(expr, "end", later_s); } rule = create_xml_node(can_run, XML_TAG_RULE); expr = create_xml_node(rule, XML_TAG_EXPRESSION); id = crm_concat("cli-prefer-rule", rsc_id, '-'); crm_xml_add(rule, XML_ATTR_ID, id); crm_free(id); crm_xml_add(rule, XML_RULE_ATTR_SCORE, INFINITY_S); id = crm_concat("cli-prefer-expr", rsc_id, '-'); crm_xml_add(expr, XML_ATTR_ID, id); crm_free(id); crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, "#uname"); crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq"); crm_xml_add(expr, XML_EXPR_ATTR_VALUE, preferred_node); crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string"); add_node_copy(constraints, can_run); } if(preferred_node != NULL || existing_node != NULL) { crm_log_xml_notice(fragment, "CLI Update"); rc = cib_conn->cmds->update(cib_conn, XML_CIB_TAG_CONSTRAINTS, fragment, NULL, cib_options); } bail: free_xml(fragment); free_xml(dont_run); free_xml(can_run); crm_free(later_s); return rc; } static int list_resource_operations(const char *rsc_id, const char *host_uname, gboolean active, pe_working_set_t *data_set) { resource_t *rsc = NULL; int opts = pe_print_printf|pe_print_rsconly|pe_print_suppres_nl; GListPtr ops = find_operations(rsc_id, host_uname, active, data_set); - slist_iter(xml_op, crm_data_t, ops, lpc, + slist_iter(xml_op, xmlNode, ops, lpc, const char *op_rsc = crm_element_value(xml_op, "resource"); const char *last = crm_element_value(xml_op, "last_run"); const char *status_s = crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS); int status = crm_parse_int(status_s, "0"); rsc = pe_find_resource(data_set->resources, op_rsc); rsc->fns->print(rsc, "", opts, stdout); fprintf(stdout, ": %s (node=%s, call=%s, rc=%s", ID(xml_op), crm_element_value(xml_op, XML_ATTR_UNAME), crm_element_value(xml_op, XML_LRM_ATTR_CALLID), crm_element_value(xml_op, XML_LRM_ATTR_RC)); if(last) { time_t run_at = crm_parse_int(last, "0"); fprintf(stdout, ", last-run=%s, exec=%sms\n", ctime(&run_at), crm_element_value(xml_op, "exec_time")); } fprintf(stdout, "): %s\n", op_status2text(status)); ); return cib_ok; } int main(int argc, char **argv) { pe_working_set_t data_set; - crm_data_t *cib_xml_copy = NULL; + xmlNode *cib_xml_copy = NULL; cib_t * cib_conn = NULL; enum cib_errors rc = cib_ok; int argerr = 0; int flag; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"quiet", 0, 0, 'Q'}, {"list", 0, 0, 'L'}, {"list-raw", 0, 0, 'l'}, {"refresh", 0, 0, 'R'}, {"reprobe", 0, 0, 'P'}, {"query-xml", 0, 0, 'x'}, {"delete", 0, 0, 'D'}, {"cleanup", 0, 0, 'C'}, {"locate", 0, 0, 'W'}, {"migrate", 0, 0, 'M'}, {"un-migrate", 0, 0, 'U'}, {"resource", 1, 0, 'r'}, {"host-uname", 1, 0, 'H'}, {"lifetime", 1, 0, 'u'}, {"fail", 0, 0, 'F'}, {"force", 0, 0, 'f'}, {"meta", 0, 0, 'm'}, {"list-operations", 0, 0, 'O'}, {"list-all-operations", 0, 0, 'o'}, {"set-parameter", 1, 0, 'p'}, {"get-parameter", 1, 0, 'g'}, {"delete-parameter",1, 0, 'd'}, {"property-value", 1, 0, 'v'}, {"get-property", 1, 0, 'G'}, {"set-property", 1, 0, 'S'}, {"resource-type", 1, 0, 't'}, {"xml-file", 0, 0, 'X'}, {0, 0, 0, 0} }; #endif crm_log_init(basename(argv[0]), LOG_ERR, FALSE, FALSE, argc, argv); if(argc < 2) { usage(crm_system_name, LSB_EXIT_EINVAL); } 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) { case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case '?': usage(crm_system_name, LSB_EXIT_OK); break; case 'X': xml_file = crm_strdup(optarg); break; case 'Q': BE_QUIET = TRUE; break; case 'm': attr_set_type = XML_TAG_META_SETS; break; case 'L': case 'l': case 'R': case 'x': case 'D': case 'F': case 'C': case 'P': case 'W': case 'M': case 'U': rsc_cmd = flag; break; case 'u': migrate_lifetime = crm_strdup(optarg); break; case 'p': crm_debug_2("Option %c => %s", flag, optarg); prop_name = optarg; rsc_cmd = flag; break; case 'g': crm_debug_2("Option %c => %s", flag, optarg); prop_name = optarg; rsc_cmd = flag; break; case 'd': crm_debug_2("Option %c => %s", flag, optarg); prop_name = optarg; rsc_cmd = flag; break; case 'S': crm_debug_2("Option %c => %s", flag, optarg); prop_name = optarg; rsc_cmd = flag; break; case 'O': case 'o': crm_debug_2("Option %c => %s", flag, optarg); rsc_cmd = flag; break; case 'G': crm_debug_2("Option %c => %s", flag, optarg); prop_name = optarg; rsc_cmd = flag; break; case 'f': do_force = TRUE; break; case 'i': crm_debug_2("Option %c => %s", flag, optarg); prop_id = optarg; break; case 's': crm_debug_2("Option %c => %s", flag, optarg); prop_set = optarg; break; case 'r': crm_debug_2("Option %c => %s", flag, optarg); rsc_id = optarg; break; case 'v': crm_debug_2("Option %c => %s", flag, optarg); prop_value = optarg; break; case 't': crm_debug_2("Option %c => %s", flag, optarg); rsc_type = optarg; break; case 'H': crm_debug_2("Option %c => %s", flag, optarg); host_uname = optarg; break; default: CMD_ERR("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag); ++argerr; break; } } if (optind < argc && argv[optind] != NULL) { CMD_ERR("non-option ARGV-elements: "); while (optind < argc && argv[optind] != NULL) { CMD_ERR("%s ", argv[optind++]); ++argerr; } CMD_ERR("\n"); } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } crm_malloc0(our_pid, 11); if(our_pid != NULL) { snprintf(our_pid, 10, "%d", getpid()); our_pid[10] = '\0'; } if(do_force) { crm_debug("Forcing..."); cib_options |= cib_scope_local|cib_quorum_override; } if(rsc_cmd == 'L' || rsc_cmd == 'O' || rsc_cmd == 'o' || rsc_cmd == 'W' || rsc_cmd == 'D' || rsc_cmd == 'x' || rsc_cmd == 'M' || rsc_cmd == 'U' || rsc_cmd == 'C' || rsc_cmd == 'F' || rsc_cmd == 'p' || rsc_cmd == 'd' || rsc_cmd == 'g' || rsc_cmd == 'G' || rsc_cmd == 'S' || rsc_cmd == 'l') { resource_t *rsc = NULL; if(xml_file != NULL) { FILE *xml_strm = fopen(xml_file, "r"); if(strstr(xml_file, ".bz2") != NULL) { cib_xml_copy = file2xml(xml_strm, TRUE); } else { cib_xml_copy = file2xml(xml_strm, FALSE); } if(xml_strm != NULL) { fclose(xml_strm); } } else { cib_conn = cib_new(); rc = cib_conn->cmds->signon( cib_conn, crm_system_name, cib_command_synchronous); if(rc != cib_ok) { CMD_ERR("Error signing on to the CIB service: %s\n", cib_error2string(rc)); return rc; } cib_xml_copy = get_cib_copy(cib_conn); } set_working_set_defaults(&data_set); data_set.input = cib_xml_copy; data_set.now = new_ha_date(TRUE); cluster_status(&data_set); rsc = pe_find_resource(data_set.resources, rsc_id); if(rsc != NULL) { rsc_id = rsc->id; } else { rc = cib_NOTEXISTS; } } if(rsc_cmd == 'R' || rsc_cmd == 'C' || rsc_cmd == 'F' || rsc_cmd == 'P') { GCHSource *src = NULL; src = init_client_ipc_comms(CRM_SYSTEM_CRMD, crmd_msg_callback, NULL, &crmd_channel); if(src == NULL) { CMD_ERR("Error signing on to the CRMd service\n"); return 1; } send_hello_message( crmd_channel, our_pid, crm_system_name, "0", "1"); set_IPC_Channel_dnotify(src, resource_ipc_connection_destroy); } crm_warn("here i am - 3"); if(rsc_cmd == 'L') { rc = cib_ok; do_find_resource_list(&data_set, FALSE); } else if(rsc_cmd == 'l') { rc = cib_ok; do_find_resource_list(&data_set, TRUE); } else if(rsc_cmd == 'C') { rc = delete_lrm_rsc(crmd_channel, host_uname, rsc_id, &data_set); } else if(rsc_cmd == 'F') { rc = fail_lrm_rsc(crmd_channel, host_uname, rsc_id, &data_set); } else if(rsc_cmd == 'O') { rc = list_resource_operations(rsc_id, host_uname, TRUE, &data_set); } else if(rsc_cmd == 'o') { rc = list_resource_operations(rsc_id, host_uname, FALSE, &data_set); } else if(rc == cib_NOTEXISTS) { CMD_ERR("Resource %s not found: %s\n", crm_str(rsc_id), cib_error2string(rc)); } else if(rsc_cmd == 'W') { if(rsc_id == NULL) { CMD_ERR("Must supply a resource id with -r\n"); return cib_NOTEXISTS; } rc = do_find_resource(rsc_id, &data_set); } else if(rsc_cmd == 'x') { if(rsc_id == NULL) { CMD_ERR("Must supply a resource id with -r\n"); return cib_NOTEXISTS; } rc = dump_resource(rsc_id, &data_set); } else if(rsc_cmd == 'U') { if(rsc_id == NULL) { CMD_ERR("Must supply a resource id with -r\n"); return cib_NOTEXISTS; } rc = migrate_resource(rsc_id, NULL, NULL, cib_conn); } else if(rsc_cmd == 'M') { node_t *dest = NULL; node_t *current = NULL; const char *current_uname = NULL; resource_t *rsc = pe_find_resource(data_set.resources, rsc_id); if(rsc != NULL && rsc->running_on != NULL) { current = rsc->running_on->data; if(current != NULL) { current_uname = current->details->uname; } } if(host_uname != NULL) { dest = pe_find_node(data_set.nodes, host_uname); } if(rsc == NULL) { CMD_ERR("Resource %s not migrated:" " not found\n", rsc_id); } else if(rsc->variant == pe_native && g_list_length(rsc->running_on) > 1) { CMD_ERR("Resource %s not migrated:" " active on multiple nodes\n", rsc_id); } else if(host_uname != NULL && dest == NULL) { CMD_ERR("Error performing operation: " "%s is not a known node\n", host_uname); } else if(host_uname != NULL && safe_str_eq(current_uname, host_uname)) { CMD_ERR("Error performing operation: " "%s is already active on %s\n", rsc_id, host_uname); } else if(current_uname != NULL && (do_force || host_uname == NULL)) { rc = migrate_resource(rsc_id, current_uname, host_uname, cib_conn); } else if(host_uname != NULL) { rc = migrate_resource( rsc_id, NULL, host_uname, cib_conn); } else { CMD_ERR("Resource %s not migrated: " "not-active and no prefered location" " specified.\n", rsc_id); } } else if(rsc_cmd == 'G') { if(rsc_id == NULL) { CMD_ERR("Must supply a resource id with -r\n"); return cib_NOTEXISTS; } rc = dump_resource_prop(rsc_id, prop_name, &data_set); } else if(rsc_cmd == 'S') { - crm_data_t *msg_data = NULL; + xmlNode *msg_data = NULL; if(prop_value == NULL || strlen(prop_value) == 0) { CMD_ERR("You need to supply a value with the -v option\n"); return CIBRES_MISSING_FIELD; } else if(cib_conn == NULL) { return cib_connection; } if(rsc_id == NULL) { CMD_ERR("Must supply a resource id with -r\n"); return cib_NOTEXISTS; } CRM_DEV_ASSERT(rsc_type != NULL); CRM_DEV_ASSERT(prop_name != NULL); CRM_DEV_ASSERT(prop_value != NULL); msg_data = create_xml_node(NULL, rsc_type); crm_xml_add(msg_data, XML_ATTR_ID, rsc_id); crm_xml_add(msg_data, prop_name, prop_value); rc = cib_conn->cmds->modify(cib_conn, XML_CIB_TAG_RESOURCES, msg_data, NULL, cib_options); free_xml(msg_data); } else if(rsc_cmd == 'g') { if(rsc_id == NULL) { CMD_ERR("Must supply a resource id with -r\n"); return cib_NOTEXISTS; } rc = dump_resource_attr(rsc_id, prop_name, &data_set); } else if(rsc_cmd == 'p') { if(rsc_id == NULL) { CMD_ERR("Must supply a resource id with -r\n"); return cib_NOTEXISTS; } if(prop_value == NULL || strlen(prop_value) == 0) { CMD_ERR("You need to supply a value with the -v option\n"); return CIBRES_MISSING_FIELD; } rc = set_resource_attr(rsc_id, prop_set, prop_id, prop_name, prop_value, cib_conn, &data_set); } else if(rsc_cmd == 'd') { if(rsc_id == NULL) { CMD_ERR("Must supply a resource id with -r\n"); return cib_NOTEXISTS; } rc = delete_resource_attr(rsc_id, prop_id, prop_set, prop_name, cib_conn, &data_set); } else if(rsc_cmd == 'P') { - HA_Message *cmd = NULL; + xmlNode *cmd = NULL; cmd = create_request(CRM_OP_REPROBE, NULL, host_uname, CRM_SYSTEM_CRMD, crm_system_name, our_pid); send_ipc_message(crmd_channel, cmd); - crm_msg_del(cmd); + free_xml(cmd); } else if(rsc_cmd == 'R') { refresh_lrm(crmd_channel, host_uname); } else if(rsc_cmd == 'D') { - crm_data_t *msg_data = NULL; + xmlNode *msg_data = NULL; if(rsc_id == NULL) { CMD_ERR("Must supply a resource id with -r\n"); return cib_NOTEXISTS; } if(rsc_type == NULL) { CMD_ERR("You need to specify a resource type with -t"); return cib_NOTEXISTS; } else if(cib_conn == NULL) { return cib_connection; } msg_data = create_xml_node(NULL, rsc_type); crm_xml_add(msg_data, XML_ATTR_ID, rsc_id); rc = cib_conn->cmds->delete(cib_conn, XML_CIB_TAG_RESOURCES, msg_data, NULL, cib_options); free_xml(msg_data); } else { CMD_ERR("Unknown command: %c\n", rsc_cmd); } if(cib_conn != NULL) { cleanup_calculations(&data_set); cib_conn->cmds->signoff(cib_conn); } if(rc == cib_no_quorum) { CMD_ERR("Error performing operation: %s\n", cib_error2string(rc)); CMD_ERR("Try using -f\n"); } else if(rc != cib_ok) { CMD_ERR("Error performing operation: %s\n", cib_error2string(rc)); } return rc; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-?VS] -(L|Q|W|D|C|P|p) [options]\n", cmd); fprintf(stream, "\t--%s (-%c)\t: this help message\n", "help", '?'); fprintf(stream, "\t--%s (-%c)\t: " "turn on debug info. additional instances increase verbosity\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c)\t: Print only the value on stdout (for use with -W)\n", "quiet", 'Q'); fprintf(stream, "\nCommands\n"); fprintf(stream, "\t--%s (-%c)\t: List all resources\n", "list", 'L'); fprintf(stream, "\t--%s (-%c)\t: Query a resource\n" "\t\t\t Requires: -r\n", "query-xml", 'x'); fprintf(stream, "\t--%s (-%c)\t: Locate a resource\n" "\t\t\t Requires: -r\n", "locate", 'W'); fprintf(stream, "\t--%s (-%c)\t: Migrate a resource from it current" " location. Use -H to specify a destination\n" "\t\tIf -H is not specified, we will force the resource to move by" " creating a rule for the current location and a score of -INFINITY\n" "\t\tNOTE: This will prevent the resource from running on this" " node until the constraint is removed with -U\n" "\t\t\t Requires: -r, Optional: -H, -f, --lifetime\n", "migrate", 'M'); fprintf(stream, "\t--%s (-%c)\t: Remove all constraints created by -M\n" "\t\t\t Requires: -r\n", "un-migrate", 'U'); fprintf(stream, "\t--%s (-%c)\t: Delete a resource from the CIB\n" "\t\t\t Requires: -r, -t\n", "delete", 'D'); fprintf(stream, "\t--%s (-%c)\t: Delete a resource from the LRM\n" "\t\t\t Requires: -r. Optional: -H\n", "cleanup", 'C'); fprintf(stream, "\t--%s (-%c)\t: Recheck for resources started outside of the CRM\n" "\t\t\t Optional: -H\n", "reprobe", 'P'); fprintf(stream, "\t--%s (-%c)\t: Refresh the CIB from the LRM\n" "\t\t\t Optional: -H\n", "refresh", 'R'); fprintf(stream, "\t--%s (-%c) \t: " "Set the named parameter for a resource\n" "\t\t\t Requires: -r, -v. Optional: -i, -s, --meta\n", "set-parameter", 'p'); fprintf(stream, "\t--%s (-%c) \t: " "Get the named parameter for a resource\n" "\t\t\t Requires: -r. Optional: -i, -s, --meta\n", "get-parameter", 'g'); fprintf(stream, "\t--%s (-%c) : " "Delete the named parameter for a resource\n" "\t\t\t Requires: -r. Optional: -i, --meta\n", "delete-parameter", 'd'); fprintf(stream, "\t--%s (-%c) : " "List the active resource operations. Optionally filtered by resource and/or node.\n" "\t\t\t Optional: -H, -r\n", "list-operations", 'O'); fprintf(stream, "\t--%s (-%c) : " "List all resource operations. Optionally filtered by resource and/or node.\n" "\t\t\t Optional: -H, -r\n", "list-all-operations", 'o'); fprintf(stream, "\nOptions\n"); fprintf(stream, "\t--%s (-%c) \t: Resource ID\n", "resource", 'r'); fprintf(stream, "\t--%s (-%c) \t: " "Resource type (primitive, clone, group, ...)\n", "resource-type", 't'); fprintf(stream, "\t--%s (-%c) \t: " "Property value\n", "property-value", 'v'); fprintf(stream, "\t--%s (-%c) \t: " "Host name\n", "host-uname", 'H'); fprintf(stream, "\t--%s\t: Modify a resource's configuration option rather than one which is passed to the resource agent script." "\n\t\tFor use with -p, -g, -d\n", "meta"); fprintf(stream, "\t--%s (-%c) \t: " "Lifespan of migration constraints\n", "lifetime", 'u'); fprintf(stream, "\t--%s (-%c)\t: " "Force the resource to move by creating a rule for the" " current location and a score of -INFINITY\n" "\t\tThis should be used if the resource's stickiness and" " constraint scores total more than INFINITY (Currently 100,000)\n" "\t\tNOTE: This will prevent the resource from running on this" " node until the constraint is removed with -U or the --lifetime duration expires\n", "force", 'f'); fprintf(stream, "\t-%c \t: (Advanced Use Only) ID of the instance_attributes object to change\n", 's'); fprintf(stream, "\t-%c \t: (Advanced Use Only) ID of the nvpair object to change/delete\n", 'i'); fflush(stream); exit(exit_status); } diff --git a/crm/admin/crm_verify.c b/crm/admin/crm_verify.c index f1ba607778..72569c939a 100644 --- a/crm/admin/crm_verify.c +++ b/crm/admin/crm_verify.c @@ -1,320 +1,320 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define OPTARGS "V?X:x:pLS:D:" #ifdef HAVE_GETOPT_H # include #endif #include #include gboolean USE_LIVE_CIB = FALSE; char *cib_save = NULL; void usage(const char *cmd, int exit_status); extern gboolean stage0(pe_working_set_t *data_set); extern void cleanup_alloc_calculations(pe_working_set_t *data_set); -extern crm_data_t * do_calculations( - pe_working_set_t *data_set, crm_data_t *xml_input, ha_time_t *now); +extern xmlNode * do_calculations( + pe_working_set_t *data_set, xmlNode *xml_input, ha_time_t *now); const char *dtd_file = DTD_DIRECTORY"/crm.dtd"; int main(int argc, char **argv) { - crm_data_t *cib_object = NULL; - crm_data_t *status = NULL; + xmlNode *cib_object = NULL; + xmlNode *status = NULL; int argerr = 0; int flag; pe_working_set_t data_set; cib_t * cib_conn = NULL; int rc = cib_ok; gboolean xml_stdin = FALSE; const char *xml_file = NULL; const char *xml_string = NULL; g_log_set_handler(NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG | G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL, cl_glib_msg_handler, NULL); /* and for good measure... - this enum is a bit field (!) */ g_log_set_always_fatal((GLogLevelFlags)0); /*value out of range*/ crm_log_init(basename(argv[0]), LOG_ERR, FALSE, TRUE, 0, NULL); CL_SIGNAL(DEBUG_INC, alter_debug); CL_SIGNAL(DEBUG_DEC, alter_debug); while (1) { #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {F_CRM_DATA, 1, 0, 'X'}, {"dtd-file", 1, 0, 'D'}, {"xml-file", 1, 0, 'x'}, {"xml-pipe", 0, 0, 'p'}, {"save-xml", 1, 0, 'S'}, {"live-check", 0, 0, 'L'}, {"help", 0, 0, '?'}, {0, 0, 0, 0} }; #endif #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"); break; #endif case 'D': crm_debug_2("Option %c => %s", flag, optarg); dtd_file = optarg; break; case 'X': crm_debug_2("Option %c => %s", flag, optarg); xml_string = crm_strdup(optarg); break; case 'x': crm_debug_2("Option %c => %s", flag, optarg); xml_file = crm_strdup(optarg); break; case 'p': xml_stdin = TRUE; break; case 'S': cib_save = crm_strdup(optarg); break; case 'V': alter_debug(DEBUG_INC); break; case 'L': USE_LIVE_CIB = TRUE; break; case '?': usage(crm_system_name, LSB_EXIT_GENERIC); break; default: printf("?? getopt returned character code 0%o ??\n", 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) { crm_err("%d errors in option parsing", argerr); usage(crm_system_name, LSB_EXIT_GENERIC); } crm_info("=#=#=#=#= Getting XML =#=#=#=#="); if(USE_LIVE_CIB) { cib_conn = cib_new(); rc = cib_conn->cmds->signon( cib_conn, crm_system_name, cib_command_synchronous); } if(USE_LIVE_CIB) { if(rc == cib_ok) { int options = cib_scope_local|cib_sync_call; crm_info("Reading XML from: live cluster"); rc = cib_conn->cmds->query( cib_conn, NULL, &cib_object, options); } if(rc != cib_ok) { fprintf(stderr, "Live CIB query failed: %s\n", cib_error2string(rc)); return 3; } if(cib_object == NULL) { fprintf(stderr, "Live CIB query failed: empty result\n"); return 3; } } else if(xml_file != NULL) { FILE *xml_strm = fopen(xml_file, "r"); cib_object = file2xml(xml_strm, FALSE); if(cib_object == NULL) { fprintf(stderr, "Couldn't parse input file: %s\n", xml_file); return 1; } fclose(xml_strm); } else if(xml_string != NULL) { cib_object = string2xml(xml_string); if(cib_object == NULL) { fprintf(stderr, "Couldn't parse input string: %s\n", xml_string); return 1; } } else if(xml_stdin) { cib_object = stdin2xml(); if(cib_object == NULL) { fprintf(stderr, "Couldn't parse input from STDIN.\n"); return 1; } } else { fprintf(stderr, "No configuration source specified." " Use --help for usage information.\n"); return 3; } if(cib_save != NULL) { write_xml_file(cib_object, cib_save, FALSE); } status = get_object_root(XML_CIB_TAG_STATUS, cib_object); if(status == NULL) { create_xml_node(cib_object, XML_CIB_TAG_STATUS); } #if CRM_DEPRECATED_SINCE_2_0_4 xml_child_iter_filter(status, node_state, XML_CIB_TAG_STATE, xml_remove_prop(node_state, XML_CIB_TAG_LRM); ); #endif crm_notice("Required feature set: %s", feature_set(cib_object)); if(do_id_check(cib_object, NULL, FALSE, FALSE)) { crm_config_err("ID Check failed"); } if(validate_with_dtd(cib_object, FALSE, dtd_file) == FALSE) { crm_config_err("CIB did not pass DTD validation"); } if(USE_LIVE_CIB) { /* we will always have a status section and can do a full simulation */ do_calculations(&data_set, cib_object, NULL); } else { set_working_set_defaults(&data_set); data_set.now = new_ha_date(TRUE); data_set.input = cib_object; stage0(&data_set); } cleanup_alloc_calculations(&data_set); if(crm_config_error) { fprintf(stderr, "Errors found during check: config not valid\n"); if(crm_log_level < LOG_WARNING) { fprintf(stderr, " -V may provide more details\n"); } rc = 2; } else if(crm_config_warning) { fprintf(stderr, "Warnings found during check: config may not be valid\n"); if(crm_log_level < LOG_WARNING) { fprintf(stderr, " Use -V for more details\n"); } rc = 1; } if(USE_LIVE_CIB) { cib_conn->cmds->signoff(cib_conn); cib_delete(cib_conn); } return rc; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-V] [-D] -(?|L|X|x|p)\n", cmd); fprintf(stream, "\t--%s (-%c)\t: this help message\n", "help", '?'); fprintf(stream, "\t--%s (-%c)\t: " "turn on debug info. additional instances increase verbosity\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c)\t: Connect to the running cluster\n", "live-check", 'L'); fprintf(stream, "\t--%s (-%c) \t: Use the configuration in the supplied string\n", F_CRM_DATA, 'X'); fprintf(stream, "\t--%s (-%c) \t: Use the configuration in the named file\n", "xml-file", 'x'); fprintf(stream, "\t--%s (-%c) \t: Use the configuration piped in via stdin\n", "xml-pipe", 'p'); fprintf(stream, "\t--%s (-%c) \t: Use the named dtd file instead of %s\n", "dtd-file", 'D', dtd_file); fflush(stream); exit(exit_status); } diff --git a/crm/admin/crmadmin.c b/crm/admin/crmadmin.c index cfa61ac97b..44aa98e2e2 100644 --- a/crm/admin/crmadmin.c +++ b/crm/admin/crmadmin.c @@ -1,716 +1,721 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_GETOPT_H # include #endif int message_timer_id = -1; int message_timeout_ms = 30*1000; GMainLoop *mainloop = NULL; IPC_Channel *crmd_channel = NULL; char *admin_uuid = NULL; void usage(const char *cmd, int exit_status); gboolean do_init(void); int do_work(void); void crmadmin_ipc_connection_destroy(gpointer user_data); gboolean admin_msg_callback(IPC_Channel * source_data, void *private_data); char *pluralSection(const char *a_section); -crm_data_t *handleCibMod(void); -int do_find_node_list(crm_data_t *xml_node); +xmlNode *handleCibMod(void); +int do_find_node_list(xmlNode *xml_node); gboolean admin_message_timeout(gpointer data); -gboolean is_node_online(crm_data_t *node_state); +gboolean is_node_online(xmlNode *node_state); enum debug { debug_none, debug_dec, debug_inc }; gboolean BE_VERBOSE = FALSE; int expected_responses = 1; gboolean BASH_EXPORT = FALSE; gboolean DO_HEALTH = FALSE; gboolean DO_RESET = FALSE; gboolean DO_RESOURCE = FALSE; gboolean DO_ELECT_DC = FALSE; gboolean DO_WHOIS_DC = FALSE; gboolean DO_NODE_LIST = FALSE; gboolean BE_SILENT = FALSE; gboolean DO_RESOURCE_LIST = FALSE; enum debug DO_DEBUG = debug_none; const char *crmd_operation = NULL; -crm_data_t *msg_options = NULL; +xmlNode *msg_options = NULL; const char *standby_on_off = "on"; const char *admin_verbose = XML_BOOLEAN_FALSE; char *id = NULL; char *this_msg_reference = NULL; char *disconnect = NULL; char *dest_node = NULL; char *rsc_name = NULL; char *crm_option = NULL; int operation_status = 0; const char *sys_to = NULL; #define OPTARGS "V?K:S:HE:Dd:i:RNqt:Bv" int main(int argc, char **argv) { int argerr = 0; int flag; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"quiet", 0, 0, 'q'}, {"reference", 1, 0, 0}, {XML_ATTR_TIMEOUT, 1, 0, 't'}, {"bash-export", 0, 0, 'B'}, /* daemon options */ {"kill", 1, 0, 'K'}, /* stop a node */ {"die", 0, 0, 0}, /* kill a node, no respawn */ {"debug_inc", 1, 0, 'i'}, {"debug_dec", 1, 0, 'd'}, {"status", 1, 0, 'S'}, {"standby", 1, 0, 's'}, {"active", 1, 0, 'a'}, {"health", 0, 0, 'H'}, {"election", 0, 0, 'E'}, {"dc_lookup", 0, 0, 'D'}, {"nodes", 0, 0, 'N'}, {"option", 1, 0, 'o'}, {"version", 0, 0, 'v'}, {0, 0, 0, 0} }; #endif crm_log_init(basename(argv[0]), LOG_ERR, FALSE, TRUE, argc, argv); if(argc < 2) { usage(crm_system_name, LSB_EXIT_EINVAL); } 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: if (strcasecmp("reference", long_options[option_index].name) == 0) { this_msg_reference = crm_strdup(optarg); } else if (strcasecmp("die", long_options[option_index].name) == 0) { DO_RESET = TRUE; crmd_operation = CRM_OP_DIE; } else { printf( "?? Long option (--%s) is not yet properly supported ??\n", long_options[option_index].name); ++argerr; } break; #endif /* a sample test for multiple instance if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); */ case 'v': fprintf(stdout, "HA Version %s, CRM Version %s (CIB feature set %s) %s\n", VERSION, CRM_FEATURE_SET, CIB_FEATURE_SET, HA_HG_VERSION); exit(0); break; case 'V': BE_VERBOSE = TRUE; admin_verbose = XML_BOOLEAN_TRUE; cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case 't': message_timeout_ms = atoi(optarg); if(message_timeout_ms < 1) { message_timeout_ms = 30*1000; } break; case '?': usage(crm_system_name, LSB_EXIT_OK); break; case 'D': DO_WHOIS_DC = TRUE; break; case 'B': BASH_EXPORT = TRUE; break; case 'K': DO_RESET = TRUE; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); crmd_operation = CRM_OP_LOCAL_SHUTDOWN; break; case 'q': BE_SILENT = TRUE; break; case 'i': DO_DEBUG = debug_inc; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 'd': DO_DEBUG = debug_dec; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 'S': DO_HEALTH = TRUE; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 'E': DO_ELECT_DC = TRUE; break; case 'N': DO_NODE_LIST = TRUE; break; case 'H': DO_HEALTH = 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); } if (do_init()) { int res = 0; res = do_work(); if (res > 0) { /* wait for the reply by creating a mainloop and running it until * the callbacks are invoked... */ mainloop = g_main_new(FALSE); expected_responses++; crm_debug_2("Waiting for %d replies from the local CRM", expected_responses); message_timer_id = Gmain_timeout_add( message_timeout_ms, admin_message_timeout, NULL); g_main_run(mainloop); return_to_orig_privs(); } else if(res < 0) { crm_err("No message to send"); operation_status = -1; } } else { crm_warn("Init failed, could not perform requested operations"); operation_status = -2; } crm_debug_2("%s exiting normally", crm_system_name); return operation_status; } int do_work(void) { int ret = 1; /* construct the request */ - crm_data_t *msg_data = NULL; + xmlNode *msg_data = NULL; gboolean all_is_good = TRUE; msg_options = create_xml_node(NULL, XML_TAG_OPTIONS); crm_xml_add(msg_options, XML_ATTR_VERBOSE, admin_verbose); crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0"); if (DO_HEALTH == TRUE) { crm_debug_2("Querying the system"); sys_to = CRM_SYSTEM_DC; if (dest_node != NULL) { sys_to = CRM_SYSTEM_CRMD; crmd_operation = CRM_OP_PING; if (BE_VERBOSE) { expected_responses = 1; } crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0"); } else { crm_info("Cluster-wide health not available yet"); all_is_good = FALSE; } } else if(DO_ELECT_DC) { /* tell the local node to initiate an election */ sys_to = CRM_SYSTEM_CRMD; crmd_operation = CRM_OP_VOTE; crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0"); dest_node = NULL; ret = 0; /* no return message */ } else if(DO_WHOIS_DC) { sys_to = CRM_SYSTEM_DC; crmd_operation = CRM_OP_PING; crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0"); dest_node = NULL; } else if(DO_NODE_LIST) { cib_t * the_cib = cib_new(); - crm_data_t *output = NULL; + xmlNode *output = NULL; enum cib_errors rc = the_cib->cmds->signon( the_cib, crm_system_name, cib_command_synchronous); if(rc != cib_ok) { return -1; } output = get_cib_copy(the_cib); do_find_node_list(output); free_xml(output); the_cib->cmds->signoff(the_cib); exit(rc); } else if(DO_RESET) { /* tell dest_node to initiate the shutdown proceedure * * if dest_node is NULL, the request will be sent to the * local node */ sys_to = CRM_SYSTEM_CRMD; crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0"); ret = 0; /* no return message */ } else if(DO_DEBUG == debug_inc) { /* tell dest_node to increase its debug level * * if dest_node is NULL, the request will be sent to the * local node */ sys_to = CRM_SYSTEM_CRMD; crmd_operation = CRM_OP_DEBUG_UP; ret = 0; /* no return message */ } else if(DO_DEBUG == debug_dec) { /* tell dest_node to increase its debug level * * if dest_node is NULL, the request will be sent to the * local node */ sys_to = CRM_SYSTEM_CRMD; crmd_operation = CRM_OP_DEBUG_DOWN; ret = 0; /* no return message */ } else { crm_err("Unknown options"); all_is_good = FALSE; } if(all_is_good == FALSE) { crm_err("Creation of request failed. No message to send"); return -1; } /* send it */ if (crmd_channel == NULL) { crm_err("The IPC connection is not valid, cannot send anything"); return -1; } if(sys_to == NULL) { if (dest_node != NULL) { sys_to = CRM_SYSTEM_CRMD; } else { sys_to = CRM_SYSTEM_DC; } } { - HA_Message *cmd = create_request( + xmlNode *cmd = create_request( crmd_operation, msg_data, dest_node, sys_to, crm_system_name, admin_uuid); if(this_msg_reference != NULL) { - ha_msg_mod(cmd, XML_ATTR_REFERENCE, this_msg_reference); + crm_xml_add(cmd, XML_ATTR_REFERENCE, this_msg_reference); } send_ipc_message(crmd_channel, cmd); - crm_msg_del(cmd); + free_xml(cmd); } return ret; } void crmadmin_ipc_connection_destroy(gpointer user_data) { crm_err("Connection to CRMd was terminated"); if(mainloop) { g_main_quit(mainloop); } else { exit(1); } } gboolean do_init(void) { GCHSource *src = NULL; crm_malloc0(admin_uuid, 11); if(admin_uuid != NULL) { snprintf(admin_uuid, 10, "%d", getpid()); admin_uuid[10] = '\0'; } src = init_client_ipc_comms( CRM_SYSTEM_CRMD, admin_msg_callback, NULL, &crmd_channel); if(DO_RESOURCE || DO_RESOURCE_LIST || DO_NODE_LIST) { return TRUE; } else if(crmd_channel != NULL) { send_hello_message( crmd_channel, admin_uuid, crm_system_name,"0", "1"); set_IPC_Channel_dnotify(src, crmadmin_ipc_connection_destroy); return TRUE; } return FALSE; } gboolean admin_msg_callback(IPC_Channel * server, void *private_data) { int rc = 0; int lpc = 0; + xmlNode *xml = NULL; IPC_Message *msg = NULL; ha_msg_input_t *new_input = NULL; gboolean hack_return_good = TRUE; static int received_responses = 0; char *filename = NULL; int filename_len = 0; const char *result = NULL; Gmain_timeout_remove(message_timer_id); while (server->ch_status != IPC_DISCONNECT && server->ops->is_message_pending(server) == TRUE) { if(new_input != NULL) { delete_ha_msg_input(new_input); new_input = NULL; } rc = server->ops->recv(server, &msg); if (rc != IPC_OK) { cl_perror("Receive failure (%d)", rc); return !hack_return_good; } if (msg == NULL) { crm_debug_4("No message this time"); continue; } lpc++; received_responses++; - new_input = new_ipc_msg_input(msg); - crm_log_message(LOG_MSG, new_input->msg); + + xml = convert_ipc_message(msg, __FUNCTION__); + new_input = new_ipc_msg_input(xml); + free_xml(xml); + + crm_log_xml(LOG_MSG, "ipc", new_input->msg); msg->msg_done(msg); if (new_input->xml == NULL) { crm_info("XML in IPC message was not valid... " "discarding."); goto cleanup; } else if (validate_crm_message( new_input->msg, crm_system_name, admin_uuid, XML_ATTR_RESPONSE) == FALSE) { crm_debug_2("Message was not a CRM response. Discarding."); goto cleanup; } - result = cl_get_string(new_input->msg, XML_ATTR_RESULT); + result = crm_element_value(new_input->msg, XML_ATTR_RESULT); if(result == NULL || strcasecmp(result, "ok") == 0) { result = "pass"; } else { result = "fail"; } if(DO_HEALTH) { const char *state = crm_element_value( new_input->xml, "crmd_state"); printf("Status of %s@%s: %s (%s)\n", crm_element_value(new_input->xml,XML_PING_ATTR_SYSFROM), - cl_get_string(new_input->msg, F_CRM_HOST_FROM), + crm_element_value(new_input->msg, F_CRM_HOST_FROM), state, crm_element_value(new_input->xml,XML_PING_ATTR_STATUS)); if(BE_SILENT && state != NULL) { fprintf(stderr, "%s\n", state); } } else if(DO_WHOIS_DC) { - const char *dc = cl_get_string( + const char *dc = crm_element_value( new_input->msg, F_CRM_HOST_FROM); printf("Designated Controller is: %s\n", dc); if(BE_SILENT && dc != NULL) { fprintf(stderr, "%s\n", dc); } } if (this_msg_reference != NULL) { /* in testing mode... */ /* 31 = "test-_.xml" + an_int_as_string + '\0' */ filename_len = 31 + strlen(this_msg_reference); crm_malloc0(filename, filename_len); if(filename != NULL) { snprintf(filename, filename_len, "%s-%s_%d.xml", result, this_msg_reference, received_responses); filename[filename_len - 1] = '\0'; if (0 > write_xml_file( new_input->xml, filename, FALSE)) { crm_crit("Could not save response to" " %s", filename); } } } cleanup: delete_ha_msg_input(new_input); new_input = NULL; } if (server->ch_status == IPC_DISCONNECT) { crm_debug_2("admin_msg_callback: received HUP"); return !hack_return_good; } if (received_responses >= expected_responses) { crm_debug_2( "Recieved expected number (%d) of messages from Heartbeat." " Exiting normally.", expected_responses); exit(0); } message_timer_id = Gmain_timeout_add( message_timeout_ms, admin_message_timeout, NULL); return hack_return_good; } gboolean admin_message_timeout(gpointer data) { fprintf(stderr, "No messages received in %d seconds.. aborting\n", (int)message_timeout_ms/1000); crm_err("No messages received in %d seconds", (int)message_timeout_ms/1000); operation_status = -3; g_main_quit(mainloop); return FALSE; } gboolean -is_node_online(crm_data_t *node_state) +is_node_online(xmlNode *node_state) { const char *uname = crm_element_value(node_state,XML_ATTR_UNAME); const char *join_state = crm_element_value(node_state,XML_CIB_ATTR_JOINSTATE); const char *exp_state = crm_element_value(node_state,XML_CIB_ATTR_EXPSTATE); const char *crm_state = crm_element_value(node_state,XML_CIB_ATTR_CRMDSTATE); const char *ha_state = crm_element_value(node_state,XML_CIB_ATTR_HASTATE); const char *ccm_state = crm_element_value(node_state,XML_CIB_ATTR_INCCM); if(safe_str_neq(join_state, CRMD_JOINSTATE_DOWN) && (ha_state == NULL || safe_str_eq(ha_state, "active")) && crm_is_true(ccm_state) && safe_str_eq(crm_state, "online")) { crm_debug_3("Node %s is online", uname); return TRUE; } crm_debug_3("Node %s: ha=%s ccm=%s join=%s exp=%s crm=%s", uname, crm_str(ha_state), crm_str(ccm_state), crm_str(join_state), crm_str(exp_state), crm_str(crm_state)); crm_debug_3("Node %s is offline", uname); return FALSE; } int -do_find_node_list(crm_data_t *xml_node) +do_find_node_list(xmlNode *xml_node) { int found = 0; - crm_data_t *nodes = get_object_root(XML_CIB_TAG_NODES, xml_node); + xmlNode *nodes = get_object_root(XML_CIB_TAG_NODES, xml_node); xml_child_iter_filter( nodes, node, XML_CIB_TAG_NODE, if(BASH_EXPORT) { printf("export %s=%s\n", crm_element_value(node, XML_ATTR_UNAME), crm_element_value(node, XML_ATTR_ID)); } else { printf("%s node: %s (%s)\n", crm_element_value(node, XML_ATTR_TYPE), crm_element_value(node, XML_ATTR_UNAME), crm_element_value(node, XML_ATTR_ID)); } found++; ); if(found == 0) { printf("NO nodes configured\n"); } return found; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-?Vs] [command] [command args]\n", cmd); fprintf(stream, "Options\n"); fprintf(stream, "\t--%s (-%c)\t: this help message\n", "help", '?'); fprintf(stream, "\t--%s (-%c)\t: version details\n", "version", 'v'); fprintf(stream, "\t--%s (-%c)\t: " "turn on debug info. additional instances increase verbosity\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c)\t: be very *very* quiet\n", "quiet", 'q'); fprintf(stream, "\t--%s (-%c)\t: Only applies to -N.\n" "\t\tCreate Bash export entries of the form \"export uname=uuid\"\n", "bash-export", 'B'); fprintf(stream, "\nCommands\n"); fprintf(stream, "\t--%s (-%c) \t: " "increment the CRMd debug level on \n", CRM_OP_DEBUG_UP,'i'); fprintf(stream, "\t--%s (-%c) \t: " "decrement the CRMd debug level on \n", CRM_OP_DEBUG_DOWN,'d'); fprintf(stream, "\t--%s (-%c) \t: " "shutdown the CRMd on \n", "kill", 'K'); fprintf(stream, "\t--%s (-%c) \t: " "request the status of \n", "status", 'S'); #if 0 fprintf(stream, "\t--%s (-%c)\t\t: " "request the status of all nodes\n", "health", 'H'); #endif fprintf(stream, "\t--%s (-%c) \t: " "initiate an election from \n", "election", 'E'); fprintf(stream, "\t--%s (-%c)\t: " "request the uname of the DC\n", "dc_lookup", 'D'); fprintf(stream, "\t--%s (-%c)\t\t: " "request the uname of all member nodes\n", "nodes", 'N'); /* fprintf(stream, "\t--%s (-%c)\t\n", "disconnect", 'D'); */ fflush(stream); exit(exit_status); } diff --git a/crm/admin/xml_diff.c b/crm/admin/xml_diff.c index 1611361c88..ecf360b95e 100644 --- a/crm/admin/xml_diff.c +++ b/crm/admin/xml_diff.c @@ -1,268 +1,268 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_GETOPT_H #include #endif #include /* someone complaining about _ha_msg_mod not being found */ void usage(const char *cmd, int exit_status); #define OPTARGS "V?o:n:p:scfO:N:" int main(int argc, char **argv) { gboolean apply = FALSE; gboolean raw_1 = FALSE; gboolean raw_2 = FALSE; gboolean filter = FALSE; gboolean use_stdin = FALSE; gboolean as_cib = FALSE; int argerr = 0; int flag; - crm_data_t *object_1 = NULL; - crm_data_t *object_2 = NULL; - crm_data_t *output = NULL; + xmlNode *object_1 = NULL; + xmlNode *object_2 = NULL; + xmlNode *output = NULL; const char *xml_file_1 = NULL; const char *xml_file_2 = NULL; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {"original", 1, 0, 'o'}, {"new", 1, 0, 'n'}, {"original-string", 1, 0, 'O'}, {"new-string", 1, 0, 'N'}, {"patch", 1, 0, 'p'}, {"stdin", 0, 0, 's'}, {"cib", 0, 0, 'c'}, {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {0, 0, 0, 0} }; #endif crm_log_init("diff", LOG_CRIT-1, FALSE, FALSE, 0, NULL); if(argc < 2) { usage(crm_system_name, LSB_EXIT_EINVAL); } 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) { case 'o': xml_file_1 = optarg; break; case 'O': xml_file_1 = optarg; raw_1 = TRUE; break; case 'n': xml_file_2 = optarg; break; case 'N': xml_file_2 = optarg; raw_2 = TRUE; break; case 'p': xml_file_2 = optarg; apply = TRUE; break; case 'f': filter = TRUE; break; case 's': use_stdin = TRUE; break; case 'c': as_cib = TRUE; break; case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); 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); } if(raw_1) { object_1 = string2xml(xml_file_1); } else if(use_stdin) { fprintf(stderr, "Input first XML fragment:"); object_1 = stdin2xml(); } else if(xml_file_1 != NULL) { FILE *xml_strm = fopen(xml_file_1, "r"); if(xml_strm != NULL) { crm_debug("Reading: %s", xml_file_1); if(strstr(xml_file_1, ".bz2") != NULL) { object_1 = file2xml(xml_strm, TRUE); } else { object_1 = file2xml(xml_strm, FALSE); } fclose(xml_strm); } else { cl_perror("Couldn't open %s for reading", xml_file_1); } } if(raw_2) { object_2 = string2xml(xml_file_2); } else if(use_stdin) { fprintf(stderr, "Input second XML fragment:"); object_2 = stdin2xml(); } else if(xml_file_2 != NULL) { FILE *xml_strm = fopen(xml_file_2, "r"); if(xml_strm != NULL) { crm_debug("Reading: %s", xml_file_2); if(strstr(xml_file_2, ".bz2") != NULL) { object_2 = file2xml(xml_strm, TRUE); } else { object_2 = file2xml(xml_strm, FALSE); } fclose(xml_strm); } else { cl_perror("Couldn't open %s for reading", xml_file_2); } } CRM_ASSERT(object_1 != NULL); CRM_ASSERT(object_2 != NULL); if(apply) { if(as_cib == FALSE) { apply_xml_diff(object_1, object_2, &output); } else { apply_cib_diff(object_1, object_2, &output); } } else { if(as_cib == FALSE) { output = diff_xml_object(object_1, object_2, filter); } else { output = diff_cib_object(object_1, object_2, filter); } } if(output != NULL) { char *buffer = dump_xml_formatted(output); fprintf(stdout, "%s", crm_str(buffer)); crm_free(buffer); } free_xml(object_1); free_xml(object_2); free_xml(output); if(apply == FALSE && output != NULL) { return 1; } return 0; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status != 0 ? stderr : stdout; fprintf(stream, "usage: %s [-?V] [oO] [pnN]\n", cmd); fprintf(stream, "Options\n"); fprintf(stream, "\t--%s (-%c)\tthis help message\n", "help", '?'); fprintf(stream, "\t--%s (-%c) \t\n", "original", 'o'); fprintf(stream, "\t--%s (-%c) \t\n", "new", 'n'); fprintf(stream, "\t--%s (-%c) \t\n", "original-string", 'O'); fprintf(stream, "\t--%s (-%c) \t\n", "new-string", 'N'); fprintf(stream, "\t--%s (-%c) \tApply a patch to the original XML\n", "patch", 'p'); fprintf(stream, "\t--%s (-%c)\tCompare/patch the inputs as a CIB\n", "cib", 'c'); fprintf(stream, "\t--%s (-%c)\tRead the inputs from stdin\n", "stdin", 's'); fflush(stream); exit(exit_status); } diff --git a/crm/ais/ipc_bridge.c b/crm/ais/ipc_bridge.c index b007f09b5c..e1c0e465d2 100644 --- a/crm/ais/ipc_bridge.c +++ b/crm/ais/ipc_bridge.c @@ -1,225 +1,225 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int num_clients = 0; GHashTable *ipc_client_list = NULL; gboolean ais_shutdown_flag = FALSE; typedef struct ais_client_s { char *id; char *name; char *callback_id; const char *channel_name; IPC_Channel *channel; GCHSource *source; unsigned long num_calls; } ais_client_t; static void ais_ipc_connection_destroy(gpointer user_data) { ais_client_t *ais_client = user_data; if(ais_client == NULL) { return; } if(ais_client->source != NULL) { crm_debug_4("Deleting %s (%p) from mainloop", ais_client->name, ais_client->source); G_main_del_IPC_Channel(ais_client->source); ais_client->source = NULL; } crm_debug_3("Destroying %s (%p)", ais_client->name, user_data); num_clients--; crm_debug("Num unfree'd clients: %d", num_clients); crm_free(ais_client->name); crm_free(ais_client->callback_id); crm_free(ais_client->id); crm_free(ais_client); crm_debug_4("Freed the cib client"); return; } static gboolean ais_process_disconnect(IPC_Channel *channel, ais_client_t *ais_client) { if (channel == NULL) { CRM_DEV_ASSERT(ais_client == NULL); } else if (ais_client == NULL) { crm_err("No client"); } else { CRM_DEV_ASSERT(channel->ch_status != IPC_CONNECT); crm_debug_2("Cleaning up after client disconnect: %s/%s/%s", crm_str(ais_client->name), ais_client->channel_name, ais_client->id); if(ais_client->id != NULL) { if(!g_hash_table_remove(ipc_client_list, ais_client->id)) { crm_err("Client %s not found in the hashtable", ais_client->name); } } } if(ais_shutdown_flag && g_hash_table_size(ipc_client_list) == 0) { crm_info("All clients disconnected..."); exit(0); } return FALSE; } static gboolean ais_ipc_callback(IPC_Channel *channel, gpointer user_data) { int lpc = 0; - HA_Message *op_request = NULL; + xmlNode *op_request = NULL; gboolean keep_channel = TRUE; ais_client_t *ais_client = user_data; if(ais_client == NULL) { crm_err("Receieved call from unknown source. Discarding."); return FALSE; } if(ais_client->name == NULL) { ais_client->name = crm_itoa(channel->farside_pid); } if(ais_client->id == NULL) { ais_client->id = crm_strdup(ais_client->name); g_hash_table_insert(ipc_client_list, ais_client->id, ais_client); } crm_err("Callback for %s on %s channel", ais_client->id, ais_client->channel_name); while(IPC_ISRCONN(channel)) { if(channel->ops->is_message_pending(channel) == 0) { break; } op_request = msgfromIPC_noauth(channel); if (op_request == NULL) { perror("Receive failure:"); break; } lpc++; crm_assert_failed = FALSE; ha_msg_add(op_request, "client-id", ais_client->id); ha_msg_add(op_request, "client-name", ais_client->name); - crm_log_message_adv(LOG_ERR, "Client[inbound]", op_request); + crm_log_xml(LOG_ERR, "Client[inbound]", op_request); /* cib_common_callback_worker( */ /* op_request, cib_client, force_synchronous, privileged); */ crm_msg_del(op_request); if(channel->ch_status == IPC_CONNECT) { break; } } crm_debug_2("Processed %d messages", lpc); if(channel->ch_status != IPC_CONNECT) { crm_debug_2("Client disconnected"); keep_channel = ais_process_disconnect(channel, ais_client); } return keep_channel; } gboolean ais_client_connect(IPC_Channel *channel, gpointer user_data) { const char *channel_name = user_data; ais_client_t *new_client = NULL; crm_debug_3("Connecting channel"); if (channel == NULL) { crm_err("Channel was NULL"); } else if (channel->ch_status != IPC_CONNECT) { crm_err("Channel was disconnected"); } else if(channel_name == NULL) { crm_err("user_data must contain channel name"); } else if(ais_shutdown_flag) { crm_info("Ignoring new client [%d] during shutdown", channel->farside_pid); } else { crm_malloc0(new_client, sizeof(ais_client_t)); num_clients++; new_client->channel = channel; new_client->channel_name = channel_name; crm_debug_3("Created channel %p for channel %s", new_client, new_client->channel_name); channel->ops->set_recv_qlen(channel, 500); channel->ops->set_send_qlen(channel, 500); new_client->source = G_main_add_IPC_Channel( G_PRIORITY_DEFAULT, channel, FALSE, ais_ipc_callback, new_client, ais_ipc_connection_destroy); crm_debug_3("Channel %s connected for client %s", new_client->channel_name, new_client->id); } if(new_client == NULL) { return FALSE; } return TRUE; } diff --git a/crm/ais/test.c b/crm/ais/test.c index 327f4b34e4..fc800bcd2a 100644 --- a/crm/ais/test.c +++ b/crm/ais/test.c @@ -1,104 +1,104 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_GETOPT_H # include #endif int message_timer_id = -1; int message_timeout_ms = 30*1000; GMainLoop *mainloop = NULL; void usage(const char *cmd, int exit_status); #define OPTARGS "V?K:S:HE:Dd:i:RNqt:Bv" int main(int argc, char **argv) { int rc = 0; const char *host = NULL; - crm_data_t *msg = NULL; + xmlNode *msg = NULL; crm_log_init(basename(argv[0]), LOG_DEBUG, FALSE, TRUE, 0, NULL); msg = create_xml_node(NULL, XML_TAG_OPTIONS); crm_xml_add(msg, "hello", "world"); crm_xml_add(msg, "time", "now"); if(argc > 1) { host = argv[1]; } rc = send_ais_message(msg, FALSE, host, crm_msg_ais); if (rc != SA_AIS_OK) { return 1; } mainloop = g_main_new(FALSE); /* message_timer_id = Gmain_timeout_add( */ /* message_timeout_ms, admin_message_timeout, NULL); */ g_main_run(mainloop); crm_debug_2("%s exiting normally", crm_system_name); return 0; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-?Vs] [command] [command args]\n", cmd); fprintf(stream, "Options\n"); fprintf(stream, "\t--%s (-%c)\t: this help message\n", "help", '?'); fflush(stream); exit(exit_status); } diff --git a/crmd/atest.c b/crmd/atest.c index 6c5531384d..24799061ce 100644 --- a/crmd/atest.c +++ b/crmd/atest.c @@ -1,42 +1,143 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include -#define OPTARGS "V?f:" +#define OPTARGS "V?X:I:" + +#ifdef HAVE_GETOPT_H +# include +#endif int main(int argc, char ** argv) { - if(crm_get_msec("0") < 0) { - fprintf(stderr, "error\n"); + int flag; + char *buffer = NULL; + xmlNode *xml = NULL; + HA_Message *ha = NULL; + const char *xml_file = NULL; + const char *input_file = NULL; + + crm_log_init("atest", LOG_DEBUG, FALSE, TRUE, argc, argv); + while (1) { +#ifdef HAVE_GETOPT_H + int option_index = 0; + static struct option long_options[] = { + /* Top-level Options */ + {"help", 0, 0, '?'}, + {"verbose", 0, 0, 'V'}, + + {"xml-file", 1, 0, 'X'}, + {"save-input", 1, 0, 'I'}, + + {0, 0, 0, 0} + }; +#endif + +#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"); + + break; +#endif + case 'X': + xml_file = optarg; + break; + case 'I': + input_file = optarg; + break; + case '?': + /* usage("ptest", 0); */ + break; + default: + printf("?? getopt returned character code 0%o ??\n", flag); + break; } - return 0; + } + + if(xml_file != NULL) { + FILE *xml_strm = fopen(xml_file, "r"); + if(xml_strm == NULL) { + cl_perror("Could not open %s for reading", xml_file); + + } else { + if(strstr(xml_file, ".bz2") != NULL) { + xml = file2xml(xml_strm, TRUE); + + } else { + xml = file2xml(xml_strm, FALSE); + } + fclose(xml_strm); + } + } + + crm_log_xml_info(xml, "read"); + + ha = convert_xml_message(xml); + crm_log_message_adv(LOG_INFO, "ha", ha); + + xml = convert_ha_message(NULL, ha, "foo"); + + crm_log_xml_info(xml, "write"); + + if(input_file != NULL) { + FILE *input_strm = fopen(input_file, "w"); + if(input_strm == NULL) { + cl_perror("Could not open %s for writing", input_file); + } else { + buffer = dump_xml_formatted(xml); + if(fprintf(input_strm, "%s\n", buffer) < 0) { + cl_perror("Write to %s failed", input_file); + } + fflush(input_strm); + fclose(input_strm); + crm_free(buffer); + } + } + + if(crm_get_msec("0") < 0) { + fprintf(stderr, "error\n"); + } + return 0; } diff --git a/crmd/callbacks.c b/crmd/callbacks.c index d2c0cc50c7..f7d80d2b78 100644 --- a/crmd/callbacks.c +++ b/crmd/callbacks.c @@ -1,649 +1,650 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include -crm_data_t *find_xml_in_hamessage(const HA_Message * msg); +xmlNode *find_xml_in_hamessage(const xmlNode * msg); void crmd_ha_connection_destroy(gpointer user_data); -void crmd_ha_msg_filter(HA_Message *msg); +void crmd_ha_msg_filter(xmlNode *msg); /* From join_dc... */ extern gboolean check_join_state( enum crmd_fsa_state cur_state, const char *source); /* #define MAX_EMPTY_CALLBACKS 20 */ /* int empty_callbacks = 0; */ #define trigger_fsa(source) crm_debug_3("Triggering FSA: %s", __FUNCTION__); \ G_main_set_trigger(source); #if SUPPORT_HEARTBEAT gboolean crmd_ha_msg_dispatch(ll_cluster_t *cluster_conn, gpointer user_data) { IPC_Channel *channel = NULL; gboolean stay_connected = TRUE; crm_debug_3("Invoked"); if(cluster_conn != NULL) { channel = cluster_conn->llc_ops->ipcchan(cluster_conn); } CRM_CHECK(cluster_conn != NULL, ;); CRM_CHECK(channel != NULL, ;); if(channel != NULL && IPC_ISRCONN(channel)) { if(cluster_conn->llc_ops->msgready(cluster_conn) == 0) { crm_debug_2("no message ready yet"); } /* invoke the callbacks but dont block */ cluster_conn->llc_ops->rcvmsg(cluster_conn, 0); } if (channel == NULL || channel->ch_status != IPC_CONNECT) { if(is_set(fsa_input_register, R_HA_DISCONNECTED) == FALSE) { crm_crit("Lost connection to heartbeat service."); } else { crm_info("Lost connection to heartbeat service."); } trigger_fsa(fsa_source); stay_connected = FALSE; } return stay_connected; } #endif void crmd_ha_connection_destroy(gpointer user_data) { crm_debug_3("Invoked"); if(is_set(fsa_input_register, R_HA_DISCONNECTED)) { /* we signed out, so this is expected */ crm_info("Heartbeat disconnection complete"); return; } crm_crit("Lost connection to heartbeat service!"); register_fsa_input(C_HA_DISCONNECT, I_ERROR, NULL); trigger_fsa(fsa_source); } void -crmd_ha_msg_filter(HA_Message *msg) +crmd_ha_msg_filter(xmlNode *msg) { ha_msg_input_t *new_input = NULL; - const char *from = ha_msg_value(msg, F_ORIG); - const char *seq = ha_msg_value(msg, F_SEQ); - const char *op = ha_msg_value(msg, F_CRM_TASK); + const char *from = crm_element_value(msg, F_ORIG); + const char *seq = crm_element_value(msg, F_SEQ); + const char *op = crm_element_value(msg, F_CRM_TASK); - const char *sys_to = ha_msg_value(msg, F_CRM_SYS_TO); - const char *sys_from = ha_msg_value(msg, F_CRM_SYS_FROM); + const char *sys_to = crm_element_value(msg, F_CRM_SYS_TO); + const char *sys_from = crm_element_value(msg, F_CRM_SYS_FROM); if(safe_str_eq(sys_to, CRM_SYSTEM_DC) && AM_I_DC == FALSE) { crm_debug_2("Ignoring message for the DC [F_SEQ=%s]", seq); return; } else if(safe_str_eq(sys_from, CRM_SYSTEM_DC)) { if(AM_I_DC && safe_str_neq(from, fsa_our_uname)) { crm_err("Another DC detected: %s (op=%s)", from, op); /* make sure the election happens NOW */ if(fsa_state != S_ELECTION) { new_input = new_ha_msg_input(msg); register_fsa_error_adv(C_FSA_INTERNAL, I_ELECTION, NULL, new_input, __FUNCTION__); } } else { crm_debug_2("Processing DC message from %s [F_SEQ=%s]", from, seq); } } if(new_input == NULL) { - crm_log_message_adv(LOG_MSG, "HA[inbound]", msg); + crm_log_xml(LOG_MSG, "HA[inbound]", msg); new_input = new_ha_msg_input(msg); route_message(C_HA_MESSAGE, new_input); } delete_ha_msg_input(new_input); trigger_fsa(fsa_source); } #if SUPPORT_HEARTBEAT void -crmd_ha_msg_callback(HA_Message * msg, void* private_data) +crmd_ha_msg_callback(HA_Message *hamsg, void* private_data) { int level = LOG_DEBUG; oc_node_t *from_node = NULL; - const char *from = ha_msg_value(msg, F_ORIG); - const char *op = ha_msg_value(msg, F_CRM_TASK); - const char *sys_from = ha_msg_value(msg, F_CRM_SYS_FROM); + xmlNode *msg = convert_ha_message(NULL, hamsg, __FUNCTION__); + const char *from = crm_element_value(msg, F_ORIG); + const char *op = crm_element_value(msg, F_CRM_TASK); + const char *sys_from = crm_element_value(msg, F_CRM_SYS_FROM); - CRM_DEV_ASSERT(from != NULL); + CRM_CHECK(from != NULL, crm_log_xml_err(msg, "anon"); return); crm_debug_2("HA[inbound]: %s from %s", op, from); if(crm_peer_cache == NULL || crm_active_members() == 0) { crm_debug("Ignoring HA messages until we are" " connected to the CCM (%s op from %s)", op, from); - crm_log_message_adv( + crm_log_xml( LOG_MSG, "HA[inbound]: Ignore (No CCM)", msg); return; } from_node = g_hash_table_lookup(crm_peer_cache, from); if(from_node == NULL) { if(safe_str_eq(op, CRM_OP_VOTE)) { level = LOG_WARNING; } else if(AM_I_DC && safe_str_eq(op, CRM_OP_JOIN_ANNOUNCE)) { level = LOG_WARNING; } else if(safe_str_eq(sys_from, CRM_SYSTEM_DC)) { level = LOG_WARNING; } do_crm_log(level, "Ignoring HA message (op=%s) from %s: not in our" " membership list (size=%d)", op, from, crm_active_members()); - crm_log_message_adv(LOG_MSG, "HA[inbound]: CCM Discard", msg); + crm_log_xml(LOG_MSG, "HA[inbound]: CCM Discard", msg); } else { crmd_ha_msg_filter(msg); } return; } #endif /* * Apparently returning TRUE means "stay connected, keep doing stuff". * Returning FALSE means "we're all done, close the connection" */ gboolean crmd_ipc_msg_callback(IPC_Channel *client, gpointer user_data) { int lpc = 0; - HA_Message *msg = NULL; + xmlNode *msg = NULL; ha_msg_input_t *new_input = NULL; crmd_client_t *curr_client = (crmd_client_t*)user_data; gboolean stay_connected = TRUE; crm_debug_2("Invoked: %s", curr_client->table_key); while(IPC_ISRCONN(client)) { if(client->ops->is_message_pending(client) == 0) { break; } - msg = msgfromIPC_noauth(client); + msg = xmlfromIPC(client, 0); if (msg == NULL) { crm_info("%s: no message this time", curr_client->table_key); continue; } lpc++; new_input = new_ha_msg_input(msg); - crm_msg_del(msg); + free_xml(msg); crm_debug_2("Processing msg from %s", curr_client->table_key); - crm_log_message_adv(LOG_DEBUG_2, "CRMd[inbound]", new_input->msg); + crm_log_xml(LOG_DEBUG_2, "CRMd[inbound]", new_input->msg); if(crmd_authorize_message(new_input, curr_client)) { route_message(C_IPC_MESSAGE, new_input); } delete_ha_msg_input(new_input); new_input = NULL; msg = NULL; if(client->ch_status != IPC_CONNECT) { break; } } crm_debug_2("Processed %d messages", lpc); if (client->ch_status != IPC_CONNECT) { stay_connected = FALSE; process_client_disconnect(curr_client); } trigger_fsa(fsa_source); return stay_connected; } extern GCHSource *lrm_source; gboolean lrm_dispatch(IPC_Channel *src_not_used, gpointer user_data) { /* ?? src == lrm_channel ?? */ ll_lrm_t *lrm = (ll_lrm_t*)user_data; IPC_Channel *lrm_channel = lrm->lrm_ops->ipcchan(lrm); crm_debug_3("Invoked"); lrm->lrm_ops->rcvmsg(lrm, FALSE); if(lrm_channel->ch_status != IPC_CONNECT) { if(is_set(fsa_input_register, R_LRM_CONNECTED)) { crm_crit("LRM Connection failed"); register_fsa_input(C_FSA_INTERNAL, I_ERROR, NULL); clear_bit_inplace(fsa_input_register, R_LRM_CONNECTED); } else { crm_info("LRM Connection disconnected"); } lrm_source = NULL; return FALSE; } return TRUE; } extern gboolean process_lrm_event(lrm_op_t *op); void lrm_op_callback(lrm_op_t* op) { CRM_CHECK(op != NULL, return); process_lrm_event(op); } void crmd_ha_status_callback(const char *node, const char *status, void *private) { - crm_data_t *update = NULL; + xmlNode *update = NULL; crm_node_t *member = NULL; crm_notice("Status update: Node %s now has status [%s]",node,status); member = g_hash_table_lookup(crm_peer_cache, node); if(member == NULL) { /* Make sure it is created so crm_update_peer_proc() succeeds */ const char *uuid = get_uuid(node); member = crm_update_peer(0, 0, -1, 0, uuid, node, NULL, NULL); } if(safe_str_eq(status, PINGSTATUS)) { return; } if(safe_str_eq(status, DEADSTATUS)) { /* this node is toast */ crm_update_peer_proc(node, crm_proc_ais, OFFLINESTATUS); update = create_node_state( node, DEADSTATUS, XML_BOOLEAN_NO, OFFLINESTATUS, CRMD_STATE_INACTIVE, NULL, TRUE, __FUNCTION__); } else { crm_update_peer_proc(node, crm_proc_ais, ONLINESTATUS); update = create_node_state( node, ACTIVESTATUS, NULL, NULL, NULL, NULL, FALSE, __FUNCTION__); } if(update != NULL) { /* this change should not be broadcast */ fsa_cib_anon_update( XML_CIB_TAG_STATUS, update, cib_inhibit_bcast|cib_scope_local|cib_quorum_override); trigger_fsa(fsa_source); free_xml(update); } } void crmd_client_status_callback(const char * node, const char * client, const char * status, void * private) { const char *join = NULL; crm_node_t *member = NULL; - crm_data_t *update = NULL; + xmlNode *update = NULL; gboolean clear_shutdown = FALSE; crm_debug_3("Invoked"); if(safe_str_neq(client, CRM_SYSTEM_CRMD)) { return; } if(safe_str_eq(status, JOINSTATUS)){ status = ONLINESTATUS; clear_shutdown = TRUE; } else if(safe_str_eq(status, LEAVESTATUS)){ status = OFFLINESTATUS; join = CRMD_STATE_INACTIVE; /* clear_shutdown = TRUE; */ } set_bit_inplace(fsa_input_register, R_PEER_DATA); crm_notice("Status update: Client %s/%s now has status [%s]", node, client, status); if(safe_str_eq(status, ONLINESTATUS)) { /* remove the cached value in case it changed */ crm_debug_2("Uncaching UUID for %s", node); unget_uuid(node); } member = g_hash_table_lookup(crm_peer_cache, node); if(member == NULL) { /* Make sure it is created so crm_update_peer_proc() succeeds */ const char *uuid = get_uuid(node); member = crm_update_peer(0, 0, -1, 0, uuid, node, NULL, NULL); } crm_update_peer_proc(node, crm_proc_crmd, status); if(is_set(fsa_input_register, R_CIB_CONNECTED) == FALSE) { return; } else if(fsa_state == S_STOPPING) { return; } if(safe_str_eq(node, fsa_our_dc) && safe_str_eq(status, OFFLINESTATUS)){ /* did our DC leave us */ crm_info("Got client status callback - our DC is dead"); register_fsa_input(C_CRMD_STATUS_CALLBACK, I_ELECTION, NULL); } else { crm_debug_3("Got client status callback"); update = create_node_state(node, NULL, NULL, status, join, NULL, clear_shutdown, __FUNCTION__); if(safe_str_eq(status, ONLINESTATUS)){ crm_xml_add(update, XML_CIB_ATTR_REPLACE, XML_CIB_TAG_LRM",,"XML_TAG_TRANSIENT_NODEATTRS","); } /* it is safe to keep these updates on the local node * each node updates their own CIB */ fsa_cib_anon_update( XML_CIB_TAG_STATUS, update, cib_inhibit_bcast|cib_scope_local|cib_quorum_override); free_xml(update); if(AM_I_DC && safe_str_eq(status, OFFLINESTATUS)) { erase_node_from_join(node); check_join_state(fsa_state, __FUNCTION__); } } trigger_fsa(fsa_source); } void crmd_ipc_connection_destroy(gpointer user_data) { GCHSource *source = NULL; crmd_client_t *client = user_data; /* Calling this function on an _active_ connection results in: * crmd_ipc_connection_destroy (callbacks.c:431) * -> G_main_del_IPC_Channel (GSource.c:478) * -> g_source_unref * -> G_CH_destroy_int (GSource.c:647) * -> crmd_ipc_connection_destroy (callbacks.c:437)\ * * A better alternative is to call G_main_del_IPC_Channel() directly */ if(client == NULL) { crm_debug_4("No client to delete"); return; } crm_debug_2("Disconnecting client %s (%p)", client->table_key, client); source = client->client_source; client->client_source = NULL; if(source != NULL) { crm_debug_3("Deleting %s (%p) from mainloop", client->table_key, source); G_main_del_IPC_Channel(source); } crm_free(client->table_key); crm_free(client->sub_sys); crm_free(client->uuid); crm_free(client); return; } gboolean crmd_client_connect(IPC_Channel *client_channel, gpointer user_data) { crm_debug_3("Invoked"); if (client_channel == NULL) { crm_err("Channel was NULL"); } else if (client_channel->ch_status == IPC_DISCONNECT) { crm_err("Channel was disconnected"); } else { crmd_client_t *blank_client = NULL; crm_debug_3("Channel connected"); crm_malloc0(blank_client, sizeof(crmd_client_t)); CRM_ASSERT(blank_client != NULL); crm_debug_2("Created client: %p", blank_client); client_channel->ops->set_recv_qlen(client_channel, 1024); client_channel->ops->set_send_qlen(client_channel, 1024); blank_client->client_channel = client_channel; blank_client->sub_sys = NULL; blank_client->uuid = NULL; blank_client->table_key = NULL; blank_client->client_source = G_main_add_IPC_Channel( G_PRIORITY_LOW, client_channel, FALSE, crmd_ipc_msg_callback, blank_client, crmd_ipc_connection_destroy); } return TRUE; } #if SUPPORT_HEARTBEAT static gboolean fsa_have_quorum = FALSE; gboolean ccm_dispatch(int fd, gpointer user_data) { int rc = 0; oc_ev_t *ccm_token = (oc_ev_t*)user_data; gboolean was_error = FALSE; crm_debug_3("Invoked"); rc = oc_ev_handle_event(ccm_token); if(rc != 0) { if(is_set(fsa_input_register, R_CCM_DISCONNECTED) == FALSE) { /* we signed out, so this is expected */ register_fsa_input(C_CCM_CALLBACK, I_ERROR, NULL); crm_err("CCM connection appears to have failed: rc=%d.", rc); } was_error = TRUE; } trigger_fsa(fsa_source); return !was_error; } void crmd_ccm_msg_callback( oc_ed_t event, void *cookie, size_t size, const void *data) { gboolean update_cache = FALSE; const oc_ev_membership_t *membership = data; gboolean update_quorum = FALSE; gboolean trigger_transition = FALSE; crm_debug_3("Invoked"); CRM_ASSERT(data != NULL); crm_info("Quorum %s after event=%s (id=%d)", ccm_have_quorum(event)?"(re)attained":"lost", ccm_event_name(event), membership->m_instance); if(crm_peer_seq > membership->m_instance) { crm_err("Membership instance ID went backwards! %llu->%d", crm_peer_seq, membership->m_instance); CRM_ASSERT(crm_peer_seq <= membership->m_instance); return; } /* * OC_EV_MS_NEW_MEMBERSHIP: membership with quorum * OC_EV_MS_MS_INVALID: membership without quorum * OC_EV_MS_NOT_PRIMARY: previous membership no longer valid * OC_EV_MS_PRIMARY_RESTORED: previous membership restored * OC_EV_MS_EVICTED: the client is evicted from ccm. */ switch(event) { case OC_EV_MS_NEW_MEMBERSHIP: case OC_EV_MS_INVALID: update_cache = TRUE; update_quorum = TRUE; break; case OC_EV_MS_NOT_PRIMARY: break; case OC_EV_MS_PRIMARY_RESTORED: update_cache = TRUE; crm_peer_seq = membership->m_instance; if(AM_I_DC && need_transition(fsa_state)) { trigger_transition = TRUE; } break; case OC_EV_MS_EVICTED: update_quorum = TRUE; register_fsa_input(C_FSA_INTERNAL, I_STOP, NULL); crm_err("Shutting down after CCM event: %s", ccm_event_name(event)); break; default: crm_err("Unknown CCM event: %d", event); } if(update_quorum) { crm_have_quorum = ccm_have_quorum(event); crm_update_quorum(crm_have_quorum); if(crm_have_quorum == FALSE) { /* did we just loose quorum? */ if(fsa_have_quorum && need_transition(fsa_state)) { crm_info("Quorum lost: triggering transition (%s)", ccm_event_name(event)); trigger_transition = TRUE; } } } if(update_cache) { crm_debug_2("Updating cache after event %s", ccm_event_name(event)); do_ccm_update_cache(C_CCM_CALLBACK, fsa_state, event, data, NULL); } else if(event != OC_EV_MS_NOT_PRIMARY) { crm_peer_seq = membership->m_instance; register_fsa_action(A_TE_CANCEL); } oc_ev_callback_done(cookie); return; } #endif void crmd_cib_connection_destroy(gpointer user_data) { crm_debug_3("Invoked"); trigger_fsa(fsa_source); if(is_set(fsa_input_register, R_CIB_CONNECTED) == FALSE) { crm_info("Connection to the CIB terminated..."); return; } /* eventually this will trigger a reconnect, not a shutdown */ crm_err("Connection to the CIB terminated..."); register_fsa_input(C_FSA_INTERNAL, I_ERROR, NULL); clear_bit_inplace(fsa_input_register, R_CIB_CONNECTED); return; } longclock_t fsa_start = 0; longclock_t fsa_stop = 0; longclock_t fsa_diff = 0; gboolean crm_fsa_trigger(gpointer user_data) { unsigned int fsa_diff_ms = 0; if(fsa_diff_max_ms > 0) { fsa_start = time_longclock(); } crm_debug_2("Invoked (queue len: %d)", g_list_length(fsa_message_queue)); s_crmd_fsa(C_FSA_INTERNAL); crm_debug_2("Exited (queue len: %d)", g_list_length(fsa_message_queue)); if(fsa_diff_max_ms > 0) { fsa_stop = time_longclock(); fsa_diff = sub_longclock(fsa_stop, fsa_start); fsa_diff_ms = longclockto_ms(fsa_diff); if(fsa_diff_ms > fsa_diff_max_ms) { crm_err("FSA took %dms to complete", fsa_diff_ms); } else if(fsa_diff_ms > fsa_diff_warn_ms) { crm_warn("FSA took %dms to complete", fsa_diff_ms); } } return TRUE; } diff --git a/crmd/ccm.c b/crmd/ccm.c index e74d8c180f..bb8ecde8cb 100644 --- a/crmd/ccm.c +++ b/crmd/ccm.c @@ -1,478 +1,478 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #if SUPPORT_HEARTBEAT #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include gboolean membership_flux_hack = FALSE; void post_cache_update(int instance); #if SUPPORT_HEARTBEAT oc_ev_t *fsa_ev_token; void oc_ev_special(const oc_ev_t *, oc_ev_class_t , int ); void crmd_ccm_msg_callback( oc_ed_t event, void *cookie, size_t size, const void *data); #endif void ghash_update_cib_node(gpointer key, gpointer value, gpointer user_data); void check_dead_member(const char *uname, GHashTable *members); void reap_dead_ccm_nodes(gpointer key, gpointer value, gpointer user_data); #define CCM_EVENT_DETAIL 0 #define CCM_EVENT_DETAIL_PARTIAL 0 int num_ccm_register_fails = 0; int max_ccm_register_fails = 30; int last_peer_update = 0; extern GHashTable *voted; struct update_data_s { const char *state; const char *caller; - crm_data_t *updates; + xmlNode *updates; gboolean overwrite_join; }; void reap_dead_ccm_nodes(gpointer key, gpointer value, gpointer user_data) { crm_node_t *node = value; if(crm_is_member_active(node) == FALSE) { check_dead_member(node->uname, NULL); } } void check_dead_member(const char *uname, GHashTable *members) { CRM_CHECK(uname != NULL, return); if(members != NULL && g_hash_table_lookup(members, uname) != NULL) { crm_err("%s didnt really leave the membership!", uname); return; } erase_node_from_join(uname); if(voted != NULL) { g_hash_table_remove(voted, uname); } if(safe_str_eq(fsa_our_uname, uname)) { crm_err("We're not part of the cluster anymore"); } if(AM_I_DC == FALSE && safe_str_eq(uname, fsa_our_dc)) { crm_warn("Our DC node (%s) left the cluster", uname); register_fsa_input(C_FSA_INTERNAL, I_ELECTION, NULL); } } /* A_CCM_CONNECT */ void 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) { #if SUPPORT_HEARTBEAT if(is_heartbeat_cluster()) { if(action & A_CCM_DISCONNECT){ set_bit_inplace(fsa_input_register, R_CCM_DISCONNECTED); oc_ev_unregister(fsa_ev_token); } if(action & A_CCM_CONNECT) { int ret; int fsa_ev_fd; gboolean did_fail = FALSE; crm_peer_init(); crm_debug_3("Registering with CCM"); clear_bit_inplace(fsa_input_register, R_CCM_DISCONNECTED); 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; } else { crm_err("CCM Activation failed %d (max) times", num_ccm_register_fails); register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL); return; } } crm_info("CCM connection established..." " waiting for first callback"); G_main_add_fd(G_PRIORITY_HIGH, fsa_ev_fd, FALSE, ccm_dispatch, fsa_ev_token, default_ipc_connection_destroy); } } #endif if(action & ~(A_CCM_CONNECT|A_CCM_DISCONNECT)) { crm_err("Unexpected action %s in %s", fsa_action2string(action), __FUNCTION__); } } #if SUPPORT_HEARTBEAT 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); } crm_debug_2("-----------------------"); } #endif void post_cache_update(int instance) { static int last_size = 0; - HA_Message *no_op = NULL; + xmlNode *no_op = NULL; if(is_openais_cluster()) { int new_size = crm_active_members(); membership_flux_hack = FALSE; if((last_size - new_size) > 1) { crm_info("We're lost more than two peers (%d -> %d): Potential membership instability", last_size, new_size); membership_flux_hack = TRUE; } last_size = new_size; } crm_peer_seq = instance; crm_debug("Updated cache after membership event %d.", instance); if((fsa_input_register & R_CCM_DATA) == 0) { populate_cib_nodes(FALSE); } g_hash_table_foreach(crm_peer_cache, reap_dead_ccm_nodes, NULL); set_bit_inplace(fsa_input_register, R_CCM_DATA); do_update_cib_nodes(FALSE, __FUNCTION__); /* Membership changed, remind everyone we're here. * This will aid detection of duplicate DCs */ no_op = create_request( CRM_OP_NOOP, NULL, NULL, CRM_SYSTEM_CRMD, AM_I_DC?CRM_SYSTEM_DC:CRM_SYSTEM_CRMD, NULL); send_msg_via_ha(no_op); } /* A_CCM_UPDATE_CACHE */ /* * Take the opportunity to update the node status in the CIB as well */ #if SUPPORT_HEARTBEAT void do_ccm_update_cache( enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, - oc_ed_t event, const oc_ev_membership_t *oc, crm_data_t *xml) + oc_ed_t event, const oc_ev_membership_t *oc, xmlNode *xml) { unsigned long long instance = 0; unsigned int lpc = 0; if(is_heartbeat_cluster()) { CRM_ASSERT(oc != NULL); instance = oc->m_instance; } CRM_ASSERT(crm_peer_seq <= instance); switch(cur_state) { case S_STOPPING: case S_TERMINATE: case S_HALT: crm_debug("Ignoring %s CCM event %llu, we're in state %s", ccm_event_name(event), instance, fsa_state2string(cur_state)); return; case S_ELECTION: register_fsa_action(A_ELECTION_CHECK); break; default: break; } if(is_heartbeat_cluster()) { ccm_event_detail(oc, event); /*--*-- Recently Dead Member Nodes --*--*/ for(lpc=0; lpc < oc->m_n_out; lpc++) { crm_update_ccm_node(oc, lpc+oc->m_out_idx, CRM_NODE_LOST); } /*--*-- All Member Nodes --*--*/ for(lpc=0; lpc < oc->m_n_member; lpc++) { crm_update_ccm_node(oc, lpc+oc->m_memb_idx, CRM_NODE_ACTIVE); } } if(event == OC_EV_MS_EVICTED) { crm_update_peer( 0, 0, -1, 0, fsa_our_uuid, fsa_our_uname, NULL, CRM_NODE_EVICTED); /* 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_adv(cause, I_ERROR, NULL, NULL, __FUNCTION__); } post_cache_update(instance); return; } #endif static void -ccm_node_update_complete(const HA_Message *msg, int call_id, int rc, - crm_data_t *output, void *user_data) +ccm_node_update_complete(xmlNode *msg, int call_id, int rc, + xmlNode *output, void *user_data) { fsa_data_t *msg_data = NULL; last_peer_update = 0; if(rc == cib_ok) { crm_debug("Node update %d complete", call_id); } else { crm_err("Node update %d failed", call_id); - crm_log_message(LOG_DEBUG, msg); + crm_log_xml(LOG_DEBUG, "failed", msg); register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); } } void ghash_update_cib_node(gpointer key, gpointer value, gpointer user_data) { - crm_data_t *tmp1 = NULL; + xmlNode *tmp1 = NULL; const char *join = NULL; crm_node_t *node = value; struct update_data_s* data = (struct update_data_s*)user_data; data->state = XML_BOOLEAN_NO; if(safe_str_eq(node->state, CRM_NODE_ACTIVE)) { data->state = XML_BOOLEAN_YES; } crm_debug_2("Updating %s: %s (overwrite=%s)", node->uname, data->state, data->overwrite_join?"true":"false"); if(data->overwrite_join) { if((node->processes & crm_proc_crmd) == FALSE) { join = CRMD_JOINSTATE_DOWN; } else { const char *peer_member = g_hash_table_lookup( confirmed_nodes, node->uname); if(peer_member != NULL) { join = CRMD_JOINSTATE_MEMBER; } else { join = CRMD_JOINSTATE_PENDING; } } } tmp1 = create_node_state( node->uname, (node->processes&crm_proc_ais)?ACTIVESTATUS:DEADSTATUS, data->state, (node->processes&crm_proc_crmd)?ONLINESTATUS:OFFLINESTATUS, join, NULL, FALSE, data->caller); add_node_copy(data->updates, tmp1); free_xml(tmp1); } void do_update_cib_nodes(gboolean overwrite, const char *caller) { int call_id = 0; int call_options = cib_scope_local|cib_quorum_override; struct update_data_s update_data; - crm_data_t *fragment = NULL; + xmlNode *fragment = NULL; if(crm_peer_cache == NULL) { /* We got a replace notification before being connected to * the CCM. * So there is no need to update the local CIB with our values * - since we have none. */ return; } fragment = create_xml_node(NULL, XML_CIB_TAG_STATUS); update_data.caller = caller; update_data.updates = fragment; update_data.overwrite_join = overwrite; if(overwrite == FALSE) { call_options = call_options|cib_inhibit_bcast; crm_debug_2("Inhibiting bcast for membership updates"); } g_hash_table_foreach(crm_peer_cache, ghash_update_cib_node, &update_data); fsa_cib_update(XML_CIB_TAG_STATUS, fragment, call_options, call_id); add_cib_op_callback(call_id, FALSE, NULL, ccm_node_update_complete); last_peer_update = call_id; free_xml(fragment); } static void cib_quorum_update_complete( - const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data) + xmlNode *msg, int call_id, int rc, xmlNode *output, void *user_data) { fsa_data_t *msg_data = NULL; if(rc == cib_ok) { crm_debug("Quorum update %d complete", call_id); } else { crm_err("Quorum update %d failed", call_id); - crm_log_message(LOG_DEBUG, msg); + crm_log_xml(LOG_DEBUG, "failed", msg); register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); } } void crm_update_quorum(gboolean bool) { int call_id = 0; - crm_data_t *update = NULL; + xmlNode *update = NULL; int call_options = cib_scope_local|cib_quorum_override; fsa_has_quorum = bool; update = create_xml_node(NULL, XML_TAG_CIB); crm_xml_add_int(update, XML_ATTR_HAVE_QUORUM, fsa_has_quorum); fsa_cib_update(XML_TAG_CIB, update, call_options, call_id); crm_info("Updating quorum status to %s (call=%d)", bool?"true":"false", call_id); add_cib_op_callback(call_id, FALSE, NULL, cib_quorum_update_complete); free_xml(update); } diff --git a/crmd/cib.c b/crmd/cib.c index 6f4d3dec48..b7e74abe12 100644 --- a/crmd/cib.c +++ b/crmd/cib.c @@ -1,311 +1,310 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include /* for access */ #include #include #include /* for calls to open */ #include /* for calls to open */ #include /* for calls to open */ #include /* for getpwuid */ #include /* for initgroups */ #include /* for getrlimit */ #include /* for getrlimit */ #include #include #include #include #include #include #include struct crm_subsystem_s *cib_subsystem = NULL; int cib_retries = 0; static void -revision_check_callback(const HA_Message *msg, int call_id, int rc, - crm_data_t *output, void *user_data) +revision_check_callback(xmlNode *msg, int call_id, int rc, + xmlNode *output, void *user_data) { int cmp = -1; const char *revision = NULL; - crm_data_t *generation = NULL; + xmlNode *generation = NULL; #if CRM_DEPRECATED_SINCE_2_0_4 if(safe_str_eq(crm_element_name(output), XML_TAG_CIB)) { generation = output; } else { generation = find_xml_node(output, XML_TAG_CIB, TRUE); } #else generation = output; CRM_DEV_ASSERT(safe_str_eq(crm_element_name(generation), XML_TAG_CIB)); #endif if(rc != cib_ok) { fsa_data_t *msg_data = NULL; register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); return; } crm_debug_3("Checking our feature revision is allowed: %s", CIB_FEATURE_SET); revision = crm_element_value(generation, XML_ATTR_CIB_REVISION); cmp = compare_version(revision, CIB_FEATURE_SET); if(cmp > 0) { crm_err("This build (%s) does not support the current" " resource configuration", VERSION); crm_err("We can support up to CIB feature set %s (current=%s)", CIB_FEATURE_SET, revision); crm_err("Shutting down the CRM"); /* go into a stall state */ register_fsa_error_adv( C_FSA_INTERNAL, I_SHUTDOWN, NULL, NULL, __FUNCTION__); return; } revision = crm_element_value(generation, XML_ATTR_CRM_VERSION); cmp = compare_version(revision, CRM_FEATURE_SET); if(cmp > 0) { crm_err("This build (%s) does not support the current" " resource configuration", VERSION); crm_err("We can support up to CRM feature set %s (current=%s)", revision, CRM_FEATURE_SET); crm_err("Shutting down the CRM"); /* go into a stall state */ register_fsa_error_adv( C_FSA_INTERNAL, I_SHUTDOWN, NULL, NULL, __FUNCTION__); return; } } static void -do_cib_replaced(const char *event, HA_Message *msg) +do_cib_replaced(const char *event, xmlNode *msg) { crm_debug("Updating the CIB after a replace"); populate_cib_nodes(FALSE); do_update_cib_nodes(AM_I_DC, __FUNCTION__); if(AM_I_DC) { /* start the join process again so we get everyone's LRM status */ register_fsa_input(C_FSA_INTERNAL, I_ELECTION, NULL); } } /* A_CIB_STOP, A_CIB_START, A_CIB_RESTART, */ void do_cib_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) { struct crm_subsystem_s *this_subsys = cib_subsystem; long long stop_actions = A_CIB_STOP; long long start_actions = A_CIB_START; if(action & stop_actions) { crm_info("Disconnecting CIB"); clear_bit_inplace(fsa_input_register, R_CIB_CONNECTED); CRM_ASSERT(fsa_cib_conn != NULL); if(fsa_cib_conn->state != cib_disconnected) { fsa_cib_conn->cmds->set_slave( fsa_cib_conn, cib_scope_local); fsa_cib_conn->cmds->signoff(fsa_cib_conn); } } if(action & start_actions) { int rc = cib_ok; CRM_ASSERT(fsa_cib_conn != NULL); if(cur_state == S_STOPPING) { crm_err("Ignoring request to start %s after shutdown", this_subsys->name); return; } rc = fsa_cib_conn->cmds->signon( fsa_cib_conn, CRM_SYSTEM_CRMD, cib_command); if(rc != cib_ok) { /* a short wait that usually avoids stalling the FSA */ sleep(1); rc = fsa_cib_conn->cmds->signon( fsa_cib_conn, CRM_SYSTEM_CRMD, cib_command); } if(rc != cib_ok){ crm_debug("Could not connect to the CIB service"); } else if(cib_ok != fsa_cib_conn->cmds->set_connection_dnotify( fsa_cib_conn, crmd_cib_connection_destroy)) { crm_err("Could not set dnotify callback"); } else if(cib_ok != fsa_cib_conn->cmds->add_notify_callback( fsa_cib_conn, T_CIB_REPLACE_NOTIFY, do_cib_replaced)) { crm_err("Could not set CIB notification callback"); } else { set_bit_inplace( fsa_input_register, R_CIB_CONNECTED); } if(is_set(fsa_input_register, R_CIB_CONNECTED) == FALSE) { cib_retries++; crm_warn("Couldn't complete CIB registration %d" " times... pause and retry", cib_retries); if(cib_retries < 30) { crm_timer_start(wait_timer); crmd_fsa_stall(NULL); } else { crm_err("Could not complete CIB" " registration %d times..." " hard error", cib_retries); register_fsa_error( C_FSA_INTERNAL, I_ERROR, NULL); } } else { int call_id = 0; crm_info("CIB connection established"); call_id = fsa_cib_conn->cmds->query( fsa_cib_conn, NULL, NULL, cib_scope_local); add_cib_op_callback(call_id, FALSE, NULL, revision_check_callback); cib_retries = 0; } } } /* A_CIB_INVOKE, A_CIB_BUMPGEN, A_UPDATE_NODESTATUS */ void do_cib_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) { - HA_Message *answer = NULL; + xmlNode *answer = NULL; ha_msg_input_t *cib_msg = fsa_typed_data(fsa_dt_ha_msg); - const char *sys_from = cl_get_string(cib_msg->msg, F_CRM_SYS_FROM); + const char *sys_from = crm_element_value(cib_msg->msg, F_CRM_SYS_FROM); if(fsa_cib_conn->state == cib_disconnected) { if(cur_state != S_STOPPING) { crm_err("CIB is disconnected"); - crm_log_message_adv(LOG_WARNING, "CIB Input", cib_msg->msg); + crm_log_xml(LOG_WARNING, "CIB Input", cib_msg->msg); return; } crm_info("CIB is disconnected"); - crm_log_message_adv(LOG_DEBUG, "CIB Input", cib_msg->msg); + crm_log_xml(LOG_DEBUG, "CIB Input", cib_msg->msg); return; } if(action & A_CIB_INVOKE) { if(safe_str_eq(sys_from, CRM_SYSTEM_CRMD)) { action = A_CIB_INVOKE_LOCAL; } else if(safe_str_eq(sys_from, CRM_SYSTEM_DC)) { action = A_CIB_INVOKE_LOCAL; } } if(action & A_CIB_INVOKE || action & A_CIB_INVOKE_LOCAL) { int call_options = 0; enum cib_errors rc = cib_ok; - crm_data_t *cib_frag = NULL; + xmlNode *cib_frag = NULL; const char *section = NULL; - const char *op = cl_get_string(cib_msg->msg, F_CRM_TASK); + const char *op = crm_element_value(cib_msg->msg, F_CRM_TASK); - section = cl_get_string(cib_msg->msg, F_CIB_SECTION); + section = crm_element_value(cib_msg->msg, F_CIB_SECTION); - ha_msg_value_int(cib_msg->msg, F_CIB_CALLOPTS, &call_options); + crm_element_value_int(cib_msg->msg, F_CIB_CALLOPTS, &call_options); - crm_log_message(LOG_MSG, cib_msg->msg); - crm_log_xml_debug_3(cib_msg->xml, "[CIB update]"); + crm_log_xml(LOG_MSG, "udpate", cib_msg->msg); if(op == NULL) { crm_err("Invalid CIB Message"); register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); return; } cib_frag = NULL; rc = fsa_cib_conn->cmds->variant_op( fsa_cib_conn, op, NULL, section, cib_msg->xml, &cib_frag, call_options); if(rc < cib_ok || (action & A_CIB_INVOKE)) { answer = create_reply(cib_msg->msg, cib_frag); - ha_msg_add(answer,XML_ATTR_RESULT,cib_error2string(rc)); + crm_xml_add(answer,XML_ATTR_RESULT,cib_error2string(rc)); } if(action & A_CIB_INVOKE) { if(relay_message(answer, TRUE) == FALSE) { crm_err("Confused what to do with cib result"); - crm_log_message(LOG_ERR, answer); - crm_msg_del(answer); + crm_log_xml(LOG_ERR, "reply", answer); + free_xml(answer); register_fsa_input(C_FSA_INTERNAL, I_ERROR, NULL); return; } } else if(rc < cib_ok) { ha_msg_input_t *input = NULL; crm_err("Internal CRM/CIB command from %s() failed: %s", msg_data->origin, cib_error2string(rc)); - crm_log_message_adv(LOG_WARNING, "CIB Input", cib_msg->msg); - crm_log_message_adv(LOG_WARNING, "CIB Reply", answer); + crm_log_xml(LOG_WARNING, "CIB Input", cib_msg->msg); + crm_log_xml(LOG_WARNING, "CIB Reply", answer); input = new_ha_msg_input(answer); register_fsa_input(C_FSA_INTERNAL, I_ERROR, input); - crm_msg_del(answer); + free_xml(answer); delete_ha_msg_input(input); } } else { crm_err("Unexpected action %s in %s", fsa_action2string(action), __FUNCTION__); } } diff --git a/crmd/control.c b/crmd/control.c index 7003f43565..ed8771d595 100644 --- a/crmd/control.c +++ b/crmd/control.c @@ -1,975 +1,975 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include char *ipc_server = NULL; extern void post_cache_update(int seq); extern void crmd_ha_connection_destroy(gpointer user_data); gboolean crm_shutdown(int nsig, gpointer unused); gboolean fsa_has_quorum = FALSE; GHashTable *ipc_clients = NULL; GTRIGSource *fsa_source = NULL; /* A_HA_CONNECT */ #if SUPPORT_AIS -extern void crmd_ha_msg_filter(HA_Message * msg); +extern void crmd_ha_msg_filter(xmlNode * msg); static gboolean crm_ais_dispatch(AIS_Message *wrapper, char *data, int sender) { int seq = 0; const char *seq_s = NULL; - crm_data_t *xml = string2xml(data); + xmlNode *xml = string2xml(data); if(xml == NULL) { crm_err("Message received: %d:'%.120s'", wrapper->id, data); return TRUE; } crm_debug_2("Message received: %d:'%.120s'", wrapper->id, data); - ha_msg_add(xml, F_ORIG, wrapper->sender.uname); - ha_msg_add_int(xml, F_SEQ, wrapper->id); + crm_xml_add(xml, F_ORIG, wrapper->sender.uname); + crm_xml_add_int(xml, F_SEQ, wrapper->id); switch(wrapper->header.id) { case crm_class_notify: break; case crm_class_members: seq_s = crm_element_value(xml, "seq"); CRM_ASSERT(xml != NULL); seq = crm_int_helper(seq_s, NULL); set_bit_inplace(fsa_input_register, R_PEER_DATA); post_cache_update(seq); crm_update_quorum(crm_have_quorum); break; default: crmd_ha_msg_filter(xml); break; } free_xml(xml); return TRUE; } static void crm_ais_destroy(gpointer user_data) { crm_err("AIS connection terminated"); ais_fd_sync = -1; exit(1); } #endif void do_ha_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 registered = FALSE; if(action & A_HA_DISCONNECT) { if(is_openais_cluster()) { crm_peer_destroy(); crm_info("Disconnected from OpenAIS"); #if SUPPORT_HEARTBEAT } else if(fsa_cluster_conn != NULL) { set_bit_inplace(fsa_input_register, R_HA_DISCONNECTED); fsa_cluster_conn->llc_ops->signoff(fsa_cluster_conn, FALSE); crm_info("Disconnected from Heartbeat"); #endif } } if(action & A_HA_CONNECT) { void *dispatch = NULL; void *destroy = NULL; if(is_openais_cluster()) { #if SUPPORT_AIS destroy = crm_ais_destroy; dispatch = crm_ais_dispatch; #endif } else if(is_heartbeat_cluster()) { #if SUPPORT_HEARTBEAT dispatch = crmd_ha_msg_callback; destroy = crmd_ha_connection_destroy; #endif } registered = crm_cluster_connect( &fsa_our_uname, &fsa_our_uuid, dispatch, destroy, #if SUPPORT_HEARTBEAT &fsa_cluster_conn #else NULL #endif ); #if SUPPORT_HEARTBEAT if(is_heartbeat_cluster()) { crm_debug_3("Be informed of Node Status changes"); if (registered && fsa_cluster_conn->llc_ops->set_nstatus_callback( fsa_cluster_conn, crmd_ha_status_callback, fsa_cluster_conn) != HA_OK){ crm_err("Cannot set nstatus callback: %s", fsa_cluster_conn->llc_ops->errmsg(fsa_cluster_conn)); registered = FALSE; } crm_debug_3("Be informed of CRM Client Status changes"); if (registered && fsa_cluster_conn->llc_ops->set_cstatus_callback( fsa_cluster_conn, crmd_client_status_callback, fsa_cluster_conn) != HA_OK) { crm_err("Cannot set cstatus callback: %s", fsa_cluster_conn->llc_ops->errmsg(fsa_cluster_conn)); registered = FALSE; } populate_cib_nodes(TRUE); } #endif if(registered == FALSE) { set_bit_inplace(fsa_input_register, R_HA_DISCONNECTED); register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); return; } clear_bit_inplace(fsa_input_register, R_HA_DISCONNECTED); crm_info("Connected to Heartbeat"); } if(action & ~(A_HA_CONNECT|A_HA_DISCONNECT)) { crm_err("Unexpected action %s in %s", fsa_action2string(action), __FUNCTION__); } } /* A_SHUTDOWN */ void do_shutdown(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 lpc = 0; gboolean continue_shutdown = TRUE; struct crm_subsystem_s *subsystems[] = { pe_subsystem, te_subsystem }; /* just in case */ set_bit_inplace(fsa_input_register, R_SHUTDOWN); for(lpc = 0; lpc < DIMOF(subsystems); lpc++) { struct crm_subsystem_s *a_subsystem = subsystems[lpc]; if(is_set(fsa_input_register, a_subsystem->flag_connected)) { crm_info("Terminating the %s", a_subsystem->name); if(stop_subsystem(a_subsystem, TRUE) == FALSE) { /* its gone... */ crm_err("Faking %s exit", a_subsystem->name); clear_bit_inplace(fsa_input_register, a_subsystem->flag_connected); } continue_shutdown = FALSE; } } if(continue_shutdown == FALSE) { crm_info("Waiting for subsystems to exit"); crmd_fsa_stall(NULL); } crm_info("All subsystems stopped, continuing"); } /* A_SHUTDOWN_REQ */ void do_shutdown_req(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) { - HA_Message *msg = NULL; + xmlNode *msg = NULL; crm_info("Sending shutdown request to DC: %s", crm_str(fsa_our_dc)); msg = create_request( CRM_OP_SHUTDOWN_REQ, NULL, NULL, CRM_SYSTEM_DC, CRM_SYSTEM_CRMD, NULL); /* set_bit_inplace(fsa_input_register, R_STAYDOWN); */ if(send_request(msg, NULL) == FALSE) { if(AM_I_DC) { crm_info("Processing shutdown locally"); } else { register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); } } } extern char *max_generation_from; -extern crm_data_t *max_generation_xml; +extern xmlNode *max_generation_xml; extern GHashTable *meta_hash; extern GHashTable *resources; extern GHashTable *voted; void log_connected_client(gpointer key, gpointer value, gpointer user_data); void log_connected_client(gpointer key, gpointer value, gpointer user_data) { crmd_client_t *client = value; crm_err("%s is still connected at exit", client->table_key); } static void free_mem(fsa_data_t *msg_data) { #if SUPPORT_HEARTBEAT if(fsa_cluster_conn) { fsa_cluster_conn->llc_ops->delete(fsa_cluster_conn); fsa_cluster_conn = NULL; } #endif slist_destroy(fsa_data_t, fsa_data, fsa_message_queue, crm_info("Dropping %s: [ state=%s cause=%s origin=%s ]", fsa_input2string(fsa_data->fsa_input), fsa_state2string(fsa_state), fsa_cause2string(fsa_data->fsa_cause), fsa_data->origin); delete_fsa_input(fsa_data); ); delete_fsa_input(msg_data); if(ipc_clients) { crm_debug("Number of connected clients: %d", g_hash_table_size(ipc_clients)); /* g_hash_table_foreach(ipc_clients, log_connected_client, NULL); */ g_hash_table_destroy(ipc_clients); } empty_uuid_cache(); crm_peer_destroy(); clear_bit_inplace(fsa_input_register, R_CCM_DATA); if(te_subsystem->client && te_subsystem->client->client_source) { crm_debug("Full destroy: TE"); G_main_del_IPC_Channel(te_subsystem->client->client_source); } else { crm_debug("Partial destroy: TE"); crmd_ipc_connection_destroy(te_subsystem->client); } crm_free(te_subsystem); if(pe_subsystem->client && pe_subsystem->client->client_source) { crm_debug("Full destroy: PE"); G_main_del_IPC_Channel(pe_subsystem->client->client_source); } else { crm_debug("Partial destroy: PE"); crmd_ipc_connection_destroy(pe_subsystem->client); } crm_free(pe_subsystem); crm_free(cib_subsystem); if(integrated_nodes) { g_hash_table_destroy(integrated_nodes); } if(finalized_nodes) { g_hash_table_destroy(finalized_nodes); } if(confirmed_nodes) { g_hash_table_destroy(confirmed_nodes); } if(meta_hash) { g_hash_table_destroy(meta_hash); } if(resources) { g_hash_table_destroy(resources); } if(voted) { g_hash_table_destroy(voted); } cib_delete(fsa_cib_conn); fsa_cib_conn = NULL; if(fsa_lrm_conn) { fsa_lrm_conn->lrm_ops->delete(fsa_lrm_conn); } crm_free(integration_timer); crm_free(finalization_timer); crm_free(election_trigger); crm_free(election_timeout); crm_free(shutdown_escalation_timer); crm_free(wait_timer); crm_free(recheck_timer); crm_free(fsa_our_dc_version); crm_free(fsa_our_uuid); crm_free(fsa_our_dc); crm_free(ipc_server); crm_free(max_generation_from); free_xml(max_generation_xml); } /* A_EXIT_0, A_EXIT_1 */ void do_exit(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 exit_code = 0; int log_level = LOG_INFO; const char *exit_type = "gracefully"; if(action & A_EXIT_1) { exit_code = 1; log_level = LOG_ERR; exit_type = "forcefully"; } verify_stopped(cur_state, LOG_ERR); do_crm_log(log_level, "Performing %s - %s exiting the CRMd", fsa_action2string(action), exit_type); if(is_set(fsa_input_register, R_IN_RECOVERY)) { crm_err("Could not recover from internal error"); exit_code = 2; } if(is_set(fsa_input_register, R_STAYDOWN)) { crm_warn("Inhibiting respawn by Heartbeat"); exit_code = 100; } free_mem(msg_data); crm_info("[%s] stopped (%d)", crm_system_name, exit_code); cl_flush_logs(); exit(exit_code); } /* A_STARTUP */ void do_startup(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 was_error = 0; int interval = 1; /* seconds between DC heartbeats */ crm_debug("Registering Signal Handlers"); G_main_add_SignalHandler( G_PRIORITY_HIGH, SIGTERM, crm_shutdown, NULL, NULL); fsa_source = G_main_add_TriggerHandler( G_PRIORITY_HIGH, crm_fsa_trigger, NULL, NULL); ipc_clients = g_hash_table_new(g_str_hash, g_str_equal); crm_debug("Creating CIB and LRM objects"); fsa_cib_conn = cib_new(); fsa_lrm_conn = ll_lrm_new(XML_CIB_TAG_LRM); crm_debug("Init server comms"); if(ipc_server == NULL) { ipc_server = crm_strdup(CRM_SYSTEM_CRMD); } was_error = init_server_ipc_comms(ipc_server, crmd_client_connect, default_ipc_connection_destroy); /* set up the timers */ crm_malloc0(integration_timer, sizeof(fsa_timer_t)); crm_malloc0(finalization_timer, sizeof(fsa_timer_t)); crm_malloc0(election_trigger, sizeof(fsa_timer_t)); crm_malloc0(election_timeout, sizeof(fsa_timer_t)); crm_malloc0(shutdown_escalation_timer, sizeof(fsa_timer_t)); crm_malloc0(wait_timer, sizeof(fsa_timer_t)); crm_malloc0(recheck_timer, sizeof(fsa_timer_t)); interval = interval * 1000; if(election_trigger != NULL) { election_trigger->source_id = 0; election_trigger->period_ms = -1; election_trigger->fsa_input = I_DC_TIMEOUT; election_trigger->callback = crm_timer_popped; election_trigger->repeat = FALSE; } else { was_error = TRUE; } if(election_timeout != NULL) { election_timeout->source_id = 0; election_timeout->period_ms = -1; election_timeout->fsa_input = I_ELECTION_DC; election_timeout->callback = crm_timer_popped; election_timeout->repeat = FALSE; } else { was_error = TRUE; } if(integration_timer != NULL) { integration_timer->source_id = 0; integration_timer->period_ms = -1; integration_timer->fsa_input = I_INTEGRATED; integration_timer->callback = crm_timer_popped; integration_timer->repeat = FALSE; } else { was_error = TRUE; } if(finalization_timer != NULL) { finalization_timer->source_id = 0; finalization_timer->period_ms = -1; finalization_timer->fsa_input = I_FINALIZED; finalization_timer->callback = crm_timer_popped; finalization_timer->repeat = FALSE; /* for possible enabling... a bug in the join protocol left * a slave in S_PENDING while we think its in S_NOT_DC * * raising I_FINALIZED put us into a transition loop which is * never resolved. * in this loop we continually send probes which the node * NACK's because its in S_PENDING * * if we have nodes where heartbeat is active but the * CRM is not... then this will be handled in the * integration phase */ finalization_timer->fsa_input = I_ELECTION; } else { was_error = TRUE; } if(shutdown_escalation_timer != NULL) { shutdown_escalation_timer->source_id = 0; shutdown_escalation_timer->period_ms = -1; shutdown_escalation_timer->fsa_input = I_STOP; shutdown_escalation_timer->callback = crm_timer_popped; shutdown_escalation_timer->repeat = FALSE; } else { was_error = TRUE; } if(wait_timer != NULL) { wait_timer->source_id = 0; wait_timer->period_ms = 2000; wait_timer->fsa_input = I_NULL; wait_timer->callback = crm_timer_popped; wait_timer->repeat = FALSE; } else { was_error = TRUE; } if(recheck_timer != NULL) { recheck_timer->source_id = 0; recheck_timer->period_ms = -1; recheck_timer->fsa_input = I_PE_CALC; recheck_timer->callback = crm_timer_popped; recheck_timer->repeat = FALSE; } else { was_error = TRUE; } /* set up the sub systems */ crm_malloc0(cib_subsystem, sizeof(struct crm_subsystem_s)); crm_malloc0(te_subsystem, sizeof(struct crm_subsystem_s)); crm_malloc0(pe_subsystem, sizeof(struct crm_subsystem_s)); if(cib_subsystem != NULL) { cib_subsystem->pid = -1; cib_subsystem->path = BIN_DIR; cib_subsystem->name = CRM_SYSTEM_CIB; cib_subsystem->command = BIN_DIR"/"CRM_SYSTEM_CIB; cib_subsystem->args = "-VVc"; cib_subsystem->flag_connected = R_CIB_CONNECTED; cib_subsystem->flag_required = R_CIB_REQUIRED; } else { was_error = TRUE; } if(te_subsystem != NULL) { te_subsystem->pid = -1; te_subsystem->path = BIN_DIR; te_subsystem->name = CRM_SYSTEM_TENGINE; te_subsystem->command = BIN_DIR"/"CRM_SYSTEM_TENGINE; te_subsystem->args = NULL; te_subsystem->flag_connected = R_TE_CONNECTED; te_subsystem->flag_required = R_TE_REQUIRED; } else { was_error = TRUE; } if(pe_subsystem != NULL) { pe_subsystem->pid = -1; pe_subsystem->path = BIN_DIR; pe_subsystem->name = CRM_SYSTEM_PENGINE; pe_subsystem->command = BIN_DIR"/"CRM_SYSTEM_PENGINE; pe_subsystem->args = NULL; pe_subsystem->flag_connected = R_PE_CONNECTED; pe_subsystem->flag_required = R_PE_REQUIRED; } else { was_error = TRUE; } if(was_error) { register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); } welcomed_nodes = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); integrated_nodes = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); finalized_nodes = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); confirmed_nodes = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); set_sigchld_proctrack(G_PRIORITY_HIGH,DEFAULT_MAXDISPATCHTIME); } /* A_STOP */ void do_stop(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) { register_fsa_input(C_FSA_INTERNAL, I_TERMINATE, NULL); } /* A_STARTED */ void do_started(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) { if(cur_state != S_STARTING) { crm_err("Start cancelled... %s", fsa_state2string(cur_state)); return; } else if(is_set(fsa_input_register, R_CCM_DATA) == FALSE) { crm_info("Delaying start, CCM (%.16llx) not connected", R_CCM_DATA); crmd_fsa_stall(NULL); return; } else if(is_set(fsa_input_register, R_LRM_CONNECTED) == FALSE) { crm_info("Delaying start, LRM (%.16llx) not connected", R_LRM_CONNECTED); crmd_fsa_stall(NULL); return; } else if(is_set(fsa_input_register, R_CIB_CONNECTED) == FALSE) { crm_info("Delaying start, CIB (%.16llx) not connected", R_CIB_CONNECTED); crmd_fsa_stall(NULL); return; } else if(is_set(fsa_input_register, R_READ_CONFIG) == FALSE) { crm_info("Delaying start, Config not read (%.16llx)", R_READ_CONFIG); crmd_fsa_stall(NULL); return; } else if(is_set(fsa_input_register, R_PEER_DATA) == FALSE) { HA_Message *msg = NULL; /* try reading from HA */ crm_info("Delaying start, Peer data (%.16llx) not recieved", R_PEER_DATA); crm_debug_3("Looking for a HA message"); #if SUPPORT_HEARTBEAT if(is_heartbeat_cluster()) { msg = fsa_cluster_conn->llc_ops->readmsg(fsa_cluster_conn, 0); } #endif if(msg != NULL) { crm_debug_3("There was a HA message"); crm_msg_del(msg); } /* this should no longer be required */ /* crm_timer_start(wait_timer); */ crmd_fsa_stall(NULL); return; } crm_info("The local CRM is operational"); clear_bit_inplace(fsa_input_register, R_STARTING); register_fsa_input(msg_data->fsa_cause, I_PENDING, NULL); } /* A_RECOVER */ void do_recover(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) { set_bit_inplace(fsa_input_register, R_IN_RECOVERY); crm_err("Action %s (%.16llx) not supported", fsa_action2string(action), action); register_fsa_input(C_FSA_INTERNAL, I_TERMINATE, NULL); } pe_cluster_option crmd_opts[] = { /* name, old-name, validate, default, description */ { XML_CONFIG_ATTR_DC_DEADTIME, NULL, "time", NULL, "10s", &check_time, "How long to wait for a response from other nodes during startup.", "The \"correct\" value will depend on the speed and load of your network." }, { XML_CONFIG_ATTR_RECHECK, NULL, "time", "Zero disables polling. Positive values are an interval in seconds (unless other SI units are specified. eg. 5min)", "0", &check_timer, "Polling interval for time based changes to options, resource parameters and constraints.", "The Cluster is primarily event driven, however the configuration can have elements that change based on time. To ensure these changes take effect, we can optionally poll the cluster's status for changes." }, { XML_CONFIG_ATTR_ELECTION_FAIL, NULL, "time", NULL, "2min", &check_timer, "*** Advanced Use Only ***.", "If need to adjust this value, it probably indicates the presence of a bug." }, { XML_CONFIG_ATTR_FORCE_QUIT, NULL, "time", NULL, "20min", &check_timer, "*** Advanced Use Only ***.", "If need to adjust this value, it probably indicates the presence of a bug." }, { "crmd-integration-timeout", NULL, "time", NULL, "3min", &check_timer, "*** Advanced Use Only ***.", "If need to adjust this value, it probably indicates the presence of a bug." }, { "crmd-finalization-timeout", NULL, "time", NULL, "30min", &check_timer, "*** Advanced Use Only ***.", "If you need to adjust this value, it probably indicates the presence of a bug." }, }; void crmd_metadata(void) { config_metadata("CRM Daemon", "1.0", "CRM Daemon Options", "This is a fake resource that details the options that can be configured for the CRM Daemon.", crmd_opts, DIMOF(crmd_opts)); } static void verify_crmd_options(GHashTable *options) { verify_all_options(options, crmd_opts, DIMOF(crmd_opts)); } static const char * crmd_pref(GHashTable *options, const char *name) { return get_cluster_pref(options, crmd_opts, DIMOF(crmd_opts), name); } static void -config_query_callback(const HA_Message *msg, int call_id, int rc, - crm_data_t *output, void *user_data) +config_query_callback(xmlNode *msg, int call_id, int rc, + xmlNode *output, void *user_data) { const char *value = NULL; GHashTable *config_hash = NULL; ha_time_t *now = new_ha_date(TRUE); if(rc != cib_ok) { fsa_data_t *msg_data = NULL; crm_err("Local CIB query resulted in an error: %s", cib_error2string(rc)); register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); if(rc == cib_bad_permissions || rc == cib_bad_digest || rc == cib_bad_config) { crm_err("The cluster is mis-configured - shutting down and staying down"); set_bit_inplace(fsa_input_register, R_STAYDOWN); } return; } crm_debug("Call %d : Parsing CIB options", call_id); config_hash = g_hash_table_new_full( g_str_hash,g_str_equal, g_hash_destroy_str,g_hash_destroy_str); unpack_instance_attributes( output, XML_CIB_TAG_PROPSET, NULL, config_hash, CIB_OPTIONS_FIRST, now); value = g_hash_table_lookup(config_hash, XML_CONFIG_ATTR_DC_DEADTIME); if(value == NULL) { /* apparently we're not allowed to free the result of getenv */ char *param_val = getenv(ENV_PREFIX "initdead"); value = crmd_pref(config_hash, XML_CONFIG_ATTR_DC_DEADTIME); if(param_val != NULL) { int from_env = crm_get_msec(param_val) / 2; int from_defaults = crm_get_msec(value); if(from_env > from_defaults) { g_hash_table_replace( config_hash, crm_strdup(XML_CONFIG_ATTR_DC_DEADTIME), crm_strdup(param_val)); } } } verify_crmd_options(config_hash); value = crmd_pref(config_hash, XML_CONFIG_ATTR_DC_DEADTIME); election_trigger->period_ms = crm_get_msec(value); value = crmd_pref(config_hash, XML_CONFIG_ATTR_FORCE_QUIT); shutdown_escalation_timer->period_ms = crm_get_msec(value); value = crmd_pref(config_hash, XML_CONFIG_ATTR_ELECTION_FAIL); election_timeout->period_ms = crm_get_msec(value); value = crmd_pref(config_hash, XML_CONFIG_ATTR_RECHECK); recheck_timer->period_ms = crm_get_msec(value); value = crmd_pref(config_hash, "crmd-integration-timeout"); integration_timer->period_ms = crm_get_msec(value); value = crmd_pref(config_hash, "crmd-finalization-timeout"); finalization_timer->period_ms = crm_get_msec(value); set_bit_inplace(fsa_input_register, R_READ_CONFIG); crm_debug_3("Triggering FSA: %s", __FUNCTION__); G_main_set_trigger(fsa_source); g_hash_table_destroy(config_hash); } /* A_READCONFIG */ void do_read_config(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 = fsa_cib_conn->cmds->query( fsa_cib_conn, XML_CIB_TAG_CRMCONFIG, NULL, cib_scope_local); add_cib_op_callback(call_id, FALSE, NULL, config_query_callback); crm_debug_2("Querying the CIB... call %d", call_id); } gboolean crm_shutdown(int nsig, gpointer unused) { if (crmd_mainloop != NULL && g_main_is_running(crmd_mainloop)) { if(is_set(fsa_input_register, R_SHUTDOWN)) { crm_err("Escalating the shutdown"); register_fsa_input_before(C_SHUTDOWN, I_ERROR, NULL); } else { crm_info("Requesting shutdown"); set_bit_inplace(fsa_input_register, R_SHUTDOWN); register_fsa_input(C_SHUTDOWN,I_SHUTDOWN,NULL); if(shutdown_escalation_timer->period_ms < 1) { GHashTable *config_hash = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); const char *value = crmd_pref( config_hash, XML_CONFIG_ATTR_FORCE_QUIT); int msec = crm_get_msec(value); crm_info("Using default shutdown escalation: %dms", msec); shutdown_escalation_timer->period_ms = msec; g_hash_table_destroy(config_hash); } /* cant rely on this... */ crm_timer_start(shutdown_escalation_timer); } } else { crm_info("exit from shutdown"); exit(LSB_EXIT_OK); } return TRUE; } static void -default_cib_update_callback(const HA_Message *msg, int call_id, int rc, - crm_data_t *output, void *user_data) +default_cib_update_callback(xmlNode *msg, int call_id, int rc, + xmlNode *output, void *user_data) { if(rc != cib_ok) { fsa_data_t *msg_data = NULL; crm_err("CIB Update failed: %s", cib_error2string(rc)); crm_log_xml_warn(output, "update:failed"); register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); } } #if SUPPORT_HEARTBEAT static void populate_cib_nodes_ha(gboolean with_client_status) { int call_id = 0; const char *ha_node = NULL; - crm_data_t *cib_node_list = NULL; + xmlNode *cib_node_list = NULL; if(fsa_cluster_conn == NULL) { crm_debug("Not connected"); return; } /* Async get client status information in the cluster */ crm_debug_2("Invoked"); if(with_client_status) { crm_debug_3("Requesting an initial dump of CRMD client_status"); fsa_cluster_conn->llc_ops->client_status( fsa_cluster_conn, NULL, CRM_SYSTEM_CRMD, -1); } crm_info("Requesting the list of configured nodes"); fsa_cluster_conn->llc_ops->init_nodewalk(fsa_cluster_conn); cib_node_list = create_xml_node(NULL, XML_CIB_TAG_NODES); do { const char *ha_node_type = NULL; const char *ha_node_uuid = NULL; - crm_data_t *cib_new_node = NULL; + xmlNode *cib_new_node = NULL; ha_node = fsa_cluster_conn->llc_ops->nextnode(fsa_cluster_conn); if(ha_node == NULL) { continue; } ha_node_type = fsa_cluster_conn->llc_ops->node_type( fsa_cluster_conn, ha_node); if(safe_str_neq(NORMALNODE, ha_node_type)) { crm_debug("Node %s: skipping '%s'", ha_node, ha_node_type); continue; } ha_node_uuid = get_uuid(ha_node); if(ha_node_uuid == NULL) { crm_warn("Node %s: no uuid found", ha_node); continue; } crm_notice("Node: %s (uuid: %s)", ha_node, ha_node_uuid); cib_new_node = create_xml_node(cib_node_list, XML_CIB_TAG_NODE); crm_xml_add(cib_new_node, XML_ATTR_ID, ha_node_uuid); crm_xml_add(cib_new_node, XML_ATTR_UNAME, ha_node); crm_xml_add(cib_new_node, XML_ATTR_TYPE, ha_node_type); } while(ha_node != NULL); fsa_cluster_conn->llc_ops->end_nodewalk(fsa_cluster_conn); /* Now update the CIB with the list of nodes */ fsa_cib_update( XML_CIB_TAG_NODES, cib_node_list, cib_scope_local|cib_quorum_override|cib_inhibit_bcast, call_id); add_cib_op_callback(call_id, FALSE, NULL, default_cib_update_callback); free_xml(cib_node_list); crm_debug_2("Complete"); } #endif static void create_cib_node_definition( gpointer key, gpointer value, gpointer user_data) { crm_node_t *node = value; - crm_data_t *cib_nodes = user_data; - crm_data_t *cib_new_node = NULL; + xmlNode *cib_nodes = user_data; + xmlNode *cib_new_node = NULL; crm_notice("Node: %s (uuid: %s)", node->uname, node->uuid); cib_new_node = create_xml_node(cib_nodes, XML_CIB_TAG_NODE); crm_xml_add(cib_new_node, XML_ATTR_ID, node->uuid); crm_xml_add(cib_new_node, XML_ATTR_UNAME, node->uname); crm_xml_add(cib_new_node, XML_ATTR_TYPE, NORMALNODE); } void populate_cib_nodes(gboolean with_client_status) { int call_id = 0; - crm_data_t *cib_node_list = NULL; + xmlNode *cib_node_list = NULL; #if SUPPORT_HEARTBEAT if(is_heartbeat_cluster()) { populate_cib_nodes_ha(with_client_status); return; } #endif if(is_openais_cluster() && with_client_status) { crm_info("Requesting the list of configured nodes"); #if SUPPORT_AIS send_ais_text(crm_class_members, __FUNCTION__, TRUE, NULL, crm_msg_ais); #endif } cib_node_list = create_xml_node(NULL, XML_CIB_TAG_NODES); g_hash_table_foreach( crm_peer_cache, create_cib_node_definition, cib_node_list); fsa_cib_update( XML_CIB_TAG_NODES, cib_node_list, cib_scope_local|cib_quorum_override|cib_inhibit_bcast, call_id); add_cib_op_callback(call_id, FALSE, NULL, default_cib_update_callback); free_xml(cib_node_list); crm_debug_2("Complete"); } diff --git a/crmd/crmd_callbacks.h b/crmd/crmd_callbacks.h index 4772b5cfd1..2d288640d0 100644 --- a/crmd/crmd_callbacks.h +++ b/crmd/crmd_callbacks.h @@ -1,63 +1,63 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #if SUPPORT_HEARTBEAT #include extern void ccm_event_detail(const oc_ev_membership_t *oc, oc_ed_t event); extern gboolean ccm_dispatch(int fd, gpointer user_data); extern void crmd_ccm_msg_callback( oc_ed_t event, void *cookie, size_t size, const void *data); extern gboolean crmd_ha_msg_dispatch( ll_cluster_t *cluster_conn, gpointer user_data); #endif /* * Apparently returning TRUE means "stay connected, keep doing stuff". * Returning FALSE means "we're all done, close the connection" */ extern void crmd_ipc_connection_destroy(gpointer user_data); extern void crmd_ha_msg_callback( - HA_Message * msg, void* private_data); + HA_Message *hamsg, void* private_data); extern gboolean crmd_ipc_msg_callback( IPC_Channel *client, gpointer user_data); extern gboolean crmd_ipc_msg_callback( IPC_Channel *client, gpointer user_data); extern gboolean lrm_dispatch(IPC_Channel*src, gpointer user_data); extern void lrm_op_callback (lrm_op_t* op); extern void crmd_ha_status_callback( const char *node, const char * status, void* private_data); extern void crmd_client_status_callback( const char * node, const char * client, const char * status, void * private); -extern void msg_ccm_join(const HA_Message *msg, void *foo); +extern void msg_ccm_join(const xmlNode *msg, void *foo); extern gboolean crmd_client_connect( IPC_Channel *newclient, gpointer user_data); extern void crmd_cib_connection_destroy(gpointer user_data); extern gboolean crm_fsa_trigger(gpointer user_data); diff --git a/crmd/crmd_fsa.h b/crmd/crmd_fsa.h index 89d3492b91..967f638918 100644 --- a/crmd/crmd_fsa.h +++ b/crmd/crmd_fsa.h @@ -1,138 +1,134 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 CRMD_FSA__H #define CRMD_FSA__H #include #if SUPPORT_HEARTBEAT # include # include extern ll_cluster_t *fsa_cluster_conn; #endif #include #include #include #include #include /* copy from struct client_child in heartbeat.h * * Plus a couple of other things */ struct crm_subsystem_s { pid_t pid; /* Process id of child process */ const char* name; /* executable name */ const char* path; /* Command location */ const char* command; /* Command with path */ const char* args; /* Command arguments */ crmd_client_t* client; /* Client connection object */ gboolean sent_kill; IPC_Channel *ipc; /* How can we communicate with it */ long long flag_connected; /* */ long long flag_required; /* */ }; typedef struct fsa_timer_s fsa_timer_t; struct fsa_timer_s { guint source_id; /* timer source id */ int period_ms; /* timer period */ enum crmd_fsa_input fsa_input; gboolean (*callback)(gpointer data); gboolean repeat; }; enum fsa_data_type { fsa_dt_none, fsa_dt_ha_msg, fsa_dt_xml, fsa_dt_lrm, }; typedef struct fsa_data_s fsa_data_t; struct fsa_data_s { int id; enum crmd_fsa_input fsa_input; enum crmd_fsa_cause fsa_cause; long long actions; const char *origin; void *data; enum fsa_data_type data_type; }; extern enum crmd_fsa_state s_crmd_fsa(enum crmd_fsa_cause cause); /* Global FSA stuff */ extern volatile gboolean do_fsa_stall; extern volatile enum crmd_fsa_state fsa_state; extern volatile long long fsa_input_register; extern volatile long long fsa_actions; extern ll_lrm_t *fsa_lrm_conn; extern cib_t *fsa_cib_conn; extern char *fsa_our_uname; extern char *fsa_our_uuid; extern char *fsa_pe_ref; /* the last invocation of the PE */ extern char *fsa_our_dc; extern char *fsa_our_dc_version; extern GListPtr fsa_message_queue; extern fsa_timer_t *election_trigger; /* */ extern fsa_timer_t *election_timeout; /* */ extern fsa_timer_t *shutdown_escalation_timer; /* */ extern fsa_timer_t *integration_timer; extern fsa_timer_t *finalization_timer; extern fsa_timer_t *wait_timer; extern fsa_timer_t *recheck_timer; extern GTRIGSource *fsa_source; extern struct crm_subsystem_s *cib_subsystem; extern struct crm_subsystem_s *te_subsystem; extern struct crm_subsystem_s *pe_subsystem; extern GHashTable *welcomed_nodes; extern GHashTable *integrated_nodes; extern GHashTable *finalized_nodes; extern GHashTable *confirmed_nodes; extern GHashTable *crmd_peer_state; /* these two should be moved elsewhere... */ extern void do_update_cib_nodes(gboolean overwrite, const char *caller); extern gboolean do_dc_heartbeat(gpointer data); -gboolean add_cib_op_callback( - int call_id, gboolean only_success, void *user_data, - void (*callback)(const HA_Message*, int, int, crm_data_t*,void*)); - #define AM_I_DC is_set(fsa_input_register, R_THE_DC) #define AM_I_OPERATIONAL (is_set(fsa_input_register, R_STARTING)==FALSE) extern unsigned long long saved_ccm_membership_id; #include #include #endif diff --git a/crmd/crmd_messages.h b/crmd/crmd_messages.h index e2f6ae1058..2a512a71e7 100644 --- a/crmd/crmd_messages.h +++ b/crmd/crmd_messages.h @@ -1,116 +1,114 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 XML_CRM_MESSAGES__H #define XML_CRM_MESSAGES__H #include #include #include #include extern void *fsa_typed_data_adv( fsa_data_t *fsa_data, enum fsa_data_type a_type, const char *caller); #define fsa_typed_data(x) fsa_typed_data_adv(msg_data, x, __FUNCTION__) extern void register_fsa_error_adv( enum crmd_fsa_cause cause, enum crmd_fsa_input input, fsa_data_t *cur_data, void *new_data, const char *raised_from); #define register_fsa_error(cause, input, new_data) register_fsa_error_adv(cause, input, msg_data, new_data, __FUNCTION__) extern int register_fsa_input_adv( enum crmd_fsa_cause cause, enum crmd_fsa_input input, void *data, long long with_actions, gboolean prepend, const char *raised_from); extern void fsa_dump_queue(int log_level); extern void route_message(enum crmd_fsa_cause cause, ha_msg_input_t *input); #define crmd_fsa_stall(cur_input) if(cur_input != NULL) { \ register_fsa_input_adv( \ ((fsa_data_t*)cur_input)->fsa_cause, I_WAIT_FOR_EVENT, \ ((fsa_data_t*)cur_input)->data, action, TRUE, __FUNCTION__); \ } else { \ register_fsa_input_adv( \ C_FSA_INTERNAL, I_WAIT_FOR_EVENT, \ NULL, action, TRUE, __FUNCTION__); \ } \ #define register_fsa_input(cause, input, data) register_fsa_input_adv(cause, input, data, A_NOTHING, FALSE, __FUNCTION__) #define register_fsa_action(action) { \ fsa_actions |= action; \ if(fsa_source) { \ G_main_set_trigger(fsa_source); \ } \ crm_debug("%s added action %s to the FSA", \ __FUNCTION__, fsa_action2string(action)); \ } #define register_fsa_input_before(cause, input, data) register_fsa_input_adv(cause, input, data, A_NOTHING, TRUE, __FUNCTION__) #define register_fsa_input_later(cause, input, data) register_fsa_input_adv(cause, input, data, A_NOTHING, FALSE, __FUNCTION__) void delete_fsa_input(fsa_data_t *fsa_data); GListPtr put_message(fsa_data_t *new_message); fsa_data_t *get_message(void); gboolean is_message(void); gboolean have_wait_message(void); extern gboolean relay_message( - HA_Message *relay_message, gboolean originated_locally); - -extern void crmd_ha_msg_callback(HA_Message * msg, void* private_data); + xmlNode *relay_message, gboolean originated_locally); extern gboolean crmd_ipc_msg_callback(IPC_Channel *client, gpointer user_data); extern void process_message( - HA_Message *msg, gboolean originated_locally,const char *src_node_name); + xmlNode *msg, gboolean originated_locally,const char *src_node_name); -extern gboolean crm_dc_process_message(crm_data_t *whole_message, - crm_data_t *action, +extern gboolean crm_dc_process_message(xmlNode *whole_message, + xmlNode *action, const char *host_from, const char *sys_from, const char *sys_to, const char *op, gboolean dc_mode); -extern gboolean send_msg_via_ha(HA_Message *msg); -extern gboolean send_msg_via_ipc(HA_Message *msg, const char *sys); +extern gboolean send_msg_via_ha(xmlNode *msg); +extern gboolean send_msg_via_ipc(xmlNode *msg, const char *sys); extern gboolean add_pending_outgoing_reply(const char *originating_node_name, const char *crm_msg_reference, const char *sys_to, const char *sys_from); extern gboolean crmd_authorize_message( ha_msg_input_t *client_msg, crmd_client_t *curr_client); -extern gboolean send_request(HA_Message *msg, char **msg_reference); +extern gboolean send_request(xmlNode *msg, char **msg_reference); extern enum crmd_fsa_input handle_message(ha_msg_input_t *stored_msg); extern void lrm_op_callback(lrm_op_t* op); extern void msg_queue_helper(void); #endif diff --git a/crmd/crmd_utils.h b/crmd/crmd_utils.h index bc5c583c78..602d0e1a95 100644 --- a/crmd/crmd_utils.h +++ b/crmd/crmd_utils.h @@ -1,79 +1,79 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 CRMD_UTILS__H #define CRMD_UTILS__H #include #include #define CLIENT_EXIT_WAIT 30 extern void process_client_disconnect(crmd_client_t *curr_client); #define fsa_cib_update(section, data, options, call_id) \ if(fsa_cib_conn != NULL) { \ call_id = fsa_cib_conn->cmds->update( \ fsa_cib_conn, section, data, NULL, options); \ \ } else { \ crm_err("No CIB connection available"); \ } #define fsa_cib_anon_update(section, data, options) \ if(fsa_cib_conn != NULL) { \ fsa_cib_conn->cmds->update( \ fsa_cib_conn, section, data, NULL, options); \ \ } else { \ crm_err("No CIB connection available"); \ } extern gboolean fsa_has_quorum; extern int last_peer_update; extern gboolean crm_timer_stop (fsa_timer_t *timer); extern gboolean crm_timer_start(fsa_timer_t *timer); extern gboolean crm_timer_popped(gpointer data); -extern crm_data_t *create_node_state( +extern xmlNode *create_node_state( const char *uname, const char *ha_state, const char *ccm_state, const char *crmd_state, const char *join_state, const char *exp_state, gboolean clear_shutdown, const char *src); extern void create_node_entry( const char *uuid, const char *uname, const char *type); extern gboolean stop_subsystem ( struct crm_subsystem_s *centry, gboolean force_quit); extern gboolean start_subsystem(struct crm_subsystem_s *centry); extern lrm_op_t *copy_lrm_op(const lrm_op_t *op); extern lrm_rsc_t *copy_lrm_rsc(const lrm_rsc_t *rsc); extern void fsa_dump_actions(long long action, const char *text); extern void fsa_dump_inputs( int log_level, const char *text, long long input_register); extern gboolean need_transition(enum crmd_fsa_state state); -extern void update_dc(HA_Message *msg, gboolean assert_same); +extern void update_dc(xmlNode *msg, gboolean assert_same); extern void erase_node_from_join(const char *node); extern void populate_cib_nodes(gboolean with_client_status); extern void crm_update_quorum(gboolean bool); #endif diff --git a/crmd/election.c b/crmd/election.c index c9dd7570b5..ebb79d206d 100644 --- a/crmd/election.c +++ b/crmd/election.c @@ -1,447 +1,447 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include GHashTable *voted = NULL; uint highest_born_on = -1; static int current_election_id = 1; /* A_ELECTION_VOTE */ void do_election_vote(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 not_voting = FALSE; - HA_Message *vote = NULL; + xmlNode *vote = NULL; /* don't vote if we're in one of these states or wanting to shut down */ switch(cur_state) { case S_RECOVERY: case S_STOPPING: case S_TERMINATE: crm_warn("Not voting in election, we're in state %s", fsa_state2string(cur_state)); not_voting = TRUE; break; default: break; } if(not_voting == FALSE) { if(is_set(fsa_input_register, R_STARTING)) { not_voting = TRUE; } } if(not_voting) { if(AM_I_DC) { register_fsa_input(C_FSA_INTERNAL, I_RELEASE_DC, NULL); } else { register_fsa_input(C_FSA_INTERNAL, I_PENDING, NULL); } return; } vote = create_request( CRM_OP_VOTE, NULL, NULL, CRM_SYSTEM_CRMD, CRM_SYSTEM_CRMD, NULL); current_election_id++; - ha_msg_add(vote, F_CRM_ELECTION_OWNER, fsa_our_uuid); - ha_msg_add_int(vote, F_CRM_ELECTION_ID, current_election_id); + crm_xml_add(vote, F_CRM_ELECTION_OWNER, fsa_our_uuid); + crm_xml_add_int(vote, F_CRM_ELECTION_ID, current_election_id); send_request(vote, NULL); crm_debug("Destroying voted hash"); g_hash_table_destroy(voted); voted = NULL; if(cur_state == S_ELECTION || cur_state == S_RELEASE_DC) { crm_timer_start(election_timeout); } else if(cur_state != S_INTEGRATION) { crm_err("Broken? Voting in state %s", fsa_state2string(cur_state)); } return; } char *dc_hb_msg = NULL; int beat_num = 0; gboolean do_dc_heartbeat(gpointer data) { #if 0 fsa_timer_t *timer = (fsa_timer_t *)data; crm_debug_3("Sending DC Heartbeat %d", beat_num); - HA_Message *msg = ha_msg_new(5); - ha_msg_add(msg, F_TYPE, T_CRM); - ha_msg_add(msg, F_SUBTYPE, XML_ATTR_REQUEST); - ha_msg_add(msg, F_CRM_SYS_TO, CRM_SYSTEM_CRMD); - ha_msg_add(msg, F_CRM_SYS_FROM, CRM_SYSTEM_DC); - ha_msg_add(msg, F_CRM_TASK, CRM_OP_HBEAT); - ha_msg_add_int(msg, "dc_beat_seq", beat_num); + xmlNode *msg = ha_msg_new(5); + crm_xml_add(msg, F_TYPE, T_CRM); + crm_xml_add(msg, F_SUBTYPE, XML_ATTR_REQUEST); + crm_xml_add(msg, F_CRM_SYS_TO, CRM_SYSTEM_CRMD); + crm_xml_add(msg, F_CRM_SYS_FROM, CRM_SYSTEM_DC); + crm_xml_add(msg, F_CRM_TASK, CRM_OP_HBEAT); + crm_xml_add_int(msg, "dc_beat_seq", beat_num); beat_num++; if(send_msg_via_ha(msg) == FALSE) { /* this is bad */ crm_timer_stop(timer); /* make it not go off again */ register_fsa_input(C_HEARTBEAT_FAILED, I_SHUTDOWN, NULL); return FALSE; } #endif return TRUE; } struct election_data_s { const char *winning_uname; unsigned int winning_bornon; }; static void log_member_uname(gpointer key, gpointer value, gpointer user_data) { if(crm_is_member_active(value)) { crm_err("%s: %s", (char*)user_data, (char*)key); } } static void log_node(gpointer key, gpointer value, gpointer user_data) { crm_err("%s: %s", (char*)user_data, (char*)key); } void do_election_check(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 voted_size = g_hash_table_size(voted); int num_members = crm_active_members(); /* in the case of #voted > #members, it is better to * wait for the timeout and give the cluster time to * stabilize */ if(fsa_state != S_ELECTION) { crm_debug("Ignore election check: we not in an election"); } else if(voted_size >= num_members) { /* we won and everyone has voted */ crm_timer_stop(election_timeout); register_fsa_input(C_FSA_INTERNAL, I_ELECTION_DC, NULL); if(voted_size > num_members) { char *data = NULL; data = crm_strdup("member"); g_hash_table_foreach(crm_peer_cache, log_member_uname, data); crm_free(data); data = crm_strdup("voted"); g_hash_table_foreach(voted, log_node, data); crm_free(data); } crm_debug("Destroying voted hash"); g_hash_table_destroy(voted); voted = NULL; } else { crm_info("Still waiting on %d non-votes (%d total)", num_members - voted_size, num_members); } return; } /* A_ELECTION_COUNT */ void do_election_count_vote(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 election_id = -1; gboolean we_loose = FALSE; static time_t last_election_loss = 0; enum crmd_fsa_input election_result = I_NULL; crm_node_t *our_node = NULL, *your_node = NULL; ha_msg_input_t *vote = fsa_typed_data(fsa_dt_ha_msg); - const char *op = cl_get_string(vote->msg, F_CRM_TASK); - const char *vote_from = cl_get_string(vote->msg, F_CRM_HOST_FROM); - const char *your_version = cl_get_string(vote->msg, F_CRM_VERSION); - const char *election_owner= cl_get_string(vote->msg, F_CRM_ELECTION_OWNER); + const char *op = crm_element_value(vote->msg, F_CRM_TASK); + const char *vote_from = crm_element_value(vote->msg, F_CRM_HOST_FROM); + const char *your_version = crm_element_value(vote->msg, F_CRM_VERSION); + const char *election_owner= crm_element_value(vote->msg, F_CRM_ELECTION_OWNER); /* if the membership copy is NULL we REALLY shouldnt be voting * the question is how we managed to get here. */ CRM_CHECK(crm_peer_cache != NULL, return); CRM_CHECK(vote_from != NULL, vote_from = fsa_our_uname); our_node = g_hash_table_lookup(crm_peer_cache, fsa_our_uname); your_node = g_hash_table_lookup(crm_peer_cache, vote_from); if(your_node == NULL) { crm_debug("Election ignore: The other side doesn't exist in CCM: %s", vote_from); return; } if(voted == NULL) { crm_debug("Created voted hash"); voted = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); } - ha_msg_value_int(vote->msg, F_CRM_ELECTION_ID, &election_id); + crm_element_value_int(vote->msg, F_CRM_ELECTION_ID, &election_id); crm_debug("Election %d, owner: %s", election_id, election_owner); /* update the list of nodes that have voted */ if(crm_str_eq(fsa_our_uuid, election_owner, TRUE) || crm_str_eq(fsa_our_uname, election_owner, TRUE)) { if(election_id == current_election_id) { char *uname_copy = NULL; char *op_copy = crm_strdup(op); uname_copy = crm_strdup(your_node->uname); g_hash_table_replace(voted, uname_copy, op_copy); crm_info("Updated voted hash for %s to %s", your_node->uname, op); } else { crm_debug("Ignore old '%s' from %s: %d vs. %d", op, your_node->uname, election_id, current_election_id); return; } } else { CRM_CHECK(safe_str_neq(op, CRM_OP_NOVOTE), return); } if(vote_from == NULL || crm_str_eq(vote_from, fsa_our_uname, TRUE)) { /* don't count our own vote */ crm_info("Election ignore: our %s (%s)", op,crm_str(vote_from)); return; } else if(crm_str_eq(op, CRM_OP_NOVOTE, TRUE)) { crm_info("Election ignore: no-vote from %s", vote_from); return; } crm_info("Election check: %s from %s", op, vote_from); if(our_node == NULL || safe_str_neq(our_node->state, CRM_NODE_MEMBER)) { crm_info("Election fail: we don't exist in CCM"); we_loose = TRUE; } else if(compare_version(your_version, CRM_FEATURE_SET) < 0) { crm_info("Election fail: version"); we_loose = TRUE; } else if(compare_version(your_version, CRM_FEATURE_SET) > 0) { crm_info("Election pass: version"); } else if(is_heartbeat_cluster() && your_node->born < our_node->born) { crm_debug("Election fail: born_on"); we_loose = TRUE; } else if(is_heartbeat_cluster() && your_node->born > our_node->born) { crm_debug("Election pass: born_on"); } else if(fsa_our_uname == NULL || strcasecmp(fsa_our_uname, vote_from) > 0) { crm_debug("Election fail: uname"); we_loose = TRUE; } else { CRM_CHECK(strcasecmp(fsa_our_uname, vote_from) != 0, ;); crm_debug("Them: %s (born=%llu) Us: %s (born=%llu)", vote_from, (unsigned long long)your_node->born, fsa_our_uname, (unsigned long long)our_node->born); /* cant happen... * } else if(strcasecmp(fsa_our_uname, vote_from) == 0) { * * default... * } else { // strcasecmp(fsa_our_uname, vote_from) < 0 * we win */ } if(we_loose) { gboolean vote_sent = FALSE; - HA_Message *novote = create_request( + xmlNode *novote = create_request( CRM_OP_NOVOTE, NULL, vote_from, CRM_SYSTEM_CRMD, CRM_SYSTEM_CRMD, NULL); update_dc(NULL, FALSE); crm_timer_stop(election_timeout); crm_debug("Election lost to %s (%d)", vote_from, election_id); if(fsa_input_register & R_THE_DC) { crm_debug_3("Give up the DC to %s", vote_from); election_result = I_RELEASE_DC; } else { crm_debug_3("We werent the DC anyway"); election_result = I_PENDING; } - ha_msg_add(novote, F_CRM_ELECTION_OWNER, election_owner); - ha_msg_add_int(novote, F_CRM_ELECTION_ID, election_id); + crm_xml_add(novote, F_CRM_ELECTION_OWNER, election_owner); + crm_xml_add_int(novote, F_CRM_ELECTION_ID, election_id); vote_sent = send_request(novote, NULL); CRM_DEV_ASSERT(vote_sent); fsa_cib_conn->cmds->set_slave(fsa_cib_conn, cib_scope_local); last_election_loss = time(NULL); } else { int dampen = 2; time_t tm_now = time(NULL); if(tm_now - last_election_loss < (time_t)dampen) { crm_debug("Election ignore: We already lost an election less than %ds ago", dampen); return; } last_election_loss = 0; election_result = I_ELECTION; crm_info("Election won over %s", vote_from); g_hash_table_destroy(voted); voted = NULL; } register_fsa_input(C_FSA_INTERNAL, election_result, NULL); } /* A_ELECT_TIMER_START, A_ELECTION_TIMEOUT */ /* we won */ void do_election_timer_ctrl(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) { } static void -feature_update_callback(const HA_Message *msg, int call_id, int rc, - crm_data_t *output, void *user_data) +feature_update_callback(xmlNode *msg, int call_id, int rc, + xmlNode *output, void *user_data) { if(rc != cib_ok) { fsa_data_t *msg_data = NULL; register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); } } /* A_DC_TAKEOVER */ void do_dc_takeover(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 rc = cib_ok; - crm_data_t *cib = NULL; + xmlNode *cib = NULL; crm_info("Taking over DC status for this partition"); set_bit_inplace(fsa_input_register, R_THE_DC); if(voted != NULL) { crm_debug_2("Destroying voted hash"); g_hash_table_destroy(voted); voted = NULL; } set_bit_inplace(fsa_input_register, R_JOIN_OK); set_bit_inplace(fsa_input_register, R_INVOKE_PE); fsa_cib_conn->cmds->set_slave_all(fsa_cib_conn, cib_none); fsa_cib_conn->cmds->set_master(fsa_cib_conn, cib_none); cib = createEmptyCib(); crm_xml_add(cib, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET); crm_xml_add(cib, XML_ATTR_CIB_REVISION, CIB_FEATURE_SET); fsa_cib_update(XML_TAG_CIB, cib, cib_quorum_override, rc); add_cib_op_callback(rc, FALSE, NULL, feature_update_callback); update_attr(fsa_cib_conn, cib_none, XML_CIB_TAG_CRMCONFIG, NULL, NULL, NULL, "dc-version", VERSION"-"HA_HG_VERSION, FALSE); free_xml(cib); } /* A_DC_RELEASE */ void do_dc_release(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) { if(action & A_DC_RELEASE) { crm_debug("Releasing the role of DC"); clear_bit_inplace(fsa_input_register, R_THE_DC); } else if (action & A_DC_RELEASED) { crm_info("DC role released"); #if 0 if( are there errors ) { /* we cant stay up if not healthy */ /* or perhaps I_ERROR and go to S_RECOVER? */ result = I_SHUTDOWN; } #endif register_fsa_input(C_FSA_INTERNAL, I_RELEASE_SUCCESS, NULL); } else { crm_err("Unknown action %s", fsa_action2string(action)); } crm_debug_2("Am I still the DC? %s", AM_I_DC?XML_BOOLEAN_YES:XML_BOOLEAN_NO); } diff --git a/crmd/fsa.c b/crmd/fsa.c index 5501af0b7b..fcece34cb8 100644 --- a/crmd/fsa.c +++ b/crmd/fsa.c @@ -1,774 +1,773 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include longclock_t action_start = 0; longclock_t action_stop = 0; longclock_t action_diff = 0; unsigned int action_diff_ms = 0; char *fsa_our_dc = NULL; cib_t *fsa_cib_conn = NULL; char *fsa_our_dc_version = NULL; ll_lrm_t *fsa_lrm_conn; char *fsa_our_uuid = NULL; char *fsa_our_uname = NULL; #if SUPPORT_HEARTBEAT ll_cluster_t *fsa_cluster_conn; #endif fsa_timer_t *wait_timer = NULL; fsa_timer_t *recheck_timer = NULL; fsa_timer_t *election_trigger = NULL; fsa_timer_t *election_timeout = NULL; fsa_timer_t *integration_timer = NULL; fsa_timer_t *finalization_timer = NULL; fsa_timer_t *shutdown_escalation_timer = NULL; volatile gboolean do_fsa_stall = FALSE; volatile long long fsa_input_register = 0; volatile long long fsa_actions = A_NOTHING; volatile enum crmd_fsa_state fsa_state = S_STARTING; extern uint highest_born_on; extern uint num_join_invites; extern GHashTable *welcomed_nodes; extern GHashTable *finalized_nodes; extern GHashTable *confirmed_nodes; extern GHashTable *integrated_nodes; extern void initialize_join(gboolean before); #define DOT_PREFIX "actions:trace: " #define do_dot_log(fmt, args...) do_crm_log(LOG_DEBUG_2, fmt, ##args) long long do_state_transition(long long actions, enum crmd_fsa_state cur_state, enum crmd_fsa_state next_state, fsa_data_t *msg_data); long long clear_flags(long long actions, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input); void dump_rsc_info(void); -void dump_rsc_info_callback(const HA_Message *msg, int call_id, int rc, - crm_data_t *output, void *user_data); +void dump_rsc_info_callback(const xmlNode *msg, int call_id, int rc, + xmlNode *output, void *user_data); void ghash_print_node(gpointer key, gpointer value, gpointer user_data); void s_crmd_fsa_actions(fsa_data_t *fsa_data); void log_fsa_input(fsa_data_t *stored_msg); void init_dotfile(void); void init_dotfile(void) { do_dot_log(DOT_PREFIX"digraph \"g\" {"); do_dot_log(DOT_PREFIX" size = \"30,30\""); do_dot_log(DOT_PREFIX" graph ["); do_dot_log(DOT_PREFIX" fontsize = \"12\""); do_dot_log(DOT_PREFIX" fontname = \"Times-Roman\""); do_dot_log(DOT_PREFIX" fontcolor = \"black\""); do_dot_log(DOT_PREFIX" bb = \"0,0,398.922306,478.927856\""); do_dot_log(DOT_PREFIX" color = \"black\""); do_dot_log(DOT_PREFIX" ]"); do_dot_log(DOT_PREFIX" node ["); do_dot_log(DOT_PREFIX" fontsize = \"12\""); do_dot_log(DOT_PREFIX" fontname = \"Times-Roman\""); do_dot_log(DOT_PREFIX" fontcolor = \"black\""); do_dot_log(DOT_PREFIX" shape = \"ellipse\""); do_dot_log(DOT_PREFIX" color = \"black\""); do_dot_log(DOT_PREFIX" ]"); do_dot_log(DOT_PREFIX" edge ["); do_dot_log(DOT_PREFIX" fontsize = \"12\""); do_dot_log(DOT_PREFIX" fontname = \"Times-Roman\""); do_dot_log(DOT_PREFIX" fontcolor = \"black\""); do_dot_log(DOT_PREFIX" color = \"black\""); do_dot_log(DOT_PREFIX" ]"); do_dot_log(DOT_PREFIX"// special nodes"); do_dot_log(DOT_PREFIX" \"S_PENDING\" "); do_dot_log(DOT_PREFIX" ["); do_dot_log(DOT_PREFIX" color = \"blue\""); do_dot_log(DOT_PREFIX" fontcolor = \"blue\""); do_dot_log(DOT_PREFIX" ]"); do_dot_log(DOT_PREFIX" \"S_TERMINATE\" "); do_dot_log(DOT_PREFIX" ["); do_dot_log(DOT_PREFIX" color = \"red\""); do_dot_log(DOT_PREFIX" fontcolor = \"red\""); do_dot_log(DOT_PREFIX" ]"); do_dot_log(DOT_PREFIX"// DC only nodes"); do_dot_log(DOT_PREFIX" \"S_INTEGRATION\" [ fontcolor = \"green\" ]"); do_dot_log(DOT_PREFIX" \"S_POLICY_ENGINE\" [ fontcolor = \"green\" ]"); do_dot_log(DOT_PREFIX" \"S_TRANSITION_ENGINE\" [ fontcolor = \"green\" ]"); do_dot_log(DOT_PREFIX" \"S_RELEASE_DC\" [ fontcolor = \"green\" ]"); do_dot_log(DOT_PREFIX" \"S_IDLE\" [ fontcolor = \"green\" ]"); } static void do_fsa_action(fsa_data_t *fsa_data, long long an_action, void (*function)(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data)) { int action_log_level = LOG_DEBUG; gboolean do_time_check = TRUE; if(is_set(fsa_actions, an_action) == FALSE) { crm_err("Action %s (%.16llx) was not requestsed", fsa_action2string(an_action), an_action); return; } if(an_action & A_MSG_ROUTE) { action_log_level = LOG_DEBUG_2; } else if(an_action & A_CIB_START) { do_time_check = FALSE; } fsa_actions &= ~an_action; crm_debug_3("Invoking action %s (%.16llx)", fsa_action2string(an_action), an_action); if(do_time_check) { action_start = time_longclock(); } do_crm_log(action_log_level, DOT_PREFIX"\t// %s", fsa_action2string(an_action)); function(an_action, fsa_data->fsa_cause, fsa_state, fsa_data->fsa_input, fsa_data); crm_debug_3("Action complete: %s (%.16llx)", fsa_action2string(an_action), an_action); if(do_time_check) { action_stop = time_longclock(); action_diff = sub_longclock(action_stop, action_start); action_diff_ms = longclockto_ms(action_diff); if(action_diff_ms > action_diff_max_ms) { crm_err("Action %s took %dms to complete", fsa_action2string(an_action), action_diff_ms); } else if(action_diff_ms > action_diff_warn_ms) { crm_warn("Action %s took %dms to complete", fsa_action2string(an_action), action_diff_ms); } } } enum crmd_fsa_state s_crmd_fsa(enum crmd_fsa_cause cause) { fsa_data_t *fsa_data = NULL; long long register_copy = fsa_input_register; long long new_actions = A_NOTHING; enum crmd_fsa_state last_state = fsa_state; crm_debug_2("FSA invoked with Cause: %s\tState: %s", fsa_cause2string(cause), fsa_state2string(fsa_state)); do_fsa_stall = FALSE; if(is_message() == FALSE && fsa_actions != A_NOTHING) { /* fake the first message so we can get into the loop */ crm_malloc0(fsa_data, sizeof(fsa_data_t)); fsa_data->fsa_input = I_NULL; fsa_data->fsa_cause = C_FSA_INTERNAL; fsa_data->origin = __FUNCTION__; fsa_data->data_type = fsa_dt_none; fsa_message_queue = g_list_append(fsa_message_queue, fsa_data); fsa_data = NULL; } while(is_message() && do_fsa_stall == FALSE) { crm_debug_2("Checking messages (%d remaining)", g_list_length(fsa_message_queue)); fsa_data = get_message(); CRM_DEV_ASSERT(fsa_data != NULL); if(crm_assert_failed) { continue; } log_fsa_input(fsa_data); /* add any actions back to the queue */ fsa_actions |= fsa_data->actions; /* get the next batch of actions */ new_actions = crmd_fsa_actions[fsa_data->fsa_input][fsa_state]; fsa_actions |= new_actions; if(fsa_data->fsa_input != I_NULL && fsa_data->fsa_input != I_ROUTER) { crm_debug("Processing %s: [ state=%s cause=%s origin=%s ]", fsa_input2string(fsa_data->fsa_input), fsa_state2string(fsa_state), fsa_cause2string(fsa_data->fsa_cause), fsa_data->origin); } /* if(fsa_actions & A_SHUTDOWN) { crm_log_level = LOG_DEBUG_2; } */ #ifdef FSA_TRACE if(new_actions != A_NOTHING) { crm_debug_2("Adding FSA actions %.16llx for %s/%s", new_actions, fsa_input2string(fsa_data->fsa_input), fsa_state2string(fsa_state)); fsa_dump_actions(new_actions, "\tFSA scheduled"); } else if(fsa_data->fsa_input != I_NULL && new_actions == A_NOTHING) { crm_debug("No action specified for input,state (%s,%s)", fsa_input2string(fsa_data->fsa_input), fsa_state2string(fsa_state)); } if(fsa_data->actions != A_NOTHING) { crm_debug_2("Adding input actions %.16llx for %s/%s", new_actions, fsa_input2string(fsa_data->fsa_input), fsa_state2string(fsa_state)); fsa_dump_actions(fsa_data->actions,"\tInput scheduled"); } #endif /* logging : *before* the state is changed */ if(is_set(fsa_actions, A_ERROR)) { do_fsa_action(fsa_data, A_ERROR, do_log); } if(is_set(fsa_actions, A_WARN)) { do_fsa_action(fsa_data, A_WARN, do_log); } if(is_set(fsa_actions, A_LOG)) { do_fsa_action(fsa_data, A_LOG, do_log); } /* update state variables */ last_state = fsa_state; fsa_state = crmd_fsa_state[fsa_data->fsa_input][fsa_state]; /* * Hook to allow actions to removed due to certain inputs */ fsa_actions = clear_flags( fsa_actions, cause, fsa_state, fsa_data->fsa_input); /* * Hook for change of state. * Allows actions to be added or removed when entering a state */ if(last_state != fsa_state){ fsa_actions = do_state_transition( fsa_actions, last_state, fsa_state, fsa_data); } else { do_dot_log(DOT_PREFIX"\t// FSA input: State=%s \tCause=%s" " \tInput=%s \tOrigin=%s() \tid=%d", fsa_state2string(fsa_state), fsa_cause2string(fsa_data->fsa_cause), fsa_input2string(fsa_data->fsa_input), fsa_data->origin, fsa_data->id); } /* start doing things... */ s_crmd_fsa_actions(fsa_data); delete_fsa_input(fsa_data); fsa_data = NULL; } if(g_list_length(fsa_message_queue) > 0 || fsa_actions != A_NOTHING || do_fsa_stall) { crm_debug("Exiting the FSA: queue=%d, fsa_actions=0x%llx, stalled=%s", g_list_length(fsa_message_queue), fsa_actions, do_fsa_stall?"true":"false"); } else { crm_debug_2("Exiting the FSA"); } /* cleanup inputs? */ if(register_copy != fsa_input_register) { long long same = register_copy & fsa_input_register; fsa_dump_inputs(LOG_DEBUG, "Added input:", fsa_input_register ^ same); fsa_dump_inputs(LOG_DEBUG, "Removed input:", register_copy ^ same); } fsa_dump_queue(LOG_DEBUG); return fsa_state; } void s_crmd_fsa_actions(fsa_data_t *fsa_data) { /* * Process actions in order of priority but do only one * action at a time to avoid complicating the ordering. */ while(fsa_actions != A_NOTHING && do_fsa_stall == FALSE) { msg_queue_helper(); CRM_DEV_ASSERT(fsa_data != NULL); if(crm_assert_failed) { return; } /* regular action processing in order of action priority * * Make sure all actions that connect to required systems * are performed first */ if(is_set(fsa_actions, A_ERROR)) { do_fsa_action(fsa_data, A_ERROR, do_log); } else if(is_set(fsa_actions, A_WARN)) { do_fsa_action(fsa_data, A_WARN, do_log); } else if(is_set(fsa_actions, A_LOG)) { do_fsa_action(fsa_data, A_LOG, do_log); /* get out of here NOW! before anything worse happens */ } else if(is_set(fsa_actions, A_EXIT_1)) { do_fsa_action(fsa_data, A_EXIT_1, do_exit); /* essential start tasks */ } else if(is_set(fsa_actions, A_STARTUP)) { do_fsa_action(fsa_data, A_STARTUP, do_startup); } else if(is_set(fsa_actions, A_CIB_START)) { do_fsa_action(fsa_data, A_CIB_START, do_cib_control); } else if(is_set(fsa_actions, A_HA_CONNECT)) { do_fsa_action(fsa_data, A_HA_CONNECT, do_ha_control); } else if(is_set(fsa_actions, A_READCONFIG)) { do_fsa_action(fsa_data, A_READCONFIG, do_read_config); /* sub-system start/connect */ } else if(is_set(fsa_actions, A_LRM_CONNECT)) { do_fsa_action(fsa_data, A_LRM_CONNECT, do_lrm_control); } else if(is_set(fsa_actions, A_CCM_CONNECT)) { do_fsa_action(fsa_data, A_CCM_CONNECT, do_ccm_control); } else if(is_set(fsa_actions, A_TE_START)) { do_fsa_action(fsa_data, A_TE_START, do_te_control); } else if(is_set(fsa_actions, A_PE_START)) { do_fsa_action(fsa_data, A_PE_START, do_pe_control); /* sub-system restart */ } else if(is_set(fsa_actions, O_CIB_RESTART)) { do_fsa_action(fsa_data, O_CIB_RESTART, do_cib_control); } else if(is_set(fsa_actions, O_PE_RESTART)) { do_fsa_action(fsa_data, O_PE_RESTART, do_pe_control); } else if(is_set(fsa_actions, O_TE_RESTART)) { do_fsa_action(fsa_data, O_TE_RESTART, do_te_control); /* Timers */ /* else if(is_set(fsa_actions, O_DC_TIMER_RESTART)) { do_fsa_action(fsa_data, O_DC_TIMER_RESTART, do_timer_control) */; } else if(is_set(fsa_actions, A_DC_TIMER_STOP)) { do_fsa_action(fsa_data, A_DC_TIMER_STOP, do_timer_control); } else if(is_set(fsa_actions, A_INTEGRATE_TIMER_STOP)) { do_fsa_action(fsa_data, A_INTEGRATE_TIMER_STOP, do_timer_control); } else if(is_set(fsa_actions, A_INTEGRATE_TIMER_START)) { do_fsa_action(fsa_data, A_INTEGRATE_TIMER_START,do_timer_control); } else if(is_set(fsa_actions, A_FINALIZE_TIMER_STOP)) { do_fsa_action(fsa_data, A_FINALIZE_TIMER_STOP, do_timer_control); } else if(is_set(fsa_actions, A_FINALIZE_TIMER_START)) { do_fsa_action(fsa_data, A_FINALIZE_TIMER_START, do_timer_control); /* * Highest priority actions */ } else if(is_set(fsa_actions, A_CIB_BUMPGEN)) { do_fsa_action(fsa_data, A_CIB_BUMPGEN, do_cib_invoke); } else if(is_set(fsa_actions, A_MSG_ROUTE)) { do_fsa_action(fsa_data, A_MSG_ROUTE, do_msg_route); } else if(is_set(fsa_actions, A_RECOVER)) { do_fsa_action(fsa_data, A_RECOVER, do_recover); } else if(is_set(fsa_actions, A_CL_JOIN_RESULT)) { do_fsa_action(fsa_data, A_CL_JOIN_RESULT, do_cl_join_finalize_respond); } else if(is_set(fsa_actions, A_CL_JOIN_REQUEST)) { do_fsa_action(fsa_data, A_CL_JOIN_REQUEST, do_cl_join_offer_respond); } else if(is_set(fsa_actions, A_SHUTDOWN_REQ)) { do_fsa_action(fsa_data, A_SHUTDOWN_REQ, do_shutdown_req); } else if(is_set(fsa_actions, A_ELECTION_VOTE)) { do_fsa_action(fsa_data, A_ELECTION_VOTE, do_election_vote); } else if(is_set(fsa_actions, A_ELECTION_COUNT)) { do_fsa_action(fsa_data, A_ELECTION_COUNT, do_election_count_vote); } else if(is_set(fsa_actions, A_LRM_EVENT)) { do_fsa_action(fsa_data, A_LRM_EVENT, do_lrm_event); /* * High priority actions */ } else if(is_set(fsa_actions, A_STARTED)) { do_fsa_action(fsa_data, A_STARTED, do_started); } else if(is_set(fsa_actions, A_CL_JOIN_QUERY)) { do_fsa_action(fsa_data, A_CL_JOIN_QUERY, do_cl_join_query); } else if(is_set(fsa_actions, A_DC_TIMER_START)) { do_fsa_action(fsa_data, A_DC_TIMER_START, do_timer_control); /* * Medium priority actions */ } else if(is_set(fsa_actions, A_DC_TAKEOVER)) { do_fsa_action(fsa_data, A_DC_TAKEOVER, do_dc_takeover); } else if(is_set(fsa_actions, A_DC_RELEASE)) { do_fsa_action(fsa_data, A_DC_RELEASE, do_dc_release); } else if(is_set(fsa_actions, A_ELECTION_CHECK)) { do_fsa_action(fsa_data, A_ELECTION_CHECK, do_election_check); } else if(is_set(fsa_actions, A_ELECTION_START)) { do_fsa_action(fsa_data, A_ELECTION_START, do_election_vote); } else if(is_set(fsa_actions, A_TE_HALT)) { do_fsa_action(fsa_data, A_TE_HALT, do_te_invoke); } else if(is_set(fsa_actions, A_TE_CANCEL)) { do_fsa_action(fsa_data, A_TE_CANCEL, do_te_invoke); } else if(is_set(fsa_actions, A_DC_JOIN_OFFER_ALL)) { do_fsa_action(fsa_data, A_DC_JOIN_OFFER_ALL, do_dc_join_offer_all); } else if(is_set(fsa_actions, A_DC_JOIN_OFFER_ONE)) { do_fsa_action(fsa_data, A_DC_JOIN_OFFER_ONE, do_dc_join_offer_all); } else if(is_set(fsa_actions, A_DC_JOIN_PROCESS_REQ)) { do_fsa_action(fsa_data, A_DC_JOIN_PROCESS_REQ, do_dc_join_filter_offer); } else if(is_set(fsa_actions, A_DC_JOIN_PROCESS_ACK)) { do_fsa_action(fsa_data, A_DC_JOIN_PROCESS_ACK, do_dc_join_ack); /* * Low(er) priority actions * Make sure the CIB is always updated before invoking the * PE, and the PE before the TE */ } else if(is_set(fsa_actions, A_CIB_INVOKE_LOCAL)) { do_fsa_action(fsa_data, A_CIB_INVOKE_LOCAL, do_cib_invoke); } else if(is_set(fsa_actions, A_CIB_INVOKE)) { do_fsa_action(fsa_data, A_CIB_INVOKE, do_cib_invoke); } else if(is_set(fsa_actions, A_DC_JOIN_FINALIZE)) { do_fsa_action(fsa_data, A_DC_JOIN_FINALIZE, do_dc_join_finalize); } else if(is_set(fsa_actions, A_LRM_INVOKE)) { do_fsa_action(fsa_data, A_LRM_INVOKE, do_lrm_invoke); } else if(is_set(fsa_actions, A_PE_INVOKE)) { do_fsa_action(fsa_data, A_PE_INVOKE, do_pe_invoke); } else if(is_set(fsa_actions, A_TE_INVOKE)) { do_fsa_action(fsa_data, A_TE_INVOKE, do_te_invoke); } else if(is_set(fsa_actions, A_CL_JOIN_ANNOUNCE)) { do_fsa_action(fsa_data, A_CL_JOIN_ANNOUNCE, do_cl_join_announce); /* sub-system stop */ } else if(is_set(fsa_actions, A_DC_RELEASED)) { do_fsa_action(fsa_data, A_DC_RELEASED, do_dc_release); } else if(is_set(fsa_actions, A_PE_STOP)) { do_fsa_action(fsa_data, A_PE_STOP, do_pe_control); } else if(is_set(fsa_actions, A_TE_STOP)) { do_fsa_action(fsa_data, A_TE_STOP, do_te_control); } else if(is_set(fsa_actions, A_SHUTDOWN)) { do_fsa_action(fsa_data, A_SHUTDOWN, do_shutdown); } else if(is_set(fsa_actions, A_LRM_DISCONNECT)) { do_fsa_action(fsa_data, A_LRM_DISCONNECT, do_lrm_control); } else if(is_set(fsa_actions, A_CCM_DISCONNECT)) { do_fsa_action(fsa_data, A_CCM_DISCONNECT, do_ccm_control); } else if(is_set(fsa_actions, A_HA_DISCONNECT)) { do_fsa_action(fsa_data, A_HA_DISCONNECT, do_ha_control); } else if(is_set(fsa_actions, A_CIB_STOP)) { do_fsa_action(fsa_data, A_CIB_STOP, do_cib_control); } else if(is_set(fsa_actions, A_STOP)) { do_fsa_action(fsa_data, A_STOP, do_stop); /* exit gracefully */ } else if(is_set(fsa_actions, A_EXIT_0)) { do_fsa_action(fsa_data, A_EXIT_0, do_exit); /* Error checking and reporting */ } else { crm_err("Action %s (0x%llx) not supported ", fsa_action2string(fsa_actions), fsa_actions); register_fsa_error_adv(C_FSA_INTERNAL, I_ERROR, fsa_data, NULL, __FUNCTION__); } } } void log_fsa_input(fsa_data_t *stored_msg) { crm_debug_2("Processing queued input %d", stored_msg->id); if(stored_msg->fsa_cause == C_CCM_CALLBACK) { crm_debug_3("FSA processing CCM callback from %s", stored_msg->origin); } else if(stored_msg->fsa_cause == C_LRM_OP_CALLBACK) { crm_debug_3("FSA processing LRM callback from %s", stored_msg->origin); } else if(stored_msg->data == NULL) { crm_debug_3("FSA processing input from %s", stored_msg->origin); } else { ha_msg_input_t *ha_input = fsa_typed_data_adv( stored_msg, fsa_dt_ha_msg, __FUNCTION__); crm_debug_3("FSA processing XML message from %s", stored_msg->origin); - crm_log_message(LOG_MSG, ha_input->msg); - crm_log_xml_debug_3(ha_input->xml, "FSA message data"); + crm_log_xml(LOG_MSG, "FSA message data", ha_input->xml); } } long long do_state_transition(long long actions, enum crmd_fsa_state cur_state, enum crmd_fsa_state next_state, fsa_data_t *msg_data) { long long tmp = actions; gboolean clear_recovery_bit = TRUE; enum crmd_fsa_cause cause = msg_data->fsa_cause; enum crmd_fsa_input current_input = msg_data->fsa_input; const char *state_from = fsa_state2string(cur_state); const char *state_to = fsa_state2string(next_state); const char *input = fsa_input2string(current_input); CRM_DEV_ASSERT(cur_state != next_state); do_dot_log(DOT_PREFIX"\t%s -> %s [ label=%s cause=%s origin=%s ]", state_from, state_to, input, fsa_cause2string(cause), msg_data->origin); crm_info("State transition %s -> %s [ input=%s cause=%s origin=%s ]", state_from, state_to, input, fsa_cause2string(cause), msg_data->origin); /* the last two clauses might cause trouble later */ if(election_timeout != NULL && next_state != S_ELECTION && cur_state != S_RELEASE_DC) { crm_timer_stop(election_timeout); /* } else { */ /* crm_timer_start(election_timeout); */ } #if 0 if(is_set(fsa_input_register, R_SHUTDOWN)){ set_bit_inplace(tmp, A_DC_TIMER_STOP); } #endif if(next_state == S_INTEGRATION) { set_bit_inplace(tmp, A_INTEGRATE_TIMER_START); } else { set_bit_inplace(tmp, A_INTEGRATE_TIMER_STOP); } if(next_state == S_FINALIZE_JOIN) { set_bit_inplace(tmp, A_FINALIZE_TIMER_START); } else { set_bit_inplace(tmp, A_FINALIZE_TIMER_STOP); } if(next_state != S_PENDING) { set_bit_inplace(tmp, A_DC_TIMER_STOP); } if(next_state != S_ELECTION) { highest_born_on = 0; } if(next_state != S_IDLE) { crm_timer_stop(recheck_timer); } switch(next_state) { case S_PENDING: fsa_cib_conn->cmds->set_slave(fsa_cib_conn, cib_scope_local); /* fall through */ case S_ELECTION: crm_debug_2("Resetting our DC to NULL on transition to %s", fsa_state2string(next_state)); update_dc(NULL, FALSE); break; case S_NOT_DC: if(is_set(fsa_input_register, R_SHUTDOWN)){ crm_info("(Re)Issuing shutdown request now" " that we have a new DC"); set_bit_inplace(tmp, A_SHUTDOWN_REQ); } CRM_DEV_ASSERT(fsa_our_dc != NULL); if(fsa_our_dc == NULL) { crm_err("Reached S_NOT_DC without a DC" " being recorded"); } break; case S_RECOVERY: clear_recovery_bit = FALSE; break; case S_FINALIZE_JOIN: CRM_DEV_ASSERT(AM_I_DC); if(cause == C_TIMER_POPPED) { crm_warn("Progressed to state %s after %s", fsa_state2string(next_state), fsa_cause2string(cause)); } if(g_hash_table_size(welcomed_nodes) > 0) { char *msg = crm_strdup( " Welcome reply not received from"); crm_warn("%u cluster nodes failed to respond" " to the join offer.", g_hash_table_size(welcomed_nodes)); g_hash_table_foreach( welcomed_nodes, ghash_print_node, msg); crm_free(msg); } else { crm_info("All %d cluster nodes " "responded to the join offer.", g_hash_table_size(integrated_nodes)); } break; case S_POLICY_ENGINE: CRM_DEV_ASSERT(AM_I_DC); if(cause == C_TIMER_POPPED) { crm_warn("Progressed to state %s after %s", fsa_state2string(next_state), fsa_cause2string(cause)); } if(g_hash_table_size(finalized_nodes) > 0) { char *msg = crm_strdup( " Confirm not received from"); crm_err("%u cluster nodes failed to confirm" " their join.", g_hash_table_size(finalized_nodes)); g_hash_table_foreach( finalized_nodes, ghash_print_node, msg); crm_free(msg); } else if(g_hash_table_size(confirmed_nodes) == crm_active_members()) { crm_info("All %u cluster nodes are" " eligible to run resources.", crm_active_members()); } else if(g_hash_table_size(confirmed_nodes) > crm_active_members()) { crm_err("We have more confirmed nodes than our membership does"); register_fsa_input(C_FSA_INTERNAL, I_ELECTION, NULL); } else if(saved_ccm_membership_id != crm_peer_seq) { crm_info("Membership changed: %llu -> %llu - join restart", saved_ccm_membership_id, crm_peer_seq); register_fsa_input_before(C_FSA_INTERNAL, I_NODE_JOIN, NULL); } else { crm_warn("Only %u of %u cluster " "nodes are eligible to run resources - continue %d", g_hash_table_size(confirmed_nodes), crm_active_members(), g_hash_table_size(welcomed_nodes)); } /* initialize_join(FALSE); */ break; case S_STOPPING: case S_TERMINATE: /* possibly redundant */ set_bit_inplace(fsa_input_register, R_SHUTDOWN); break; case S_IDLE: CRM_DEV_ASSERT(AM_I_DC); dump_rsc_info(); if(is_set(fsa_input_register, R_SHUTDOWN)){ crm_info("(Re)Issuing shutdown request now" " that we are the DC"); set_bit_inplace(tmp, A_SHUTDOWN_REQ); } if(recheck_timer->period_ms > 0) { crm_timer_start(recheck_timer); } break; default: break; } if(clear_recovery_bit && next_state != S_PENDING) { tmp &= ~A_RECOVER; } else if(clear_recovery_bit == FALSE) { tmp |= A_RECOVER; } if(tmp != actions) { fsa_dump_actions(actions ^ tmp, "New actions"); actions = tmp; } return actions; } long long clear_flags(long long actions, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input) { long long saved_actions = actions; long long startup_actions = A_STARTUP|A_CIB_START|A_LRM_CONNECT|A_CCM_CONNECT|A_HA_CONNECT|A_READCONFIG|A_STARTED|A_CL_JOIN_QUERY; if(cur_state == S_STOPPING || is_set(fsa_input_register, R_SHUTDOWN)) { clear_bit_inplace(actions, startup_actions); } fsa_dump_actions(actions ^ saved_actions, "Cleared Actions"); return actions; } void dump_rsc_info(void) { } void ghash_print_node(gpointer key, gpointer value, gpointer user_data) { const char *text = user_data; const char *uname = key; const char *value_s = value; crm_info("%s: %s %s", text, uname, value_s); } diff --git a/crmd/fsa_proto.h b/crmd/fsa_proto.h index 9e9b5e3cbd..b038f0d814 100644 --- a/crmd/fsa_proto.h +++ b/crmd/fsa_proto.h @@ -1,370 +1,370 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 XML_FSA_PROTO__H #define XML_FSA_PROTO__H -extern crm_data_t *do_lrm_query(gboolean); +extern xmlNode *do_lrm_query(gboolean); /* A_READCONFIG */ void do_read_config(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); /* A_PE_INVOKE */ void 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); /* A_ERROR */ void do_error(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_LOG */ void do_log(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_STARTUP */ void do_startup(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_CIB_START, STOP, RESTART */ void do_cib_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_HA_CONNECT */ void do_ha_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_CCM_CONNECT */ void do_ccm_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_LRM_CONNECT */ void do_lrm_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_PE_START, STOP, RESTART */ void do_pe_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_TE_START, STOP, RESTART */ void do_te_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_STARTED */ void do_started(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_MSG_ROUTE */ void do_msg_route(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_RECOVER */ void do_recover(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_ELECTION_VOTE */ void do_election_vote(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_ELECTION_COUNT */ void do_election_count_vote(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_ELECTION_CHECK */ void do_election_check(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_ELECT_TIMER_START, A_ELECTION_TIMEOUT */ void do_election_timer_ctrl(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_DC_TIMER_STOP */ void do_timer_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); #if SUPPORT_HEARTBEAT /* A_CCM_UPDATE_CACHE */ void do_ccm_update_cache( enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, - oc_ed_t event, const oc_ev_membership_t *oc, crm_data_t *xml); + oc_ed_t event, const oc_ev_membership_t *oc, xmlNode *xml); #endif /* A_CCM_EVENT */ void do_ccm_event(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_DC_TAKEOVER */ void do_dc_takeover(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_DC_RELEASE */ void do_dc_release(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_DC_JOIN_OFFER_ALL */ void do_dc_join_offer_all(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_DC_JOIN_OFFER_ONE */ void do_dc_join_offer_one(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_DC_JOIN_ACK */ void do_dc_join_ack(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_DC_JOIN_REQ */ void do_dc_join_filter_offer(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_DC_JOIN_FINALIZE */ void do_dc_join_finalize(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_CL_JOIN_QUERY */ /* is there a DC out there? */ void do_cl_join_query(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); /* A_CL_JOIN_ANNOUNCE */ void do_cl_join_announce(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); /* A_CL_JOIN_REQUEST */ void do_cl_join_offer_respond(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); /* A_CL_JOIN_RESULT */ void do_cl_join_finalize_respond(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); /* A_CIB_INVOKE */ void do_cib_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_UPDATE_NODESTATUS */ void do_update_node_status(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_LRM_INVOKE */ void do_lrm_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_LRM_EVENT */ void do_lrm_event(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_PE_INVOKE */ void do_pe_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_TE_INVOKE, A_TE_CANCEL */ void do_te_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_TE_INVOKE */ void do_te_copyto(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_SHUTDOWN_REQ */ void do_shutdown_req(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_SHUTDOWN */ void do_shutdown(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_STOP */ void do_stop(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_EXIT_0, A_EXIT_1 */ void do_exit(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); #endif diff --git a/crmd/join_client.c b/crmd/join_client.c index b449f83385..b96c936adf 100644 --- a/crmd/join_client.c +++ b/crmd/join_client.c @@ -1,271 +1,271 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include int reannounce_count = 0; -void join_query_callback(const HA_Message *msg, int call_id, int rc, - crm_data_t *output, void *user_data); +void join_query_callback(xmlNode *msg, int call_id, int rc, + xmlNode *output, void *user_data); extern ha_msg_input_t *copy_ha_msg_input(ha_msg_input_t *orig); /* A_CL_JOIN_QUERY */ /* is there a DC out there? */ void do_cl_join_query(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) { - HA_Message *req = create_request(CRM_OP_JOIN_ANNOUNCE, NULL, NULL, + xmlNode *req = create_request(CRM_OP_JOIN_ANNOUNCE, NULL, NULL, CRM_SYSTEM_DC, CRM_SYSTEM_CRMD, NULL); sleep(1); /* give the CCM time to propogate to the DC */ crm_debug("Querying for a DC"); send_msg_via_ha(req); } /* A_CL_JOIN_ANNOUNCE */ /* this is kind of a workaround for the fact that we may not be around * or are otherwise unable to reply when the DC sends out A_WELCOME_ALL */ void do_cl_join_announce(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) { /* Once we hear from the DC, we can stop the timer * * This timer was started either on startup or when a node * left the CCM list */ /* dont announce if we're in one of these states */ if(cur_state != S_PENDING) { crm_warn("Do not announce ourselves in state %s", fsa_state2string(cur_state)); return; } if(AM_I_OPERATIONAL) { /* send as a broadcast */ - HA_Message *req = create_request( + xmlNode *req = create_request( CRM_OP_JOIN_ANNOUNCE, NULL, NULL, CRM_SYSTEM_DC, CRM_SYSTEM_CRMD, NULL); crm_debug("Announcing availability"); update_dc(NULL, FALSE); send_msg_via_ha(req); } else { /* Delay announce until we have finished local startup */ crm_warn("Delaying announce until local startup is complete"); return; } } static int query_call_id = 0; /* A_CL_JOIN_REQUEST */ /* aka. accept the welcome offer */ void do_cl_join_offer_respond(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) { ha_msg_input_t *input = fsa_typed_data(fsa_dt_ha_msg); - const char *welcome_from = cl_get_string(input->msg, F_CRM_HOST_FROM); - const char *join_id = ha_msg_value(input->msg, F_CRM_JOIN_ID); + const char *welcome_from = crm_element_value(input->msg, F_CRM_HOST_FROM); + const char *join_id = crm_element_value(input->msg, F_CRM_JOIN_ID); #if 0 if(we are sick) { log error ; /* save the request for later? */ return; } #endif crm_debug_2("Accepting join offer: join-%s", - cl_get_string(input->msg, F_CRM_JOIN_ID)); + crm_element_value(input->msg, F_CRM_JOIN_ID)); /* we only ever want the last one */ if(query_call_id > 0) { crm_debug_3("Cancelling previous join query: %d", query_call_id); remove_cib_op_callback(query_call_id, FALSE); query_call_id = 0; } update_dc(input->msg, FALSE); if(safe_str_neq(welcome_from, fsa_our_dc)) { /* dont do anything until DC's sort themselves out */ crm_err("Expected a welcome from %s, but %s replied", fsa_our_dc, welcome_from); return; } CRM_DEV_ASSERT(input != NULL); query_call_id = fsa_cib_conn->cmds->query( fsa_cib_conn, NULL, NULL, cib_scope_local); add_cib_op_callback( query_call_id, FALSE, crm_strdup(join_id), join_query_callback); crm_debug_2("Registered join query callback: %d", query_call_id); register_fsa_action(A_DC_TIMER_STOP); } void -join_query_callback(const HA_Message *msg, int call_id, int rc, - crm_data_t *output, void *user_data) +join_query_callback(xmlNode *msg, int call_id, int rc, + xmlNode *output, void *user_data) { - crm_data_t *local_cib = NULL; + xmlNode *local_cib = NULL; char *join_id = user_data; - crm_data_t *generation = create_xml_node( + xmlNode *generation = create_xml_node( NULL, XML_CIB_TAG_GENERATION_TUPPLE); CRM_DEV_ASSERT(join_id != NULL); query_call_id = 0; if(rc == cib_ok) { #if CRM_DEPRECATED_SINCE_2_0_4 if(safe_str_eq(crm_element_name(output), XML_TAG_CIB)) { local_cib = output; } else { local_cib = find_xml_node(output, XML_TAG_CIB, TRUE); } #else local_cib = output; CRM_DEV_ASSERT(safe_str_eq(crm_element_name(local_cib), XML_TAG_CIB)); #endif } if(local_cib != NULL) { - HA_Message *reply = NULL; + xmlNode *reply = NULL; crm_debug("Respond to join offer join-%s", join_id); crm_debug("Acknowledging %s as our DC", fsa_our_dc); copy_in_properties(generation, local_cib); reply = create_request( CRM_OP_JOIN_REQUEST, generation, fsa_our_dc, CRM_SYSTEM_DC, CRM_SYSTEM_CRMD, NULL); - ha_msg_add(reply, F_CRM_JOIN_ID, join_id); + crm_xml_add(reply, F_CRM_JOIN_ID, join_id); send_msg_via_ha(reply); } else { crm_err("Could not retrieve Generation to attach to our" " join acknowledgement: %s", cib_error2string(rc)); register_fsa_error_adv( C_FSA_INTERNAL, I_ERROR, NULL, NULL, __FUNCTION__); } crm_free(join_id); free_xml(generation); } /* A_CL_JOIN_RESULT */ /* aka. this is notification that we have (or have not) been accepted */ void do_cl_join_finalize_respond(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) { - crm_data_t *tmp1 = NULL; + xmlNode *tmp1 = NULL; gboolean was_nack = TRUE; ha_msg_input_t *input = fsa_typed_data(fsa_dt_ha_msg); int join_id = -1; - const char *op = cl_get_string(input->msg,F_CRM_TASK); - const char *ack_nack = cl_get_string(input->msg,CRM_OP_JOIN_ACKNAK); - const char *welcome_from = cl_get_string(input->msg,F_CRM_HOST_FROM); + const char *op = crm_element_value(input->msg,F_CRM_TASK); + const char *ack_nack = crm_element_value(input->msg,CRM_OP_JOIN_ACKNAK); + const char *welcome_from = crm_element_value(input->msg,F_CRM_HOST_FROM); if(safe_str_neq(op, CRM_OP_JOIN_ACKNAK)) { crm_debug_2("Ignoring op=%s message", op); return; } /* calculate if it was an ack or a nack */ if(crm_is_true(ack_nack)) { was_nack = FALSE; } - ha_msg_value_int(input->msg, F_CRM_JOIN_ID, &join_id); + crm_element_value_int(input->msg, F_CRM_JOIN_ID, &join_id); if(was_nack) { crm_err("Join join-%d with %s failed. NACK'd", join_id, welcome_from); register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); return; } if(AM_I_DC == FALSE && safe_str_eq(welcome_from, fsa_our_uname)) { crm_warn("Discarding our own welcome - we're no longer the DC"); return; } update_dc(input->msg, TRUE); /* send our status section to the DC */ crm_debug("Confirming join join-%d: %s", - join_id, cl_get_string(input->msg, F_CRM_TASK)); + join_id, crm_element_value(input->msg, F_CRM_TASK)); crm_debug_2("Discovering local LRM status"); tmp1 = do_lrm_query(TRUE); if(tmp1 != NULL) { - HA_Message *reply = create_request( + xmlNode *reply = create_request( CRM_OP_JOIN_CONFIRM, tmp1, fsa_our_dc, CRM_SYSTEM_DC, CRM_SYSTEM_CRMD, NULL); - ha_msg_add_int(reply, F_CRM_JOIN_ID, join_id); + crm_xml_add_int(reply, F_CRM_JOIN_ID, join_id); crm_debug("join-%d: Join complete." " Sending local LRM status to %s", join_id, fsa_our_dc); send_msg_via_ha(reply); if(AM_I_DC == FALSE) { register_fsa_input_adv(cause, I_NOT_DC, NULL, A_NOTHING, TRUE, __FUNCTION__); } free_xml(tmp1); } else { crm_err("Could send our LRM state to the DC"); register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL); } } diff --git a/crmd/join_dc.c b/crmd/join_dc.c index 7d177cbacf..0fb6096a7b 100644 --- a/crmd/join_dc.c +++ b/crmd/join_dc.c @@ -1,670 +1,670 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include GHashTable *welcomed_nodes = NULL; GHashTable *integrated_nodes = NULL; GHashTable *finalized_nodes = NULL; GHashTable *confirmed_nodes = NULL; char *max_epoch = NULL; char *max_generation_from = NULL; -crm_data_t *max_generation_xml = NULL; +xmlNode *max_generation_xml = NULL; void initialize_join(gboolean before); gboolean finalize_join_for(gpointer key, gpointer value, gpointer user_data); -void finalize_sync_callback(const HA_Message *msg, int call_id, int rc, - crm_data_t *output, void *user_data); +void finalize_sync_callback(xmlNode *msg, int call_id, int rc, + xmlNode *output, void *user_data); gboolean check_join_state(enum crmd_fsa_state cur_state, const char *source); void finalize_join(const char *caller); static int current_join_id = 0; unsigned long long saved_ccm_membership_id = 0; static void update_attrd(void) { static IPC_Channel *attrd = NULL; if(attrd == NULL) { crm_info("Connecting to attrd..."); attrd = init_client_ipc_comms_nodispatch(T_ATTRD); } if(attrd != NULL) { - HA_Message *update = ha_msg_new(3); - ha_msg_add(update, F_TYPE, T_ATTRD); - ha_msg_add(update, F_ORIG, "crmd"); - ha_msg_add(update, "task", "refresh"); + xmlNode *update = create_xml_node(NULL, __FUNCTION__); + crm_xml_add(update, F_TYPE, T_ATTRD); + crm_xml_add(update, F_ORIG, "crmd"); + crm_xml_add(update, "task", "refresh"); if(send_ipc_message(attrd, update) == FALSE) { crm_err("attrd refresh failed"); attrd = NULL; } else { crm_debug("sent attrd refresh"); } - crm_msg_del(update); + free_xml(update); } else { crm_info("Couldn't connect to attrd this time"); } } void initialize_join(gboolean before) { /* clear out/reset a bunch of stuff */ crm_debug("join-%d: Initializing join data (flag=%s)", current_join_id, before?"true":"false"); g_hash_table_destroy(welcomed_nodes); g_hash_table_destroy(integrated_nodes); g_hash_table_destroy(finalized_nodes); g_hash_table_destroy(confirmed_nodes); if(before) { if(max_generation_from != NULL) { crm_free(max_generation_from); max_generation_from = NULL; } if(max_generation_xml != NULL) { free_xml(max_generation_xml); max_generation_xml = NULL; } clear_bit_inplace(fsa_input_register, R_HAVE_CIB); clear_bit_inplace(fsa_input_register, R_CIB_ASKED); } welcomed_nodes = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); integrated_nodes = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); finalized_nodes = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); confirmed_nodes = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); } void erase_node_from_join(const char *uname) { if(uname == NULL) { return; } if(welcomed_nodes != NULL) { g_hash_table_remove(welcomed_nodes, uname); } if(integrated_nodes != NULL) { g_hash_table_remove(integrated_nodes, uname); } if(finalized_nodes != NULL) { g_hash_table_remove(finalized_nodes, uname); } if(confirmed_nodes != NULL) { g_hash_table_remove(confirmed_nodes, uname); } } static void join_make_offer(gpointer key, gpointer value, gpointer user_data) { const char *join_to = NULL; const crm_node_t *member = value; CRM_ASSERT(member != NULL); if(crm_is_member_active(member) == FALSE) { return; } join_to = member->uname; if(join_to == NULL) { crm_err("No recipient for welcome message"); return; } erase_node_from_join(join_to); if(saved_ccm_membership_id != crm_peer_seq) { saved_ccm_membership_id = crm_peer_seq; crm_info("Making join offers based on membership %llu", crm_peer_seq); } if(member->processes & crm_proc_crmd) { - HA_Message *offer = create_request( + xmlNode *offer = create_request( CRM_OP_JOIN_OFFER, NULL, join_to, CRM_SYSTEM_CRMD, CRM_SYSTEM_DC, NULL); char *join_offered = crm_itoa(current_join_id); - ha_msg_add_int(offer, F_CRM_JOIN_ID, current_join_id); + crm_xml_add_int(offer, F_CRM_JOIN_ID, current_join_id); /* send the welcome */ crm_debug("join-%d: Sending offer to %s", current_join_id, join_to); send_msg_via_ha(offer); g_hash_table_insert( welcomed_nodes, crm_strdup(join_to), join_offered); } else { crm_info("Peer process on %s is not active (yet?): %.8lx %d", join_to, (long)member->processes, g_hash_table_size(crm_peer_cache)); } } /* A_DC_JOIN_OFFER_ALL */ void do_dc_join_offer_all(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) { /* reset everyones status back to down or in_ccm in the CIB * * any nodes that are active in the CIB but not in the CCM list * will be seen as offline by the PE anyway */ current_join_id++; initialize_join(TRUE); /* do_update_cib_nodes(TRUE, __FUNCTION__); */ update_dc(NULL, FALSE); g_hash_table_foreach(crm_peer_cache, join_make_offer, NULL); /* dont waste time by invoking the PE yet; */ crm_info("join-%d: Waiting on %d outstanding join acks", current_join_id, g_hash_table_size(welcomed_nodes)); } /* A_DC_JOIN_OFFER_ONE */ void do_dc_join_offer_one(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) { crm_node_t *member; ha_msg_input_t *welcome = fsa_typed_data(fsa_dt_ha_msg); const char *join_to = NULL; if(welcome == NULL) { crm_err("Attempt to send welcome message " "without a message to reply to!"); return; } - join_to = cl_get_string(welcome->msg, F_CRM_HOST_FROM); + join_to = crm_element_value(welcome->msg, F_CRM_HOST_FROM); if(join_to != NULL && (cur_state == S_INTEGRATION || cur_state == S_FINALIZE_JOIN)) { /* note: it _is_ possible that a node will have been * sick or starting up when the original offer was made. * however, it will either re-announce itself in due course * _or_ we can re-store the original offer on the client. */ crm_debug("Re-offering membership to %s...", join_to); } crm_info("join-%d: Processing annouce request from %s in state %s", current_join_id, join_to, fsa_state2string(cur_state)); /* always offer to the DC (ourselves) * this ensures the correct value for max_generation_from */ member = g_hash_table_lookup(crm_peer_cache, fsa_our_uname); join_make_offer(NULL, member, NULL); member = g_hash_table_lookup(crm_peer_cache, join_to); join_make_offer(NULL, member, NULL); /* this was a genuine join request, cancel any existing * transition and invoke the PE */ if(need_transition(fsa_state)) { register_fsa_action(A_TE_CANCEL); } /* dont waste time by invoking the pe yet; */ crm_debug("Waiting on %d outstanding join acks for join-%d", g_hash_table_size(welcomed_nodes), current_join_id); } /* A_DC_JOIN_PROCESS_REQ */ void do_dc_join_filter_offer(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) { - crm_data_t *generation = NULL; + xmlNode *generation = NULL; int cmp = 0; int join_id = -1; gboolean ack_nack_bool = TRUE; const char *ack_nack = CRMD_JOINSTATE_MEMBER; ha_msg_input_t *join_ack = fsa_typed_data(fsa_dt_ha_msg); - const char *join_from = cl_get_string(join_ack->msg,F_CRM_HOST_FROM); - const char *ref = cl_get_string(join_ack->msg,XML_ATTR_REFERENCE); + const char *join_from = crm_element_value(join_ack->msg,F_CRM_HOST_FROM); + const char *ref = crm_element_value(join_ack->msg,XML_ATTR_REFERENCE); gpointer join_node = g_hash_table_lookup( crm_peer_cache, join_from); crm_debug("Processing req from %s", join_from); generation = join_ack->xml; - ha_msg_value_int(join_ack->msg, F_CRM_JOIN_ID, &join_id); + crm_element_value_int(join_ack->msg, F_CRM_JOIN_ID, &join_id); if(max_generation_xml != NULL && generation != NULL) { cmp = cib_compare_generation(max_generation_xml, generation); } if(join_node == NULL) { crm_err("Node %s is not a member", join_from); ack_nack_bool = FALSE; } else if(generation == NULL) { crm_err("Generation was NULL"); ack_nack_bool = FALSE; } else if(join_id != current_join_id) { crm_debug("Invalid response from %s: join-%d vs. join-%d", join_from, join_id, current_join_id); check_join_state(cur_state, __FUNCTION__); return; } else if(max_generation_xml == NULL) { max_generation_xml = copy_xml(generation); max_generation_from = crm_strdup(join_from); } else if(cmp < 0 || (cmp == 0 && safe_str_eq(join_from, fsa_our_uname))) { crm_debug("%s has a better generation number than" " the current max %s", join_from, max_generation_from); if(max_generation_xml) { crm_log_xml_debug(max_generation_xml, "Max generation"); } crm_log_xml_debug(generation, "Their generation"); crm_free(max_generation_from); free_xml(max_generation_xml); max_generation_from = crm_strdup(join_from); max_generation_xml = copy_xml(join_ack->xml); } if(ack_nack_bool == FALSE) { /* NACK this client */ ack_nack = CRMD_STATE_INACTIVE; crm_err("join-%d: NACK'ing node %s (ref %s)", join_id, join_from, ref); } else { crm_debug("join-%d: Welcoming node %s (ref %s)", join_id, join_from, ref); } /* add them to our list of CRMD_STATE_ACTIVE nodes */ g_hash_table_insert( integrated_nodes, crm_strdup(join_from), crm_strdup(ack_nack)); crm_debug("%u nodes have been integrated into join-%d", g_hash_table_size(integrated_nodes), join_id); g_hash_table_remove(welcomed_nodes, join_from); if(check_join_state(cur_state, __FUNCTION__) == FALSE) { /* dont waste time by invoking the PE yet; */ crm_debug("join-%d: Still waiting on %d outstanding offers", join_id, g_hash_table_size(welcomed_nodes)); } } /* A_DC_JOIN_FINALIZE */ void do_dc_join_finalize(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 cib_errors rc = cib_ok; /* This we can do straight away and avoid clients timing us out * while we compute the latest CIB */ crm_debug("Finializing join-%d for %d clients", current_join_id, g_hash_table_size(integrated_nodes)); if(g_hash_table_size(integrated_nodes) == 0) { return; } clear_bit_inplace(fsa_input_register, R_HAVE_CIB); if(max_generation_from == NULL || safe_str_eq(max_generation_from, fsa_our_uname)){ set_bit_inplace(fsa_input_register, R_HAVE_CIB); } if(is_set(fsa_input_register, R_IN_TRANSITION)) { crm_warn("join-%d: We are still in a transition." " Delaying until the TE completes.", current_join_id); crmd_fsa_stall(NULL); return; } if(is_set(fsa_input_register, R_HAVE_CIB) == FALSE) { /* ask for the agreed best CIB */ crm_info("join-%d: Asking %s for its copy of the CIB", current_join_id, crm_str(max_generation_from)); crm_log_xml_debug(max_generation_xml, "Requesting version"); set_bit_inplace(fsa_input_register, R_CIB_ASKED); rc = fsa_cib_conn->cmds->sync_from( fsa_cib_conn, max_generation_from, NULL, cib_quorum_override); add_cib_op_callback_timeout( rc, 60, FALSE, crm_strdup(max_generation_from), finalize_sync_callback); return; } else { /* Send _our_ CIB out to everyone */ fsa_cib_conn->cmds->sync_from( fsa_cib_conn, fsa_our_uname, NULL,cib_quorum_override); update_attrd(); } finalize_join(__FUNCTION__); } void -finalize_sync_callback(const HA_Message *msg, int call_id, int rc, - crm_data_t *output, void *user_data) +finalize_sync_callback(xmlNode *msg, int call_id, int rc, + xmlNode *output, void *user_data) { CRM_DEV_ASSERT(cib_not_master != rc); clear_bit_inplace(fsa_input_register, R_CIB_ASKED); if(rc != cib_ok) { do_crm_log((rc==cib_old_data?LOG_WARNING:LOG_ERR), "Sync from %s resulted in an error: %s", (char*)user_data, cib_error2string(rc)); /* restart the whole join process */ register_fsa_error_adv( C_FSA_INTERNAL, I_ELECTION_DC,NULL,NULL,__FUNCTION__); } else if(AM_I_DC && fsa_state == S_FINALIZE_JOIN) { finalize_join(__FUNCTION__); update_attrd(); } else { crm_debug("No longer the DC in S_FINALIZE_JOIN: %s/%s", AM_I_DC?"DC":"CRMd", fsa_state2string(fsa_state)); } crm_free(user_data); } void finalize_join(const char *caller) { - crm_data_t *cib = createEmptyCib(); + xmlNode *cib = createEmptyCib(); set_bit_inplace(fsa_input_register, R_HAVE_CIB); clear_bit_inplace(fsa_input_register, R_CIB_ASKED); set_uuid(cib, XML_ATTR_DC_UUID, fsa_our_uname); crm_debug_3("Update %s in the CIB to our uuid: %s", XML_ATTR_DC_UUID, crm_element_value(cib, XML_ATTR_DC_UUID)); fsa_cib_anon_update(NULL, cib, cib_quorum_override); free_xml(cib); crm_debug_3("Syncing to %d clients", g_hash_table_size(finalized_nodes)); /* make sure dc_uuid is re-set to us */ if(check_join_state(fsa_state, caller) == FALSE) { crm_debug("Notifying %d clients of join-%d results", g_hash_table_size(integrated_nodes), current_join_id); g_hash_table_foreach_remove( integrated_nodes, finalize_join_for, NULL); } } static void -join_update_complete_callback(const HA_Message *msg, int call_id, int rc, - crm_data_t *output, void *user_data) +join_update_complete_callback(xmlNode *msg, int call_id, int rc, + xmlNode *output, void *user_data) { fsa_data_t *msg_data = NULL; if(rc == cib_ok) { crm_debug("Join update %d complete", call_id); check_join_state(fsa_state, __FUNCTION__); } else { crm_err("Join update %d failed", call_id); - crm_log_message(LOG_DEBUG, msg); + crm_log_xml(LOG_DEBUG, "failed", msg); register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); } } /* A_DC_JOIN_PROCESS_ACK */ void do_dc_join_ack(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 join_id = -1; int call_id = 0; ha_msg_input_t *join_ack = fsa_typed_data(fsa_dt_ha_msg); const char *join_id_s = NULL; const char *join_state = NULL; - const char *op = cl_get_string(join_ack->msg, F_CRM_TASK); - const char *join_from = cl_get_string(join_ack->msg, F_CRM_HOST_FROM); + const char *op = crm_element_value(join_ack->msg, F_CRM_TASK); + const char *join_from = crm_element_value(join_ack->msg, F_CRM_HOST_FROM); if(safe_str_neq(op, CRM_OP_JOIN_CONFIRM)) { crm_debug("Ignoring op=%s message from %s", op, join_from); return; } - ha_msg_value_int(join_ack->msg, F_CRM_JOIN_ID, &join_id); - join_id_s = ha_msg_value(join_ack->msg, F_CRM_JOIN_ID); + crm_element_value_int(join_ack->msg, F_CRM_JOIN_ID, &join_id); + join_id_s = crm_element_value(join_ack->msg, F_CRM_JOIN_ID); /* now update them to "member" */ crm_debug_2("Processing ack from %s", join_from); join_state = (const char *) g_hash_table_lookup(finalized_nodes, join_from); if(join_state == NULL) { crm_err("Join not in progress: ignoring join-%d from %s", join_id, join_from); return; } else if(safe_str_neq(join_state, CRMD_JOINSTATE_MEMBER)) { crm_err("Node %s wasnt invited to join the cluster",join_from); g_hash_table_remove(finalized_nodes, join_from); return; } else if(join_id != current_join_id) { crm_err("Invalid response from %s: join-%d vs. join-%d", join_from, join_id, current_join_id); g_hash_table_remove(finalized_nodes, join_from); return; } g_hash_table_remove(finalized_nodes, join_from); if(g_hash_table_lookup(confirmed_nodes, join_from) != NULL) { crm_err("join-%d: hash already contains confirmation from %s", join_id, join_from); } g_hash_table_insert( confirmed_nodes, crm_strdup(join_from), crm_strdup(join_id_s)); crm_info("join-%d: Updating node state to %s for %s", join_id, CRMD_JOINSTATE_MEMBER, join_from); /* update CIB with the current LRM status from the node * We dont need to notify the TE of these updates, a transition will * be started in due time */ fsa_cib_update(XML_CIB_TAG_STATUS, join_ack->xml, cib_scope_local|cib_quorum_override, call_id); add_cib_op_callback( call_id, FALSE, NULL, join_update_complete_callback); crm_debug("join-%d: Registered callback for LRM update %d", join_id, call_id); } gboolean finalize_join_for(gpointer key, gpointer value, gpointer user_data) { const char *join_to = NULL; const char *join_state = NULL; - HA_Message *acknak = NULL; + xmlNode *acknak = NULL; if(key == NULL || value == NULL) { return TRUE; } join_to = (const char *)key; join_state = (const char *)value; /* make sure the node exists in the config section */ create_node_entry(join_to, join_to, NORMALNODE); /* send the ack/nack to the node */ acknak = create_request( CRM_OP_JOIN_ACKNAK, NULL, join_to, CRM_SYSTEM_CRMD, CRM_SYSTEM_DC, NULL); - ha_msg_add_int(acknak, F_CRM_JOIN_ID, current_join_id); + crm_xml_add_int(acknak, F_CRM_JOIN_ID, current_join_id); /* set the ack/nack */ if(safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER)) { crm_debug("join-%d: ACK'ing join request from %s, state %s", current_join_id, join_to, join_state); - ha_msg_add(acknak, CRM_OP_JOIN_ACKNAK, XML_BOOLEAN_TRUE); + crm_xml_add(acknak, CRM_OP_JOIN_ACKNAK, XML_BOOLEAN_TRUE); g_hash_table_insert( finalized_nodes, crm_strdup(join_to), crm_strdup(CRMD_JOINSTATE_MEMBER)); } else { crm_warn("join-%d: NACK'ing join request from %s, state %s", current_join_id, join_to, join_state); - ha_msg_add(acknak, CRM_OP_JOIN_ACKNAK, XML_BOOLEAN_FALSE); + crm_xml_add(acknak, CRM_OP_JOIN_ACKNAK, XML_BOOLEAN_FALSE); } send_msg_via_ha(acknak); return TRUE; } void ghash_print_node(gpointer key, gpointer value, gpointer user_data); gboolean check_join_state(enum crmd_fsa_state cur_state, const char *source) { crm_debug("Invoked by %s in state: %s", source, fsa_state2string(cur_state)); if(saved_ccm_membership_id != crm_peer_seq) { crm_info("%s: Membership changed since join started: %llu -> %llu", source, saved_ccm_membership_id, crm_peer_seq); register_fsa_input_before(C_FSA_INTERNAL, I_NODE_JOIN, NULL); } else if(cur_state == S_INTEGRATION) { if(g_hash_table_size(welcomed_nodes) == 0) { crm_debug("join-%d: Integration of %d peers complete: %s", current_join_id, g_hash_table_size(integrated_nodes), source); register_fsa_input_before( C_FSA_INTERNAL, I_INTEGRATED, NULL); return TRUE; } } else if(cur_state == S_FINALIZE_JOIN) { if(is_set(fsa_input_register, R_HAVE_CIB) == FALSE) { crm_debug("join-%d: Delaying I_FINALIZED until we have the CIB", current_join_id); return TRUE; } else if(g_hash_table_size(integrated_nodes) == 0 && g_hash_table_size(finalized_nodes) == 0) { crm_debug("join-%d complete: %s", current_join_id, source); register_fsa_input_later( C_FSA_INTERNAL, I_FINALIZED, NULL); } else if(g_hash_table_size(integrated_nodes) != 0 && g_hash_table_size(finalized_nodes) != 0) { char *msg = NULL; crm_err("join-%d: Waiting on %d integrated nodes" " AND %d finalized nodes", current_join_id, g_hash_table_size(integrated_nodes), g_hash_table_size(finalized_nodes)); msg = crm_strdup("Integrated node"); g_hash_table_foreach(integrated_nodes, ghash_print_node, msg); crm_free(msg); msg = crm_strdup("Finalized node"); g_hash_table_foreach(finalized_nodes, ghash_print_node, msg); crm_free(msg); } else if(g_hash_table_size(integrated_nodes) != 0) { crm_debug("join-%d: Still waiting on %d integrated nodes", current_join_id, g_hash_table_size(integrated_nodes)); } else if(g_hash_table_size(finalized_nodes) != 0) { crm_debug("join-%d: Still waiting on %d finalized nodes", current_join_id, g_hash_table_size(finalized_nodes)); } } return FALSE; } diff --git a/crmd/lrm.c b/crmd/lrm.c index 1819f50a79..7f402a1d32 100644 --- a/crmd/lrm.c +++ b/crmd/lrm.c @@ -1,1811 +1,1810 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include /* for access */ #include #include #include #include #include #include #include #include #include #include #include struct recurring_op_s { char *rsc_id; char *op_key; int call_id; int interval; }; char *make_stop_id(const char *rsc, int call_id); gboolean build_operation_update( - crm_data_t *rsc_list, lrm_op_t *op, const char *src, int lpc); + xmlNode *rsc_list, lrm_op_t *op, const char *src, int lpc); -gboolean build_active_RAs(crm_data_t *rsc_list); +gboolean build_active_RAs(xmlNode *rsc_list); gboolean is_rsc_active(const char *rsc_id); void do_update_resource(lrm_op_t *op); gboolean process_lrm_event(lrm_op_t *op); void do_lrm_rsc_op(lrm_rsc_t *rsc, const char *operation, - crm_data_t *msg, HA_Message *request); + xmlNode *msg, xmlNode *request); lrm_op_t *construct_op( - crm_data_t *rsc_op, const char *rsc_id, const char *operation); + xmlNode *rsc_op, const char *rsc_id, const char *operation); void send_direct_ack(const char *to_host, const char *to_sys, lrm_op_t* op, const char *rsc_id); void free_recurring_op(gpointer value); GHashTable *meta_hash = NULL; GHashTable *resources = NULL; GHashTable *pending_ops = NULL; GCHSource *lrm_source = NULL; int num_lrm_register_fails = 0; int max_lrm_register_fails = 30; /* A_LRM_CONNECT */ void do_lrm_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 = HA_OK; if(action & A_LRM_DISCONNECT) { if(verify_stopped(cur_state, LOG_INFO) == FALSE) { crmd_fsa_stall(NULL); return; } if(lrm_source) { crm_debug("Removing LRM connection from MainLoop"); if(G_main_del_IPC_Channel(lrm_source) == FALSE) { crm_err("Could not remove LRM connection" " from MainLoop"); } lrm_source = NULL; } if(fsa_lrm_conn) { fsa_lrm_conn->lrm_ops->signoff(fsa_lrm_conn); crm_info("Disconnected from the LRM"); clear_bit_inplace(fsa_input_register, R_LRM_CONNECTED); } /* TODO: Clean up the hashtable */ } if(action & A_LRM_CONNECT) { ret = HA_OK; pending_ops = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, free_recurring_op); resources = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); if(NULL == fsa_lrm_conn) { register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); ret = HA_FAIL; } if(ret == HA_OK) { crm_debug("Connecting to the LRM"); ret = fsa_lrm_conn->lrm_ops->signon( fsa_lrm_conn, CRM_SYSTEM_CRMD); } if(ret != HA_OK) { if(++num_lrm_register_fails < max_lrm_register_fails) { crm_warn("Failed to sign on to the LRM %d" " (%d max) times", num_lrm_register_fails, max_lrm_register_fails); crm_timer_start(wait_timer); crmd_fsa_stall(NULL); return; } } if(ret == HA_OK) { crm_debug_4("LRM: set_lrm_callback..."); ret = fsa_lrm_conn->lrm_ops->set_lrm_callback( fsa_lrm_conn, lrm_op_callback); if(ret != HA_OK) { crm_err("Failed to set LRM callbacks"); } } if(ret != HA_OK) { crm_err("Failed to sign on to the LRM %d" " (max) times", num_lrm_register_fails); register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); return; } /* TODO: create a destroy handler that causes * some recovery to happen */ lrm_source = G_main_add_IPC_Channel( G_PRIORITY_LOW, fsa_lrm_conn->lrm_ops->ipcchan(fsa_lrm_conn), FALSE, lrm_dispatch, fsa_lrm_conn, default_ipc_connection_destroy); set_bit_inplace(fsa_input_register, R_LRM_CONNECTED); crm_debug("LRM connection established"); } if(action & ~(A_LRM_CONNECT|A_LRM_DISCONNECT)) { crm_err("Unexpected action %s in %s", fsa_action2string(action), __FUNCTION__); } } static void ghash_print_pending(gpointer key, gpointer value, gpointer user_data) { const char *action = key; int *log_level = user_data; do_crm_log(*log_level, "Pending action: %s", action); } gboolean verify_stopped(enum crmd_fsa_state cur_state, int log_level) { gboolean rc = TRUE; GListPtr lrm_list = NULL; crm_debug("Checking for active resources before exit"); if(cur_state == S_TERMINATE) { log_level = LOG_ERR; } if(g_hash_table_size(pending_ops) > 0) { rc = FALSE; do_crm_log(log_level, "%d pending LRM operations at shutdown%s", g_hash_table_size(pending_ops), cur_state == S_TERMINATE?"":"... waiting"); if(cur_state == S_TERMINATE || !is_set(fsa_input_register, R_SENT_RSC_STOP)) { g_hash_table_foreach( pending_ops, ghash_print_pending, &log_level); } goto bail; } if(lrm_source != NULL && fsa_lrm_conn != NULL) { lrm_list = fsa_lrm_conn->lrm_ops->get_all_rscs(fsa_lrm_conn); } slist_iter( rsc_id, char, lrm_list, lpc, if(is_rsc_active(rsc_id) == FALSE) { continue; } rc = FALSE; crm_err("Resource %s was active at shutdown." " You may ignore this error if it is unmanaged.", rsc_id); ); bail: set_bit_inplace(fsa_input_register, R_SENT_RSC_STOP); if(cur_state == S_TERMINATE) { rc = TRUE; } return rc; } static const char * get_rsc_metadata(const char *type, const char *class, const char *provider) { int len = 0; char *key = NULL; char *metadata = NULL; if(meta_hash == NULL) { meta_hash = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); } CRM_CHECK(type != NULL, return NULL); CRM_CHECK(class != NULL, return NULL); if(provider == NULL) { provider = "heartbeat"; } len = strlen(type) + strlen(class) + strlen(provider) + 4; crm_malloc0(key, len); sprintf(key, "%s::%s:%s", type, class, provider); key[len-1] = 0; metadata = g_hash_table_lookup(meta_hash, key); if(metadata) { crm_debug_2("Returning cached metadata for %s", key); goto out; } crm_debug("Retreiving metadata for %s", key); metadata = fsa_lrm_conn->lrm_ops->get_rsc_type_metadata( fsa_lrm_conn, class, type, provider); if(metadata) { /* copy the metadata because the LRM likes using * g_alloc instead of cl_malloc */ char *m_copy = crm_strdup(metadata); g_hash_table_insert(meta_hash, key, m_copy); key = NULL; /* prevent it from being free'd */ g_free(metadata); metadata = m_copy; } else { crm_warn("No metadata found for %s", key); } out: crm_free(key); return metadata; } static GListPtr get_rsc_restart_list(lrm_rsc_t *rsc, lrm_op_t *op) { gboolean supported = FALSE; GListPtr restart_list = NULL; const char *value = NULL; const char *metadata_str = get_rsc_metadata( rsc->type, rsc->class, rsc->provider); - crm_data_t *params = NULL; - crm_data_t *actions = NULL; - crm_data_t *metadata = NULL; + xmlNode *params = NULL; + xmlNode *actions = NULL; + xmlNode *metadata = NULL; if(metadata_str == NULL) { return NULL; } metadata = string2xml(metadata_str); if(metadata == NULL) { crm_err("Metadata for %s::%s:%s is not valid XML", rsc->provider, rsc->class, rsc->type); return NULL; } actions = find_xml_node(metadata, "actions", TRUE); xml_child_iter_filter( actions, action, "action", value = crm_element_value(action, "name"); if(safe_str_eq("reload", value)) { supported = TRUE; break; } ); if(supported == FALSE) { goto cleanup; } params = find_xml_node(metadata, "parameters", TRUE); xml_child_iter_filter( params, param, "parameter", value = crm_element_value(param, "unique"); if(crm_is_true(value)) { value = crm_element_value(param, "name"); crm_debug("Attr %s is not reloadable", value); restart_list = g_list_append( restart_list, crm_strdup(value)); } ); cleanup: free_xml(metadata); return restart_list; } static void -append_restart_list(crm_data_t *update, lrm_op_t *op, const char *version) +append_restart_list(xmlNode *update, lrm_op_t *op, const char *version) { int len = 0; char *list = NULL; char *digest = NULL; lrm_rsc_t *rsc = NULL; const char *value = NULL; gboolean non_empty = FALSE; - crm_data_t *restart = NULL; + xmlNode *restart = NULL; GListPtr restart_list = NULL; if(op->interval > 0) { /* monitors are not reloadable */ return; } else if(safe_str_neq(CRMD_ACTION_START, op->op_type)) { /* only starts are potentially reloadable */ return; } else if(compare_version("1.0.8", version) > 0) { crm_debug("Caller version %s does not support reloads", version); return; } rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, op->rsc_id); if(rsc == NULL) { crm_info("Resource %s no longer in the LRM", op->rsc_id); return; } restart_list = get_rsc_restart_list(rsc, op); if(restart_list == NULL) { crm_debug("Resource %s does not support reloads", op->rsc_id); return; } restart = create_xml_node(NULL, "parameters"); slist_iter(param, const char, restart_list, lpc, int start = len; value = g_hash_table_lookup(op->params, param); if(value != NULL) { non_empty = TRUE; crm_xml_add(restart, param, value); } len += strlen(param) + 2; crm_realloc(list, len+1); sprintf(list+start, " %s ", param); ); digest = calculate_xml_digest(restart, TRUE, FALSE); crm_xml_add(update, XML_LRM_ATTR_OP_RESTART, list); crm_xml_add(update, XML_LRM_ATTR_RESTART_DIGEST, digest); crm_debug("%s : %s", digest, list); if(non_empty) { crm_log_xml_debug(restart, "restart digest source"); } slist_destroy(char, child, restart_list, crm_free(child)); free_xml(restart); crm_free(digest); crm_free(list); } gboolean build_operation_update( - crm_data_t *xml_rsc, lrm_op_t *op, const char *src, int lpc) + xmlNode *xml_rsc, lrm_op_t *op, const char *src, int lpc) { char *magic = NULL; const char *task = NULL; - crm_data_t *xml_op = NULL; + xmlNode *xml_op = NULL; char *op_id = NULL; char *local_user_data = NULL; const char *caller_version = NULL; char *digest = NULL; - crm_data_t *args_xml = NULL; - crm_data_t *args_parent = NULL; + xmlNode *args_xml = NULL; + xmlNode *args_parent = NULL; CRM_DEV_ASSERT(op != NULL); if(crm_assert_failed) { return FALSE; } crm_debug_2("%s: Updating resouce %s after %s %s op", src, op->rsc_id, op_status2text(op->op_status), op->op_type); if(op->op_status == LRM_OP_CANCELLED) { crm_debug_3("Ignoring cancelled op"); return TRUE; } if(AM_I_DC) { caller_version = CRM_FEATURE_SET; } else if(fsa_our_dc_version != NULL) { caller_version = fsa_our_dc_version; } else { /* there is a small risk in formerly mixed clusters that * it will be sub-optimal. * however with our upgrade policy, the update we send * should still be completely supported anyway */ caller_version = g_hash_table_lookup( op->params, XML_ATTR_CRM_VERSION); crm_warn("Falling back to operation originator version: %s", caller_version); } crm_debug_3("DC version: %s", caller_version); task = op->op_type; /* remap the task name under various scenarios * this makes life easier for the PE when its trying determin the current state */ if(crm_str_eq(task, "reload", TRUE)) { if(op->op_status == LRM_OP_DONE) { task = CRMD_ACTION_START; } else { task = CRMD_ACTION_STATUS; } } else if(crm_str_eq(task, CRMD_ACTION_MIGRATE, TRUE)) { /* if the migrate_from fails it will have enough info to do the right thing */ if(op->op_status == LRM_OP_DONE) { task = CRMD_ACTION_STOP; } else { task = CRMD_ACTION_STATUS; } } else if(op->op_status == LRM_OP_DONE && crm_str_eq(task, CRMD_ACTION_MIGRATED, TRUE)) { task = CRMD_ACTION_START; } if(safe_str_eq(task, CRMD_ACTION_NOTIFY)) { const char *n_type = g_hash_table_lookup( op->params, crm_meta_name("notify_type")); const char *n_task = g_hash_table_lookup( op->params, crm_meta_name("notify_operation")); #if CRM_DEPRECATED_SINCE_2_0_5 if(n_type == NULL) { n_type = g_hash_table_lookup(op->params, "notify_type"); } if(n_task == NULL) { n_task = g_hash_table_lookup(op->params, "notify_operation"); } #endif CRM_DEV_ASSERT(n_type != NULL); CRM_DEV_ASSERT(n_task != NULL); op_id = generate_notify_key(op->rsc_id, n_type, n_task); /* these are not yet allowed to fail */ op->op_status = LRM_OP_DONE; op->rc = 0; } else { op_id = generate_op_key(op->rsc_id, task, op->interval); } xml_op = find_entity(xml_rsc, XML_LRM_TAG_RSC_OP, op_id); if(xml_op != NULL) { crm_log_xml(LOG_DEBUG, "Replacing existing entry", xml_op); } else { xml_op = create_xml_node(xml_rsc, XML_LRM_TAG_RSC_OP); } crm_xml_add(xml_op, XML_ATTR_ID, op_id); crm_free(op_id); crm_xml_add(xml_op, XML_LRM_ATTR_TASK, task); crm_xml_add(xml_op, XML_ATTR_ORIGIN, src); if(op->user_data == NULL) { char *id = crm_itoa(op->call_id); crm_debug("Generating fake transition key for:" " %s_%s_%d %d from %s", op->rsc_id, op->op_type, op->interval, op->call_id, op->app_name); local_user_data = generate_transition_key(-1, 0, id); op->user_data = local_user_data; crm_free(id); } if(compare_version("1.0.3", caller_version) > 0) { magic = generate_transition_magic_v202( op->user_data, op->op_status); } else { magic = generate_transition_magic( op->user_data, op->op_status, op->rc); } crm_xml_add(xml_op, XML_ATTR_TRANSITION_KEY, op->user_data); crm_xml_add(xml_op, XML_ATTR_TRANSITION_MAGIC, magic); crm_free(magic); switch(op->op_status) { case LRM_OP_PENDING: break; case LRM_OP_CANCELLED: crm_err("What to do here"); break; case LRM_OP_ERROR: case LRM_OP_TIMEOUT: case LRM_OP_NOTSUPPORTED: crm_debug_2("Resource action %s/%s %s: %d", op->rsc_id, task, op_status2text(op->op_status), op->rc); break; case LRM_OP_DONE: break; } crm_xml_add_int(xml_op, XML_LRM_ATTR_CALLID, op->call_id); /* set these on 'xml_rsc' too to make life easy for the PE */ crm_xml_add(xml_op, XML_ATTR_CRM_VERSION, caller_version); crm_xml_add_int(xml_op, XML_LRM_ATTR_RC, op->rc); crm_xml_add_int(xml_op, XML_LRM_ATTR_OPSTATUS, op->op_status); crm_xml_add_int(xml_op, XML_LRM_ATTR_INTERVAL, op->interval); if(compare_version("2.1", caller_version) <= 0) { if(op->t_run || op->t_rcchange || op->exec_time || op->queue_time) { crm_debug("Timing data (%s_%s_%d): last=%lu change=%lu exec=%lu queue=%lu", op->rsc_id, op->op_type, op->interval, op->t_run, op->t_rcchange, op->exec_time, op->queue_time); crm_xml_add_int(xml_op, "last_run", op->t_run); crm_xml_add_int(xml_op, "last_rc_change", op->t_rcchange); crm_xml_add_int(xml_op, "exec_time", op->exec_time); crm_xml_add_int(xml_op, "queue_time", op->queue_time); } } /* this will enable us to later determin that the * resource's parameters have changed and we should force * a restart */ args_parent = NULL; #if CRM_DEPRECATED_SINCE_2_0_4 if(compare_version("1.0.4", caller_version) > 0) { args_parent = xml_op; } #endif args_xml = create_xml_node(args_parent, XML_TAG_PARAMS); g_hash_table_foreach(op->params, hash2field, args_xml); filter_action_parameters(args_xml, caller_version); digest = calculate_xml_digest(args_xml, TRUE, FALSE); if(op->interval == 0 && safe_str_neq(task, CRMD_ACTION_STOP)) { crm_debug("Calculated digest %s for %s (%s)\n", digest, ID(xml_op), crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC)); crm_log_xml(LOG_DEBUG, "digest:source", args_xml); } crm_xml_add(xml_op, XML_LRM_ATTR_OP_DIGEST, digest); crm_free(digest); if(args_parent == NULL) { free_xml(args_xml); } append_restart_list(xml_op, op, caller_version); if(op->op_status != LRM_OP_DONE && crm_str_eq(op->op_type, CRMD_ACTION_MIGRATED, TRUE)) { const char *host = g_hash_table_lookup( op->params, crm_meta_name("migrate_source_uuid")); crm_xml_add(xml_op, CRMD_ACTION_MIGRATED, host); } if(local_user_data) { crm_free(local_user_data); op->user_data = NULL; } return TRUE; } gboolean is_rsc_active(const char *rsc_id) { GList *op_list = NULL; gboolean active = FALSE; lrm_rsc_t *the_rsc = NULL; state_flag_t cur_state = 0; int max_call_id = -1; if(fsa_lrm_conn == NULL) { return FALSE; } the_rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rsc_id); crm_debug_3("Processing lrm_rsc_t entry %s", rsc_id); if(the_rsc == NULL) { crm_err("NULL resource returned from the LRM"); return FALSE; } op_list = the_rsc->ops->get_cur_state(the_rsc, &cur_state); crm_debug_3("\tcurrent state:%s",cur_state==LRM_RSC_IDLE?"Idle":"Busy"); slist_iter( op, lrm_op_t, op_list, llpc, crm_debug_2("Processing op %s_%d (%d) for %s (status=%d, rc=%d)", op->op_type, op->interval, op->call_id, the_rsc->id, op->op_status, op->rc); CRM_ASSERT(max_call_id <= op->call_id); if(op->rc == EXECRA_OK && safe_str_eq(op->op_type, CRMD_ACTION_STOP)) { active = FALSE; } else if(op->rc == EXECRA_OK && safe_str_eq(op->op_type, CRMD_ACTION_MIGRATE)) { /* a stricter check is too complex... * leave that to the PE */ active = FALSE; } else if(op->rc == EXECRA_NOT_RUNNING) { active = FALSE; } else { active = TRUE; } max_call_id = op->call_id; lrm_free_op(op); ); g_list_free(op_list); lrm_free_rsc(the_rsc); return active; } gboolean -build_active_RAs(crm_data_t *rsc_list) +build_active_RAs(xmlNode *rsc_list) { GList *op_list = NULL; GList *lrm_list = NULL; gboolean found_op = FALSE; state_flag_t cur_state = 0; if(fsa_lrm_conn == NULL) { return FALSE; } lrm_list = fsa_lrm_conn->lrm_ops->get_all_rscs(fsa_lrm_conn); slist_iter( rid, char, lrm_list, lpc, lrm_rsc_t *the_rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid); - crm_data_t *xml_rsc = create_xml_node( + xmlNode *xml_rsc = create_xml_node( rsc_list, XML_LRM_TAG_RESOURCE); int max_call_id = -1; crm_debug_2("Processing lrm_rsc_t entry %s", rid); if(the_rsc == NULL) { crm_err("NULL resource returned from the LRM"); continue; } crm_xml_add(xml_rsc, XML_ATTR_ID, the_rsc->id); crm_xml_add(xml_rsc, XML_ATTR_TYPE, the_rsc->type); crm_xml_add(xml_rsc, XML_AGENT_ATTR_CLASS, the_rsc->class); crm_xml_add(xml_rsc, XML_AGENT_ATTR_PROVIDER,the_rsc->provider); op_list = the_rsc->ops->get_cur_state(the_rsc, &cur_state); crm_debug_2("\tcurrent state:%s", cur_state==LRM_RSC_IDLE?"Idle":"Busy"); slist_iter( op, lrm_op_t, op_list, llpc, crm_debug_2("Processing op %s for %s (status=%d, rc=%d)", op->op_type, the_rsc->id, op->op_status, op->rc); if(max_call_id < op->call_id) { build_operation_update( xml_rsc, op, __FUNCTION__, llpc); } else if(max_call_id > op->call_id) { crm_err("Bad call_id in list=%d. Previous call_id=%d", op->call_id, max_call_id); } else { crm_warn("lrm->get_cur_state() returned" " duplicate entries for call_id=%d", op->call_id); } max_call_id = op->call_id; found_op = TRUE; lrm_free_op(op); ); if(found_op == FALSE && g_list_length(op_list) != 0) { crm_err("Could not properly determin last op" " for %s from %d entries", the_rsc->id, g_list_length(op_list)); } g_list_free(op_list); lrm_free_rsc(the_rsc); ); g_list_free(lrm_list); return TRUE; } -crm_data_t* +xmlNode* do_lrm_query(gboolean is_replace) { gboolean shut_down = FALSE; - crm_data_t *xml_result= NULL; - crm_data_t *xml_state = NULL; - crm_data_t *xml_data = NULL; - crm_data_t *rsc_list = NULL; + xmlNode *xml_result= NULL; + xmlNode *xml_state = NULL; + xmlNode *xml_data = NULL; + xmlNode *rsc_list = NULL; const char *exp_state = CRMD_JOINSTATE_MEMBER; if(is_set(fsa_input_register, R_SHUTDOWN)) { exp_state = CRMD_STATE_INACTIVE; shut_down = TRUE; } xml_state = create_node_state( fsa_our_uname, ACTIVESTATUS, XML_BOOLEAN_TRUE, ONLINESTATUS, CRMD_JOINSTATE_MEMBER, exp_state, !shut_down, __FUNCTION__); xml_data = create_xml_node(xml_state, XML_CIB_TAG_LRM); crm_xml_add(xml_data, XML_ATTR_ID, fsa_our_uuid); rsc_list = create_xml_node(xml_data, XML_LRM_TAG_RESOURCES); /* Build a list of active (not always running) resources */ build_active_RAs(rsc_list); if(is_replace) { crm_xml_add(xml_state, XML_CIB_ATTR_REPLACE, XML_CIB_TAG_LRM); } xml_result = create_cib_fragment(xml_state, XML_CIB_TAG_STATUS); free_xml(xml_state); crm_log_xml_debug_3(xml_state, "Current state of the LRM"); return xml_result; } static void delete_rsc_entry(const char *rsc_id) { - crm_data_t *xml_top = NULL; - crm_data_t *xml_tmp = NULL; + xmlNode *xml_top = NULL; + xmlNode *xml_tmp = NULL; /* * Remove the rsc from the CIB * * Avoids refreshing the entire LRM section of this host */ CRM_CHECK(rsc_id != NULL, return); xml_top = create_xml_node(NULL, XML_CIB_TAG_STATE); crm_xml_add(xml_top, XML_ATTR_ID, fsa_our_uuid); xml_tmp = create_xml_node(xml_top, XML_CIB_TAG_LRM); crm_xml_add(xml_tmp, XML_ATTR_ID, fsa_our_uuid); xml_tmp = create_xml_node(xml_tmp, XML_LRM_TAG_RESOURCES); xml_tmp = create_xml_node(xml_tmp, XML_LRM_TAG_RESOURCE); crm_xml_add(xml_tmp, XML_ATTR_ID, rsc_id); crm_debug("sync: Sending delete op for %s", rsc_id); fsa_cib_conn->cmds->delete_absolute(fsa_cib_conn, XML_CIB_TAG_STATUS, xml_top, NULL, cib_quorum_override); /* crm_log_xml_err(xml_top, "op:cancel"); */ free_xml(xml_top); } static void delete_op_entry(lrm_op_t *op, const char *rsc_id, const char *key, int call_id) { - crm_data_t *xml_top = NULL; + xmlNode *xml_top = NULL; /* * Remove the op from the CIB * * Avoids refreshing the entire LRM section of this host */ if(op != NULL) { xml_top = create_xml_node(NULL, XML_LRM_TAG_RSC_OP); crm_xml_add_int(xml_top, XML_LRM_ATTR_CALLID, op->call_id); crm_xml_add(xml_top, XML_ATTR_TRANSITION_KEY, op->user_data); crm_debug("async: Sending delete op for %s_%s_%d (call=%d)", op->rsc_id, op->op_type, op->interval, op->call_id); fsa_cib_conn->cmds->delete(fsa_cib_conn, XML_CIB_TAG_STATUS, xml_top, NULL, cib_quorum_override); } else if (rsc_id != NULL && key != NULL) { - crm_data_t *xml_tmp = NULL; + xmlNode *xml_tmp = NULL; xml_top = create_xml_node(NULL, XML_CIB_TAG_STATE); crm_xml_add(xml_top, XML_ATTR_ID, fsa_our_uuid); xml_tmp = create_xml_node(xml_top, XML_CIB_TAG_LRM); crm_xml_add(xml_tmp, XML_ATTR_ID, fsa_our_uuid); xml_tmp = create_xml_node(xml_tmp, XML_LRM_TAG_RESOURCES); xml_tmp = create_xml_node(xml_tmp, XML_LRM_TAG_RESOURCE); crm_xml_add(xml_tmp, XML_ATTR_ID, rsc_id); xml_tmp = create_xml_node(xml_tmp, XML_LRM_TAG_RSC_OP); crm_xml_add(xml_tmp, XML_ATTR_ID, key); if(call_id > 0) { crm_xml_add_int(xml_tmp, XML_LRM_ATTR_CALLID, call_id); } crm_debug("sync: Sending delete op for %s (call=%d)", key, call_id); fsa_cib_conn->cmds->delete_absolute(fsa_cib_conn, XML_CIB_TAG_STATUS, xml_top, NULL, cib_quorum_override); } else { crm_err("Not enough information to delete op entry: rsc=%p key=%p", rsc_id, key); return; } crm_log_xml_debug_2(xml_top, "op:cancel"); free_xml(xml_top); } static gboolean cancel_op(lrm_rsc_t *rsc, const char *key, int op, gboolean remove) { int rc = HA_OK; CRM_CHECK(op != 0, return FALSE); CRM_CHECK(rsc != NULL, return FALSE); if(key == NULL) { key = "unknown"; } crm_debug("Cancelling op %d for %s (%s)", op, rsc->id, key); rc = rsc->ops->cancel_op(rsc, op); if(rc != HA_OK) { crm_debug("Op %d for %s (%s): Nothing to cancel", op, rsc->id, key); if(key && remove) { delete_op_entry(NULL, rsc->id, key, op); } /* not doing this will block the node from shutting down */ g_hash_table_remove(pending_ops, key); } return TRUE; } const char *cancel_key = NULL; gboolean cancel_done = FALSE; lrm_rsc_t *cancel_rsc = NULL; static void cancel_action_by_key(gpointer key, gpointer value, gpointer user_data) { struct recurring_op_s *op = (struct recurring_op_s*)value; if(safe_str_eq(op->op_key, cancel_key)) { cancel_done = TRUE; cancel_op(cancel_rsc, key, op->call_id, TRUE); } } static gboolean cancel_op_key(lrm_rsc_t *rsc, const char *key, gboolean remove) { CRM_CHECK(rsc != NULL, return FALSE); cancel_key = key; cancel_rsc = rsc; cancel_done = FALSE; CRM_CHECK(key != NULL, return FALSE); g_hash_table_foreach(pending_ops, cancel_action_by_key, NULL); if(cancel_done == FALSE && remove) { crm_err("No known %s operation to cancel", key); delete_op_entry(NULL, rsc->id, key, 0); } return cancel_done; } static lrm_rsc_t * -get_lrm_resource(crm_data_t *resource, crm_data_t *op_msg, gboolean do_create) +get_lrm_resource(xmlNode *resource, xmlNode *op_msg, gboolean do_create) { char rid[64]; lrm_rsc_t *rsc = NULL; const char *short_id = ID(resource); const char *long_id = crm_element_value(resource, XML_ATTR_ID_LONG); crm_debug_2("Retrieving %s from the LRM.", short_id); CRM_CHECK(short_id != NULL, return NULL); if(rsc == NULL) { /* check if its already there (short name) */ strncpy(rid, short_id, 64); rid[63] = 0; rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid); } if(rsc == NULL && long_id != NULL) { /* try the long name instead */ strncpy(rid, long_id, 64); rid[63] = 0; rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid); } if(rsc == NULL && do_create) { /* add it to the LRM */ const char *type = crm_element_value(resource, XML_ATTR_TYPE); const char *class = crm_element_value(resource, XML_AGENT_ATTR_CLASS); const char *provider = crm_element_value(resource, XML_AGENT_ATTR_PROVIDER); GHashTable *params = xml2list(op_msg); CRM_CHECK(class != NULL, return NULL); CRM_CHECK(type != NULL, return NULL); crm_debug("Adding rsc %s before operation", short_id); strncpy(rid, short_id, 64); rid[63] = 0; #if CRM_DEPRECATED_SINCE_2_0_3 if(op_msg != NULL) { if(g_hash_table_lookup( params, XML_ATTR_CRM_VERSION) == NULL) { g_hash_table_destroy(params); params = xml2list_202(op_msg); } } #endif if(g_hash_table_size(params) == 0) { crm_log_xml_warn(op_msg, "EmptyParams"); } fsa_lrm_conn->lrm_ops->add_rsc( fsa_lrm_conn, rid, class, type, provider, params); rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid); g_hash_table_destroy(params); if(rsc == NULL) { fsa_data_t *msg_data = NULL; crm_err("Could not add resource %s to LRM", rid); register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL); } } return rsc; } static gboolean lrm_remove_deleted_op( gpointer key, gpointer value, gpointer user_data) { const char *rsc = user_data; struct recurring_op_s *pending = value; if(safe_str_eq(rsc, pending->rsc_id)) { crm_info("Removing op %s:%d for deleted resource %s", pending->op_key, pending->call_id, rsc); return TRUE; } return FALSE; } /* A_LRM_INVOKE */ void do_lrm_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) { gboolean create_rsc = TRUE; const char *crm_op = NULL; const char *from_sys = NULL; const char *from_host = NULL; const char *operation = NULL; ha_msg_input_t *input = fsa_typed_data(fsa_dt_ha_msg); - crm_op = cl_get_string(input->msg, F_CRM_TASK); - from_sys = cl_get_string(input->msg, F_CRM_SYS_FROM); + crm_op = crm_element_value(input->msg, F_CRM_TASK); + from_sys = crm_element_value(input->msg, F_CRM_SYS_FROM); if(safe_str_neq(from_sys, CRM_SYSTEM_TENGINE)) { - from_host = cl_get_string(input->msg, F_CRM_HOST_FROM); + from_host = crm_element_value(input->msg, F_CRM_HOST_FROM); } crm_debug_2("LRM command from: %s", from_sys); if(safe_str_eq(crm_op, CRM_OP_LRM_DELETE)) { operation = CRMD_ACTION_DELETE; } else if(safe_str_eq(operation, CRM_OP_LRM_REFRESH)) { crm_op = CRM_OP_LRM_REFRESH; } else if(safe_str_eq(crm_op, CRM_OP_LRM_FAIL)) { crm_info("Failing resource..."); operation = "fail"; } else if(input->xml != NULL) { operation = crm_element_value(input->xml, XML_LRM_ATTR_TASK); } if(safe_str_eq(crm_op, CRM_OP_LRM_REFRESH)) { enum cib_errors rc = cib_ok; - crm_data_t *fragment = do_lrm_query(TRUE); + xmlNode *fragment = do_lrm_query(TRUE); crm_info("Forcing a local LRM refresh"); fsa_cib_update(XML_CIB_TAG_STATUS, fragment, cib_quorum_override, rc); free_xml(fragment); } else if(safe_str_eq(crm_op, CRM_OP_LRM_QUERY)) { - crm_data_t *data = do_lrm_query(FALSE); - HA_Message *reply = create_reply(input->msg, data); + xmlNode *data = do_lrm_query(FALSE); + xmlNode *reply = create_reply(input->msg, data); if(relay_message(reply, TRUE) == FALSE) { crm_err("Unable to route reply"); - crm_log_message(LOG_ERR, reply); - crm_msg_del(reply); + crm_log_xml(LOG_ERR, "reply", reply); + free_xml(reply); } free_xml(data); } else if(safe_str_eq(operation, CRM_OP_PROBED) || safe_str_eq(crm_op, CRM_OP_REPROBE)) { const char *probed = XML_BOOLEAN_TRUE; if(safe_str_eq(crm_op, CRM_OP_REPROBE)) { probed = XML_BOOLEAN_FALSE; } update_attr(fsa_cib_conn, cib_none, XML_CIB_TAG_STATUS, fsa_our_uuid, NULL, NULL, CRM_OP_PROBED, probed, FALSE); } else if(operation != NULL) { lrm_rsc_t *rsc = NULL; - crm_data_t *params = NULL; - crm_data_t *xml_rsc = find_xml_node( + xmlNode *params = NULL; + xmlNode *xml_rsc = find_xml_node( input->xml, XML_CIB_TAG_RESOURCE, TRUE); CRM_CHECK(xml_rsc != NULL, return); /* only the first 16 chars are used by the LRM */ params = find_xml_node(input->xml, XML_TAG_ATTRS, TRUE); if(safe_str_eq(operation, CRMD_ACTION_DELETE)) { create_rsc = FALSE; } rsc = get_lrm_resource(xml_rsc, input->xml, create_rsc); if(rsc == NULL && create_rsc) { crm_err("Invalid resource definition"); - crm_log_xml_warn(input->msg, "Bad command"); + crm_log_xml_warn(input->msg, "bad input"); } else if(rsc == NULL) { lrm_op_t* op = NULL; crm_err("Not creating resource for a %s event: %s", operation, ID(input->xml)); - crm_log_xml_warn(input->msg, "Bad command"); + crm_log_xml_warn(input->msg, "bad input"); op = construct_op(input->xml, ID(xml_rsc), operation); op->op_status = LRM_OP_DONE; op->rc = EXECRA_OK; CRM_ASSERT(op != NULL); send_direct_ack(from_host, from_sys, op, ID(xml_rsc)); free_lrm_op(op); } else if(safe_str_eq(operation, CRMD_ACTION_CANCEL)) { lrm_op_t* op = NULL; char *op_key = NULL; int call = 0; const char *call_id = NULL; const char *op_task = NULL; const char *op_interval = NULL; CRM_CHECK(params != NULL, crm_log_xml_warn(input->xml, "Bad command"); return); op_interval = crm_element_value(params, crm_meta_name("interval")); op_task = crm_element_value(params, crm_meta_name(XML_LRM_ATTR_TASK)); call_id = crm_element_value(params, crm_meta_name(XML_LRM_ATTR_CALLID)); #if CRM_DEPRECATED_SINCE_2_0_5 if(op_interval == NULL) { op_interval = crm_element_value(params, "interval"); } if(op_task == NULL) { op_task = crm_element_value(params, XML_LRM_ATTR_TASK); if(op_task == NULL) { op_task = crm_element_value(params, "task"); } } #endif CRM_CHECK(op_task != NULL, crm_log_xml_warn(input->xml, "Bad command"); return); CRM_CHECK(op_interval != NULL, crm_log_xml_warn(input->xml, "Bad command"); return); op = construct_op(input->xml, rsc->id, op_task); CRM_ASSERT(op != NULL); op_key = generate_op_key( rsc->id,op_task,crm_parse_int(op_interval,"0")); call = crm_parse_int(call_id, "0"); if(call == 0) { cancel_op_key(rsc, op_key, TRUE); } else { cancel_op(rsc, op_key, call, TRUE); } op->op_status = LRM_OP_DONE; op->rc = EXECRA_OK; send_direct_ack(from_host, from_sys, op, rsc->id); crm_free(op_key); free_lrm_op(op); } else if(safe_str_eq(operation, CRMD_ACTION_DELETE)) { int rc = HA_OK; lrm_op_t* op = NULL; CRM_ASSERT(rsc != NULL); op = construct_op(input->xml, rsc->id, operation); CRM_ASSERT(op != NULL); op->op_status = LRM_OP_DONE; op->rc = EXECRA_OK; crm_info("Removing resource %s from the LRM", rsc->id); rc = fsa_lrm_conn->lrm_ops->delete_rsc(fsa_lrm_conn, rsc->id); if(rc != HA_OK) { crm_err("Failed to remove resource %s", rsc->id); op->op_status = LRM_OP_ERROR; op->rc = EXECRA_UNKNOWN_ERROR; } delete_rsc_entry(rsc->id); send_direct_ack(from_host, from_sys, op, rsc->id); free_lrm_op(op); g_hash_table_foreach_remove(pending_ops, lrm_remove_deleted_op, rsc->id); if(safe_str_neq(from_sys, CRM_SYSTEM_TENGINE)) { /* this isn't expected - trigger a new transition */ time_t now = time(NULL); char *now_s = crm_itoa(now); crm_debug("Triggering a refresh after %s deleted %s from the LRM", from_sys, rsc->id); update_attr(fsa_cib_conn, cib_none, XML_CIB_TAG_CRMCONFIG, NULL, NULL, NULL, "last-lrm-refresh", now_s, FALSE); crm_free(now_s); } } else if(rsc != NULL) { do_lrm_rsc_op(rsc, operation, input->xml, input->msg); } lrm_free_rsc(rsc); } else { crm_err("Operation was neither a lrm_query, nor a rsc op. %s", crm_str(crm_op)); register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); } } lrm_op_t * -construct_op(crm_data_t *rsc_op, const char *rsc_id, const char *operation) +construct_op(xmlNode *rsc_op, const char *rsc_id, const char *operation) { lrm_op_t *op = NULL; const char *op_delay = NULL; const char *op_timeout = NULL; const char *op_interval = NULL; const char *transition = NULL; CRM_DEV_ASSERT(rsc_id != NULL); crm_malloc0(op, sizeof(lrm_op_t)); op->op_type = crm_strdup(operation); op->op_status = LRM_OP_PENDING; op->rc = -1; op->rsc_id = crm_strdup(rsc_id); op->interval = 0; op->timeout = 0; op->start_delay = 0; op->copyparams = 0; op->app_name = crm_strdup(CRM_SYSTEM_CRMD); if(rsc_op == NULL) { CRM_DEV_ASSERT(safe_str_eq(CRMD_ACTION_STOP, operation)); op->user_data = NULL; op->user_data_len = 0; /* the stop_all_resources() case * by definition there is no DC (or they'd be shutting * us down). * So we should put our version here. */ op->params = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); g_hash_table_insert(op->params, crm_strdup(XML_ATTR_CRM_VERSION), crm_strdup(CRM_FEATURE_SET)); crm_debug_2("Constructed %s op for %s", operation, rsc_id); return op; } op->params = xml2list(rsc_op); #if CRM_DEPRECATED_SINCE_2_0_3 if(g_hash_table_lookup(op->params, XML_ATTR_CRM_VERSION) == NULL) { g_hash_table_destroy(op->params); op->params = xml2list_202(rsc_op); } #endif if(op->params == NULL) { CRM_DEV_ASSERT(safe_str_eq(CRMD_ACTION_STOP, operation)); } op_delay = g_hash_table_lookup(op->params, crm_meta_name("start_delay")); op_timeout = g_hash_table_lookup(op->params, crm_meta_name("timeout")); op_interval = g_hash_table_lookup(op->params, crm_meta_name("interval")); #if CRM_DEPRECATED_SINCE_2_0_5 if(op_delay == NULL) { op_delay = g_hash_table_lookup(op->params, "start_delay"); } if(op_timeout == NULL) { op_timeout = g_hash_table_lookup(op->params, "timeout"); } if(op_interval == NULL) { op_interval = g_hash_table_lookup(op->params, "interval"); } #endif op->interval = crm_parse_int(op_interval, "0"); op->timeout = crm_parse_int(op_timeout, "0"); op->start_delay = crm_parse_int(op_delay, "0"); /* sanity */ if(op->interval < 0) { op->interval = 0; } if(op->timeout < 0) { op->timeout = 0; } if(op->start_delay < 0) { op->start_delay = 0; } transition = crm_element_value(rsc_op, XML_ATTR_TRANSITION_KEY); CRM_CHECK(transition != NULL, return op); op->user_data = crm_strdup(transition); op->user_data_len = 1+strlen(op->user_data); if(op->interval != 0) { if(safe_str_eq(operation, CRMD_ACTION_START) || safe_str_eq(operation, CRMD_ACTION_STOP)) { crm_err("Start and Stop actions cannot have an interval"); op->interval = 0; } } /* reset the resource's parameters? */ if(op->interval == 0) { if(safe_str_eq(CRMD_ACTION_START, operation) || safe_str_eq(CRMD_ACTION_STATUS, operation)) { op->copyparams = 1; } } crm_debug_2("Constructed %s op for %s: interval=%d", operation, rsc_id, op->interval); return op; } void send_direct_ack(const char *to_host, const char *to_sys, lrm_op_t* op, const char *rsc_id) { - HA_Message *reply = NULL; - crm_data_t *update, *iter; - crm_data_t *fragment; + xmlNode *reply = NULL; + xmlNode *update, *iter; + xmlNode *fragment; CRM_DEV_ASSERT(op != NULL); if(crm_assert_failed) { return; } if(op->rsc_id == NULL) { CRM_DEV_ASSERT(rsc_id != NULL); op->rsc_id = crm_strdup(rsc_id); } if(to_sys == NULL) { to_sys = CRM_SYSTEM_TENGINE; } update = create_node_state( fsa_our_uname, NULL, NULL, NULL, NULL, NULL, FALSE, __FUNCTION__); iter = create_xml_node(update, XML_CIB_TAG_LRM); crm_xml_add(iter, XML_ATTR_ID, fsa_our_uuid); iter = create_xml_node(iter, XML_LRM_TAG_RESOURCES); iter = create_xml_node(iter, XML_LRM_TAG_RESOURCE); crm_xml_add(iter, XML_ATTR_ID, op->rsc_id); build_operation_update(iter, op, __FUNCTION__, 0); fragment = create_cib_fragment(update, XML_CIB_TAG_STATUS); reply = create_request(CRM_OP_INVOKE_LRM, fragment, to_host, to_sys, CRM_SYSTEM_LRMD, NULL); crm_log_xml_debug_2(update, "ACK Update"); crm_info("ACK'ing resource op %s_%s_%d from %s: %s", op->rsc_id, op->op_type, op->interval, op->user_data, - cl_get_string(reply, XML_ATTR_REFERENCE)); + crm_element_value(reply, XML_ATTR_REFERENCE)); if(relay_message(reply, TRUE) == FALSE) { - crm_log_message_adv(LOG_ERR, "Unable to route reply", reply); - crm_msg_del(reply); + crm_log_xml(LOG_ERR, "Unable to route reply", reply); + free_xml(reply); } free_xml(fragment); free_xml(update); } static void stop_recurring_action_by_rsc(gpointer key, gpointer value, gpointer user_data) { lrm_rsc_t *rsc = user_data; struct recurring_op_s *op = (struct recurring_op_s*)value; if(op->interval != 0 && safe_str_eq(op->rsc_id, rsc->id)) { cancel_op(rsc, key, op->call_id, FALSE); } } void do_lrm_rsc_op(lrm_rsc_t *rsc, const char *operation, - crm_data_t *msg, HA_Message *request) + xmlNode *msg, xmlNode *request) { int call_id = 0; char *op_id = NULL; lrm_op_t* op = NULL; fsa_data_t *msg_data = NULL; const char *transition = NULL; CRM_CHECK(rsc != NULL, return); if(msg != NULL) { transition = crm_element_value(msg, XML_ATTR_TRANSITION_KEY); if(transition == NULL) { - crm_err("Missing transition"); - crm_log_message(LOG_ERR, msg); + crm_log_xml_err(msg, "Missing transition number"); } } op = construct_op(msg, rsc->id, operation); /* stop the monitor before stopping the resource */ if(crm_str_eq(operation, CRMD_ACTION_STOP, TRUE) || crm_str_eq(operation, CRMD_ACTION_MIGRATE, TRUE)) { g_hash_table_foreach(pending_ops, stop_recurring_action_by_rsc, rsc); } /* now do the op */ crm_info("Performing op=%s_%s_%d key=%s)", rsc->id, operation, op->interval, transition); if(fsa_state != S_NOT_DC && fsa_state != S_TRANSITION_ENGINE) { if(safe_str_neq(operation, "fail") && safe_str_neq(operation, CRMD_ACTION_STOP)) { crm_info("Discarding attempt to perform action %s on %s" " in state %s", operation, rsc->id, fsa_state2string(fsa_state)); op->rc = 99; op->op_status = LRM_OP_ERROR; send_direct_ack(NULL, NULL, op, rsc->id); free_lrm_op(op); crm_free(op_id); return; } } op_id = generate_op_key(rsc->id, op->op_type, op->interval); if(op->interval > 0) { /* cancel it so we can then restart it without conflict */ cancel_op_key(rsc, op_id, FALSE); op->target_rc = CHANGED; } else { op->target_rc = EVERYTIME; } g_hash_table_replace(resources,crm_strdup(rsc->id), crm_strdup(op_id)); call_id = rsc->ops->perform_op(rsc, op); if(call_id <= 0) { crm_err("Operation %s on %s failed: %d", operation, rsc->id, call_id); register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL); } else { /* record all operations so we can wait * for them to complete during shutdown */ char *call_id_s = make_stop_id(rsc->id, call_id); struct recurring_op_s *pending = NULL; crm_malloc0(pending, sizeof(struct recurring_op_s)); crm_debug("Recording pending op: %d - %s %s", call_id, op_id, call_id_s); pending->call_id = call_id; pending->interval = op->interval; pending->op_key = crm_strdup(op_id); pending->rsc_id = crm_strdup(rsc->id); g_hash_table_replace(pending_ops, call_id_s, pending); } crm_free(op_id); free_lrm_op(op); return; } void free_recurring_op(gpointer value) { struct recurring_op_s *op = (struct recurring_op_s*)value; crm_free(op->rsc_id); crm_free(op->op_key); crm_free(op); } void free_lrm_op(lrm_op_t *op) { g_hash_table_destroy(op->params); crm_free(op->user_data); crm_free(op->output); crm_free(op->rsc_id); crm_free(op->op_type); crm_free(op->app_name); crm_free(op); } static void dup_attr(gpointer key, gpointer value, gpointer user_data) { g_hash_table_replace(user_data, crm_strdup(key), crm_strdup(value)); } lrm_op_t * copy_lrm_op(const lrm_op_t *op) { lrm_op_t *op_copy = NULL; CRM_DEV_ASSERT(op != NULL); if(crm_assert_failed) { return NULL; } CRM_ASSERT(op->rsc_id != NULL); crm_malloc0(op_copy, sizeof(lrm_op_t)); op_copy->op_type = crm_strdup(op->op_type); /* input fields */ op_copy->params = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); if(op->params != NULL) { g_hash_table_foreach(op->params, dup_attr, op_copy->params); } op_copy->timeout = op->timeout; op_copy->interval = op->interval; op_copy->target_rc = op->target_rc; /* in the CRM, this is always a string */ 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); if(op->app_name != NULL) { 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; } static void -cib_rsc_callback(const HA_Message *msg, int call_id, int rc, - crm_data_t *output, void *user_data) +cib_rsc_callback(xmlNode *msg, int call_id, int rc, + xmlNode *output, void *user_data) { switch(rc) { case cib_ok: case cib_diff_failed: case cib_diff_resync: crm_debug("Resource update %d complete: rc=%d", call_id, rc); break; default: crm_err("Resource update %d failed: (rc=%d) %s", call_id, rc, cib_error2string(rc)); } } void do_update_resource(lrm_op_t* op) { /* */ int rc = cib_ok; lrm_rsc_t *rsc = NULL; - crm_data_t *update, *iter; + xmlNode *update, *iter; CRM_CHECK(op != NULL, return); update = create_node_state( fsa_our_uname, NULL, NULL, NULL, NULL, NULL, FALSE, __FUNCTION__); iter = create_xml_node(update, XML_CIB_TAG_LRM); crm_xml_add(iter, XML_ATTR_ID, fsa_our_uuid); iter = create_xml_node(iter, XML_LRM_TAG_RESOURCES); iter = create_xml_node(iter, XML_LRM_TAG_RESOURCE); crm_xml_add(iter, XML_ATTR_ID, op->rsc_id); rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, op->rsc_id); CRM_CHECK(rsc->type != NULL, crm_err("Resource %s has no value for type", op->rsc_id)); CRM_CHECK(rsc->class != NULL, crm_err("Resource %s has no value for class", op->rsc_id)); crm_xml_add(iter, XML_ATTR_TYPE, rsc->type); crm_xml_add(iter, XML_AGENT_ATTR_CLASS, rsc->class); crm_xml_add(iter, XML_AGENT_ATTR_PROVIDER,rsc->provider); lrm_free_rsc(rsc); build_operation_update(iter, op, __FUNCTION__, 0); /* make it an asyncronous call and be done with it * * Best case: * the resource state will be discovered during * the next signup or election. * * Bad case: * we are shutting down and there is no DC at the time, * but then why were we shutting down then anyway? * (probably because of an internal error) * * Worst case: * we get shot for having resources "running" when the really weren't * * the alternative however means blocking here for too long, which * isnt acceptable */ fsa_cib_update(XML_CIB_TAG_STATUS, update, cib_quorum_override, rc); if(rc > 0) { /* the return code is a call number, not an error code */ crm_debug("Sent resource state update message: %d", rc); add_cib_op_callback(rc, FALSE, NULL, cib_rsc_callback); } else { crm_err("Resource state update failed: %s", cib_error2string(rc)); } free_xml(update); } void do_lrm_event(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data) { CRM_CHECK(FALSE, return); } gboolean process_lrm_event(lrm_op_t *op) { char *op_id = NULL; char *op_key = NULL; int log_level = LOG_ERR; CRM_CHECK(op != NULL, return FALSE); CRM_CHECK(op->rsc_id != NULL, return FALSE); op_key = generate_op_key(op->rsc_id, op->op_type, op->interval); switch(op->op_status) { case LRM_OP_ERROR: case LRM_OP_PENDING: case LRM_OP_NOTSUPPORTED: break; case LRM_OP_CANCELLED: log_level = LOG_INFO; break; case LRM_OP_DONE: log_level = LOG_INFO; break; case LRM_OP_TIMEOUT: log_level = LOG_DEBUG_3; crm_err("LRM operation %s (%d) %s (timeout=%dms)", op_key, op->call_id, op_status2text(op->op_status), op->timeout); break; default: crm_err("Mapping unknown status (%d) to ERROR", op->op_status); op->op_status = LRM_OP_ERROR; } if(op->op_status == LRM_OP_ERROR && (op->rc == EXECRA_RUNNING_MASTER || op->rc == EXECRA_NOT_RUNNING)) { /* Leave it up to the TE/PE to decide if this is an error */ op->op_status = LRM_OP_DONE; log_level = LOG_INFO; } do_crm_log(log_level, "LRM operation %s (call=%d, rc=%d) %s %s", op_key, op->call_id, op->rc, op_status2text(op->op_status), op->op_status==LRM_OP_ERROR?execra_code2string(op->rc):""); if(op->op_status == LRM_OP_ERROR && op->output != NULL) { crm_info("Result: %s", op->output); } if(op->op_status != LRM_OP_CANCELLED) { do_update_resource(op); if(op->interval != 0) { goto out; } } else if(op->interval == 0) { /* no known valid reason for this to happen */ crm_err("Op %s (call=%d): Cancelled", op_key, op->call_id); } else if(op->user_data != NULL) { delete_op_entry(op, NULL, NULL, op->call_id); } else { crm_err("Op %s (call=%d): No user data", op_key, op->call_id); } op_id = make_stop_id(op->rsc_id, op->call_id); if(g_hash_table_remove(pending_ops, op_id)) { crm_debug("Op %s (call=%d): Confirmed", op_key, op->call_id); goto out; } crm_err("Op %s (call=%d): Not matched", op_key, op->call_id); out: crm_free(op_key); crm_free(op_id); return TRUE; } char * make_stop_id(const char *rsc, int call_id) { char *op_id = NULL; crm_malloc0(op_id, strlen(rsc) + 34); if(op_id != NULL) { snprintf(op_id, strlen(rsc) + 34, "%s:%d", rsc, call_id); } return op_id; } diff --git a/crmd/main.c b/crmd/main.c index 0245d9a240..5f400cdf87 100644 --- a/crmd/main.c +++ b/crmd/main.c @@ -1,187 +1,187 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define OPTARGS "hV" void usage(const char* cmd, int exit_status); int crmd_init(void); -void crmd_hamsg_callback(const HA_Message * msg, void* private_data); +void crmd_hamsg_callback(const xmlNode * msg, void* private_data); extern void init_dotfile(void); GMainLoop* crmd_mainloop = NULL; int main(int argc, char ** argv) { int flag; int argerr = 0; crm_log_init(CRM_SYSTEM_CRMD, LOG_INFO, TRUE, FALSE, 0, NULL); crm_info("CRM Hg Version: %s\n", HA_HG_VERSION); while ((flag = getopt(argc, argv, OPTARGS)) != EOF) { switch(flag) { case 'V': cl_log_enable_stderr(1); alter_debug(DEBUG_INC); break; case 'h': /* Help message */ usage(crm_system_name, LSB_EXIT_OK); break; default: ++argerr; break; } } if(argc - optind == 1 && safe_str_eq("metadata", argv[optind])) { crmd_metadata(); return 0; } else if(argc - optind == 1 && safe_str_eq("version", argv[optind])) { fprintf(stderr, "CRM Version: "); fprintf(stdout, "%s (%s)\n", VERSION, HA_HG_VERSION); return 0; } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name,LSB_EXIT_GENERIC); } /* read local config file */ crm_debug_3("Enabling coredumps"); if(cl_enable_coredumps(1) != 0) { crm_warn("Cannot enable coredumps"); } if(crm_is_writable(HA_VARLIBDIR"/heartbeat/pengine", NULL, HA_CCMUSER, HA_APIGROUP, FALSE) == FALSE) { fprintf(stderr,"ERROR: Bad permissions on " HA_VARLIBDIR"/heartbeat/pengine... See logs for details\n"); fflush(stderr); return 100; } return crmd_init(); } int crmd_init(void) { int exit_code = 0; enum crmd_fsa_state state; fsa_state = S_STARTING; fsa_input_register = 0; /* zero out the regester */ init_dotfile(); crm_info("Starting %s", crm_system_name); register_fsa_input(C_STARTUP, I_STARTUP, NULL); state = s_crmd_fsa(C_STARTUP); if (state == S_PENDING || state == S_STARTING) { /* Create the mainloop and run it... */ crmd_mainloop = g_main_new(FALSE); crm_info("Starting %s's mainloop", crm_system_name); #ifdef REALTIME_SUPPORT static int crm_realtime = 1; if (crm_realtime == 1){ cl_enable_realtime(); }else if (crm_realtime == 0){ cl_disable_realtime(); } cl_make_realtime(SCHED_RR, 5, 64, 64); #endif g_main_run(crmd_mainloop); return_to_orig_privs(); if(is_set(fsa_input_register, R_STAYDOWN)) { crm_info("Inhibiting respawn by Heartbeat"); exit_code = 100; } } else { crm_err("Startup of %s failed. Current state: %s", crm_system_name, fsa_state2string(state)); exit_code = 1; } crm_info("[%s] stopped (%d)", crm_system_name, exit_code); return exit_code; } void usage(const char* cmd, int exit_status) { FILE* stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-V] [-h|version|metadata]\n", cmd); fprintf(stream, "\t-h\t: this help message\n"); fprintf(stream, "\t-V\t: increase verbosity\n"); fprintf(stream, "\tmetadata\t: show configurable crmd options\n"); fprintf(stream, "\tversion\t\t: show version information and quit\n"); fflush(stream); exit(exit_status); } diff --git a/crmd/messages.c b/crmd/messages.c index afa46c8ea3..b35c7b72b0 100644 --- a/crmd/messages.c +++ b/crmd/messages.c @@ -1,1210 +1,1208 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include GListPtr fsa_message_queue = NULL; extern void crm_shutdown(int nsig); enum crmd_fsa_input handle_request(ha_msg_input_t *stored_msg); enum crmd_fsa_input handle_response(ha_msg_input_t *stored_msg); -enum crmd_fsa_input handle_shutdown_request(HA_Message *stored_msg); +enum crmd_fsa_input handle_shutdown_request(xmlNode *stored_msg); ha_msg_input_t *copy_ha_msg_input(ha_msg_input_t *orig); gboolean ipc_queue_helper(gpointer key, gpointer value, gpointer user_data); #ifdef MSG_LOG # define ROUTER_RESULT(x) crm_debug_3("Router result: %s", x); \ - crm_log_message_adv(LOG_MSG, "router.log", relay_message); + crm_log_xml(LOG_MSG, "router.log", relay_message); #else # define ROUTER_RESULT(x) crm_debug_3("Router result: %s", x) #endif /* debug only, can wrap all it likes */ int last_data_id = 0; void register_fsa_error_adv( enum crmd_fsa_cause cause, enum crmd_fsa_input input, fsa_data_t *cur_data, void *new_data, const char *raised_from) { /* save the current actions if any */ if(fsa_actions != A_NOTHING) { register_fsa_input_adv( cur_data?cur_data->fsa_cause:C_FSA_INTERNAL, I_NULL, cur_data?cur_data->data:NULL, fsa_actions, TRUE, __FUNCTION__); } /* reset the action list */ fsa_actions = A_NOTHING; /* register the error */ register_fsa_input_adv( cause, input, new_data, A_NOTHING, TRUE, raised_from); } static gboolean last_was_vote = FALSE; int register_fsa_input_adv( enum crmd_fsa_cause cause, enum crmd_fsa_input input, void *data, long long with_actions, gboolean prepend, const char *raised_from) { unsigned old_len = g_list_length(fsa_message_queue); fsa_data_t *fsa_data = NULL; last_data_id++; CRM_CHECK(raised_from != NULL, raised_from = ""); crm_debug("%s %s FSA input %d (%s) (cause=%s) %s data", raised_from, prepend?"prepended":"appended",last_data_id, fsa_input2string(input), fsa_cause2string(cause), data?"with":"without"); if(input == I_WAIT_FOR_EVENT) { do_fsa_stall = TRUE; crm_debug("Stalling the FSA pending further input: cause=%s", fsa_cause2string(cause)); if(old_len > 0) { crm_warn("%s stalled the FSA with pending inputs", raised_from); fsa_dump_queue(LOG_DEBUG); } if(data == NULL) { set_bit_inplace(fsa_actions, with_actions); with_actions = A_NOTHING; return 0; } crm_err("%s stalled the FSA with data - this may be broken", raised_from); } if(old_len == 0) { last_was_vote = FALSE; } if(input == I_NULL && with_actions == A_NOTHING /* && data == NULL */){ /* no point doing anything */ crm_err("Cannot add entry to queue: no input and no action"); return 0; } else if(data == NULL) { last_was_vote = FALSE; #if 0 } else if(last_was_vote && cause == C_HA_MESSAGE && input == I_ROUTER) { - const char *op = cl_get_string( + const char *op = crm_element_value( ((ha_msg_input_t*)data)->msg, F_CRM_TASK); if(safe_str_eq(op, CRM_OP_VOTE)) { /* It is always safe to treat N successive votes as * a single one * * If all the discarded votes are more "loosing" than * the first then the result is accurate * (win or loose). * * If any of the discarded votes are less "loosing" * than the first then we will cast our vote and the * eventual winner will vote us down again (which * even in the case that N=2, is no worse than if we * had not disarded the vote). */ crm_debug_2("Vote compression: %d", old_len); return 0; } #endif } else if (cause == C_HA_MESSAGE && input == I_ROUTER) { - const char *op = cl_get_string( + const char *op = crm_element_value( ((ha_msg_input_t*)data)->msg, F_CRM_TASK); if(safe_str_eq(op, CRM_OP_VOTE)) { last_was_vote = TRUE; crm_debug_3("Added vote: %d", old_len); } } else { last_was_vote = FALSE; } crm_malloc0(fsa_data, sizeof(fsa_data_t)); fsa_data->id = last_data_id; fsa_data->fsa_input = input; fsa_data->fsa_cause = cause; fsa_data->origin = raised_from; fsa_data->data = NULL; fsa_data->data_type = fsa_dt_none; fsa_data->actions = with_actions; if(with_actions != A_NOTHING) { crm_debug_3("Adding actions %.16llx to input", with_actions); } if(data != NULL) { switch(cause) { case C_FSA_INTERNAL: case C_CRMD_STATUS_CALLBACK: case C_IPC_MESSAGE: case C_HA_MESSAGE: crm_debug_3("Copying %s data from %s as a HA msg", fsa_cause2string(cause), raised_from); fsa_data->data = copy_ha_msg_input(data); fsa_data->data_type = fsa_dt_ha_msg; break; case C_LRM_OP_CALLBACK: crm_debug_3("Copying %s data from %s as lrm_op_t", fsa_cause2string(cause), raised_from); fsa_data->data = copy_lrm_op((lrm_op_t*)data); fsa_data->data_type = fsa_dt_lrm; break; case C_CCM_CALLBACK: case C_SUBSYSTEM_CONNECT: case C_LRM_MONITOR_CALLBACK: case C_TIMER_POPPED: case C_SHUTDOWN: case C_HEARTBEAT_FAILED: case C_HA_DISCONNECT: case C_ILLEGAL: case C_UNKNOWN: case C_STARTUP: crm_err("Copying %s data (from %s)" " not yet implemented", fsa_cause2string(cause), raised_from); exit(1); break; } crm_debug_4("%s data copied", fsa_cause2string(fsa_data->fsa_cause)); } /* make sure to free it properly later */ if(prepend) { crm_debug_2("Prepending input"); fsa_message_queue = g_list_prepend(fsa_message_queue, fsa_data); } else { fsa_message_queue = g_list_append(fsa_message_queue, fsa_data); } crm_debug_2("Queue len: %d", g_list_length(fsa_message_queue)); fsa_dump_queue(LOG_DEBUG_2); if(old_len == g_list_length(fsa_message_queue)){ crm_err("Couldnt add message to the queue"); } if(fsa_source) { crm_debug_3("Triggering FSA: %s", __FUNCTION__); G_main_set_trigger(fsa_source); } return last_data_id; } void fsa_dump_queue(int log_level) { if(log_level < (int)crm_log_level) { return; } slist_iter( data, fsa_data_t, fsa_message_queue, lpc, do_crm_log(log_level, "queue[%d(%d)]: input %s raised by %s()\t(cause=%s)", lpc, data->id, fsa_input2string(data->fsa_input), data->origin, fsa_cause2string(data->fsa_cause)); ); } ha_msg_input_t * copy_ha_msg_input(ha_msg_input_t *orig) { ha_msg_input_t *input_copy = NULL; crm_malloc0(input_copy, sizeof(ha_msg_input_t)); if(orig != NULL) { crm_debug_4("Copy msg"); - input_copy->msg = ha_msg_copy(orig->msg); + input_copy->msg = copy_xml(orig->msg); if(orig->xml != NULL) { crm_debug_4("Copy xml"); input_copy->xml = copy_xml(orig->xml); } } else { crm_debug_3("No message to copy"); } return input_copy; } void delete_fsa_input(fsa_data_t *fsa_data) { lrm_op_t *op = NULL; - crm_data_t *foo = NULL; + xmlNode *foo = NULL; if(fsa_data == NULL) { return; } crm_debug_4("About to free %s data", fsa_cause2string(fsa_data->fsa_cause)); if(fsa_data->data != NULL) { switch(fsa_data->data_type) { case fsa_dt_ha_msg: delete_ha_msg_input(fsa_data->data); break; case fsa_dt_xml: foo = fsa_data->data; free_xml(foo); break; case fsa_dt_lrm: op = (lrm_op_t*)fsa_data->data; free_lrm_op(op); break; case fsa_dt_none: if(fsa_data->data != NULL) { crm_err("Dont know how to free %s data from %s", fsa_cause2string(fsa_data->fsa_cause), fsa_data->origin); exit(1); } break; } crm_debug_4("%s data freed", fsa_cause2string(fsa_data->fsa_cause)); } crm_free(fsa_data); } /* returns the next message */ fsa_data_t * get_message(void) { fsa_data_t* message = g_list_nth_data(fsa_message_queue, 0); fsa_message_queue = g_list_remove(fsa_message_queue, message); crm_debug_2("Processing input %d", message->id); return message; } /* returns the current head of the FIFO queue */ gboolean is_message(void) { return (g_list_length(fsa_message_queue) > 0); } void * fsa_typed_data_adv( fsa_data_t *fsa_data, enum fsa_data_type a_type, const char *caller) { void *ret_val = NULL; if(fsa_data == NULL) { do_crm_log(LOG_ERR, "%s: No FSA data available", caller); } else if(fsa_data->data == NULL) { do_crm_log(LOG_ERR, "%s: No message data available", caller); } else if(fsa_data->data_type != a_type) { do_crm_log(LOG_CRIT, "%s: Message data was the wrong type! %d vs. requested=%d." " Origin: %s", caller, fsa_data->data_type, a_type, fsa_data->origin); CRM_ASSERT(fsa_data->data_type == a_type); } else { ret_val = fsa_data->data; } return ret_val; } /* A_MSG_ROUTE */ void do_msg_route(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) { ha_msg_input_t *input = fsa_typed_data(fsa_dt_ha_msg); route_message(msg_data->fsa_cause, input); } void route_message(enum crmd_fsa_cause cause, ha_msg_input_t *input) { enum crmd_fsa_input result = I_NULL; CRM_CHECK(cause == C_IPC_MESSAGE || cause == C_HA_MESSAGE, return); /* try passing the buck first */ crm_debug_4("Attempting to route message"); if(relay_message(input->msg, cause==C_IPC_MESSAGE)) { crm_debug_4("Message routed..."); input->msg = NULL; return; } crm_debug_4("Message wasn't routed... try handling locally"); /* calculate defer */ result = handle_message(input); switch(result) { case I_NULL: crm_debug_4("Message processed"); break; case I_CIB_OP: break; case I_ROUTER: break; case I_NODE_JOIN: case I_JOIN_REQUEST: case I_JOIN_RESULT: break; default: crm_debug_4("Defering local processing of message"); register_fsa_input_later(cause, result, input); result = I_NULL; break; } if(result != I_NULL) { /* add to the front of the queue */ register_fsa_input(cause, result, input); } } /* * This method frees msg */ gboolean -send_request(HA_Message *msg, char **msg_reference) +send_request(xmlNode *msg, char **msg_reference) { gboolean was_sent = FALSE; /* crm_log_xml_debug_3(request, "Final request..."); */ if(msg_reference != NULL) { *msg_reference = crm_strdup( - cl_get_string(msg, XML_ATTR_REFERENCE)); + crm_element_value(msg, XML_ATTR_REFERENCE)); } was_sent = relay_message(msg, TRUE); if(was_sent == FALSE) { ha_msg_input_t *fsa_input = new_ha_msg_input(msg); register_fsa_input(C_IPC_MESSAGE, I_ROUTER, fsa_input); delete_ha_msg_input(fsa_input); - crm_msg_del(msg); + free_xml(msg); } return was_sent; } /* unless more processing is required, relay_message is freed */ gboolean -relay_message(HA_Message *relay_message, gboolean originated_locally) +relay_message(xmlNode *relay_message, gboolean originated_locally) { int is_for_dc = 0; int is_for_dcib = 0; int is_for_te = 0; int is_for_crm = 0; int is_for_cib = 0; int is_local = 0; gboolean processing_complete = FALSE; - const char *host_to = cl_get_string(relay_message, F_CRM_HOST_TO); - const char *sys_to = cl_get_string(relay_message, F_CRM_SYS_TO); - const char *sys_from= cl_get_string(relay_message, F_CRM_SYS_FROM); - const char *type = cl_get_string(relay_message, F_TYPE); + const char *host_to = crm_element_value(relay_message, F_CRM_HOST_TO); + const char *sys_to = crm_element_value(relay_message, F_CRM_SYS_TO); + const char *sys_from= crm_element_value(relay_message, F_CRM_SYS_FROM); + const char *type = crm_element_value(relay_message, F_TYPE); const char *msg_error = NULL; crm_debug_3("Routing message %s", - cl_get_string(relay_message, XML_ATTR_REFERENCE)); + crm_element_value(relay_message, XML_ATTR_REFERENCE)); if(relay_message == NULL) { msg_error = "Cannot route empty message"; } else if(safe_str_eq(CRM_OP_HELLO, - cl_get_string(relay_message, F_CRM_TASK))){ + crm_element_value(relay_message, F_CRM_TASK))){ /* quietly ignore */ processing_complete = TRUE; } else if(safe_str_neq(type, T_CRM)) { msg_error = "Bad message type"; } else if(sys_to == NULL) { msg_error = "Bad message destination: no subsystem"; } if(msg_error != NULL) { processing_complete = TRUE; crm_err("%s", msg_error); - crm_log_message(LOG_WARNING, relay_message); + crm_log_xml(LOG_WARNING, "bad msg", relay_message); } if(processing_complete) { - crm_msg_del(relay_message); + free_xml(relay_message); return TRUE; } processing_complete = TRUE; is_for_dc = (strcasecmp(CRM_SYSTEM_DC, sys_to) == 0); is_for_dcib = (strcasecmp(CRM_SYSTEM_DCIB, sys_to) == 0); is_for_te = (strcasecmp(CRM_SYSTEM_TENGINE, sys_to) == 0); is_for_cib = (strcasecmp(CRM_SYSTEM_CIB, sys_to) == 0); is_for_crm = (strcasecmp(CRM_SYSTEM_CRMD, sys_to) == 0); is_local = 0; if(host_to == NULL || strlen(host_to) == 0) { if(is_for_dc || is_for_te) { is_local = 0; } else if(is_for_crm && originated_locally) { is_local = 0; } else { is_local = 1; } } else if(strcasecmp(fsa_our_uname, host_to) == 0) { is_local=1; } if(is_for_dc || is_for_dcib || is_for_te) { if(AM_I_DC && is_for_te) { ROUTER_RESULT("Message result: Local relay"); send_msg_via_ipc(relay_message, sys_to); } else if(AM_I_DC) { ROUTER_RESULT("Message result: DC/CRMd process"); processing_complete = FALSE; /* more to be done by caller */ } else if(originated_locally && safe_str_neq(sys_from, CRM_SYSTEM_PENGINE) && safe_str_neq(sys_from, CRM_SYSTEM_TENGINE)) { /* Neither the TE or PE should be sending messages * to DC's on other nodes * * By definition, if we are no longer the DC, then * the PE or TE's data should be discarded */ ROUTER_RESULT("Message result: External relay to DC"); send_msg_via_ha(relay_message); } else { /* discard */ ROUTER_RESULT("Message result: Discard, not DC"); - crm_msg_del(relay_message); + free_xml(relay_message); } } else if(is_local && (is_for_crm || is_for_cib)) { ROUTER_RESULT("Message result: CRMd process"); processing_complete = FALSE; /* more to be done by caller */ } else if(is_local) { ROUTER_RESULT("Message result: Local relay"); send_msg_via_ipc(relay_message, sys_to); } else { ROUTER_RESULT("Message result: External relay"); send_msg_via_ha(relay_message); } return processing_complete; } gboolean crmd_authorize_message(ha_msg_input_t *client_msg, crmd_client_t *curr_client) { /* check the best case first */ - const char *sys_from = cl_get_string(client_msg->msg, F_CRM_SYS_FROM); + const char *sys_from = crm_element_value(client_msg->msg, F_CRM_SYS_FROM); char *uuid = NULL; char *client_name = NULL; char *major_version = NULL; char *minor_version = NULL; const char *filtered_from; gpointer table_key = NULL; gboolean auth_result = FALSE; struct crm_subsystem_s *the_subsystem = NULL; gboolean can_reply = FALSE; /* no-one has registered with this id */ - const char *op = cl_get_string(client_msg->msg, F_CRM_TASK); + const char *op = crm_element_value(client_msg->msg, F_CRM_TASK); if (safe_str_neq(CRM_OP_HELLO, op)) { if(sys_from == NULL) { crm_warn("Message [%s] was had no value for %s... discarding", - cl_get_string(client_msg->msg, XML_ATTR_REFERENCE), + crm_element_value(client_msg->msg, XML_ATTR_REFERENCE), F_CRM_SYS_FROM); return FALSE; } filtered_from = sys_from; /* The CIB can have two names on the DC */ if(strcasecmp(sys_from, CRM_SYSTEM_DCIB) == 0) filtered_from = CRM_SYSTEM_CIB; if (g_hash_table_lookup (ipc_clients, filtered_from) != NULL) { can_reply = TRUE; /* reply can be routed */ } crm_debug_2("Message reply can%s be routed from %s.", can_reply?"":" not", sys_from); if(can_reply == FALSE) { crm_warn("Message [%s] not authorized", - cl_get_string(client_msg->msg, XML_ATTR_REFERENCE)); + crm_element_value(client_msg->msg, XML_ATTR_REFERENCE)); } return can_reply; } crm_debug_3("received client join msg"); - crm_log_message(LOG_MSG, client_msg->msg); + crm_log_xml(LOG_MSG, "join", client_msg->msg); auth_result = process_hello_message( client_msg->xml, &uuid, &client_name, &major_version, &minor_version); if (auth_result == TRUE) { if(client_name == NULL || uuid == NULL) { crm_err("Bad client details (client_name=%s, uuid=%s)", crm_str(client_name), crm_str(uuid)); auth_result = FALSE; } } if (auth_result == TRUE) { /* check version */ int mav = atoi(major_version); int miv = atoi(minor_version); crm_debug_3("Checking client version number"); if (mav < 0 || miv < 0) { crm_err("Client version (%d:%d) is not acceptable", mav, miv); auth_result = FALSE; } crm_free(major_version); crm_free(minor_version); } if (safe_str_eq(CRM_SYSTEM_PENGINE, client_name)) { the_subsystem = pe_subsystem; } else if (safe_str_eq(CRM_SYSTEM_TENGINE, client_name)) { the_subsystem = te_subsystem; } if (auth_result == TRUE && the_subsystem != NULL) { /* if we already have one of those clients * only applies to te, pe etc. not admin clients */ crm_debug_3("Checking if %s is required/already connected", client_name); table_key = (gpointer)crm_strdup(client_name); if(is_set(fsa_input_register, the_subsystem->flag_connected)) { auth_result = FALSE; crm_free(table_key); table_key = NULL; crm_warn("Bit\t%.16llx set in %.16llx", the_subsystem->flag_connected, fsa_input_register); crm_err("Client %s is already connected", client_name); } else if(FALSE == is_set(fsa_input_register, the_subsystem->flag_required)) { crm_warn("Bit\t%.16llx not set in %.16llx", the_subsystem->flag_connected, fsa_input_register); crm_warn("Client %s joined but we dont need it", client_name); stop_subsystem(the_subsystem, TRUE); } else { the_subsystem->ipc = curr_client->client_channel; set_bit_inplace(fsa_input_register, the_subsystem->flag_connected); } } else { table_key = (gpointer)generate_hash_key(client_name, uuid); } if (auth_result == TRUE) { crm_debug_2("Accepted client %s", crm_str(table_key)); curr_client->table_key = table_key; curr_client->sub_sys = crm_strdup(client_name); curr_client->uuid = crm_strdup(uuid); g_hash_table_insert (ipc_clients, table_key, curr_client->client_channel); send_hello_message(curr_client->client_channel, "n/a", CRM_SYSTEM_CRMD, "0", "1"); crm_debug_3("Updated client list with %s", crm_str(table_key)); crm_debug_3("Triggering FSA: %s", __FUNCTION__); G_main_set_trigger(fsa_source); if(the_subsystem != NULL) { CRM_CHECK(the_subsystem->client == NULL, process_client_disconnect(the_subsystem->client)); the_subsystem->client = curr_client; } } else { crm_free(table_key); crm_warn("Rejected client logon request"); curr_client->client_channel->ch_status = IPC_DISC_PENDING; } if(uuid != NULL) crm_free(uuid); if(minor_version != NULL) crm_free(minor_version); if(major_version != NULL) crm_free(major_version); if(client_name != NULL) crm_free(client_name); /* hello messages should never be processed further */ return FALSE; } enum crmd_fsa_input handle_message(ha_msg_input_t *stored_msg) { enum crmd_fsa_input next_input = I_NULL; const char *type = NULL; if(stored_msg == NULL || stored_msg->msg == NULL) { crm_err("No message to handle"); return I_NULL; } - type = cl_get_string(stored_msg->msg, F_CRM_MSG_TYPE); + type = crm_element_value(stored_msg->msg, F_CRM_MSG_TYPE); if(safe_str_eq(type, XML_ATTR_REQUEST)) { next_input = handle_request(stored_msg); } else if(safe_str_eq(type, XML_ATTR_RESPONSE)) { next_input = handle_response(stored_msg); } else { crm_err("Unknown message type: %s", type); } /* crm_debug_2("%s: Next input is %s", __FUNCTION__, */ /* fsa_input2string(next_input)); */ return next_input; } #define schedule_pe() do { \ next_input = I_PE_CALC; \ if(fsa_pe_ref) { \ crm_debug("Cancelling %s...", fsa_pe_ref); \ crm_free(fsa_pe_ref); \ fsa_pe_ref = NULL; \ } \ } while(0) enum crmd_fsa_input handle_request(ha_msg_input_t *stored_msg) { - HA_Message *msg = NULL; + xmlNode *msg = NULL; enum crmd_fsa_input next_input = I_NULL; - const char *op = cl_get_string(stored_msg->msg, F_CRM_TASK); - const char *sys_to = cl_get_string(stored_msg->msg, F_CRM_SYS_TO); - const char *host_from = cl_get_string(stored_msg->msg, F_CRM_HOST_FROM); + const char *op = crm_element_value(stored_msg->msg, F_CRM_TASK); + const char *sys_to = crm_element_value(stored_msg->msg, F_CRM_SYS_TO); + const char *host_from = crm_element_value(stored_msg->msg, F_CRM_HOST_FROM); crm_debug_2("Received %s "XML_ATTR_REQUEST" from %s in state %s", op, host_from, fsa_state2string(fsa_state)); if(op == NULL) { - crm_err("Bad message"); - crm_log_message(LOG_ERR, stored_msg->msg); + crm_log_xml(LOG_ERR, "Bad message", stored_msg->msg); /*========== common actions ==========*/ } else if(strcasecmp(op, CRM_OP_NOOP) == 0) { crm_debug_2("no-op from %s", crm_str(host_from)); } else if(strcasecmp(op, CRM_OP_NOVOTE) == 0) { register_fsa_input_adv(C_HA_MESSAGE, I_NULL, stored_msg, A_ELECTION_COUNT|A_ELECTION_CHECK, FALSE, __FUNCTION__); } else if(strcasecmp(op, CRM_OP_VOTE) == 0) { /* count the vote and decide what to do after that */ register_fsa_input_adv(C_HA_MESSAGE, I_NULL, stored_msg, A_ELECTION_COUNT|A_ELECTION_CHECK, FALSE, __FUNCTION__); /* Sometimes we _must_ go into S_ELECTION */ if(fsa_state == S_HALT) { crm_debug("Forcing an election from S_HALT"); next_input = I_ELECTION; #if 0 } else if(AM_I_DC) { /* This is the old way of doing things but what is gained? */ next_input = I_ELECTION; #endif } } else if(strcasecmp(op, CRM_OP_LOCAL_SHUTDOWN) == 0) { crm_shutdown(SIGTERM); /*next_input = I_SHUTDOWN; */ next_input = I_NULL; } else if(strcasecmp(op, CRM_OP_PING) == 0) { /* eventually do some stuff to figure out * if we /are/ ok */ - crm_data_t *ping = createPingAnswerFragment(sys_to, "ok"); + xmlNode *ping = createPingAnswerFragment(sys_to, "ok"); crm_xml_add(ping, "crmd_state", fsa_state2string(fsa_state)); crm_info("Current ping state: %s", fsa_state2string(fsa_state)); msg = create_reply(stored_msg->msg, ping); free_xml(ping); if(relay_message(msg, TRUE) == FALSE) { - crm_msg_del(msg); + free_xml(msg); } /* probably better to do this via signals on the * local node */ } else if(strcasecmp(op, CRM_OP_DEBUG_UP) == 0) { alter_debug(DEBUG_INC); crm_info("Debug set to %d", get_crm_log_level()); } else if(strcasecmp(op, CRM_OP_DEBUG_DOWN) == 0) { alter_debug(DEBUG_DEC); crm_info("Debug set to %d", get_crm_log_level()); } else if(strcasecmp(op, CRM_OP_JOIN_OFFER) == 0) { next_input = I_JOIN_OFFER; crm_debug("Raising I_JOIN_OFFER: join-%s", - cl_get_string(stored_msg->msg, F_CRM_JOIN_ID)); + crm_element_value(stored_msg->msg, F_CRM_JOIN_ID)); } else if(strcasecmp(op, CRM_OP_JOIN_ACKNAK) == 0) { next_input = I_JOIN_RESULT; crm_debug("Raising I_JOIN_RESULT: join-%s", - cl_get_string(stored_msg->msg, F_CRM_JOIN_ID)); + crm_element_value(stored_msg->msg, F_CRM_JOIN_ID)); } else if(strcasecmp(op, CRM_OP_LRM_DELETE) == 0 || strcasecmp(op, CRM_OP_LRM_FAIL) == 0 || strcasecmp(op, CRM_OP_LRM_REFRESH) == 0 || strcasecmp(op, CRM_OP_REPROBE) == 0) { - cl_msg_modstring(stored_msg->msg, F_CRM_SYS_TO, CRM_SYSTEM_LRMD); + crm_xml_add(stored_msg->msg, F_CRM_SYS_TO, CRM_SYSTEM_LRMD); next_input = I_ROUTER; /* this functionality should only be enabled * if this is a development build */ } else if(CRM_DEV_BUILD && strcasecmp(op, CRM_OP_DIE) == 0/*constant condition*/) { crm_warn("Test-only code: Killing the CRM without mercy"); crm_warn("Inhibiting respawns"); exit(100); /*========== (NOT_DC)-Only Actions ==========*/ } else if(AM_I_DC == FALSE){ gboolean dc_match = safe_str_eq(host_from, fsa_our_dc); if(dc_match || fsa_our_dc == NULL) { if(strcasecmp(op, CRM_OP_HBEAT) == 0) { crm_debug_3("Received DC heartbeat from %s", host_from); next_input = I_DC_HEARTBEAT; } else if(fsa_our_dc == NULL) { crm_warn("CRMd discarding request: %s" " (DC: %s, from: %s)", op, crm_str(fsa_our_dc), host_from); - crm_warn("Ignored Request"); - crm_log_message(LOG_WARNING, stored_msg->msg); + crm_log_xml(LOG_WARNING, "Ignored Request", stored_msg->msg); } else if(strcasecmp(op, CRM_OP_SHUTDOWN) == 0) { next_input = I_STOP; } else { crm_err("CRMd didnt expect request: %s", op); - crm_log_message(LOG_ERR, stored_msg->msg); + crm_log_xml(LOG_ERR, "bad request", stored_msg->msg); } } else { crm_warn("Discarding %s op from %s", op, host_from); } /*========== DC-Only Actions ==========*/ } else if(AM_I_DC) { - const char *message = ha_msg_value(stored_msg->msg, "message"); + const char *message = crm_element_value( + stored_msg->msg, "message"); /* setting "fsa_pe_ref = NULL" makes sure we ignore any * PE reply that might be pending or in the queue while * we ask the CIB for a more up-to-date copy */ if(safe_str_eq(op, CRM_OP_TEABORT)) { crm_debug("Transition cancelled: %s/%s", op, message); clear_bit_inplace(fsa_input_register, R_IN_TRANSITION); if(need_transition(fsa_state)) { schedule_pe(); } else { crm_debug("Filtering %s op in state %s", op, fsa_state2string(fsa_state)); } } else if(strcasecmp(op, CRM_OP_TECOMPLETE) == 0) { crm_debug("Transition complete: %s/%s", op, message); clear_bit_inplace(fsa_input_register, R_IN_TRANSITION); if(fsa_state == S_TRANSITION_ENGINE) { next_input = I_TE_SUCCESS; } else { crm_debug("Filtering %s op in state %s", op, fsa_state2string(fsa_state)); } } else if(strcasecmp(op, CRM_OP_JOIN_ANNOUNCE) == 0) { next_input = I_NODE_JOIN; } else if(strcasecmp(op, CRM_OP_JOIN_REQUEST) == 0) { next_input = I_JOIN_REQUEST; } else if(strcasecmp(op, CRM_OP_JOIN_CONFIRM) == 0) { next_input = I_JOIN_RESULT; } else if(strcasecmp(op, CRM_OP_SHUTDOWN) == 0) { gboolean dc_match = safe_str_eq(host_from, fsa_our_dc); if(dc_match) { crm_err("We didnt ask to be shut down yet our" " TE is telling us too." " Better get out now!"); next_input = I_TERMINATE; } else if(is_set(fsa_input_register, R_SHUTDOWN)) { crm_info("Shutting ourselves down (DC)"); next_input = I_STOP; } else if(fsa_state != S_STOPPING) { crm_err("Another node is asking us to shutdown" " but we think we're ok."); next_input = I_ELECTION; } } else if(strcasecmp(op, CRM_OP_SHUTDOWN_REQ) == 0) { /* a slave wants to shut down */ /* create cib fragment and add to message */ next_input = handle_shutdown_request(stored_msg->msg); } else { crm_err("Unexpected request (%s) sent to the DC", op); - crm_log_message(LOG_ERR, stored_msg->msg); + crm_log_xml(LOG_ERR, "Unexpected", stored_msg->msg); } } return next_input; } enum crmd_fsa_input handle_response(ha_msg_input_t *stored_msg) { enum crmd_fsa_input next_input = I_NULL; - const char *op = cl_get_string(stored_msg->msg, F_CRM_TASK); - const char *sys_from = cl_get_string(stored_msg->msg, F_CRM_SYS_FROM); - const char *host_from = cl_get_string(stored_msg->msg, F_CRM_HOST_FROM); - const char *msg_ref = cl_get_string(stored_msg->msg, XML_ATTR_REFERENCE); + const char *op = crm_element_value(stored_msg->msg, F_CRM_TASK); + const char *sys_from = crm_element_value(stored_msg->msg, F_CRM_SYS_FROM); + const char *host_from = crm_element_value(stored_msg->msg, F_CRM_HOST_FROM); + const char *msg_ref = crm_element_value(stored_msg->msg, XML_ATTR_REFERENCE); crm_debug_2("Received %s "XML_ATTR_RESPONSE" from %s in state %s", op, host_from, fsa_state2string(fsa_state)); if(op == NULL) { - crm_err("Bad message"); - crm_log_message(LOG_ERR, stored_msg->msg); + crm_log_xml(LOG_ERR, "Bad message", stored_msg->msg); } else if(AM_I_DC && strcasecmp(op, CRM_OP_PECALC) == 0) { crm_debug_2("Processing %s reply %s (fsa=%s)", sys_from, msg_ref, crm_str(fsa_pe_ref)); if(msg_ref != NULL && safe_str_eq(msg_ref, fsa_pe_ref)) { next_input = I_PE_SUCCESS; crm_debug_2("Completed: %s...", fsa_pe_ref); crm_free(fsa_pe_ref); fsa_pe_ref = NULL; } else { crm_debug_2("Skipping superceeded reply from %s", sys_from); } } else if(strcasecmp(op, CRM_OP_VOTE) == 0 || strcasecmp(op, CRM_OP_HBEAT) == 0 || strcasecmp(op, CRM_OP_SHUTDOWN_REQ) == 0 || strcasecmp(op, CRM_OP_SHUTDOWN) == 0) { crm_debug_2("Ignoring %s from %s in %s", op, host_from, fsa_state2string(fsa_state)); next_input = I_NULL; } else { crm_err("Unexpected response (op=%s) sent to the %s", op, AM_I_DC?"DC":"CRMd"); next_input = I_NULL; } return next_input; } enum crmd_fsa_input -handle_shutdown_request(HA_Message *stored_msg) +handle_shutdown_request(xmlNode *stored_msg) { /* handle here to avoid potential version issues * where the shutdown message/proceedure may have * been changed in later versions. * * This way the DC is always in control of the shutdown */ time_t now = time(NULL); - crm_data_t *node_state = NULL; - const char *host_from = cl_get_string(stored_msg, F_CRM_HOST_FROM); + xmlNode *node_state = NULL; + const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM); if(host_from == NULL) { /* we're shutting down and the DC */ host_from = fsa_our_uname; } crm_info("Creating shutdown request for %s",host_from); - crm_log_message(LOG_MSG, stored_msg); + crm_log_xml(LOG_MSG, "message", stored_msg); node_state = create_node_state( host_from, NULL, NULL, NULL, NULL, CRMD_STATE_INACTIVE, FALSE, __FUNCTION__); crm_xml_add_int(node_state, XML_CIB_ATTR_SHUTDOWN, (int)now); fsa_cib_anon_update(XML_CIB_TAG_STATUS,node_state, cib_quorum_override); crm_log_xml_debug_2(node_state, "Shutdown update"); free_xml(node_state); /* will be picked up by the TE as long as its running */ if(need_transition(fsa_state) && is_set(fsa_input_register, R_TE_CONNECTED) == FALSE) { register_fsa_action(A_TE_CANCEL); } return I_NULL; } /* frees msg upon completion */ gboolean -send_msg_via_ha(HA_Message *msg) +send_msg_via_ha(xmlNode *msg) { int log_level = LOG_DEBUG_3; gboolean broadcast = FALSE; gboolean all_is_good = TRUE; - const char *op = cl_get_string(msg, F_CRM_TASK); - const char *sys_to = cl_get_string(msg, F_CRM_SYS_TO); - const char *host_to = cl_get_string(msg, F_CRM_HOST_TO); + const char *op = crm_element_value(msg, F_CRM_TASK); + const char *sys_to = crm_element_value(msg, F_CRM_SYS_TO); + const char *host_to = crm_element_value(msg, F_CRM_HOST_TO); enum crm_ais_msg_types dest = 0; if(is_openais_cluster()) { dest = 1; #if SUPPORT_AIS dest = text2msg_type(sys_to); #endif } if (msg == NULL) { crm_err("Attempt to send NULL Message via HA failed."); all_is_good = FALSE; } else { crm_debug_4("Relaying message to (%s) via HA", host_to); } if (all_is_good) { if (sys_to == NULL || strlen(sys_to) == 0) { crm_err("You did not specify a destination sub-system" " for this message."); all_is_good = FALSE; } } /* There are a number of messages may not need to be ordered. * At a later point perhaps we should detect them and send them * as unordered messages. */ if (all_is_good) { if (host_to == NULL || strlen(host_to) == 0 || safe_str_eq(sys_to, CRM_SYSTEM_DC)) { broadcast = TRUE; all_is_good = send_cluster_message(NULL, dest, msg, FALSE); } else { all_is_good = send_cluster_message(host_to, dest, msg, FALSE); } } if(all_is_good == FALSE) { log_level = LOG_WARNING; } if(log_level == LOG_WARNING || (safe_str_neq(op, CRM_OP_HBEAT))) { do_crm_log(log_level, "Sending %sHA message (ref=%s) to %s@%s %s.", broadcast?"broadcast ":"directed ", - cl_get_string(msg, XML_ATTR_REFERENCE), + crm_element_value(msg, XML_ATTR_REFERENCE), crm_str(sys_to), host_to==NULL?"":host_to, all_is_good?"succeeded":"failed"); } - crm_msg_del(msg); + free_xml(msg); return all_is_good; } /* msg is deleted by the time this returns */ gboolean -send_msg_via_ipc(HA_Message *msg, const char *sys) +send_msg_via_ipc(xmlNode *msg, const char *sys) { gboolean send_ok = TRUE; IPC_Channel *client_channel; crm_debug_4("relaying msg to sub_sys=%s via IPC", sys); client_channel = (IPC_Channel*)g_hash_table_lookup(ipc_clients, sys); - if(cl_get_string(msg, F_CRM_HOST_FROM) == NULL) { - ha_msg_add(msg, F_CRM_HOST_FROM, fsa_our_uname); + if(crm_element_value(msg, F_CRM_HOST_FROM) == NULL) { + crm_xml_add(msg, F_CRM_HOST_FROM, fsa_our_uname); } if (client_channel != NULL) { crm_debug_3("Sending message via channel %s.", sys); send_ok = send_ipc_message(client_channel, msg); } else if(sys != NULL && strcasecmp(sys, CRM_SYSTEM_CIB) == 0) { crm_err("Sub-system (%s) has been incorporated into the CRMd.", sys); crm_err("Change the way we handle this CIB message"); - crm_log_message(LOG_ERR, msg); + crm_log_xml(LOG_ERR, "cib op", msg); send_ok = FALSE; } else if(sys != NULL && strcasecmp(sys, CRM_SYSTEM_LRMD) == 0) { fsa_data_t *fsa_data = NULL; ha_msg_input_t *msg_copy = new_ha_msg_input(msg); crm_malloc0(fsa_data, sizeof(fsa_data_t)); fsa_data->fsa_input = I_MESSAGE; fsa_data->fsa_cause = C_IPC_MESSAGE; fsa_data->data = msg_copy; fsa_data->origin = __FUNCTION__; fsa_data->data_type = fsa_dt_ha_msg; #ifdef FSA_TRACE crm_debug_2("Invoking action %s (%.16llx)", fsa_action2string(A_LRM_INVOKE), A_LRM_INVOKE); #endif do_lrm_invoke(A_LRM_INVOKE, C_IPC_MESSAGE, fsa_state, I_MESSAGE, fsa_data); delete_ha_msg_input(msg_copy); crm_free(fsa_data); } else { crm_err("Unknown Sub-system (%s)... discarding message.", crm_str(sys)); send_ok = FALSE; } - crm_msg_del(msg); + free_xml(msg); return send_ok; } void msg_queue_helper(void) { #if SUPPORT_HEARTBEAT IPC_Channel *ipc = NULL; if(fsa_cluster_conn != NULL) { ipc = fsa_cluster_conn->llc_ops->ipcchan( fsa_cluster_conn); } if(ipc != NULL) { ipc->ops->resume_io(ipc); } /* g_hash_table_foreach_remove(ipc_clients, ipc_queue_helper, NULL); */ #endif } gboolean ipc_queue_helper(gpointer key, gpointer value, gpointer user_data) { crmd_client_t *ipc_client = value; if(ipc_client->client_channel != NULL) { ipc_client->client_channel->ops->is_message_pending(ipc_client->client_channel); } return FALSE; } diff --git a/crmd/misc.c b/crmd/misc.c index 82b1553a60..ec741857fc 100644 --- a/crmd/misc.c +++ b/crmd/misc.c @@ -1,75 +1,75 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include /* A_LOG, A_WARN, A_ERROR */ void do_log(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) { unsigned log_type = LOG_DEBUG_3; if(action & A_LOG) { log_type = LOG_DEBUG_2; } else if(action & A_WARN) { log_type = LOG_WARNING; } else if(action & A_ERROR) { log_type = LOG_ERR; } do_crm_log(log_type, "[[FSA]] Input %s from %s() received in state (%s)", fsa_input2string(msg_data->fsa_input), msg_data->origin, fsa_state2string(cur_state)); if(msg_data->data_type == fsa_dt_ha_msg) { ha_msg_input_t *input = fsa_typed_data(msg_data->data_type); if(log_type > LOG_DEBUG) { - crm_log_message(log_type, input->msg); + crm_log_xml(log_type, "input", input->msg); } } else if(msg_data->data_type == fsa_dt_xml) { - crm_data_t *input = fsa_typed_data(msg_data->data_type); + xmlNode *input = fsa_typed_data(msg_data->data_type); if(crm_log_level >= log_type) { print_xml_formatted( log_type, __FUNCTION__, input, NULL); } } else if(msg_data->data_type == fsa_dt_lrm) { lrm_op_t *input = fsa_typed_data(msg_data->data_type); do_crm_log(log_type, "Resource %s: Call ID %d returned %d (%d)." " New status if rc=0: %s", input->rsc_id, input->call_id, input->rc, input->op_status, (char*)input->user_data); } } diff --git a/crmd/pengine.c b/crmd/pengine.c index 3201d66bfa..d55fa3e337 100644 --- a/crmd/pengine.c +++ b/crmd/pengine.c @@ -1,185 +1,185 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include /* for access */ #include #include #include #include /* for calls to open */ #include /* for calls to open */ #include /* for calls to open */ #include /* for getpwuid */ #include /* for initgroups */ #include /* for getrlimit */ #include /* for getrlimit */ #include #include #include #include #include #include #include #include #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); +void do_pe_invoke_callback(xmlNode *msg, int call_id, int rc, + xmlNode *output, void *user_data); /* A_PE_START, A_PE_STOP, A_TE_RESTART */ void 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) { 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) { stop_subsystem(this_subsys, FALSE); } 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); } } } int fsa_pe_query = 0; char *fsa_pe_ref = NULL; /* A_PE_INVOKE */ void 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) { if(is_set(fsa_input_register, R_PE_CONNECTED) == FALSE){ crm_info("Waiting for the PE to connect"); crmd_fsa_stall(NULL); return; } 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; } crm_debug("Requesting the current CIB: %s",fsa_state2string(fsa_state)); fsa_pe_query = fsa_cib_conn->cmds->query( fsa_cib_conn, NULL, NULL, cib_scope_local); if(FALSE == add_cib_op_callback( fsa_pe_query, 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); } } void -do_pe_invoke_callback(const HA_Message *msg, int call_id, int rc, - crm_data_t *output, void *user_data) +do_pe_invoke_callback(xmlNode *msg, int call_id, int rc, + xmlNode *output, void *user_data) { - HA_Message *cmd = NULL; - crm_data_t *local_cib = NULL; + xmlNode *cmd = NULL; + xmlNode *local_cib = NULL; #if CRM_DEPRECATED_SINCE_2_0_4 if(safe_str_eq(crm_element_name(output), XML_TAG_CIB)) { local_cib = output; } else { local_cib = find_xml_node(output, XML_TAG_CIB, TRUE); } #else local_cib = output; #endif if(call_id != fsa_pe_query) { crm_debug_2("Skipping superceeded CIB query: %d (current=%d)", call_id, fsa_pe_query); return; } else if(AM_I_DC == FALSE || is_set(fsa_input_register, R_PE_CONNECTED) == FALSE) { crm_debug("No need to invoke the PE anymore"); return; } else if(need_transition(fsa_state) == FALSE) { crm_debug("Discarding PE request in state: %s", fsa_state2string(fsa_state)); return; } else if(last_peer_update != 0) { crm_debug("Re-asking for the CIB: peer update %d still pending", last_peer_update); mssleep(500); register_fsa_action(A_PE_INVOKE); return; } else if(fsa_state != S_POLICY_ENGINE) { crm_err("Invoking PE in state: %s", fsa_state2string(fsa_state)); } CRM_DEV_ASSERT(local_cib != NULL); CRM_DEV_ASSERT(crm_element_value(local_cib, XML_ATTR_DC_UUID) != NULL); crm_xml_add_int(local_cib, XML_ATTR_HAVE_QUORUM, fsa_has_quorum); crm_xml_add_int(local_cib, XML_ATTR_CCM_TRANSITION, crm_peer_seq); 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: ref=%s, seq=%llu, quorate=%d", fsa_pe_ref, crm_peer_seq, fsa_has_quorum); } diff --git a/crmd/tengine.c b/crmd/tengine.c index 351a45bea9..99be19cb12 100644 --- a/crmd/tengine.c +++ b/crmd/tengine.c @@ -1,172 +1,172 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include /* for access */ #include #include #include /* for calls to open */ #include /* for calls to open */ #include /* for calls to open */ #include /* for getpwuid */ #include /* for initgroups */ #include /* for getrlimit */ #include /* for getrlimit */ #include #include #include #include #include #include #include struct crm_subsystem_s *te_subsystem = NULL; /* A_TE_START, A_TE_STOP, A_TE_RESTART */ void do_te_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) { struct crm_subsystem_s *this_subsys = te_subsystem; long long stop_actions = A_TE_STOP; long long start_actions = A_TE_START; /* if(action & stop_actions && cur_state != S_STOPPING */ /* && is_set(fsa_input_register, R_TE_PEND)) { */ /* result = I_WAIT_FOR_EVENT; */ /* return result; */ /* } */ if(action & stop_actions) { stop_subsystem(this_subsys, FALSE); } 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); } } } /* A_TE_INVOKE, A_TE_CANCEL */ void do_te_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) { - HA_Message *cmd = NULL; + xmlNode *cmd = NULL; if(AM_I_DC == FALSE) { crm_debug("Not DC: No need to invoke the TE (anymore): %s", fsa_action2string(action)); return; } else if(fsa_state != S_TRANSITION_ENGINE && (action & A_TE_INVOKE)) { crm_debug("No need to invoke the TE (%s) in state %s", fsa_action2string(action), fsa_state2string(fsa_state)); return; } else if(!is_set(fsa_input_register, te_subsystem->flag_required)) { crm_err("Ignoring action %s in state: %s" " - We dont want the TE anymore", fsa_action2string(action), fsa_state2string(cur_state)); return; } else if(is_set(fsa_input_register, R_TE_CONNECTED) == FALSE) { crm_info("Waiting for the TE to connect before action %s", fsa_action2string(action)); if(action & A_TE_INVOKE) { register_fsa_input( msg_data->fsa_cause, msg_data->fsa_input, msg_data->data); } crmd_fsa_stall(NULL); return; } if(action & A_TE_INVOKE) { ha_msg_input_t *input = fsa_typed_data(fsa_dt_ha_msg); - const char *graph_file = cl_get_string(input->msg, F_CRM_TGRAPH); - const char *graph_input = cl_get_string(input->msg, F_CRM_TGRAPH_INPUT); + const char *graph_file = crm_element_value(input->msg, F_CRM_TGRAPH); + const char *graph_input = crm_element_value(input->msg, F_CRM_TGRAPH_INPUT); if(graph_file != NULL || input->xml != NULL) { crm_debug("Starting a transition"); set_bit_inplace(fsa_input_register, R_IN_TRANSITION); cmd = create_request( CRM_OP_TRANSITION, input->xml, NULL, CRM_SYSTEM_TENGINE, CRM_SYSTEM_DC, NULL); - ha_msg_add(cmd, F_CRM_TGRAPH_INPUT, graph_input); + crm_xml_add(cmd, F_CRM_TGRAPH_INPUT, graph_input); if(graph_file) { - ha_msg_add(cmd, F_CRM_TGRAPH, graph_file); + crm_xml_add(cmd, F_CRM_TGRAPH, graph_file); } send_request(cmd, NULL); } else { register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL); } } else if(action & A_TE_CANCEL) { crm_debug("Cancelling the active Transition"); cmd = create_request( CRM_OP_TEABORT, NULL, NULL, CRM_SYSTEM_TENGINE, CRM_SYSTEM_DC, NULL); send_request(cmd, NULL); } else if(action & A_TE_HALT) { cmd = create_request( CRM_OP_TE_HALT, NULL, NULL, CRM_SYSTEM_TENGINE, CRM_SYSTEM_DC, NULL); send_request(cmd, NULL); } } diff --git a/crmd/utils.c b/crmd/utils.c index 732878be4c..a939951a11 100644 --- a/crmd/utils.c +++ b/crmd/utils.c @@ -1,1209 +1,1209 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* A_DC_TIMER_STOP, A_DC_TIMER_START, * A_FINALIZE_TIMER_STOP, A_FINALIZE_TIMER_START * A_INTEGRATE_TIMER_STOP, A_INTEGRATE_TIMER_START */ void 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; 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 */ register_fsa_input(cause, I_ELECTION, NULL); } } 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); */ } } static const char * get_timer_desc(fsa_timer_t *timer) { if(timer == election_trigger) { return "Election Trigger"; } else if(timer == election_timeout) { return "Election Timeout"; } else if(timer == shutdown_escalation_timer) { return "Shutdown Escalation"; } else if(timer == integration_timer) { return "Integration Timer"; } else if(timer == finalization_timer) { return "Finalization Timer"; } else if(timer == wait_timer) { return "Wait Timer"; } else if(timer == recheck_timer) { return "PEngine Recheck Timer"; } return "Unknown Timer"; } gboolean crm_timer_popped(gpointer data) { fsa_timer_t *timer = (fsa_timer_t *)data; if(timer == wait_timer || timer == recheck_timer || timer == finalization_timer || timer == election_trigger) { crm_info("%s (%s) just popped!", get_timer_desc(timer), fsa_input2string(timer->fsa_input)); } else { crm_err("%s (%s) just popped!", get_timer_desc(timer), 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_PE_CALC && fsa_state != S_IDLE) { crm_debug("Discarding %s event in state: %s", fsa_input2string(timer->fsa_input), fsa_state2string(fsa_state)); } else if(timer->fsa_input == I_FINALIZED && fsa_state != S_FINALIZE_JOIN) { crm_debug("Discarding %s event in state: %s", fsa_input2string(timer->fsa_input), fsa_state2string(fsa_state)); } else if(timer->fsa_input != I_NULL) { register_fsa_input(C_TIMER_POPPED, timer->fsa_input, NULL); } crm_debug_3("Triggering FSA: %s", __FUNCTION__); G_main_set_trigger(fsa_source); return TRUE; } gboolean crm_timer_start(fsa_timer_t *timer) { const char *timer_desc = get_timer_desc(timer); if(timer->source_id == 0 && timer->period_ms > 0) { timer->source_id = Gmain_timeout_add( timer->period_ms, timer->callback, (void*)timer); CRM_ASSERT(timer->source_id != 0); 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 = get_timer_desc(timer); if(timer == NULL) { crm_err("Attempted to stop NULL timer"); return FALSE; } else if(timer->source_id != 0) { crm_debug("Stopping %s (%s:%dms), src=%d", timer_desc, fsa_input2string(timer->fsa_input), timer->period_ms, timer->source_id); Gmain_timeout_remove(timer->source_id); timer->source_id = 0; } else { crm_debug_2("%s (%s:%dms) already stopped", timer_desc, fsa_input2string(timer->fsa_input), timer->period_ms); return FALSE; } return TRUE; } const char * fsa_input2string(enum crmd_fsa_input input) { const char *inputAsText = NULL; switch(input){ case I_NULL: inputAsText = "I_NULL"; 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 = ""; } 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 = ""; } 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 = ""; } 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_ELECTION_CHECK: actionAsText = "A_ELECTION_CHECK"; 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_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_HALT: actionAsText = "A_TE_HALT"; 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 = ""; } 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, "%s %.16llx (R_THE_DC)", text, R_THE_DC); } if(is_set(input_register, R_STARTING)) { do_crm_log(log_level, "%s %.16llx (R_STARTING)", text, R_STARTING); } if(is_set(input_register, R_SHUTDOWN)) { do_crm_log(log_level, "%s %.16llx (R_SHUTDOWN)", text, R_SHUTDOWN); } if(is_set(input_register, R_STAYDOWN)) { do_crm_log(log_level, "%s %.16llx (R_STAYDOWN)", text, R_STAYDOWN); } if(is_set(input_register, R_JOIN_OK)) { do_crm_log(log_level, "%s %.16llx (R_JOIN_OK)", text, R_JOIN_OK); } if(is_set(input_register, R_READ_CONFIG)) { do_crm_log(log_level, "%s %.16llx (R_READ_CONFIG)", text, R_READ_CONFIG); } if(is_set(input_register, R_INVOKE_PE)) { do_crm_log(log_level, "%s %.16llx (R_INVOKE_PE)", text, R_INVOKE_PE); } if(is_set(input_register, R_CIB_CONNECTED)) { do_crm_log(log_level, "%s %.16llx (R_CIB_CONNECTED)", text, R_CIB_CONNECTED); } if(is_set(input_register, R_PE_CONNECTED)) { do_crm_log(log_level, "%s %.16llx (R_PE_CONNECTED)", text, R_PE_CONNECTED); } if(is_set(input_register, R_TE_CONNECTED)) { do_crm_log(log_level, "%s %.16llx (R_TE_CONNECTED)", text, R_TE_CONNECTED); } if(is_set(input_register, R_LRM_CONNECTED)) { do_crm_log(log_level, "%s %.16llx (R_LRM_CONNECTED)", text, R_LRM_CONNECTED); } if(is_set(input_register, R_CIB_REQUIRED)) { do_crm_log(log_level, "%s %.16llx (R_CIB_REQUIRED)", text, R_CIB_REQUIRED); } if(is_set(input_register, R_PE_REQUIRED)) { do_crm_log(log_level, "%s %.16llx (R_PE_REQUIRED)", text, R_PE_REQUIRED); } if(is_set(input_register, R_TE_REQUIRED)) { do_crm_log(log_level, "%s %.16llx (R_TE_REQUIRED)", text, R_TE_REQUIRED); } if(is_set(input_register, R_REQ_PEND)) { do_crm_log(log_level, "%s %.16llx (R_REQ_PEND)", text, R_REQ_PEND); } if(is_set(input_register, R_PE_PEND)) { do_crm_log(log_level, "%s %.16llx (R_PE_PEND)", text, R_PE_PEND); } if(is_set(input_register, R_TE_PEND)) { do_crm_log(log_level, "%s %.16llx (R_TE_PEND)", text, R_TE_PEND); } if(is_set(input_register, R_RESP_PEND)) { do_crm_log(log_level, "%s %.16llx (R_RESP_PEND)", text, R_RESP_PEND); } if(is_set(input_register, R_CIB_DONE)) { do_crm_log(log_level, "%s %.16llx (R_CIB_DONE)", text, R_CIB_DONE); } if(is_set(input_register, R_HAVE_CIB)) { do_crm_log(log_level, "%s %.16llx (R_HAVE_CIB)", text, R_HAVE_CIB); } if(is_set(input_register, R_CIB_ASKED)) { do_crm_log(log_level, "%s %.16llx (R_CIB_ASKED)", text, R_CIB_ASKED); } if(is_set(input_register, R_CCM_DATA)) { do_crm_log(log_level, "%s %.16llx (R_CCM_DATA)", text, R_CCM_DATA); } if(is_set(input_register, R_PEER_DATA)) { do_crm_log(log_level, "%s %.16llx (R_PEER_DATA)", text, R_PEER_DATA); } if(is_set(input_register, R_IN_RECOVERY)) { do_crm_log(log_level, "%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, "Action %.16llx (A_READCONFIG) %s", A_READCONFIG, text); } if(is_set(action, A_STARTUP)) { do_crm_log(log_level, "Action %.16llx (A_STARTUP) %s", A_STARTUP, text); } if(is_set(action, A_STARTED)) { do_crm_log(log_level, "Action %.16llx (A_STARTED) %s", A_STARTED, text); } if(is_set(action, A_HA_CONNECT)) { do_crm_log(log_level, "Action %.16llx (A_CONNECT) %s", A_HA_CONNECT, text); } if(is_set(action, A_HA_DISCONNECT)) { do_crm_log(log_level, "Action %.16llx (A_DISCONNECT) %s", A_HA_DISCONNECT, text); } if(is_set(action, A_LRM_CONNECT)) { do_crm_log(log_level, "Action %.16llx (A_LRM_CONNECT) %s", A_LRM_CONNECT, text); } if(is_set(action, A_LRM_EVENT)) { do_crm_log(log_level, "Action %.16llx (A_LRM_EVENT) %s", A_LRM_EVENT, text); } if(is_set(action, A_LRM_INVOKE)) { do_crm_log(log_level, "Action %.16llx (A_LRM_INVOKE) %s", A_LRM_INVOKE, text); } if(is_set(action, A_LRM_DISCONNECT)) { do_crm_log(log_level, "Action %.16llx (A_LRM_DISCONNECT) %s", A_LRM_DISCONNECT, text); } if(is_set(action, A_DC_TIMER_STOP)) { do_crm_log(log_level, "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, "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, "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, "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, "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, "Action %.16llx (A_FINALIZE_TIMER_STOP) %s", A_FINALIZE_TIMER_STOP, text); } if(is_set(action, A_ELECTION_COUNT)) { do_crm_log(log_level, "Action %.16llx (A_ELECTION_COUNT) %s", A_ELECTION_COUNT, text); } if(is_set(action, A_ELECTION_VOTE)) { do_crm_log(log_level, "Action %.16llx (A_ELECTION_VOTE) %s", A_ELECTION_VOTE, text); } if(is_set(action, A_ELECTION_CHECK)) { do_crm_log(log_level, "Action %.16llx (A_ELECTION_CHECK) %s", A_ELECTION_CHECK, text); } if(is_set(action, A_CL_JOIN_ANNOUNCE)) { do_crm_log(log_level, "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, "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, "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, "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, "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, "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, "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, "Action %.16llx (A_DC_JOIN_FINALIZE) %s", A_DC_JOIN_FINALIZE, text); } if(is_set(action, A_MSG_PROCESS)) { do_crm_log(log_level, "Action %.16llx (A_MSG_PROCESS) %s", A_MSG_PROCESS, text); } if(is_set(action, A_MSG_ROUTE)) { do_crm_log(log_level, "Action %.16llx (A_MSG_ROUTE) %s", A_MSG_ROUTE, text); } if(is_set(action, A_RECOVER)) { do_crm_log(log_level, "Action %.16llx (A_RECOVER) %s", A_RECOVER, text); } if(is_set(action, A_DC_RELEASE)) { do_crm_log(log_level, "Action %.16llx (A_DC_RELEASE) %s", A_DC_RELEASE, text); } if(is_set(action, A_DC_RELEASED)) { do_crm_log(log_level, "Action %.16llx (A_DC_RELEASED) %s", A_DC_RELEASED, text); } if(is_set(action, A_DC_TAKEOVER)) { do_crm_log(log_level, "Action %.16llx (A_DC_TAKEOVER) %s", A_DC_TAKEOVER, text); } if(is_set(action, A_SHUTDOWN)) { do_crm_log(log_level, "Action %.16llx (A_SHUTDOWN) %s", A_SHUTDOWN, text); } if(is_set(action, A_SHUTDOWN_REQ)) { do_crm_log(log_level, "Action %.16llx (A_SHUTDOWN_REQ) %s", A_SHUTDOWN_REQ, text); } if(is_set(action, A_STOP)) { do_crm_log(log_level, "Action %.16llx (A_STOP ) %s", A_STOP , text); } if(is_set(action, A_EXIT_0)) { do_crm_log(log_level, "Action %.16llx (A_EXIT_0) %s", A_EXIT_0, text); } if(is_set(action, A_EXIT_1)) { do_crm_log(log_level, "Action %.16llx (A_EXIT_1) %s", A_EXIT_1, text); } if(is_set(action, A_CCM_CONNECT)) { do_crm_log(log_level, "Action %.16llx (A_CCM_CONNECT) %s", A_CCM_CONNECT, text); } if(is_set(action, A_CCM_DISCONNECT)) { do_crm_log(log_level, "Action %.16llx (A_CCM_DISCONNECT) %s", A_CCM_DISCONNECT, text); } if(is_set(action, A_CIB_BUMPGEN)) { do_crm_log(log_level, "Action %.16llx (A_CIB_BUMPGEN) %s", A_CIB_BUMPGEN, text); } if(is_set(action, A_CIB_INVOKE)) { do_crm_log(log_level, "Action %.16llx (A_CIB_INVOKE) %s", A_CIB_INVOKE, text); } if(is_set(action, A_CIB_START)) { do_crm_log(log_level, "Action %.16llx (A_CIB_START) %s", A_CIB_START, text); } if(is_set(action, A_CIB_STOP)) { do_crm_log(log_level, "Action %.16llx (A_CIB_STOP) %s", A_CIB_STOP, text); } if(is_set(action, A_TE_INVOKE)) { do_crm_log(log_level, "Action %.16llx (A_TE_INVOKE) %s", A_TE_INVOKE, text); } if(is_set(action, A_TE_START)) { do_crm_log(log_level, "Action %.16llx (A_TE_START) %s", A_TE_START, text); } if(is_set(action, A_TE_STOP)) { do_crm_log(log_level, "Action %.16llx (A_TE_STOP) %s", A_TE_STOP, text); } if(is_set(action, A_TE_CANCEL)) { do_crm_log(log_level, "Action %.16llx (A_TE_CANCEL) %s", A_TE_CANCEL, text); } if(is_set(action, A_PE_INVOKE)) { do_crm_log(log_level, "Action %.16llx (A_PE_INVOKE) %s", A_PE_INVOKE, text); } if(is_set(action, A_PE_START)) { do_crm_log(log_level, "Action %.16llx (A_PE_START) %s", A_PE_START, text); } if(is_set(action, A_PE_STOP)) { do_crm_log(log_level, "Action %.16llx (A_PE_STOP) %s", A_PE_STOP, text); } if(is_set(action, A_NODE_BLOCK)) { do_crm_log(log_level, "Action %.16llx (A_NODE_BLOCK) %s", A_NODE_BLOCK, text); } if(is_set(action, A_UPDATE_NODESTATUS)) { do_crm_log(log_level, "Action %.16llx (A_UPDATE_NODESTATUS) %s", A_UPDATE_NODESTATUS, text); } if(is_set(action, A_LOG)) { do_crm_log(log_level, "Action %.16llx (A_LOG ) %s", A_LOG, text); } if(is_set(action, A_ERROR)) { do_crm_log(log_level, "Action %.16llx (A_ERROR ) %s", A_ERROR, text); } if(is_set(action, A_WARN)) { do_crm_log(log_level, "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); + xmlNode *tmp1 = create_xml_node(NULL, XML_CIB_TAG_NODE); crm_debug_3("Creating node entry for %s", uname); set_uuid(tmp1, XML_ATTR_UUID, uname); crm_xml_add(tmp1, XML_ATTR_UNAME, uname); crm_xml_add(tmp1, XML_ATTR_TYPE, type); fsa_cib_anon_update(XML_CIB_TAG_NODES, tmp1, cib_scope_local|cib_quorum_override); free_xml(tmp1); } -crm_data_t* +xmlNode* create_node_state( const char *uname, const char *ha_state, const char *ccm_state, const char *crmd_state, const char *join_state, const char *exp_state, gboolean clear_shutdown, const char *src) { - crm_data_t *node_state = create_xml_node(NULL, XML_CIB_TAG_STATE); + xmlNode *node_state = create_xml_node(NULL, XML_CIB_TAG_STATE); crm_debug_2("%s Creating node state entry for %s", src, uname); set_uuid(node_state, XML_ATTR_UUID, uname); if(crm_element_value(node_state, XML_ATTR_UUID) == NULL) { crm_debug("Node %s is not a cluster member", uname); free_xml(node_state); return NULL; } 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, XML_ATTR_ORIGIN, src); if(clear_shutdown) { crm_xml_add(node_state, XML_CIB_ATTR_SHUTDOWN, "0"); #if CRM_DEPRECATED_SINCE_2_0_3 crm_xml_add(node_state, "clear_shutdown", "true"); #endif /* crm_xml_add(node_state, */ /* XML_CIB_ATTR_REPLACE, XML_TAG_TRANSIENT_NODEATTRS); */ } 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_CHECK(curr_client != NULL, return); crm_debug_2("received HUP from %s", curr_client->table_key); if (curr_client->sub_sys == NULL) { crm_debug_2("Client hadn't registered with us yet"); } else if (strcasecmp(CRM_SYSTEM_PENGINE, curr_client->sub_sys) == 0) { the_subsystem = pe_subsystem; } else if (strcasecmp(CRM_SYSTEM_TENGINE, curr_client->sub_sys) == 0) { the_subsystem = te_subsystem; } else if (strcasecmp(CRM_SYSTEM_CIB, curr_client->sub_sys) == 0){ the_subsystem = cib_subsystem; } if(the_subsystem != NULL) { the_subsystem->ipc = NULL; the_subsystem->client = NULL; crm_info("Received HUP from %s:[%d]", the_subsystem->name, the_subsystem->pid); } else { /* else that was a transient client */ crm_debug_2("Received HUP from transient client"); } if (curr_client->table_key != NULL) { /* * Key is destroyed below as: * curr_client->table_key * Value is cleaned up by: * crmd_ipc_connection_destroy * which will also call: * G_main_del_IPC_Channel */ g_hash_table_remove(ipc_clients, curr_client->table_key); } } -void update_dc(HA_Message *msg, gboolean assert_same) +void update_dc(xmlNode *msg, gboolean assert_same) { char *last_dc = fsa_our_dc; const char *dc_version = NULL; const char *welcome_from = NULL; if(msg != NULL) { - dc_version = cl_get_string(msg, F_CRM_VERSION); - welcome_from = cl_get_string(msg, F_CRM_HOST_FROM); + dc_version = crm_element_value(msg, F_CRM_VERSION); + welcome_from = crm_element_value(msg, F_CRM_HOST_FROM); CRM_CHECK(dc_version != NULL, return); CRM_CHECK(welcome_from != NULL, return); if(AM_I_DC && safe_str_neq(welcome_from, fsa_our_uname)) { crm_warn("Not updating DC to %s (%s): we are also a DC", welcome_from, dc_version); return; } if(assert_same) { CRM_CHECK(fsa_our_dc != NULL, ;); CRM_CHECK(safe_str_eq(fsa_our_dc, welcome_from), ;); } } crm_free(fsa_our_dc_version); fsa_our_dc_version = NULL; fsa_our_dc = NULL; if(welcome_from != NULL) { fsa_our_dc = crm_strdup(welcome_from); } if(dc_version != NULL) { fsa_our_dc_version = crm_strdup(dc_version); } if(fsa_our_dc != NULL) { crm_info("Set DC to %s (%s)", crm_str(fsa_our_dc), crm_str(fsa_our_dc_version)); } else if(last_dc != NULL) { crm_info("Unset DC %s", crm_str(last_dc)); } crm_free(last_dc); } diff --git a/include/crm/cib.h b/include/crm/cib.h index e87ddc16ab..75f635ed32 100644 --- a/include/crm/cib.h +++ b/include/crm/cib.h @@ -1,413 +1,412 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 CIB__H #define CIB__H #include #include #include #include #define CIB_FEATURE_SET "2.0" #define USE_PESKY_FRAGMENTS 1 /* use compare_version() for doing comparisons */ enum cib_variant { cib_native, cib_database, cib_edir }; enum cib_state { cib_connected_command, cib_connected_query, cib_disconnected }; enum cib_conn_type { cib_command, cib_query, cib_query_synchronous, cib_command_synchronous, cib_no_connection }; enum cib_call_options { cib_none = 0x00000000, cib_verbose = 0x00000001, cib_discard_reply = 0x00000010, cib_scope_local = 0x00000100, cib_sync_call = 0x00001000, cib_inhibit_notify = 0x00010000, cib_quorum_override = 0x00100000, cib_inhibit_bcast = 0x01000000, cib_force_diff = 0x10000000 }; #define cib_default_options = cib_none enum cib_errors { cib_ok = 0, cib_operation = -1, cib_create_msg = -2, cib_not_connected = -3, cib_not_authorized = -4, cib_send_failed = -5, cib_reply_failed = -6, cib_return_code = -7, cib_output_ptr = -8, cib_output_data = -9, cib_connection = -10, cib_authentication = -11, cib_missing = -12, cib_variant = -28, CIBRES_MISSING_ID = -13, CIBRES_MISSING_TYPE = -14, CIBRES_MISSING_FIELD = -15, CIBRES_OBJTYPE_MISMATCH = -16, CIBRES_CORRUPT = -17, CIBRES_OTHER = -18, cib_unknown = -19, cib_STALE = -20, cib_EXISTS = -21, cib_NOTEXISTS = -22, cib_ACTIVATION = -23, cib_NOSECTION = -24, cib_NOOBJECT = -25, cib_NOPARENT = -26, cib_NODECOPY = -27, cib_NOTSUPPORTED = -29, cib_registration_msg = -30, cib_callback_token = -31, cib_callback_register = -32, cib_msg_field_add = -33, cib_client_gone = -34, cib_not_master = -35, cib_client_corrupt = -36, cib_master_timeout = -37, cib_revision_unsupported= -38, cib_revision_unknown = -39, cib_missing_data = -40, cib_remote_timeout = -41, cib_no_quorum = -42, cib_diff_failed = -43, cib_diff_resync = -44, cib_old_data = -45, cib_id_check = -46, cib_dtd_validation = -47, cib_bad_section = -48, cib_bad_digest = -49, cib_bad_permissions = -50, cib_bad_config = -51, cib_invalid_argument = -52 }; enum cib_update_op { CIB_UPDATE_OP_NONE = 0, CIB_UPDATE_OP_ADD, CIB_UPDATE_OP_MODIFY, CIB_UPDATE_OP_DELETE, CIB_UPDATE_OP_MAX }; enum cib_section { cib_section_none, cib_section_all, cib_section_nodes, cib_section_constraints, cib_section_resources, cib_section_crmconfig, cib_section_status }; #define CIB_OP_SLAVE "cib_slave" #define CIB_OP_SLAVEALL "cib_slave_all" #define CIB_OP_MASTER "cib_master" #define CIB_OP_SYNC "cib_sync" #define CIB_OP_SYNC_ONE "cib_sync_one" #define CIB_OP_ISMASTER "cib_ismaster" #define CIB_OP_BUMP "cib_bump" #define CIB_OP_QUERY "cib_query" #define CIB_OP_CREATE "cib_create" #define CIB_OP_UPDATE "cib_update" #define CIB_OP_MODIFY "cib_modify" #define CIB_OP_DELETE "cib_delete" #define CIB_OP_DELETE_ALT "cib_delete_alt" #define CIB_OP_ERASE "cib_erase" #define CIB_OP_REPLACE "cib_replace" #define CIB_OP_NOTIFY "cib_notify" #define CIB_OP_APPLY_DIFF "cib_apply_diff" #define F_CIB_CLIENTID "cib_clientid" #define F_CIB_CALLOPTS "cib_callopt" #define F_CIB_CALLID "cib_callid" #define F_CIB_CALLDATA "cib_calldata" #define F_CIB_OPERATION "cib_op" #define F_CIB_ISREPLY "cib_isreplyto" #define F_CIB_SECTION "cib_section" #define F_CIB_HOST "cib_host" #define F_CIB_RC "cib_rc" #define F_CIB_DELEGATED "cib_delegated_from" #define F_CIB_OBJID "cib_object" #define F_CIB_OBJTYPE "cib_object_type" #define F_CIB_EXISTING "cib_existing_object" #define F_CIB_SEENCOUNT "cib_seen" #define F_CIB_TIMEOUT "cib_timeout" #define F_CIB_UPDATE "cib_update" #define F_CIB_CALLBACK_TOKEN "cib_callback_token" #define F_CIB_GLOBAL_UPDATE "cib_update" #define F_CIB_UPDATE_RESULT "cib_update_result" #define F_CIB_CLIENTNAME "cib_clientname" #define F_CIB_NOTIFY_TYPE "cib_notify_type" #define F_CIB_NOTIFY_ACTIVATE "cib_notify_activate" #define F_CIB_UPDATE_DIFF "cib_update_diff" #define T_CIB "cib" #define T_CIB_NOTIFY "cib_notify" /* notify sub-types */ #define T_CIB_PRE_NOTIFY "cib_pre_notify" #define T_CIB_POST_NOTIFY "cib_post_notify" #define T_CIB_UPDATE_CONFIRM "cib_update_confirmation" #define T_CIB_DIFF_NOTIFY "cib_diff_notify" #define T_CIB_REPLACE_NOTIFY "cib_refresh_notify" #define cib_channel_ro "cib_ro" #define cib_channel_rw "cib_rw" #define cib_channel_callback "cib_callback" #define cib_channel_ro_synchronous "cib_ro_syncronous" #define cib_channel_rw_synchronous "cib_rw_syncronous" typedef struct cib_s cib_t; typedef struct cib_api_operations_s { int (*variant_op)( cib_t *cib, const char *op, const char *host, - const char *section, crm_data_t *data, - crm_data_t **output_data, int call_options); + const char *section, xmlNode *data, + xmlNode **output_data, int call_options); int (*signon) ( cib_t *cib, const char *name, enum cib_conn_type type); int (*signoff)(cib_t *cib); int (*free) (cib_t *cib); int (*set_op_callback)( cib_t *cib, void (*callback)( - const HA_Message *msg, int callid , - int rc, crm_data_t *output)); + const xmlNode *msg, int callid , + int rc, xmlNode *output)); int (*add_notify_callback)( cib_t *cib, const char *event, void (*callback)( - const char *event, HA_Message *msg)); + const char *event, xmlNode *msg)); int (*del_notify_callback)( cib_t *cib, const char *event, void (*callback)( - const char *event, HA_Message *msg)); + const char *event, xmlNode *msg)); int (*set_connection_dnotify)( cib_t *cib, void (*dnotify)(gpointer user_data)); IPC_Channel *(*channel)(cib_t* cib); int (*inputfd)(cib_t* cib); int (*noop)(cib_t *cib, int call_options); int (*ping)( - cib_t *cib, crm_data_t **output_data, int call_options); + cib_t *cib, xmlNode **output_data, int call_options); int (*query)(cib_t *cib, const char *section, - crm_data_t **output_data, int call_options); + xmlNode **output_data, int call_options); int (*query_from)( cib_t *cib, const char *host, const char *section, - crm_data_t **output_data, int call_options); + xmlNode **output_data, int call_options); int (*is_master) (cib_t *cib); int (*set_master)(cib_t *cib, int call_options); int (*set_slave) (cib_t *cib, int call_options); int (*set_slave_all)(cib_t *cib, int call_options); int (*sync)(cib_t *cib, const char *section, int call_options); int (*sync_from)( cib_t *cib, const char *host, const char *section, int call_options); int (*bump_epoch)(cib_t *cib, int call_options); - int (*create)(cib_t *cib, const char *section, crm_data_t *data, - crm_data_t **output_data, int call_options); - int (*modify)(cib_t *cib, const char *section, crm_data_t *data, - crm_data_t **output_data, int call_options); - int (*update)(cib_t *cib, const char *section, crm_data_t *data, - crm_data_t **output_data, int call_options); - int (*replace)(cib_t *cib, const char *section, crm_data_t *data, - crm_data_t **output_data, int call_options); - int (*delete)(cib_t *cib, const char *section, crm_data_t *data, - crm_data_t **output_data, int call_options); + int (*create)(cib_t *cib, const char *section, xmlNode *data, + xmlNode **output_data, int call_options); + int (*modify)(cib_t *cib, const char *section, xmlNode *data, + xmlNode **output_data, int call_options); + int (*update)(cib_t *cib, const char *section, xmlNode *data, + xmlNode **output_data, int call_options); + int (*replace)(cib_t *cib, const char *section, xmlNode *data, + xmlNode **output_data, int call_options); + int (*delete)(cib_t *cib, const char *section, xmlNode *data, + xmlNode **output_data, int call_options); int (*delete_absolute)( - cib_t *cib, const char *section, crm_data_t *data, - crm_data_t **output_data, int call_options); + cib_t *cib, const char *section, xmlNode *data, + xmlNode **output_data, int call_options); int (*erase)( - cib_t *cib, crm_data_t **output_data, int call_options); + cib_t *cib, xmlNode **output_data, int call_options); int (*quit)(cib_t *cib, int call_options); gboolean (*msgready)(cib_t* cib); int (*rcvmsg)(cib_t* cib, int blocking); gboolean (*dispatch)(IPC_Channel *channel, gpointer user_data); int (*register_callback)( cib_t* cib, const char *callback, int enabled); } cib_api_operations_t; struct cib_s { enum cib_state state; enum cib_conn_type type; int call_id; int call_timeout; void *variant_opaque; GList *notify_list; - void (*op_callback)(const HA_Message *msg, int call_id, - int rc, crm_data_t *output); + void (*op_callback)(const xmlNode *msg, int call_id, + int rc, xmlNode *output); cib_api_operations_t *cmds; }; typedef struct cib_notify_client_s { const char *event; const char *obj_id; /* implement one day */ const char *obj_type; /* implement one day */ void (*callback)( - const char *event, HA_Message *msg); + const char *event, xmlNode *msg); } cib_notify_client_t; struct timer_rec_s { int call_id; int timeout; guint ref; }; typedef struct cib_callback_client_s { - void (*callback)( - const HA_Message*, int, int, crm_data_t*, void*); + void (*callback)(xmlNode*, int, int, xmlNode*, void*); void *user_data; gboolean only_success; struct timer_rec_s *timer; } cib_callback_client_t; /* Core functions */ extern cib_t *cib_new(void); extern void cib_delete(cib_t *cib); extern gboolean startCib(const char *filename); -extern crm_data_t *get_cib_copy(cib_t *cib); -extern crm_data_t *cib_get_generation(cib_t *cib); -extern int cib_compare_generation(crm_data_t *left, crm_data_t *right); +extern xmlNode *get_cib_copy(cib_t *cib); +extern xmlNode *cib_get_generation(cib_t *cib); +extern int cib_compare_generation(xmlNode *left, xmlNode *right); extern gboolean add_cib_op_callback_timeout( int call_id, int timeout, gboolean only_success, void *user_data, - void (*callback)(const HA_Message*, int, int, crm_data_t*,void*)); + void (*callback)(xmlNode*, int, int, xmlNode*,void*)); extern gboolean add_cib_op_callback( int call_id, gboolean only_success, void *user_data, - void (*callback)(const HA_Message*, int, int, crm_data_t*,void*)); + void (*callback)(xmlNode*, int, int, xmlNode*,void*)); extern void remove_cib_op_callback(int call_id, gboolean all_callbacks); extern int num_cib_op_callbacks(void); /* Utility functions */ -extern crm_data_t *get_object_root(const char *object_type,crm_data_t *the_root); -extern crm_data_t *create_cib_fragment_adv( - crm_data_t *update, const char *section, const char *source); +extern xmlNode *get_object_root(const char *object_type,xmlNode *the_root); +extern xmlNode *create_cib_fragment_adv( + xmlNode *update, const char *section, const char *source); extern char *cib_pluralSection(const char *a_section); extern const char *get_crm_option( - crm_data_t *cib, const char *name, gboolean do_warn); + xmlNode *cib, const char *name, gboolean do_warn); /* Error Interpretation*/ extern const char *cib_error2string(enum cib_errors); extern const char *cib_op2string(enum cib_update_op); -extern crm_data_t *createEmptyCib(void); -extern gboolean verifyCibXml(crm_data_t *cib); +extern xmlNode *createEmptyCib(void); +extern gboolean verifyCibXml(xmlNode *cib); extern int cib_section2enum(const char *a_section); #define create_cib_fragment(update,cib_section) create_cib_fragment_adv(update, cib_section, __FUNCTION__) -extern gboolean cib_config_changed(crm_data_t *old_cib, crm_data_t *new_cib, crm_data_t **result); +extern gboolean cib_config_changed(xmlNode *old_cib, xmlNode *new_cib, xmlNode **result); -extern crm_data_t *diff_cib_object( - crm_data_t *old, crm_data_t *new,gboolean suppress); +extern xmlNode *diff_cib_object( + xmlNode *old, xmlNode *new,gboolean suppress); extern gboolean apply_cib_diff( - crm_data_t *old, crm_data_t *diff, crm_data_t **new); + xmlNode *old, xmlNode *diff, xmlNode **new); -extern void log_cib_diff(int log_level, crm_data_t *diff, const char *function); +extern void log_cib_diff(int log_level, xmlNode *diff, const char *function); extern gboolean cib_diff_version_details( - crm_data_t *diff, int *admin_epoch, int *epoch, int *updates, + xmlNode *diff, int *admin_epoch, int *epoch, int *updates, int *_admin_epoch, int *_epoch, int *_updates); extern gboolean cib_version_details( - crm_data_t *cib, int *admin_epoch, int *epoch, int *updates); + xmlNode *cib, int *admin_epoch, int *epoch, int *updates); extern enum cib_errors update_attr( cib_t *the_cib, int call_options, const char *section, const char *node_uuid, const char *set_name, const char *attr_id, const char *attr_name, const char *attr_value, gboolean to_console); extern enum cib_errors find_attr_details( - crm_data_t *xml_search, const char *node_uuid, + xmlNode *xml_search, const char *node_uuid, const char *set_name, const char *attr_id, const char *attr_name, - crm_data_t **xml_obj, gboolean to_console); + xmlNode **xml_obj, gboolean to_console); extern enum cib_errors read_attr( cib_t *the_cib, const char *section, const char *node_uuid, const char *set_name, const char *attr_id, const char *attr_name, char **attr_value, gboolean to_console); extern enum cib_errors delete_attr( cib_t *the_cib, int options, const char *section, const char *node_uuid, const char *set_name, const char *attr_id, const char *attr_name, const char *attr_value, gboolean to_console); extern enum cib_errors query_node_uuid( cib_t *the_cib, const char *uname, char **uuid); extern enum cib_errors query_node_uname( cib_t *the_cib, const char *uuid, char **uname); extern enum cib_errors query_standby(cib_t *the_cib, const char *uuid, char **scope, char **standby_value); extern enum cib_errors set_standby( cib_t *the_cib, const char *uuid, const char *scope, const char *standby_value); enum cib_errors delete_standby( cib_t *the_cib, const char *uuid, const char *scope, const char *standby_value); -extern const char *feature_set(crm_data_t *xml_obj); +extern const char *feature_set(xmlNode *xml_obj); #endif diff --git a/include/crm/common/cluster.h b/include/crm/common/cluster.h index 55f126bb5d..5b1d3e4eef 100644 --- a/include/crm/common/cluster.h +++ b/include/crm/common/cluster.h @@ -1,86 +1,86 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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_CLUSTER__H #define CRM_COMMON_CLUSTER__H #include #include #include #include #include extern gboolean crm_have_quorum; extern GHashTable *crm_peer_cache; extern unsigned long long crm_peer_seq; extern void crm_peer_init(void); extern void crm_peer_destroy(void); extern gboolean crm_cluster_connect( char **our_uname, char **our_uuid, void *dispatch, void *destroy, #if SUPPORT_HEARTBEAT ll_cluster_t **hb_conn #else void **unused #endif ); extern gboolean send_cluster_message( - const char *node, enum crm_ais_msg_types service, HA_Message *data, gboolean ordered); + const char *node, enum crm_ais_msg_types service, xmlNode *data, gboolean ordered); extern void destroy_crm_node(gpointer data); -extern crm_node_t *crm_update_ais_node(crm_data_t *member, long long seq); +extern crm_node_t *crm_update_ais_node(xmlNode *member, long long seq); extern void crm_update_peer_proc( const char *uname, uint32_t flag, const char *status); extern crm_node_t *crm_update_peer( unsigned int id, unsigned long long born, int32_t votes, uint32_t children, const char *uuid, const char *uname, const char *addr, const char *state); extern gboolean crm_is_member_active(const crm_node_t *node); extern guint crm_active_members(void); extern guint reap_crm_membership(void); extern guint crm_active_members(void); extern guint crm_active_peers(uint32_t peer); extern gboolean crm_calculate_quorum(void); #if SUPPORT_HEARTBEAT extern gboolean ccm_have_quorum(oc_ed_t event); extern const char *ccm_event_name(oc_ed_t event); extern crm_node_t *crm_update_ccm_node( const oc_ev_membership_t *oc, int offset, const char *state); #endif #if SUPPORT_AIS extern int ais_fd_sync; extern GFDSource *ais_source; extern gboolean send_ais_text( int class, const char *data, gboolean local, const char *node, enum crm_ais_msg_types dest); #endif extern void empty_uuid_cache(void); extern const char *get_uuid(const char *uname); extern const char *get_uname(const char *uuid); -extern void set_uuid(crm_data_t *node, const char *attr, const char *uname); +extern void set_uuid(xmlNode *node, const char *attr, const char *uname); extern void unget_uuid(const char *uname); enum crm_ais_msg_types text2msg_type(const char *text); #endif diff --git a/include/crm/common/ipc.h b/include/crm/common/ipc.h index 5dd115d1f9..8f3c8f6a0f 100644 --- a/include/crm/common/ipc.h +++ b/include/crm/common/ipc.h @@ -1,98 +1,98 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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_IPC__H #define CRM_COMMON_IPC__H #include #include #include #include typedef struct crmd_client_s { char *sub_sys; char *uuid; char *table_key; IPC_Channel *client_channel; GCHSource *client_source; } crmd_client_t; -extern gboolean send_ipc_message(IPC_Channel *ipc_client, HA_Message *msg); +extern gboolean send_ipc_message(IPC_Channel *ipc_client, xmlNode *msg); extern void default_ipc_connection_destroy(gpointer user_data); extern int init_server_ipc_comms( char *channel_name, gboolean (*channel_client_connect)( IPC_Channel *newclient, gpointer user_data), void (*channel_connection_destroy)(gpointer user_data)); extern GCHSource *init_client_ipc_comms( const char *channel_name, gboolean (*dispatch)( IPC_Channel* source_data, gpointer user_data), void *client_data, IPC_Channel **ch); extern IPC_Channel *init_client_ipc_comms_nodispatch(const char *channel_name); extern gboolean subsystem_msg_dispatch(IPC_Channel *sender, void *user_data); extern IPC_WaitConnection *wait_channel_init(char daemonsocket[]); extern gboolean is_ipc_empty(IPC_Channel *ch); -extern crm_data_t *createPingRequest(const char *crm_msg_reference, +extern xmlNode *createPingRequest(const char *crm_msg_reference, const char *to); -extern HA_Message *validate_crm_message(HA_Message *msg, +extern xmlNode *validate_crm_message(xmlNode *msg, const char *sys, const char *uuid, const char *msg_type); extern void send_hello_message(IPC_Channel *ipc_client, const char *uuid, const char *client_name, const char *major_version, const char *minor_version); #define create_reply(request, xml_response_data) create_reply_adv(request, xml_response_data, __FUNCTION__); -extern HA_Message *create_reply_adv(HA_Message *request, crm_data_t *xml_response_data, const char *origin); +extern xmlNode *create_reply_adv(xmlNode *request, xmlNode *xml_response_data, const char *origin); #define create_request(task, xml_data, host_to, sys_to, sys_from, uuid_from) create_request_adv(task, xml_data, host_to, sys_to, sys_from, uuid_from, __FUNCTION__) -extern HA_Message *create_request_adv( - const char *task, crm_data_t *xml_data, const char *host_to, +extern xmlNode *create_request_adv( + const char *task, xmlNode *xml_data, const char *host_to, const char *sys_to, const char *sys_from, const char *uuid_from, const char *origin); typedef struct ha_msg_input_s { - HA_Message *msg; - crm_data_t *xml; + xmlNode *msg; + xmlNode *xml; } ha_msg_input_t; -extern ha_msg_input_t *new_ipc_msg_input(IPC_Message *orig); -extern ha_msg_input_t *new_ha_msg_input(const HA_Message *orig); +extern ha_msg_input_t *new_ipc_msg_input(xmlNode *orig); +extern ha_msg_input_t *new_ha_msg_input(xmlNode *orig); extern void delete_ha_msg_input(ha_msg_input_t *orig); - +extern xmlNode *xmlfromIPC(IPC_Channel *ch, int timeout); #endif diff --git a/include/crm/common/msg.h b/include/crm/common/msg.h index 52cfdea5a7..efbc05b0b8 100644 --- a/include/crm/common/msg.h +++ b/include/crm/common/msg.h @@ -1,36 +1,36 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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_MSG__H #define CRM_COMMON_MSG__H #include #include #include #include -extern crm_data_t *createPingAnswerFragment(const char *from, +extern xmlNode *createPingAnswerFragment(const char *from, const char *status); -extern gboolean process_hello_message(crm_data_t *hello, +extern gboolean process_hello_message(xmlNode *hello, char **uuid, char **client_name, char **major_version, char **minor_version); #endif diff --git a/include/crm/common/util.h b/include/crm/common/util.h index 3bddb810d9..3ce7e99802 100644 --- a/include/crm/common/util.h +++ b/include/crm/common/util.h @@ -1,191 +1,191 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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_UTIL__H #define CRM_COMMON_UTIL__H #include #include #if SUPPORT_HEARTBEAT # include # include #endif #include #include #include #include #define DEBUG_INC SIGUSR1 #define DEBUG_DEC SIGUSR2 extern unsigned int crm_log_level; extern gboolean crm_config_error; extern gboolean crm_config_warning; #define crm_config_err(fmt...) { crm_config_error = TRUE; crm_err(fmt); } #define crm_config_warn(fmt...) { crm_config_warning = TRUE; crm_warn(fmt); } extern gboolean crm_log_init( const char *entity, int level, gboolean coredir, gboolean to_stderr, int argc, char **argv); /* returns the old value */ extern unsigned int set_crm_log_level(unsigned int level); extern unsigned int get_crm_log_level(void); extern char *crm_itoa(int an_int); extern char *crm_strdup_fn(const char *a, const char *file, const char *fn, int line); extern char *generate_hash_key(const char *crm_msg_reference, const char *sys); extern char *generate_hash_value(const char *src_node, const char *src_subsys); extern gboolean decodeNVpair(const char *srcstring, char separator, char **name, char **value); extern int compare_version(const char *version1, const char *version2); extern char *generateReference(const char *custom1, const char *custom2); extern void alter_debug(int nsig); extern void g_hash_destroy_str(gpointer data); extern gboolean crm_is_true(const char * s); extern int crm_str_to_boolean(const char * s, int * ret); extern long crm_get_msec(const char * input); extern const char *op_status2text(op_status_t status); extern char *generate_op_key( const char *rsc_id, const char *op_type, int interval); extern gboolean parse_op_key( const char *key, char **rsc_id, char **op_type, int *interval); extern char *generate_notify_key( const char *rsc_id, const char *notify_type, const char *op_type); extern char *generate_transition_magic_v202( const char *transition_key, int op_status); extern char *generate_transition_magic( const char *transition_key, int op_status, int op_rc); extern gboolean decode_transition_magic( const char *magic, char **uuid, int *transition_id, int *action_id, int *op_status, int *op_rc); extern char *generate_transition_key(int action, int transition_id, const char *node); extern gboolean decode_transition_key( const char *key, char **uuid, int *action, int *transition_id); extern char *crm_concat(const char *prefix, const char *suffix, char join); extern gboolean decode_op_key( const char *key, char **rsc_id, char **op_type, int *interval); -extern void filter_action_parameters(crm_data_t *param_set, const char *version); -extern void filter_reload_parameters(crm_data_t *param_set, const char *restart_string); +extern void filter_action_parameters(xmlNode *param_set, const char *version); +extern void filter_reload_parameters(xmlNode *param_set, const char *restart_string); #define safe_str_eq(a, b) crm_str_eq(a, b, FALSE) extern gboolean crm_str_eq(const char *a, const char *b, gboolean use_case); extern gboolean safe_str_neq(const char *a, const char *b); extern int crm_parse_int(const char *text, const char *default_text); extern long crm_int_helper(const char *text, char **end_text); #define crm_atoi(text, default_text) crm_parse_int(text, default_text) extern void crm_abort(const char *file, const char *function, int line, const char *condition, gboolean do_core, gboolean do_fork); extern char *generate_series_filename( const char *directory, const char *series, int sequence, gboolean bzip); extern int get_last_sequence(const char *directory, const char *series); extern void write_last_sequence( const char *directory, const char *series, int sequence, int max); extern void crm_make_daemon( const char *name, gboolean daemonize, const char *pidfile); typedef struct pe_cluster_option_s { const char *name; const char *alt_name; const char *type; const char *values; const char *default_value; gboolean (*is_valid)(const char *); const char *description_short; const char *description_long; } pe_cluster_option; extern const char *cluster_option( GHashTable* options, gboolean(*validate)(const char*), const char *name, const char *old_name, const char *def_value); extern const char *get_cluster_pref( GHashTable *options, pe_cluster_option *option_list, int len, const char *name); extern void config_metadata( const char *name, const char *version, const char *desc_short, const char *desc_long, pe_cluster_option *option_list, int len); extern void verify_all_options(GHashTable *options, pe_cluster_option *option_list, int len); extern gboolean check_time(const char *value); extern gboolean check_timer(const char *value); extern gboolean check_boolean(const char *value); extern gboolean check_number(const char *value); extern int char2score(const char *score); extern char *score2char(int score); extern gboolean crm_is_writable( const char *dir, const char *file, const char *user, const char *group, gboolean need_both); extern long long crm_set_bit(const char *function, long long word, long long bit); extern long long crm_clear_bit(const char *function, long long word, long long bit); #define set_bit(word, bit) word = crm_set_bit(__PRETTY_FUNCTION__, word, bit) #define clear_bit(word, bit) word = crm_clear_bit(__PRETTY_FUNCTION__, word, bit) #define set_bit_inplace(word, bit) word |= bit #define clear_bit_inplace(word, bit) word &= ~bit extern gboolean is_set(long long action_list, long long action); extern gboolean is_not_set(long long action_list, long long action); extern gboolean is_set_any(long long action_list, long long action); extern gboolean is_openais_cluster(void); extern gboolean is_heartbeat_cluster(void); #endif diff --git a/include/crm/common/xml.h b/include/crm/common/xml.h index 13fd216a98..9839dd2f48 100644 --- a/include/crm/common/xml.h +++ b/include/crm/common/xml.h @@ -1,325 +1,308 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include -/* #define USE_LIBXML 1 */ -#if CRM_DEV_BUILD -# define XML_PARANOIA_CHECKS 1 -#else -# define XML_PARANOIA_CHECKS 0 -#endif - -#ifdef USE_LIBXML -# include - typedef xmlNode crm_data_t; -#else - typedef struct ha_msg crm_data_t; -#endif +#define USE_LIBXML 1 +#include +typedef xmlNode crm_data_t; extern gboolean add_message_xml( - HA_Message *msg, const char *field, const crm_data_t *xml); -extern crm_data_t *get_message_xml(HA_Message *msg, const char *field); -extern GHashTable *xml2list(crm_data_t *parent); + xmlNode *msg, const char *field, xmlNode *xml); +extern xmlNode *get_message_xml(xmlNode *msg, const char *field); +extern GHashTable *xml2list(xmlNode *parent); #if CRM_DEPRECATED_SINCE_2_0_3 -extern GHashTable *xml2list_202(crm_data_t *parent); +extern GHashTable *xml2list_202(xmlNode *parent); #endif extern void hash2nvpair(gpointer key, gpointer value, gpointer user_data); extern void hash2field(gpointer key, gpointer value, gpointer user_data); extern void hash2metafield(gpointer key, gpointer value, gpointer user_data); -extern gboolean do_id_check(crm_data_t *xml_obj, GHashTable *id_hash, +extern gboolean do_id_check(xmlNode *xml_obj, GHashTable *id_hash, gboolean silent_add, gboolean silent_rename); /* * 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); -extern void expand_plus_plus(crm_data_t* target, const char *name, const char *value); -extern void fix_plus_plus_recursive(crm_data_t* target); +extern void copy_in_properties(xmlNode *target, xmlNode *src); +extern void expand_plus_plus(xmlNode* target, const char *name, const char *value); +extern void fix_plus_plus_recursive(xmlNode* target); /* * Find a child named search_path[i] at level i in the XML fragment where i=0 * is an immediate child of root. * * 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); +extern xmlNode *find_xml_node_nested( + xmlNode *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 root. * * Once the last child specified by node_path is found, find the value * of attr_name. * * If error 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, +extern const char *get_xml_attr_nested(xmlNode *parent, const char **node_path, int length, const char *attr_name, gboolean error); -#define free_xml(a_node) do { \ - if(a_node != NULL) { \ - crm_validate_data(a_node); \ - ha_msg_del(a_node); \ - } \ - } while(0) -void free_xml_from_parent(crm_data_t *parent, crm_data_t *a_node); +void free_xml_from_parent(xmlNode *parent, xmlNode *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); +extern xmlNode *create_xml_node(xmlNode *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); + xmlNode *node, const char *name, const char *value); extern const char *crm_xml_add_int( - crm_data_t* node, const char *name, int value); + xmlNode* 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 add_xml_tstamp(crm_data_t *a_node); +extern void unlink_xml_node(xmlNode *node); /* * */ -extern void purge_diff_markers(crm_data_t *a_node); +extern void purge_diff_markers(xmlNode *a_node); /* * Returns a deep copy of src_node * */ -extern crm_data_t *copy_xml(const crm_data_t *src_node); +extern xmlNode *copy_xml(xmlNode *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); +extern xmlNode *add_node_copy( + xmlNode *new_parent, xmlNode *xml_node); -extern int add_node_nocopy(crm_data_t *parent, const char *name, crm_data_t *child); +extern int add_node_nocopy(xmlNode *parent, const char *name, xmlNode *child); /* * XML I/O Functions * * Whitespace between tags is discarded. */ -extern crm_data_t *file2xml(FILE *input, gboolean compressed); +extern xmlNode *file2xml(FILE *input, gboolean compressed); -extern crm_data_t *stdin2xml(void); +extern xmlNode *stdin2xml(void); -extern crm_data_t *string2xml(const char *input); +extern xmlNode *string2xml(const char *input); extern int write_xml_file( - crm_data_t *xml_node, const char *filename, gboolean compress); + xmlNode *xml_node, const char *filename, gboolean compress); -extern char *dump_xml_formatted(const crm_data_t *msg); +extern char *dump_xml_formatted(xmlNode *msg); -extern char *dump_xml_unformatted(const crm_data_t *msg); +extern char *dump_xml_unformatted(xmlNode *msg); extern void print_xml_formatted( int log_level, const char *function, - const crm_data_t *an_xml_node, const char *text); + xmlNode *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 xmlNode *diff_xml_object( + xmlNode *left, xmlNode *right, gboolean suppress); -extern void log_xml_diff(unsigned int log_level, crm_data_t *diff, const char *function); +extern void log_xml_diff(unsigned int log_level, xmlNode *diff, const char *function); extern gboolean apply_xml_diff( - crm_data_t *old, crm_data_t *diff, crm_data_t **new); + xmlNode *old, xmlNode *diff, xmlNode **new); /* * Searching & Modifying */ -extern crm_data_t *find_xml_node( - crm_data_t *cib, const char * node_path, gboolean must_find); +extern xmlNode *find_xml_node( + xmlNode *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 xmlNode *find_entity( + xmlNode *parent, const char *node_name, const char *id); -extern crm_data_t *subtract_xml_object( - crm_data_t *left, crm_data_t *right, const char *marker); +extern xmlNode *subtract_xml_object( + xmlNode *left, xmlNode *right, const char *marker); extern int add_xml_object( - crm_data_t *parent, crm_data_t *target, const crm_data_t *update); + xmlNode *parent, xmlNode *target, xmlNode *update); -extern void xml_remove_prop(crm_data_t *obj, const char *name); +extern void xml_remove_prop(xmlNode *obj, const char *name); extern gboolean replace_xml_child( - crm_data_t *parent, crm_data_t *child, crm_data_t *update, gboolean delete_only); + xmlNode *parent, xmlNode *child, xmlNode *update, gboolean delete_only); -extern gboolean update_xml_child(crm_data_t *child, crm_data_t *to_update); +extern gboolean update_xml_child(xmlNode *child, xmlNode *to_update); extern int find_xml_children( - crm_data_t **children, crm_data_t *root, + xmlNode **children, xmlNode *root, const char *tag, const char *field, const char *value, gboolean search_matches); /* * */ -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 int crm_element_value_int(xmlNode *data, const char *name, int *dest); +extern const char *crm_element_value(xmlNode *data, const char *name); +extern char *crm_element_value_copy(xmlNode *data, const char *name); +extern const char *crm_element_value_const(const xmlNode *data, const char *name); -extern const char *crm_element_name(const crm_data_t *data); +extern const char *crm_element_name(const xmlNode *data); -extern void xml_validate(const crm_data_t *root); +extern void xml_validate(const xmlNode *root); -extern gboolean xml_has_children(const crm_data_t *root); +extern gboolean xml_has_children(const xmlNode *root); -extern char *calculate_xml_digest(crm_data_t *local_cib, gboolean sort, gboolean do_filter); +extern char *calculate_xml_digest(xmlNode *local_cib, gboolean sort, gboolean do_filter); extern gboolean validate_with_dtd( - crm_data_t *xml_blob, gboolean to_logs, const char *dtd_file); + xmlNode *xml_blob, gboolean to_logs, const char *dtd_file); #if XML_PARANOIA_CHECKS # define crm_validate_data(obj) xml_validate(obj) #else # define crm_validate_data(obj) CRM_DEV_ASSERT(obj != NULL) #endif -#define xml_child_iter(parent, child, loop_code) \ +# define xml_child_iter(parent, child, code) do { \ 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 \ - && parent->types[__counter] != FT_UNCOMPRESS) { \ - continue; \ - } \ - child = (crm_data_t*)parent->values[__counter]; \ - if(child == NULL) { \ - crm_debug_4("Skipping %s == NULL", \ - parent->names[__counter]); \ - } else { \ - loop_code; \ + xmlNode *child = NULL; \ + xmlNode *__crm_xml_iter = parent->children; \ + while(__crm_xml_iter != NULL) { \ + child = __crm_xml_iter; \ + __crm_xml_iter = __crm_xml_iter->next; \ + if(child) { \ + code; \ } \ } \ } else { \ crm_debug_4("Parent of loop was NULL"); \ - } + } \ + } while(0) -#define xml_child_iter_filter(parent, child, filter, loop_code) \ +# define xml_child_iter_filter(parent, child, filter, code) do { \ 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 \ - && parent->types[__counter] != FT_UNCOMPRESS) { \ - continue; \ - } \ - child = (crm_data_t*)parent->values[__counter]; \ - if(child == NULL) { \ - crm_debug_4("Skipping %s == NULL", \ - parent->names[__counter]); \ - } else if(filter == NULL/*constant condition*/ \ - || safe_str_eq(filter, parent->names[__counter])) { \ - loop_code; \ - } else { \ - crm_debug_4("Skipping <%s../>", \ - parent->names[__counter]); \ - } \ + xmlNode *child = NULL; \ + xmlNode *__crm_xml_iter = parent->children; \ + while(__crm_xml_iter != NULL) { \ + child = __crm_xml_iter; \ + __crm_xml_iter = __crm_xml_iter->next; \ + if(filter == NULL \ + || safe_str_eq(filter, (const char *)child->name)) { \ + code; \ + } else { \ + crm_debug_4("Skipping <%s../>", child->name); \ } \ + } \ } 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); \ - prop_name = (const char*)parent->names[__counter]; \ - if(parent->types[__counter] != FT_STRING) { \ - continue; \ - } else if(prop_name[0] == '_' \ - && prop_name[1] == '_') { \ - continue; \ - } \ - prop_value = (const char*)parent->values[__counter]; \ - code; \ + crm_debug_4("Parent of loop was NULL"); \ + } \ + } while(0) + +# define xml_prop_iter(parent, prop_name, prop_value, code) do { \ + if(parent != NULL) { \ + xmlAttrPtr prop_iter = parent->properties; \ + const char *prop_name = NULL; \ + const char *prop_value = NULL; \ + while(prop_iter != NULL) { \ + prop_name = (const char *)prop_iter->name; \ + prop_value = (const char *)xmlGetProp(parent, prop_iter->name); \ + prop_iter = prop_iter->next; \ + if(prop_name) { \ + code; \ } \ + } \ } else { \ - crm_debug_4("Parent of loop was NULL"); \ - } + crm_debug_4("Parent of loop was NULL"); \ + } \ + } while(0) + +# define free_xml(a_node) do { \ + if((a_node) == NULL) { \ + } else if ((a_node)->doc != NULL) { \ + xmlFreeDoc((a_node)->doc); \ + } else { \ + /* make sure the node is unlinked first */ \ + xmlUnlinkNode(a_node); \ + xmlFreeNode(a_node); \ + } \ + } while(0) + + +extern xmlNode *first_named_child(xmlNode *parent, const char *name); + +extern xmlNode *convert_ipc_message(IPC_Message *msg, const char *field); +extern xmlNode *convert_ha_message(xmlNode *parent, HA_Message *msg, const char *field); + +extern HA_Message *convert_xml_message(xmlNode *msg); #endif diff --git a/include/crm/crm.h b/include/crm/crm.h index 3811611151..c004f3bc5c 100644 --- a/include/crm/crm.h +++ b/include/crm/crm.h @@ -1,323 +1,321 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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__H #define CRM__H #include #include #include #undef MIN #undef MAX #include #include #include #ifdef MCHECK #include #endif +#include + #define EOS '\0' #define DIMOF(a) ((int) (sizeof(a)/sizeof(a[0])) ) #define HAURL(url) HA_URLBASE url #ifndef CRM_DEV_BUILD # define CRM_DEV_BUILD 0 #endif #define CRM_DEPRECATED_SINCE_2_0_1 0 #define CRM_DEPRECATED_SINCE_2_0_2 0 #define CRM_DEPRECATED_SINCE_2_0_3 0 #define CRM_DEPRECATED_SINCE_2_0_4 1 #define CRM_DEPRECATED_SINCE_2_0_5 1 #define CRM_DEPRECATED_SINCE_2_0_6 1 #define CRM_DEPRECATED_SINCE_2_0_7 1 #define CRM_DEPRECATED_SINCE_2_0_8 1 #define CRM_DEPRECATED_SINCE_2_1_0 1 #define CRM_META "CRM_meta" #define crm_meta_name(field) CRM_META"_"field #define ipc_call_diff_max_ms 5000 #define action_diff_warn_ms 5000 #define action_diff_max_ms 20000 #define fsa_diff_warn_ms 10000 #define fsa_diff_max_ms 30000 #include #define CRM_ASSERT(expr) if((expr) == FALSE) { \ crm_abort(__FILE__, __PRETTY_FUNCTION__, __LINE__, #expr, TRUE, FALSE); \ } extern gboolean crm_assert_failed; #define CRM_DEV_ASSERT(expr) \ crm_assert_failed = FALSE; \ if((expr) == FALSE) { \ crm_assert_failed = TRUE; \ crm_abort(__FILE__,__PRETTY_FUNCTION__,__LINE__, #expr, FALSE, TRUE); \ } #define CRM_CHECK(expr, failure_action) if((expr) == FALSE) { \ crm_abort(__FILE__,__PRETTY_FUNCTION__,__LINE__, #expr, FALSE, TRUE); \ failure_action; \ } #define CRM_CHECK_AND_STORE(expr, failure_action) if((expr) == FALSE) { \ crm_abort(__FILE__,__PRETTY_FUNCTION__,__LINE__, #expr, TRUE, TRUE); \ failure_action; \ } extern const char *crm_system_name; /* Clean these up at some point, some probably should be runtime options */ #define WORKING_DIR HA_VARLIBDIR"/heartbeat/crm" #define CRM_SOCK_DIR HA_VARRUNDIR"/heartbeat/crm" #define BIN_DIR HA_LIBDIR"/heartbeat" #define SOCKET_LEN 1024 #define APPNAME_LEN 256 #define MAX_IPC_FAIL 5 #define CIB_FILENAME WORKING_DIR"/cib.xml" #define CIB_BACKUP WORKING_DIR"/cib_backup.xml" #define CRM_FEATURE_SET "2.1" #define MSG_LOG 1 #define DOT_FSA_ACTIONS 1 #define DOT_ALL_FSA_INPUTS 1 /* #define FSA_TRACE 1 */ #define INFINITY_S "INFINITY" #define MINUS_INFINITY_S "-INFINITY" #define INFINITY 1000000 /* Sub-systems */ #define CRM_SYSTEM_DC "dc" #define CRM_SYSTEM_DCIB "dcib" /* The master CIB */ #define CRM_SYSTEM_CIB "cib" #define CRM_SYSTEM_CRMD "crmd" #define CRM_SYSTEM_LRMD "lrmd" #define CRM_SYSTEM_PENGINE "pengine" #define CRM_SYSTEM_TENGINE "tengine" /* Valid operations */ #define CRM_OP_NOOP "noop" #define CRM_OP_JOIN_ANNOUNCE "join_announce" #define CRM_OP_JOIN_OFFER "join_offer" #define CRM_OP_JOIN_REQUEST "join_request" #define CRM_OP_JOIN_ACKNAK "join_ack_nack" #define CRM_OP_JOIN_CONFIRM "join_confirm" #define CRM_OP_DIE "die_no_respawn" #define CRM_OP_RETRIVE_CIB "retrieve_cib" #define CRM_OP_PING "ping" #define CRM_OP_VOTE "vote" #define CRM_OP_NOVOTE "no-vote" #define CRM_OP_HELLO "hello" #define CRM_OP_HBEAT "dc_beat" #define CRM_OP_PECALC "pe_calc" #define CRM_OP_ABORT "abort" #define CRM_OP_QUIT "quit" #define CRM_OP_LOCAL_SHUTDOWN "start_shutdown" #define CRM_OP_SHUTDOWN_REQ "req_shutdown" #define CRM_OP_SHUTDOWN "do_shutdown" #define CRM_OP_FENCE "stonith" #define CRM_OP_EVENTCC "event_cc" #define CRM_OP_TEABORT "te_abort" #define CRM_OP_TEABORTED "te_abort_confirmed" /* we asked */ #define CRM_OP_TE_HALT "te_halt" #define CRM_OP_TECOMPLETE "te_complete" #define CRM_OP_TETIMEOUT "te_timeout" #define CRM_OP_TRANSITION "transition" #define CRM_OP_REGISTER "register" #define CRM_OP_DEBUG_UP "debug_inc" #define CRM_OP_DEBUG_DOWN "debug_dec" #define CRM_OP_INVOKE_LRM "lrm_invoke" #define CRM_OP_LRM_REFRESH "lrm_refresh" #define CRM_OP_LRM_QUERY "lrm_query" #define CRM_OP_LRM_DELETE "lrm_delete" #define CRM_OP_LRM_FAIL "lrm_fail" #define CRM_OP_PROBED "probe_complete" #define CRM_OP_REPROBE "probe_again" #define CRMD_STATE_ACTIVE "member" #define CRMD_STATE_INACTIVE "down" #define CRMD_JOINSTATE_DOWN CRMD_STATE_INACTIVE #define CRMD_JOINSTATE_PENDING "pending" #define CRMD_JOINSTATE_MEMBER CRMD_STATE_ACTIVE #define CRMD_ACTION_DELETE "delete" #define CRMD_ACTION_CANCEL "cancel" #define CRMD_ACTION_MIGRATE "migrate_to" #define CRMD_ACTION_MIGRATED "migrate_from" #define CRMD_ACTION_START "start" #define CRMD_ACTION_STARTED "running" #define CRMD_ACTION_STOP "stop" #define CRMD_ACTION_STOPPED "stopped" #define CRMD_ACTION_PROMOTE "promote" #define CRMD_ACTION_PROMOTED "promoted" #define CRMD_ACTION_DEMOTE "demote" #define CRMD_ACTION_DEMOTED "demoted" #define CRMD_ACTION_NOTIFY "notify" #define CRMD_ACTION_NOTIFIED "notified" #define CRMD_ACTION_STATUS "monitor" typedef GList* GListPtr; #define slist_destroy(child_type, child, parent, a) \ { \ GListPtr __crm_iter_head = parent; \ child_type *child = NULL; \ while(__crm_iter_head != NULL) { \ child = (child_type *) __crm_iter_head->data; \ __crm_iter_head = __crm_iter_head->next; \ { a; } \ } \ g_list_free(parent); \ } #define slist_iter(child, child_type, parent, counter, a) \ { \ GListPtr __crm_iter_head = parent; \ child_type *child = NULL; \ int counter = 0; \ for(; __crm_iter_head != NULL; counter++) { \ child = (child_type *) __crm_iter_head->data; \ __crm_iter_head = __crm_iter_head->next; \ { a; } \ } \ } #define LOG_DEBUG_2 LOG_DEBUG+1 #define LOG_DEBUG_3 LOG_DEBUG+2 #define LOG_DEBUG_4 LOG_DEBUG+3 #define LOG_DEBUG_5 LOG_DEBUG+4 #define LOG_DEBUG_6 LOG_DEBUG+5 #define LOG_MSG LOG_DEBUG_3 /* * Throughout the macros below, note the leading, pre-comma, space in the * various ' , ##args' occurences to aid portability across versions of 'gcc'. * http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html#Variadic-Macros */ #define do_crm_log(level, fmt, args...) do { \ if(crm_log_level < (level)) { \ continue; \ } else if((level) > LOG_DEBUG) { \ cl_log(LOG_DEBUG, "debug%d: %s: " fmt, \ level-LOG_INFO, __PRETTY_FUNCTION__ , ##args); \ } else { \ cl_log(level, "%s: " fmt, \ __PRETTY_FUNCTION__ , ##args); \ } \ } while(0) #define crm_crit(fmt, args...) do_crm_log(LOG_CRIT, fmt , ##args) #define crm_err(fmt, args...) do_crm_log(LOG_ERR, fmt , ##args) #define crm_warn(fmt, args...) do_crm_log(LOG_WARNING, fmt , ##args) #define crm_notice(fmt, args...) do_crm_log(LOG_NOTICE, fmt , ##args) #define crm_info(fmt, args...) do_crm_log(LOG_INFO, fmt , ##args) #define crm_debug(fmt, args...) do_crm_log(LOG_DEBUG, fmt , ##args) #define crm_debug_2(fmt, args...) do_crm_log(LOG_DEBUG_2, fmt , ##args) #define crm_debug_3(fmt, args...) do_crm_log(LOG_DEBUG_3, fmt , ##args) #define crm_debug_4(fmt, args...) do_crm_log(LOG_DEBUG_4, fmt , ##args) #define crm_debug_5(fmt, args...) do_crm_log(LOG_DEBUG_5, fmt , ##args) #define crm_debug_6(fmt, args...) do_crm_log(LOG_DEBUG_6, fmt , ##args) extern void crm_log_message_adv( int level, const char *alt_debugfile, const HA_Message *msg); -#define crm_log_message(level, msg) if(crm_log_level >= (level)) { \ - crm_log_message_adv(level, NULL, msg); \ - } - #define crm_log_xml(level, text, xml) if(crm_log_level >= (level)) { \ print_xml_formatted(level, __PRETTY_FUNCTION__, xml, text); \ } #define crm_log_xml_crit(xml, text) crm_log_xml(LOG_CRIT, text, xml) #define crm_log_xml_err(xml, text) crm_log_xml(LOG_ERR, text, xml) #define crm_log_xml_warn(xml, text) crm_log_xml(LOG_WARNING, text, xml) #define crm_log_xml_notice(xml, text) crm_log_xml(LOG_NOTICE, text, xml) #define crm_log_xml_info(xml, text) crm_log_xml(LOG_INFO, text, xml) #define crm_log_xml_debug(xml, text) crm_log_xml(LOG_DEBUG, text, xml) #define crm_log_xml_debug_2(xml, text) crm_log_xml(LOG_DEBUG_2, text, xml) #define crm_log_xml_debug_3(xml, text) crm_log_xml(LOG_DEBUG_3, text, xml) #define crm_log_xml_debug_4(xml, text) crm_log_xml(LOG_DEBUG_4, text, xml) #define crm_log_xml_debug_5(xml, text) crm_log_xml(LOG_DEBUG_5, text, xml) #define crm_str(x) (const char*)(x?x:"") #if CRM_DEV_BUILD # define crm_malloc0(malloc_obj, length) do { \ if(malloc_obj) { \ crm_err("Potential memory leak:" \ " %s at %s:%d not NULL before alloc.", \ #malloc_obj, __FILE__, __LINE__); \ } \ malloc_obj = cl_malloc(length); \ if(malloc_obj == NULL) { \ crm_err("Failed allocation of %lu bytes", (unsigned long)length); \ CRM_ASSERT(malloc_obj != NULL); \ } \ memset(malloc_obj, 0, length); \ } while(0) /* it's not a memory leak to already have an object to realloc, that's * the usual case, however if it does have a value, it must have been * allocated by the same allocator! */ # define crm_realloc(realloc_obj, length) do { \ if (realloc_obj != NULL) { \ CRM_ASSERT(cl_is_allocated(realloc_obj) == 1); \ } \ realloc_obj = cl_realloc(realloc_obj, length); \ CRM_ASSERT(realloc_obj != NULL); \ } while(0) # define crm_free(free_obj) if(free_obj) { \ CRM_ASSERT(cl_is_allocated(free_obj) == 1); \ cl_free(free_obj); \ free_obj=NULL; \ } #else # define crm_malloc0(malloc_obj, length) do { \ malloc_obj = cl_malloc(length); \ if(malloc_obj == NULL) { \ crm_err("Failed allocation of %lu bytes", (unsigned long)length); \ CRM_ASSERT(malloc_obj != NULL); \ } \ memset(malloc_obj, 0, length); \ } while(0) # define crm_realloc(realloc_obj, length) do { \ realloc_obj = cl_realloc(realloc_obj, length); \ CRM_ASSERT(realloc_obj != NULL); \ } while(0) # define crm_free(free_obj) if(free_obj) { cl_free(free_obj); free_obj=NULL; } #endif #define crm_msg_del(msg) if(msg != NULL) { ha_msg_del(msg); msg = NULL; } #define crm_strdup(str) crm_strdup_fn(str, __FILE__, __PRETTY_FUNCTION__, __LINE__) #endif diff --git a/include/crm/pengine/complex.h b/include/crm/pengine/complex.h index edf525dce6..d36a7a7ba4 100644 --- a/include/crm/pengine/complex.h +++ b/include/crm/pengine/complex.h @@ -1,120 +1,120 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 PENGINE_COMPLEX__H #define PENGINE_COMPLEX__H #define n_object_classes 3 /*#define PE_OBJ_F_ ""*/ #define PE_OBJ_T_NATIVE "native" #define PE_OBJ_T_GROUP "group" #define PE_OBJ_T_INCARNATION "clone" #define PE_OBJ_T_MASTER "master" enum pe_obj_types { pe_unknown = -1, pe_native = 0, pe_group = 1, pe_clone = 2, pe_master = 3 }; extern int get_resource_type(const char *name); typedef struct resource_object_functions_s { gboolean (*unpack)(resource_t *, pe_working_set_t *); resource_t *(*find_child)(resource_t *, const char *); GListPtr (*children)(resource_t *); /* parameter result must be free'd */ char *(*parameter)( resource_t *, node_t *, gboolean, const char *, pe_working_set_t *); void (*print)(resource_t *, const char *, long, void *); gboolean (*active)(resource_t *,gboolean); enum rsc_role_e (*state)(const resource_t *, gboolean); node_t *(*location)(resource_t *, GListPtr*, gboolean); void (*free)(resource_t *); } resource_object_functions_t; extern void common_update_score(resource_t *rsc, const char *id, int score); extern void common_apply_stickiness(resource_t *rsc, node_t *node, pe_working_set_t *data_set); extern char *native_parameter( resource_t *rsc, node_t *node, gboolean create, const char *name, pe_working_set_t *data_set); extern gboolean native_unpack(resource_t *rsc, pe_working_set_t *data_set); extern gboolean group_unpack(resource_t *rsc, pe_working_set_t *data_set); extern gboolean clone_unpack(resource_t *rsc, pe_working_set_t *data_set); extern gboolean master_unpack(resource_t *rsc, pe_working_set_t *data_set); extern GListPtr native_children(resource_t *rsc); extern GListPtr group_children(resource_t *rsc); extern GListPtr clone_children(resource_t *rsc); extern GListPtr master_children(resource_t *rsc); extern resource_t *native_find_child(resource_t *rsc, const char *id); extern resource_t *group_find_child(resource_t *rsc, const char *id); extern resource_t *clone_find_child(resource_t *rsc, const char *id); extern resource_t *master_find_child(resource_t *rsc, const char *id); extern gboolean native_active(resource_t *rsc, gboolean all); extern gboolean group_active(resource_t *rsc, gboolean all); extern gboolean clone_active(resource_t *rsc, gboolean all); extern gboolean master_active(resource_t *rsc, gboolean all); extern void native_print( resource_t *rsc, const char *pre_text, long options, void *print_data); extern void group_print( resource_t *rsc, const char *pre_text, long options, void *print_data); extern void clone_print( resource_t *rsc, const char *pre_text, long options, void *print_data); extern void master_print( resource_t *rsc, const char *pre_text, long options, void *print_data); extern void native_free(resource_t *rsc); extern void group_free(resource_t *rsc); extern void clone_free(resource_t *rsc); extern void master_free(resource_t *rsc); extern enum rsc_role_e native_resource_state(const resource_t *rsc, gboolean current); extern enum rsc_role_e group_resource_state(const resource_t *rsc, gboolean current); extern enum rsc_role_e clone_resource_state(const resource_t *rsc, gboolean current); extern enum rsc_role_e master_resource_state(const resource_t *rsc, gboolean current); extern node_t *native_location(resource_t *rsc, GListPtr *list, gboolean current); extern resource_object_functions_t resource_class_functions[]; -extern gboolean common_unpack(crm_data_t * xml_obj, resource_t **rsc, +extern gboolean common_unpack(xmlNode * xml_obj, resource_t **rsc, resource_t *parent, pe_working_set_t *data_set); extern void common_print(resource_t *rsc, const char *pre_text, long options, void *print_data); extern void common_free(resource_t *rsc); extern void native_add_running( resource_t *rsc, node_t *node, pe_working_set_t *data_set); extern void get_meta_attributes(GHashTable *meta_hash, resource_t *rsc, node_t *node, pe_working_set_t *data_set); typedef struct resource_alloc_functions_s resource_alloc_functions_t; #endif diff --git a/include/crm/pengine/rules.h b/include/crm/pengine/rules.h index 68d995bcd2..e708c9f080 100644 --- a/include/crm/pengine/rules.h +++ b/include/crm/pengine/rules.h @@ -1,49 +1,49 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 PENGINE_RULES__H #define PENGINE_RULES__H #include #include #include enum expression_type { not_expr, nested_rule, attr_expr, loc_expr, role_expr, time_expr }; -extern enum expression_type find_expression_type(crm_data_t *expr); +extern enum expression_type find_expression_type(xmlNode *expr); extern gboolean test_ruleset( - crm_data_t *ruleset, GHashTable *node_hash, ha_time_t *now); + xmlNode *ruleset, GHashTable *node_hash, ha_time_t *now); -extern gboolean test_rule(crm_data_t *rule, GHashTable *node_hash, +extern gboolean test_rule(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role, ha_time_t *now); -extern gboolean test_expression(crm_data_t *expr, GHashTable *node_hash, +extern gboolean test_expression(xmlNode *expr, GHashTable *node_hash, enum rsc_role_e role, ha_time_t *now); extern void unpack_instance_attributes( - crm_data_t *xml_obj, const char *set_name, GHashTable *node_hash, + xmlNode *xml_obj, const char *set_name, GHashTable *node_hash, GHashTable *hash, const char *always_first, ha_time_t *now); #endif diff --git a/include/crm/pengine/status.h b/include/crm/pengine/status.h index 441f34dfa0..85a9360177 100644 --- a/include/crm/pengine/status.h +++ b/include/crm/pengine/status.h @@ -1,230 +1,230 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 PENGINE_STATUS__H #define PENGINE_STATUS__H #include #include #include typedef struct node_s node_t; typedef struct action_s action_t; typedef struct resource_s resource_t; typedef enum no_quorum_policy_e { no_quorum_freeze, no_quorum_stop, no_quorum_ignore } no_quorum_policy_t; enum node_type { node_ping, node_member }; enum pe_restart { pe_restart_restart, pe_restart_ignore }; typedef struct pe_working_set_s { - crm_data_t *input; + xmlNode *input; ha_time_t *now; /* options extracted from the input */ char *transition_idle_timeout; char *dc_uuid; node_t *dc_node; gboolean have_quorum; gboolean stonith_enabled; const char *stonith_action; gboolean symmetric_cluster; gboolean is_managed_default; gboolean start_failure_fatal; gboolean remove_after_stop; gboolean stop_rsc_orphans; gboolean stop_action_orphans; int default_resource_stickiness; int default_resource_fail_stickiness; no_quorum_policy_t no_quorum_policy; GHashTable *config_hash; GListPtr nodes; GListPtr resources; GListPtr placement_constraints; GListPtr ordering_constraints; GListPtr colocation_constraints; GListPtr actions; - crm_data_t *failed; + xmlNode *failed; /* stats */ int num_synapse; int max_valid_nodes; int order_id; int action_id; /* final output */ - crm_data_t *graph; + xmlNode *graph; } pe_working_set_t; struct node_shared_s { const char *id; const char *uname; gboolean online; gboolean standby; gboolean unclean; gboolean shutdown; gboolean expected_up; gboolean is_dc; int num_resources; GListPtr running_rsc; /* resource_t* */ GListPtr allocated_rsc; /* resource_t* */ GHashTable *attrs; /* char* => char* */ enum node_type type; }; struct node_s { int weight; gboolean fixed; int count; struct node_shared_s *details; }; #include #define pe_rsc_orphan 0x00000001ULL #define pe_rsc_managed 0x00000002ULL #define pe_rsc_notify 0x00000010ULL #define pe_rsc_unique 0x00000020ULL #define pe_rsc_can_migrate 0x00000040ULL #define pe_rsc_provisional 0x00000100ULL #define pe_rsc_allocating 0x00000200ULL #define pe_rsc_merging 0x00000400ULL #define pe_rsc_failed 0x00010000ULL #define pe_rsc_shutdown 0x00020000ULL #define pe_rsc_runnable 0x00040000ULL #define pe_rsc_start_pending 0x00080000ULL #define pe_rsc_starting 0x00100000ULL #define pe_rsc_stopping 0x00200000ULL struct resource_s { char *id; char *clone_name; char *long_name; - crm_data_t *xml; - crm_data_t *ops_xml; + xmlNode *xml; + xmlNode *ops_xml; resource_t *parent; void *variant_opaque; enum pe_obj_types variant; resource_object_functions_t *fns; resource_alloc_functions_t *cmds; enum rsc_recovery_type recovery_type; enum pe_restart restart_type; int priority; int stickiness; int sort_index; int fail_stickiness; int effective_priority; unsigned long long flags; GListPtr rsc_cons_lhs; /* rsc_colocation_t* */ GListPtr rsc_cons; /* rsc_colocation_t* */ GListPtr rsc_location; /* rsc_to_node_t* */ GListPtr actions; /* action_t* */ node_t *allocated_to; GListPtr running_on; /* node_t* */ GListPtr known_on; /* node_t* */ GListPtr allowed_nodes; /* node_t* */ enum rsc_role_e role; enum rsc_role_e next_role; GHashTable *meta; GHashTable *parameters; GListPtr children; /* resource_t* */ }; struct action_s { int id; int priority; resource_t *rsc; void *rsc_opaque; node_t *node; char *task; char *uuid; - crm_data_t *op_entry; + xmlNode *op_entry; gboolean pseudo; gboolean runnable; gboolean optional; gboolean failure_is_fatal; gboolean implied_by_stonith; gboolean allow_reload_conversion; enum rsc_start_requirement needs; enum action_fail_response on_fail; enum rsc_role_e fail_role; gboolean dumped; gboolean processed; action_t *pre_notify; action_t *pre_notified; action_t *post_notify; action_t *post_notified; int seen_count; GHashTable *meta; GHashTable *extra; GHashTable *notify_keys; /* do NOT free */ GListPtr actions_before; /* action_warpper_t* */ GListPtr actions_after; /* action_warpper_t* */ }; gboolean cluster_status(pe_working_set_t *data_set); extern void set_working_set_defaults(pe_working_set_t *data_set); extern void cleanup_calculations(pe_working_set_t *data_set); extern resource_t *pe_find_resource(GListPtr rsc_list, const char *id_rh); 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 GListPtr find_operations( const char *rsc, const char *node, gboolean active_filter, pe_working_set_t *data_set); #endif diff --git a/include/crm/transition.h b/include/crm/transition.h index 12327339b6..2bacb0fcbc 100644 --- a/include/crm/transition.h +++ b/include/crm/transition.h @@ -1,151 +1,151 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include /* #include */ /* #include */ typedef enum { action_type_pseudo, action_type_rsc, action_type_crm } action_type_e; typedef struct te_timer_s crm_action_timer_t; typedef struct synapse_s { int id; int priority; gboolean ready; gboolean executed; gboolean confirmed; GListPtr actions; /* crm_action_t* */ GListPtr inputs; /* crm_action_t* */ } synapse_t; typedef struct crm_action_s { int id; int timeout; int interval; GHashTable *params; action_type_e type; crm_action_timer_t *timer; synapse_t *synapse; gboolean sent_update; /* sent to the CIB */ gboolean executed; /* sent to the CRM */ gboolean confirmed; gboolean failed; gboolean can_fail; - crm_data_t *xml; + xmlNode *xml; } crm_action_t; enum timer_reason { timeout_action, timeout_action_warn, timeout_abort, }; struct te_timer_s { int source_id; int timeout; enum timer_reason reason; crm_action_t *action; }; /* order matters here */ enum transition_action { tg_stop, tg_abort, tg_restart, tg_shutdown, }; typedef struct crm_graph_s { int id; int abort_priority; gboolean complete; const char *abort_reason; enum transition_action completion_action; int num_actions; int num_synapses; int batch_limit; int network_delay; int transition_timeout; GListPtr synapses; /* synpase_t* */ } crm_graph_t; typedef struct crm_graph_functions_s { gboolean (*pseudo)(crm_graph_t *graph, crm_action_t *action); gboolean (*rsc)(crm_graph_t *graph, crm_action_t *action); gboolean (*crmd)(crm_graph_t *graph, crm_action_t *action); gboolean (*stonith)(crm_graph_t *graph, crm_action_t *action); } crm_graph_functions_t; enum transition_status { transition_active, transition_pending, /* active but no actions performed this time */ transition_complete, transition_stopped, transition_terminated, transition_action_failed, transition_failed, }; extern void set_default_graph_functions(void); extern void set_graph_functions(crm_graph_functions_t *fns); -extern crm_graph_t *unpack_graph(crm_data_t *xml_graph); +extern crm_graph_t *unpack_graph(xmlNode *xml_graph); extern int run_graph(crm_graph_t *graph); extern gboolean update_graph(crm_graph_t *graph, crm_action_t *action); extern void destroy_graph(crm_graph_t *graph); extern const char *transition_status(enum transition_status state); extern void print_graph(unsigned int log_level, crm_graph_t *graph); extern void print_action( int log_level, const char *prefix, crm_action_t *action); extern void update_abort_priority( crm_graph_t *graph, int priority, enum transition_action action, const char *abort_reason); extern const char *actiontype2text(action_type_e type); #ifdef TESTING # define te_log_action(log_level, fmt, args...) { \ do_crm_log(log_level, fmt, ##args); \ fprintf(stderr, fmt"\n", ##args); \ } #else # define te_log_action(log_level, fmt, args...) do_crm_log(log_level, fmt, ##args) #endif diff --git a/lib/crm/cib/cib_attrs.c b/lib/crm/cib/cib_attrs.c index eba32274c4..825d85ca33 100644 --- a/lib/crm/cib/cib_attrs.c +++ b/lib/crm/cib/cib_attrs.c @@ -1,697 +1,697 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #define attr_common_setup(section) \ gboolean is_crm_config = FALSE; \ gboolean is_node_transient = FALSE; \ char *local_set_name = NULL; \ if(attr_id == NULL && attr_name == NULL) { \ return cib_missing; \ \ } else if(safe_str_eq(section, XML_CIB_TAG_CRMCONFIG)) { \ node_uuid = NULL; \ is_crm_config = TRUE; \ tag = XML_CIB_TAG_CRMCONFIG; \ if(set_name == NULL) { \ set_name = CIB_OPTIONS_FIRST; \ } \ \ } else if(safe_str_eq(section, XML_CIB_TAG_NODES)) { \ tag = XML_CIB_TAG_NODE; \ if(node_uuid == NULL) { \ return cib_missing; \ } \ if(set_name == NULL) { \ local_set_name = crm_concat(section, node_uuid, '-'); \ set_name = local_set_name; \ } \ \ } else if(safe_str_eq(section, XML_CIB_TAG_STATUS)) { \ is_node_transient = TRUE; \ tag = XML_TAG_TRANSIENT_NODEATTRS; \ if(set_name == NULL) { \ local_set_name = crm_concat(section, node_uuid, '-'); \ set_name = local_set_name; \ } \ \ } else { \ return cib_bad_section; \ } \ \ if(attr_id == NULL) { \ local_attr_id = crm_concat(set_name, attr_name, '-'); \ attr_id = local_attr_id; \ \ } else if(attr_name == NULL) { \ attr_name = attr_id; \ } \ #define attr_msg(level, fmt, args...) do { \ if(to_console) { \ printf(fmt"\n", ##args); \ } else { \ do_crm_log(level, fmt , ##args); \ } \ } while(0) enum cib_errors -find_attr_details(crm_data_t *xml_search, const char *node_uuid, +find_attr_details(xmlNode *xml_search, const char *node_uuid, const char *set_name, const char *attr_id, const char *attr_name, - crm_data_t **xml_obj, gboolean to_console) + xmlNode **xml_obj, gboolean to_console) { int matches = 0; - crm_data_t *nv_children = NULL; - crm_data_t *set_children = NULL; + xmlNode *nv_children = NULL; + xmlNode *set_children = NULL; const char *set_type = XML_TAG_ATTR_SETS; const char *tag = crm_element_name(xml_search); CRM_CHECK(xml_obj != NULL, return cib_output_ptr); *xml_obj = NULL; CRM_CHECK(xml_search != NULL, return cib_NOTEXISTS); if(node_uuid != NULL || safe_str_eq(tag, XML_CIB_TAG_CRMCONFIG)) { set_type = XML_CIB_TAG_PROPSET; /* filter by node */ matches = find_xml_children( &set_children, xml_search, NULL, XML_ATTR_ID, node_uuid, FALSE); crm_log_xml_debug_2(set_children, "search by node:"); if(matches == 0) { CRM_CHECK(set_children == NULL, crm_err("Memory leak")); attr_msg(LOG_INFO, "No node matching id=%s in %s", node_uuid, TYPE(xml_search)); return cib_NOTEXISTS; } } /* filter by set name */ if(set_name != NULL) { - crm_data_t *tmp = NULL; + xmlNode *tmp = NULL; matches = find_xml_children( &tmp, set_children?set_children:xml_search, set_type, XML_ATTR_ID, set_name, FALSE); free_xml(set_children); set_children = tmp; crm_log_xml_debug_2(set_children, "search by set:"); if(matches == 0) { attr_msg(LOG_INFO, "No set matching id=%s in %s", set_name, TYPE(xml_search)); CRM_CHECK(set_children == NULL, crm_err("Memory leak")); return cib_NOTEXISTS; } } matches = 0; if(attr_id == NULL) { matches = find_xml_children( &nv_children, set_children?set_children:xml_search, XML_CIB_TAG_NVPAIR, XML_NVPAIR_ATTR_NAME, attr_name, FALSE); crm_log_xml_debug_2(nv_children, "search by name:"); } else if(attr_id != NULL) { matches = find_xml_children( &nv_children, set_children?set_children:xml_search, XML_CIB_TAG_NVPAIR, XML_ATTR_ID, attr_id, FALSE); crm_log_xml_debug(nv_children, "search by id:"); } if(matches == 1) { - crm_data_t *single_match = NULL; + xmlNode *single_match = NULL; xml_child_iter(nv_children, child, single_match = copy_xml(child); break; ); free_xml(nv_children); free_xml(set_children); *xml_obj = single_match; return cib_ok; } else if(matches == 0) { free_xml(set_children); return cib_NOTEXISTS; } attr_msg(LOG_WARNING, "Multiple attributes match name=%s in %s:", attr_name, TYPE(xml_search)); if(set_name != NULL) { xml_child_iter( nv_children, child, attr_msg(LOG_INFO, " Value: %s \t(set=%s, id=%s)", crm_element_value(child, XML_NVPAIR_ATTR_VALUE), set_name, ID(child)); ); } else { free_xml(set_children); set_children = NULL; find_xml_children( &set_children, xml_search, set_type, NULL, NULL, FALSE); xml_child_iter( set_children, set, const char *set_id = ID(set); free_xml(nv_children); nv_children = NULL; find_xml_children( &nv_children, set, XML_CIB_TAG_NVPAIR, XML_NVPAIR_ATTR_NAME, attr_name, FALSE); xml_child_iter( nv_children, child, attr_msg(LOG_INFO, " Value: %s \t(set=%s, id=%s)", crm_element_value(child, XML_NVPAIR_ATTR_VALUE), set_id, ID(child)); ); ); } free_xml(nv_children); free_xml(set_children); return cib_missing_data; } enum cib_errors update_attr(cib_t *the_cib, int call_options, const char *section, const char *node_uuid, const char *set_name, const char *attr_id, const char *attr_name, const char *attr_value, gboolean to_console) { const char *tag = NULL; enum cib_errors rc = cib_ok; - crm_data_t *xml_top = NULL; - crm_data_t *xml_obj = NULL; - crm_data_t *xml_search = NULL; + xmlNode *xml_top = NULL; + xmlNode *xml_obj = NULL; + xmlNode *xml_search = NULL; char *local_attr_id = NULL; CRM_CHECK(section != NULL, return cib_missing); CRM_CHECK(attr_name != NULL || attr_id != NULL, return cib_missing); if(safe_str_eq(section, XML_CIB_TAG_CRMCONFIG)) { node_uuid = NULL; } else if(safe_str_eq(section, XML_CIB_TAG_NODES)) { CRM_CHECK(node_uuid != NULL, return cib_NOTEXISTS); } else if(safe_str_eq(section, XML_CIB_TAG_STATUS)) { CRM_CHECK(node_uuid != NULL, return cib_NOTEXISTS); } rc = the_cib->cmds->query(the_cib, section, &xml_search, cib_sync_call|cib_scope_local); if(rc != cib_ok) { attr_msg(LOG_ERR, "Query failed for attribute %s (section=%s, node=%s, set=%s): %s", attr_name, section, crm_str(set_name), crm_str(node_uuid), cib_error2string(rc)); return rc; } rc = find_attr_details( xml_search, node_uuid, set_name, attr_id, attr_name, &xml_obj, to_console); free_xml(xml_search); if(rc == cib_missing_data) { return rc; } if(xml_obj != NULL) { local_attr_id = crm_strdup(ID(xml_obj)); attr_id = local_attr_id; } if(attr_id == NULL || xml_obj == NULL) { attr_common_setup(section); CRM_CHECK(attr_id != NULL, crm_free(local_attr_id); free_xml(xml_obj); return cib_missing); CRM_CHECK(set_name != NULL, crm_free(local_attr_id); free_xml(xml_obj); return cib_missing); if(attr_value == NULL) { crm_free(local_attr_id); free_xml(xml_obj); return cib_missing_data; } if(is_node_transient) { xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_STATE); crm_xml_add(xml_obj, XML_ATTR_ID, node_uuid); if(xml_top == NULL) { xml_top = xml_obj; } } crm_debug_2("Creating %s/%s", section, tag); if(tag != NULL) { xml_obj = create_xml_node(xml_obj, tag); crm_xml_add(xml_obj, XML_ATTR_ID, node_uuid); if(xml_top == NULL) { xml_top = xml_obj; } } if(node_uuid == NULL) { xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_PROPSET); } else { xml_obj = create_xml_node(xml_obj, XML_TAG_ATTR_SETS); } crm_xml_add(xml_obj, XML_ATTR_ID, set_name); if(xml_top == NULL) { xml_top = xml_obj; } xml_obj = create_xml_node(xml_obj, XML_TAG_ATTRS); crm_free(local_set_name); } else { free_xml(xml_obj); xml_obj = NULL; } xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_NVPAIR); if(xml_top == NULL) { xml_top = xml_obj; } crm_xml_add(xml_obj, XML_ATTR_ID, attr_id); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, attr_value); crm_log_xml_debug_2(xml_top, "update_attr"); rc = the_cib->cmds->modify(the_cib, section, xml_top, NULL, call_options|cib_quorum_override); if(rc == cib_diff_resync) { /* this is an internal matter - the update succeeded */ rc = cib_ok; } if(rc < cib_ok) { attr_msg(LOG_ERR, "Error setting %s=%s (section=%s, set=%s): %s", attr_name, attr_value, section, crm_str(set_name), cib_error2string(rc)); crm_log_xml_info(xml_top, "Update"); } crm_free(local_attr_id); free_xml(xml_top); return rc; } enum cib_errors read_attr(cib_t *the_cib, const char *section, const char *node_uuid, const char *set_name, const char *attr_id, const char *attr_name, char **attr_value, gboolean to_console) { enum cib_errors rc = cib_ok; - crm_data_t *xml_obj = NULL; - crm_data_t *xml_next = NULL; - crm_data_t *fragment = NULL; + xmlNode *xml_obj = NULL; + xmlNode *xml_next = NULL; + xmlNode *fragment = NULL; CRM_CHECK(section != NULL, return cib_missing); CRM_CHECK(attr_name != NULL || attr_id != NULL, return cib_missing); if(safe_str_eq(section, XML_CIB_TAG_CRMCONFIG)) { node_uuid = NULL; } else if(safe_str_eq(section, XML_CIB_TAG_NODES)) { CRM_CHECK(node_uuid != NULL, return cib_NOTEXISTS); } else if(safe_str_eq(section, XML_CIB_TAG_STATUS)) { CRM_CHECK(node_uuid != NULL, return cib_NOTEXISTS); } CRM_ASSERT(attr_value != NULL); *attr_value = NULL; crm_debug("Searching for attribute %s (section=%s, node=%s, set=%s)", attr_name, section, crm_str(node_uuid), crm_str(set_name)); rc = the_cib->cmds->query( the_cib, section, &fragment, cib_sync_call|cib_scope_local); if(rc != cib_ok) { attr_msg(LOG_ERR, "Query failed for attribute %s (section=%s, node=%s, set=%s): %s", attr_name, section, crm_str(set_name), crm_str(node_uuid), cib_error2string(rc)); return rc; } #if CRM_DEPRECATED_SINCE_2_0_4 if(safe_str_eq(crm_element_name(fragment), section)) { xml_obj = fragment; } else { - crm_data_t *a_node = NULL; + xmlNode *a_node = NULL; a_node = find_xml_node(fragment, XML_TAG_CIB, TRUE); xml_obj = get_object_root(section, a_node); } #else xml_obj = fragment; CRM_CHECK(safe_str_eq(crm_element_name(xml_obj), section), return cib_output_data); #endif CRM_ASSERT(xml_obj != NULL); crm_log_xml_debug_2(xml_obj, "Result section"); rc = find_attr_details( xml_obj, node_uuid, set_name, attr_id, attr_name, &xml_next, to_console); free_xml(fragment); if(rc == cib_missing_data) { return rc; } if(xml_next != NULL) { *attr_value = crm_element_value_copy( xml_next, XML_NVPAIR_ATTR_VALUE); } return xml_next == NULL?cib_NOTEXISTS:cib_ok; } enum cib_errors delete_attr(cib_t *the_cib, int options, const char *section, const char *node_uuid, const char *set_name, const char *attr_id, const char *attr_name, const char *attr_value, gboolean to_console) { enum cib_errors rc = cib_ok; - crm_data_t *xml_obj = NULL; - crm_data_t *xml_search = NULL; + xmlNode *xml_obj = NULL; + xmlNode *xml_search = NULL; char *local_attr_id = NULL; CRM_CHECK(section != NULL, return cib_missing); CRM_CHECK(attr_name != NULL || attr_id != NULL, return cib_missing); if(safe_str_eq(section, XML_CIB_TAG_CRMCONFIG)) { node_uuid = NULL; } else if(safe_str_eq(section, XML_CIB_TAG_NODES)) { CRM_CHECK(node_uuid != NULL, return cib_NOTEXISTS); } else if(safe_str_eq(section, XML_CIB_TAG_STATUS)) { CRM_CHECK(node_uuid != NULL, return cib_NOTEXISTS); } if(attr_id == NULL || attr_value != NULL) { rc = the_cib->cmds->query(the_cib, section, &xml_search, cib_sync_call|cib_scope_local); if(rc != cib_ok) { attr_msg(LOG_ERR, "Query failed for section=%s of the CIB: %s", section, cib_error2string(rc)); return rc; } rc = find_attr_details( xml_search, node_uuid, set_name, attr_id, attr_name, &xml_obj, to_console); free_xml(xml_search); if(rc == cib_missing_data) { return rc; } if(xml_obj != NULL) { if(attr_value != NULL) { const char *current = crm_element_value(xml_obj, XML_NVPAIR_ATTR_VALUE); if(safe_str_neq(attr_value, current)) { return cib_NOTEXISTS; } } local_attr_id = crm_strdup(ID(xml_obj)); attr_id = local_attr_id; xml_obj = NULL; } } if(attr_id == NULL) { return cib_NOTEXISTS; } xml_obj = create_xml_node(NULL, XML_CIB_TAG_NVPAIR); crm_xml_add(xml_obj, XML_ATTR_ID, attr_id); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, attr_value); rc = the_cib->cmds->delete( the_cib, section, xml_obj, NULL, options|cib_quorum_override); crm_free(local_attr_id); free_xml(xml_obj); return rc; } enum cib_errors query_node_uuid(cib_t *the_cib, const char *uname, char **uuid) { enum cib_errors rc = cib_ok; - crm_data_t *xml_obj = NULL; - crm_data_t *fragment = NULL; + xmlNode *xml_obj = NULL; + xmlNode *fragment = NULL; const char *child_name = NULL; CRM_ASSERT(uname != NULL); CRM_ASSERT(uuid != NULL); rc = the_cib->cmds->query(the_cib, XML_CIB_TAG_NODES, &fragment, cib_sync_call|cib_scope_local); if(rc != cib_ok) { return rc; } #if CRM_DEPRECATED_SINCE_2_0_4 if(safe_str_eq(crm_element_name(fragment), XML_CIB_TAG_NODES)) { xml_obj = fragment; } else { xml_obj = find_xml_node(fragment, XML_TAG_CIB, TRUE); xml_obj = get_object_root(XML_CIB_TAG_NODES, xml_obj); } #else xml_obj = fragment; CRM_CHECK(safe_str_eq(crm_element_name(xml_obj), XML_CIB_TAG_NODES), return cib_output_data); #endif CRM_ASSERT(xml_obj != NULL); crm_log_xml_debug(xml_obj, "Result section"); rc = cib_NOTEXISTS; *uuid = NULL; xml_child_iter_filter( xml_obj, a_child, XML_CIB_TAG_NODE, child_name = crm_element_value(a_child, XML_ATTR_UNAME); if(safe_str_eq(uname, child_name)) { child_name = ID(a_child); if(child_name != NULL) { *uuid = crm_strdup(child_name); rc = cib_ok; } break; } ); free_xml(fragment); return rc; } enum cib_errors query_node_uname(cib_t *the_cib, const char *uuid, char **uname) { enum cib_errors rc = cib_ok; - crm_data_t *xml_obj = NULL; - crm_data_t *fragment = NULL; + xmlNode *xml_obj = NULL; + xmlNode *fragment = NULL; const char *child_name = NULL; CRM_ASSERT(uname != NULL); CRM_ASSERT(uuid != NULL); rc = the_cib->cmds->query(the_cib, XML_CIB_TAG_NODES, &fragment, cib_sync_call|cib_scope_local); if(rc != cib_ok) { return rc; } #if CRM_DEPRECATED_SINCE_2_0_4 if(safe_str_eq(crm_element_name(fragment), XML_CIB_TAG_NODES)) { xml_obj = fragment; } else { xml_obj = find_xml_node(fragment, XML_TAG_CIB, TRUE); xml_obj = get_object_root(XML_CIB_TAG_NODES, xml_obj); } #else xml_obj = fragment; CRM_CHECK(safe_str_eq(crm_element_name(xml_obj), XML_CIB_TAG_NODES), return cib_output_data); #endif CRM_ASSERT(xml_obj != NULL); crm_log_xml_debug_2(xml_obj, "Result section"); rc = cib_NOTEXISTS; *uname = NULL; xml_child_iter_filter( xml_obj, a_child, XML_CIB_TAG_NODE, child_name = ID(a_child); if(safe_str_eq(uuid, child_name)) { child_name = crm_element_value(a_child, XML_ATTR_UNAME); if(child_name != NULL) { *uname = crm_strdup(child_name); rc = cib_ok; } break; } ); free_xml(fragment); return rc; } #define standby_common char *attr_id = NULL; \ int str_length = 3; \ char *set_name = NULL; \ const char *attr_name = "standby"; \ \ CRM_CHECK(uuid != NULL, return cib_missing_data); \ str_length += strlen(attr_name); \ str_length += strlen(uuid); \ if(safe_str_eq(type, "reboot") \ || safe_str_eq(type, XML_CIB_TAG_STATUS)) { \ const char *extra = "transient"; \ type = XML_CIB_TAG_STATUS; \ str_length += strlen(extra); \ crm_malloc0(attr_id, str_length); \ sprintf(attr_id, "%s-%s-%s", extra, attr_name, uuid); \ \ } else { \ crm_malloc0(attr_id, str_length); \ sprintf(attr_id, "%s-%s", attr_name, uuid); \ } enum cib_errors query_standby(cib_t *the_cib, const char *uuid, char **scope, char **standby_value) { enum cib_errors rc = cib_ok; CRM_CHECK(standby_value != NULL, return cib_missing_data); CRM_CHECK(scope != NULL, return cib_missing_data); if(*scope != NULL) { const char *type = *scope; standby_common; rc = read_attr(the_cib, type, uuid, set_name, attr_id, attr_name, standby_value, TRUE); crm_free(attr_id); crm_free(set_name); } else { *scope = crm_strdup(XML_CIB_TAG_NODES); rc = query_standby(the_cib, uuid, scope, standby_value); if(rc == cib_NOTEXISTS) { crm_free(*scope); *scope = crm_strdup(XML_CIB_TAG_STATUS); crm_debug("No standby value found with " "lifetime=forever, checking lifetime=reboot"); rc = query_standby(the_cib, uuid, scope, standby_value); } } return rc; } enum cib_errors set_standby(cib_t *the_cib, const char *uuid, const char *scope, const char *standby_value) { enum cib_errors rc = cib_ok; CRM_CHECK(standby_value != NULL, return cib_missing_data); if(scope != NULL) { const char *type = scope; standby_common; rc = update_attr(the_cib, cib_sync_call, type, uuid, set_name, attr_id, attr_name, standby_value, TRUE); crm_free(attr_id); crm_free(set_name); } else { rc = set_standby(the_cib, uuid, XML_CIB_TAG_NODES, standby_value); } return rc; } enum cib_errors delete_standby(cib_t *the_cib, const char *uuid, const char *scope, const char *standby_value) { enum cib_errors rc = cib_ok; if(scope != NULL) { const char *type = scope; standby_common; rc = delete_attr(the_cib, cib_sync_call, type, uuid, set_name, attr_id, attr_name, standby_value, TRUE); crm_free(attr_id); crm_free(set_name); } else { rc = delete_standby( the_cib, uuid, XML_CIB_TAG_STATUS, standby_value); rc = delete_standby( the_cib, uuid, XML_CIB_TAG_NODES, standby_value); } return rc; } diff --git a/lib/crm/cib/cib_client.c b/lib/crm/cib/cib_client.c index 263fd849ac..770cc12172 100644 --- a/lib/crm/cib/cib_client.c +++ b/lib/crm/cib/cib_client.c @@ -1,1654 +1,1654 @@ /* * Copyright (c) 2004 International Business Machines * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser 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 library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* short term hack to reduce callback messages */ typedef struct cib_native_opaque_s { IPC_Channel *command_channel; IPC_Channel *callback_channel; GCHSource *callback_source; } cib_native_opaque_t; GHashTable *cib_op_callback_table = NULL; gboolean verify_cib_cmds(cib_t *cib); int cib_client_set_op_callback( - cib_t *cib, void (*callback)(const struct ha_msg *msg, int call_id, - int rc, crm_data_t *output)); + cib_t *cib, void (*callback)(const xmlNode *msg, int call_id, + int rc, xmlNode *output)); int cib_client_noop(cib_t *cib, int call_options); -int cib_client_ping(cib_t *cib, crm_data_t **output_data, int call_options); +int cib_client_ping(cib_t *cib, xmlNode **output_data, int call_options); int cib_client_query(cib_t *cib, const char *section, - crm_data_t **output_data, int call_options); + xmlNode **output_data, int call_options); int cib_client_query_from(cib_t *cib, const char *host, const char *section, - crm_data_t **output_data, int call_options); + xmlNode **output_data, int call_options); int cib_client_sync(cib_t *cib, const char *section, int call_options); int cib_client_sync_from( cib_t *cib, const char *host, const char *section, int call_options); int cib_client_is_master(cib_t *cib); int cib_client_set_slave(cib_t *cib, int call_options); int cib_client_set_slave_all(cib_t *cib, int call_options); int cib_client_set_master(cib_t *cib, int call_options); int cib_client_bump_epoch(cib_t *cib, int call_options); -int cib_client_create(cib_t *cib, const char *section, crm_data_t *data, - crm_data_t **output_data, int call_options); -int cib_client_modify(cib_t *cib, const char *section, crm_data_t *data, - crm_data_t **output_data, int call_options); -int cib_client_update(cib_t *cib, const char *section, crm_data_t *data, - crm_data_t **output_data, int call_options); -int cib_client_replace(cib_t *cib, const char *section, crm_data_t *data, - crm_data_t **output_data, int call_options); -int cib_client_delete(cib_t *cib, const char *section, crm_data_t *data, - crm_data_t **output_data, int call_options); +int cib_client_create(cib_t *cib, const char *section, xmlNode *data, + xmlNode **output_data, int call_options); +int cib_client_modify(cib_t *cib, const char *section, xmlNode *data, + xmlNode **output_data, int call_options); +int cib_client_update(cib_t *cib, const char *section, xmlNode *data, + xmlNode **output_data, int call_options); +int cib_client_replace(cib_t *cib, const char *section, xmlNode *data, + xmlNode **output_data, int call_options); +int cib_client_delete(cib_t *cib, const char *section, xmlNode *data, + xmlNode **output_data, int call_options); int cib_client_delete_absolute( - cib_t *cib, const char *section, crm_data_t *data, - crm_data_t **output_data, int call_options); + cib_t *cib, const char *section, xmlNode *data, + xmlNode **output_data, int call_options); int cib_client_erase( - cib_t *cib, crm_data_t **output_data, int call_options); + cib_t *cib, xmlNode **output_data, int call_options); int cib_client_quit(cib_t *cib, int call_options); int cib_client_add_notify_callback( cib_t *cib, const char *event, void (*callback)( - const char *event, struct ha_msg *msg)); + const char *event, xmlNode *msg)); int cib_client_del_notify_callback( cib_t *cib, const char *event, void (*callback)( - const char *event, struct ha_msg *msg)); + const char *event, xmlNode *msg)); gint ciblib_GCompareFunc(gconstpointer a, gconstpointer b); extern cib_t *cib_native_new(cib_t *cib); extern void cib_native_delete(cib_t *cib); static enum cib_variant configured_variant = cib_native; static void cib_destroy_op_callback(gpointer data) { cib_callback_client_t *blob = data; if(blob->timer && blob->timer->ref > 0) { g_source_remove(blob->timer->ref); } crm_free(blob); } /* define of the api functions*/ cib_t* cib_new(void) { cib_t* new_cib = NULL; if(configured_variant != cib_native) { crm_err("Only the native CIB type is currently implemented"); return NULL; } if(cib_op_callback_table != NULL) { g_hash_table_destroy(cib_op_callback_table); cib_op_callback_table = NULL; } if(cib_op_callback_table == NULL) { cib_op_callback_table = g_hash_table_new_full( g_direct_hash, g_direct_equal, NULL, cib_destroy_op_callback); } crm_malloc0(new_cib, sizeof(cib_t)); new_cib->call_id = 1; new_cib->type = cib_none; new_cib->state = cib_disconnected; new_cib->op_callback = NULL; new_cib->variant_opaque = NULL; new_cib->notify_list = NULL; /* the rest will get filled in by the variant constructor */ crm_malloc0(new_cib->cmds, sizeof(cib_api_operations_t)); new_cib->cmds->set_op_callback = cib_client_set_op_callback; new_cib->cmds->add_notify_callback = cib_client_add_notify_callback; new_cib->cmds->del_notify_callback = cib_client_del_notify_callback; new_cib->cmds->noop = cib_client_noop; new_cib->cmds->ping = cib_client_ping; new_cib->cmds->query = cib_client_query; new_cib->cmds->sync = cib_client_sync; new_cib->cmds->query_from = cib_client_query_from; new_cib->cmds->sync_from = cib_client_sync_from; new_cib->cmds->is_master = cib_client_is_master; new_cib->cmds->set_master = cib_client_set_master; new_cib->cmds->set_slave = cib_client_set_slave; new_cib->cmds->set_slave_all = cib_client_set_slave_all; new_cib->cmds->bump_epoch = cib_client_bump_epoch; new_cib->cmds->create = cib_client_create; new_cib->cmds->modify = cib_client_modify; new_cib->cmds->update = cib_client_update; new_cib->cmds->replace = cib_client_replace; new_cib->cmds->delete = cib_client_delete; new_cib->cmds->erase = cib_client_erase; new_cib->cmds->quit = cib_client_quit; new_cib->cmds->delete_absolute = cib_client_delete_absolute; cib_native_new(new_cib); if(verify_cib_cmds(new_cib) == FALSE) { cib_delete(new_cib); return NULL; } return new_cib; } void cib_delete(cib_t *cib) { GList *list = cib->notify_list; while(list != NULL) { cib_notify_client_t *client = g_list_nth_data(list, 0); list = g_list_remove(list, client); crm_free(client); } cib_native_delete(cib); g_hash_table_destroy(cib_op_callback_table); crm_free(cib->cmds); crm_free(cib); } int cib_client_set_op_callback( - cib_t *cib, void (*callback)(const struct ha_msg *msg, int call_id, - int rc, crm_data_t *output)) + cib_t *cib, void (*callback)(const xmlNode *msg, int call_id, + int rc, xmlNode *output)) { if(callback == NULL) { crm_info("Un-Setting operation callback"); } else { crm_debug_3("Setting operation callback"); } cib->op_callback = callback; return cib_ok; } int cib_client_noop(cib_t *cib, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CRM_OP_NOOP, NULL, NULL, NULL, NULL, call_options); } -int cib_client_ping(cib_t *cib, crm_data_t **output_data, int call_options) +int cib_client_ping(cib_t *cib, xmlNode **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CRM_OP_PING, NULL,NULL,NULL, output_data, call_options); } int cib_client_query(cib_t *cib, const char *section, - crm_data_t **output_data, int call_options) + xmlNode **output_data, int call_options) { return cib->cmds->query_from( cib, NULL, section, output_data, call_options); } int cib_client_query_from(cib_t *cib, const char *host, const char *section, - crm_data_t **output_data, int call_options) + xmlNode **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op(cib, CIB_OP_QUERY, host, section, NULL, output_data, call_options); } int cib_client_is_master(cib_t *cib) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CIB_OP_ISMASTER, NULL, NULL,NULL,NULL, cib_scope_local|cib_sync_call); } int cib_client_set_slave(cib_t *cib, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CIB_OP_SLAVE, NULL,NULL,NULL,NULL, call_options); } int cib_client_set_slave_all(cib_t *cib, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CIB_OP_SLAVEALL, NULL,NULL,NULL,NULL, call_options); } int cib_client_set_master(cib_t *cib, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } crm_debug_3("Adding cib_scope_local to options"); return cib->cmds->variant_op( cib, CIB_OP_MASTER, NULL,NULL,NULL,NULL, call_options|cib_scope_local); } int cib_client_bump_epoch(cib_t *cib, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CIB_OP_BUMP, NULL, NULL, NULL, NULL, call_options); } int cib_client_sync(cib_t *cib, const char *section, int call_options) { return cib->cmds->sync_from(cib, NULL, section, call_options); } int cib_client_sync_from( cib_t *cib, const char *host, const char *section, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CIB_OP_SYNC, host, section, NULL, NULL, call_options); } -int cib_client_create(cib_t *cib, const char *section, crm_data_t *data, - crm_data_t **output_data, int call_options) +int cib_client_create(cib_t *cib, const char *section, xmlNode *data, + xmlNode **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op(cib, CIB_OP_CREATE, NULL, section, data, output_data, call_options); } -int cib_client_modify(cib_t *cib, const char *section, crm_data_t *data, - crm_data_t **output_data, int call_options) +int cib_client_modify(cib_t *cib, const char *section, xmlNode *data, + xmlNode **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op(cib, CIB_OP_MODIFY, NULL, section, data, output_data, call_options); } -int cib_client_update(cib_t *cib, const char *section, crm_data_t *data, - crm_data_t **output_data, int call_options) +int cib_client_update(cib_t *cib, const char *section, xmlNode *data, + xmlNode **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op(cib, CIB_OP_UPDATE, NULL, section, data, output_data, call_options); } -int cib_client_replace(cib_t *cib, const char *section, crm_data_t *data, - crm_data_t **output_data, int call_options) +int cib_client_replace(cib_t *cib, const char *section, xmlNode *data, + xmlNode **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } else if(data == NULL) { return cib_missing_data; } return cib->cmds->variant_op(cib, CIB_OP_REPLACE, NULL, section, data, output_data, call_options); } -int cib_client_delete(cib_t *cib, const char *section, crm_data_t *data, - crm_data_t **output_data, int call_options) +int cib_client_delete(cib_t *cib, const char *section, xmlNode *data, + xmlNode **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op(cib, CIB_OP_DELETE, NULL, section, data, output_data, call_options); } int cib_client_delete_absolute( - cib_t *cib, const char *section, crm_data_t *data, - crm_data_t **output_data, int call_options) + cib_t *cib, const char *section, xmlNode *data, + xmlNode **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op(cib, CIB_OP_DELETE_ALT, NULL, section, data, output_data, call_options); } int cib_client_erase( - cib_t *cib, crm_data_t **output_data, int call_options) + cib_t *cib, xmlNode **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op(cib, CIB_OP_ERASE, NULL, NULL, NULL, output_data, call_options); } int cib_client_quit(cib_t *cib, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CRM_OP_QUIT, NULL, NULL, NULL, NULL, call_options); } int cib_client_add_notify_callback( cib_t *cib, const char *event, void (*callback)( - const char *event, struct ha_msg *msg)) + const char *event, xmlNode *msg)) { GList *list_item = NULL; cib_notify_client_t *new_client = NULL; crm_debug_2("Adding callback for %s events (%d)", event, g_list_length(cib->notify_list)); crm_malloc0(new_client, sizeof(cib_notify_client_t)); new_client->event = event; new_client->callback = callback; list_item = g_list_find_custom( cib->notify_list, new_client, ciblib_GCompareFunc); if(list_item != NULL) { crm_warn("Callback already present"); crm_free(new_client); } else { cib->notify_list = g_list_append( cib->notify_list, new_client); cib->cmds->register_callback(cib, event, 1); crm_debug_3("Callback added (%d)", g_list_length(cib->notify_list)); } return cib_ok; } int cib_client_del_notify_callback( cib_t *cib, const char *event, void (*callback)( - const char *event, struct ha_msg *msg)) + const char *event, xmlNode *msg)) { GList *list_item = NULL; cib_notify_client_t *new_client = NULL; crm_debug("Removing callback for %s events", event); crm_malloc0(new_client, sizeof(cib_notify_client_t)); new_client->event = event; new_client->callback = callback; list_item = g_list_find_custom( cib->notify_list, new_client, ciblib_GCompareFunc); cib->cmds->register_callback(cib, event, 0); if(list_item != NULL) { cib_notify_client_t *list_client = list_item->data; cib->notify_list = g_list_remove(cib->notify_list, list_client); crm_free(list_client); crm_debug_3("Removed callback"); } else { crm_debug_3("Callback not present"); } crm_free(new_client); return cib_ok; } gint ciblib_GCompareFunc(gconstpointer a, gconstpointer b) { const cib_notify_client_t *a_client = a; const cib_notify_client_t *b_client = b; if(a_client->callback == b_client->callback && safe_str_neq(a_client->event, b_client->event)) { return 0; } else if(((long)a_client->callback) < ((long)b_client->callback)) { return -1; } return 1; } static gboolean cib_async_timeout_handler(gpointer data) { struct timer_rec_s *timer = data; int call_id = timer->call_id; cib_callback_client_t *blob = NULL; crm_err("Async call %d timed out after %ds", call_id, timer->timeout); /* Send an async reply with rc=cib_remote_timeout */ blob = g_hash_table_lookup(cib_op_callback_table, GINT_TO_POINTER(call_id)); if(blob != NULL && blob->callback != NULL) { crm_debug_3("Callback found for call %d", call_id); blob->callback(NULL, call_id, cib_remote_timeout, NULL, blob->user_data); } remove_cib_op_callback(timer->call_id, FALSE); /* Always return TRUE, never remove the handler * We do that in remove_cib_op_callback() */ return TRUE; } gboolean add_cib_op_callback( int call_id, gboolean only_success, void *user_data, - void (*callback)(const HA_Message*, int, int, crm_data_t*,void*)) + void (*callback)(xmlNode*, int, int, xmlNode*,void*)) { return add_cib_op_callback_timeout(call_id, 1, only_success, user_data, callback); } gboolean add_cib_op_callback_timeout( int call_id, int timeout, gboolean only_success, void *user_data, - void (*callback)(const HA_Message*, int, int, crm_data_t*,void*)) + void (*callback)(xmlNode*, int, int, xmlNode*,void*)) { cib_callback_client_t *blob = NULL; if(call_id < 0) { crm_warn("CIB call failed: %s", cib_error2string(call_id)); if(only_success == FALSE) { callback(NULL, call_id, call_id, NULL, user_data); } return FALSE; } crm_malloc0(blob, sizeof(cib_callback_client_t)); blob->only_success = only_success; blob->user_data = user_data; blob->callback = callback; if(timeout > 0) { struct timer_rec_s *async_timer = NULL; crm_malloc0(async_timer, sizeof(struct timer_rec_s)); blob->timer = async_timer; async_timer->call_id = call_id; async_timer->timeout = timeout*1000; async_timer->ref = Gmain_timeout_add( async_timer->timeout, cib_async_timeout_handler, async_timer); } g_hash_table_insert(cib_op_callback_table, GINT_TO_POINTER(call_id), blob); return TRUE; } void remove_cib_op_callback(int call_id, gboolean all_callbacks) { if(all_callbacks) { if(cib_op_callback_table != NULL) { g_hash_table_destroy(cib_op_callback_table); } cib_op_callback_table = g_hash_table_new_full( g_direct_hash, g_direct_equal, NULL, cib_destroy_op_callback); } else { g_hash_table_remove( cib_op_callback_table, GINT_TO_POINTER(call_id)); } } int num_cib_op_callbacks(void) { if(cib_op_callback_table == NULL) { return 0; } return g_hash_table_size(cib_op_callback_table); } char * cib_pluralSection(const char *a_section) { char *a_section_parent = NULL; if (a_section == NULL) { a_section_parent = crm_strdup("all"); } else if(strcasecmp(a_section, XML_TAG_CIB) == 0) { a_section_parent = crm_strdup("all"); } else if(strcasecmp(a_section, XML_CIB_TAG_NODE) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_NODES); } else if(strcasecmp(a_section, XML_CIB_TAG_STATE) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_STATUS); } else if(strcasecmp(a_section, XML_CIB_TAG_CONSTRAINT) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS); } else if(strcasecmp(a_section, XML_CONS_TAG_RSC_LOCATION) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS); } else if(strcasecmp(a_section, XML_CONS_TAG_RSC_DEPEND) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS); } else if(strcasecmp(a_section, XML_CONS_TAG_RSC_ORDER) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS); } else if(strcasecmp(a_section, "resource") == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES); } else if(strcasecmp(a_section, XML_CIB_TAG_RESOURCE) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES); } else if(strcasecmp(a_section, XML_CIB_TAG_GROUP) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES); } else if(strcasecmp(a_section, XML_CIB_TAG_INCARNATION) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES); } else if(strcasecmp(a_section, XML_CIB_TAG_NVPAIR) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_CRMCONFIG); } else if(strcasecmp(a_section, XML_TAG_ATTR_SETS) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_CRMCONFIG); } else { crm_err("Unknown section %s", a_section); a_section_parent = crm_strdup("all"); } crm_debug_2("Plural of %s is %s", crm_str(a_section), a_section_parent); return a_section_parent; } const char * cib_error2string(enum cib_errors return_code) { const char *error_msg = NULL; switch(return_code) { case cib_bad_permissions: error_msg = "bad permissions for the on-disk configuration. shutdown heartbeat and repair."; break; case cib_bad_digest: error_msg = "the on-disk configuration was manually altered. shutdown heartbeat and repair."; break; case cib_bad_config: error_msg = "the on-disk configuration is not valid"; break; case cib_msg_field_add: error_msg = "failed adding field to cib message"; break; case cib_id_check: error_msg = "missing id or id-collision detected"; break; case cib_operation: error_msg = "invalid operation"; break; case cib_create_msg: error_msg = "couldnt create cib message"; break; case cib_client_gone: error_msg = "client left before we could send reply"; break; case cib_not_connected: error_msg = "not connected"; break; case cib_not_authorized: error_msg = "not authorized"; break; case cib_send_failed: error_msg = "send failed"; break; case cib_reply_failed: error_msg = "reply failed"; break; case cib_return_code: error_msg = "no return code"; break; case cib_output_ptr: error_msg = "nowhere to store output"; break; case cib_output_data: error_msg = "corrupt output data"; break; case cib_connection: error_msg = "connection failed"; break; case cib_callback_register: error_msg = "couldnt register callback channel"; break; case cib_authentication: error_msg = ""; break; case cib_registration_msg: error_msg = "invalid registration msg"; break; case cib_callback_token: error_msg = "callback token not found"; break; case cib_missing: error_msg = "cib object missing"; break; case cib_variant: error_msg = "unknown/corrupt cib variant"; break; case CIBRES_MISSING_ID: error_msg = "The id field is missing"; break; case CIBRES_MISSING_TYPE: error_msg = "The type field is missing"; break; case CIBRES_MISSING_FIELD: error_msg = "A required field is missing"; break; case CIBRES_OBJTYPE_MISMATCH: error_msg = "CIBRES_OBJTYPE_MISMATCH"; break; case cib_EXISTS: error_msg = "The object already exists"; break; case cib_NOTEXISTS: error_msg = "The object/attribute does not exist"; break; case CIBRES_CORRUPT: error_msg = "The CIB is corrupt"; break; case cib_NOOBJECT: error_msg = "The update was empty"; break; case cib_NOPARENT: error_msg = "The parent object does not exist"; break; case cib_NODECOPY: error_msg = "Failed while copying update"; break; case CIBRES_OTHER: error_msg = "CIBRES_OTHER"; break; case cib_ok: error_msg = "ok"; break; case cib_unknown: error_msg = "Unknown error"; break; case cib_STALE: error_msg = "Discarded old update"; break; case cib_ACTIVATION: error_msg = "Activation Failed"; break; case cib_NOSECTION: error_msg = "Required section was missing"; break; case cib_NOTSUPPORTED: error_msg = "Supplied information is not supported"; break; case cib_not_master: error_msg = "Local service is not the master instance"; break; case cib_client_corrupt: error_msg = "Service client not valid"; break; case cib_remote_timeout: error_msg = "Remote node did not respond"; break; case cib_master_timeout: error_msg = "No master service is currently active"; break; case cib_revision_unsupported: error_msg = "The required CIB revision number is not supported"; break; case cib_revision_unknown: error_msg = "The CIB revision number could not be determined"; break; case cib_missing_data: error_msg = "Required data for this CIB API call not found"; break; case cib_no_quorum: error_msg = "Write requires quorum"; break; case cib_diff_failed: error_msg = "Application of an update diff failed"; break; case cib_diff_resync: error_msg = "Application of an update diff failed, requesting a full refresh"; break; case cib_bad_section: error_msg = "Invalid CIB section specified"; break; case cib_old_data: error_msg = "Update was older than existing configuration"; break; case cib_dtd_validation: error_msg = "Update does not conform to the DTD in "DTD_DIRECTORY"/crm.dtd"; break; case cib_invalid_argument: error_msg = "Invalid argument"; break; } if(error_msg == NULL) { crm_err("Unknown CIB Error Code: %d", return_code); error_msg = ""; } return error_msg; } const char * cib_op2string(enum cib_update_op operation) { const char *operation_msg = NULL; switch(operation) { case 0: operation_msg = "none"; break; case 1: operation_msg = "add"; break; case 2: operation_msg = "modify"; break; case 3: operation_msg = "delete"; break; case CIB_UPDATE_OP_MAX: operation_msg = "invalid operation"; break; } if(operation_msg == NULL) { crm_err("Unknown CIB operation %d", operation); operation_msg = ""; } return operation_msg; } int cib_section2enum(const char *a_section) { if(a_section == NULL || strcasecmp(a_section, "all") == 0) { return cib_section_all; } else if(strcasecmp(a_section, XML_CIB_TAG_NODES) == 0) { return cib_section_nodes; } else if(strcasecmp(a_section, XML_CIB_TAG_STATUS) == 0) { return cib_section_status; } else if(strcasecmp(a_section, XML_CIB_TAG_CONSTRAINTS) == 0) { return cib_section_constraints; } else if(strcasecmp(a_section, XML_CIB_TAG_RESOURCES) == 0) { return cib_section_resources; } else if(strcasecmp(a_section, XML_CIB_TAG_CRMCONFIG) == 0) { return cib_section_crmconfig; } crm_err("Unknown CIB section: %s", a_section); return cib_section_none; } int -cib_compare_generation(crm_data_t *left, crm_data_t *right) +cib_compare_generation(xmlNode *left, xmlNode *right) { int lpc = 0; const char *attributes[] = { XML_ATTR_GENERATION_ADMIN, XML_ATTR_GENERATION, XML_ATTR_NUMUPDATES, XML_ATTR_NUMPEERS }; crm_log_xml_debug_3(left, "left"); crm_log_xml_debug_3(right, "right"); for(lpc = 0; lpc < DIMOF(attributes); lpc++) { int int_elem_l = -1; int int_elem_r = -1; const char *elem_r = NULL; const char *elem_l = crm_element_value(left, attributes[lpc]); if(right != NULL) { elem_r = crm_element_value(right, attributes[lpc]); } if(elem_l != NULL) { int_elem_l = crm_parse_int(elem_l, NULL); } if(elem_r != NULL) { int_elem_r = crm_parse_int(elem_r, NULL); } if(int_elem_l < int_elem_r) { crm_debug_2("%s (%s < %s)", attributes[lpc], crm_str(elem_l), crm_str(elem_r)); return -1; } else if(int_elem_l > int_elem_r) { crm_debug_2("%s (%s > %s)", attributes[lpc], crm_str(elem_l), crm_str(elem_r)); return 1; } } return 0; } -crm_data_t* +xmlNode* get_cib_copy(cib_t *cib) { - crm_data_t *xml_cib; + xmlNode *xml_cib; #if CRM_DEPRECATED_SINCE_2_0_4 - crm_data_t *xml_cib_copy; + xmlNode *xml_cib_copy; #endif int options = cib_scope_local|cib_sync_call; if(cib->cmds->query(cib, NULL, &xml_cib, options) != cib_ok) { crm_err("Couldnt retrieve the CIB"); return NULL; } else if(xml_cib == NULL) { crm_err("The CIB result was empty"); return NULL; } if(safe_str_eq(crm_element_name(xml_cib), XML_TAG_CIB)) { return xml_cib; #if CRM_DEPRECATED_SINCE_2_0_4 } else { xml_cib_copy = copy_xml( find_xml_node(xml_cib, XML_TAG_CIB, TRUE)); free_xml(xml_cib); return xml_cib_copy; #endif } free_xml(xml_cib); return NULL; } -crm_data_t* +xmlNode* cib_get_generation(cib_t *cib) { - crm_data_t *the_cib = get_cib_copy(cib); - crm_data_t *generation = create_xml_node( + xmlNode *the_cib = get_cib_copy(cib); + xmlNode *generation = create_xml_node( NULL, XML_CIB_TAG_GENERATION_TUPPLE); if(the_cib != NULL) { copy_in_properties(generation, the_cib); free_xml(the_cib); } return generation; } gboolean -apply_cib_diff(crm_data_t *old, crm_data_t *diff, crm_data_t **new) +apply_cib_diff(xmlNode *old, xmlNode *diff, xmlNode **new) { gboolean result = TRUE; const char *value = NULL; int this_updates = 0; int this_epoch = 0; int this_admin_epoch = 0; int diff_add_updates = 0; int diff_add_epoch = 0; int diff_add_admin_epoch = 0; int diff_del_updates = 0; int diff_del_epoch = 0; int diff_del_admin_epoch = 0; CRM_CHECK(diff != NULL, return FALSE); CRM_CHECK(old != NULL, return FALSE); value = crm_element_value(old, XML_ATTR_GENERATION_ADMIN); this_admin_epoch = crm_parse_int(value, "0"); crm_debug_3("%s=%d (%s)", XML_ATTR_GENERATION_ADMIN, this_admin_epoch, value); value = crm_element_value(old, XML_ATTR_GENERATION); this_epoch = crm_parse_int(value, "0"); crm_debug_3("%s=%d (%s)", XML_ATTR_GENERATION, this_epoch, value); value = crm_element_value(old, XML_ATTR_NUMUPDATES); this_updates = crm_parse_int(value, "0"); crm_debug_3("%s=%d (%s)", XML_ATTR_NUMUPDATES, this_updates, value); cib_diff_version_details( diff, &diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates, &diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates); value = NULL; if(result && diff_del_admin_epoch != this_admin_epoch) { value = XML_ATTR_GENERATION_ADMIN; result = FALSE; crm_debug_3("%s=%d", value, diff_del_admin_epoch); } else if(result && diff_del_epoch != this_epoch) { value = XML_ATTR_GENERATION; result = FALSE; crm_debug_3("%s=%d", value, diff_del_epoch); } else if(result && diff_del_updates != this_updates) { value = XML_ATTR_NUMUPDATES; result = FALSE; crm_debug_3("%s=%d", value, diff_del_updates); } if(result) { - int len = 0; - crm_data_t *tmp = NULL; - crm_data_t *diff_copy = copy_xml(diff); + xmlNode *tmp = NULL; + xmlNode *diff_copy = copy_xml(diff); tmp = find_xml_node(diff_copy, "diff-removed", TRUE); if(tmp != NULL) { - len = tmp->nfields; - cl_msg_remove(tmp, XML_ATTR_GENERATION_ADMIN); - cl_msg_remove(tmp, XML_ATTR_GENERATION); - cl_msg_remove(tmp, XML_ATTR_NUMUPDATES); + xml_remove_prop(tmp, XML_ATTR_GENERATION_ADMIN); + xml_remove_prop(tmp, XML_ATTR_GENERATION); + xml_remove_prop(tmp, XML_ATTR_NUMUPDATES); } tmp = find_xml_node(diff_copy, "diff-added", TRUE); if(tmp != NULL) { - len = tmp->nfields; - cl_msg_remove(tmp, XML_ATTR_GENERATION_ADMIN); - cl_msg_remove(tmp, XML_ATTR_GENERATION); - cl_msg_remove(tmp, XML_ATTR_NUMUPDATES); + xml_remove_prop(tmp, XML_ATTR_GENERATION_ADMIN); + xml_remove_prop(tmp, XML_ATTR_GENERATION); + xml_remove_prop(tmp, XML_ATTR_NUMUPDATES); } result = apply_xml_diff(old, diff_copy, new); free_xml(diff_copy); } else { crm_err("target and diff %s values didnt match", value); } return result; } -gboolean xml_has_child(crm_data_t *data, const char *name); +gboolean xml_has_child(xmlNode *data, const char *name); gboolean -xml_has_child(crm_data_t *data, const char *name) +xml_has_child(xmlNode *data, const char *name) { xml_child_iter_filter(data, child, name, return TRUE; ); return FALSE; } gboolean -cib_config_changed(crm_data_t *old_cib, crm_data_t *new_cib, crm_data_t **result) +cib_config_changed(xmlNode *old_cib, xmlNode *new_cib, xmlNode **result) { gboolean config_changes = FALSE; const char *tag = NULL; - crm_data_t *diff = NULL; - crm_data_t *dest = NULL; + xmlNode *diff = NULL; + xmlNode *dest = NULL; if(result) { *result = NULL; } diff = diff_xml_object(old_cib, new_cib, FALSE); if(diff == NULL) { return FALSE; } tag = "diff-removed"; dest = find_xml_node(diff, tag, FALSE); if(dest) { dest = find_xml_node(dest, "cib", FALSE); } if(dest) { if(xml_has_child(dest, "status")) { - cl_msg_remove(dest, "status"); + xmlNode *status = first_named_child(dest, "status"); + free_xml(status); } if(xml_has_children(dest)) { config_changes = TRUE; } } tag = "diff-added"; dest = find_xml_node(diff, tag, FALSE); if(dest) { dest = find_xml_node(dest, "cib", FALSE); } if(dest) { if(xml_has_child(dest, "status")) { - cl_msg_remove(dest, "status"); + xmlNode *status = first_named_child(dest, "status"); + free_xml(status); } xml_prop_iter(dest, name, value, config_changes = TRUE); if(xml_has_children(dest)) { config_changes = TRUE; } } if(result) { *result = diff; } else { free_xml(diff); } return config_changes; } -crm_data_t * -diff_cib_object(crm_data_t *old_cib, crm_data_t *new_cib, gboolean suppress) +xmlNode * +diff_cib_object(xmlNode *old_cib, xmlNode *new_cib, gboolean suppress) { - crm_data_t *dest = NULL; - crm_data_t *src = NULL; + xmlNode *dest = NULL; + xmlNode *src = NULL; const char *name = NULL; const char *value = NULL; - crm_data_t *diff = diff_xml_object(old_cib, new_cib, suppress); + xmlNode *diff = diff_xml_object(old_cib, new_cib, suppress); /* add complete version information */ src = old_cib; dest = find_xml_node(diff, "diff-removed", FALSE); if(src != NULL && dest != NULL) { name = XML_ATTR_GENERATION_ADMIN; value = crm_element_value(src, name); if(value == NULL) { value = "0"; } crm_xml_add(dest, name, value); name = XML_ATTR_GENERATION; value = crm_element_value(src, name); if(value == NULL) { value = "0"; } crm_xml_add(dest, name, value); name = XML_ATTR_NUMUPDATES; value = crm_element_value(src, name); if(value == NULL) { value = "0"; } crm_xml_add(dest, name, value); } src = new_cib; dest = find_xml_node(diff, "diff-added", FALSE); if(src != NULL && dest != NULL) { name = XML_ATTR_GENERATION_ADMIN; value = crm_element_value(src, name); if(value == NULL) { value = "0"; } crm_xml_add(dest, name, value); name = XML_ATTR_GENERATION; value = crm_element_value(src, name); if(value == NULL) { value = "0"; } crm_xml_add(dest, name, value); name = XML_ATTR_NUMUPDATES; value = crm_element_value(src, name); if(value == NULL) { value = "0"; } crm_xml_add(dest, name, value); } return diff; } void -log_cib_diff(int log_level, crm_data_t *diff, const char *function) +log_cib_diff(int log_level, xmlNode *diff, const char *function) { int add_updates = 0; int add_epoch = 0; int add_admin_epoch = 0; int del_updates = 0; int del_epoch = 0; int del_admin_epoch = 0; if(diff == NULL) { return; } cib_diff_version_details( diff, &add_admin_epoch, &add_epoch, &add_updates, &del_admin_epoch, &del_epoch, &del_updates); if(add_updates != del_updates) { do_crm_log(log_level, "%s: Diff: --- %d.%d.%d", function, del_admin_epoch, del_epoch, del_updates); do_crm_log(log_level, "%s: Diff: +++ %d.%d.%d", function, add_admin_epoch, add_epoch, add_updates); } else if(diff != NULL) { do_crm_log(log_level, "%s: Local-only Change: %d.%d.%d", function, add_admin_epoch, add_epoch, add_updates); } log_xml_diff(log_level, diff, function); } gboolean cib_version_details( - crm_data_t *cib, int *admin_epoch, int *epoch, int *updates) + xmlNode *cib, int *admin_epoch, int *epoch, int *updates) { const char *value = NULL; if(cib == NULL) { *admin_epoch = -1; *epoch = -1; *updates = -1; return FALSE; } else { value = crm_element_value(cib, XML_ATTR_GENERATION_ADMIN); *admin_epoch = crm_parse_int(value, "-1"); value = crm_element_value(cib, XML_ATTR_GENERATION); *epoch = crm_parse_int(value, "-1"); value = crm_element_value(cib, XML_ATTR_NUMUPDATES); *updates = crm_parse_int(value, "-1"); } return TRUE; } gboolean cib_diff_version_details( - crm_data_t *diff, int *admin_epoch, int *epoch, int *updates, + xmlNode *diff, int *admin_epoch, int *epoch, int *updates, int *_admin_epoch, int *_epoch, int *_updates) { - crm_data_t *tmp = NULL; + xmlNode *tmp = NULL; tmp = find_xml_node(diff, "diff-added", FALSE); cib_version_details(tmp, admin_epoch, epoch, updates); tmp = find_xml_node(diff, "diff-removed", FALSE); cib_version_details(tmp, _admin_epoch, _epoch, _updates); return TRUE; } /* * The caller should never free the return value */ -crm_data_t* -get_object_root(const char *object_type, crm_data_t *the_root) +xmlNode* +get_object_root(const char *object_type, xmlNode *the_root) { const char *node_stack[2]; - crm_data_t *tmp_node = NULL; + xmlNode *tmp_node = NULL; if(the_root == NULL) { crm_err("CIB root object was NULL"); return NULL; } node_stack[0] = XML_CIB_TAG_CONFIGURATION; node_stack[1] = object_type; if(object_type == NULL || strlen(object_type) == 0 || safe_str_eq(XML_CIB_TAG_SECTION_ALL, object_type) || safe_str_eq(XML_TAG_CIB, object_type)) { /* get the whole cib */ return the_root; } else if(strcasecmp(object_type, XML_CIB_TAG_STATUS) == 0) { /* these live in a different place */ tmp_node = find_xml_node(the_root, XML_CIB_TAG_STATUS, FALSE); node_stack[0] = object_type; node_stack[1] = NULL; } else { + /* tmp_node = first_named_child(the_root, XML_CIB_TAG_CONFIGURATION); */ tmp_node = find_xml_node_nested(the_root, node_stack, 2); } if (tmp_node == NULL) { crm_debug_2("Section [%s [%s]] not present in %s", node_stack[0], node_stack[1]?node_stack[1]:"", crm_element_name(the_root)); } return tmp_node; } const char * -get_crm_option(crm_data_t *cib, const char *name, gboolean do_warn) +get_crm_option(xmlNode *cib, const char *name, gboolean do_warn) { const char * value = NULL; - crm_data_t * a_default = NULL; - crm_data_t * config = get_object_root(XML_CIB_TAG_CRMCONFIG, cib); + xmlNode * a_default = NULL; + xmlNode * config = get_object_root(XML_CIB_TAG_CRMCONFIG, cib); if(config != NULL) { a_default = find_entity(config, XML_CIB_TAG_NVPAIR, name); } if(a_default == NULL) { if(do_warn) { crm_warn("Option %s not set", name); } return NULL; } value = crm_element_value(a_default, XML_NVPAIR_ATTR_VALUE); if(safe_str_eq(value, "")) { value = NULL; } return value; } -crm_data_t* +xmlNode* create_cib_fragment_adv( - crm_data_t *update, const char *update_section, const char *source) + xmlNode *update, const char *update_section, const char *source) { - crm_data_t *cib = NULL; + xmlNode *cib = NULL; gboolean whole_cib = FALSE; - crm_data_t *object_root = NULL; + xmlNode *object_root = NULL; const char *update_name = NULL; char *local_section = NULL; /* crm_debug("Creating a blank fragment: %s", update_section); */ if(update == NULL && update_section == NULL) { crm_debug_3("Creating a blank fragment"); update = createEmptyCib(); crm_xml_add(cib, XML_ATTR_ORIGIN, source); return update; } else if(update == NULL) { crm_err("No update to create a fragment for"); return NULL; } else if(update_section == NULL) { local_section = cib_pluralSection(update_name); update_section = local_section; } if(safe_str_eq(crm_element_name(update), XML_TAG_CIB)) { whole_cib = TRUE; } if(whole_cib == FALSE) { cib = createEmptyCib(); crm_xml_add(cib, XML_ATTR_ORIGIN, source); object_root = get_object_root(update_section, cib); add_node_copy(object_root, update); } else { cib = copy_xml(update); crm_xml_add(cib, XML_ATTR_ORIGIN, source); } crm_free(local_section); crm_debug_3("Verifying created fragment"); if(verifyCibXml(cib) == FALSE) { crm_err("Fragment creation failed"); crm_log_xml_err(cib, "[src]"); free_xml(cib); cib = NULL; } return cib; } /* * It is the callers responsibility to free both the new CIB (output) * and the new CIB (input) */ -crm_data_t* +xmlNode* createEmptyCib(void) { - crm_data_t *cib_root = NULL, *config = NULL, *status = NULL; + xmlNode *cib_root = NULL, *config = NULL, *status = NULL; cib_root = create_xml_node(NULL, XML_TAG_CIB); config = create_xml_node(cib_root, XML_CIB_TAG_CONFIGURATION); status = create_xml_node(cib_root, XML_CIB_TAG_STATUS); /* crm_xml_add(cib_root, "version", "1"); */ crm_xml_add(cib_root, "generated", XML_BOOLEAN_TRUE); create_xml_node(config, XML_CIB_TAG_CRMCONFIG); create_xml_node(config, XML_CIB_TAG_NODES); create_xml_node(config, XML_CIB_TAG_RESOURCES); create_xml_node(config, XML_CIB_TAG_CONSTRAINTS); if (verifyCibXml(cib_root)) { return cib_root; } free_xml(cib_root); crm_crit("The generated CIB did not pass integrity testing!!" " All hope is lost."); return NULL; } gboolean -verifyCibXml(crm_data_t *cib) +verifyCibXml(xmlNode *cib) { int lpc = 0; gboolean is_valid = TRUE; - crm_data_t *tmp_node = NULL; + xmlNode *tmp_node = NULL; const char *sections[] = { XML_CIB_TAG_NODES, XML_CIB_TAG_RESOURCES, XML_CIB_TAG_CONSTRAINTS, XML_CIB_TAG_STATUS, XML_CIB_TAG_CRMCONFIG }; if (cib == NULL) { crm_warn("CIB was empty."); return FALSE; } /* basic tests... are the standard section all there */ for(lpc = 0; lpc < DIMOF(sections); lpc++) { tmp_node = get_object_root(sections[lpc], cib); if (tmp_node == NULL) { crm_warn("Section %s is not present in the CIB", sections[lpc]); is_valid = FALSE; } } /* more integrity tests */ return is_valid; } gboolean verify_cib_cmds(cib_t *cib) { gboolean valid = TRUE; if(cib->cmds->variant_op == NULL) { crm_err("Operation variant_op not set"); valid = FALSE; } if(cib->cmds->signon == NULL) { crm_err("Operation signon not set"); valid = FALSE; } if(cib->cmds->signoff == NULL) { crm_err("Operation signoff not set"); valid = FALSE; } if(cib->cmds->free == NULL) { crm_err("Operation free not set"); valid = FALSE; } if(cib->cmds->set_op_callback == NULL) { crm_err("Operation set_op_callback not set"); valid = FALSE; } if(cib->cmds->add_notify_callback == NULL) { crm_err("Operation add_notify_callback not set"); valid = FALSE; } if(cib->cmds->del_notify_callback == NULL) { crm_err("Operation del_notify_callback not set"); valid = FALSE; } if(cib->cmds->set_connection_dnotify == NULL) { crm_err("Operation set_connection_dnotify not set"); valid = FALSE; } if(cib->cmds->channel == NULL) { crm_err("Operation channel not set"); valid = FALSE; } if(cib->cmds->inputfd == NULL) { crm_err("Operation inputfd not set"); valid = FALSE; } if(cib->cmds->noop == NULL) { crm_err("Operation noop not set"); valid = FALSE; } if(cib->cmds->ping == NULL) { crm_err("Operation ping not set"); valid = FALSE; } if(cib->cmds->query == NULL) { crm_err("Operation query not set"); valid = FALSE; } if(cib->cmds->query_from == NULL) { crm_err("Operation query_from not set"); valid = FALSE; } if(cib->cmds->is_master == NULL) { crm_err("Operation is_master not set"); valid = FALSE; } if(cib->cmds->set_master == NULL) { crm_err("Operation set_master not set"); valid = FALSE; } if(cib->cmds->set_slave == NULL) { crm_err("Operation set_slave not set"); valid = FALSE; } if(cib->cmds->set_slave_all == NULL) { crm_err("Operation set_slave_all not set"); valid = FALSE; } if(cib->cmds->sync == NULL) { crm_err("Operation sync not set"); valid = FALSE; } if(cib->cmds->sync_from == NULL) { crm_err("Operation sync_from not set"); valid = FALSE; } if(cib->cmds->bump_epoch == NULL) { crm_err("Operation bump_epoch not set"); valid = FALSE; } if(cib->cmds->create == NULL) { crm_err("Operation create not set"); valid = FALSE; } if(cib->cmds->modify == NULL) { crm_err("Operation modify not set"); valid = FALSE; } if(cib->cmds->replace == NULL) { crm_err("Operation replace not set"); valid = FALSE; } if(cib->cmds->delete == NULL) { crm_err("Operation delete not set"); valid = FALSE; } if(cib->cmds->erase == NULL) { crm_err("Operation erase not set"); valid = FALSE; } if(cib->cmds->quit == NULL) { crm_err("Operation quit not set"); valid = FALSE; } if(cib->cmds->msgready == NULL) { crm_err("Operation msgready not set"); valid = FALSE; } if(cib->cmds->rcvmsg == NULL) { crm_err("Operation rcvmsg not set"); valid = FALSE; } if(cib->cmds->dispatch == NULL) { crm_err("Operation dispatch not set"); valid = FALSE; } return valid; } diff --git a/lib/crm/cib/cib_native.c b/lib/crm/cib/cib_native.c index a474bfe79d..1d341bb4e2 100644 --- a/lib/crm/cib/cib_native.c +++ b/lib/crm/cib/cib_native.c @@ -1,908 +1,880 @@ /* * Copyright (c) 2004 International Business Machines * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser 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 library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef struct cib_native_opaque_s { IPC_Channel *command_channel; IPC_Channel *callback_channel; GCHSource *callback_source; } cib_native_opaque_t; int cib_native_perform_op( cib_t *cib, const char *op, const char *host, const char *section, - crm_data_t *data, crm_data_t **output_data, int call_options); + xmlNode *data, xmlNode **output_data, int call_options); int cib_native_signon(cib_t* cib, const char *name, enum cib_conn_type type); int cib_native_signoff(cib_t* cib); int cib_native_free(cib_t* cib); IPC_Channel *cib_native_channel(cib_t* cib); int cib_native_inputfd(cib_t* cib); gboolean cib_native_msgready(cib_t* cib); int cib_native_rcvmsg(cib_t* cib, int blocking); gboolean cib_native_dispatch(IPC_Channel *channel, gpointer user_data); cib_t *cib_native_new (cib_t *cib); void cib_native_delete(cib_t *cib); int cib_native_set_connection_dnotify( cib_t *cib, void (*dnotify)(gpointer user_data)); void cib_native_notify(gpointer data, gpointer user_data); -void cib_native_callback(cib_t *cib, struct ha_msg *msg); +void cib_native_callback(cib_t *cib, xmlNode *msg); int cib_native_register_callback(cib_t* cib, const char *callback, int enabled); cib_t* cib_native_new (cib_t *cib) { cib_native_opaque_t *native = NULL; crm_malloc0(cib->variant_opaque, sizeof(cib_native_opaque_t)); native = cib->variant_opaque; native->command_channel = NULL; native->callback_channel = NULL; /* assign variant specific ops*/ cib->cmds->variant_op = cib_native_perform_op; cib->cmds->signon = cib_native_signon; cib->cmds->signoff = cib_native_signoff; cib->cmds->free = cib_native_free; cib->cmds->channel = cib_native_channel; cib->cmds->inputfd = cib_native_inputfd; cib->cmds->msgready = cib_native_msgready; cib->cmds->rcvmsg = cib_native_rcvmsg; cib->cmds->dispatch = cib_native_dispatch; cib->cmds->register_callback = cib_native_register_callback; cib->cmds->set_connection_dnotify = cib_native_set_connection_dnotify; return cib; } void cib_native_delete(cib_t *cib) { crm_free(cib->variant_opaque); } int cib_native_signon(cib_t* cib, const char *name, enum cib_conn_type type) { int rc = cib_ok; char *uuid_ticket = NULL; - struct ha_msg *reg_msg = NULL; + xmlNode *reg_msg = NULL; cib_native_opaque_t *native = cib->variant_opaque; crm_debug_4("Connecting command channel"); if(type == cib_command) { cib->state = cib_connected_command; native->command_channel = init_client_ipc_comms_nodispatch( cib_channel_rw); } else if(type == cib_query) { cib->state = cib_connected_query; native->command_channel = init_client_ipc_comms_nodispatch( cib_channel_ro); } else if(type == cib_query_synchronous) { cib->state = cib_connected_query; native->command_channel = init_client_ipc_comms_nodispatch( cib_channel_ro_synchronous); } else if(type == cib_command_synchronous) { cib->state = cib_connected_query; native->command_channel = init_client_ipc_comms_nodispatch( cib_channel_rw_synchronous); } else { return cib_not_connected; } if(native->command_channel == NULL) { crm_debug("Connection to command channel failed"); rc = cib_connection; } else if(native->command_channel->ch_status != IPC_CONNECT) { crm_err("Connection may have succeeded," " but authentication to command channel failed"); rc = cib_authentication; } if(type == cib_query_synchronous || type == cib_command_synchronous) { return rc; } if(rc == cib_ok) { crm_debug_4("Connecting callback channel"); native->callback_source = init_client_ipc_comms( cib_channel_callback, cib_native_dispatch, cib, &(native->callback_channel)); if(native->callback_channel == NULL) { crm_debug("Connection to callback channel failed"); rc = cib_connection; } else if(native->callback_channel->ch_status != IPC_CONNECT) { crm_err("Connection may have succeeded," " but authentication to callback channel failed"); rc = cib_authentication; } else if(native->callback_source == NULL) { crm_err("Callback source not recorded"); rc = cib_connection; } else { native->callback_channel->send_queue->max_qlen = 500; } } if(rc == cib_ok) { crm_debug_4("Waiting for msg on command channel"); - reg_msg = msgfromIPC(native->command_channel, MSG_ALLOWINTR); + reg_msg = xmlfromIPC(native->command_channel, 0); if(native->command_channel->ops->get_chan_status( native->command_channel) != IPC_CONNECT) { crm_err("No reply message - disconnected - %d", rc); rc = cib_not_connected; } else if(rc != IPC_OK) { crm_err("No reply message - failed - %d", rc); rc = cib_reply_failed; } else if(reg_msg == NULL) { crm_err("No reply message - empty - %d", rc); rc = cib_reply_failed; } } if(rc == cib_ok) { const char *msg_type = NULL; - msg_type = cl_get_string(reg_msg, F_CIB_OPERATION); + msg_type = crm_element_value(reg_msg, F_CIB_OPERATION); if(safe_str_neq(msg_type, CRM_OP_REGISTER) ) { crm_err("Invalid registration message: %s", msg_type); rc = cib_registration_msg; } else { const char *tmp_ticket = NULL; crm_debug_4("Retrieving callback channel ticket"); - tmp_ticket = cl_get_string( + tmp_ticket = crm_element_value( reg_msg, F_CIB_CALLBACK_TOKEN); if(tmp_ticket == NULL) { rc = cib_callback_token; } else { uuid_ticket = crm_strdup(tmp_ticket); } } } if(reg_msg != NULL) { - crm_msg_del(reg_msg); - reg_msg = NULL; + free_xml(reg_msg); + reg_msg = NULL; } if(rc == cib_ok) { crm_debug_4("Registering callback channel with ticket %s", crm_str(uuid_ticket)); - reg_msg = ha_msg_new(2); - ha_msg_add(reg_msg, F_CIB_OPERATION, CRM_OP_REGISTER); - ha_msg_add(reg_msg, F_CIB_CALLBACK_TOKEN, uuid_ticket); - ha_msg_add(reg_msg, F_CIB_CLIENTNAME, name); + reg_msg = create_xml_node(NULL, __FUNCTION__); + crm_xml_add(reg_msg, F_CIB_OPERATION, CRM_OP_REGISTER); + crm_xml_add(reg_msg, F_CIB_CALLBACK_TOKEN, uuid_ticket); + crm_xml_add(reg_msg, F_CIB_CLIENTNAME, name); if(send_ipc_message( native->callback_channel, reg_msg) == FALSE) { rc = cib_callback_register; } - crm_msg_del(reg_msg); + free_xml(reg_msg); crm_free(uuid_ticket); } if(rc == cib_ok) { /* In theory IPC_INTR could trip us up here */ crm_debug_4("wait for the callback channel setup to complete"); - reg_msg = msgfromIPC(native->callback_channel, MSG_ALLOWINTR); + reg_msg = xmlfromIPC(native->callback_channel, 0); if(native->callback_channel->ops->get_chan_status( native->callback_channel) != IPC_CONNECT) { crm_err("No reply message - disconnected - %d", rc); rc = cib_not_connected; } else if(reg_msg == NULL) { crm_err("No reply message - empty - %d", rc); rc = cib_reply_failed; } - crm_msg_del(reg_msg); + free_xml(reg_msg); } if(rc == cib_ok) { crm_debug("Connection to CIB successful"); return cib_ok; } crm_debug("Connection to CIB failed: %s", cib_error2string(rc)); cib_native_signoff(cib); return rc; } int cib_native_signoff(cib_t* cib) { cib_native_opaque_t *native = cib->variant_opaque; crm_debug("Signing out of the CIB Service"); /* close channels */ if (native->command_channel != NULL) { native->command_channel->ops->destroy( native->command_channel); native->command_channel = NULL; } if (native->callback_source != NULL) { G_main_del_IPC_Channel(native->callback_source); native->callback_source = NULL; } if (native->callback_channel != NULL) { #ifdef BUG native->callback_channel->ops->destroy( native->callback_channel); #endif native->callback_channel = NULL; } cib->state = cib_disconnected; cib->type = cib_none; return cib_ok; } int cib_native_free (cib_t* cib) { int rc = cib_ok; crm_warn("Freeing CIB"); if(cib->state != cib_disconnected) { rc = cib_native_signoff(cib); if(rc == cib_ok) { crm_free(cib); } } return rc; } IPC_Channel * cib_native_channel(cib_t* cib) { cib_native_opaque_t *native = NULL; if(cib == NULL) { crm_err("Missing cib object"); return NULL; } native = cib->variant_opaque; if(native != NULL) { return native->callback_channel; } crm_err("couldnt find variant specific data in %p", cib); return NULL; } int cib_native_inputfd(cib_t* cib) { IPC_Channel *ch = cib_native_channel(cib); return ch->ops->get_recv_select_fd(ch); } -static HA_Message * +static xmlNode * cib_create_op( int call_id, const char *op, const char *host, const char *section, - crm_data_t *data, int call_options) + xmlNode *data, int call_options) { int rc = HA_OK; - HA_Message *op_msg = NULL; - op_msg = ha_msg_new(9); + xmlNode *op_msg = create_xml_node(NULL, "cib-op"); CRM_CHECK(op_msg != NULL, return NULL); - rc = ha_msg_add(op_msg, F_XML_TAGNAME, "cib_command"); + crm_xml_add(op_msg, F_XML_TAGNAME, "cib_command"); - if(rc == HA_OK) { - rc = ha_msg_add(op_msg, F_TYPE, T_CIB); - } - if(rc == HA_OK) { - rc = ha_msg_add(op_msg, F_CIB_OPERATION, op); - } - if(rc == HA_OK && host != NULL) { - rc = ha_msg_add(op_msg, F_CIB_HOST, host); - } - if(rc == HA_OK && section != NULL) { - rc = ha_msg_add(op_msg, F_CIB_SECTION, section); - } - if(rc == HA_OK) { - rc = ha_msg_add_int(op_msg, F_CIB_CALLID, call_id); - } - if(rc == HA_OK) { - crm_debug_4("Sending call options: %.8lx, %d", - (long)call_options, call_options); - rc = ha_msg_add_int(op_msg, F_CIB_CALLOPTS, call_options); - } + crm_xml_add(op_msg, F_TYPE, T_CIB); + crm_xml_add(op_msg, F_CIB_OPERATION, op); + crm_xml_add(op_msg, F_CIB_HOST, host); + crm_xml_add(op_msg, F_CIB_SECTION, section); + crm_xml_add_int(op_msg, F_CIB_CALLID, call_id); + crm_debug_4("Sending call options: %.8lx, %d", + (long)call_options, call_options); + crm_xml_add_int(op_msg, F_CIB_CALLOPTS, call_options); - if(rc == HA_OK && data != NULL) { + if(data != NULL) { #if 0 const char *tag = crm_element_name(data); - crm_data_t *cib = data; + xmlNode *cib = data; if(safe_str_neq(tag, XML_TAG_CIB)) { cib = find_xml_node(data, XML_TAG_CIB, FALSE); if(cib != NULL) { tag = XML_TAG_CIB; } } if(safe_str_eq(tag, XML_TAG_CIB)) { const char *version = feature_set(cib); crm_xml_add(cib, XML_ATTR_CIB_REVISION, version); } else { crm_info("Skipping feature check for %s tag", tag); } #endif add_message_xml(op_msg, F_CIB_CALLDATA, data); } if (rc != HA_OK) { crm_err("Failed to create CIB operation message"); - crm_log_message(LOG_ERR, op_msg); - crm_msg_del(op_msg); + crm_log_xml(LOG_ERR, "op", op_msg); + free_xml(op_msg); return NULL; } if(call_options & cib_inhibit_bcast) { CRM_CHECK((call_options & cib_scope_local), return NULL); } return op_msg; } static gboolean timer_expired = FALSE; static struct timer_rec_s *sync_timer = NULL; static gboolean cib_timeout_handler(gpointer data) { struct timer_rec_s *timer = data; timer_expired = TRUE; crm_err("Call %d timed out after %ds", timer->call_id, timer->timeout); /* Always return TRUE, never remove the handler * We do that after the while-loop in cib_native_perform_op() */ return TRUE; } int cib_native_perform_op( cib_t *cib, const char *op, const char *host, const char *section, - crm_data_t *data, crm_data_t **output_data, int call_options) + xmlNode *data, xmlNode **output_data, int call_options) { int rc = HA_OK; - struct ha_msg *op_msg = NULL; - struct ha_msg *op_reply = NULL; + xmlNode *op_msg = NULL; + xmlNode *op_reply = NULL; cib_native_opaque_t *native = cib->variant_opaque; if(sync_timer == NULL) { crm_malloc0(sync_timer, sizeof(struct timer_rec_s)); } if(cib->state == cib_disconnected) { return cib_not_connected; } if(output_data != NULL) { *output_data = NULL; } if(op == NULL) { crm_err("No operation specified"); return cib_operation; } cib->call_id++; /* prevent call_id from being negative (or zero) and conflicting * with the cib_errors enum * use 2 because we use it as (cib->call_id - 1) below */ if(cib->call_id < 1) { cib->call_id = 1; } op_msg = cib_create_op( cib->call_id, op, host, section, data, call_options); if(op_msg == NULL) { return cib_create_msg; } crm_debug_3("Sending %s message to CIB service", op); if(send_ipc_message(native->command_channel, op_msg) == FALSE) { crm_err("Sending message to CIB service FAILED"); - crm_msg_del(op_msg); + free_xml(op_msg); return cib_send_failed; } else { crm_debug_3("Message sent"); } - crm_msg_del(op_msg); + free_xml(op_msg); if((call_options & cib_discard_reply)) { crm_debug_3("Discarding reply"); return cib_ok; } else if(!(call_options & cib_sync_call)) { crm_debug_3("Async call, returning"); CRM_CHECK(cib->call_id != 0, return cib_reply_failed); return cib->call_id; } rc = IPC_OK; crm_debug_3("Waiting for a syncronous reply"); if(cib->call_timeout > 0) { /* We need this, even with msgfromIPC_timeout(), because we might * get other/older replies that don't match the active request */ timer_expired = FALSE; sync_timer->call_id = cib->call_id; sync_timer->timeout = cib->call_timeout*1000; sync_timer->ref = Gmain_timeout_add( sync_timer->timeout, cib_timeout_handler, sync_timer); } while(timer_expired == FALSE && IPC_ISRCONN(native->command_channel)) { int reply_id = -1; int msg_id = cib->call_id; -#if HAVE_MSGFROMIPC_TIMEOUT - int ipc_rc = 0; - - op_reply = msgfromIPC_timeout( - native->command_channel, MSG_ALLOWINTR, - cib->call_timeout, &ipc_rc); - - if(ipc_rc == IPC_TIMEOUT) { - timer_expired = TRUE; - break; - } -#else - op_reply = msgfromIPC(native->command_channel, MSG_ALLOWINTR); -#endif - + op_reply = xmlfromIPC(native->command_channel, cib->call_timeout); if(op_reply == NULL) { break; } - CRM_CHECK(ha_msg_value_int( - op_reply, F_CIB_CALLID, &reply_id) == HA_OK, - crm_msg_del(op_reply); + crm_element_value_int(op_reply, F_CIB_CALLID, &reply_id); + CRM_CHECK(reply_id > 0, + free_xml(op_reply); if(sync_timer->ref > 0) { g_source_remove(sync_timer->ref); sync_timer->ref = 0; } return cib_reply_failed); if(reply_id == msg_id) { break; } else if(reply_id < msg_id) { crm_debug("Recieved old reply: %d (wanted %d)", reply_id, msg_id); - crm_log_message_adv( + crm_log_xml( LOG_MSG, "Old reply", op_reply); } else if((reply_id - 10000) > msg_id) { /* wrap-around case */ crm_debug("Recieved old reply: %d (wanted %d)", reply_id, msg_id); - crm_log_message_adv( + crm_log_xml( LOG_MSG, "Old reply", op_reply); } else { crm_err("Received a __future__ reply:" " %d (wanted %d)", reply_id, msg_id); } - crm_msg_del(op_reply); + free_xml(op_reply); op_reply = NULL; } if(sync_timer->ref > 0) { g_source_remove(sync_timer->ref); sync_timer->ref = 0; } if(timer_expired) { return cib_remote_timeout; } if(op_reply == NULL) { if(IPC_ISRCONN(native->command_channel) == FALSE) { crm_err("No reply message - disconnected - %d", native->command_channel->ch_status); cib->state = cib_disconnected; return cib_not_connected; } crm_err("No reply message - empty - %d", rc); return cib_reply_failed; } if(IPC_ISRCONN(native->command_channel) == FALSE) { crm_err("CIB disconnected: %d", native->command_channel->ch_status); cib->state = cib_disconnected; } crm_debug_3("Syncronous reply recieved"); rc = cib_ok; /* Start processing the reply... */ - if(ha_msg_value_int(op_reply, F_CIB_RC, &rc) != HA_OK) { + if(crm_element_value_int(op_reply, F_CIB_RC, &rc) != 0) { rc = cib_return_code; } if(rc == cib_ok || rc == cib_not_master || rc == cib_master_timeout) { - crm_log_message(LOG_MSG, op_reply); + crm_log_xml(LOG_MSG, "passed", op_reply); } else { /* } else if(rc == cib_remote_timeout) { */ crm_err("Call failed: %s", cib_error2string(rc)); - crm_log_message(LOG_WARNING, op_reply); + crm_log_xml(LOG_WARNING, "failed", op_reply); } if(output_data == NULL) { /* do nothing more */ } else if(!(call_options & cib_discard_reply)) { *output_data = get_message_xml(op_reply, F_CIB_CALLDATA); if(*output_data == NULL) { crm_debug_3("No output in reply to \"%s\" command %d", op, cib->call_id - 1); } } - crm_msg_del(op_reply); + free_xml(op_reply); return rc; } gboolean cib_native_msgready(cib_t* cib) { cib_native_opaque_t *native = NULL; if (cib == NULL) { crm_err("No CIB!"); return FALSE; } native = cib->variant_opaque; if(native->command_channel != NULL) { /* drain the channel */ IPC_Channel *cmd_ch = native->command_channel; - HA_Message *cmd_msg = NULL; + xmlNode *cmd_msg = NULL; while(cmd_ch->ch_status != IPC_DISCONNECT && cmd_ch->ops->is_message_pending(cmd_ch)) { /* this will happen when the CIB exited from beneath us */ - cmd_msg = msgfromIPC_noauth(cmd_ch); - crm_msg_del(cmd_msg); + cmd_msg = xmlfromIPC(cmd_ch, 0); + free_xml(cmd_msg); } } else { crm_err("No command channel"); } if(native->callback_channel == NULL) { crm_err("No callback channel"); return FALSE; } else if(native->callback_channel->ch_status == IPC_DISCONNECT) { crm_info("Lost connection to the CIB service [%d].", native->callback_channel->farside_pid); return FALSE; } else if(native->callback_channel->ops->is_message_pending( native->callback_channel)) { crm_debug_4("Message pending on command channel [%d]", native->callback_channel->farside_pid); return TRUE; } crm_debug_3("No message pending"); return FALSE; } int cib_native_rcvmsg(cib_t* cib, int blocking) { const char *type = NULL; - struct ha_msg* msg = NULL; + xmlNode* msg = NULL; cib_native_opaque_t *native = NULL; if (cib == NULL) { crm_err("No CIB!"); return FALSE; } native = cib->variant_opaque; /* if it is not blocking mode and no message in the channel, return */ if (blocking == 0 && cib_native_msgready(cib) == FALSE) { crm_debug_3("No message ready and non-blocking..."); return 0; } else if (cib_native_msgready(cib) == FALSE) { crm_debug("Waiting for message from CIB service..."); if(native->callback_channel == NULL) { return 0; } else if(native->callback_channel->ch_status != IPC_CONNECT) { return 0; } else if(native->command_channel && native->command_channel->ch_status != IPC_CONNECT){ return 0; } native->callback_channel->ops->waitin(native->callback_channel); } /* IPC_INTR is not a factor here */ - msg = msgfromIPC_noauth(native->callback_channel); + msg = xmlfromIPC(native->callback_channel, 0); if (msg == NULL) { crm_warn("Received a NULL msg from CIB service."); return 0; } /* do callbacks */ - type = cl_get_string(msg, F_TYPE); + type = crm_element_value(msg, F_TYPE); crm_debug_4("Activating %s callbacks...", type); if(safe_str_eq(type, T_CIB)) { cib_native_callback(cib, msg); } else if(safe_str_eq(type, T_CIB_NOTIFY)) { g_list_foreach(cib->notify_list, cib_native_notify, msg); } else { crm_err("Unknown message type: %s", type); } - crm_msg_del(msg); + free_xml(msg); return 1; } void -cib_native_callback(cib_t *cib, struct ha_msg *msg) +cib_native_callback(cib_t *cib, xmlNode *msg) { int rc = 0; int call_id = 0; - crm_data_t *output = NULL; + xmlNode *output = NULL; cib_callback_client_t *blob = NULL; cib_callback_client_t local_blob; /* gcc4 had a point... make sure (at least) local_blob.callback * is initialized before use */ local_blob.callback = NULL; local_blob.user_data = NULL; local_blob.only_success = FALSE; - ha_msg_value_int(msg, F_CIB_CALLID, &call_id); - + crm_element_value_int(msg, F_CIB_CALLID, &call_id); blob = g_hash_table_lookup( cib_op_callback_table, GINT_TO_POINTER(call_id)); if(blob != NULL) { crm_debug_3("Callback found for call %d", call_id); /* local_blob.callback = blob->callback; */ /* local_blob.user_data = blob->user_data; */ /* local_blob.only_success = blob->only_success; */ local_blob = *blob; blob = NULL; remove_cib_op_callback(call_id, FALSE); } else { crm_debug_3("No callback found for call %d", call_id); local_blob.callback = NULL; } - ha_msg_value_int(msg, F_CIB_RC, &rc); + crm_element_value_int(msg, F_CIB_RC, &rc); if(rc == cib_diff_resync) { /* This is anare internal value that clients do not and should not care about */ rc = cib_ok; } output = get_message_xml(msg, F_CIB_CALLDATA); if(local_blob.callback != NULL && (rc == cib_ok || local_blob.only_success == FALSE)) { local_blob.callback( msg, call_id, rc, output, local_blob.user_data); } else if(cib->op_callback == NULL && rc != cib_ok) { crm_warn("CIB command failed: %s", cib_error2string(rc)); - crm_log_message_adv(LOG_DEBUG, "Failed CIB Update", msg); + crm_log_xml(LOG_DEBUG, "Failed CIB Update", msg); } if(cib->op_callback == NULL) { crm_debug_3("No OP callback set, ignoring reply"); } else { cib->op_callback(msg, call_id, rc, output); } free_xml(output); crm_debug_4("OP callback activated."); } void cib_native_notify(gpointer data, gpointer user_data) { - struct ha_msg *msg = user_data; + xmlNode *msg = user_data; cib_notify_client_t *entry = data; const char *event = NULL; if(msg == NULL) { crm_warn("Skipping callback - NULL message"); return; } - event = cl_get_string(msg, F_SUBTYPE); + event = crm_element_value(msg, F_SUBTYPE); if(entry == NULL) { crm_warn("Skipping callback - NULL callback client"); return; } else if(entry->callback == NULL) { crm_warn("Skipping callback - NULL callback"); return; } else if(safe_str_neq(entry->event, event)) { crm_debug_4("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event); return; } crm_debug_4("Invoking callback for %p/%s event...", entry, event); entry->callback(event, msg); crm_debug_4("Callback invoked..."); } gboolean cib_native_dispatch(IPC_Channel *channel, gpointer user_data) { int lpc = 0; cib_t *cib = user_data; cib_native_opaque_t *native = NULL; crm_debug_3("Received callback"); if(user_data == NULL){ crm_err("user_data field must contain the CIB struct"); return FALSE; } native = cib->variant_opaque; while(cib_native_msgready(cib)) { lpc++; /* invoke the callbacks but dont block */ if(cib_native_rcvmsg(cib, 0) < 1) { break; } } crm_debug_3("%d CIB messages dispatched", lpc); if(native->callback_channel && native->callback_channel->ch_status != IPC_CONNECT) { crm_crit("Lost connection to the CIB service [%d/callback].", channel->farside_pid); if(native->callback_source != NULL) { G_main_del_IPC_Channel(native->callback_source); native->callback_source = NULL; } return FALSE; } else if(native->command_channel && native->command_channel->ch_status != IPC_CONNECT) { crm_crit("Lost connection to the CIB service [%d/command].", channel->farside_pid); return FALSE; } return TRUE; } int cib_native_set_connection_dnotify( cib_t *cib, void (*dnotify)(gpointer user_data)) { cib_native_opaque_t *native = NULL; if (cib == NULL) { crm_err("No CIB!"); return FALSE; } native = cib->variant_opaque; if(dnotify == NULL) { crm_warn("Setting dnotify back to default value"); set_IPC_Channel_dnotify(native->callback_source, default_ipc_connection_destroy); } else { crm_debug_3("Setting dnotify"); set_IPC_Channel_dnotify(native->callback_source, dnotify); } return cib_ok; } int cib_native_register_callback(cib_t* cib, const char *callback, int enabled) { - HA_Message *notify_msg = ha_msg_new(3); + xmlNode *notify_msg = create_xml_node(NULL, "cib-callback"); cib_native_opaque_t *native = cib->variant_opaque; /* short term hack - should make this generic somehow */ - ha_msg_add(notify_msg, F_CIB_OPERATION, T_CIB_NOTIFY); - ha_msg_add(notify_msg, F_CIB_NOTIFY_TYPE, callback); - ha_msg_add_int(notify_msg, F_CIB_NOTIFY_ACTIVATE, enabled); + crm_xml_add(notify_msg, F_CIB_OPERATION, T_CIB_NOTIFY); + crm_xml_add(notify_msg, F_CIB_NOTIFY_TYPE, callback); + crm_xml_add_int(notify_msg, F_CIB_NOTIFY_ACTIVATE, enabled); send_ipc_message(native->callback_channel, notify_msg); - crm_msg_del(notify_msg); + free_xml(notify_msg); return cib_ok; } diff --git a/lib/crm/cib/cib_version.c b/lib/crm/cib/cib_version.c index 2bb7bcc0cd..aa6b7449a2 100644 --- a/lib/crm/cib/cib_version.c +++ b/lib/crm/cib/cib_version.c @@ -1,163 +1,163 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include const char * feature_sets[] = { "1.1", "1.2", "1.3", "2.0", }; typedef struct tag_set_s { int length; const char **tags; } tag_set_t; const char *feature_tags_12[] = { "master_slave", }; const char *feature_tags_20[] = { "cluster_property_set", "meta_attributes", "transient_attributes", }; tag_set_t feature_tags[] = { { 0, NULL }, { 1, feature_tags_12 }, { 0, NULL }, { 3, feature_tags_20 }, }; const char *feature_attrs_12[] = { "master_node_max", }; const char *feature_attrs_20[] = { "start_delay", "disabled", "on_fail", "prereq", "collocated", "globally_unique", "from_role", "to_role", "node_attribute", "score_attribute", "hours", "transition_key", "op_digest", "op_restart_digest", "op_force_restart", }; tag_set_t feature_attrs[] = { { 0, NULL }, { 1, feature_attrs_12 }, { 0, NULL }, { 15, feature_attrs_20 }, }; static int -internal_update_feature_set(crm_data_t *xml_obj, int current) +internal_update_feature_set(xmlNode *xml_obj, int current) { int lpc = current; int lpc_nested = 0; const char *value = NULL; int num_sets = DIMOF(feature_sets); CRM_CHECK(compare_version( CIB_FEATURE_SET, feature_sets[num_sets-1]) == 0, return num_sets-1); for(;lpc < num_sets; lpc++) { const char *tag = crm_element_name(xml_obj); crm_debug_3("Checking set %d with %d tags", lpc, feature_tags[lpc].length); lpc_nested = 0; for(; lpc_nested < feature_tags[lpc].length; lpc_nested++) { const char *name = feature_tags[lpc].tags[lpc_nested]; crm_debug_4("Checking %s vs. %s", tag, name); if(safe_str_eq(tag, name)) { crm_debug_2("Found feature %s from set %s", tag, feature_sets[lpc]); current = lpc; break; } } if(current == lpc) { continue; } lpc_nested = 0; for(; lpc_nested < feature_attrs[lpc].length; lpc_nested++) { const char *name = feature_attrs[lpc].tags[lpc_nested]; crm_debug_4("Checking for %s", name); value = crm_element_value(xml_obj, name); if(value != NULL) { crm_info("Found feature '%s' from set %s", name, feature_sets[lpc]); current = lpc; break; } } } if(current == (num_sets -1)) { return current; } xml_child_iter(xml_obj, xml_child, current = internal_update_feature_set(xml_child,current); if(current == (num_sets -1)) { return current; } ); return current; } const char * -feature_set(crm_data_t *xml_obj) +feature_set(xmlNode *xml_obj) { int set = internal_update_feature_set(xml_obj, 0); CRM_ASSERT(set < DIMOF(feature_sets)); return feature_sets[set]; } diff --git a/lib/crm/common/Makefile.am b/lib/crm/common/Makefile.am index 7cf81af65d..1d103c306d 100644 --- a/lib/crm/common/Makefile.am +++ b/lib/crm/common/Makefile.am @@ -1,51 +1,56 @@ # # Copyright (C) 2004 Andrew Beekhof # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program 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 program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # MAINTAINERCLEANFILES = Makefile.in INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ -I$(top_builddir)/libltdl -I$(top_srcdir)/libltdl \ -I$(AISPREFIX)/include/openais ## libraries lib_LTLIBRARIES = libcrmcommon.la libcrmcluster.la libcrmcluster_la_SOURCES = cluster.c membership.c if BUILD_AIS_SUPPORT libcrmcluster_la_SOURCES += ais.c endif if BUILD_HEARTBEAT_SUPPORT libcrmcluster_la_SOURCES += heartbeat.c endif +libcrmcluster_la_LDFLAGS = -version-info 1:0:0 +# Must use non-fatal CFLAGS because glib insists on pretending things are const +# when they're not and thus we need the crm_element_value_const() hack +#libcrmcommon_la_CFLAGS = -Wno-discard-qual -libcrmcluster_la_LDFLAGS = -version-info 1:0:0 +# Must use non-fatal CFLAGS because glib insists on pretending things are const when they're not +CFLAGS = $(NON_FATAL_CFLAGS) libcrmcommon_la_SOURCES = ipc.c utils.c xml.c ctrl.c iso8601.c \ iso8601_fields.c libcrmcommon_la_LDFLAGS = -version-info 2:0:0 clean-generic: rm -f *.log *.debug *.xml *~ install-exec-local: uninstall-local: diff --git a/lib/crm/common/ais.c b/lib/crm/common/ais.c index cfb1112d60..7fcf1a2298 100644 --- a/lib/crm/common/ais.c +++ b/lib/crm/common/ais.c @@ -1,494 +1,490 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include "stack.h" #include enum crm_ais_msg_types text2msg_type(const char *text) { int type = crm_msg_none; CRM_CHECK(text != NULL, return type); if(safe_str_eq(text, "ais")) { type = crm_msg_ais; } else if(safe_str_eq(text, "crm_plugin")) { type = crm_msg_ais; } else if(safe_str_eq(text, CRM_SYSTEM_CIB)) { type = crm_msg_cib; } else if(safe_str_eq(text, CRM_SYSTEM_CRMD)) { type = crm_msg_crmd; } else if(safe_str_eq(text, CRM_SYSTEM_DC)) { type = crm_msg_crmd; } else if(safe_str_eq(text, CRM_SYSTEM_TENGINE)) { type = crm_msg_te; } else if(safe_str_eq(text, CRM_SYSTEM_PENGINE)) { type = crm_msg_pe; } else if(safe_str_eq(text, CRM_SYSTEM_LRMD)) { type = crm_msg_lrmd; } else { crm_debug_2("Unknown message type: %s", text); } return type; } char *get_ais_data(AIS_Message *msg) { int rc = BZ_OK; char *uncompressed = NULL; unsigned int new_size = msg->size; if(msg->is_compressed == FALSE) { crm_debug_2("Returning uncompressed message data"); uncompressed = strdup(msg->data); } else { crm_debug_2("Decompressing message data"); crm_malloc0(uncompressed, new_size); rc = BZ2_bzBuffToBuffDecompress( uncompressed, &new_size, msg->data, msg->compressed_size, 1, 0); CRM_ASSERT(rc = BZ_OK); CRM_ASSERT(new_size == msg->size); } return uncompressed; } #if SUPPORT_AIS int ais_fd_sync = -1; static int ais_fd_async = -1; /* never send messages via this channel */ GFDSource *ais_source = NULL; GFDSource *ais_source_sync = NULL; struct res_overlay { mar_res_header_t header __attribute((aligned(8))); /* char buf[4096]; */ }; gboolean send_ais_text(int class, const char *data, gboolean local, const char *node, enum crm_ais_msg_types dest) { int retries = 0; static int msg_id = 0; static int local_pid = 0; int rc = SA_AIS_OK; mar_res_header_t header; AIS_Message *ais_msg = NULL; enum crm_ais_msg_types sender = text2msg_type(crm_system_name); if(local_pid == 0) { local_pid = getpid(); } CRM_CHECK(data != NULL, return FALSE); crm_malloc0(ais_msg, sizeof(AIS_Message)); ais_msg->id = msg_id++; ais_msg->header.id = class; ais_msg->host.type = dest; ais_msg->host.local = local; if(node) { ais_msg->host.size = strlen(node); memset(ais_msg->host.uname, 0, MAX_NAME); memcpy(ais_msg->host.uname, node, ais_msg->host.size); ais_msg->host.id = 0; } else { ais_msg->host.size = 0; memset(ais_msg->host.uname, 0, MAX_NAME); ais_msg->host.id = 0; } ais_msg->sender.type = sender; ais_msg->sender.pid = local_pid; ais_msg->sender.size = 0; memset(ais_msg->sender.uname, 0, MAX_NAME); ais_msg->sender.id = 0; ais_msg->size = 1 + strlen(data); if(ais_msg->size < 5120) { failback: crm_realloc(ais_msg, sizeof(AIS_Message) + ais_msg->size); memcpy(ais_msg->data, data, ais_msg->size); } else { char *compressed = NULL; char *uncompressed = crm_strdup(data); unsigned int len = (ais_msg->size * 1.1) + 600; /* recomended size */ crm_debug_5("Compressing message payload"); crm_malloc0(compressed, len); rc = BZ2_bzBuffToBuffCompress( compressed, &len, uncompressed, ais_msg->size, 3, 0, 30); crm_free(uncompressed); if(rc != BZ_OK) { crm_err("Compression failed: %d", rc); crm_free(compressed); goto failback; } crm_realloc(ais_msg, sizeof(AIS_Message) + len + 1); memcpy(ais_msg->data, compressed, len); crm_free(compressed); ais_msg->is_compressed = TRUE; ais_msg->compressed_size = len; crm_debug("Compression details: %d -> %d", ais_msg->size, ais_data_len(ais_msg)); } ais_msg->header.size = sizeof(AIS_Message) + ais_data_len(ais_msg); crm_debug("Sending%s message %d to %s.%s (data=%d, total=%d)", ais_msg->is_compressed?" compressed":"", ais_msg->id, ais_dest(&(ais_msg->host)), msg_type2text(dest), ais_data_len(ais_msg), ais_msg->header.size); retry: errno = 0; rc = saSendReceiveReply(ais_fd_sync, ais_msg, ais_msg->header.size, &header, sizeof (mar_res_header_t)); if(rc == SA_AIS_OK) { CRM_CHECK(header.error == 0, rc = header.error); } if(rc == SA_AIS_ERR_TRY_AGAIN && retries < 20) { retries++; crm_info("Peer overloaded: Re-sending message (Attempt %d of 20)", retries); mssleep(retries * 100); /* Proportional back off */ goto retry; } if(rc != SA_AIS_OK) { cl_perror("Sending message %d: FAILED (rc=%d): %s", ais_msg->id, rc, ais_error2text(rc)); ais_fd_async = -1; } else { crm_debug_4("Message %d: sent", ais_msg->id); } crm_free(ais_msg); return (rc == SA_AIS_OK); } gboolean -send_ais_message(crm_data_t *msg, +send_ais_message(xmlNode *msg, gboolean local, const char *node, enum crm_ais_msg_types dest) { gboolean rc = TRUE; char *data = NULL; if(ais_fd_async < 0 || ais_source == NULL) { crm_err("Not connected to AIS"); return FALSE; } - if(cl_get_string(msg, F_XML_TAGNAME) == NULL) { - ha_msg_add(msg, F_XML_TAGNAME, "ais_msg"); - } - data = dump_xml_unformatted(msg); rc = send_ais_text(0, data, local, node, dest); crm_free(data); return rc; } void terminate_ais_connection(void) { close(ais_fd_sync); close(ais_fd_async); crm_notice("Disconnected from AIS"); /* G_main_del_fd(ais_source); */ /* G_main_del_fd(ais_source_sync); */ } static gboolean ais_dispatch(int sender, gpointer user_data) { char *data = NULL; char *uncompressed = NULL; AIS_Message *msg = NULL; SaAisErrorT rc = SA_AIS_OK; mar_res_header_t *header = NULL; static int header_len = sizeof(mar_res_header_t); gboolean (*dispatch)(AIS_Message*,char*,int) = user_data; crm_malloc0(header, header_len); errno = 0; rc = saRecvRetry(sender, header, header_len); if (rc != SA_AIS_OK) { cl_perror("Receiving message header failed: (%d) %s", rc, ais_error2text(rc)); goto bail; } else if(header->size == header_len) { crm_err("Empty message: error=%d", header->error); goto done; } else if(header->size == 0 || header->size < header_len) { crm_err("Mangled header: size=%d, header=%d, error=%d", header->size, header_len, header->error); goto done; } else if(header->error != 0) { crm_err("Header contined error: %d", header->error); } crm_debug_2("Looking for %d (%d - %d) more bytes", header->size - header_len, header->size, header_len); crm_realloc(header, header->size); /* Use a char* so we can store the remainder into an offset */ data = (char*)header; errno = 0; rc = saRecvRetry(sender, data+header_len, header->size - header_len); msg = (AIS_Message*)data; if (rc != SA_AIS_OK) { cl_perror("Receiving message body failed: (%d) %s", rc, ais_error2text(rc)); goto bail; } crm_debug_3("Got new%s message (size=%d, %d, %d)", msg->is_compressed?" compressed":"", ais_data_len(msg), msg->size, msg->compressed_size); data = msg->data; if(msg->is_compressed) { int rc = BZ_OK; unsigned int new_size = msg->size; if(check_message_sanity(msg, NULL) == FALSE) { goto badmsg; } crm_debug_5("Decompressing message data"); crm_malloc0(uncompressed, new_size); rc = BZ2_bzBuffToBuffDecompress( uncompressed, &new_size, data, msg->compressed_size, 1, 0); if(rc != BZ_OK) { crm_err("Decompression failed: %d", rc); crm_free(uncompressed); goto badmsg; } CRM_ASSERT(rc == BZ_OK); CRM_ASSERT(new_size == msg->size); data = uncompressed; } else if(check_message_sanity(msg, data) == FALSE) { goto badmsg; } else if(safe_str_eq("identify", data)) { int pid = getpid(); char *pid_s = crm_itoa(pid); send_ais_text(0, pid_s, TRUE, NULL, crm_msg_ais); crm_free(pid_s); goto done; } if(msg->header.id == crm_class_members) { - crm_data_t *xml = string2xml(data); + xmlNode *xml = string2xml(data); if(xml != NULL) { const char *seq_s = crm_element_value(xml, "id"); unsigned long seq = crm_int_helper(seq_s, NULL); crm_info("Processing membership %ld/%s", seq, seq_s); /* crm_log_xml_debug(xml, __PRETTY_FUNCTION__); */ xml_child_iter(xml, node, crm_update_ais_node(node, seq)); crm_calculate_quorum(); } else { crm_warn("Invalid peer update: %s", data); } free_xml(xml); } if(dispatch != NULL) { dispatch(msg, data, sender); } done: crm_free(uncompressed); crm_free(msg); return TRUE; badmsg: crm_err("Invalid message (id=%d, dest=%s:%s, from=%s:%s.%d):" " min=%d, total=%d, size=%d, bz2_size=%d", msg->id, ais_dest(&(msg->host)), msg_type2text(msg->host.type), ais_dest(&(msg->sender)), msg_type2text(msg->sender.type), msg->sender.pid, (int)sizeof(AIS_Message), msg->header.size, msg->size, msg->compressed_size); goto done; bail: crm_err("AIS connection failed"); return FALSE; } static void ais_destroy(gpointer user_data) { crm_err("AIS connection terminated"); ais_fd_sync = -1; exit(1); } gboolean init_ais_connection( gboolean (*dispatch)(AIS_Message*,char*,int), void (*destroy)(gpointer), char **our_uuid, char **our_uname) { int rc = SA_AIS_OK; struct utsname name; if(our_uname != NULL) { if(uname(&name) < 0) { cl_perror("uname(2) call failed"); exit(100); } *our_uname = crm_strdup(name.nodename); crm_notice("Local node name: %s", *our_uname); } if(our_uuid != NULL) { *our_uuid = crm_strdup(name.nodename); } /* 16 := CRM_SERVICE */ crm_info("Creating connection to our AIS plugin"); rc = saServiceConnect (&ais_fd_async, &ais_fd_sync, 16); if (rc != SA_AIS_OK) { crm_info("Connection to our AIS plugin failed"); return FALSE; } if(destroy == NULL) { crm_debug("Using the default destroy handler"); destroy = ais_destroy; } crm_info("AIS connection established"); #if 0 ais_source_sync = G_main_add_fd( G_PRIORITY_HIGH, ais_fd_sync, FALSE, ais_dispatch, dispatch, destroy); #endif ais_source = G_main_add_fd( G_PRIORITY_HIGH, ais_fd_async, FALSE, ais_dispatch, dispatch, destroy); return TRUE; } gboolean check_message_sanity(AIS_Message *msg, char *data) { gboolean sane = TRUE; gboolean repaired = FALSE; int dest = msg->host.type; int tmp_size = msg->header.size - sizeof(AIS_Message); if(sane && msg->header.size == 0) { crm_warn("Message with no size"); sane = FALSE; } if(sane && msg->header.error != 0) { crm_warn("Message header contains an error: %d", msg->header.error); sane = FALSE; } if(sane && ais_data_len(msg) != tmp_size) { int cur_size = ais_data_len(msg); repaired = TRUE; if(msg->is_compressed) { msg->compressed_size = tmp_size; } else { msg->size = tmp_size; } crm_warn("Repaired message payload size %d -> %d", cur_size, tmp_size); } if(sane && ais_data_len(msg) == 0) { crm_warn("Message with no payload"); sane = FALSE; } if(sane && data && msg->is_compressed == FALSE) { int str_size = strlen(data) + 1; if(ais_data_len(msg) != str_size) { int lpc = 0; crm_warn("Message payload is corrupted: expected %d bytes, got %d", ais_data_len(msg), str_size); sane = FALSE; for(lpc = (str_size - 10); lpc < msg->size; lpc++) { if(lpc < 0) { lpc = 0; } crm_debug("bad_data[%d]: %d / '%c'", lpc, data[lpc], data[lpc]); } } } if(sane == FALSE) { crm_err("Invalid message %d: (dest=%s:%s, from=%s:%s.%d, compressed=%d, size=%d, total=%d)", msg->id, ais_dest(&(msg->host)), msg_type2text(dest), ais_dest(&(msg->sender)), msg_type2text(msg->sender.type), msg->sender.pid, msg->is_compressed, ais_data_len(msg), msg->header.size); } else if(repaired) { crm_err("Repaired message %d: (dest=%s:%s, from=%s:%s.%d, compressed=%d, size=%d, total=%d)", msg->id, ais_dest(&(msg->host)), msg_type2text(dest), ais_dest(&(msg->sender)), msg_type2text(msg->sender.type), msg->sender.pid, msg->is_compressed, ais_data_len(msg), msg->header.size); } else { crm_debug_3("Verfied message %d: (dest=%s:%s, from=%s:%s.%d, compressed=%d, size=%d, total=%d)", msg->id, ais_dest(&(msg->host)), msg_type2text(dest), ais_dest(&(msg->sender)), msg_type2text(msg->sender.type), msg->sender.pid, msg->is_compressed, ais_data_len(msg), msg->header.size); } return sane; } #endif diff --git a/lib/crm/common/cluster.c b/lib/crm/common/cluster.c index cc3f7dea98..42c015c9be 100644 --- a/lib/crm/common/cluster.c +++ b/lib/crm/common/cluster.c @@ -1,247 +1,247 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "stack.h" -HA_Message *create_common_message( - HA_Message *original_request, crm_data_t *xml_response_data); +xmlNode *create_common_message( + xmlNode *original_request, xmlNode *xml_response_data); gboolean crm_cluster_connect( char **our_uname, char **our_uuid, void *dispatch, void *destroy, #if SUPPORT_HEARTBEAT ll_cluster_t **hb_conn #else void **hb_conn #endif ) { if(hb_conn != NULL) { *hb_conn = NULL; } #if SUPPORT_AIS if(is_openais_cluster()) { crm_peer_init(); return init_ais_connection(dispatch, destroy, our_uuid, our_uname); } #endif #if SUPPORT_HEARTBEAT if(is_heartbeat_cluster()) { CRM_ASSERT(hb_conn != NULL); if(*hb_conn == NULL) { *hb_conn = ll_cluster_new("heartbeat"); } heartbeat_cluster = *hb_conn; /* make sure we are disconnected first */ heartbeat_cluster->llc_ops->signoff(heartbeat_cluster, FALSE); return register_heartbeat_conn( heartbeat_cluster, our_uuid, our_uname, dispatch, destroy); } #endif return FALSE; } gboolean send_cluster_message( - const char *node, enum crm_ais_msg_types service, HA_Message *data, gboolean ordered) { + const char *node, enum crm_ais_msg_types service, xmlNode *data, gboolean ordered) { #if SUPPORT_AIS if(is_openais_cluster()) { return send_ais_message(data, FALSE, node, service); } #endif #if SUPPORT_HEARTBEAT if(is_heartbeat_cluster()) { return send_ha_message(heartbeat_cluster, data, node, ordered); } #endif return FALSE; } static GHashTable *crm_uuid_cache = NULL; static GHashTable *crm_uname_cache = NULL; void empty_uuid_cache(void) { if(crm_uuid_cache != NULL) { g_hash_table_destroy(crm_uuid_cache); crm_uuid_cache = NULL; } } void unget_uuid(const char *uname) { if(crm_uuid_cache == NULL) { return; } g_hash_table_remove(crm_uuid_cache, uname); } const char * get_uuid(const char *uname) { char *uuid_calc = NULL; CRM_CHECK(uname != NULL, return NULL); if(crm_uuid_cache == NULL) { crm_uuid_cache = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); } CRM_CHECK(uname != NULL, return NULL); /* avoid blocking calls where possible */ uuid_calc = g_hash_table_lookup(crm_uuid_cache, uname); if(uuid_calc != NULL) { return uuid_calc; } #if SUPPORT_AIS if(is_openais_cluster()) { uuid_calc = crm_strdup(uname); goto fallback; } #endif #if SUPPORT_HEARTBEAT if(is_heartbeat_cluster()) { cl_uuid_t uuid_raw; const char *unknown = "00000000-0000-0000-0000-000000000000"; if(heartbeat_cluster == NULL) { crm_warn("No connection to heartbeat, using uuid=uname"); uuid_calc = crm_strdup(uname); goto fallback; } if(heartbeat_cluster->llc_ops->get_uuid_by_name( heartbeat_cluster, uname, &uuid_raw) == HA_FAIL) { crm_err("get_uuid_by_name() call failed for host %s", uname); crm_free(uuid_calc); return NULL; } crm_malloc0(uuid_calc, 50); cl_uuid_unparse(&uuid_raw, uuid_calc); if(safe_str_eq(uuid_calc, unknown)) { crm_warn("Could not calculate UUID for %s", uname); crm_free(uuid_calc); return NULL; } } #endif fallback: g_hash_table_insert(crm_uuid_cache, crm_strdup(uname), uuid_calc); uuid_calc = g_hash_table_lookup(crm_uuid_cache, uname); return uuid_calc; } const char * get_uname(const char *uuid) { char *uname = NULL; if(crm_uuid_cache == NULL) { crm_uname_cache = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); } CRM_CHECK(uuid != NULL, return NULL); /* avoid blocking calls where possible */ uname = g_hash_table_lookup(crm_uname_cache, uuid); if(uname != NULL) { return uname; } #if SUPPORT_AIS if(is_openais_cluster()) { g_hash_table_insert(crm_uuid_cache, crm_strdup(uuid), crm_strdup(uuid)); } #endif #if SUPPORT_HEARTBEAT if(is_heartbeat_cluster()) { if(heartbeat_cluster != NULL && uuid != NULL) { cl_uuid_t uuid_raw; char *uuid_copy = crm_strdup(uuid); cl_uuid_parse(uuid_copy, &uuid_raw); if(heartbeat_cluster->llc_ops->get_name_by_uuid( heartbeat_cluster, &uuid_raw, uname, 256) == HA_FAIL) { crm_err("Could not calculate UUID for %s", uname); crm_free(uuid_copy); } else { g_hash_table_insert(crm_uuid_cache, uuid_copy, crm_strdup(uname)); } } } #endif return g_hash_table_lookup(crm_uname_cache, uuid); } void -set_uuid(crm_data_t *node,const char *attr,const char *uname) +set_uuid(xmlNode *node,const char *attr,const char *uname) { const char *uuid_calc = get_uuid(uname); crm_xml_add(node, attr, uuid_calc); return; } -crm_data_t* +xmlNode* createPingAnswerFragment(const char *from, const char *status) { - crm_data_t *ping = NULL; + xmlNode *ping = NULL; ping = create_xml_node(NULL, XML_CRM_TAG_PING); crm_xml_add(ping, XML_PING_ATTR_STATUS, status); crm_xml_add(ping, XML_PING_ATTR_SYSFROM, from); return ping; } diff --git a/lib/crm/common/heartbeat.c b/lib/crm/common/heartbeat.c index 6040122b5d..dc97e33841 100644 --- a/lib/crm/common/heartbeat.c +++ b/lib/crm/common/heartbeat.c @@ -1,215 +1,217 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "stack.h" -HA_Message *create_common_message( - HA_Message *original_request, crm_data_t *xml_response_data); +xmlNode *create_common_message( + xmlNode *original_request, xmlNode *xml_response_data); #if SUPPORT_HEARTBEAT ll_cluster_t *heartbeat_cluster = NULL; gboolean -send_ha_message(ll_cluster_t *hb_conn, HA_Message *msg, const char *node, gboolean force_ordered) +send_ha_message(ll_cluster_t *hb_conn, xmlNode *xml, const char *node, gboolean force_ordered) { gboolean all_is_good = TRUE; + HA_Message *msg = convert_xml_message(xml); if (msg == NULL) { crm_err("cant send NULL message"); all_is_good = FALSE; } else if(hb_conn == NULL) { crm_err("No heartbeat connection specified"); all_is_good = FALSE; } else if(hb_conn->llc_ops->chan_is_connected(hb_conn) == FALSE) { crm_err("Not connected to Heartbeat"); all_is_good = FALSE; } else if(node != NULL) { if(hb_conn->llc_ops->send_ordered_nodemsg( hb_conn, msg, node) != HA_OK) { all_is_good = FALSE; crm_err("Send failed"); } } else if(force_ordered) { if(hb_conn->llc_ops->send_ordered_clustermsg(hb_conn, msg) != HA_OK) { all_is_good = FALSE; crm_err("Broadcast Send failed"); } } else { if(hb_conn->llc_ops->sendclustermsg(hb_conn, msg) != HA_OK) { all_is_good = FALSE; crm_err("Broadcast Send failed"); } } if(all_is_good == FALSE && hb_conn != NULL) { IPC_Channel *ipc = NULL; IPC_Queue *send_q = NULL; if(hb_conn->llc_ops->chan_is_connected(hb_conn) != HA_OK) { ipc = hb_conn->llc_ops->ipcchan(hb_conn); } if(ipc != NULL) { /* ipc->ops->resume_io(ipc); */ send_q = ipc->send_queue; } if(send_q != NULL) { CRM_CHECK(send_q->current_qlen < send_q->max_qlen, ;); } } - crm_log_message_adv(all_is_good?LOG_MSG:LOG_WARNING,"HA[outbound]",msg); + crm_log_xml(all_is_good?LOG_MSG:LOG_WARNING, "HA[outbound]", xml); + crm_msg_del(msg); return all_is_good; } gboolean ha_msg_dispatch(ll_cluster_t *cluster_conn, gpointer user_data) { IPC_Channel *channel = NULL; crm_debug_3("Invoked"); if(cluster_conn != NULL) { channel = cluster_conn->llc_ops->ipcchan(cluster_conn); } CRM_CHECK(cluster_conn != NULL, return FALSE); CRM_CHECK(channel != NULL, return FALSE); if(channel != NULL && IPC_ISRCONN(channel)) { if(cluster_conn->llc_ops->msgready(cluster_conn) == 0) { crm_debug_2("no message ready yet"); } /* invoke the callbacks but dont block */ cluster_conn->llc_ops->rcvmsg(cluster_conn, 0); } if (channel == NULL || channel->ch_status != IPC_CONNECT) { crm_info("Lost connection to heartbeat service."); return FALSE; } return TRUE; } gboolean register_heartbeat_conn( ll_cluster_t *hb_cluster, char **uuid, char **uname, - void (*hb_message)(HA_Message * msg, void* private_data), + void (*hb_message)(HA_Message *msg, void* private_data), void (*hb_destroy)(gpointer user_data)) { const char *const_uuid = NULL; const char *const_uname = NULL; crm_debug("Signing in with Heartbeat"); if (hb_cluster->llc_ops->signon(hb_cluster, crm_system_name) != HA_OK) { crm_err("Cannot sign on with heartbeat: %s", hb_cluster->llc_ops->errmsg(hb_cluster)); return FALSE; } if (HA_OK != hb_cluster->llc_ops->set_msg_callback( hb_cluster, crm_system_name, hb_message, hb_cluster)){ crm_err("Cannot set msg callback: %s", hb_cluster->llc_ops->errmsg(hb_cluster)); return FALSE; } G_main_add_ll_cluster(G_PRIORITY_HIGH, hb_cluster, FALSE, ha_msg_dispatch, hb_cluster, hb_destroy); const_uname = hb_cluster->llc_ops->get_mynodeid(hb_cluster); CRM_CHECK(const_uname != NULL, return FALSE); const_uuid = get_uuid(const_uname); CRM_CHECK(const_uuid != NULL, return FALSE); crm_info("Hostname: %s", const_uname); crm_info("UUID: %s", const_uuid); if(uname) { *uname = crm_strdup(const_uname); } if(uuid) { *uuid = crm_strdup(const_uuid); } return TRUE; } gboolean ccm_have_quorum(oc_ed_t event) { if(event==OC_EV_MS_NEW_MEMBERSHIP || event==OC_EV_MS_PRIMARY_RESTORED) { return TRUE; } return FALSE; } const char * ccm_event_name(oc_ed_t event) { if(event==OC_EV_MS_NEW_MEMBERSHIP) { return "NEW MEMBERSHIP"; } else if(event==OC_EV_MS_NOT_PRIMARY) { return "NOT PRIMARY"; } else if(event==OC_EV_MS_PRIMARY_RESTORED) { return "PRIMARY RESTORED"; } else if(event==OC_EV_MS_EVICTED) { return "EVICTED"; } else if(event==OC_EV_MS_INVALID) { return "INVALID"; } return "NO QUORUM MEMBERSHIP"; } #endif diff --git a/lib/crm/common/ipc.c b/lib/crm/common/ipc.c index b67dc44019..9262851594 100644 --- a/lib/crm/common/ipc.c +++ b/lib/crm/common/ipc.c @@ -1,654 +1,713 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include + +xmlNode *xmlfromIPC(IPC_Channel *ch, int timeout) +{ + xmlNode *xml = NULL; + HA_Message *msg = NULL; + +#if HAVE_MSGFROMIPC_TIMEOUT + int ipc_rc = 0; + + msg = msgfromIPC_timeout(ch, MSG_ALLOWINTR, timeout, &ipc_rc); + + if(ipc_rc == IPC_TIMEOUT) { + crm_err("No message received in the required interval (%ds)", timeout); + return NULL; + } +#else + if(timeout) { + crm_warn("Timeouts are not supported"); + } + msg = msgfromIPC_noauth(ch); +#endif + + xml = convert_ha_message(NULL, msg, __FUNCTION__); + crm_msg_del(msg); + + return xml; +} + +static int xml2ipcchan(xmlNode *m, IPC_Channel *ch) +{ + HA_Message *msg = NULL; + IPC_Message *imsg = NULL; + + if (m == NULL || ch == NULL) { + cl_log(LOG_ERR, "Invalid msg2ipcchan argument"); + errno = EINVAL; + return HA_FAIL; + } + + msg = convert_xml_message(m); + if ((imsg = hamsg2ipcmsg(msg, ch)) == NULL) { + cl_log(LOG_ERR, "hamsg2ipcmsg() failure"); + crm_msg_del(msg); + return HA_FAIL; + } + crm_msg_del(msg); + + if (ch->ops->send(ch, imsg) != IPC_OK) { + if (ch->ch_status == IPC_CONNECT) { + snprintf(ch->failreason,MAXFAILREASON, + "send failed,farside_pid=%d, sendq length=%ld(max is %ld)", + ch->farside_pid, (long)ch->send_queue->current_qlen, + (long)ch->send_queue->max_qlen); + } + imsg->msg_done(imsg); + return HA_FAIL; + } + return HA_OK; +} + /* frees msg */ gboolean -send_ipc_message(IPC_Channel *ipc_client, HA_Message *msg) +send_ipc_message(IPC_Channel *ipc_client, xmlNode *msg) { gboolean all_is_good = TRUE; int fail_level = LOG_WARNING; if(ipc_client != NULL && ipc_client->conntype == IPC_CLIENT) { fail_level = LOG_ERR; } if (msg == NULL) { crm_err("cant send NULL message"); all_is_good = FALSE; } else if (ipc_client == NULL) { crm_err("cant send message without an IPC Channel"); all_is_good = FALSE; } else if(ipc_client->ops->get_chan_status(ipc_client) != IPC_CONNECT) { do_crm_log(fail_level, "IPC Channel to %d is not connected", (int)ipc_client->farside_pid); all_is_good = FALSE; } - if(all_is_good && msg2ipcchan(msg, ipc_client) != HA_OK) { + if(all_is_good && xml2ipcchan(msg, ipc_client) != HA_OK) { do_crm_log(fail_level, "Could not send IPC message to %d", (int)ipc_client->farside_pid); all_is_good = FALSE; if(ipc_client->ops->get_chan_status(ipc_client) != IPC_CONNECT) { do_crm_log(fail_level, "IPC Channel to %d is no longer connected", (int)ipc_client->farside_pid); } else if(ipc_client->conntype == IPC_CLIENT) { if(ipc_client->send_queue->current_qlen >= ipc_client->send_queue->max_qlen) { crm_err("Send queue to %d (size=%d) full.", ipc_client->farside_pid, (int)ipc_client->send_queue->max_qlen); } } } /* ipc_client->ops->resume_io(ipc_client); */ - crm_log_message_adv(all_is_good?LOG_MSG:LOG_WARNING,"IPC[outbound]",msg); + crm_log_xml(all_is_good?LOG_MSG:LOG_WARNING,"IPC[outbound]",msg); return all_is_good; } void default_ipc_connection_destroy(gpointer user_data) { return; } int init_server_ipc_comms( char *channel_name, gboolean (*channel_client_connect)(IPC_Channel *newclient,gpointer user_data), void (*channel_connection_destroy)(gpointer user_data)) { /* the clients wait channel is the other source of events. * This source delivers the clients connection events. * listen to this source at a relatively lower priority. */ char commpath[SOCKET_LEN]; IPC_WaitConnection *wait_ch; sprintf(commpath, CRM_SOCK_DIR "/%s", channel_name); wait_ch = wait_channel_init(commpath); if (wait_ch == NULL) { return 1; } G_main_add_IPC_WaitConnection( G_PRIORITY_LOW, wait_ch, NULL, FALSE, channel_client_connect, channel_name, channel_connection_destroy); crm_debug_3("Listening on: %s", commpath); return 0; } GCHSource* init_client_ipc_comms(const char *channel_name, gboolean (*dispatch)( IPC_Channel* source_data, gpointer user_data), void *client_data, IPC_Channel **ch) { IPC_Channel *a_ch = NULL; GCHSource *the_source = NULL; void *callback_data = client_data; a_ch = init_client_ipc_comms_nodispatch(channel_name); if(ch != NULL) { *ch = a_ch; if(callback_data == NULL) { callback_data = a_ch; } } if(a_ch == NULL) { crm_warn("Setup of client connection failed," " not adding channel to mainloop"); return NULL; } if(dispatch == NULL) { crm_warn("No dispatch method specified..." "maybe you meant init_client_ipc_comms_nodispatch()?"); } else { crm_debug_3("Adding dispatch method to channel"); the_source = G_main_add_IPC_Channel( G_PRIORITY_HIGH, a_ch, FALSE, dispatch, callback_data, default_ipc_connection_destroy); } return the_source; } IPC_Channel * init_client_ipc_comms_nodispatch(const char *channel_name) { IPC_Channel *ch; GHashTable *attrs; static char path[] = IPC_PATH_ATTR; char *commpath = NULL; int local_socket_len = 2; /* 2 = '/' + '\0' */ local_socket_len += strlen(channel_name); local_socket_len += strlen(CRM_SOCK_DIR); crm_malloc0(commpath, local_socket_len); sprintf(commpath, CRM_SOCK_DIR "/%s", channel_name); commpath[local_socket_len - 1] = '\0'; crm_debug("Attempting to talk on: %s", commpath); attrs = g_hash_table_new(g_str_hash,g_str_equal); g_hash_table_insert(attrs, path, commpath); ch = ipc_channel_constructor(IPC_ANYTYPE, attrs); g_hash_table_destroy(attrs); if (ch == NULL) { crm_err("Could not access channel on: %s", commpath); crm_free(commpath); return NULL; } else if (ch->ops->initiate_connection(ch) != IPC_OK) { crm_debug("Could not init comms on: %s", commpath); ch->ops->destroy(ch); crm_free(commpath); return NULL; } ch->ops->set_recv_qlen(ch, 512); ch->ops->set_send_qlen(ch, 512); ch->should_send_block = TRUE; crm_debug_3("Processing of %s complete", commpath); crm_free(commpath); return ch; } IPC_WaitConnection * wait_channel_init(char daemonsocket[]) { IPC_WaitConnection *wait_ch; mode_t mask; char path[] = IPC_PATH_ATTR; GHashTable * attrs; attrs = g_hash_table_new(g_str_hash,g_str_equal); g_hash_table_insert(attrs, path, daemonsocket); mask = umask(0); wait_ch = ipc_wait_conn_constructor(IPC_ANYTYPE, attrs); if (wait_ch == NULL) { cl_perror("Can't create wait channel of type %s", IPC_ANYTYPE); exit(1); } mask = umask(mask); g_hash_table_destroy(attrs); return wait_ch; } longclock_t ipc_call_start = 0; longclock_t ipc_call_stop = 0; longclock_t ipc_call_diff = 0; gboolean subsystem_msg_dispatch(IPC_Channel *sender, void *user_data) { int lpc = 0; - HA_Message *msg = NULL; + xmlNode *msg = NULL; ha_msg_input_t *new_input = NULL; gboolean all_is_well = TRUE; const char *sys_to; const char *task; while(IPC_ISRCONN(sender)) { gboolean process = FALSE; if(sender->ops->is_message_pending(sender) == 0) { break; } - msg = msgfromIPC_noauth(sender); + msg = xmlfromIPC(sender, 0); if (msg == NULL) { crm_err("No message from %d this time", sender->farside_pid); continue; } lpc++; new_input = new_ha_msg_input(msg); - crm_msg_del(msg); + free_xml(msg); msg = NULL; - crm_log_message(LOG_MSG, new_input->msg); + crm_log_xml(LOG_MSG, "ipc", new_input->msg); - sys_to = cl_get_string(new_input->msg, F_CRM_SYS_TO); - task = cl_get_string(new_input->msg, F_CRM_TASK); + sys_to = crm_element_value(new_input->msg, F_CRM_SYS_TO); + task = crm_element_value(new_input->msg, F_CRM_TASK); if(safe_str_eq(task, CRM_OP_HELLO)) { process = TRUE; } else if(sys_to == NULL) { crm_err("Value of %s was NULL!!", F_CRM_SYS_TO); } else if(task == NULL) { crm_err("Value of %s was NULL!!", F_CRM_TASK); } else { process = TRUE; } if(process){ gboolean (*process_function) - (HA_Message *msg, crm_data_t *data, IPC_Channel *sender) = NULL; + (xmlNode *msg, xmlNode *data, IPC_Channel *sender) = NULL; process_function = user_data; #ifdef MSG_LOG - crm_log_message_adv( + crm_log_xml( LOG_MSG, __FUNCTION__, new_input->msg); #endif if(ipc_call_diff_max_ms > 0) { ipc_call_start = time_longclock(); } if(FALSE == process_function( new_input->msg, new_input->xml, sender)) { crm_warn("Received a message destined for %s" " by mistake", sys_to); } if(ipc_call_diff_max_ms > 0) { unsigned int ipc_call_diff_ms = 0; ipc_call_stop = time_longclock(); ipc_call_diff = sub_longclock( ipc_call_stop, ipc_call_start); ipc_call_diff_ms = longclockto_ms( ipc_call_diff); if(ipc_call_diff_ms > ipc_call_diff_max_ms) { crm_err("%s took %dms to complete", sys_to, ipc_call_diff_ms); } } } else { #ifdef MSG_LOG - crm_log_message_adv( + crm_log_xml( LOG_ERR, NULL, new_input->msg); #endif } delete_ha_msg_input(new_input); new_input = NULL; if(sender->ch_status == IPC_CONNECT) { break; } } crm_debug_2("Processed %d messages", lpc); if (sender->ch_status != IPC_CONNECT) { crm_err("The server %d has left us: Shutting down...NOW", sender->farside_pid); exit(1); /* shutdown properly later */ return !all_is_well; } return all_is_well; } gboolean is_ipc_empty(IPC_Channel *ch) { if(ch == NULL) { return TRUE; } else if(ch->send_queue->current_qlen == 0 && ch->recv_queue->current_qlen == 0) { return TRUE; } return FALSE; } void send_hello_message(IPC_Channel *ipc_client, const char *uuid, const char *client_name, const char *major_version, const char *minor_version) { - crm_data_t *hello_node = NULL; - HA_Message *hello = NULL; + xmlNode *hello_node = NULL; + xmlNode *hello = NULL; if (uuid == NULL || strlen(uuid) == 0 || client_name == NULL || strlen(client_name) == 0 || major_version == NULL || strlen(major_version) == 0 || minor_version == NULL || strlen(minor_version) == 0) { crm_err("Missing fields, Hello message will not be valid."); return; } hello_node = create_xml_node(NULL, XML_TAG_OPTIONS); crm_xml_add(hello_node, "major_version", major_version); crm_xml_add(hello_node, "minor_version", minor_version); crm_xml_add(hello_node, "client_name", client_name); crm_xml_add(hello_node, "client_uuid", uuid); crm_debug_4("creating hello message"); hello = create_request( CRM_OP_HELLO, hello_node, NULL, NULL, client_name, uuid); send_ipc_message(ipc_client, hello); crm_debug_4("hello message sent"); free_xml(hello_node); - crm_msg_del(hello); + free_xml(hello); } gboolean -process_hello_message(crm_data_t *hello, +process_hello_message(xmlNode *hello, char **uuid, char **client_name, char **major_version, char **minor_version) { const char *local_uuid; const char *local_client_name; const char *local_major_version; const char *local_minor_version; *uuid = NULL; *client_name = NULL; *major_version = NULL; *minor_version = NULL; if(hello == NULL) { return FALSE; } local_uuid = crm_element_value(hello, "client_uuid"); local_client_name = crm_element_value(hello, "client_name"); local_major_version = crm_element_value(hello, "major_version"); local_minor_version = crm_element_value(hello, "minor_version"); if (local_uuid == NULL || strlen(local_uuid) == 0) { crm_err("Hello message was not valid (field %s not found)", "uuid"); return FALSE; } else if (local_client_name==NULL || strlen(local_client_name)==0){ crm_err("Hello message was not valid (field %s not found)", "client name"); return FALSE; } else if(local_major_version == NULL || strlen(local_major_version) == 0){ crm_err("Hello message was not valid (field %s not found)", "major version"); return FALSE; } else if (local_minor_version == NULL || strlen(local_minor_version) == 0){ crm_err("Hello message was not valid (field %s not found)", "minor version"); return FALSE; } *uuid = crm_strdup(local_uuid); *client_name = crm_strdup(local_client_name); *major_version = crm_strdup(local_major_version); *minor_version = crm_strdup(local_minor_version); crm_debug_3("Hello message ok"); return TRUE; } -HA_Message * -create_request_adv(const char *task, crm_data_t *msg_data, +xmlNode * +create_request_adv(const char *task, xmlNode *msg_data, const char *host_to, const char *sys_to, const char *sys_from, const char *uuid_from, const char *origin) { char *true_from = NULL; - HA_Message *request = NULL; + xmlNode *request = NULL; char *reference = generateReference(task, sys_from); if (uuid_from != NULL) { true_from = generate_hash_key(sys_from, uuid_from); } else if(sys_from != NULL) { true_from = crm_strdup(sys_from); } else { crm_err("No sys from specified"); } /* host_from will get set for us if necessary by CRMd when routed */ - request = ha_msg_new(11); - - ha_msg_add(request, F_CRM_ORIGIN, origin); - ha_msg_add(request, F_TYPE, T_CRM); - ha_msg_add(request, F_CRM_VERSION, CRM_FEATURE_SET); - ha_msg_add(request, F_CRM_MSG_TYPE, XML_ATTR_REQUEST); - ha_msg_add(request, XML_ATTR_REFERENCE, reference); - ha_msg_add(request, F_CRM_TASK, task); - ha_msg_add(request, F_CRM_SYS_TO, sys_to); - ha_msg_add(request, F_CRM_SYS_FROM, true_from); + request = create_xml_node(NULL, __FUNCTION__); + crm_xml_add(request, F_CRM_ORIGIN, origin); + crm_xml_add(request, F_TYPE, T_CRM); + crm_xml_add(request, F_CRM_VERSION, CRM_FEATURE_SET); + crm_xml_add(request, F_CRM_MSG_TYPE, XML_ATTR_REQUEST); + crm_xml_add(request, XML_ATTR_REFERENCE, reference); + crm_xml_add(request, F_CRM_TASK, task); + crm_xml_add(request, F_CRM_SYS_TO, sys_to); + crm_xml_add(request, F_CRM_SYS_FROM, true_from); /* HOSTTO will be ignored if it is to the DC anyway. */ if(host_to != NULL && strlen(host_to) > 0) { - ha_msg_add(request, F_CRM_HOST_TO, host_to); + crm_xml_add(request, F_CRM_HOST_TO, host_to); } if (msg_data != NULL) { add_message_xml(request, F_CRM_DATA, msg_data); } crm_free(reference); crm_free(true_from); return request; } ha_msg_input_t * -new_ha_msg_input(const HA_Message *orig) +new_ha_msg_input(xmlNode *orig) { ha_msg_input_t *input_copy = NULL; crm_malloc0(input_copy, sizeof(ha_msg_input_t)); - - input_copy->msg = ha_msg_copy(orig); + input_copy->msg = copy_xml(orig); input_copy->xml = get_message_xml(input_copy->msg, F_CRM_DATA); return input_copy; } ha_msg_input_t * -new_ipc_msg_input(IPC_Message *orig) +new_ipc_msg_input(xmlNode *orig) { + /* HA_Message *msg = NULL; */ ha_msg_input_t *input_copy = NULL; crm_malloc0(input_copy, sizeof(ha_msg_input_t)); - input_copy->msg = ipcmsg2hamsg(orig); + /* msg = ipcmsg2hamsg(orig); */ + input_copy->msg = copy_xml(orig); input_copy->xml = get_message_xml(input_copy->msg, F_CRM_DATA); return input_copy; } void delete_ha_msg_input(ha_msg_input_t *orig) { if(orig == NULL) { return; } - crm_msg_del(orig->msg); + free_xml(orig->msg); free_xml(orig->xml); crm_free(orig); } -HA_Message * +xmlNode * validate_crm_message( - HA_Message *msg, const char *sys, const char *uuid, const char *msg_type) + xmlNode *msg, const char *sys, const char *uuid, const char *msg_type) { const char *from = NULL; const char *to = NULL; const char *type = NULL; const char *crm_msg_reference = NULL; - HA_Message *action = NULL; + xmlNode *action = NULL; const char *true_sys; char *local_sys = NULL; if (msg == NULL) { return NULL; } - from = cl_get_string(msg, F_CRM_SYS_FROM); - to = cl_get_string(msg, F_CRM_SYS_TO); - type = cl_get_string(msg, F_CRM_MSG_TYPE); + from = crm_element_value(msg, F_CRM_SYS_FROM); + to = crm_element_value(msg, F_CRM_SYS_TO); + type = crm_element_value(msg, F_CRM_MSG_TYPE); - crm_msg_reference = cl_get_string(msg, XML_ATTR_REFERENCE); + crm_msg_reference = crm_element_value(msg, XML_ATTR_REFERENCE); action = msg; true_sys = sys; if (uuid != NULL) { local_sys = generate_hash_key(sys, uuid); true_sys = local_sys; } if (to == NULL) { crm_info("No sub-system defined."); action = NULL; } else if (true_sys != NULL && strcasecmp(to, true_sys) != 0) { crm_debug_3("The message is not for this sub-system (%s != %s).", to, true_sys); action = NULL; } crm_free(local_sys); if (type == NULL) { crm_info("No message type defined."); return NULL; } else if (msg_type != NULL && strcasecmp(msg_type, type) != 0) { crm_info("Expecting a (%s) message but received a (%s).", msg_type, type); action = NULL; } if (crm_msg_reference == NULL) { crm_info("No message crm_msg_reference defined."); action = NULL; } /* if(action != NULL) crm_debug_3( "XML is valid and node with message type (%s) found.", type); crm_debug_3("Returning node (%s)", crm_element_name(action)); */ return action; } /* * This method adds a copy of xml_response_data */ -HA_Message * -create_reply_adv(HA_Message *original_request, - crm_data_t *xml_response_data, const char *origin) +xmlNode * +create_reply_adv(xmlNode *original_request, + xmlNode *xml_response_data, const char *origin) { - HA_Message *reply = NULL; - - const char *host_from= cl_get_string(original_request, F_CRM_HOST_FROM); - const char *sys_from = cl_get_string(original_request, F_CRM_SYS_FROM); - const char *sys_to = cl_get_string(original_request, F_CRM_SYS_TO); - const char *type = cl_get_string(original_request, F_CRM_MSG_TYPE); - const char *operation= cl_get_string(original_request, F_CRM_TASK); - const char *crm_msg_reference = cl_get_string( + xmlNode *reply = NULL; + + const char *host_from= crm_element_value(original_request, F_CRM_HOST_FROM); + const char *sys_from = crm_element_value(original_request, F_CRM_SYS_FROM); + const char *sys_to = crm_element_value(original_request, F_CRM_SYS_TO); + const char *type = crm_element_value(original_request, F_CRM_MSG_TYPE); + const char *operation= crm_element_value(original_request, F_CRM_TASK); + const char *crm_msg_reference = crm_element_value( original_request, XML_ATTR_REFERENCE); if (type == NULL) { crm_err("Cannot create new_message," " no message type in original message"); CRM_ASSERT(type != NULL); return NULL; #if 0 } else if (strcasecmp(XML_ATTR_REQUEST, type) != 0) { crm_err("Cannot create new_message," " original message was not a request"); return NULL; #endif } - reply = ha_msg_new(10); - - ha_msg_add(reply, F_CRM_ORIGIN, origin); - ha_msg_add(reply, F_TYPE, T_CRM); - ha_msg_add(reply, F_CRM_VERSION, CRM_FEATURE_SET); - ha_msg_add(reply, F_CRM_MSG_TYPE, XML_ATTR_RESPONSE); - ha_msg_add(reply, XML_ATTR_REFERENCE, crm_msg_reference); - ha_msg_add(reply, F_CRM_TASK, operation); + reply = create_xml_node(NULL, __FUNCTION__); + crm_xml_add(reply, F_CRM_ORIGIN, origin); + crm_xml_add(reply, F_TYPE, T_CRM); + crm_xml_add(reply, F_CRM_VERSION, CRM_FEATURE_SET); + crm_xml_add(reply, F_CRM_MSG_TYPE, XML_ATTR_RESPONSE); + crm_xml_add(reply, XML_ATTR_REFERENCE, crm_msg_reference); + crm_xml_add(reply, F_CRM_TASK, operation); /* since this is a reply, we reverse the from and to */ - ha_msg_add(reply, F_CRM_SYS_TO, sys_from); - ha_msg_add(reply, F_CRM_SYS_FROM, sys_to); + crm_xml_add(reply, F_CRM_SYS_TO, sys_from); + crm_xml_add(reply, F_CRM_SYS_FROM, sys_to); /* HOSTTO will be ignored if it is to the DC anyway. */ if(host_from != NULL && strlen(host_from) > 0) { - ha_msg_add(reply, F_CRM_HOST_TO, host_from); + crm_xml_add(reply, F_CRM_HOST_TO, host_from); } if (xml_response_data != NULL) { add_message_xml(reply, F_CRM_DATA, xml_response_data); } return reply; } diff --git a/lib/crm/common/membership.c b/lib/crm/common/membership.c index ae3ec410c6..65095d8b85 100644 --- a/lib/crm/common/membership.c +++ b/lib/crm/common/membership.c @@ -1,390 +1,390 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #ifndef _GNU_SOURCE # define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include struct quorum_count_s { guint votes_max; guint votes_active; guint votes_total; guint nodes_max; guint nodes_total; }; GHashTable *crm_peer_cache = NULL; unsigned long long crm_peer_seq = 0; unsigned long long crm_max_peers = 0; struct quorum_count_s quorum_stats; gboolean crm_have_quorum = FALSE; gboolean crm_is_member_active(const crm_node_t *node) { if(safe_str_eq(node->state, CRM_NODE_MEMBER)) { return TRUE; } return FALSE; } static gboolean crm_reap_dead_member( gpointer key, gpointer value, gpointer user_data) { if(crm_is_member_active(value) == FALSE) { return TRUE; } return FALSE; } guint reap_crm_membership(void) { /* remove all dead members */ return g_hash_table_foreach_remove( crm_peer_cache, crm_reap_dead_member, NULL); } static void crm_count_member( gpointer key, gpointer value, gpointer user_data) { guint *count = user_data; if(crm_is_member_active(value)) { *count = *count + 1; } } guint crm_active_members(void) { guint count = 0; g_hash_table_foreach(crm_peer_cache, crm_count_member, &count); return count; } struct peer_count_s { uint32_t peer; guint count; }; static void crm_count_peer( gpointer key, gpointer value, gpointer user_data) { crm_node_t *node = value; struct peer_count_s *search = user_data; if(crm_is_member_active(node) && (node->processes & search->peer)) { search->count = search->count + 1; } } guint crm_active_peers(uint32_t peer) { struct peer_count_s search; search.count = 0; search.peer = peer; g_hash_table_foreach(crm_peer_cache, crm_count_peer, &search); return search.count; } void destroy_crm_node(gpointer data) { crm_node_t *node = data; crm_info("Destroying entry for node %u", node->id); crm_free(node->addr); crm_free(node->uname); crm_free(node->state); crm_free(node); } void crm_peer_init(void) { crm_warn("Set these options via openais.conf"); quorum_stats.votes_max = 2; quorum_stats.votes_active = 0; quorum_stats.votes_total = 0; quorum_stats.nodes_max = 1; quorum_stats.nodes_total = 0; crm_peer_destroy(); if(crm_peer_cache == NULL) { crm_peer_cache = g_hash_table_new_full( g_str_hash, g_str_equal, NULL, destroy_crm_node); } } void crm_peer_destroy(void) { if(crm_peer_cache != NULL) { g_hash_table_destroy(crm_peer_cache); crm_peer_cache = NULL; } } crm_node_t *crm_update_peer( unsigned int id, unsigned long long born, int32_t votes, uint32_t children, const char *uuid, const char *uname, const char *addr, const char *state) { crm_node_t *node = NULL; CRM_CHECK(uname != NULL, return NULL); CRM_ASSERT(crm_peer_cache != NULL); node = g_hash_table_lookup(crm_peer_cache, uname); if(node == NULL) { crm_info("Creating entry for node %s/%u/%llu", uname, id, born); CRM_CHECK(id >= 0, return NULL); CRM_CHECK(uuid != NULL, return NULL); crm_malloc0(node, sizeof(crm_node_t)); node->id = id; node->born = 0; node->processes = 0; node->uuid = crm_strdup(uuid); node->uname = crm_strdup(uname); node->votes = votes; node->addr = NULL; node->state = crm_strdup("unknown"); g_hash_table_insert(crm_peer_cache, node->uname, node); node = g_hash_table_lookup(crm_peer_cache, uname); CRM_ASSERT(node != NULL); } if(votes > 0 && node->votes != votes) { node->votes = votes; crm_info("Node %s now has %d votes", node->uname, votes); } if(id > 0 && id != node->id) { node->id = id; crm_info("Node %s now has id %u", node->uname, id); } if(children > 0 && children != node->processes) { crm_info("Node %s now has children: %.32x (%u)", node->uname, children, children); node->processes = children; } if(state != NULL) { if(node->state == NULL || crm_str_eq(node->state, state, FALSE) == FALSE) { crm_free(node->state); node->state = crm_strdup(state); crm_info("Node %s is now: %s", node->uname, state); if(crm_is_member_active(node)) { node->born = born; } else { node->born = -1; } } } if(addr != NULL) { if(node->addr == NULL || crm_str_eq(node->addr, addr, FALSE) == FALSE) { crm_free(node->addr); node->addr = crm_strdup(addr); crm_info("Node %s now has address: %s", node->uname, addr); } } return node; } -crm_node_t *crm_update_ais_node(crm_data_t *member, long long seq) +crm_node_t *crm_update_ais_node(xmlNode *member, long long seq) { const char *addr = crm_element_value(member, "addr"); const char *uname = crm_element_value(member, "uname"); const char *state = crm_element_value(member, "state"); const char *id_s = crm_element_value(member, "id"); const char *votes_s = crm_element_value(member, "votes"); const char *procs_s = crm_element_value(member, "processes"); int votes = crm_int_helper(votes_s, NULL); unsigned int id = crm_int_helper(id_s, NULL); unsigned int procs = crm_int_helper(procs_s, NULL); return crm_update_peer(id, seq, votes, procs, uname, uname, addr, state); } #if SUPPORT_HEARTBEAT crm_node_t *crm_update_ccm_node( const oc_ev_membership_t *oc, int offset, const char *state) { crm_node_t *node = NULL; const char *uuid = NULL; CRM_CHECK(oc->m_array[offset].node_uname != NULL, return NULL); uuid = get_uuid(oc->m_array[offset].node_uname); node = crm_update_peer(oc->m_array[offset].node_id, oc->m_array[offset].node_born_on, -1, 0, uuid, oc->m_array[offset].node_uname, NULL, state); if(safe_str_eq(CRM_NODE_ACTIVE, state)) { crm_update_peer_proc( oc->m_array[offset].node_uname, crm_proc_ais, ONLINESTATUS); } return node; } #endif void crm_update_peer_proc(const char *uname, uint32_t flag, const char *status) { crm_node_t *node = NULL; gboolean changed = FALSE; CRM_ASSERT(crm_peer_cache != NULL); CRM_CHECK(uname != NULL, return); node = g_hash_table_lookup(crm_peer_cache, uname); CRM_CHECK(node != NULL, return); if(safe_str_eq(status, ONLINESTATUS)) { if((node->processes & flag) == 0) { set_bit_inplace(node->processes, flag); changed = TRUE; } } else if(node->processes & flag) { clear_bit_inplace(node->processes, flag); changed = TRUE; } if(changed) { crm_info("%s.%s is now %s", uname, peer2text(flag), status); } } static void crm_count_quorum( gpointer key, gpointer value, gpointer user_data) { crm_node_t *node = value; quorum_stats.nodes_total += 1; quorum_stats.votes_total += node->votes; if(crm_is_member_active(node)) { quorum_stats.votes_active = quorum_stats.votes_active + node->votes; } } gboolean crm_calculate_quorum(void) { unsigned int limit = 0; gboolean quorate = TRUE; quorum_stats.votes_total = 0; quorum_stats.nodes_total = 0; quorum_stats.votes_active = 0; g_hash_table_foreach(crm_peer_cache, crm_count_quorum, NULL); if(quorum_stats.votes_total > quorum_stats.votes_max) { crm_info("Known quorum votes: %u -> %u", quorum_stats.votes_max, quorum_stats.votes_total); quorum_stats.votes_max = quorum_stats.votes_total; } if(quorum_stats.nodes_total > quorum_stats.nodes_max) { crm_info("Known quorum nodes: %u -> %u", quorum_stats.nodes_max, quorum_stats.nodes_total); quorum_stats.nodes_max = quorum_stats.nodes_total; } limit = (quorum_stats.votes_max + 2) / 2; if(quorum_stats.votes_active < limit) { quorate = FALSE; } crm_debug("known: %u, available: %u, limit: %u, active: %u: %s", quorum_stats.votes_max, quorum_stats.votes_total, limit, quorum_stats.votes_active, quorate?"true":"false"); if(quorate != crm_have_quorum) { crm_notice("Membership %llu: quorum %s", crm_peer_seq, quorate?"attained":"lost"); } else { crm_debug("Membership %llu: quorum %s", crm_peer_seq, quorate?"retained":"lost"); } crm_have_quorum = quorate; return quorate; } /* Code appropriated (with permission) from cman/daemon/commands.c under GPLv2 */ #if 0 static int calculate_quorum(int allow_decrease, int max_expected, unsigned int *ret_total_votes) { struct list *nodelist; struct cluster_node *node; unsigned int total_votes = 0; unsigned int highest_expected = 0; unsigned int newquorum, q1, q2; unsigned int total_nodes = 0; list_iterate(nodelist, &cluster_members_list) { node = list_item(nodelist, struct cluster_node); if (node->state == NODESTATE_MEMBER) { highest_expected = max(highest_expected, node->expected_votes); total_votes += node->votes; total_nodes++; } } if (quorum_device && quorum_device->state == NODESTATE_MEMBER) total_votes += quorum_device->votes; if (max_expected > 0) highest_expected = max_expected; /* This quorum calculation is taken from the OpenVMS Cluster Systems * manual, but, then, you guessed that didn't you */ q1 = (highest_expected + 2) / 2; q2 = (total_votes + 2) / 2; newquorum = max(q1, q2); /* Normally quorum never decreases but the system administrator can * force it down by setting expected votes to a maximum value */ if (!allow_decrease) newquorum = max(quorum, newquorum); /* The special two_node mode allows each of the two nodes to retain * quorum if the other fails. Only one of the two should live past * fencing (as both nodes try to fence each other in split-brain.) * Also: if there are more than two nodes, force us inquorate to avoid * any damage or confusion. */ if (two_node && total_nodes <= 2) newquorum = 1; if (ret_total_votes) *ret_total_votes = total_votes; return newquorum; } #endif diff --git a/lib/crm/common/stack.h b/lib/crm/common/stack.h index d62f151038..714f91adeb 100644 --- a/lib/crm/common/stack.h +++ b/lib/crm/common/stack.h @@ -1,48 +1,48 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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_STACK__H #define CRM_STACK__H #if SUPPORT_HEARTBEAT extern ll_cluster_t *heartbeat_cluster; -extern gboolean send_ha_message(ll_cluster_t *hb_conn, HA_Message *msg, +extern gboolean send_ha_message(ll_cluster_t *hb_conn, xmlNode *msg, const char *node, gboolean force_ordered); extern gboolean ha_msg_dispatch(ll_cluster_t *cluster_conn, gpointer user_data); extern gboolean register_heartbeat_conn( ll_cluster_t *hb_cluster, char **uuid, char **uname, - void (*hb_message)(HA_Message * msg, void* private_data), + void (*hb_message)(HA_Message *msg, void* private_data), void (*hb_destroy)(gpointer user_data)); #endif #if SUPPORT_AIS extern gboolean send_ais_message( - crm_data_t *msg, gboolean local, + xmlNode *msg, gboolean local, const char *node, enum crm_ais_msg_types dest); extern void terminate_ais_connection(void); extern gboolean init_ais_connection( gboolean (*dispatch)(AIS_Message*,char*,int), void (*destroy)(gpointer), char **our_uuid, char **our_uname); #endif #endif diff --git a/lib/crm/common/utils.c b/lib/crm/common/utils.c index 11567a9bcf..c1dc0f858d 100644 --- a/lib/crm/common/utils.c +++ b/lib/crm/common/utils.c @@ -1,1616 +1,1609 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #ifndef _GNU_SOURCE # define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef MAXLINE # define MAXLINE 512 #endif static uint ref_counter = 0; gboolean crm_assert_failed = FALSE; unsigned int crm_log_level = LOG_INFO; gboolean crm_config_error = FALSE; gboolean crm_config_warning = FALSE; const char *crm_system_name = "unknown"; void crm_set_env_options(void); gboolean check_time(const char *value) { if(crm_get_msec(value) < 5000) { return FALSE; } return TRUE; } gboolean check_timer(const char *value) { if(crm_get_msec(value) < 0) { return FALSE; } return TRUE; } gboolean check_boolean(const char *value) { int tmp = FALSE; if(crm_str_to_boolean(value, &tmp) != 1) { return FALSE; } return TRUE; } gboolean check_number(const char *value) { errno = 0; if(value == NULL) { return FALSE; } else if(safe_str_eq(value, MINUS_INFINITY_S)) { } else if(safe_str_eq(value, INFINITY_S)) { } else { crm_int_helper(value, NULL); } if(errno != 0) { return FALSE; } return TRUE; } int char2score(const char *score) { int score_f = 0; if(score == NULL) { } else if(safe_str_eq(score, MINUS_INFINITY_S)) { score_f = -INFINITY; } else if(safe_str_eq(score, INFINITY_S)) { score_f = INFINITY; } else if(safe_str_eq(score, "+"INFINITY_S)) { score_f = INFINITY; } else { score_f = crm_parse_int(score, NULL); if(score_f > 0 && score_f > INFINITY) { score_f = INFINITY; } else if(score_f < 0 && score_f < -INFINITY) { score_f = -INFINITY; } } return score_f; } char * score2char(int score) { if(score >= INFINITY) { return crm_strdup("+"INFINITY_S); } else if(score <= -INFINITY) { return crm_strdup("-"INFINITY_S); } return crm_itoa(score); } const char * cluster_option(GHashTable* options, gboolean(*validate)(const char*), const char *name, const char *old_name, const char *def_value) { const char *value = NULL; CRM_ASSERT(name != NULL); if(options != NULL) { value = g_hash_table_lookup(options, name); } if(value == NULL && old_name && options != NULL) { value = g_hash_table_lookup(options, old_name); if(value != NULL) { crm_config_warn("Using deprecated name '%s' for" " cluster option '%s'", old_name, name); g_hash_table_insert( options, crm_strdup(name), crm_strdup(value)); value = g_hash_table_lookup(options, old_name); } } if(value == NULL) { crm_debug("Using default value '%s' for cluster option '%s'", def_value, name); if(options == NULL) { return def_value; } g_hash_table_insert( options, crm_strdup(name), crm_strdup(def_value)); value = g_hash_table_lookup(options, name); } if(validate && validate(value) == FALSE) { crm_config_err("Value '%s' for cluster option '%s' is invalid." " Defaulting to %s", value, name, def_value); g_hash_table_replace(options, crm_strdup(name), crm_strdup(def_value)); value = g_hash_table_lookup(options, name); } return value; } const char * get_cluster_pref(GHashTable *options, pe_cluster_option *option_list, int len, const char *name) { int lpc = 0; const char *value = NULL; gboolean found = FALSE; for(lpc = 0; lpc < len; lpc++) { if(safe_str_eq(name, option_list[lpc].name)) { found = TRUE; value = cluster_option(options, option_list[lpc].is_valid, option_list[lpc].name, option_list[lpc].alt_name, option_list[lpc].default_value); } } CRM_CHECK(found, crm_err("No option named: %s", name)); CRM_ASSERT(value != NULL); return value; } void config_metadata(const char *name, const char *version, const char *desc_short, const char *desc_long, pe_cluster_option *option_list, int len) { int lpc = 0; fprintf(stdout, "" "\n" "\n" " %s\n" " %s\n" " %s\n" " \n", name, version, desc_long, desc_short); for(lpc = 0; lpc < len; lpc++) { if(option_list[lpc].description_long == NULL && option_list[lpc].description_short == NULL) { continue; } fprintf(stdout, " \n" " %s\n" " \n" " %s%s%s\n" " \n", option_list[lpc].name, option_list[lpc].description_short, option_list[lpc].type, option_list[lpc].default_value, option_list[lpc].description_long?option_list[lpc].description_long:option_list[lpc].description_short, option_list[lpc].values?" Allowed values: ":"", option_list[lpc].values?option_list[lpc].values:""); } fprintf(stdout, " \n\n"); } void verify_all_options(GHashTable *options, pe_cluster_option *option_list, int len) { int lpc = 0; for(lpc = 0; lpc < len; lpc++) { cluster_option(options, option_list[lpc].is_valid, option_list[lpc].name, option_list[lpc].alt_name, option_list[lpc].default_value); } } char * generateReference(const char *custom1, const char *custom2) { const char *local_cust1 = custom1; const char *local_cust2 = custom2; int reference_len = 4; char *since_epoch = NULL; reference_len += 20; /* too big */ reference_len += 40; /* too big */ if(local_cust1 == NULL) { local_cust1 = "_empty_"; } reference_len += strlen(local_cust1); if(local_cust2 == NULL) { local_cust2 = "_empty_"; } reference_len += strlen(local_cust2); crm_malloc0(since_epoch, reference_len); if(since_epoch != NULL) { sprintf(since_epoch, "%s-%s-%ld-%u", local_cust1, local_cust2, (unsigned long)time(NULL), ref_counter++); } return since_epoch; } gboolean decodeNVpair(const char *srcstring, char separator, char **name, char **value) { int lpc = 0; int len = 0; const char *temp = NULL; CRM_ASSERT(name != NULL && value != NULL); *name = NULL; *value = NULL; crm_debug_4("Attempting to decode: [%s]", srcstring); if (srcstring != NULL) { len = strlen(srcstring); while(lpc <= len) { if (srcstring[lpc] == separator) { crm_malloc0(*name, lpc+1); if(*name == NULL) { break; /* and return FALSE */ } strncpy(*name, srcstring, lpc); (*name)[lpc] = '\0'; /* this sucks but as the strtok manpage says.. * it *is* a bug */ len = len-lpc; len--; if(len <= 0) { *value = NULL; } else { crm_malloc0(*value, len+1); if(*value == NULL) { crm_free(*name); break; /* and return FALSE */ } temp = srcstring+lpc+1; strncpy(*value, temp, len); (*value)[len] = '\0'; } return TRUE; } lpc++; } } if(*name != NULL) { crm_free(*name); } *name = NULL; *value = NULL; return FALSE; } char * crm_concat(const char *prefix, const char *suffix, char join) { int len = 0; char *new_str = NULL; CRM_ASSERT(prefix != NULL); CRM_ASSERT(suffix != NULL); len = strlen(prefix) + strlen(suffix) + 2; crm_malloc0(new_str, (len)); sprintf(new_str, "%s%c%s", prefix, join, suffix); new_str[len-1] = 0; return new_str; } char * generate_hash_key(const char *crm_msg_reference, const char *sys) { char *hash_key = crm_concat(sys?sys:"none", crm_msg_reference, '_'); crm_debug_3("created hash key: (%s)", hash_key); return hash_key; } char * generate_hash_value(const char *src_node, const char *src_subsys) { char *hash_value = NULL; if (src_node == NULL || src_subsys == NULL) { return NULL; } if (strcasecmp(CRM_SYSTEM_DC, src_subsys) == 0) { hash_value = crm_strdup(src_subsys); if (!hash_value) { crm_err("memory allocation failed in " "generate_hash_value()"); } return hash_value; } hash_value = crm_concat(src_node, src_subsys, '_'); crm_info("created hash value: (%s)", hash_value); return hash_value; } char * crm_itoa(int an_int) { int len = 32; char *buffer = NULL; crm_malloc0(buffer, (len+1)); if(buffer != NULL) { snprintf(buffer, len, "%d", an_int); } return buffer; } extern int LogToLoggingDaemon(int priority, const char * buf, int bstrlen, gboolean use_pri_str); gboolean crm_log_init( const char *entity, int level, gboolean coredir, gboolean to_stderr, int argc, char **argv) { /* const char *test = "Testing log daemon connection"; */ /* Redirect messages from glib functions to our handler */ /* cl_malloc_forced_for_glib(); */ g_log_set_handler(NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG | G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL, cl_glib_msg_handler, NULL); /* and for good measure... - this enum is a bit field (!) */ g_log_set_always_fatal((GLogLevelFlags)0); /*value out of range*/ crm_system_name = entity; cl_log_set_entity(entity); cl_log_set_facility(HA_LOG_FACILITY); if(coredir) { cl_set_corerootdir(HA_COREDIR); cl_cdtocoredir(); } set_crm_log_level(level); crm_set_env_options(); cl_log_args(argc, argv); cl_log_enable_stderr(to_stderr); CL_SIGNAL(DEBUG_INC, alter_debug); CL_SIGNAL(DEBUG_DEC, alter_debug); return TRUE; } /* returns the old value */ unsigned int set_crm_log_level(unsigned int level) { unsigned int old = crm_log_level; while(crm_log_level < 100 && crm_log_level < level) { alter_debug(DEBUG_INC); } while(crm_log_level > 0 && crm_log_level > level) { alter_debug(DEBUG_DEC); } return old; } unsigned int get_crm_log_level(void) { return crm_log_level; } void -crm_log_message_adv(int level, const char *prefix, const HA_Message *msg) -{ +crm_log_message_adv(int level, const char *prefix, const HA_Message *msg) { if((int)crm_log_level >= level) { do_crm_log(level, "#========= %s message start ==========#", prefix?prefix:""); if(level > LOG_DEBUG) { cl_log_message(LOG_DEBUG, msg); } else { cl_log_message(level, msg); } } } static int crm_version_helper(const char *text, char **end_text) { int atoi_result = -1; CRM_ASSERT(end_text != NULL); errno = 0; if(text != NULL && text[0] != 0) { atoi_result = (int)strtol(text, end_text, 10); if(errno == EINVAL) { crm_err("Conversion of '%s' %c failed", text, text[0]); atoi_result = -1; } } return atoi_result; } int compare_version(const char *version1, const char *version2) { int rc = 0; int lpc = 0; char *ver1_copy = NULL, *ver2_copy = NULL; char *rest1 = NULL, *rest2 = NULL; if(version1 == NULL && version2 == NULL) { return 0; } else if(version1 == NULL) { return -1; } else if(version2 == NULL) { return 1; } ver1_copy = crm_strdup(version1); ver2_copy = crm_strdup(version2); rest1 = ver1_copy; rest2 = ver2_copy; while(1) { int digit1 = 0; int digit2 = 0; lpc++; if(rest1 == rest2) { break; } if(rest1 != NULL) { digit1 = crm_version_helper(rest1, &rest1); } if(rest2 != NULL) { digit2 = crm_version_helper(rest2, &rest2); } if(digit1 < digit2){ rc = -1; crm_debug_5("%d < %d", digit1, digit2); break; } else if (digit1 > digit2){ rc = 1; crm_debug_5("%d > %d", digit1, digit2); break; } if(rest1 != NULL && rest1[0] == '.') { rest1++; } if(rest1 != NULL && rest1[0] == 0) { rest1 = NULL; } if(rest2 != NULL && rest2[0] == '.') { rest2++; } if(rest2 != NULL && rest2[0] == 0) { rest2 = NULL; } } crm_free(ver1_copy); crm_free(ver2_copy); if(rc == 0) { crm_debug_3("%s == %s (%d)", version1, version2, lpc); } else if(rc < 0) { crm_debug_3("%s < %s (%d)", version1, version2, lpc); } else if(rc > 0) { crm_debug_3("%s > %s (%d)", version1, version2, lpc); } return rc; } gboolean do_stderr = FALSE; void alter_debug(int nsig) { CL_SIGNAL(DEBUG_INC, alter_debug); CL_SIGNAL(DEBUG_DEC, alter_debug); switch(nsig) { case DEBUG_INC: if (crm_log_level < 100) { crm_log_level++; } break; case DEBUG_DEC: if (crm_log_level > 0) { crm_log_level--; } break; default: fprintf(stderr, "Unknown signal %d\n", nsig); cl_log(LOG_ERR, "Unknown signal %d", nsig); break; } } void g_hash_destroy_str(gpointer data) { crm_free(data); } #include #include #include long crm_int_helper(const char *text, char **end_text) { long atoi_result = -1; char *local_end_text = NULL; errno = 0; if(text != NULL) { if(end_text != NULL) { atoi_result = strtoul(text, end_text, 10); } else { atoi_result = strtoul(text, &local_end_text, 10); } /* CRM_CHECK(errno != EINVAL); */ if(errno == EINVAL) { crm_err("Conversion of %s failed", text); atoi_result = -1; } else { if(errno == ERANGE) { crm_err("Conversion of %s was clipped: %ld", text, atoi_result); } if(end_text == NULL && local_end_text[0] != '\0') { crm_err("Characters left over after parsing " "\"%s\": \"%s\"", text, local_end_text); } } } return atoi_result; } int crm_parse_int(const char *text, const char *default_text) { int atoi_result = -1; if(text != NULL) { atoi_result = crm_int_helper(text, NULL); if(errno == 0) { return atoi_result; } } if(default_text != NULL) { atoi_result = crm_int_helper(default_text, NULL); if(errno == 0) { return atoi_result; } } else { crm_err("No default conversion value supplied"); } return -1; } gboolean crm_str_eq(const char *a, const char *b, gboolean use_case) { if(a == NULL || b == NULL) { /* shouldn't be comparing NULLs */ CRM_CHECK(a != b, return TRUE); return FALSE; } else if(use_case && a[0] != b[0]) { return FALSE; } else if(a == b) { return TRUE; } else if(strcasecmp(a, b) == 0) { return TRUE; } return FALSE; } gboolean safe_str_neq(const char *a, const char *b) { if(a == b) { return FALSE; } else if(a==NULL || b==NULL) { return TRUE; } else if(strcasecmp(a, b) == 0) { return FALSE; } return TRUE; } char * crm_strdup_fn(const char *src, const char *file, const char *fn, int line) { char *dup = NULL; CRM_CHECK(src != NULL, return NULL); crm_malloc0(dup, strlen(src) + 1); return strcpy(dup, src); } #define ENV_PREFIX "HA_" void crm_set_env_options(void) { cl_inherit_logging_environment(500); cl_log_set_logd_channel_source(NULL, NULL); if(debug_level > 0 && (debug_level+LOG_INFO) > (int)crm_log_level) { set_crm_log_level(LOG_INFO + debug_level); } } gboolean crm_is_true(const char * s) { gboolean ret = FALSE; if(s != NULL) { cl_str_to_boolean(s, &ret); } return ret; } int crm_str_to_boolean(const char * s, int * ret) { if(s == NULL) { return -1; } else if (strcasecmp(s, "true") == 0 || strcasecmp(s, "on") == 0 || strcasecmp(s, "yes") == 0 || strcasecmp(s, "y") == 0 || strcasecmp(s, "1") == 0){ *ret = TRUE; return 1; } else if (strcasecmp(s, "false") == 0 || strcasecmp(s, "off") == 0 || strcasecmp(s, "no") == 0 || strcasecmp(s, "n") == 0 || strcasecmp(s, "0") == 0){ *ret = FALSE; return 1; } return -1; } #ifndef NUMCHARS # define NUMCHARS "0123456789." #endif #ifndef WHITESPACE # define WHITESPACE " \t\n\r\f" #endif long crm_get_msec(const char * input) { const char * cp = input; const char * units; long multiplier = 1000; long divisor = 1; long ret = -1; double dret; if(input == NULL) { return 0; } cp += strspn(cp, WHITESPACE); units = cp + strspn(cp, NUMCHARS); units += strspn(units, WHITESPACE); if (strchr(NUMCHARS, *cp) == NULL) { return ret; } if (strncasecmp(units, "ms", 2) == 0 || strncasecmp(units, "msec", 4) == 0) { multiplier = 1; divisor = 1; }else if (strncasecmp(units, "us", 2) == 0 || strncasecmp(units, "usec", 4) == 0) { multiplier = 1; divisor = 1000; }else if (strncasecmp(units, "s", 1) == 0 || strncasecmp(units, "sec", 3) == 0) { multiplier = 1000; divisor = 1; }else if (strncasecmp(units, "m", 1) == 0 || strncasecmp(units, "min", 3) == 0) { multiplier = 60*1000; divisor = 1; }else if (strncasecmp(units, "h", 1) == 0 || strncasecmp(units, "hr", 2) == 0) { multiplier = 60*60*1000; divisor = 1; }else if (*units != EOS && *units != '\n' && *units != '\r') { return ret; } dret = atof(cp); dret *= (double)multiplier; dret /= (double)divisor; dret += 0.5; ret = (long)dret; return(ret); } const char * op_status2text(op_status_t status) { switch(status) { case LRM_OP_PENDING: return "pending"; break; case LRM_OP_DONE: return "complete"; break; case LRM_OP_ERROR: return "Error"; break; case LRM_OP_TIMEOUT: return "Timed Out"; break; case LRM_OP_NOTSUPPORTED: return "NOT SUPPORTED"; break; case LRM_OP_CANCELLED: return "Cancelled"; break; } CRM_CHECK(status >= LRM_OP_PENDING && status <= LRM_OP_CANCELLED, crm_err("Unknown status: %d", status)); return "UNKNOWN!"; } char * generate_op_key(const char *rsc_id, const char *op_type, int interval) { int len = 35; char *op_id = NULL; CRM_CHECK(rsc_id != NULL, return NULL); CRM_CHECK(op_type != NULL, return NULL); len += strlen(op_type); len += strlen(rsc_id); crm_malloc0(op_id, len); CRM_CHECK(op_id != NULL, return NULL); sprintf(op_id, "%s_%s_%d", rsc_id, op_type, interval); return op_id; } gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, int *interval) { char *mutable_key = NULL; char *mutable_key_ptr = NULL; int len = 0, offset = 0, ch = 0; CRM_CHECK(key != NULL, return FALSE); *interval = 0; len = strlen(key); offset = len-1; crm_debug_3("Source: %s", key); while(offset > 0 && isdigit(key[offset])) { int digits = len-offset; ch = key[offset] - '0'; CRM_CHECK(ch < 10, return FALSE); CRM_CHECK(ch >= 0, return FALSE); while(digits > 1) { digits--; ch = ch * 10; } *interval += ch; offset--; } crm_debug_3(" Interval: %d", *interval); CRM_CHECK(key[offset] == '_', return FALSE); mutable_key = crm_strdup(key); mutable_key_ptr = mutable_key_ptr; mutable_key[offset] = 0; offset--; while(offset > 0 && key[offset] != '_') { offset--; } CRM_CHECK(key[offset] == '_', crm_free(mutable_key); return FALSE); mutable_key_ptr = mutable_key+offset+1; crm_debug_3(" Action: %s", mutable_key_ptr); *op_type = crm_strdup(mutable_key_ptr); mutable_key[offset] = 0; offset--; CRM_CHECK(mutable_key != mutable_key_ptr, crm_free(mutable_key); return FALSE); crm_debug_3(" Resource: %s", mutable_key); *rsc_id = crm_strdup(mutable_key); crm_free(mutable_key); return TRUE; } char * generate_notify_key(const char *rsc_id, const char *notify_type, const char *op_type) { int len = 12; char *op_id = NULL; CRM_CHECK(rsc_id != NULL, return NULL); CRM_CHECK(op_type != NULL, return NULL); CRM_CHECK(notify_type != NULL, return NULL); len += strlen(op_type); len += strlen(rsc_id); len += strlen(notify_type); crm_malloc0(op_id, len); if(op_id != NULL) { sprintf(op_id, "%s_%s_notify_%s_0", rsc_id, notify_type, op_type); } return op_id; } char * generate_transition_magic_v202(const char *transition_key, int op_status) { int len = 80; char *fail_state = NULL; CRM_CHECK(transition_key != NULL, return NULL); len += strlen(transition_key); crm_malloc0(fail_state, len); if(fail_state != NULL) { snprintf(fail_state, len, "%d:%s", op_status,transition_key); } return fail_state; } char * generate_transition_magic(const char *transition_key, int op_status, int op_rc) { int len = 80; char *fail_state = NULL; CRM_CHECK(transition_key != NULL, return NULL); len += strlen(transition_key); crm_malloc0(fail_state, len); if(fail_state != NULL) { snprintf(fail_state, len, "%d:%d;%s", op_status, op_rc, transition_key); } return fail_state; } gboolean decode_transition_magic( const char *magic, char **uuid, int *transition_id, int *action_id, int *op_status, int *op_rc) { char *rc = NULL; char *key = NULL; char *magic2 = NULL; char *status = NULL; gboolean result = TRUE; if(decodeNVpair(magic, ':', &status, &magic2) == FALSE) { crm_err("Couldn't find ':' in: %s", magic); result = FALSE; goto bail; } if(decodeNVpair(magic2, ';', &rc, &key) == FALSE) { crm_err("Couldn't find ';' in: %s", magic2); result = FALSE; goto bail; } CRM_CHECK(decode_transition_key(key, uuid, transition_id, action_id), result = FALSE; goto bail; ); *op_rc = crm_parse_int(rc, NULL); *op_status = crm_parse_int(status, NULL); bail: crm_free(rc); crm_free(key); crm_free(magic2); crm_free(status); return result; } char * generate_transition_key(int transition_id, int action_id, const char *node) { int len = 40; char *fail_state = NULL; CRM_CHECK(node != NULL, return NULL); len += strlen(node); crm_malloc0(fail_state, len); if(fail_state != NULL) { snprintf(fail_state, len, "%d:%d:%s", action_id, transition_id, node); } return fail_state; } gboolean decode_transition_key( const char *key, char **uuid, int *transition_id, int *action_id) { char *tmp = NULL; char *action = NULL; char *transition = NULL; *uuid = NULL; *action_id = -1; *transition_id = -1; if(decodeNVpair(key, ':', &action, &tmp) == FALSE) { crm_err("Couldn't find ':' in: %s", key); return FALSE; } *action_id = crm_parse_int(action, NULL); crm_free(action); if(decodeNVpair(tmp, ':', &transition, uuid) == FALSE) { /* this would be an error but some versions dont * have the action */ *transition_id = *action_id; *action_id = -1; *uuid = tmp; } else { *transition_id = crm_parse_int(transition, NULL); crm_free(transition); crm_free(tmp); } return TRUE; } void -filter_action_parameters(crm_data_t *param_set, const char *version) +filter_action_parameters(xmlNode *param_set, const char *version) { char *timeout = NULL; char *interval = NULL; #if CRM_DEPRECATED_SINCE_2_0_5 const char *filter_205[] = { XML_ATTR_TE_TARGET_RC, XML_ATTR_LRM_PROBE, XML_RSC_ATTR_START, XML_RSC_ATTR_NOTIFY, XML_RSC_ATTR_UNIQUE, XML_RSC_ATTR_MANAGED, XML_RSC_ATTR_PRIORITY, XML_RSC_ATTR_MULTIPLE, XML_RSC_ATTR_STICKINESS, XML_RSC_ATTR_FAIL_STICKINESS, XML_RSC_ATTR_TARGET_ROLE, /* ignore clone fields */ XML_RSC_ATTR_INCARNATION, XML_RSC_ATTR_INCARNATION_MAX, XML_RSC_ATTR_INCARNATION_NODEMAX, XML_RSC_ATTR_MASTER_MAX, XML_RSC_ATTR_MASTER_NODEMAX, /* old field names */ "role", "crm_role", "te-target-rc", /* ignore notify fields */ "notify_stop_resource", "notify_stop_uname", "notify_start_resource", "notify_start_uname", "notify_active_resource", "notify_active_uname", "notify_inactive_resource", "notify_inactive_uname", "notify_promote_resource", "notify_promote_uname", "notify_demote_resource", "notify_demote_uname", "notify_master_resource", "notify_master_uname", "notify_slave_resource", "notify_slave_uname" }; #endif const char *attr_filter[] = { XML_ATTR_ID, XML_ATTR_CRM_VERSION, XML_LRM_ATTR_OP_DIGEST, }; gboolean do_delete = FALSE; int lpc = 0; static int meta_len = 0; if(meta_len == 0) { meta_len = strlen(CRM_META); } if(param_set == NULL) { return; } #if CRM_DEPRECATED_SINCE_2_0_5 if(version == NULL || compare_version("1.0.5", version)) { for(lpc = 0; lpc < DIMOF(filter_205); lpc++) { xml_remove_prop(param_set, filter_205[lpc]); } } #endif for(lpc = 0; lpc < DIMOF(attr_filter); lpc++) { xml_remove_prop(param_set, attr_filter[lpc]); } timeout = crm_element_value_copy(param_set, CRM_META"_timeout"); interval = crm_element_value_copy(param_set, CRM_META"_interval"); xml_prop_iter(param_set, prop_name, prop_value, do_delete = FALSE; if(strncasecmp(prop_name, CRM_META, meta_len) == 0) { do_delete = TRUE; } if(do_delete) { - /* remove it */ xml_remove_prop(param_set, prop_name); - /* unwind the counetr */ - __counter--; } ); if(crm_get_msec(interval) && compare_version(version, "1.0.8")) { /* Re-instate the operation's timeout value */ if(timeout != NULL) { crm_xml_add(param_set, CRM_META"_timeout", timeout); } } crm_free(interval); crm_free(timeout); } void -filter_reload_parameters(crm_data_t *param_set, const char *restart_string) +filter_reload_parameters(xmlNode *param_set, const char *restart_string) { int len = 0; char *name = NULL; char *match = NULL; if(param_set == NULL) { return; } xml_prop_iter(param_set, prop_name, prop_value, name = NULL; len = strlen(prop_name) + 3; crm_malloc0(name, len); sprintf(name, " %s ", prop_name); name[len-1] = 0; match = strstr(restart_string, name); if(match == NULL) { - /* remove it */ crm_debug_3("%s not found in %s", prop_name, restart_string); xml_remove_prop(param_set, prop_name); - /* unwind the counetr */ - __counter--; } crm_free(name); ); } void crm_abort(const char *file, const char *function, int line, const char *assert_condition, gboolean do_core, gboolean do_fork) { int rc = 0; int pid = 0; int status = 0; if(do_core == FALSE) { do_crm_log(LOG_ERR, "%s: Triggered assert at %s:%d : %s", function, file, line, assert_condition); return; } else if(do_fork) { do_crm_log(LOG_ERR, "%s: Triggered non-fatal assert at %s:%d : %s", function, file, line, assert_condition); pid=fork(); } else { do_crm_log(LOG_ERR, "%s: Triggered fatal assert at %s:%d : %s", function, file, line, assert_condition); } switch(pid) { case -1: crm_err("Cannot fork!"); return; default: /* Parent */ do_crm_log(LOG_ERR, "%s: Forked child %d to record non-fatal assert at %s:%d : %s", function, pid, file, line, assert_condition); do { rc = waitpid(pid, &status, 0); if(rc < 0 && errno != EINTR) { cl_perror("%s: Cannot wait on forked child %d", function, pid); } } while(rc < 0 && errno == EINTR); return; case 0: /* Child */ abort(); break; } } char * generate_series_filename( const char *directory, const char *series, int sequence, gboolean bzip) { int len = 40; char *filename = NULL; const char *ext = "raw"; CRM_CHECK(directory != NULL, return NULL); CRM_CHECK(series != NULL, return NULL); len += strlen(directory); len += strlen(series); crm_malloc0(filename, len); CRM_CHECK(filename != NULL, return NULL); if(bzip) { ext = "bz2"; } sprintf(filename, "%s/%s-%d.%s", directory, series, sequence, ext); return filename; } int get_last_sequence(const char *directory, const char *series) { FILE *file_strm = NULL; int start = 0, length = 0, read_len = 0; char *series_file = NULL; char *buffer = NULL; int seq = 0; int len = 36; CRM_CHECK(directory != NULL, return 0); CRM_CHECK(series != NULL, return 0); len += strlen(directory); len += strlen(series); crm_malloc0(series_file, len); CRM_CHECK(series_file != NULL, return 0); sprintf(series_file, "%s/%s.last", directory, series); file_strm = fopen(series_file, "r"); if(file_strm == NULL) { crm_debug("Series file %s does not exist", series_file); crm_free(series_file); return 0; } /* see how big the file is */ start = ftell(file_strm); fseek(file_strm, 0L, SEEK_END); length = ftell(file_strm); fseek(file_strm, 0L, start); CRM_ASSERT(start == ftell(file_strm)); crm_debug_3("Reading %d bytes from file", length); crm_malloc0(buffer, (length+1)); read_len = fread(buffer, 1, length, file_strm); if(read_len != length) { crm_err("Calculated and read bytes differ: %d vs. %d", length, read_len); crm_free(buffer); buffer = NULL; } else if(length <= 0) { crm_info("%s was not valid", series_file); crm_free(buffer); buffer = NULL; } crm_free(series_file); seq = crm_parse_int(buffer, "0"); crm_free(buffer); fclose(file_strm); return seq; } void write_last_sequence( const char *directory, const char *series, int sequence, int max) { int rc = 0; int len = 36; char *buffer = NULL; FILE *file_strm = NULL; char *series_file = NULL; CRM_CHECK(directory != NULL, return); CRM_CHECK(series != NULL, return); if(max == 0) { return; } while(max > 0 && sequence > max) { sequence -= max; } buffer = crm_itoa(sequence); len += strlen(directory); len += strlen(series); crm_malloc0(series_file, len); sprintf(series_file, "%s/%s.last", directory, series); file_strm = fopen(series_file, "w"); if(file_strm == NULL) { crm_err("Cannout open series file %s for writing", series_file); goto bail; } rc = fprintf(file_strm, "%s", buffer); if(rc < 0) { cl_perror("Cannot write to series file %s", series_file); } bail: if(file_strm != NULL) { fflush(file_strm); fclose(file_strm); } crm_free(series_file); crm_free(buffer); } void crm_make_daemon(const char *name, gboolean daemonize, const char *pidfile) { long pid; const char *devnull = "/dev/null"; if(daemonize == FALSE) { return; } pid = fork(); if (pid < 0) { fprintf(stderr, "%s: could not start daemon\n", name); cl_perror("fork"); exit(LSB_EXIT_GENERIC); } else if (pid > 0) { exit(LSB_EXIT_OK); } if (cl_lock_pidfile(pidfile) < 0 ) { pid = cl_read_pidfile_no_checking(pidfile); crm_warn("%s: already running [pid %ld] (%s).\n", name, pid, pidfile); exit(LSB_EXIT_OK); } umask(022); close(STDIN_FILENO); (void)open(devnull, O_RDONLY); /* Stdin: fd 0 */ close(STDOUT_FILENO); (void)open(devnull, O_WRONLY); /* Stdout: fd 1 */ close(STDERR_FILENO); (void)open(devnull, O_WRONLY); /* Stderr: fd 2 */ } gboolean crm_is_writable(const char *dir, const char *file, const char *user, const char *group, gboolean need_both) { int s_res = -1; struct stat buf; char *full_file = NULL; const char *target = NULL; gboolean pass = TRUE; gboolean readwritable = FALSE; CRM_ASSERT(dir != NULL); if(file != NULL) { full_file = crm_concat(dir, file, '/'); target = full_file; s_res = stat(full_file, &buf); if( s_res == 0 && S_ISREG(buf.st_mode) == FALSE ) { crm_err("%s must be a regular file", target); pass = FALSE; goto out; } } if (s_res != 0) { target = dir; s_res = stat(dir, &buf); if(s_res != 0) { crm_err("%s must exist and be a directory", dir); pass = FALSE; goto out; } else if( S_ISDIR(buf.st_mode) == FALSE ) { crm_err("%s must be a directory", dir); pass = FALSE; } } if(user) { struct passwd *sys_user = NULL; sys_user = getpwnam(user); readwritable = (sys_user != NULL && buf.st_uid == sys_user->pw_uid && (buf.st_mode & (S_IRUSR|S_IWUSR))); if(readwritable == FALSE) { crm_err("%s must be owned and r/w by user %s", target, user); if(need_both) { pass = FALSE; } } } if(group) { struct group *sys_grp = getgrnam(group); readwritable = ( sys_grp != NULL && buf.st_gid == sys_grp->gr_gid && (buf.st_mode & (S_IRGRP|S_IWGRP))); if(readwritable == FALSE) { if(need_both || user == NULL) { pass = FALSE; crm_err("%s must be owned and r/w by group %s", target, group); } else { crm_warn("%s should be owned and r/w by group %s", target, group); } } } out: crm_free(full_file); return pass; } static unsigned long long crm_bit_filter = 0; /* 0x00000002ULL; */ static unsigned int bit_log_level = LOG_DEBUG_5; long long crm_clear_bit(const char *function, long long word, long long bit) { unsigned int level = bit_log_level; if(bit & crm_bit_filter) { level = LOG_ERR; } do_crm_log(level, "Bit 0x%.16llx cleared by %s", bit, function); word &= ~bit; return word; } long long crm_set_bit(const char *function, long long word, long long bit) { unsigned int level = bit_log_level; if(bit & crm_bit_filter) { level = LOG_ERR; } do_crm_log(level, "Bit 0x%.16llx set by %s", bit, function); word |= bit; return word; } gboolean is_not_set(long long word, long long bit) { crm_debug_5("Checking bit\t%.16llx in %.16llx", bit, word); return ((word & bit) == 0); } gboolean is_set(long long word, long long bit) { crm_debug_5("Checking bit\t%.16llx in %.16llx", bit, word); return ((word & bit) == bit); } gboolean is_set_any(long long word, long long bit) { crm_debug_5("Checking bit\t%.16llx in %.16llx", bit, word); return ((word & bit) != 0); } gboolean is_openais_cluster(void) { static const char *cluster_type = NULL; if(cluster_type == NULL) { cluster_type = getenv("HA_cluster_type"); } if(safe_str_eq("openais", cluster_type)) { #if SUPPORT_AIS return TRUE; #else CRM_ASSERT(safe_str_eq("openais", cluster_type) == FALSE); #endif } return FALSE; } gboolean is_heartbeat_cluster(void) { #if SUPPORT_HEARTBEAT return !is_openais_cluster(); #else CRM_ASSERT(is_openais_cluster()); return FALSE; #endif } diff --git a/lib/crm/common/xml.c b/lib/crm/common/xml.c index da5aef21ce..0922018633 100644 --- a/lib/crm/common/xml.c +++ b/lib/crm/common/xml.c @@ -1,2709 +1,2809 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_BZLIB_H # include #endif #define XML_BUFFER_SIZE 4096 static const char *filter[] = { XML_ATTR_ORIGIN, XML_DIFF_MARKER, XML_CIB_ATTR_WRITTEN, }; +static void add_ha_nocopy(HA_Message *parent, HA_Message *child, const char *field) +{ + int next = parent->nfields; + if (parent->nfields >= parent->nalloc && ha_msg_expand(parent) != HA_OK ) { + crm_err("Parent expansion failed"); + return; + } + + parent->names[next] = crm_strdup(field); + parent->nlens[next] = strlen(field); + parent->values[next] = child; + parent->vlens[next] = sizeof(HA_Message); + parent->types[next] = FT_UNCOMPRESS; + parent->nfields++; +} + int is_comment_start(const char *input, size_t offset, size_t max); int is_comment_end(const char *input, size_t offset, size_t max); gboolean drop_comments(const char *input, size_t *offset, size_t max); 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 depth, xmlNode *data, gboolean formatted); int dump_data_element( - int depth, char **buffer, const crm_data_t *data, gboolean formatted); + int depth, char **buffer, xmlNode *data, gboolean formatted); -crm_data_t *parse_xml(const char *input, size_t *offset); +xmlNode *parse_xml(const char *input, size_t *offset); int get_tag_name(const char *input, size_t offset, size_t max); int get_attr_name(const char *input, size_t offset, size_t max); int get_attr_value(const char *input, size_t offset, size_t max); -gboolean can_prune_leaf(crm_data_t *xml_node); +gboolean can_prune_leaf(xmlNode *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); + xmlNode *xml_node, xmlNode *parent); +int in_upper_context(int depth, int context, xmlNode *xml_node); -crm_data_t * -find_xml_node(crm_data_t *root, const char * search_path, gboolean must_find) +xmlNode * +find_xml_node(xmlNode *root, const char * search_path, gboolean must_find) { const char *name = "NULL"; if(must_find || root != NULL) { crm_validate_data(root); } if(root != NULL) { name = crm_element_name(root); } if(search_path == NULL) { crm_warn("Will never find "); return NULL; } xml_child_iter_filter( root, a_child, search_path, /* crm_debug_5("returning node (%s).", crm_element_name(a_child)); */ crm_log_xml(LOG_DEBUG_5, "found:", a_child); crm_log_xml(LOG_DEBUG_6, "in:", root); crm_validate_data(a_child); return a_child; ); if(must_find) { crm_warn("Could not find %s in %s.", search_path, name); } else if(root != NULL) { crm_debug_3("Could not find %s in %s.", search_path, name); } else { crm_debug_3("Could not find %s in .", search_path); } return NULL; } -crm_data_t* -find_xml_node_nested(crm_data_t *root, const char **search_path, int len) +xmlNode* +find_xml_node_nested(xmlNode *root, const char **search_path, int len) { int j; gboolean is_found = TRUE; - crm_data_t *match = NULL; - crm_data_t *lastMatch = root; + xmlNode *match = NULL; + xmlNode *lastMatch = root; crm_validate_data(root); if(search_path == NULL || search_path[0] == 0) { 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).", crm_element_name(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.", crm_element_name(lastMatch), crm_element_name(root)); return NULL; } const char * -get_xml_attr_nested(crm_data_t *parent, +get_xml_attr_nested(xmlNode *parent, const char **node_path, int length, const char *attr_name, gboolean error) { const char *attr_value = NULL; - crm_data_t *attr_parent = NULL; + xmlNode *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 || attr_name[0] == 0) { crm_err("Can not find attribute with no name in %s", crm_element_name(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 || attr_value[0] == 0) && error) { crm_err("No value present for %s at %s", attr_name, crm_element_name(attr_parent)); return NULL; } return attr_value; } -crm_data_t* -find_entity(crm_data_t *parent, const char *node_name, const char *id) +xmlNode* +find_entity(xmlNode *parent, const char *node_name, const char *id) { crm_validate_data(parent); xml_child_iter_filter( parent, a_child, node_name, if(id == NULL || crm_str_eq(id, ID(a_child), TRUE)) { crm_debug_4("returning node (%s).", crm_element_name(a_child)); return a_child; } ); crm_debug_3("node <%s id=%s> not found in %s.", node_name, id, crm_element_name(parent)); return NULL; } void -copy_in_properties(crm_data_t* target, const crm_data_t *src) +copy_in_properties(xmlNode* target, xmlNode *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, expand_plus_plus(target, local_prop_name, local_prop_value) ); crm_validate_data(target); } return; } -void fix_plus_plus_recursive(crm_data_t* target) +void fix_plus_plus_recursive(xmlNode* target) { xml_prop_iter(target, name, value, expand_plus_plus(target, name, value)); xml_child_iter(target, child, fix_plus_plus_recursive(child)); } void -expand_plus_plus(crm_data_t* target, const char *name, const char *value) +expand_plus_plus(xmlNode* target, const char *name, const char *value) { int int_value = 0; int value_len = 0; char *incr_value = NULL; const char *old_value = crm_element_value(target, name); /* if no previous value, set unexpanded */ if(old_value == NULL || strstr(value, "++") <= value) { crm_xml_add(target, name, value); return; } value_len = strlen(value); crm_malloc0(incr_value, value_len+2); sprintf(incr_value, "%s++", name); /* if the value is name followed by "++" we need * to increment the existing value */ if(safe_str_eq(value, incr_value)) { if(safe_str_eq(value, old_value)) { int_value = 0; } else { int_value = crm_parse_int(old_value, "0"); } crm_xml_add_int(target, name, int_value+1); } else { crm_xml_add(target, name, value); } crm_free(incr_value); return; } -crm_data_t* -add_node_copy(crm_data_t *parent, const crm_data_t *src_node) +xmlNode* +add_node_copy(xmlNode *parent, xmlNode *src_node) { const char *name = NULL; - crm_data_t *child = NULL; + xmlNode *child = NULL; CRM_CHECK(src_node != NULL, return NULL); crm_validate_data(src_node); name = crm_element_name(src_node); CRM_CHECK(name != NULL, return NULL); - - child = create_xml_node(parent, name); - copy_in_properties(child, src_node); - xml_child_iter(src_node, src_child, - add_node_copy(child, src_child); - ); - + child = copy_xml(src_node); + xmlAddChild(parent, child); return child; } int -add_node_nocopy(crm_data_t *parent, const char *name, crm_data_t *child) +add_node_nocopy(xmlNode *parent, const char *name, xmlNode *child) { int next = 0; crm_validate_data(parent); crm_validate_data(child); if(name == NULL) { name = crm_element_name(child); } if(name == NULL || name[0] == 0) { crm_err("Cannot add object with no name"); return HA_FAIL; } - if (parent->nfields >= parent->nalloc - && ha_msg_expand(parent) != HA_OK ){ - crm_err("Parent expansion failed"); - return HA_FAIL; - } - - next = parent->nfields; - parent->names[next] = crm_strdup(name); - parent->nlens[next] = strlen(name); - parent->values[next] = child; - parent->vlens[next] = sizeof(struct ha_msg); - parent->types[next] = FT_UNCOMPRESS; - parent->nfields++; - + next = 0; + xmlAddChild(parent, child); return HA_OK; } const char * -crm_xml_add(crm_data_t* node, const char *name, const char *value) +crm_xml_add(xmlNode* 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); + const char *parent_name = NULL; + + if(node != NULL) { + parent_name = crm_element_name(node); + } + + CRM_CHECK(name != NULL && name[0] != 0, return NULL); + CRM_CHECK(node != NULL, return NULL); + CRM_CHECK(parent_name != NULL, return NULL); + /* CRM_CHECK(strcasecmp(name, F_XML_TAGNAME) != 0, return NULL); */ - if (name == NULL || name[0] == 0) { - - } else if(node == NULL) { - - } else if(parent_name == NULL && strcasecmp(name, F_XML_TAGNAME) != 0) { - - } else if (value == NULL || value[0] == 0) { - xml_remove_prop(node, name); - return NULL; - - } else { - const char *new_value = NULL; - crm_validate_data(node); - ha_msg_mod(node, name, value); - new_value = crm_element_value(node, name); - return new_value; - } - + if (value == NULL || value[0] == 0) { + xml_remove_prop(node, name); return NULL; + + } else { + xmlChar *xml_name = xmlCharStrdup(name); + xmlChar *xml_value = xmlCharStrdup(value); + xmlSetProp(node, xml_name, xml_value); + } + + return crm_element_value(node, name); } const char * -crm_xml_add_int(crm_data_t* node, const char *name, int value) +crm_xml_add_int(xmlNode* 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 || name[0] == 0) { - - } else if(node == NULL) { - - } else if(parent_name == NULL && strcasecmp(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; + const char *parent_name = NULL; + + if(node != NULL) { + parent_name = crm_element_name(node); + } + + CRM_CHECK(name != NULL && name[0] != 0, return NULL); + CRM_CHECK(node != NULL, return NULL); + CRM_CHECK(parent_name != NULL, return NULL); + CRM_CHECK(strcasecmp(name, F_XML_TAGNAME) != 0, return NULL); + + { + xmlChar *new_name = xmlCharStrdup(name); + xmlChar *number = (xmlChar*)crm_itoa(value); + xmlSetProp(node, new_name, number); + } + return crm_element_value(node, name); } -crm_data_t* -create_xml_node(crm_data_t *parent, const char *name) +xmlNode* +create_xml_node(xmlNode *parent, const char *name) { - const char *local_name = NULL; - const char *parent_name = NULL; - crm_data_t *ret_value = NULL; - + xmlNode *ret_value = NULL; if (name == NULL || name[0] == 0) { ret_value = NULL; } else { - local_name = name; - ret_value = ha_msg_new(3); - CRM_CHECK(ret_value != NULL, return 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_CHECK(HA_OK == ha_msg_addstruct( - parent, name, ret_value), return NULL); - crm_msg_del(ret_value); - - crm_validate_data(parent); - ret_value = parent->values[parent->nfields-1]; - } + if(parent == NULL) { + ret_value = xmlNewNode(NULL, (const xmlChar*)name); + } else { + xmlChar *local_name = xmlCharStrdup(name); + ret_value = xmlNewChild(parent, NULL, local_name, NULL); + } } - - crm_debug_5("Created node [%s [%s]]", - crm_str(parent_name), crm_str(local_name)); return ret_value; } void -free_xml_from_parent(crm_data_t *parent, crm_data_t *a_node) +free_xml_from_parent(xmlNode *parent, xmlNode *a_node) { CRM_CHECK(parent != NULL, return); CRM_CHECK(a_node != NULL, return); - crm_validate_data(parent); - cl_msg_remove_value(parent, a_node); - crm_validate_data(parent); + xmlUnlinkNode(a_node); + a_node->doc = NULL; + free_xml(a_node); } -void -add_xml_tstamp(crm_data_t *a_node) +xmlNode* +copy_xml(xmlNode *src_node) { - 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); - 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); - } + return xmlCopyNode(src_node, 1); } -crm_data_t* -copy_xml(const crm_data_t *src_node) -{ - return add_node_copy(NULL, src_node); -} - -crm_data_t* +xmlNode* string2xml(const char *input) { - crm_data_t *output = parse_xml(input, NULL); + xmlNode *output = parse_xml(input, NULL); if(output != NULL) { crm_validate_data(output); } return output; } -crm_data_t * +xmlNode * stdin2xml(void) { size_t data_length = 0; size_t read_chars = 0; char *xml_buffer = NULL; - crm_data_t *xml_obj = NULL; + xmlNode *xml_obj = NULL; do { crm_realloc(xml_buffer, XML_BUFFER_SIZE + data_length + 1); read_chars = fread(xml_buffer + data_length, 1, XML_BUFFER_SIZE, stdin); data_length += read_chars; } while (read_chars > 0); if(data_length == 0) { crm_warn("No XML supplied on stdin"); return NULL; } xml_buffer[data_length] = '\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* +xmlNode* file2xml(FILE *input, gboolean compressed) { char *buffer = NULL; gboolean work_done = FALSE; - crm_data_t *new_obj = NULL; + xmlNode *new_obj = NULL; size_t length = 0, read_len = 0; if(input == NULL) { /* Use perror here as we likely just called fopen() which return NULL */ cl_perror("File open failed, cannot read contents"); return NULL; } if(compressed) { #if HAVE_BZLIB_H int rc = 0; BZFILE *bz_file = BZ2_bzReadOpen(&rc, input, 0, 0, NULL, 0); if ( rc != BZ_OK ) { BZ2_bzReadClose ( &rc, bz_file); return NULL; } rc = BZ_OK; while ( rc == BZ_OK ) { crm_realloc(buffer, XML_BUFFER_SIZE + length + 1); read_len = BZ2_bzRead ( &rc, bz_file, buffer + length, XML_BUFFER_SIZE); crm_debug_5("Read %ld bytes from file: %d", (long)read_len, rc); if ( rc == BZ_OK || rc == BZ_STREAM_END) { length += read_len; } } buffer[length] = '\0'; read_len = length; if ( rc != BZ_STREAM_END ) { crm_err("Couldnt read compressed xml from file"); crm_free(buffer); buffer = NULL; } BZ2_bzReadClose (&rc, bz_file); if(buffer == NULL) { return NULL; } work_done = TRUE; #else crm_err("Cannot read compressed files:" " bzlib was not available at compile time"); #endif } if(work_done == FALSE) { int start = 0; start = ftell(input); fseek(input, 0L, SEEK_END); length = ftell(input); fseek(input, 0L, start); CRM_ASSERT(start == ftell(input)); crm_debug_3("Reading %ld bytes from file", (long)length); crm_malloc0(buffer, (length+1)); read_len = fread(buffer, 1, length, input); } /* see how big the file is */ if(read_len != length) { crm_err("Calculated and read bytes differ: %ld vs. %ld", (long)length, (long)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, "%s", message); } do_crm_log(log_level, "Contents of the array:"); if(array == NULL || array[0] == NULL || depth == 0) { do_crm_log(log_level, "\t"); return; } for (j=0; j < depth && array[j] != NULL; j++) { if (array[j] == NULL) { break; } do_crm_log(log_level, "\t--> (%s).", array[j]); } } int -write_xml_file(crm_data_t *xml_node, const char *filename, gboolean compress) +write_xml_file(xmlNode *xml_node, const char *filename, gboolean compress) { int res = 0; time_t now; char *buffer = NULL; char *now_str = NULL; unsigned int out = 0; FILE *file_output_strm = NULL; static mode_t cib_mode = S_IRUSR|S_IWUSR; CRM_CHECK(filename != NULL, return -1); crm_debug_3("Writing XML out to %s", filename); crm_validate_data(xml_node); if (xml_node == NULL) { crm_err("Cannot write NULL to %s", filename); return -1; } file_output_strm = fopen(filename, "w"); if(file_output_strm == NULL) { cl_perror("Cannot open %s for writing", filename); return -1; } /* establish the correct permissions */ fchmod(fileno(file_output_strm), cib_mode); 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, XML_CIB_ATTR_WRITTEN, now_str); crm_validate_data(xml_node); buffer = dump_xml_formatted(xml_node); CRM_CHECK(buffer != NULL && strlen(buffer) > 0, goto bail); if(compress) { #if HAVE_BZLIB_H int rc = BZ_OK; unsigned int in = 0; BZFILE *bz_file = NULL; bz_file = BZ2_bzWriteOpen(&rc, file_output_strm, 5, 0, 30); if(rc != BZ_OK) { crm_err("bzWriteOpen failed: %d", rc); } else { BZ2_bzWrite(&rc,bz_file,buffer,strlen(buffer)); if(rc != BZ_OK) { crm_err("bzWrite() failed: %d", rc); } } if(rc == BZ_OK) { BZ2_bzWriteClose(&rc, bz_file, 0, &in, &out); if(rc != BZ_OK) { crm_err("bzWriteClose() failed: %d",rc); out = -1; } else { crm_debug_2("%s: In: %d, out: %d", filename, in, out); } } #else crm_err("Cannot write compressed files:" " bzlib was not available at compile time"); #endif } if(out <= 0) { res = fprintf(file_output_strm, "%s", buffer); if(res < 0) { cl_perror("Cannot write output to %s", filename); goto bail; } } bail: if(fflush(file_output_strm) != 0) { cl_perror("fflush for %s failed:", filename); res = -1; } if(fsync(fileno(file_output_strm)) < 0) { cl_perror("fsync for %s failed:", filename); res = -1; } fclose(file_output_strm); crm_debug_3("Saved %d bytes to the Cib as XML", res); crm_free(buffer); return res; } void print_xml_formatted(int log_level, const char *function, - const crm_data_t *msg, const char *text) + xmlNode *msg, const char *text) { if(msg == NULL) { do_crm_log(log_level, "%s: %s: NULL", function, crm_str(text)); return; } crm_validate_data(msg); log_data_element(function, text, log_level, 0, msg, TRUE); return; } -crm_data_t * -get_message_xml(HA_Message *msg, const char *field) +static HA_Message* +convert_xml_message_struct(HA_Message *parent, xmlNode *src_node, const char *field) { - int type = 0; - crm_data_t *xml_node = NULL; + xmlNode *child = NULL; + xmlNode *__crm_xml_iter = src_node->children; + xmlAttrPtr prop_iter = src_node->properties; + const char *name = NULL; + const char *value = NULL; + + HA_Message *result = ha_msg_new(3); + ha_msg_add(result, F_XML_TAGNAME, (const char *)src_node->name); + + while(prop_iter != NULL) { + name = (const char *)prop_iter->name; + value = (const char *)xmlGetProp(src_node, prop_iter->name); + prop_iter = prop_iter->next; + ha_msg_add(result, name, value); + } + + while(__crm_xml_iter != NULL) { + child = __crm_xml_iter; + __crm_xml_iter = __crm_xml_iter->next; + convert_xml_message_struct(result, child, NULL); + } + + if(parent == NULL) { + return result; + } + + if(field) { + HA_Message *holder = holder = ha_msg_new(3); + CRM_ASSERT(holder != NULL); - type = cl_get_type(msg, field); - if(type < 0) { - /* not found */ - return NULL; + ha_msg_add(holder, F_XML_TAGNAME, field); + add_ha_nocopy(holder, result, (const char*)src_node->name); + + ha_msg_addstruct_compress(parent, field, holder); + ha_msg_del(holder); + + } else { + add_ha_nocopy(parent, result, (const char*)src_node->name); + } + return result; +} + +static void +convert_xml_child(HA_Message *msg, xmlNode *xml) +{ + int orig = 0; + int rc = BZ_OK; + unsigned int len = 0; + + char *buffer = NULL; + char *compressed = NULL; + const char *name = NULL; + + name = (const char *)xml->name; + buffer = dump_xml_unformatted(xml); + orig = strlen(buffer); + if(orig < 512) { + ha_msg_add(msg, name, buffer); + goto done; + } + + len = (orig * 1.1) + 600; /* recomended size */ + + crm_malloc0(compressed, len); + rc = BZ2_bzBuffToBuffCompress(compressed, &len, buffer, orig, 3, 0, 30); + + if(rc != BZ_OK) { + crm_err("Compression failed: %d", rc); + crm_free(compressed); + convert_xml_message_struct(msg, xml, name); + return; + } + + crm_free(buffer); + buffer = compressed; + crm_debug("Compression details: %d -> %d", orig, len); + ha_msg_addbin(msg, name, buffer, len); + done: + crm_free(buffer); + + +# if 0 + { + unsigned int used = orig; + char *uncompressed = NULL; + + crm_debug("Trying to decompress %d bytes", len); + crm_malloc0(uncompressed, orig); + rc = BZ2_bzBuffToBuffDecompress( + uncompressed, &used, compressed, len, 1, 0); + CRM_CHECK(rc == BZ_OK, ;); + CRM_CHECK(used == orig, ;); + crm_debug("rc=%d, used=%d", rc, used); + if(rc != BZ_OK) { + exit(100); + } + crm_debug("Original %s, decompressed %s", buffer, uncompressed); + crm_free(uncompressed); + } +# endif +} + +HA_Message* +convert_xml_message(xmlNode *xml) +{ + HA_Message *result = NULL; + + result = ha_msg_new(3); + ha_msg_add(result, F_XML_TAGNAME, (const char *)xml->name); + + xml_prop_iter(xml, name, value, ha_msg_add(result, name, value)); + xml_child_iter(xml, child, convert_xml_child(result, child)); + + return result; +} + +static void +convert_ha_field(xmlNode *parent, HA_Message *msg, int lpc) +{ + int type = 0; + const char *name = NULL; + const char *value = NULL; + xmlNode *xml = NULL; + + int rc = BZ_OK; + size_t orig_len = 0; + unsigned int used = 0; + char *uncompressed = NULL; + char *compressed = NULL; + int size = orig_len * 10; + + CRM_CHECK(parent != NULL, return); + CRM_CHECK(msg != NULL, return); + + name = msg->names[lpc]; + type = cl_get_type(msg, name); + + switch(type) { + case FT_COMPRESS: + case FT_STRUCT: + convert_ha_message(parent, msg->values[lpc], name); + break; + case FT_UNCOMPRESS: + convert_ha_message(parent, cl_get_struct(msg, name), name); + break; + case FT_STRING: + value = cl_get_string(msg, name); + if( value == NULL || value[0] != '<' ) { + crm_xml_add(parent, name, value); + break; + } - } else if(type == FT_STRING) { - /* Future proof */ - const char *xml_text = cl_get_string(msg, field); - xml_node = string2xml(xml_text); - - } else if(type > FT_BINARY) { - HA_Message *tmp_node = NULL; - crm_validate_data(msg); - tmp_node = cl_get_struct(msg, field); - if(tmp_node != NULL) { - const char *name = cl_get_string(tmp_node, F_XML_TAGNAME); - if(name == NULL || safe_str_neq(field, name)) { - /* Deprecated */ - xml_node = copy_xml(tmp_node); - - } else { - /* Valid XML */ - xml_child_iter(tmp_node, child, return copy_xml(child)); - } + /* unpack xml string */ + xml = string2xml(value); + if(xml == NULL) { + crm_xml_add(parent, name, value); + break; } + + add_node_nocopy(parent, name, xml); + break; - } else if(type == FT_BINARY) { - /* Future proof */ - int rc = BZ_OK; - size_t orig_len = 0; - unsigned int used = 0; - char *uncompressed = NULL; - const char *const_value = cl_get_binary(msg, field, &orig_len); - char *compressed = NULL; - int size = orig_len * 10; + case FT_BINARY: + value = cl_get_binary(msg, name, &orig_len); + size = orig_len * 10; if(orig_len < 1) { - crm_err("Invalid binary field: %s", field); - return NULL; + crm_err("Invalid binary field: %s", name); + return; } crm_malloc0(compressed, orig_len); - memcpy(compressed, const_value, orig_len); + memcpy(compressed, value, orig_len); crm_debug_2("Trying to decompress %d bytes", (int)orig_len); retry: crm_realloc(uncompressed, size); memset(uncompressed, 0, size); used = size; rc = BZ2_bzBuffToBuffDecompress( uncompressed, &used, compressed, orig_len, 1, 0); if(rc == BZ_OUTBUFF_FULL) { size = size * 2; /* dont try to allocate more memory than we have */ if(size > 0) { goto retry; } } if(rc != BZ_OK) { crm_err("Decompression of %d bytes into %d failed: %d", (int)orig_len, size, rc); } else { - xml_node = string2xml(uncompressed); + xml = string2xml(uncompressed); + } + + if(xml != NULL) { + add_node_nocopy(parent, name, xml); } - crm_free(compressed); crm_free(uncompressed); - } - - return xml_node; + crm_free(compressed); + break; + } } -gboolean -add_message_xml(HA_Message *msg, const char *field, const crm_data_t *xml) +xmlNode * +convert_ha_message(xmlNode *parent, HA_Message *msg, const char *field) { - crm_validate_data(xml); - crm_validate_data(msg); + int lpc = 0; + xmlNode *child = NULL; + const char *tag = NULL; + + CRM_CHECK(msg != NULL, return parent); + + tag = cl_get_string(msg, F_XML_TAGNAME); + if(tag == NULL) { + tag = field; + } + + if(parent == NULL) { + parent = create_xml_node(NULL, tag); + child = parent; + + } else { + child = create_xml_node(parent, tag); + } - CRM_CHECK(field != NULL, return FALSE); + for (lpc = 0; lpc < msg->nfields; lpc++) { + convert_ha_field(child, msg, lpc); + } + + return parent; +} - if(is_openais_cluster()) { - crm_data_t *holder = NULL; - holder = ha_msg_new(3); - CRM_ASSERT(holder != NULL); - - crm_xml_add(holder, F_XML_TAGNAME, field); - add_node_copy(holder, xml); - - ha_msg_addstruct_compress(msg, field, holder); - free_xml(holder); +xmlNode *convert_ipc_message(IPC_Message *msg, const char *field) +{ + HA_Message *hmsg = wirefmt2msg((char *)msg->msg_body, msg->msg_len, 0); + xmlNode *xml = convert_ha_message(NULL, hmsg, __FUNCTION__); + crm_msg_del(hmsg); + return xml; +} - } else { - ha_msg_addstruct_compress(msg, field, xml); - } - - return TRUE; +xmlNode * +get_message_xml(xmlNode *msg, const char *field) +{ + xmlNode *tmp = first_named_child(msg, field); + /* FIXME: stop doing this copying */ + tmp = first_named_child(tmp, NULL); + return copy_xml(tmp); } +gboolean +add_message_xml(xmlNode *msg, const char *field, xmlNode *xml) +{ + xmlNode *holder = create_xml_node(msg, field); + add_node_copy(holder, xml); + return TRUE; +} char * -dump_xml_formatted(const crm_data_t *an_xml_node) +dump_xml_formatted(xmlNode *an_xml_node) { char *buffer = NULL; char *mutable_ptr = NULL; if(an_xml_node == NULL) { return NULL; } - crm_malloc0(buffer, 3*get_stringlen(an_xml_node)); + crm_malloc0(buffer, 1024*1024); mutable_ptr = buffer; crm_validate_data(an_xml_node); CRM_CHECK(dump_data_element( 0, &mutable_ptr, an_xml_node, TRUE) >= 0, 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) +dump_xml_unformatted(xmlNode *an_xml_node) { char *buffer = NULL; char *mutable_ptr = NULL; - crm_malloc0(buffer, 2*get_stringlen(an_xml_node)); + + crm_malloc0(buffer, 1024*1024); mutable_ptr = buffer; crm_validate_data(an_xml_node); CRM_CHECK(dump_data_element( 0, &mutable_ptr, an_xml_node, FALSE) >= 0, 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) + xmlNode *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); const char *hidden = NULL; 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, 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); hidden = crm_element_value(data, "hidden"); xml_prop_iter( data, prop_name, prop_value, if(prop_name == NULL || safe_str_eq(F_XML_TAGNAME, prop_name)) { continue; } else if(hidden != NULL && prop_name[0] != 0 && strstr(hidden, prop_name) != NULL) { prop_value = "*****"; } 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, if(child != NULL) { has_children++; break; } ); printed = sprintf(buffer, "%s>", has_children==0?"/":""); update_buffer_head(buffer, printed); do_crm_log(log_level, "%s: %s%s", function, prefix?prefix:"", print_buffer); buffer = print_buffer; if(has_children == 0) { return 0; } xml_child_iter( data, a_child, 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, "%s: %s%s", function, 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 depth, char **buffer, xmlNode *data, gboolean formatted) { int printed = 0; int child_result = 0; int has_children = 0; const char *name = NULL; if(data == NULL) { return 0; } CRM_ASSERT(buffer != NULL && *buffer != NULL); name = crm_element_name(data); if(name == NULL && depth == 0) { name = "__fake__"; } else if(name == NULL) { return 0; } crm_debug_5("Dumping %s...", name); if(formatted) { printed = print_spaces(*buffer, depth); update_buffer_head(*buffer, printed); } printed = sprintf(*buffer, "<%s", name); update_buffer_head(*buffer, printed); has_children = xml_has_children(data); xml_prop_iter(data, prop_name, prop_value, 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); ); 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, 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", name, formatted?"\n":""); update_buffer_head(*buffer, printed); crm_debug_5("Dumped %s...", name); return has_children; } gboolean -xml_has_children(const crm_data_t *xml_root) +xml_has_children(const xmlNode *xml_root) { - if(xml_root != NULL) { - xml_child_iter( - xml_root, a_child, - return TRUE; - ); + if(xml_root != NULL && xml_root->children != NULL) { + return TRUE; } return FALSE; } void -xml_validate(const crm_data_t *xml_root) +xml_validate(const xmlNode *xml_root) { - int lpc = 0; CRM_ASSERT(xml_root != NULL); - CRM_ASSERT(cl_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(cl_is_allocated(xml_root->names[lpc]) == 1); +} - if(child == NULL) { - - } else if(xml_root->types[lpc] == FT_STRUCT - || xml_root->types[lpc] == FT_UNCOMPRESS) { - crm_validate_data(child); - - } else if(xml_root->types[lpc] == FT_STRING) { - CRM_ASSERT(cl_is_allocated(child) == 1); -/* } else { */ -/* CRM_CHECK(FALSE); */ - } - } +int +crm_element_value_int(xmlNode *data, const char *name, int *dest) +{ + const char *value = crm_element_value(data, name); + CRM_CHECK(dest != NULL, return -1); + if(value) { + *dest = crm_parse_int(value, NULL); + return 0; + } + return -1; } const char * -crm_element_value(const crm_data_t *data, const char *name) +crm_element_value(xmlNode *data, const char *name) { - const char *value = NULL; - crm_validate_data(data); - value = cl_get_string(data, name); -#if XML_PARANOIA_CHECKS - CRM_CHECK(value == NULL || cl_is_allocated(value) == 1, return NULL); -#endif - return value; + CRM_CHECK(data != NULL, return NULL); + CRM_CHECK(name != NULL, return NULL); + + return (const char*)xmlGetProp(data, (const xmlChar*)name); +} + +const char * +crm_element_value_const(const xmlNode *data, const char *name) +{ + CRM_CHECK(data != NULL, return NULL); + CRM_CHECK(name != NULL, return NULL); + + return (const char*)xmlGetProp(data, (const xmlChar*)name); } char * -crm_element_value_copy(const crm_data_t *data, const char *name) +crm_element_value_copy(xmlNode *data, const char *name) { char *value_copy = NULL; const char *value = crm_element_value(data, name); if(value != NULL) { value_copy = crm_strdup(value); } return value_copy; } const char * -crm_element_name(const crm_data_t *data) +crm_element_name(const xmlNode *data) { -#if CRM_DEV_BUILD - crm_validate_data(data); -#endif - return cl_get_string(data, F_XML_TAGNAME); + return (data ? (const char *)data->name : NULL); } void -xml_remove_prop(crm_data_t *obj, const char *name) +xml_remove_prop(xmlNode *obj, const char *name) { - if(crm_element_value(obj, name) != NULL) { - cl_msg_remove(obj, name); - } + xmlUnsetProp(obj, (const xmlChar*)name); } int get_tag_name(const char *input, size_t offset, size_t max) { char ch = 0; size_t lpc = offset; const char *error = NULL; gboolean do_special = FALSE; for(; error == NULL && lpc < max; lpc++) { ch = input[lpc]; crm_debug_5("Processing char %c [%d]", ch, (int)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 { goto out; } break; case '/': case '>': case '\t': case '\n': case ' ': if(!do_special) { goto out; } 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; out: CRM_ASSERT(lpc > offset); return lpc - offset; } int get_attr_name(const char *input, size_t offset, size_t max) { char ch = 0; size_t lpc = offset; const char *error = NULL; for(; error == NULL && lpc < max; lpc++) { ch = input[lpc]; crm_debug_5("Processing char %c[%d]", ch, (int)lpc); switch(ch) { case 0: error = "unexpected EOS"; break; case '\t': case '\n': case ' ': error = "unexpected whitespace"; break; case '=': return lpc - offset; default: if('a' <= ch && ch <= 'z') { } else if('A' <= ch && ch <= 'Z') { } else if('0' <= ch && ch <= '9') { } else if(ch == '_') { } else if(ch == '-') { } else { error = "bad character, not in [a-zA-Z0-9_-]"; } break; } } crm_err("Error parsing token near %.40s: (lpc=%d, ch='%c') %s", input+offset, (int)(lpc-offset), ch, crm_str(error)); return -1; } int get_attr_value(const char *input, size_t offset, size_t max) { char ch = 0; size_t lpc = offset; const char *error = NULL; for(; error == NULL && lpc < max; lpc++) { ch = input[lpc]; crm_debug_5("Processing char %c [%d]", ch, (int)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 - offset; default: break; } } crm_err("Error parsing token near %.40s: %s", input+offset, crm_str(error)); return -1; } int is_comment_start(const char *input, size_t offset, size_t max) { size_t remaining = max - offset; CRM_CHECK(input != NULL, return 0); CRM_CHECK(offset < max, return 0); input += offset; if(remaining > 4 && input[0] == '<' && input[1] == '!' && input[2] == '-' && input[3] == '-') { crm_debug_6("Found comment start: "); return 3; } else if(remaining > 1 && input[0] == '?' && input[1] == '>') { crm_debug_6("Found comment end: ?>"); return 2; } if(remaining > 2) { crm_debug_6("Not comment end: %c%c%c", input[0], input[1], input[2]); } else { crm_debug_6("Not comment end"); } return 0; } static gboolean drop_whitespace(const char *input, size_t *offset, size_t max) { char ch = 0; size_t lpc = *offset; gboolean more = TRUE; const char *our_input = input; if(input == NULL) { return FALSE; } while(lpc < max && more) { ch = our_input[lpc]; crm_debug_6("Processing char %c[%d]", ch, (int)lpc); if(isspace(ch)) { lpc++; } else { more = FALSE; } } crm_debug_4("Finished processing whitespace"); if(lpc > *offset) { crm_debug_5("Skipped %d whitespace chars", (int)(lpc - *offset)); } (*offset) = lpc; return FALSE; } gboolean drop_comments(const char *input, size_t *offset, size_t max) { gboolean more = TRUE; gboolean in_directive = FALSE; int in_comment = FALSE; size_t lpc = 0; int tag_len = 0; char ch = 0; if(input == NULL) { return FALSE; } CRM_ASSERT(offset != NULL); lpc = *offset; while(lpc < max && more) { ch = input[lpc]; crm_debug_6("Processing char [%d]: %c ", (int)lpc, ch); switch(ch) { case 0: if(in_comment == FALSE) { more = FALSE; } else { crm_err("unexpected EOS"); crm_warn("Parsing error at or before: %s", input+lpc); } break; case '<': tag_len = is_comment_start(input, lpc, max); if(tag_len > 0) { if(in_comment) { crm_err("Nested XML comments are not supported!"); crm_warn("Parsing error at or before: %s", input+lpc); } in_comment = TRUE; lpc+=tag_len; if(tag_len == 2 && input[lpc-1] == '!') { in_directive = TRUE; } } else if(in_comment == FALSE){ more = FALSE; } else { lpc++; } break; case '>': lpc++; if(in_directive) { in_directive = FALSE; in_comment = FALSE; } break; case '-': case '?': tag_len = is_comment_end(input, lpc, max); if(tag_len > 0) { lpc+=tag_len; in_comment = FALSE; } else { lpc++; } break; case ' ': case '\t': case '\n': case '\r': lpc++; break; default: lpc++; break; } } crm_debug_4("Finished processing comments"); crm_debug_5("Skipped %d comment chars", (int)(lpc - *offset)); *offset = lpc; return FALSE; } -crm_data_t* +xmlNode* parse_xml(const char *input, size_t *offset) { char ch = 0; int len = 0; size_t lpc = 0, max = 0; char *tag_name = NULL; char *attr_name = NULL; char *attr_value = NULL; gboolean more = TRUE; gboolean were_comments = TRUE; const char *error = NULL; const char *our_input = input; - crm_data_t *new_obj = NULL; + xmlNode *new_obj = NULL; if(input == NULL) { return NULL; } if(offset != NULL) { our_input = input + (*offset); } max = strlen(our_input); were_comments = drop_comments(our_input, &lpc, max); CRM_CHECK(our_input[lpc] == '<', return NULL); lpc++; len = get_tag_name(our_input, lpc, max); crm_debug_5("Tag length: %d", (int)len); CRM_CHECK(len > 0, return NULL); crm_malloc0(tag_name, len+1); strncpy(tag_name, our_input + lpc, len+1); tag_name[len] = EOS; crm_debug_4("Processing tag %s", tag_name); - new_obj = ha_msg_new(1); - - ha_msg_add(new_obj, F_XML_TAGNAME, tag_name); + new_obj = xmlNewNode(NULL, (xmlChar*)tag_name); lpc += len; for(; more && error == NULL && lpc < max; lpc++) { ch = our_input[lpc]; crm_debug_5("Processing char %c[%d]", ch, (int)lpc); switch(ch) { case 0: error = "unexpected EOS"; break; case '/': if(our_input[lpc+1] == '>') { more = FALSE; } break; case '<': if(our_input[lpc+1] == '!') { lpc--; /* allow the '<' to be processed */ drop_comments(our_input, &lpc, max); lpc--; /* allow the '<' to be processed */ } else if(our_input[lpc+1] != '/') { - crm_data_t *child = NULL; + xmlNode *child = NULL; crm_debug_4("Start parsing child at %d...", (int)lpc); lpc--; child = parse_xml(our_input, &lpc); if(child == NULL) { error = "error parsing child"; break; } add_node_nocopy(new_obj, NULL, child); /* ha_msg_addstruct_compress( */ /* new_obj, crm_element_name(child), child); */ crm_debug_4("Finished parsing child: %s", crm_element_name(child)); if(our_input[lpc] == '<') { lpc--; /* allow the '<' to be processed */ } } else { lpc += 2; /* ') { 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, max); 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; crm_debug_4("creating nvpair: <%s %s=\"%s\"...", tag_name, attr_name, attr_value); - ha_msg_add(new_obj, attr_name, attr_value); + crm_xml_add(new_obj, attr_name, attr_value); crm_free(attr_name); crm_free(attr_value); } break; case '>': while(lpc < max && our_input[lpc+1] != '<') { lpc++; } break; case ' ': case '\t': case '\n': case '\r': break; default: len = get_attr_name(our_input, lpc, max); 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: %.40s", our_input+lpc-3); crm_free(tag_name); free_xml(new_obj); return NULL; } if(offset == NULL) { drop_comments(our_input, &lpc, max); drop_whitespace(our_input, &lpc, max); if(lpc < max) { if(crm_log_level < LOG_ERR) { fprintf(stderr, "%s: Ignoring trailing characters in XML input. Supply -V for more details.\n", __PRETTY_FUNCTION__); } else { cl_log(LOG_ERR, "%s: Ignoring trailing characters in XML input.", __PRETTY_FUNCTION__); } cl_log(LOG_ERR, "%s: Parsed %d characters of a possible %d. Trailing text was: \'%.40s\'...", __PRETTY_FUNCTION__, (int)lpc, (int)max, our_input+lpc); } } crm_debug_4("Finished processing %s tag", tag_name); crm_free(tag_name); if(offset != NULL) { (*offset) += lpc; } return new_obj; } void -log_xml_diff(unsigned int log_level, crm_data_t *diff, const char *function) +log_xml_diff(unsigned int log_level, xmlNode *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); + xmlNode *added = find_xml_node(diff, "diff-added", FALSE); + xmlNode *removed = find_xml_node(diff, "diff-removed", FALSE); gboolean is_first = TRUE; if(crm_log_level < log_level) { /* nothing will ever be printed */ return; } xml_child_iter( removed, child, log_data_element(function, "-", log_level, 0, child, TRUE); if(is_first) { is_first = FALSE; } else { do_crm_log(log_level, " --- "); } ); is_first = TRUE; xml_child_iter( added, child, log_data_element(function, "+", log_level, 0, child, TRUE); if(is_first) { is_first = FALSE; } else { do_crm_log(log_level, " --- "); } ); } void -purge_diff_markers(crm_data_t *a_node) +purge_diff_markers(xmlNode *a_node) { CRM_CHECK(a_node != NULL, return); xml_remove_prop(a_node, XML_DIFF_MARKER); xml_child_iter(a_node, child, purge_diff_markers(child); ); } gboolean -apply_xml_diff(crm_data_t *old, crm_data_t *diff, crm_data_t **new) +apply_xml_diff(xmlNode *old, xmlNode *diff, xmlNode **new) { gboolean result = TRUE; const char *digest = crm_element_value(diff, XML_ATTR_DIGEST); - crm_data_t *added = find_xml_node(diff, "diff-added", FALSE); - crm_data_t *removed = find_xml_node(diff, "diff-removed", FALSE); + xmlNode *added = find_xml_node(diff, "diff-added", FALSE); + xmlNode *removed = find_xml_node(diff, "diff-removed", FALSE); int root_nodes_seen = 0; CRM_CHECK(new != NULL, return FALSE); crm_debug_2("Substraction Phase"); xml_child_iter(removed, child_diff, CRM_CHECK(root_nodes_seen == 0, result = FALSE); if(root_nodes_seen == 0) { *new = subtract_xml_object(old, child_diff, NULL); } 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, CRM_CHECK(root_nodes_seen == 0, result = FALSE); 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; } else if(result && digest) { char *new_digest = calculate_xml_digest(*new, FALSE, TRUE); if(safe_str_neq(new_digest, digest)) { crm_info("Digest mis-match: expected %s, calculated %s", digest, new_digest); result = FALSE; } else { crm_debug_2("Digest matched: expected %s, calculated %s", digest, new_digest); } } else if(result) { int lpc = 0; - crm_data_t *intermediate = NULL; - crm_data_t *diff_of_diff = NULL; - crm_data_t *calc_added = NULL; - crm_data_t *calc_removed = NULL; + xmlNode *intermediate = NULL; + xmlNode *diff_of_diff = NULL; + xmlNode *calc_added = NULL; + xmlNode *calc_removed = NULL; const char *value = NULL; const char *name = NULL; const char *version_attrs[] = { XML_ATTR_NUMUPDATES, XML_ATTR_GENERATION, XML_ATTR_GENERATION_ADMIN }; crm_debug_2("Verification Phase"); intermediate = diff_xml_object(old, *new, FALSE); calc_added = find_xml_node(intermediate, "diff-added", FALSE); calc_removed = find_xml_node(intermediate, "diff-removed", FALSE); /* add any version details to the diff so they match */ for(lpc = 0; lpc < DIMOF(version_attrs); lpc++) { name = version_attrs[lpc]; value = crm_element_value(added, name); crm_xml_add(calc_added, name, value); value = crm_element_value(removed, name); crm_xml_add(calc_removed, name, value); } diff_of_diff = diff_xml_object(intermediate, diff, TRUE); if(diff_of_diff != NULL) { crm_info("Diff application failed!"); crm_log_xml_debug(old, "diff:original"); crm_log_xml_debug(diff, "diff:input"); result = FALSE; } free_xml(diff_of_diff); free_xml(intermediate); diff_of_diff = NULL; intermediate = NULL; } if(result) { purge_diff_markers(*new); } return result; } -crm_data_t * -diff_xml_object(crm_data_t *old, crm_data_t *new, gboolean suppress) +xmlNode * +diff_xml_object(xmlNode *old, xmlNode *new, gboolean suppress) { - crm_data_t *diff = NULL; - crm_data_t *tmp1 = NULL; - crm_data_t *added = NULL; - crm_data_t *removed = NULL; + xmlNode *diff = NULL; + xmlNode *tmp1 = NULL; + xmlNode *added = NULL; + xmlNode *removed = NULL; tmp1 = subtract_xml_object(old, new, "removed:top"); if(tmp1 != NULL) { if(suppress && can_prune_leaf(tmp1)) { - ha_msg_del(tmp1); + free_xml(tmp1); } else { diff = create_xml_node(NULL, "diff"); removed = create_xml_node(diff, "diff-removed"); added = create_xml_node(diff, "diff-added"); add_node_nocopy(removed, NULL, tmp1); } } tmp1 = subtract_xml_object(new, old, "added:top"); if(tmp1 != NULL) { if(suppress && can_prune_leaf(tmp1)) { - ha_msg_del(tmp1); + free_xml(tmp1); return diff; } if(diff == NULL) { diff = create_xml_node(NULL, "diff"); } if(removed == NULL) { removed = create_xml_node(diff, "diff-removed"); } if(added == NULL) { added = create_xml_node(diff, "diff-added"); } add_node_nocopy(added, NULL, tmp1); } return diff; } gboolean -can_prune_leaf(crm_data_t *xml_node) +can_prune_leaf(xmlNode *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; } can_prune = FALSE; ); xml_child_iter(xml_node, child, if(can_prune_leaf(child)) { - cl_msg_remove_value(xml_node, child); - __counter--; + free_xml(child); } 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) + xmlNode *xml_node, xmlNode *parent) { - crm_data_t *us = NULL; - crm_data_t *new_parent = parent; + xmlNode *us = NULL; + xmlNode *new_parent = parent; const char *name = crm_element_name(xml_node); CRM_CHECK(xml_node != NULL && name != NULL, 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, 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) +in_upper_context(int depth, int context, xmlNode *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, 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, const char *marker) +xmlNode * +subtract_xml_object(xmlNode *left, xmlNode *right, const char *marker) { gboolean skip = FALSE; gboolean differences = FALSE; - crm_data_t *diff = NULL; - crm_data_t *child_diff = NULL; - crm_data_t *right_child = NULL; + xmlNode *diff = NULL; + xmlNode *child_diff = NULL; + xmlNode *right_child = NULL; const char *id = NULL; const char *name = NULL; const char *value = NULL; const char *right_val = NULL; int lpc = 0; static int filter_len = DIMOF(filter); crm_log_xml(LOG_DEBUG_5, "left:", left); crm_log_xml(LOG_DEBUG_5, "right:", right); if(left == NULL) { return NULL; } id = ID(left); if(right == NULL) { - crm_data_t *deleted = NULL; + xmlNode *deleted = NULL; crm_debug_5("Processing <%s id=%s> (complete copy)", crm_element_name(left), id); deleted = copy_xml(left); crm_xml_add(deleted, XML_DIFF_MARKER, marker); return deleted; } name = crm_element_name(left); /* sanity checks */ CRM_CHECK(name != NULL, return NULL); /* these checks are costly haven't caught anything for a while */ /* CRM_CHECK(safe_str_eq(crm_element_name(left), */ /* crm_element_name(right)), return NULL); */ /* CRM_CHECK(safe_str_eq(id, ID(right)), return NULL); */ diff = create_xml_node(NULL, name); /* changes to name/value pairs */ crm_debug_5("Processing <%s id=%s>", crm_str(name), id); xml_prop_iter(left, prop_name, left_value, if(crm_str_eq(prop_name, XML_ATTR_ID, TRUE)) { continue; } skip = FALSE; for(lpc = 0; skip == FALSE && lpc < filter_len; lpc++){ if(crm_str_eq(prop_name, filter[lpc], TRUE)) { 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_6("\t%s: %s", crm_str(prop_name), crm_str(left_value)); } else if(safe_str_eq(left_value, right_val)) { crm_debug_5("\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_5("\t%s: %s->%s", crm_str(prop_name), crm_str(left_value), right_val); } ); /* changes to child objects */ crm_debug_3("Processing children of <%s id=%s>",crm_str(name),id); xml_child_iter( left, left_child, right_child = find_entity( right, crm_element_name(left_child), ID(left_child)); child_diff = subtract_xml_object( left_child, right_child, marker); if(child_diff != NULL) { differences = TRUE; add_node_nocopy(diff, NULL, child_diff); } ); if(differences == FALSE) { /* check for XML_DIFF_MARKER in a child */ xml_child_iter( right, right_child, value = crm_element_value(right_child, XML_DIFF_MARKER); if(value != NULL && safe_str_eq(value, "removed:top")) { crm_debug_3("Found the root of the deletion: %s", name); crm_log_xml_debug_3(right_child, "deletion"); differences = TRUE; break; } ); } if(differences == FALSE) { free_xml(diff); crm_debug_5("\tNo changes to <%s id=%s>", crm_str(name), id); return NULL; } crm_xml_add(diff, XML_ATTR_ID, id); return diff; } int -add_xml_object(crm_data_t *parent, crm_data_t *target, const crm_data_t *update) +add_xml_object(xmlNode *parent, xmlNode *target, xmlNode *update) { const char *object_id = NULL; const char *object_name = NULL; crm_log_xml(LOG_DEBUG_5, "update:", update); crm_log_xml(LOG_DEBUG_5, "target:", target); CRM_CHECK(update != NULL, return 0); object_name = crm_element_name(update); object_id = ID(update); CRM_CHECK(object_name != NULL, 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 = create_xml_node(parent, object_name); CRM_CHECK(target != NULL, return 0); crm_debug_2("Added <%s%s%s/>", crm_str(object_name), object_id?" id=":"", object_id?object_id:""); } else { crm_debug_3("Found node <%s%s%s/> to update", crm_str(object_name), object_id?" id=":"", object_id?object_id:""); } copy_in_properties(target, update); xml_child_iter( update, a_child, crm_debug_4("Updating child <%s id=%s>", crm_element_name(a_child), ID(a_child)); add_xml_object(target, NULL, a_child); ); crm_debug_3("Finished with <%s id=%s>", crm_str(object_name), crm_str(object_id)); return 0; } gboolean -update_xml_child(crm_data_t *child, crm_data_t *to_update) +update_xml_child(xmlNode *child, xmlNode *to_update) { gboolean can_update = TRUE; CRM_CHECK(child != NULL, return FALSE); CRM_CHECK(to_update != NULL, return FALSE); if(safe_str_neq(crm_element_name(to_update), crm_element_name(child))) { can_update = FALSE; } else if(safe_str_neq(ID(to_update), ID(child))) { can_update = FALSE; } else if(can_update) { crm_log_xml_debug_2(child, "Update match found..."); add_xml_object(NULL, child, to_update); } xml_child_iter( child, child_of_child, /* only update the first one */ if(can_update) { break; } can_update = update_xml_child(child_of_child, to_update); ); return can_update; } int -find_xml_children(crm_data_t **children, crm_data_t *root, +find_xml_children(xmlNode **children, xmlNode *root, const char *tag, const char *field, const char *value, gboolean search_matches) { int match_found = 0; CRM_CHECK(root != NULL, return FALSE); CRM_CHECK(children != NULL, return FALSE); if(tag != NULL && safe_str_neq(tag, crm_element_name(root))) { } else if(value != NULL && safe_str_neq(value, crm_element_value(root, field))) { } else { if(*children == NULL) { *children = create_xml_node(NULL, __FUNCTION__); } add_node_copy(*children, root); match_found = 1; } if(search_matches || match_found == 0) { xml_child_iter( root, child, match_found += find_xml_children( children, child, tag, field, value, search_matches); ); } return match_found; } gboolean -replace_xml_child(crm_data_t *parent, crm_data_t *child, crm_data_t *update, gboolean delete_only) +replace_xml_child(xmlNode *parent, xmlNode *child, xmlNode *update, gboolean delete_only) { gboolean can_delete = FALSE; const char *up_id = NULL; const char *child_id = NULL; const char *right_val = NULL; CRM_CHECK(child != NULL, return FALSE); CRM_CHECK(update != NULL, return FALSE); up_id = ID(update); child_id = ID(child); if(up_id == NULL || safe_str_eq(child_id, up_id)) { can_delete = TRUE; } if(safe_str_neq(crm_element_name(update), crm_element_name(child))) { can_delete = FALSE; } if(can_delete && delete_only) { xml_prop_iter(update, prop_name, left_value, 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_4(child, "Delete match found..."); if(delete_only) { - cl_msg_remove_value(parent, child); - } else { - /* preserve the order */ - cl_msg_replace_value(parent, child, update, - sizeof(struct ha_msg), FT_STRUCT); + free_xml(child); + + } else { + xmlNode *tmp = copy_xml(update); + xmlNode *old = xmlReplaceNode(child, tmp); + free_xml(old); } child = NULL; return TRUE; } else if(can_delete) { crm_log_xml_debug(child, "Cannot delete the search root"); can_delete = FALSE; } xml_child_iter( child, child_of_child, /* only delete the first one */ if(can_delete) { break; } can_delete = replace_xml_child(child, child_of_child, update, delete_only); ); return can_delete; } void hash2nvpair(gpointer key, gpointer value, gpointer user_data) { const char *name = key; const char *s_value = value; - crm_data_t *xml_node = user_data; - crm_data_t *xml_child = create_xml_node(xml_node, XML_CIB_TAG_NVPAIR); + xmlNode *xml_node = user_data; + xmlNode *xml_child = create_xml_node(xml_node, XML_CIB_TAG_NVPAIR); crm_xml_add(xml_child, XML_ATTR_ID, name); crm_xml_add(xml_child, XML_NVPAIR_ATTR_NAME, name); crm_xml_add(xml_child, XML_NVPAIR_ATTR_VALUE, s_value); crm_debug_3("dumped: name=%s value=%s", name, s_value); } void hash2field(gpointer key, gpointer value, gpointer user_data) { const char *name = key; const char *s_value = value; - crm_data_t *xml_node = user_data; + xmlNode *xml_node = user_data; if(crm_element_value(xml_node, name) == NULL) { crm_xml_add(xml_node, name, s_value); crm_debug_3("dumped: %s=%s", name, s_value); } else { crm_debug_2("duplicate: %s=%s", name, s_value); } } void hash2metafield(gpointer key, gpointer value, gpointer user_data) { char *crm_name = NULL; if(key == NULL || value == NULL) { return; } crm_name = crm_concat(CRM_META, key, '_'); hash2field(crm_name, value, user_data); crm_free(crm_name); } #if CRM_DEPRECATED_SINCE_2_0_3 GHashTable * -xml2list_202(crm_data_t *parent) +xml2list_202(xmlNode *parent) { - crm_data_t *nvpair_list = NULL; + xmlNode *nvpair_list = NULL; GHashTable *nvpair_hash = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); CRM_CHECK(parent != NULL, return nvpair_hash); nvpair_list = find_xml_node(parent, XML_TAG_ATTRS, FALSE); if(nvpair_list == NULL) { crm_debug("No attributes in %s", crm_element_name(parent)); crm_log_xml_debug_2( parent,"No attributes for resource op"); } xml_child_iter_filter( nvpair_list, node_iter, XML_CIB_TAG_NVPAIR, const char *key = crm_element_value( node_iter, XML_NVPAIR_ATTR_NAME); const char *value = crm_element_value( node_iter, XML_NVPAIR_ATTR_VALUE); crm_debug_2("Added %s=%s", key, value); g_hash_table_insert( nvpair_hash, crm_strdup(key), crm_strdup(value)); ); return nvpair_hash; } #endif GHashTable * -xml2list(crm_data_t *parent) +xml2list(xmlNode *parent) { - crm_data_t *nvpair_list = NULL; + xmlNode *nvpair_list = NULL; GHashTable *nvpair_hash = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); CRM_CHECK(parent != NULL, return nvpair_hash); nvpair_list = find_xml_node(parent, XML_TAG_ATTRS, FALSE); if(nvpair_list == NULL) { crm_debug_2("No attributes in %s", crm_element_name(parent)); crm_log_xml_debug_2( parent,"No attributes for resource op"); } crm_log_xml_debug_3(nvpair_list, "Unpacking"); xml_prop_iter( nvpair_list, key, value, crm_debug_4("Added %s=%s", key, value); g_hash_table_insert( nvpair_hash, crm_strdup(key), crm_strdup(value)); ); return nvpair_hash; } static void -assign_uuid(crm_data_t *xml_obj) +assign_uuid(xmlNode *xml_obj) { cl_uuid_t new_uuid; char *new_uuid_s = NULL; const char *tag_name = crm_element_name(xml_obj); const char *tag_id = ID(xml_obj); crm_malloc0(new_uuid_s, 38); cl_uuid_generate(&new_uuid); cl_uuid_unparse(&new_uuid, new_uuid_s); crm_warn("Updating object from <%s id=%s/> to <%s id=%s/>", tag_name, tag_id?tag_id:"__empty__", tag_name, new_uuid_s); crm_xml_add(xml_obj, XML_ATTR_ID, new_uuid_s); crm_log_xml_debug(xml_obj, "Updated object"); crm_free(new_uuid_s); } static gboolean tag_needs_id(const char *tag_name) { int lpc = 0; const char *allowed_list[] = { XML_TAG_CIB, XML_TAG_FRAGMENT, XML_CIB_TAG_NODES, XML_CIB_TAG_RESOURCES, XML_CIB_TAG_CONSTRAINTS, XML_CIB_TAG_STATUS, XML_LRM_TAG_RESOURCES, "configuration", "crm_config", "attributes", "operations", "diff", "diff-added", "diff-removed", }; for(lpc = 0; lpc < DIMOF(allowed_list); lpc++) { if(crm_str_eq(tag_name, allowed_list[lpc], TRUE)) { /* this tag is never meant to have an ID */ return FALSE; } } return TRUE; } static gboolean non_unique_allowed(const char *tag_name) { int lpc = 0; const char *non_unique[] = { XML_LRM_TAG_RESOURCE, XML_LRM_TAG_RSC_OP, }; for(lpc = 0; lpc < DIMOF(non_unique); lpc++) { if(safe_str_eq(tag_name, non_unique[lpc])) { /* this tag can have a non-unique ID */ return TRUE; } } return FALSE; } gboolean -do_id_check(crm_data_t *xml_obj, GHashTable *id_hash, +do_id_check(xmlNode *xml_obj, GHashTable *id_hash, gboolean silent_add, gboolean silent_rename) { char *lookup_id = NULL; gboolean modified = FALSE; char *old_id = NULL; const char *tag_id = NULL; const char *tag_name = NULL; const char *lookup_value = NULL; gboolean created_hash = FALSE; if(xml_obj == NULL) { return FALSE; } else if(id_hash == NULL) { created_hash = TRUE; id_hash = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); } xml_child_iter( xml_obj, xml_child, if(do_id_check(xml_child, id_hash, silent_add, silent_rename)) { modified = TRUE; } ); tag_id = ID(xml_obj); tag_name = TYPE(xml_obj); if(tag_needs_id(tag_name) == FALSE) { crm_debug_5("%s does not need an ID", tag_name); goto finish_id_check; } else if(tag_id != NULL && non_unique_allowed(tag_name)){ crm_debug_5("%s does not need top be unique", tag_name); goto finish_id_check; } lookup_id = NULL; if(tag_id != NULL) { lookup_id = crm_concat(tag_name, tag_id, '-'); lookup_value = g_hash_table_lookup(id_hash, lookup_id); if(lookup_value == NULL) { g_hash_table_insert(id_hash, lookup_id, crm_strdup(tag_id)); goto finish_id_check; } modified |= (!silent_rename); } else { modified |= (!silent_add); } if(tag_id != NULL) { old_id = crm_strdup(tag_id); } crm_free(lookup_id); assign_uuid(xml_obj); tag_id = ID(xml_obj); if(modified == FALSE) { /* nothing to report */ } else if(old_id != NULL && safe_str_neq(tag_id, old_id)) { crm_err("\"id\" collision detected... Multiple '%s' entries" " with id=\"%s\", assigned id=\"%s\"", tag_name, old_id, tag_id); } else if(old_id == NULL && tag_id != NULL) { crm_err("Detected <%s.../> object without an ID. Assigned: %s", tag_name, tag_id); } crm_free(old_id); finish_id_check: if(created_hash) { g_hash_table_destroy(id_hash); } return modified; } typedef struct name_value_s { const char *name; const void *value; } name_value_t; static gint sort_pairs(gconstpointer a, gconstpointer b) { const name_value_t *pair_a = a; const name_value_t *pair_b = b; if(a == NULL && b == NULL) { return 0; } else if(a == NULL) { return 1; } else if(b == NULL) { return -1; } if(pair_a->name == NULL && pair_b->name == NULL) { return 0; } else if(pair_a->name == NULL) { return 1; } else if(pair_b->name == NULL) { return -1; } return strcmp(pair_a->name, pair_b->name); } static void dump_pair(gpointer data, gpointer user_data) { name_value_t *pair = data; - crm_data_t *parent = user_data; + xmlNode *parent = user_data; crm_xml_add(parent, pair->name, pair->value); } static void free_pair(gpointer data, gpointer user_data) { name_value_t *pair = data; crm_free(pair); } -static crm_data_t * -sorted_xml(const crm_data_t *input, crm_data_t *parent, gboolean recursive) +static xmlNode * +sorted_xml(xmlNode *input, xmlNode *parent, gboolean recursive) { GListPtr sorted = NULL; GListPtr unsorted = NULL; name_value_t *pair = NULL; - crm_data_t *result = NULL; + xmlNode *result = NULL; const char *name = crm_element_name(input); CRM_CHECK(input != NULL, return NULL); name = crm_element_name(input); CRM_CHECK(name != NULL, return NULL); result = create_xml_node(parent, name); xml_prop_iter(input, p_name, p_value, crm_malloc0(pair, sizeof(name_value_t)); pair->name = p_name; pair->value = p_value; unsorted = g_list_prepend(unsorted, pair); pair = NULL; ); sorted = g_list_sort(unsorted, sort_pairs); g_list_foreach(sorted, dump_pair, result); g_list_foreach(sorted, free_pair, NULL); g_list_free(sorted); if(recursive) { xml_child_iter(input, child, sorted_xml(child, result, recursive)); } else { xml_child_iter(input, child, add_node_copy(result, child)); } return result; } static void -filter_xml(crm_data_t *data, const char **filter, int filter_len, gboolean recursive) +filter_xml(xmlNode *data, const char **filter, int filter_len, gboolean recursive) { int lpc = 0; for(lpc = 0; lpc < filter_len; lpc++) { xml_remove_prop(data, filter[lpc]); } if(recursive == FALSE) { return; } xml_child_iter(data, child, filter_xml(child, filter, filter_len, recursive)); } /* "c048eae664dba840e1d2060f00299e9d" */ char * -calculate_xml_digest(crm_data_t *input, gboolean sort, gboolean do_filter) +calculate_xml_digest(xmlNode *input, gboolean sort, gboolean do_filter) { int i = 0; int digest_len = 16; char *digest = NULL; unsigned char *raw_digest = NULL; - crm_data_t *sorted = NULL; + xmlNode *sorted = NULL; char *buffer = NULL; size_t buffer_len = 0; if(sort || do_filter) { sorted = sorted_xml(input, NULL, TRUE); } else { sorted = copy_xml(input); } if(do_filter) { filter_xml(sorted, filter, DIMOF(filter), TRUE); } buffer = dump_xml_formatted(sorted); buffer_len = strlen(buffer); CRM_CHECK(buffer != NULL && buffer_len > 0, free_xml(sorted); return NULL); crm_malloc0(digest, (2 * digest_len + 1)); crm_malloc0(raw_digest, (digest_len + 1)); MD5((unsigned char *)buffer, buffer_len, raw_digest); for(i = 0; i < digest_len; i++) { sprintf(digest+(2*i), "%02x", raw_digest[i]); } crm_debug_2("Digest %s: %s\n", digest, buffer); crm_log_xml(LOG_DEBUG_3, "digest:source", sorted); crm_free(buffer); crm_free(raw_digest); free_xml(sorted); return digest; } #if HAVE_LIBXML2 # include # include #endif gboolean validate_with_dtd( - crm_data_t *xml_blob, gboolean to_logs, const char *dtd_file) + xmlNode *xml_blob, gboolean to_logs, const char *dtd_file) { gboolean valid = TRUE; -#if HAVE_LIBXML2 char *buffer = NULL; xmlDocPtr doc = NULL; xmlDtdPtr dtd = NULL; xmlValidCtxtPtr cvp = NULL; CRM_CHECK(xml_blob != NULL, return FALSE); CRM_CHECK(dtd_file != NULL, return FALSE); buffer = dump_xml_formatted(xml_blob); CRM_CHECK(buffer != NULL, return FALSE); doc = xmlParseMemory(buffer, strlen(buffer)); CRM_CHECK(doc != NULL, valid = FALSE; goto cleanup); dtd = xmlParseDTD(NULL, (const xmlChar *)dtd_file); CRM_CHECK(dtd != NULL, goto cleanup); cvp = xmlNewValidCtxt(); CRM_CHECK(cvp != NULL, goto cleanup); if(to_logs) { cvp->userData = (void *) LOG_ERR; cvp->error = (xmlValidityErrorFunc) cl_log; cvp->warning = (xmlValidityWarningFunc) cl_log; } else { cvp->userData = (void *) stderr; cvp->error = (xmlValidityErrorFunc) fprintf; cvp->warning = (xmlValidityWarningFunc) fprintf; } if (!xmlValidateDtd(cvp, doc, dtd)) { valid = FALSE; } cleanup: if(cvp) { xmlFreeValidCtxt(cvp); } if(dtd) { xmlFreeDtd(dtd); } if(doc) { xmlFreeDoc(doc); } if(buffer) { crm_free(buffer); } -#endif return valid; } + +xmlNode *first_named_child(xmlNode *parent, const char *name) +{ + xml_child_iter_filter(parent, match, name, return match); + return NULL; +} diff --git a/lib/crm/pengine/clone.c b/lib/crm/pengine/clone.c index ce9f50bf15..34bbd16921 100644 --- a/lib/crm/pengine/clone.c +++ b/lib/crm/pengine/clone.c @@ -1,315 +1,315 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #define VARIANT_CLONE 1 #include "./variant.h" void clone_create_notifications( resource_t *rsc, action_t *action, action_t *action_complete, pe_working_set_t *data_set); static gboolean create_child_clone(resource_t *rsc, int sub_id, pe_working_set_t *data_set) { gboolean rc = TRUE; char *inc_num = NULL; char *inc_max = NULL; resource_t *child_rsc = NULL; - crm_data_t * child_copy = NULL; + xmlNode * child_copy = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); CRM_CHECK(clone_data->xml_obj_child != NULL, return FALSE); inc_num = crm_itoa(sub_id); inc_max = crm_itoa(clone_data->clone_max); child_copy = copy_xml(clone_data->xml_obj_child); crm_xml_add(child_copy, XML_RSC_ATTR_INCARNATION, inc_num); if(common_unpack(child_copy, &child_rsc, rsc, data_set) == FALSE) { pe_err("Failed unpacking resource %s", crm_element_value(child_copy, XML_ATTR_ID)); goto bail; } /* child_rsc->globally_unique = rsc->globally_unique; */ crm_debug_3("Setting clone attributes for: %s", child_rsc->id); rsc->children = g_list_append(rsc->children, child_rsc); add_hash_param(child_rsc->meta, XML_RSC_ATTR_INCARNATION_MAX, inc_max); print_resource(LOG_DEBUG_3, "Added", child_rsc, FALSE); bail: crm_free(inc_num); crm_free(inc_max); return rc; } gboolean master_unpack(resource_t *rsc, pe_working_set_t *data_set) { const char *master_max = g_hash_table_lookup( rsc->meta, XML_RSC_ATTR_MASTER_MAX); const char *master_node_max = g_hash_table_lookup( rsc->meta, XML_RSC_ATTR_MASTER_NODEMAX); add_hash_param(rsc->parameters, crm_meta_name("stateful"), XML_BOOLEAN_TRUE); if(clone_unpack(rsc, data_set)) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); clone_data->master_max = crm_parse_int(master_max, "1"); clone_data->master_node_max = crm_parse_int(master_node_max, "1"); return TRUE; } return FALSE; } gboolean clone_unpack(resource_t *rsc, pe_working_set_t *data_set) { int lpc = 0; const char *type = NULL; resource_t *self = NULL; int num_xml_children = 0; - crm_data_t *xml_tmp = NULL; - crm_data_t *xml_self = NULL; - crm_data_t *xml_obj = rsc->xml; + xmlNode *xml_tmp = NULL; + xmlNode *xml_self = NULL; + xmlNode *xml_obj = rsc->xml; clone_variant_data_t *clone_data = NULL; const char *ordered = g_hash_table_lookup( rsc->meta, XML_RSC_ATTR_ORDERED); const char *interleave = g_hash_table_lookup( rsc->meta, XML_RSC_ATTR_INTERLEAVE); const char *max_clones = g_hash_table_lookup( rsc->meta, XML_RSC_ATTR_INCARNATION_MAX); const char *max_clones_node = g_hash_table_lookup( rsc->meta, XML_RSC_ATTR_INCARNATION_NODEMAX); crm_debug_3("Processing resource %s...", rsc->id); crm_malloc0(clone_data, sizeof(clone_variant_data_t)); rsc->variant_opaque = clone_data; clone_data->interleave = FALSE; clone_data->ordered = FALSE; clone_data->active_clones = 0; clone_data->xml_obj_child = NULL; clone_data->clone_node_max = crm_parse_int(max_clones_node, "1"); clone_data->clone_max = crm_parse_int(max_clones, "-1"); if(clone_data->clone_max < 0) { clone_data->clone_max = g_list_length(data_set->nodes); } if(crm_is_true(interleave)) { clone_data->interleave = TRUE; } if(crm_is_true(ordered)) { clone_data->ordered = TRUE; } if((rsc->flags & pe_rsc_unique) == 0 && clone_data->clone_node_max > 1) { crm_config_err("Anonymous clones (%s) may only support one copy" " per node", rsc->id); clone_data->clone_node_max = 1; } crm_debug_2("Options for %s", rsc->id); crm_debug_2("\tClone max: %d", clone_data->clone_max); crm_debug_2("\tClone node max: %d", clone_data->clone_node_max); crm_debug_2("\tClone is unique: %s", is_set(rsc->flags, pe_rsc_unique)?"true":"false"); clone_data->xml_obj_child = find_xml_node( xml_obj, XML_CIB_TAG_GROUP, FALSE); if(clone_data->xml_obj_child == NULL) { clone_data->xml_obj_child = find_xml_node( xml_obj, XML_CIB_TAG_RESOURCE, TRUE); } else { xml_child_iter_filter(xml_obj, a_child, XML_CIB_TAG_RESOURCE, num_xml_children++); } if(clone_data->xml_obj_child == NULL) { crm_config_err("%s has nothing to clone", rsc->id); return FALSE; } type = crm_element_name(clone_data->xml_obj_child); xml_child_iter_filter(xml_obj, a_child, type, num_xml_children++); if(num_xml_children > 1) { crm_config_err("%s has too many children. Only the first (%s) will be cloned.", rsc->id, ID(clone_data->xml_obj_child)); } xml_self = copy_xml(rsc->xml); /* this is a bit of a hack - but simplifies everything else */ - ha_msg_mod(xml_self, F_XML_TAGNAME, XML_CIB_TAG_RESOURCE); + xml_self->name = xmlCharStrdup(XML_CIB_TAG_RESOURCE); /* set_id(xml_self, "self", -1); */ xml_tmp = find_xml_node(xml_obj, "operations", FALSE); if(xml_tmp != NULL) { add_node_copy(xml_self, xml_tmp); } /* Make clones ever so slightly sticky by default * This is the only way to ensure clone instances are not * shuffled around the cluster for no benefit */ add_hash_param(rsc->meta, "resource_stickiness", "1"); if(common_unpack(xml_self, &self, rsc, data_set)) { clone_data->self = self; } else { crm_log_xml_err(xml_self, "Couldnt unpack dummy child"); clone_data->self = self; return FALSE; } clone_data->notify_confirm = is_set(rsc->flags, pe_rsc_notify); for(lpc = 0; lpc < clone_data->clone_max; lpc++) { create_child_clone(rsc, lpc, data_set); } crm_debug_3("Added %d children to resource %s...", clone_data->clone_max, rsc->id); return TRUE; } gboolean clone_active(resource_t *rsc, gboolean all) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); slist_iter( child_rsc, resource_t, rsc->children, lpc, gboolean child_active = child_rsc->fns->active(child_rsc, all); if(all == FALSE && child_active) { return TRUE; } else if(all && child_active == FALSE) { return FALSE; } ); if(all) { return TRUE; } else { return FALSE; } } void clone_print( resource_t *rsc, const char *pre_text, long options, void *print_data) { const char *child_text = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); if(pre_text != NULL) { child_text = " "; } else { child_text = " "; } if(rsc->variant == pe_master) { status_print("%sMaster/Slave Set: %s", pre_text?pre_text:"", rsc->id); } else { status_print("%sClone Set: %s", pre_text?pre_text:"", rsc->id); } if(options & pe_print_html) { status_print("\n
    \n"); } else if((options & pe_print_log) == 0) { status_print("\n"); } slist_iter( child_rsc, resource_t, rsc->children, lpc, if(options & pe_print_html) { status_print("
  • \n"); } child_rsc->fns->print( child_rsc, child_text, options, print_data); if(options & pe_print_html) { status_print("
  • \n"); } ); if(options & pe_print_html) { status_print("
\n"); } } void clone_free(resource_t *rsc) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); crm_debug_3("Freeing %s", rsc->id); slist_iter( child_rsc, resource_t, rsc->children, lpc, crm_debug_3("Freeing child %s", child_rsc->id); free_xml(child_rsc->xml); child_rsc->fns->free(child_rsc); ); crm_debug_3("Freeing child list"); pe_free_shallow_adv(rsc->children, FALSE); if(clone_data->self) { free_xml(clone_data->self->xml); clone_data->self->fns->free(clone_data->self); } common_free(rsc); } enum rsc_role_e clone_resource_state(const resource_t *rsc, gboolean current) { enum rsc_role_e clone_role = RSC_ROLE_UNKNOWN; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); slist_iter( child_rsc, resource_t, rsc->children, lpc, enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, current); if(a_role > clone_role) { clone_role = a_role; } ); crm_debug_3("%s role: %s", rsc->id, role2text(clone_role)); return clone_role; } diff --git a/lib/crm/pengine/complex.c b/lib/crm/pengine/complex.c index 587009842d..33cbd22f6a 100644 --- a/lib/crm/pengine/complex.c +++ b/lib/crm/pengine/complex.c @@ -1,414 +1,414 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include -void populate_hash(crm_data_t *nvpair_list, GHashTable *hash, +void populate_hash(xmlNode *nvpair_list, GHashTable *hash, const char **attrs, int attrs_length); resource_object_functions_t resource_class_functions[] = { { native_unpack, native_find_child, native_children, native_parameter, native_print, native_active, native_resource_state, native_location, native_free }, { group_unpack, native_find_child, native_children, native_parameter, group_print, group_active, group_resource_state, native_location, group_free }, { clone_unpack, native_find_child, native_children, native_parameter, clone_print, clone_active, clone_resource_state, native_location, clone_free }, { master_unpack, native_find_child, native_children, native_parameter, clone_print, clone_active, clone_resource_state, native_location, clone_free } }; int get_resource_type(const char *name) { if(safe_str_eq(name, XML_CIB_TAG_RESOURCE)) { return pe_native; } else if(safe_str_eq(name, XML_CIB_TAG_GROUP)) { return pe_group; } else if(safe_str_eq(name, XML_CIB_TAG_INCARNATION)) { return pe_clone; } else if(safe_str_eq(name, XML_CIB_TAG_MASTER)) { return pe_master; } return pe_unknown; } static void dup_attr(gpointer key, gpointer value, gpointer user_data) { add_hash_param(user_data, key, value); } void get_meta_attributes(GHashTable *meta_hash, resource_t *rsc, node_t *node, pe_working_set_t *data_set) { GHashTable *node_hash = NULL; if(node) { node_hash = node->details->attrs; } xml_prop_iter(rsc->xml, prop_name, prop_value, add_hash_param(meta_hash, prop_name, prop_value); ); unpack_instance_attributes(rsc->xml, XML_TAG_META_SETS, node_hash, meta_hash, NULL, data_set->now); /* populate from the regular attributes until the GUI can create * meta attributes */ unpack_instance_attributes(rsc->xml, XML_TAG_ATTR_SETS, node_hash, meta_hash, NULL, data_set->now); /* set anything else based on the parent */ if(rsc->parent != NULL) { g_hash_table_foreach(rsc->parent->meta, dup_attr, meta_hash); } } gboolean -common_unpack(crm_data_t * xml_obj, resource_t **rsc, +common_unpack(xmlNode * xml_obj, resource_t **rsc, resource_t *parent, pe_working_set_t *data_set) { const char *value = NULL; const char *id = crm_element_value(xml_obj, XML_ATTR_ID); crm_log_xml_debug_3(xml_obj, "Processing resource input..."); if(id == NULL) { pe_err("Must specify id tag in "); return FALSE; } else if(rsc == NULL) { pe_err("Nowhere to unpack resource into"); return FALSE; } crm_malloc0(*rsc, sizeof(resource_t)); if(*rsc == NULL) { return FALSE; } (*rsc)->xml = xml_obj; (*rsc)->parent = parent; (*rsc)->ops_xml = find_xml_node(xml_obj, "operations", FALSE); (*rsc)->variant = get_resource_type(crm_element_name(xml_obj)); if((*rsc)->variant == pe_unknown) { pe_err("Unknown resource type: %s", crm_element_name(xml_obj)); crm_free(*rsc); return FALSE; } (*rsc)->parameters = g_hash_table_new_full( g_str_hash,g_str_equal, g_hash_destroy_str,g_hash_destroy_str); (*rsc)->meta = g_hash_table_new_full( g_str_hash,g_str_equal, g_hash_destroy_str,g_hash_destroy_str); value = crm_element_value(xml_obj, XML_RSC_ATTR_INCARNATION); if(value) { (*rsc)->id = crm_concat(id, value, ':'); add_hash_param((*rsc)->meta, XML_RSC_ATTR_INCARNATION, value); } else { (*rsc)->id = crm_strdup(id); } if(parent) { (*rsc)->long_name = crm_concat(parent->long_name, (*rsc)->id, ':'); } else { (*rsc)->long_name = crm_strdup((*rsc)->id); } (*rsc)->fns = &resource_class_functions[(*rsc)->variant]; crm_debug_3("Unpacking resource..."); get_meta_attributes((*rsc)->meta, *rsc, NULL, data_set); if(parent != NULL) { g_hash_table_foreach( parent->parameters, dup_attr, (*rsc)->parameters); } (*rsc)->flags = 0; set_bit((*rsc)->flags, pe_rsc_runnable); set_bit((*rsc)->flags, pe_rsc_provisional); if(data_set->is_managed_default) { set_bit((*rsc)->flags, pe_rsc_managed); } (*rsc)->rsc_cons = NULL; (*rsc)->actions = NULL; (*rsc)->role = RSC_ROLE_STOPPED; (*rsc)->next_role = RSC_ROLE_UNKNOWN; (*rsc)->recovery_type = recovery_stop_start; (*rsc)->stickiness = data_set->default_resource_stickiness; (*rsc)->fail_stickiness = data_set->default_resource_fail_stickiness; value = g_hash_table_lookup((*rsc)->meta, XML_CIB_ATTR_PRIORITY); (*rsc)->priority = crm_parse_int(value, "0"); (*rsc)->effective_priority = (*rsc)->priority; value = g_hash_table_lookup((*rsc)->meta, XML_RSC_ATTR_NOTIFY); if(crm_is_true(value)) { set_bit((*rsc)->flags, pe_rsc_notify); } value = g_hash_table_lookup((*rsc)->meta, "is_managed"); if(value != NULL && safe_str_neq("default", value)) { gboolean bool_value = TRUE; cl_str_to_boolean(value, &bool_value); if(bool_value == FALSE) { clear_bit((*rsc)->flags, pe_rsc_managed); } } crm_debug_2("Options for %s", (*rsc)->id); value = g_hash_table_lookup((*rsc)->meta, "globally_unique"); if(value == NULL || crm_is_true(value)) { set_bit((*rsc)->flags, pe_rsc_unique); } value = g_hash_table_lookup((*rsc)->meta, XML_RSC_ATTR_RESTART); if(safe_str_eq(value, "restart")) { (*rsc)->restart_type = pe_restart_restart; crm_debug_2("\tDependancy restart handling: restart"); } else { (*rsc)->restart_type = pe_restart_ignore; crm_debug_2("\tDependancy restart handling: ignore"); } value = g_hash_table_lookup((*rsc)->meta, "multiple_active"); if(safe_str_eq(value, "stop_only")) { (*rsc)->recovery_type = recovery_stop_only; crm_debug_2("\tMultiple running resource recovery: stop only"); } else if(safe_str_eq(value, "block")) { (*rsc)->recovery_type = recovery_block; crm_debug_2("\tMultiple running resource recovery: block"); } else { (*rsc)->recovery_type = recovery_stop_start; crm_debug_2("\tMultiple running resource recovery: stop/start"); } value = g_hash_table_lookup((*rsc)->meta, "resource_stickiness"); if(value != NULL && safe_str_neq("default", value)) { (*rsc)->stickiness = char2score(value); } value = g_hash_table_lookup((*rsc)->meta, XML_RSC_ATTR_FAIL_STICKINESS); if(value != NULL) { (*rsc)->fail_stickiness = char2score(value); } value = g_hash_table_lookup((*rsc)->meta, XML_RSC_ATTR_TARGET_ROLE); if(value != NULL && safe_str_neq("default", value)) { (*rsc)->next_role = text2role(value); if((*rsc)->next_role == RSC_ROLE_UNKNOWN) { crm_config_err("%s: Unknown value for " XML_RSC_ATTR_TARGET_ROLE": %s", (*rsc)->id, value); } } crm_debug_2("\tDesired next state: %s", (*rsc)->next_role!=RSC_ROLE_UNKNOWN?role2text((*rsc)->next_role):"default"); if((*rsc)->fns->unpack(*rsc, data_set) == FALSE) { return FALSE; } if(is_not_set((*rsc)->flags, pe_rsc_managed)) { crm_warn("Resource %s is currently not managed", (*rsc)->id); } else if(data_set->symmetric_cluster) { resource_location(*rsc, NULL, 0, "symmetric_default", data_set); } crm_debug_2("\tAction notification: %s", is_set((*rsc)->flags, pe_rsc_notify)?"required":"not required"); /* data_set->resources = g_list_append(data_set->resources, (*rsc)); */ return TRUE; } void common_update_score(resource_t *rsc, const char *id, int score) { node_t *node = NULL; node = pe_find_node_id(rsc->allowed_nodes, id); if(node != NULL) { crm_debug_2("Updating score for %s on %s: %d + %d", rsc->id, id, node->weight, score); node->weight = merge_weights(node->weight, score); } if(rsc->children) { slist_iter( child_rsc, resource_t, rsc->children, lpc, common_update_score(child_rsc, id, score); ); } } void common_apply_stickiness(resource_t *rsc, node_t *node, pe_working_set_t *data_set) { int fail_count = 0; char *fail_attr = NULL; const char *value = NULL; GHashTable *meta_hash = NULL; if(rsc->children) { slist_iter( child_rsc, resource_t, rsc->children, lpc, common_apply_stickiness(child_rsc, node, data_set); ); return; } meta_hash = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); get_meta_attributes(meta_hash, rsc, node, data_set); /* update resource preferences that relate to the current node */ value = g_hash_table_lookup(meta_hash, "resource_stickiness"); if(value != NULL && safe_str_neq("default", value)) { rsc->stickiness = char2score(value); } else { rsc->stickiness = data_set->default_resource_stickiness; } value = g_hash_table_lookup(meta_hash, XML_RSC_ATTR_FAIL_STICKINESS); if(value != NULL && safe_str_neq("default", value)) { rsc->fail_stickiness = char2score(value); } else { rsc->fail_stickiness = data_set->default_resource_fail_stickiness; } /* process failure stickiness */ fail_attr = crm_concat("fail-count", rsc->id, '-'); value = g_hash_table_lookup(node->details->attrs, fail_attr); if(value != NULL) { crm_debug("%s: %s", fail_attr, value); fail_count = char2score(value); } crm_free(fail_attr); if(fail_count > 0 && rsc->fail_stickiness != 0) { resource_location(rsc, node, fail_count * rsc->fail_stickiness, "fail_stickiness", data_set); crm_info("Setting failure stickiness for %s on %s: %d", rsc->id, node->details->uname, fail_count * rsc->fail_stickiness); } g_hash_table_destroy(meta_hash); } void common_free(resource_t *rsc) { if(rsc == NULL) { return; } crm_debug_5("Freeing %s %d", rsc->id, rsc->variant); g_list_free(rsc->rsc_cons); g_list_free(rsc->rsc_cons_lhs); if(rsc->parameters != NULL) { g_hash_table_destroy(rsc->parameters); } if(rsc->meta != NULL) { g_hash_table_destroy(rsc->meta); } if(is_set(rsc->flags, pe_rsc_orphan)) { free_xml(rsc->xml); } if(rsc->running_on) { g_list_free(rsc->running_on); rsc->running_on = NULL; } if(rsc->known_on) { g_list_free(rsc->known_on); rsc->known_on = NULL; } if(rsc->actions) { g_list_free(rsc->actions); rsc->actions = NULL; } pe_free_shallow_adv(rsc->rsc_location, FALSE); pe_free_shallow_adv(rsc->allowed_nodes, TRUE); crm_free(rsc->id); crm_free(rsc->long_name); crm_free(rsc->clone_name); crm_free(rsc->allocated_to); crm_free(rsc->variant_opaque); crm_free(rsc); crm_debug_5("Resource freed"); } diff --git a/lib/crm/pengine/group.c b/lib/crm/pengine/group.c index 14e058cf01..d168a29e49 100644 --- a/lib/crm/pengine/group.c +++ b/lib/crm/pengine/group.c @@ -1,219 +1,218 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #define VARIANT_GROUP 1 #include "./variant.h" gboolean group_unpack(resource_t *rsc, pe_working_set_t *data_set) { resource_t *self = NULL; - crm_data_t *xml_obj = rsc->xml; - crm_data_t *xml_self = copy_xml(rsc->xml); + xmlNode *xml_obj = rsc->xml; + xmlNode *xml_self = copy_xml(rsc->xml); group_variant_data_t *group_data = NULL; const char *group_ordered = g_hash_table_lookup( rsc->meta, XML_RSC_ATTR_ORDERED); const char *group_colocated = g_hash_table_lookup( rsc->meta, "collocated"); const char *clone_id = NULL; crm_debug_3("Processing resource %s...", rsc->id); crm_malloc0(group_data, sizeof(group_variant_data_t)); group_data->num_children = 0; group_data->self = NULL; group_data->first_child = NULL; group_data->last_child = NULL; rsc->variant_opaque = group_data; group_data->ordered = TRUE; group_data->colocated = TRUE; if(group_ordered != NULL) { cl_str_to_boolean(group_ordered, &(group_data->ordered)); } if(group_colocated != NULL) { cl_str_to_boolean(group_colocated, &(group_data->colocated)); } /* this is a bit of a hack - but simplifies everything else */ - ha_msg_mod(xml_self, F_XML_TAGNAME, XML_CIB_TAG_RESOURCE); - + xml_self->name = xmlCharStrdup(XML_CIB_TAG_RESOURCE); if(common_unpack(xml_self, &self, NULL, data_set)) { group_data->self = self; self->restart_type = pe_restart_restart; } else { crm_log_xml_err(xml_self, "Couldnt unpack dummy child"); return FALSE; } clone_id = crm_element_value(rsc->xml, XML_RSC_ATTR_INCARNATION); xml_child_iter_filter( xml_obj, xml_native_rsc, XML_CIB_TAG_RESOURCE, resource_t *new_rsc = NULL; crm_xml_add(xml_native_rsc, XML_RSC_ATTR_INCARNATION, clone_id); if(common_unpack(xml_native_rsc, &new_rsc, rsc, data_set) == FALSE) { pe_err("Failed unpacking resource %s", crm_element_value(xml_obj, XML_ATTR_ID)); if(new_rsc != NULL && new_rsc->fns != NULL) { new_rsc->fns->free(new_rsc); } } group_data->num_children++; rsc->children = g_list_append(rsc->children, new_rsc); if(group_data->first_child == NULL) { group_data->first_child = new_rsc; } group_data->last_child = new_rsc; print_resource(LOG_DEBUG_3, "Added", new_rsc, FALSE); ); if(group_data->num_children == 0) { #if 0 /* Bug #1287 */ crm_config_err("Group %s did not have any children", rsc->id); return FALSE; #else crm_config_warn("Group %s did not have any children", rsc->id); return TRUE; #endif } crm_debug_3("Added %d children to resource %s...", group_data->num_children, rsc->id); return TRUE; } gboolean group_active(resource_t *rsc, gboolean all) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); slist_iter( child_rsc, resource_t, rsc->children, lpc, gboolean child_active = child_rsc->fns->active(child_rsc, all); if(all == FALSE && child_active) { return TRUE; } else if(child_active == FALSE) { return FALSE; } ); if(all) { return TRUE; } else { return FALSE; } } void group_print( resource_t *rsc, const char *pre_text, long options, void *print_data) { const char *child_text = NULL; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); if(pre_text != NULL) { child_text = " "; } else { child_text = " "; } status_print("%sResource Group: %s", pre_text?pre_text:"", rsc->id); if(options & pe_print_html) { status_print("\n
    \n"); } else if((options & pe_print_log) == 0) { status_print("\n"); } slist_iter( child_rsc, resource_t, rsc->children, lpc, if(options & pe_print_html) { status_print("
  • \n"); } child_rsc->fns->print( child_rsc, child_text, options, print_data); if(options & pe_print_html) { status_print("
  • \n"); } ); if(options & pe_print_html) { status_print("
\n"); } } void group_free(resource_t *rsc) { group_variant_data_t *group_data = NULL; CRM_CHECK(rsc != NULL, return); get_group_variant_data(group_data, rsc); crm_debug_3("Freeing %s", rsc->id); slist_iter( child_rsc, resource_t, rsc->children, lpc, crm_debug_3("Freeing child %s", child_rsc->id); child_rsc->fns->free(child_rsc); ); crm_debug_3("Freeing child list"); pe_free_shallow_adv(rsc->children, FALSE); if(group_data->self != NULL) { free_xml(group_data->self->xml); group_data->self->fns->free(group_data->self); } common_free(rsc); } enum rsc_role_e group_resource_state(const resource_t *rsc, gboolean current) { enum rsc_role_e group_role = RSC_ROLE_UNKNOWN; slist_iter( child_rsc, resource_t, rsc->children, lpc, enum rsc_role_e role = child_rsc->fns->state(child_rsc, current); if(role > group_role) { group_role = role; } ); crm_debug_3("%s role: %s", rsc->id, role2text(group_role)); return group_role; } diff --git a/lib/crm/pengine/rules.c b/lib/crm/pengine/rules.c index c656273b2c..f245876867 100644 --- a/lib/crm/pengine/rules.c +++ b/lib/crm/pengine/rules.c @@ -1,622 +1,622 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include -ha_time_t *parse_xml_duration(ha_time_t *start, crm_data_t *duration_spec); +ha_time_t *parse_xml_duration(ha_time_t *start, xmlNode *duration_spec); -gboolean test_date_expression(crm_data_t *time_expr, ha_time_t *now); -gboolean cron_range_satisfied(ha_time_t *now, crm_data_t *cron_spec); +gboolean test_date_expression(xmlNode *time_expr, ha_time_t *now); +gboolean cron_range_satisfied(ha_time_t *now, xmlNode *cron_spec); gboolean test_attr_expression( - crm_data_t *expr, GHashTable *hash, ha_time_t *now); + xmlNode *expr, GHashTable *hash, ha_time_t *now); gboolean test_role_expression( - crm_data_t *expr, enum rsc_role_e role, ha_time_t *now); + xmlNode *expr, enum rsc_role_e role, ha_time_t *now); gboolean -test_ruleset(crm_data_t *ruleset, GHashTable *node_hash, ha_time_t *now) +test_ruleset(xmlNode *ruleset, GHashTable *node_hash, ha_time_t *now) { gboolean ruleset_default = TRUE; xml_child_iter_filter( ruleset, rule, XML_TAG_RULE, ruleset_default = FALSE; if(test_rule(rule, node_hash, RSC_ROLE_UNKNOWN, now)) { return TRUE; } ); return ruleset_default; } gboolean -test_rule(crm_data_t *rule, GHashTable *node_hash, enum rsc_role_e role, +test_rule(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role, ha_time_t *now) { gboolean test = TRUE; gboolean empty = TRUE; gboolean passed = TRUE; gboolean do_and = TRUE; const char *value = crm_element_value(rule, "boolean_op"); if(safe_str_eq(value, "or")) { do_and = FALSE; passed = FALSE; } crm_debug_2("Testing rule %s", ID(rule)); xml_child_iter( rule, expr, test = test_expression(expr, node_hash, role, now); empty = FALSE; if(test && do_and == FALSE) { crm_debug_3("Expression %s/%s passed", ID(rule), ID(expr)); return TRUE; } else if(test == FALSE && do_and) { crm_debug_3("Expression %s/%s failed", ID(rule), ID(expr)); return FALSE; } ); if(empty) { crm_err("Invalid Rule %s: rules must contain at least one expression", ID(rule)); } crm_debug_2("Rule %s %s", ID(rule), passed?"passed":"failed"); return passed; } gboolean -test_expression(crm_data_t *expr, GHashTable *node_hash, enum rsc_role_e role, +test_expression(xmlNode *expr, GHashTable *node_hash, enum rsc_role_e role, ha_time_t *now) { gboolean accept = FALSE; const char *uname = NULL; switch(find_expression_type(expr)) { case nested_rule: accept = test_rule(expr, node_hash, role, now); break; case attr_expr: case loc_expr: /* these expressions can never succeed if there is * no node to compare with */ if(node_hash != NULL) { accept = test_attr_expression(expr, node_hash, now); } break; case time_expr: accept = test_date_expression(expr, now); break; case role_expr: accept = test_role_expression(expr, role, now); break; default: CRM_CHECK(FALSE /* bad type */, return FALSE); accept = FALSE; } if(node_hash) { uname = g_hash_table_lookup(node_hash, "#uname"); } crm_debug_2("Expression %s %s on %s", ID(expr), accept?"passed":"failed", uname?uname:"all ndoes"); return accept; } enum expression_type -find_expression_type(crm_data_t *expr) +find_expression_type(xmlNode *expr) { const char *tag = NULL; const char *attr = NULL; attr = crm_element_value(expr, XML_EXPR_ATTR_ATTRIBUTE); tag = crm_element_name(expr); if(safe_str_eq(tag, "date_expression")) { return time_expr; } else if(safe_str_eq(tag, XML_TAG_RULE)) { return nested_rule; } else if(safe_str_neq(tag, "expression")) { return not_expr; } else if(safe_str_eq(attr, "#uname") || safe_str_eq(attr, "#id")) { return loc_expr; } else if(safe_str_eq(attr, "#role")) { return role_expr; } return attr_expr; } gboolean test_role_expression( - crm_data_t *expr, enum rsc_role_e role, ha_time_t *now) + xmlNode *expr, enum rsc_role_e role, ha_time_t *now) { gboolean accept = FALSE; const char *op = NULL; const char *value = NULL; if(role == RSC_ROLE_UNKNOWN) { return accept; } value = crm_element_value(expr, XML_EXPR_ATTR_VALUE); op = crm_element_value(expr, XML_EXPR_ATTR_OPERATION); if(safe_str_eq(op, "defined")) { if(role > RSC_ROLE_STARTED) { accept = TRUE; } } else if(safe_str_eq(op, "not_defined")) { if(role < RSC_ROLE_SLAVE && role > RSC_ROLE_UNKNOWN) { accept = TRUE; } } else if(safe_str_eq(op, "eq")) { if(text2role(value) == role) { accept = TRUE; } } else if(safe_str_eq(op, "ne")) { /* we will only test "ne" wtih master/slave roles style */ if(role < RSC_ROLE_SLAVE && role > RSC_ROLE_UNKNOWN) { accept = FALSE; } else if(text2role(value) != role) { accept = TRUE; } } return accept; } gboolean -test_attr_expression(crm_data_t *expr, GHashTable *hash, ha_time_t *now) +test_attr_expression(xmlNode *expr, GHashTable *hash, ha_time_t *now) { gboolean accept = FALSE; int cmp = 0; const char *h_val = NULL; const char *op = NULL; const char *type = NULL; const char *attr = NULL; const char *value = NULL; attr = crm_element_value(expr, XML_EXPR_ATTR_ATTRIBUTE); op = crm_element_value(expr, XML_EXPR_ATTR_OPERATION); value = crm_element_value(expr, XML_EXPR_ATTR_VALUE); type = crm_element_value(expr, XML_EXPR_ATTR_TYPE); if(attr == NULL || op == NULL) { pe_err("Invlaid attribute or operation in expression" " (\'%s\' \'%s\' \'%s\')", crm_str(attr), crm_str(op), crm_str(value)); return FALSE; } if(hash != NULL) { h_val = (const char*)g_hash_table_lookup(hash, attr); } if(value != NULL && h_val != NULL) { if(type == NULL || (safe_str_eq(type, "string"))) { cmp = strcasecmp(h_val, value); } else if(safe_str_eq(type, "number")) { int h_val_f = crm_parse_int(h_val, NULL); int value_f = crm_parse_int(value, NULL); if(h_val_f < value_f) { cmp = -1; } else if(h_val_f > value_f) { cmp = 1; } else { cmp = 0; } } else if(safe_str_eq(type, "version")) { cmp = compare_version(h_val, value); } } else if(value == NULL && h_val == NULL) { cmp = 0; } else if(value == NULL) { cmp = 1; } else { cmp = -1; } if(safe_str_eq(op, "defined")) { if(h_val != NULL) { accept = TRUE; } } else if(safe_str_eq(op, "not_defined")) { if(h_val == NULL) { accept = TRUE; } } else if(safe_str_eq(op, "eq")) { if((h_val == value) || cmp == 0) { accept = TRUE; } } else if(safe_str_eq(op, "ne")) { if((h_val == NULL && value != NULL) || (h_val != NULL && value == NULL) || cmp != 0) { accept = TRUE; } } else if(value == NULL || h_val == NULL) { /* the comparision is meaningless from this point on */ accept = FALSE; } else if(safe_str_eq(op, "lt")) { if(cmp < 0) { accept = TRUE; } } else if(safe_str_eq(op, "lte")) { if(cmp <= 0) { accept = TRUE; } } else if(safe_str_eq(op, "gt")) { if(cmp > 0) { accept = TRUE; } } else if(safe_str_eq(op, "gte")) { if(cmp >= 0) { accept = TRUE; } } return accept; } /* As per the nethack rules: * * moon period = 29.53058 days ~= 30, year = 365.2422 days * days moon phase advances on first day of year compared to preceding year * = 365.2422 - 12*29.53058 ~= 11 * years in Metonic cycle (time until same phases fall on the same days of * the month) = 18.6 ~= 19 * moon phase on first day of year (epact) ~= (11*(year%19) + 29) % 30 * (29 as initial condition) * current phase in days = first day phase + days elapsed in year * 6 moons ~= 177 days * 177 ~= 8 reported phases * 22 * + 11/22 for rounding * * 0-7, with 0: new, 4: full */ static int phase_of_the_moon(ha_time_t *now) { int epact, diy, goldn; diy = now->yeardays; goldn = (now->years % 19) + 1; epact = (11 * goldn + 18) % 30; if ((epact == 25 && goldn > 11) || epact == 24) epact++; return( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 ); } #define cron_check(xml_field, time_field) \ value = crm_element_value(cron_spec, xml_field); \ if(value != NULL) { \ gboolean pass = TRUE; \ decodeNVpair(value, '-', &value_low, &value_high); \ if(value_low == NULL) { \ value_low = crm_strdup(value); \ } \ value_low_i = crm_parse_int(value_low, "0"); \ value_high_i = crm_parse_int(value_high, "-1"); \ if(value_high_i < 0) { \ if(value_low_i != time_field) { \ pass = FALSE; \ } \ } else if(value_low_i > time_field) { \ pass = FALSE; \ } else if(value_high_i < time_field) { \ pass = FALSE; \ } \ crm_free(value_low); \ crm_free(value_high); \ if(pass == FALSE) { \ crm_debug("Condition '%s' in %s: failed", value, xml_field); \ return pass; \ } \ crm_debug("Condition '%s' in %s: passed", value, xml_field); \ } gboolean -cron_range_satisfied(ha_time_t *now, crm_data_t *cron_spec) +cron_range_satisfied(ha_time_t *now, xmlNode *cron_spec) { const char *value = NULL; char *value_low = NULL; char *value_high = NULL; int value_low_i = 0; int value_high_i = 0; CRM_CHECK(now != NULL, return FALSE); cron_check("seconds", now->seconds); cron_check("minutes", now->minutes); cron_check("hours", now->hours); cron_check("monthdays", now->days); cron_check("weekdays", now->weekdays); cron_check("yeardays", now->yeardays); cron_check("weeks", now->weeks); cron_check("months", now->months); cron_check("years", now->years); cron_check("weekyears", now->weekyears); cron_check("moon", phase_of_the_moon(now)); return TRUE; } #define update_field(xml_field, time_fn) \ value = crm_element_value(duration_spec, xml_field); \ if(value != NULL) { \ int value_i = crm_parse_int(value, "0"); \ time_fn(end, value_i); \ } ha_time_t * -parse_xml_duration(ha_time_t *start, crm_data_t *duration_spec) +parse_xml_duration(ha_time_t *start, xmlNode *duration_spec) { ha_time_t *end = NULL; const char *value = NULL; end = new_ha_date(FALSE); ha_set_time(end, start, TRUE); update_field("years", add_years); update_field("months", add_months); update_field("weeks", add_weeks); update_field("days", add_days); update_field("hours", add_hours); update_field("minutes", add_minutes); update_field("seconds", add_seconds); return end; } gboolean -test_date_expression(crm_data_t *time_expr, ha_time_t *now) +test_date_expression(xmlNode *time_expr, ha_time_t *now) { ha_time_t *start = NULL; ha_time_t *end = NULL; const char *value = NULL; char *value_copy = NULL; char *value_copy_start = NULL; const char *op = crm_element_value(time_expr, "operation"); - crm_data_t *duration_spec = NULL; - crm_data_t *date_spec = NULL; + xmlNode *duration_spec = NULL; + xmlNode *date_spec = NULL; gboolean passed = FALSE; crm_debug_2("Testing expression: %s", ID(time_expr)); - duration_spec = cl_get_struct(time_expr, "duration"); - date_spec = cl_get_struct(time_expr, "date_spec"); + duration_spec = first_named_child(time_expr, "duration"); + date_spec = first_named_child(time_expr, "date_spec"); value = crm_element_value(time_expr, "start"); if(value != NULL) { value_copy = crm_strdup(value); value_copy_start = value_copy; start = parse_date(&value_copy); crm_free(value_copy_start); } value = crm_element_value(time_expr, "end"); if(value != NULL) { value_copy = crm_strdup(value); value_copy_start = value_copy; end = parse_date(&value_copy); crm_free(value_copy_start); } if(start != NULL && end == NULL && duration_spec != NULL) { end = parse_xml_duration(start, duration_spec); } if(op == NULL) { op = "in_range"; } if(safe_str_eq(op, "date_spec") || safe_str_eq(op, "in_range")) { if(start != NULL && compare_date(start, now) > 0) { passed = FALSE; } else if(end != NULL && compare_date(end, now) < 0) { passed = FALSE; } else if(safe_str_eq(op, "in_range")) { passed = TRUE; } else { passed = cron_range_satisfied(now, date_spec); } } else if(safe_str_eq(op, "gt") && compare_date(start, now) < 0) { passed = TRUE; } else if(safe_str_eq(op, "lt") && compare_date(end, now) > 0) { passed = TRUE; } else if(safe_str_eq(op, "eq") && compare_date(start, now) == 0) { passed = TRUE; } else if(safe_str_eq(op, "neq") && compare_date(start, now) != 0) { passed = TRUE; } free_ha_date(start); free_ha_date(end); return passed; } typedef struct sorted_set_s { const char *name; const char *special_name; int score; - crm_data_t *attr_set; + xmlNode *attr_set; GHashTable *node_hash; GHashTable *hash; ha_time_t *now; } sorted_set_t; static gint sort_pairs(gconstpointer a, gconstpointer b) { const sorted_set_t *pair_a = a; const sorted_set_t *pair_b = b; if(a == NULL && b == NULL) { return 0; } else if(a == NULL) { return 1; } else if(b == NULL) { return -1; } if(safe_str_eq(pair_a->name, pair_a->special_name)) { return -1; } else if(safe_str_eq(pair_b->name, pair_a->special_name)) { return 1; } if(pair_a->score < pair_b->score) { return 1; } else if(pair_a->score > pair_b->score) { return -1; } return 0; } static void -populate_hash(crm_data_t *nvpair_list, GHashTable *hash) +populate_hash(xmlNode *nvpair_list, GHashTable *hash) { const char *name = NULL; const char *value = NULL; xml_child_iter_filter( nvpair_list, an_attr, XML_CIB_TAG_NVPAIR, name = crm_element_value(an_attr, XML_NVPAIR_ATTR_NAME); crm_debug_4("Setting attribute: %s", name); value = crm_element_value( an_attr, XML_NVPAIR_ATTR_VALUE); if(name == NULL || value == NULL) { continue; } else if(safe_str_eq(value, "#default")) { continue; } else if(g_hash_table_lookup(hash, name) == NULL) { g_hash_table_insert( hash, crm_strdup(name), crm_strdup(value)); } ); } static void unpack_attr_set(gpointer data, gpointer user_data) { sorted_set_t *pair = data; sorted_set_t *unpack_data = user_data; - crm_data_t *attributes = NULL; + xmlNode *attributes = NULL; if(test_ruleset(pair->attr_set, unpack_data->node_hash, unpack_data->now) == FALSE) { return; } crm_debug_3("Adding attributes from %s", pair->name); - attributes = cl_get_struct(pair->attr_set, XML_TAG_ATTRS); + attributes = first_named_child(pair->attr_set, XML_TAG_ATTRS); populate_hash(attributes, unpack_data->hash); } static void free_pair(gpointer data, gpointer user_data) { sorted_set_t *pair = data; crm_free(pair); } void unpack_instance_attributes( - crm_data_t *xml_obj, const char *set_name, GHashTable *node_hash, + xmlNode *xml_obj, const char *set_name, GHashTable *node_hash, GHashTable *hash, const char *always_first, ha_time_t *now) { GListPtr sorted = NULL; const char *score = NULL; sorted_set_t *pair = NULL; if(xml_obj == NULL) { crm_debug_4("No instance attributes"); return; } crm_debug_4("Checking for attributes"); xml_child_iter_filter( xml_obj, attr_set, set_name, pair = NULL; crm_malloc0(pair, sizeof(sorted_set_t)); pair->name = ID(attr_set); pair->special_name = always_first; pair->attr_set = attr_set; score = crm_element_value(attr_set, XML_RULE_ATTR_SCORE); pair->score = char2score(score); sorted = g_list_prepend(sorted, pair); ); if(pair != NULL) { pair->hash = hash; pair->node_hash = node_hash; pair->now = now; } sorted = g_list_sort(sorted, sort_pairs); g_list_foreach(sorted, unpack_attr_set, pair); g_list_foreach(sorted, free_pair, NULL); g_list_free(sorted); } diff --git a/lib/crm/pengine/status.c b/lib/crm/pengine/status.c index b4d6cdd172..cef43669b6 100644 --- a/lib/crm/pengine/status.c +++ b/lib/crm/pengine/status.c @@ -1,316 +1,316 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include -crm_data_t * do_calculations( - pe_working_set_t *data_set, crm_data_t *xml_input, ha_time_t *now); +xmlNode * do_calculations( + pe_working_set_t *data_set, xmlNode *xml_input, ha_time_t *now); -extern crm_data_t*get_object_root( - const char *object_type, crm_data_t *the_root); +extern xmlNode*get_object_root( + const char *object_type, xmlNode *the_root); #define PE_WORKING_DIR HA_VARLIBDIR"/heartbeat/pengine" #define MEMCHECK_STAGE_0 0 #define check_and_exit(stage) cleanup_calculations(data_set); \ crm_mem_stats(NULL); \ crm_err("Exiting: stage %d", stage); \ exit(1); /* * Unpack everything * At the end you'll have: * - A list of nodes * - A list of resources (each with any dependencies on other resources) * - A list of constraints between resources and nodes * - A list of constraints between start/stop actions * - A list of nodes that need to be stonith'd * - A list of nodes that need to be shutdown * - A list of the possible stop/start actions (without dependencies) */ gboolean cluster_status(pe_working_set_t *data_set) { - crm_data_t * config = get_object_root( + xmlNode * config = get_object_root( XML_CIB_TAG_CRMCONFIG, data_set->input); - crm_data_t * cib_nodes = get_object_root( + xmlNode * cib_nodes = get_object_root( XML_CIB_TAG_NODES, data_set->input); - crm_data_t * cib_resources = get_object_root( + xmlNode * cib_resources = get_object_root( XML_CIB_TAG_RESOURCES, data_set->input); - crm_data_t * cib_status = get_object_root( + xmlNode * cib_status = get_object_root( XML_CIB_TAG_STATUS, data_set->input); const char *value = crm_element_value( data_set->input, XML_ATTR_HAVE_QUORUM); crm_debug_3("Beginning unpack"); /* reset remaining global variables */ if(data_set->input == NULL) { return FALSE; } if(data_set->now == NULL) { data_set->now = new_ha_date(TRUE); } if(data_set->input != NULL && crm_element_value(data_set->input, XML_ATTR_DC_UUID) != NULL) { /* this should always be present */ data_set->dc_uuid = crm_element_value_copy( data_set->input, XML_ATTR_DC_UUID); } unpack_config(config, data_set); if(value != NULL) { cl_str_to_boolean(value, &data_set->have_quorum); } if(data_set->have_quorum == FALSE && data_set->no_quorum_policy != no_quorum_ignore) { crm_warn("We do not have quorum" " - fencing and resource management disabled"); } unpack_nodes(cib_nodes, data_set); unpack_resources(cib_resources, data_set); unpack_status(cib_status, data_set); return TRUE; } static 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); } } static void pe_free_actions(GListPtr actions) { GListPtr iterator = actions; while(iterator != NULL) { pe_free_action(iterator->data); iterator = iterator->next; } if(actions != NULL) { g_list_free(actions); } } static 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); pe_free_shallow_adv(details->allocated_rsc, FALSE); crm_free(details); } crm_free(node); } if(nodes != NULL) { g_list_free(nodes); } } void cleanup_calculations(pe_working_set_t *data_set) { if(data_set == NULL) { return; } if(data_set->config_hash != NULL) { g_hash_table_destroy(data_set->config_hash); } crm_free(data_set->dc_uuid); crm_free(data_set->transition_idle_timeout); crm_debug_3("deleting resources"); pe_free_resources(data_set->resources); crm_debug_3("deleting actions"); pe_free_actions(data_set->actions); crm_debug_3("deleting nodes"); pe_free_nodes(data_set->nodes); free_xml(data_set->graph); free_ha_date(data_set->now); free_xml(data_set->input); free_xml(data_set->failed); data_set->stonith_action = NULL; CRM_CHECK(data_set->ordering_constraints == NULL, ;); CRM_CHECK(data_set->placement_constraints == NULL, ;); } void set_working_set_defaults(pe_working_set_t *data_set) { data_set->input = NULL; data_set->now = NULL; data_set->graph = NULL; data_set->failed = create_xml_node(NULL, "failed-ops"); data_set->transition_idle_timeout = NULL; data_set->dc_uuid = NULL; data_set->dc_node = NULL; data_set->have_quorum = FALSE; data_set->stonith_enabled = FALSE; data_set->stonith_action = NULL; data_set->symmetric_cluster = TRUE; data_set->is_managed_default = TRUE; data_set->no_quorum_policy = no_quorum_freeze; data_set->remove_after_stop = FALSE; data_set->stop_action_orphans = TRUE; data_set->stop_rsc_orphans = TRUE; data_set->config_hash = NULL; data_set->nodes = NULL; data_set->resources = NULL; data_set->ordering_constraints = NULL; data_set->placement_constraints = NULL; data_set->colocation_constraints = NULL; data_set->actions = NULL; data_set->num_synapse = 0; data_set->max_valid_nodes = 0; data_set->order_id = 1; data_set->action_id = 1; data_set->default_resource_stickiness = 0; data_set->default_resource_fail_stickiness = 0; } resource_t * pe_find_resource(GListPtr rsc_list, const char *id) { unsigned lpc = 0; resource_t *rsc = NULL; resource_t *child_rsc = NULL; if(id == NULL) { return 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) { } else if(rsc->id && strcmp(rsc->id, id) == 0){ crm_debug_4("Found a match for %s", id); return rsc; } else if(rsc->long_name && strcmp(rsc->long_name, id) == 0) { crm_debug_4("Found a match for %s", id); return rsc; } else if(rsc->clone_name && strcmp(rsc->clone_name, id) == 0) { 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) { return child_rsc; } } crm_debug_2("No match for %s", id); 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; } 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(safe_str_eq(node->details->uname, uname)) { return node; } } /* error */ return NULL; } diff --git a/lib/crm/pengine/unpack.c b/lib/crm/pengine/unpack.c index 2926146297..1bb1daf622 100644 --- a/lib/crm/pengine/unpack.c +++ b/lib/crm/pengine/unpack.c @@ -1,1417 +1,1416 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include /* for ONLINESTATUS */ #include #include #include #include gboolean -unpack_config(crm_data_t *config, pe_working_set_t *data_set) +unpack_config(xmlNode *config, pe_working_set_t *data_set) { const char *name = NULL; const char *value = NULL; GHashTable *config_hash = g_hash_table_new_full( g_str_hash,g_str_equal, g_hash_destroy_str,g_hash_destroy_str); data_set->config_hash = config_hash; unpack_instance_attributes( config, XML_CIB_TAG_PROPSET, NULL, config_hash, CIB_OPTIONS_FIRST, data_set->now); #if CRM_DEPRECATED_SINCE_2_0_1 xml_child_iter_filter( config, a_child, XML_CIB_TAG_NVPAIR, name = crm_element_value(a_child, XML_NVPAIR_ATTR_NAME); value = crm_element_value(a_child, XML_NVPAIR_ATTR_VALUE); if(g_hash_table_lookup(config_hash, name) == NULL) { g_hash_table_insert( config_hash,crm_strdup(name),crm_strdup(value)); } crm_config_err("Creating directly" "beneath has been depreciated since" " 2.0.1", ID(a_child), name); ); #else xml_child_iter_filter( config, a_child, XML_CIB_TAG_NVPAIR, name = crm_element_value(a_child, XML_NVPAIR_ATTR_NAME); crm_config_err("Creating directly" "beneath has been depreciated since" " 2.0.1 and is now disabled", ID(a_child), name); ); #endif verify_pe_options(data_set->config_hash); value = pe_pref(data_set->config_hash, "default-action-timeout"); data_set->transition_idle_timeout = crm_strdup(value); crm_debug("Default action timeout: %s", data_set->transition_idle_timeout); value = pe_pref(data_set->config_hash, "default-resource-stickiness"); data_set->default_resource_stickiness = char2score(value); crm_debug("Default stickiness: %d", data_set->default_resource_stickiness); value = pe_pref(data_set->config_hash, "default-resource-failure-stickiness"); data_set->default_resource_fail_stickiness = char2score(value); crm_debug("Default failure stickiness: %d", data_set->default_resource_fail_stickiness); value = pe_pref(data_set->config_hash, "stonith-enabled"); cl_str_to_boolean(value, &data_set->stonith_enabled); crm_debug("STONITH of failed nodes is %s", data_set->stonith_enabled?"enabled":"disabled"); data_set->stonith_action = pe_pref(data_set->config_hash, "stonith-action"); crm_debug_2("STONITH will %s nodes", data_set->stonith_action); value = pe_pref(data_set->config_hash, "symmetric-cluster"); cl_str_to_boolean(value, &data_set->symmetric_cluster); if(data_set->symmetric_cluster) { crm_debug("Cluster is symmetric" " - resources can run anywhere by default"); } value = pe_pref(data_set->config_hash, "no-quorum-policy"); if(safe_str_eq(value, "ignore")) { data_set->no_quorum_policy = no_quorum_ignore; } else if(safe_str_eq(value, "freeze")) { data_set->no_quorum_policy = no_quorum_freeze; } else { data_set->no_quorum_policy = no_quorum_stop; } switch (data_set->no_quorum_policy) { case no_quorum_freeze: crm_debug("On loss of CCM Quorum: Freeze resources"); break; case no_quorum_stop: crm_debug("On loss of CCM Quorum: Stop ALL resources"); break; case no_quorum_ignore: crm_notice("On loss of CCM Quorum: Ignore"); break; } value = pe_pref(data_set->config_hash, "stop-orphan-resources"); cl_str_to_boolean(value, &data_set->stop_rsc_orphans); crm_debug_2("Orphan resources are %s", data_set->stop_rsc_orphans?"stopped":"ignored"); value = pe_pref(data_set->config_hash, "stop-orphan-actions"); cl_str_to_boolean(value, &data_set->stop_action_orphans); crm_debug_2("Orphan resource actions are %s", data_set->stop_action_orphans?"stopped":"ignored"); value = pe_pref(data_set->config_hash, "remove-after-stop"); cl_str_to_boolean(value, &data_set->remove_after_stop); crm_debug_2("Stopped resources are removed from the status section: %s", data_set->remove_after_stop?"true":"false"); value = pe_pref(data_set->config_hash, "is-managed-default"); cl_str_to_boolean(value, &data_set->is_managed_default); crm_debug_2("By default resources are %smanaged", data_set->is_managed_default?"":"not "); value = pe_pref(data_set->config_hash, "start-failure-is-fatal"); cl_str_to_boolean(value, &data_set->start_failure_fatal); crm_debug_2("Start failures are %s", data_set->start_failure_fatal?"always fatal":"handled by failcount"); return TRUE; } gboolean -unpack_nodes(crm_data_t * xml_nodes, pe_working_set_t *data_set) +unpack_nodes(xmlNode * xml_nodes, pe_working_set_t *data_set) { node_t *new_node = NULL; const char *id = NULL; const char *uname = NULL; const char *type = NULL; gboolean unseen_are_unclean = TRUE; const char *blind_faith = pe_pref( data_set->config_hash, "startup-fencing"); if(crm_is_true(blind_faith) == FALSE) { unseen_are_unclean = FALSE; crm_warn("Blind faith: not fencing unseen nodes"); } xml_child_iter_filter( xml_nodes, xml_obj, XML_CIB_TAG_NODE, new_node = NULL; id = crm_element_value(xml_obj, XML_ATTR_ID); uname = crm_element_value(xml_obj, XML_ATTR_UNAME); type = crm_element_value(xml_obj, XML_ATTR_TYPE); crm_debug_3("Processing node %s/%s", uname, id); if(id == NULL) { crm_config_err("Must specify id tag in "); continue; } if(type == NULL) { crm_config_err("Must specify type tag in "); continue; } if(pe_find_node(data_set->nodes, uname) != NULL) { crm_config_warn("Detected multiple node entries with uname=%s" " - this is rarely intended", uname); } crm_malloc0(new_node, sizeof(node_t)); if(new_node == NULL) { return FALSE; } new_node->weight = 0; new_node->fixed = FALSE; crm_malloc0(new_node->details, sizeof(struct node_shared_s)); if(new_node->details == NULL) { crm_free(new_node); return FALSE; } crm_debug_3("Creaing node for entry %s/%s", uname, id); new_node->details->id = id; new_node->details->uname = uname; new_node->details->type = node_ping; new_node->details->online = FALSE; new_node->details->shutdown = FALSE; new_node->details->running_rsc = NULL; new_node->details->attrs = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); /* if(data_set->have_quorum == FALSE */ /* && data_set->no_quorum_policy == no_quorum_stop) { */ /* /\* start shutting resources down *\/ */ /* new_node->weight = -INFINITY; */ /* } */ if(data_set->stonith_enabled == FALSE || unseen_are_unclean == FALSE) { /* blind faith... */ new_node->details->unclean = FALSE; } else { /* all nodes are unclean until we've seen their * status entry */ new_node->details->unclean = TRUE; } if(type == NULL || safe_str_eq(type, "member") || safe_str_eq(type, NORMALNODE)) { new_node->details->type = node_member; } add_node_attrs(xml_obj, new_node, data_set); if(crm_is_true(g_hash_table_lookup( new_node->details->attrs, "standby"))) { crm_info("Node %s is in standby-mode", new_node->details->uname); new_node->weight = -INFINITY; new_node->details->standby = TRUE; } data_set->nodes = g_list_append(data_set->nodes, new_node); crm_debug_3("Done with node %s", crm_element_value(xml_obj, XML_ATTR_UNAME)); ); return TRUE; } gboolean -unpack_resources(crm_data_t * xml_resources, pe_working_set_t *data_set) +unpack_resources(xmlNode * xml_resources, pe_working_set_t *data_set) { xml_child_iter( xml_resources, xml_obj, resource_t *new_rsc = NULL; crm_debug_3("Begining unpack... %s", xml_obj?crm_element_name(xml_obj):""); if(common_unpack(xml_obj, &new_rsc, NULL, data_set)) { data_set->resources = g_list_append( data_set->resources, new_rsc); print_resource(LOG_DEBUG_3, "Added", new_rsc, FALSE); } else { crm_config_err("Failed unpacking %s %s", crm_element_name(xml_obj), crm_element_value(xml_obj, XML_ATTR_ID)); if(new_rsc != NULL && new_rsc->fns != NULL) { new_rsc->fns->free(new_rsc); } } ); data_set->resources = g_list_sort( data_set->resources, sort_rsc_priority); return TRUE; } /* remove nodes that are down, stopping */ /* create +ve rsc_to_node constraints between resources and the nodes they are running on */ /* anything else? */ gboolean -unpack_status(crm_data_t * status, pe_working_set_t *data_set) +unpack_status(xmlNode * status, pe_working_set_t *data_set) { const char *id = NULL; const char *uname = NULL; - crm_data_t * lrm_rsc = NULL; - crm_data_t * attrs = NULL; + xmlNode * lrm_rsc = NULL; + xmlNode * attrs = NULL; node_t *this_node = NULL; crm_debug_3("Begining unpack"); xml_child_iter_filter( status, node_state, XML_CIB_TAG_STATE, id = crm_element_value(node_state, XML_ATTR_ID); uname = crm_element_value(node_state, XML_ATTR_UNAME); attrs = find_xml_node( node_state, XML_TAG_TRANSIENT_NODEATTRS, FALSE); lrm_rsc = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE); lrm_rsc = find_xml_node(lrm_rsc, XML_LRM_TAG_RESOURCES, FALSE); crm_debug_3("Processing node %s", uname); this_node = pe_find_node_id(data_set->nodes, id); if(uname == NULL) { /* error */ continue; } else if(this_node == NULL) { crm_config_warn("Node %s in status section no longer exists", uname); continue; } /* Mark the node as provisionally clean * - at least we have seen it in the current cluster's lifetime */ this_node->details->unclean = FALSE; crm_debug_3("Adding runtime node attrs"); add_node_attrs(attrs, this_node, data_set); crm_debug_3("determining node state"); determine_online_status(node_state, this_node, data_set); if(this_node->details->online || data_set->stonith_enabled) { /* offline nodes run no resources... * unless stonith is enabled in which case we need to * make sure rsc start events happen after the stonith */ crm_debug_3("Processing lrm resource entries"); unpack_lrm_resources(this_node, lrm_rsc, data_set); } ); return TRUE; } static gboolean -determine_online_status_no_fencing(crm_data_t * node_state, node_t *this_node) +determine_online_status_no_fencing(xmlNode * node_state, node_t *this_node) { gboolean online = FALSE; const char *join_state = crm_element_value(node_state, XML_CIB_ATTR_JOINSTATE); const char *crm_state = crm_element_value(node_state, XML_CIB_ATTR_CRMDSTATE); const char *ccm_state = crm_element_value(node_state, XML_CIB_ATTR_INCCM); const char *ha_state = crm_element_value(node_state, XML_CIB_ATTR_HASTATE); const char *exp_state = crm_element_value(node_state, XML_CIB_ATTR_EXPSTATE); if(ha_state == NULL) { ha_state = DEADSTATUS; } if(!crm_is_true(ccm_state) || safe_str_eq(ha_state, DEADSTATUS)){ crm_debug_2("Node is down: ha_state=%s, ccm_state=%s", crm_str(ha_state), crm_str(ccm_state)); } else if(!crm_is_true(ccm_state) || safe_str_eq(ha_state, DEADSTATUS)) { } else if(safe_str_eq(crm_state, ONLINESTATUS)) { if(safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER)) { online = TRUE; } else { crm_debug("Node is not ready to run resources: %s", join_state); } } else if(this_node->details->expected_up == FALSE) { crm_debug_2("CRMd is down: ha_state=%s, ccm_state=%s", crm_str(ha_state), crm_str(ccm_state)); crm_debug_2("\tcrm_state=%s, join_state=%s, expected=%s", crm_str(crm_state), crm_str(join_state), crm_str(exp_state)); } else { /* mark it unclean */ this_node->details->unclean = TRUE; crm_warn("Node %s is partially & un-expectedly down", this_node->details->uname); crm_info("\tha_state=%s, ccm_state=%s," " crm_state=%s, join_state=%s, expected=%s", crm_str(ha_state), crm_str(ccm_state), crm_str(crm_state), crm_str(join_state), crm_str(exp_state)); } return online; } static gboolean -determine_online_status_fencing(crm_data_t * node_state, node_t *this_node) +determine_online_status_fencing(xmlNode * node_state, node_t *this_node) { gboolean online = FALSE; const char *join_state = crm_element_value(node_state, XML_CIB_ATTR_JOINSTATE); const char *crm_state = crm_element_value(node_state, XML_CIB_ATTR_CRMDSTATE); const char *ccm_state = crm_element_value(node_state, XML_CIB_ATTR_INCCM); const char *ha_state = crm_element_value(node_state, XML_CIB_ATTR_HASTATE); const char *exp_state = crm_element_value(node_state, XML_CIB_ATTR_EXPSTATE); if(ha_state == NULL) { ha_state = DEADSTATUS; } if(crm_is_true(ccm_state) && safe_str_eq(ha_state, ACTIVESTATUS) && safe_str_eq(crm_state, ONLINESTATUS)) { online = TRUE; if(safe_str_neq(join_state, CRMD_JOINSTATE_MEMBER)) { crm_info("Node %s is not ready to run resources", this_node->details->uname); this_node->details->standby = TRUE; } } else if(crm_is_true(ccm_state) == FALSE && safe_str_eq(ha_state, DEADSTATUS) && safe_str_eq(crm_state, OFFLINESTATUS) && this_node->details->expected_up == FALSE) { crm_debug("Node %s is down: join_state=%s, expected=%s", this_node->details->uname, crm_str(join_state), crm_str(exp_state)); } else if(this_node->details->expected_up) { /* mark it unclean */ this_node->details->unclean = TRUE; crm_warn("Node %s (%s) is un-expectedly down", this_node->details->uname, this_node->details->id); crm_info("\tha_state=%s, ccm_state=%s," " crm_state=%s, join_state=%s, expected=%s", crm_str(ha_state), crm_str(ccm_state), crm_str(crm_state), crm_str(join_state), crm_str(exp_state)); } else { crm_info("Node %s is comming up", this_node->details->uname); crm_debug("\tha_state=%s, ccm_state=%s," " crm_state=%s, join_state=%s, expected=%s", crm_str(ha_state), crm_str(ccm_state), crm_str(crm_state), crm_str(join_state), crm_str(exp_state)); } return online; } gboolean determine_online_status( - crm_data_t * node_state, node_t *this_node, pe_working_set_t *data_set) + xmlNode * node_state, node_t *this_node, pe_working_set_t *data_set) { - int shutdown = 0; gboolean online = FALSE; - const char *exp_state = - crm_element_value(node_state, XML_CIB_ATTR_EXPSTATE); + const char *shutdown = crm_element_value(node_state, XML_CIB_ATTR_SHUTDOWN); + const char *exp_state = crm_element_value(node_state, XML_CIB_ATTR_EXPSTATE); if(this_node == NULL) { crm_config_err("No node to check"); return online; } - ha_msg_value_int(node_state, XML_CIB_ATTR_SHUTDOWN, &shutdown); + shutdown = crm_element_value(node_state, XML_CIB_ATTR_SHUTDOWN); this_node->details->expected_up = FALSE; if(safe_str_eq(exp_state, CRMD_JOINSTATE_MEMBER)) { this_node->details->expected_up = TRUE; } this_node->details->shutdown = FALSE; - if(shutdown != 0) { + if(shutdown != NULL && safe_str_neq("0", shutdown)) { this_node->details->shutdown = TRUE; this_node->details->expected_up = FALSE; } if(data_set->stonith_enabled == FALSE) { online = determine_online_status_no_fencing( node_state, this_node); } else { online = determine_online_status_fencing( node_state, this_node); } if(online) { this_node->details->online = TRUE; } else { /* remove node from contention */ this_node->fixed = TRUE; this_node->weight = -INFINITY; } if(online && this_node->details->shutdown) { /* dont run resources here */ this_node->fixed = TRUE; this_node->weight = -INFINITY; } if(this_node->details->unclean) { pe_proc_warn("Node %s is unclean", this_node->details->uname); } else if(this_node->details->online) { crm_info("Node %s is %s", this_node->details->uname, this_node->details->shutdown?"shutting down": this_node->details->standby?"standby":"online"); } else { crm_debug_2("Node %s is offline", this_node->details->uname); } return online; } #define set_char(x) last_rsc_id[lpc] = x; complete = TRUE; static char * increment_clone(char *last_rsc_id) { int lpc = 0; int len = 0; char *tmp = NULL; gboolean complete = FALSE; CRM_CHECK(last_rsc_id != NULL, return NULL); if(last_rsc_id != NULL) { len = strlen(last_rsc_id); } lpc = len-1; while(complete == FALSE && lpc > 0) { switch (last_rsc_id[lpc]) { case 0: lpc--; break; case '0': set_char('1'); break; case '1': set_char('2'); break; case '2': set_char('3'); break; case '3': set_char('4'); break; case '4': set_char('5'); break; case '5': set_char('6'); break; case '6': set_char('7'); break; case '7': set_char('8'); break; case '8': set_char('9'); break; case '9': last_rsc_id[lpc] = '0'; lpc--; break; case ':': tmp = last_rsc_id; crm_malloc0(last_rsc_id, len + 2); memcpy(last_rsc_id, tmp, len); last_rsc_id[++lpc] = '1'; last_rsc_id[len] = '0'; last_rsc_id[len+1] = 0; complete = TRUE; crm_free(tmp); break; default: crm_err("Unexpected char: %c (%d)", last_rsc_id[lpc], lpc); break; } } return last_rsc_id; } static resource_t * -create_fake_resource(const char *rsc_id, crm_data_t *rsc_entry, pe_working_set_t *data_set) +create_fake_resource(const char *rsc_id, xmlNode *rsc_entry, pe_working_set_t *data_set) { resource_t *rsc = NULL; - crm_data_t *xml_rsc = create_xml_node(NULL, XML_CIB_TAG_RESOURCE); + xmlNode *xml_rsc = create_xml_node(NULL, XML_CIB_TAG_RESOURCE); copy_in_properties(xml_rsc, rsc_entry); crm_xml_add(xml_rsc, XML_ATTR_ID, rsc_id); crm_log_xml_info(xml_rsc, "Orphan resource"); common_unpack(xml_rsc, &rsc, NULL, data_set); set_bit(rsc->flags, pe_rsc_orphan); data_set->resources = g_list_append(data_set->resources, rsc); return rsc; } static resource_t * unpack_find_resource( - pe_working_set_t *data_set, node_t *node, const char *rsc_id, crm_data_t *rsc_entry) + pe_working_set_t *data_set, node_t *node, const char *rsc_id, xmlNode *rsc_entry) { resource_t *rsc = NULL; gboolean is_duped_clone = FALSE; char *alt_rsc_id = crm_strdup(rsc_id); while(rsc == NULL) { crm_debug_3("looking for: %s", alt_rsc_id); rsc = pe_find_resource(data_set->resources, alt_rsc_id); /* no match */ if(rsc == NULL) { crm_debug_2("%s not found: %d", alt_rsc_id, is_duped_clone); if(is_duped_clone) { /* create one */ rsc = create_fake_resource(alt_rsc_id, rsc_entry, data_set); crm_info("Making sure orphan %s/%s is stopped on %s", rsc_id, rsc->id, node->details->uname); resource_location(rsc, NULL, -INFINITY, "__orphan_clone_dont_run__", data_set); } break; /* not running anywhere else */ } else if(rsc->running_on == NULL) { crm_debug_3("not active yet"); break; /* always unique */ } else if(is_set(rsc->flags, pe_rsc_unique)) { crm_debug_3("unique"); break; /* running somewhere already but we dont care * find another clone instead */ } else { crm_debug_3("find another one"); rsc = NULL; is_duped_clone = TRUE; alt_rsc_id = increment_clone(alt_rsc_id); } } crm_free(alt_rsc_id); if(rsc != NULL) { crm_free(rsc->clone_name); rsc->clone_name = NULL; if(is_duped_clone) { crm_info("Internally renamed %s on %s to %s", rsc_id, node->details->uname, rsc->id); rsc->clone_name = crm_strdup(rsc_id); } } return rsc; } static resource_t * -process_orphan_resource(crm_data_t *rsc_entry, node_t *node, pe_working_set_t *data_set) +process_orphan_resource(xmlNode *rsc_entry, node_t *node, pe_working_set_t *data_set) { resource_t *rsc = NULL; const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID); crm_log_xml_info(rsc_entry, "Orphan resource"); crm_config_warn("Nothing known about resource %s running on %s", rsc_id, node->details->uname); rsc = create_fake_resource(rsc_id, rsc_entry, data_set); if(data_set->stop_rsc_orphans == FALSE) { clear_bit(rsc->flags, pe_rsc_managed); } else { crm_info("Making sure orphan %s is stopped", rsc_id); print_resource(LOG_DEBUG_3, "Added orphan", rsc, FALSE); CRM_CHECK(rsc != NULL, return NULL); resource_location(rsc, NULL, -INFINITY, "__orphan_dont_run__", data_set); } return rsc; } static void process_rsc_state(resource_t *rsc, node_t *node, enum action_fail_response on_fail, - crm_data_t *migrate_op, + xmlNode *migrate_op, pe_working_set_t *data_set) { if(on_fail == action_migrate_failure) { node_t *from = NULL; const char *uuid = NULL; uuid = crm_element_value(migrate_op, CRMD_ACTION_MIGRATED); from = pe_find_node_id(data_set->nodes, uuid); process_rsc_state(rsc, from, action_fail_recover,NULL,data_set); on_fail = action_fail_recover; } crm_debug_2("Resource %s is %s on %s", rsc->id, role2text(rsc->role), node->details->uname); /* process current state */ if(rsc->role != RSC_ROLE_UNKNOWN) { rsc->known_on = g_list_append(rsc->known_on, node); } if(rsc->role != RSC_ROLE_STOPPED && rsc->role != RSC_ROLE_UNKNOWN) { if(on_fail != action_fail_ignore) { set_bit(rsc->flags, pe_rsc_failed); crm_debug_2("Force stop"); } native_add_running(rsc, node, data_set); if(is_set(rsc->flags, pe_rsc_managed) && rsc->stickiness != 0) { resource_location(rsc, node, rsc->stickiness, "stickiness", data_set); crm_debug_2("Resource %s: preferring current location" " (node=%s, weight=%d)", rsc->id, node->details->uname, rsc->stickiness); } if(on_fail == action_fail_ignore) { /* nothing to do */ } else if(node->details->unclean) { stop_action(rsc, node, FALSE); } else if(on_fail == action_fail_fence) { /* treat it as if it is still running * but also mark the node as unclean */ node->details->unclean = TRUE; stop_action(rsc, node, FALSE); } else if(on_fail == action_fail_block) { /* is_managed == FALSE will prevent any * actions being sent for the resource */ clear_bit(rsc->flags, pe_rsc_managed); } else if(on_fail == action_fail_migrate) { stop_action(rsc, node, FALSE); /* make sure it comes up somewhere else * or not at all */ resource_location(rsc, node, -INFINITY, "__action_migration_auto__",data_set); } else { stop_action(rsc, node, FALSE); } } else if(rsc->clone_name) { crm_debug_2("Resetting clone_name %s for %s (stopped)", rsc->clone_name, rsc->id); crm_free(rsc->clone_name); rsc->clone_name = NULL; } else { char *key = stop_key(rsc); GListPtr possible_matches = find_actions(rsc->actions, key, node); slist_iter(stop, action_t, possible_matches, lpc, stop->optional = TRUE; ); crm_free(key); } } /* create active recurring operations as optional */ static void process_recurring(node_t *node, resource_t *rsc, int start_index, int stop_index, GListPtr sorted_op_list, pe_working_set_t *data_set) { const char *task = NULL; const char *status = NULL; crm_debug_3("%s: Start index %d, stop index = %d", rsc->id, start_index, stop_index); - slist_iter(rsc_op, crm_data_t, sorted_op_list, lpc, + slist_iter(rsc_op, xmlNode, sorted_op_list, lpc, int interval = 0; char *key = NULL; const char *id = ID(rsc_op); const char *interval_s = NULL; if(node->details->online == FALSE) { crm_debug_4("Skipping %s/%s: node is offline", rsc->id, node->details->uname); break; } else if(start_index < stop_index) { crm_debug_4("Skipping %s/%s: not active", rsc->id, node->details->uname); break; } else if(lpc <= start_index) { crm_debug_4("Skipping %s/%s: old", id, node->details->uname); continue; } interval_s = crm_element_value(rsc_op,XML_LRM_ATTR_INTERVAL); interval = crm_parse_int(interval_s, "0"); if(interval == 0) { crm_debug_4("Skipping %s/%s: non-recurring", id, node->details->uname); continue; } status = crm_element_value(rsc_op, XML_LRM_ATTR_OPSTATUS); if(safe_str_eq(status, "-1")) { crm_debug_4("Skipping %s/%s: status", id, node->details->uname); continue; } task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); /* create the action */ key = generate_op_key(rsc->id, task, interval); crm_debug_3("Creating %s/%s", key, node->details->uname); custom_action(rsc, key, task, node, TRUE, TRUE, data_set); ); } void calculate_active_ops(GListPtr sorted_op_list, int *start_index, int *stop_index) { const char *task = NULL; const char *status = NULL; *stop_index = -1; *start_index = -1; slist_iter( - rsc_op, crm_data_t, sorted_op_list, lpc, + rsc_op, xmlNode, sorted_op_list, lpc, task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); status = crm_element_value(rsc_op, XML_LRM_ATTR_OPSTATUS); if(safe_str_eq(task, CRMD_ACTION_STOP) && safe_str_eq(status, "0")) { *stop_index = lpc; } else if(safe_str_eq(task, CRMD_ACTION_START)) { *start_index = lpc; } else if(*start_index <= *stop_index && safe_str_eq(task, CRMD_ACTION_STATUS)) { const char *rc = crm_element_value(rsc_op, XML_LRM_ATTR_RC); if(safe_str_eq(rc, "0") || safe_str_eq(rc, "8")) { *start_index = lpc; } } ); } static void unpack_lrm_rsc_state( - node_t *node, crm_data_t * rsc_entry, pe_working_set_t *data_set) + node_t *node, xmlNode * rsc_entry, pe_working_set_t *data_set) { int stop_index = -1; int start_index = -1; int max_call_id = -1; const char *task = NULL; const char *value = NULL; const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID); resource_t *rsc = NULL; GListPtr op_list = NULL; GListPtr sorted_op_list = NULL; - crm_data_t *migrate_op = NULL; + xmlNode *migrate_op = NULL; enum action_fail_response on_fail = FALSE; enum rsc_role_e saved_role = RSC_ROLE_UNKNOWN; crm_debug_3("[%s] Processing %s on %s", crm_element_name(rsc_entry), rsc_id, node->details->uname); /* extract operations */ op_list = NULL; sorted_op_list = NULL; xml_child_iter_filter( rsc_entry, rsc_op, XML_LRM_TAG_RSC_OP, op_list = g_list_append(op_list, rsc_op); ); if(op_list == NULL) { /* if there are no operations, there is nothing to do */ return; } /* find the resource */ rsc = unpack_find_resource(data_set, node, rsc_id, rsc_entry); if(rsc == NULL) { rsc = process_orphan_resource(rsc_entry, node, data_set); } CRM_ASSERT(rsc != NULL); /* process operations */ max_call_id = -1; saved_role = rsc->role; on_fail = action_fail_ignore; rsc->role = RSC_ROLE_UNKNOWN; sorted_op_list = g_list_sort(op_list, sort_op_by_callid); slist_iter( - rsc_op, crm_data_t, sorted_op_list, lpc, + rsc_op, xmlNode, sorted_op_list, lpc, task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); if(safe_str_eq(task, CRMD_ACTION_MIGRATED)) { migrate_op = rsc_op; } unpack_rsc_op(rsc, node, rsc_op, &max_call_id, &on_fail, data_set); ); /* create active recurring operations as optional */ calculate_active_ops(sorted_op_list, &start_index, &stop_index); process_recurring(node, rsc, start_index, stop_index, sorted_op_list, data_set); /* no need to free the contents */ g_list_free(sorted_op_list); process_rsc_state(rsc, node, on_fail, migrate_op, data_set); value = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE); if(value != NULL && safe_str_neq("default", value)) { enum rsc_role_e req_role = text2role(value); if(req_role != RSC_ROLE_UNKNOWN && req_role != rsc->next_role){ if(rsc->next_role != RSC_ROLE_UNKNOWN) { crm_debug("%s: Overwriting calculated next role %s" " with requested next role %s", rsc->id, role2text(rsc->next_role), role2text(req_role)); } rsc->next_role = req_role; } } if(saved_role > rsc->role) { rsc->role = saved_role; } } gboolean -unpack_lrm_resources(node_t *node, crm_data_t * lrm_rsc_list, pe_working_set_t *data_set) +unpack_lrm_resources(node_t *node, xmlNode * lrm_rsc_list, pe_working_set_t *data_set) { CRM_CHECK(node != NULL, return FALSE); crm_debug_3("Unpacking resources on %s", node->details->uname); slist_iter( rsc, resource_t, data_set->resources, lpc, common_apply_stickiness(rsc, node, data_set); ); xml_child_iter_filter( lrm_rsc_list, rsc_entry, XML_LRM_TAG_RESOURCE, unpack_lrm_rsc_state(node, rsc_entry, data_set); ); return TRUE; } gboolean -unpack_rsc_op(resource_t *rsc, node_t *node, crm_data_t *xml_op, +unpack_rsc_op(resource_t *rsc, node_t *node, xmlNode *xml_op, int *max_call_id, enum action_fail_response *on_fail, pe_working_set_t *data_set) { const char *id = NULL; const char *task = NULL; const char *task_id = NULL; const char *actual_rc = NULL; /* const char *target_rc = NULL; */ const char *task_status = NULL; const char *interval_s = NULL; const char *op_digest = NULL; const char *op_version = NULL; int interval = 0; int task_id_i = -1; int task_status_i = -2; int actual_rc_i = 0; action_t *action = NULL; node_t *effective_node = NULL; gboolean is_probe = FALSE; gboolean is_stop_action = FALSE; CRM_CHECK(rsc != NULL, return FALSE); CRM_CHECK(node != NULL, return FALSE); CRM_CHECK(xml_op != NULL, return FALSE); id = ID(xml_op); task = crm_element_value(xml_op, XML_LRM_ATTR_TASK); task_id = crm_element_value(xml_op, XML_LRM_ATTR_CALLID); task_status = crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS); op_digest = crm_element_value(xml_op, XML_LRM_ATTR_OP_DIGEST); op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION); CRM_CHECK(id != NULL, return FALSE); CRM_CHECK(task != NULL, return FALSE); CRM_CHECK(task_status != NULL, return FALSE); task_status_i = crm_parse_int(task_status, NULL); CRM_CHECK(task_status_i <= LRM_OP_ERROR, return FALSE); CRM_CHECK(task_status_i >= LRM_OP_PENDING, return FALSE); if(safe_str_eq(task, CRMD_ACTION_NOTIFY)) { /* safe to ignore these */ return TRUE; } crm_debug_2("Unpacking task %s/%s (call_id=%s, status=%s) on %s (role=%s)", id, task, task_id, task_status, node->details->uname, role2text(rsc->role)); interval_s = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL); interval = crm_parse_int(interval_s, "0"); if(interval == 0 && safe_str_eq(task, CRMD_ACTION_STATUS)) { is_probe = TRUE; } if(safe_str_eq(task, CRMD_ACTION_STOP)) { is_stop_action = TRUE; } if(task_status_i != LRM_OP_PENDING) { task_id_i = crm_parse_int(task_id, "-1"); CRM_CHECK(task_id != NULL, return FALSE); CRM_CHECK(task_id_i >= 0, return FALSE); CRM_CHECK(task_id_i > *max_call_id, return FALSE); } if(*max_call_id < task_id_i) { *max_call_id = task_id_i; } if(node->details->unclean) { crm_debug_2("Node %s (where %s is running) is unclean." " Further action depends on the value of %s", node->details->uname, rsc->id, XML_RSC_ATTR_STOPFAIL); } actual_rc = crm_element_value(xml_op, XML_LRM_ATTR_RC); CRM_CHECK(actual_rc != NULL, return FALSE); actual_rc_i = crm_parse_int(actual_rc, NULL); if(task_status_i == LRM_OP_NOTSUPPORTED) { actual_rc_i = EXECRA_UNIMPLEMENT_FEATURE; } switch(actual_rc_i) { case EXECRA_NOT_RUNNING: if(is_probe) { /* treat these like stops */ is_stop_action = TRUE; } if(is_stop_action) { task_status_i = LRM_OP_DONE; } else { task_status_i = LRM_OP_ERROR; } break; case EXECRA_RUNNING_MASTER: if(is_probe || (rsc->role == RSC_ROLE_MASTER && safe_str_eq(task, CRMD_ACTION_STATUS))) { task_status_i = LRM_OP_DONE; } else { task_status_i = LRM_OP_ERROR; if(rsc->role != RSC_ROLE_MASTER) { crm_err("%s reported %s in master mode on %s", id, rsc->id, node->details->uname); } } rsc->role = RSC_ROLE_MASTER; break; case EXECRA_FAILED_MASTER: rsc->role = RSC_ROLE_MASTER; task_status_i = LRM_OP_ERROR; break; case EXECRA_UNIMPLEMENT_FEATURE: if(interval > 0) { task_status_i = LRM_OP_ERROR; break; } /* else: fall through */ case EXECRA_INSUFFICIENT_PRIV: case EXECRA_NOT_INSTALLED: effective_node = node; /* fall through */ case EXECRA_NOT_CONFIGURED: case EXECRA_INVALID_PARAM: crm_err("Hard error: %s failed with rc=%d.", id, actual_rc_i); if(effective_node) { crm_err(" Preventing %s from re-starting on %s", rsc->id, effective_node->details->uname); } else { crm_err(" Preventing %s from re-starting anywhere in the cluster", rsc->id); } resource_location(rsc, effective_node, -INFINITY, "hard-error", data_set); if(is_probe) { /* treat these like stops */ is_stop_action = TRUE; task_status_i = LRM_OP_DONE; actual_rc_i = EXECRA_NOT_RUNNING; } else { task_status_i = LRM_OP_ERROR; } break; case EXECRA_OK: if(interval > 0 && rsc->role == RSC_ROLE_MASTER) { /* catch status ops that return 0 instead of 8 while they * are supposed to be in master mode */ task_status_i = LRM_OP_ERROR; } break; default: if(task_status_i == LRM_OP_DONE) { crm_err("Remapping %s (rc=%d) on %s to an ERROR", id, actual_rc_i, node->details->uname); task_status_i = LRM_OP_ERROR; } } if(task_status_i == LRM_OP_ERROR || task_status_i == LRM_OP_TIMEOUT || task_status_i == LRM_OP_NOTSUPPORTED) { action = custom_action(rsc, crm_strdup(id), task, NULL, TRUE, FALSE, data_set); if(action->on_fail == action_fail_ignore) { task_status_i = LRM_OP_DONE; } } switch(task_status_i) { case LRM_OP_PENDING: if(safe_str_eq(task, CRMD_ACTION_START)) { set_bit(rsc->flags, pe_rsc_start_pending); rsc->role = RSC_ROLE_STARTED; } else if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) { rsc->role = RSC_ROLE_MASTER; } break; case LRM_OP_DONE: crm_debug_3("%s/%s completed on %s", rsc->id, task, node->details->uname); if(is_stop_action) { rsc->role = RSC_ROLE_STOPPED; /* clear any previous failure actions */ *on_fail = action_fail_ignore; rsc->next_role = RSC_ROLE_UNKNOWN; } else if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) { rsc->role = RSC_ROLE_MASTER; } else if(safe_str_eq(task, CRMD_ACTION_DEMOTE)) { rsc->role = RSC_ROLE_SLAVE; } else if(rsc->role < RSC_ROLE_STARTED) { crm_debug_3("%s active on %s", rsc->id, node->details->uname); rsc->role = RSC_ROLE_STARTED; } break; case LRM_OP_ERROR: case LRM_OP_TIMEOUT: case LRM_OP_NOTSUPPORTED: crm_warn("Processing failed op %s on %s: %s", id, node->details->uname, op_status2text(task_status_i)); crm_xml_add(xml_op, XML_ATTR_UNAME, node->details->uname); add_node_copy(data_set->failed, xml_op); if(*on_fail < action->on_fail) { *on_fail = action->on_fail; } if(is_stop_action) { resource_location( rsc, node, -INFINITY, "__stop_fail__", data_set); } else if((data_set->start_failure_fatal || compare_version("2.0", op_version)) && safe_str_eq(task, CRMD_ACTION_START)) { crm_warn("Compatability handling for failed op %s on %s", id, node->details->uname); resource_location( rsc, node, -INFINITY, "__legacy_start__", data_set); } if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) { rsc->role = RSC_ROLE_MASTER; } else if(safe_str_eq(task, CRMD_ACTION_DEMOTE)) { rsc->role = RSC_ROLE_MASTER; } else if(rsc->role < RSC_ROLE_STARTED) { rsc->role = RSC_ROLE_STARTED; } crm_debug_2("Resource %s: role=%s, unclean=%s, on_fail=%s, fail_role=%s", rsc->id, role2text(rsc->role), node->details->unclean?"true":"false", fail2text(action->on_fail), role2text(action->fail_role)); if(action->fail_role != RSC_ROLE_STARTED && rsc->next_role < action->fail_role) { rsc->next_role = action->fail_role; } if(action->fail_role == RSC_ROLE_STOPPED) { crm_err("Making sure %s doesn't come up again", rsc->id); /* make sure it doesnt come up again */ pe_free_shallow_adv(rsc->allowed_nodes, TRUE); rsc->allowed_nodes = node_list_dup( data_set->nodes, FALSE, FALSE); slist_iter( node, node_t, rsc->allowed_nodes, lpc, node->weight = -INFINITY; ); } pe_free_action(action); action = NULL; break; case LRM_OP_CANCELLED: /* do nothing?? */ pe_err("Dont know what to do for cancelled ops yet"); break; } crm_debug_3("Resource %s after %s: role=%s", rsc->id, task, role2text(rsc->role)); pe_free_action(action); return TRUE; } gboolean -add_node_attrs(crm_data_t *xml_obj, node_t *node, pe_working_set_t *data_set) +add_node_attrs(xmlNode *xml_obj, node_t *node, pe_working_set_t *data_set) { g_hash_table_insert(node->details->attrs, crm_strdup("#"XML_ATTR_UNAME), crm_strdup(node->details->uname)); g_hash_table_insert(node->details->attrs, crm_strdup("#"XML_ATTR_ID), crm_strdup(node->details->id)); if(safe_str_eq(node->details->id, data_set->dc_uuid)) { data_set->dc_node = node; node->details->is_dc = TRUE; g_hash_table_insert(node->details->attrs, crm_strdup("#"XML_ATTR_DC), crm_strdup(XML_BOOLEAN_TRUE)); } else { g_hash_table_insert(node->details->attrs, crm_strdup("#"XML_ATTR_DC), crm_strdup(XML_BOOLEAN_FALSE)); } unpack_instance_attributes( xml_obj, XML_TAG_ATTR_SETS, NULL, node->details->attrs, NULL, data_set->now); return TRUE; } static GListPtr -extract_operations(const char *node, const char *rsc, crm_data_t *rsc_entry, gboolean active_filter) +extract_operations(const char *node, const char *rsc, xmlNode *rsc_entry, gboolean active_filter) { int stop_index = -1; int start_index = -1; GListPtr op_list = NULL; GListPtr sorted_op_list = NULL; /* extract operations */ op_list = NULL; sorted_op_list = NULL; xml_child_iter_filter( rsc_entry, rsc_op, XML_LRM_TAG_RSC_OP, crm_xml_add(rsc_op, "resource", rsc); crm_xml_add(rsc_op, XML_ATTR_UNAME, node); op_list = g_list_append(op_list, rsc_op); ); if(op_list == NULL) { /* if there are no operations, there is nothing to do */ return NULL; } sorted_op_list = g_list_sort(op_list, sort_op_by_callid); /* create active recurring operations as optional */ if(active_filter == FALSE) { return sorted_op_list; } op_list = NULL; calculate_active_ops(sorted_op_list, &start_index, &stop_index); - slist_iter(rsc_op, crm_data_t, sorted_op_list, lpc, + slist_iter(rsc_op, xmlNode, sorted_op_list, lpc, if(start_index < stop_index) { crm_debug_4("Skipping %s: not active", ID(rsc_entry)); break; } else if(lpc < start_index) { crm_debug_4("Skipping %s: old", ID(rsc_op)); continue; } op_list = g_list_append(op_list, rsc_op); ); g_list_free(sorted_op_list); return op_list; } GListPtr find_operations( const char *rsc, const char *node, gboolean active_filter, pe_working_set_t *data_set) { GListPtr output = NULL; GListPtr intermediate = NULL; - crm_data_t *tmp = NULL; - crm_data_t *status = find_xml_node(data_set->input, XML_CIB_TAG_STATUS, TRUE); + xmlNode *tmp = NULL; + xmlNode *status = find_xml_node(data_set->input, XML_CIB_TAG_STATUS, TRUE); const char *uname = NULL; node_t *this_node = NULL; xml_child_iter_filter( status, node_state, XML_CIB_TAG_STATE, uname = crm_element_value(node_state, XML_ATTR_UNAME); if(node != NULL && safe_str_neq(uname, node)) { continue; } this_node = pe_find_node(data_set->nodes, uname); CRM_CHECK(this_node != NULL, continue); determine_online_status(node_state, this_node, data_set); if(this_node->details->online || data_set->stonith_enabled) { /* offline nodes run no resources... * unless stonith is enabled in which case we need to * make sure rsc start events happen after the stonith */ tmp = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE); tmp = find_xml_node(tmp, XML_LRM_TAG_RESOURCES, FALSE); xml_child_iter_filter( tmp, lrm_rsc, XML_LRM_TAG_RESOURCE, const char *rsc_id = crm_element_value(lrm_rsc, XML_ATTR_ID); if(rsc != NULL && safe_str_neq(rsc_id, rsc)) { continue; } intermediate = extract_operations(uname, rsc_id, lrm_rsc, active_filter); output = g_list_concat(output, intermediate); ); } ); return output; } diff --git a/lib/crm/pengine/unpack.h b/lib/crm/pengine/unpack.h index 4b47d27126..33b1f56a5e 100644 --- a/lib/crm/pengine/unpack.h +++ b/lib/crm/pengine/unpack.h @@ -1,96 +1,96 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 PENGINE_UNPACK__H #define PENGINE_UNPACK__H extern gboolean unpack_resources( - crm_data_t *xml_resources, pe_working_set_t *data_set); + xmlNode *xml_resources, pe_working_set_t *data_set); -extern gboolean unpack_config(crm_data_t *config, pe_working_set_t *data_set); +extern gboolean unpack_config(xmlNode *config, pe_working_set_t *data_set); -extern gboolean unpack_nodes(crm_data_t *xml_nodes, pe_working_set_t *data_set); +extern gboolean unpack_nodes(xmlNode *xml_nodes, pe_working_set_t *data_set); -extern gboolean unpack_status(crm_data_t *status, pe_working_set_t *data_set); +extern gboolean unpack_status(xmlNode *status, pe_working_set_t *data_set); extern gint sort_op_by_callid(gconstpointer a, gconstpointer b); extern gboolean unpack_lrm_resources( - node_t *node, crm_data_t * lrm_state, pe_working_set_t *data_set); + node_t *node, xmlNode * lrm_state, pe_working_set_t *data_set); extern gboolean add_node_attrs( - crm_data_t * attrs, node_t *node, pe_working_set_t *data_set); + xmlNode * attrs, node_t *node, pe_working_set_t *data_set); extern gboolean unpack_rsc_op( - resource_t *rsc, node_t *node, crm_data_t *xml_op, + resource_t *rsc, node_t *node, xmlNode *xml_op, int *max_call_id, enum action_fail_response *failed, pe_working_set_t *data_set); extern gboolean determine_online_status( - crm_data_t * node_state, node_t *this_node, pe_working_set_t *data_set); + xmlNode * node_state, node_t *this_node, pe_working_set_t *data_set); extern const char *param_value( - GHashTable *hash, crm_data_t * parent, const char *name); + GHashTable *hash, xmlNode * parent, const char *name); /* * The man pages for both curses and ncurses suggest inclusion of "curses.h". * We believe the following to be acceptable and portable. */ #if defined(HAVE_LIBNCURSES) || defined(HAVE_LIBCURSES) # if defined(HAVE_NCURSES_H) && !defined(HAVE_INCOMPATIBLE_PRINTW) # include # define CURSES_ENABLED 1 # elif defined(HAVE_NCURSES_NCURSES_H) && !defined(HAVE_INCOMPATIBLE_PRINTW) # include # define CURSES_ENABLED 1 # elif defined(HAVE_CURSES_H) && !defined(HAVE_INCOMPATIBLE_PRINTW) # include # define CURSES_ENABLED 1 # elif defined(HAVE_CURSES_CURSES_H) && !defined(HAVE_INCOMPATIBLE_PRINTW) # include # define CURSES_ENABLED 1 # else # define CURSES_ENABLED 0 # endif #else # define CURSES_ENABLED 0 #endif #if CURSES_ENABLED # define status_printw(fmt, args...) printw(fmt, ##args) #else # define status_printw(fmt, args...) \ crm_err("printw support requires ncurses to be available during configure"); \ do_crm_log(LOG_WARNING, fmt, ##args); #endif #define status_print(fmt, args...) \ if(options & pe_print_html) { \ FILE *stream = print_data; \ fprintf(stream, fmt, ##args); \ } else if(options & pe_print_ncurses) { \ status_printw(fmt, ##args); \ } else if(options & pe_print_printf) { \ FILE *stream = print_data; \ fprintf(stream, fmt, ##args); \ } else if(options & pe_print_log) { \ int log_level = *(int*)print_data; \ do_crm_log(log_level, fmt, ##args); \ } #endif diff --git a/lib/crm/pengine/utils.c b/lib/crm/pengine/utils.c index e23bac6202..74dbfc4a50 100644 --- a/lib/crm/pengine/utils.c +++ b/lib/crm/pengine/utils.c @@ -1,1193 +1,1196 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include 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); + action_t *action, xmlNode *xml_obj, pe_working_set_t* data_set); 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; if(with_data == FALSE && alist != NULL) { g_list_free(alist); return; } 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_1(item); } } node_t * node_copy(node_t *this_node) { node_t *new_node = NULL; CRM_CHECK(this_node != NULL, return NULL); crm_malloc0(new_node, sizeof(node_t)); CRM_ASSERT(new_node != 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; } /* 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_id(rhs, node->details->id); 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_id(rhs, node->details->id); 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_id(list2, node->details->id); node_t *new_node = NULL; if(other_node != NULL) { new_node = node_copy(node); } if(new_node != NULL) { crm_debug_4("%s: %d + %d", node->details->uname, other_node->weight, new_node->weight); new_node->weight = merge_weights( new_node->weight, other_node->weight); crm_debug_3("New node weight for %s: %d", new_node->details->uname, new_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_id(list2, node->details->id); 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_id(list2, node->details->id); 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_id(list1, node->details->id); 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, FALSE, filter); slist_iter( node, node_t, list2, lpc, if(node == NULL) { continue; } other_node = (node_t*)pe_find_node_id( result, node->details->id); if(other_node != NULL) { crm_debug_4("%s + %s: %d + %d", node->details->uname, other_node->details->uname, node->weight, other_node->weight); 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, FALSE, filter); pe_free_shallow_adv(old_result, TRUE); } return result; } GListPtr node_list_dup(GListPtr list1, gboolean reset, 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(reset) { new_node->weight = 0; } if(new_node != NULL) { result = g_list_append(result, new_node); } ); return result; } void dump_node_scores(int level, resource_t *rsc, const char *comment, GListPtr nodes) { slist_iter( node, node_t, nodes, lpc, if(rsc) { do_crm_log(level, "%s: %s.%s = %d", comment, rsc->id, node->details->uname, node->weight); } else { do_crm_log(level, "%s: %s = %d", comment, node->details->uname, node->weight); } ); } gint sort_rsc_index(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->sort_index > resource2->sort_index) { return -1; } if(resource1->sort_index < resource2->sort_index) { return 1; } return 0; } 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; } action_t * custom_action(resource_t *rsc, char *key, const char *task, node_t *on_node, gboolean optional, gboolean save_action, pe_working_set_t *data_set) { action_t *action = NULL; GListPtr possible_matches = NULL; CRM_CHECK(key != NULL, return NULL); CRM_CHECK(task != NULL, return NULL); if(save_action && 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:"", on_node?on_node->details->uname:"", 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:"", on_node?on_node->details->uname:""); g_list_free(possible_matches); } if(action == NULL) { if(save_action) { crm_debug_2("Creating%s action %d: %s for %s on %s", optional?"":" manditory", data_set->action_id, key, rsc?rsc->id:"", on_node?on_node->details->uname:""); } crm_malloc0(action, sizeof(action_t)); if(save_action) { action->id = data_set->action_id++; } else { action->id = 0; } action->rsc = rsc; CRM_ASSERT(task != NULL); action->task = crm_strdup(task); action->node = on_node; action->uuid = key; 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 = optional; 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); action->meta = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); if(save_action) { data_set->actions = g_list_append( data_set->actions, action); } if(rsc != NULL) { action->op_entry = find_rsc_op_entry(rsc, key); unpack_operation( action, action->op_entry, data_set); if(save_action) { rsc->actions = g_list_append( rsc->actions, action); } } if(save_action) { crm_debug_4("Action %d created", action->id); } } if(optional == FALSE && action->optional) { crm_debug_2("Action %d (%s) marked manditory", action->id, action->uuid); action->optional = FALSE; } if(rsc != NULL) { enum action_tasks a_task = text2task(action->task); int warn_level = LOG_DEBUG_3; if(save_action) { warn_level = LOG_WARNING; } if(action->node != NULL && action->op_entry != NULL) { unpack_instance_attributes( action->op_entry, XML_TAG_ATTR_SETS, action->node->details->attrs, action->extra, NULL, data_set->now); } if(action->pseudo) { /* leave untouched */ } else if(action->node == NULL) { action->runnable = FALSE; } else if(is_not_set(rsc->flags, pe_rsc_managed)) { do_crm_log(warn_level, "Action %s (unmanaged)", action->uuid); action->optional = TRUE; /* action->runnable = FALSE; */ } else if(action->node->details->online == FALSE) { action->runnable = FALSE; do_crm_log(warn_level, "Action %s on %s is unrunnable (offline)", action->uuid, action->node->details->uname); if(is_set(action->rsc->flags, pe_rsc_managed) && save_action && a_task == stop_rsc) { do_crm_log(warn_level, "Marking node %s unclean", action->node->details->uname); action->node->details->unclean = TRUE; } } else if(action->needs == rsc_req_nothing) { crm_debug_3("Action %s doesnt require anything", action->uuid); action->runnable = TRUE; #if 0 /* * No point checking this * - if we dont have quorum we cant stonith anyway */ } else if(action->needs == rsc_req_stonith) { crm_debug_3("Action %s requires only stonith", action->uuid); action->runnable = TRUE; #endif } else if(data_set->have_quorum == FALSE && data_set->no_quorum_policy == no_quorum_stop) { action->runnable = FALSE; crm_debug("%s\t%s (cancelled : quorum)", action->node->details->uname, action->uuid); } else if(data_set->have_quorum == FALSE && data_set->no_quorum_policy == no_quorum_freeze) { crm_debug_3("Check resource is already active"); if(rsc->fns->active(rsc, TRUE) == FALSE) { action->runnable = FALSE; crm_debug("%s\t%s (cancelled : quorum freeze)", action->node->details->uname, action->uuid); } } else { crm_debug_3("Action %s is runnable", action->uuid); action->runnable = TRUE; } if(save_action) { switch(a_task) { case stop_rsc: set_bit(rsc->flags, pe_rsc_stopping); break; case start_rsc: clear_bit(rsc->flags, pe_rsc_starting); if(action->runnable) { set_bit(rsc->flags, pe_rsc_starting); } break; default: break; } } } return action; } void unpack_operation( - action_t *action, crm_data_t *xml_obj, pe_working_set_t* data_set) + action_t *action, xmlNode *xml_obj, pe_working_set_t* data_set) { int value_i = 0; int start_delay = 0; char *value_ms = NULL; const char *class = NULL; const char *value = NULL; const char *field = NULL; CRM_CHECK(action->rsc != NULL, return); class = g_hash_table_lookup(action->rsc->meta, "class"); if(xml_obj != NULL) { value = crm_element_value(xml_obj, "prereq"); } if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_START)) { value = g_hash_table_lookup(action->rsc->meta, "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 || safe_str_eq(class, "stonith")) { 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)"; } if(safe_str_eq(class, "stonith")) { if(action->needs == rsc_req_stonith) { crm_config_err("Stonith resources (eg. %s) cannot require" " fencing to start", action->rsc->id); } action->needs = rsc_req_nothing; value = "nothing (fencing override)"; } crm_debug_3("\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 = g_hash_table_lookup( action->rsc->meta, "on_stopfail"); if(value != NULL) { #if CRM_DEPRECATED_SINCE_2_0_2 crm_config_err("The \"on_stopfail\" attribute used in" " %s has been deprecated since 2.0.2", action->rsc->id); #else crm_config_err("The \"on_stopfail\" attribute used in" " %s has been deprecated since 2.0.2" " and is now disabled", action->rsc->id); value = NULL; #endif crm_config_err("Please use specify the \"on_fail\"" " attribute on the \"stop\" operation" " instead"); } } if(value == NULL) { } else if(safe_str_eq(value, "block")) { action->on_fail = action_fail_block; } else if(safe_str_eq(value, "fence")) { action->on_fail = action_fail_fence; value = "node fencing"; if(data_set->stonith_enabled == FALSE) { crm_config_err("Specifying on_fail=fence and" " stonith-enabled=false makes no sense"); action->on_fail = action_fail_stop; action->fail_role = RSC_ROLE_STOPPED; value = "stop resource"; } } else if(safe_str_eq(value, "ignore") || safe_str_eq(value, "nothing")) { action->on_fail = action_fail_ignore; value = "ignore"; } else if(safe_str_eq(value, "migrate")) { action->on_fail = action_fail_migrate; value = "force migration"; } else if(safe_str_eq(value, "stop")) { action->on_fail = action_fail_stop; action->fail_role = RSC_ROLE_STOPPED; value = "stop resource"; } else if(safe_str_eq(value, "restart")) { action->on_fail = action_fail_recover; value = "restart (and possibly migrate)"; } 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 && safe_str_eq(action->task, CRMD_ACTION_MIGRATED)) { action->on_fail = action_migrate_failure; value = "atomic migration recovery (default)"; } else if(value == NULL) { action->on_fail = action_fail_recover; value = "restart (and possibly migrate) (default)"; } crm_debug_3("\t%s failure handling: %s", action->task, value); value = NULL; if(xml_obj != NULL) { value = crm_element_value(xml_obj, "role_after_failure"); } if(value != NULL && action->fail_role == RSC_ROLE_UNKNOWN) { action->fail_role = text2role(value); } /* defaults */ if(action->fail_role == RSC_ROLE_UNKNOWN) { if(safe_str_eq(action->task, CRMD_ACTION_PROMOTE)) { action->fail_role = RSC_ROLE_SLAVE; } else { action->fail_role = RSC_ROLE_STARTED; } } crm_debug_3("\t%s failure results in: %s", action->task, role2text(action->fail_role)); if(xml_obj != NULL) { xml_prop_iter(xml_obj, p_name, p_value, if(p_value != NULL) { g_hash_table_insert(action->meta, crm_strdup(p_name), crm_strdup(p_value)); } ); unpack_instance_attributes(xml_obj, XML_TAG_META_SETS, NULL, action->meta, NULL, data_set->now); unpack_instance_attributes(xml_obj, XML_TAG_ATTR_SETS, NULL, action->meta, NULL, data_set->now); } field = XML_LRM_ATTR_INTERVAL; value = g_hash_table_lookup(action->meta, field); if(value != NULL) { value_i = crm_get_msec(value); CRM_CHECK(value_i >= 0, value_i = 0); value_ms = crm_itoa(value_i); g_hash_table_replace(action->meta, crm_strdup(field), value_ms); } field = "start_delay"; value = g_hash_table_lookup(action->meta, field); if(value != NULL) { value_i = crm_get_msec(value); if(value_i < 0) { value_i = 0; } start_delay = value_i; value_ms = crm_itoa(value_i); g_hash_table_replace(action->meta, crm_strdup(field), value_ms); } field = "timeout"; value = g_hash_table_lookup(action->meta, field); if(value == NULL) { value = pe_pref( data_set->config_hash, "default-action-timeout"); } value_i = crm_get_msec(value); if(value_i < 0) { value_i = 0; } value_i += start_delay; value_ms = crm_itoa(value_i); g_hash_table_replace(action->meta, crm_strdup(field), value_ms); } -crm_data_t * +xmlNode * find_rsc_op_entry(resource_t *rsc, const char *key) { int number = 0; const char *name = NULL; const char *value = NULL; const char *interval = NULL; char *match_key = NULL; - crm_data_t *op = NULL; + xmlNode *op = NULL; xml_child_iter_filter( rsc->ops_xml, operation, "op", name = crm_element_value(operation, "name"); interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL); value = crm_element_value(operation, "disabled"); if(crm_is_true(value)) { crm_debug_2("%s disabled", ID(operation)); continue; } number = crm_get_msec(interval); if(number < 0) { continue; } match_key = generate_op_key(rsc->id, name, number); if(safe_str_eq(key, match_key)) { op = operation; } crm_free(match_key); if(op != NULL) { return op; } ); crm_debug_3("No match for %s", key); return op; } void print_node(const char *pre_text, node_t *node, gboolean details) { if(node == NULL) { crm_debug_4("%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } crm_debug_4("%s%s%sNode %s: (weight=%d, 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(LOG_DEBUG_4, "\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_resource( int log_level, const char *pre_text, resource_t *rsc, gboolean details) { long options = pe_print_log; if(rsc == NULL) { do_crm_log(log_level-1, "%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } if(details) { options |= pe_print_details; } rsc->fns->print(rsc, pre_text, options, &log_level); } void pe_free_action(action_t *action) { if(action == NULL) { return; } pe_free_shallow(action->actions_before);/* action_warpper_t* */ pe_free_shallow(action->actions_after); /* action_warpper_t* */ g_hash_table_destroy(action->extra); g_hash_table_destroy(action->meta); crm_free(action->task); crm_free(action->uuid); crm_free(action); } GListPtr find_recurring_actions(GListPtr input, node_t *not_on_node) { const char *value = NULL; GListPtr result = NULL; CRM_CHECK(input != NULL, return NULL); slist_iter( action, action_t, input, lpc, value = g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL); if(value == NULL) { /* skip */ } else if(safe_str_eq(value, "0")) { /* skip */ } else if(safe_str_eq(CRMD_ACTION_CANCEL, action->task)) { /* skip */ } else if(not_on_node == NULL) { crm_debug_5("(null) Found: %s", action->uuid); result = g_list_append(result, action); } else if(action->node == NULL) { /* skip */ } else if(action->node->details != not_on_node->details) { crm_debug_5("Found: %s", action->uuid); result = g_list_append(result, action); } ); return result; } GListPtr find_actions(GListPtr input, const char *key, node_t *on_node) { GListPtr result = NULL; CRM_CHECK(key != NULL, return 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; } GListPtr find_actions_exact(GListPtr input, const char *key, node_t *on_node) { GListPtr result = NULL; CRM_CHECK(key != NULL, return 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)) { crm_debug_3("Key mismatch: %s vs. %s", key, action->uuid); continue; } else if(on_node == NULL || action->node == NULL) { crm_debug_3("on_node=%p, action->node=%p", on_node, action->node); continue; } else if(safe_str_eq(on_node->details->id, action->node->details->id)) { result = g_list_append(result, action); } crm_debug_2("Node mismatch: %s vs. %s", on_node->details->id, action->node->details->id); ); return result; } void -set_id(crm_data_t * xml_obj, const char *prefix, int child) +set_id(xmlNode * 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); } static void resource_node_score(resource_t *rsc, node_t *node, int score, const char *tag) { node_t *match = NULL; crm_debug_2("Setting %s for %s on %s: %d", tag, rsc->id, node->details->uname, score); match = pe_find_node_id(rsc->allowed_nodes, node->details->id); if(match == NULL) { match = node_copy(node); match->weight = 0; rsc->allowed_nodes = g_list_append(rsc->allowed_nodes, match); } match->weight = merge_weights(match->weight, score); } void resource_location(resource_t *rsc, node_t *node, int score, const char *tag, pe_working_set_t *data_set) { if(node != NULL) { resource_node_score(rsc, node, score, tag); } else if(data_set != NULL) { slist_iter( node, node_t, data_set->nodes, lpc, resource_node_score(rsc, node, score, tag); ); } else { slist_iter( node, node_t, rsc->allowed_nodes, lpc, resource_node_score(rsc, node, score, tag); ); } if(node == NULL && score == -INFINITY) { if(rsc->allocated_to) { crm_info("Deallocating %s from %s", rsc->id, rsc->allocated_to->details->uname); crm_free(rsc->allocated_to); rsc->allocated_to = NULL; } } } #define sort_return(an_int) crm_free(a_uuid); crm_free(b_uuid); return an_int gint sort_op_by_callid(gconstpointer a, gconstpointer b) { char *a_uuid = NULL; char *b_uuid = NULL; - const char *a_task_id = cl_get_string(a, XML_LRM_ATTR_CALLID); - const char *b_task_id = cl_get_string(b, XML_LRM_ATTR_CALLID); + const xmlNode *xml_a = a; + const xmlNode *xml_b = b; + + const char *a_xml_id = crm_element_value_const(xml_a, XML_ATTR_ID); + const char *b_xml_id = crm_element_value_const(xml_b, XML_ATTR_ID); - const char *a_key = cl_get_string(a, XML_ATTR_TRANSITION_MAGIC); - const char *b_key = cl_get_string(b, XML_ATTR_TRANSITION_MAGIC); + const char *a_task_id = crm_element_value_const(xml_a, XML_LRM_ATTR_CALLID); + const char *b_task_id = crm_element_value_const(xml_b, XML_LRM_ATTR_CALLID); - const char *a_xml_id = ID(a); - const char *b_xml_id = ID(b); + const char *a_key = crm_element_value_const(xml_a, XML_ATTR_TRANSITION_MAGIC); + const char *b_key = crm_element_value_const(xml_b, XML_ATTR_TRANSITION_MAGIC); int dummy = -1; int a_id = -1; int b_id = -1; int a_rc = -1; int b_rc = -1; int a_status = -1; int b_status = -1; int a_call_id = -1; int b_call_id = -1; if(safe_str_eq(a_xml_id, b_xml_id)) { /* We have duplicate lrm_rsc_op entries in the status * section which is unliklely to be a good thing * - we can handle it easily enough, but we need to get * to the bottom of why its happening. */ pe_err("Duplicate lrm_rsc_op entries named %s", a_xml_id); sort_return(0); } CRM_CHECK(a_task_id != NULL && b_task_id != NULL, sort_return(0)); a_call_id = crm_parse_int(a_task_id, NULL); b_call_id = crm_parse_int(b_task_id, NULL); if(a_call_id == -1 && b_call_id == -1) { /* both are pending ops so it doesnt matter since * stops are never pending */ sort_return(0); } else if(a_call_id >= 0 && a_call_id < b_call_id) { crm_debug_4("%s (%d) < %s (%d) : call id", - ID(a), a_call_id, ID(b), b_call_id); + a_xml_id, a_call_id, b_xml_id, b_call_id); sort_return(-1); } else if(b_call_id >= 0 && a_call_id > b_call_id) { crm_debug_4("%s (%d) > %s (%d) : call id", - ID(a), a_call_id, ID(b), b_call_id); + a_xml_id, a_call_id, b_xml_id, b_call_id); sort_return(1); } crm_debug_5("%s (%d) == %s (%d) : continuing", - ID(a), a_call_id, ID(b), b_call_id); + a_xml_id, a_call_id, b_xml_id, b_call_id); /* now process pending ops */ CRM_CHECK(a_key != NULL && b_key != NULL, sort_return(0)); CRM_CHECK(decode_transition_magic( a_key, &a_uuid, &a_id, &dummy, &a_status, &a_rc), sort_return(0)); CRM_CHECK(decode_transition_magic( b_key, &b_uuid, &b_id, &dummy, &b_status, &b_rc), sort_return(0)); /* try and determin the relative age of the operation... * some pending operations (ie. a start) may have been supuerceeded * by a subsequent stop * * [a|b]_id == -1 means its a shutdown operation and _always_ comes last */ if(safe_str_neq(a_uuid, b_uuid) || a_id == b_id) { /* * some of the logic in here may be redundant... * * if the UUID from the TE doesnt match then one better * be a pending operation. * pending operations dont survive between elections and joins * because we query the LRM directly */ CRM_CHECK(a_call_id == -1 || b_call_id == -1, sort_return(0)); CRM_CHECK(a_call_id >= 0 || b_call_id >= 0, sort_return(0)); if(b_call_id == -1) { crm_debug_2("%s (%d) < %s (%d) : transition + call id", - ID(a), a_call_id, ID(b), b_call_id); + a_xml_id, a_call_id, b_xml_id, b_call_id); sort_return(-1); } if(a_call_id == -1) { crm_debug_2("%s (%d) > %s (%d) : transition + call id", - ID(a), a_call_id, ID(b), b_call_id); + a_xml_id, a_call_id, b_xml_id, b_call_id); sort_return(1); } } else if((a_id >= 0 && a_id < b_id) || b_id == -1) { crm_debug_3("%s (%d) < %s (%d) : transition", - ID(a), a_id, ID(b), b_id); + a_xml_id, a_id, b_xml_id, b_id); sort_return(-1); } else if((b_id >= 0 && a_id > b_id) || a_id == -1) { crm_debug_3("%s (%d) > %s (%d) : transition", - ID(a), a_id, ID(b), b_id); + a_xml_id, a_id, b_xml_id, b_id); sort_return(1); } /* we should never end up here */ crm_err("%s (%d:%d:%s) ?? %s (%d:%d:%s) : default", - ID(a), a_call_id, a_id, a_uuid, ID(b), b_call_id, b_id, b_uuid); + a_xml_id, a_call_id, a_id, a_uuid, b_xml_id, b_call_id, b_id, b_uuid); CRM_CHECK(FALSE, sort_return(0)); } diff --git a/lib/crm/pengine/utils.h b/lib/crm/pengine/utils.h index 15d1e3c2cf..33867171bc 100644 --- a/lib/crm/pengine/utils.h +++ b/lib/crm/pengine/utils.h @@ -1,124 +1,124 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include extern node_t *node_copy(node_t *this_node) ; /* Binary like operators for lists of nodes */ extern GListPtr node_list_dup(GListPtr list1, gboolean reset, 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); extern void pe_free_shallow(GListPtr alist); extern void pe_free_shallow_adv(GListPtr alist, gboolean with_data); /* For creating the transition graph */ -extern crm_data_t *action2xml(action_t *action, gboolean as_input); +extern xmlNode *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( int log_level, const char *pre_text, resource_t *rsc, gboolean details); extern void dump_node_scores(int level, resource_t *rsc, const char *comment, GListPtr nodes); /* Sorting functions */ extern gint sort_rsc_priority(gconstpointer a, gconstpointer b); extern gint sort_rsc_index(gconstpointer a, gconstpointer b); -extern crm_data_t *find_rsc_op_entry(resource_t *rsc, const char *key); +extern xmlNode *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, gboolean foo, pe_working_set_t *data_set); #define delete_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_DELETE, 0) #define delete_action(rsc, node, optional) custom_action( \ rsc, delete_key(rsc), CRMD_ACTION_DELETE, node, \ optional, TRUE, data_set); #define stopped_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_STOPPED, 0) #define stopped_action(rsc, node, optional) custom_action( \ rsc, stopped_key(rsc), CRMD_ACTION_STOPPED, node, \ optional, TRUE, data_set); #define stop_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_STOP, 0) #define stop_action(rsc, node, optional) custom_action( \ rsc, stop_key(rsc), CRMD_ACTION_STOP, node, \ optional, TRUE, data_set); #define start_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_START, 0) #define start_action(rsc, node, optional) custom_action( \ rsc, start_key(rsc), CRMD_ACTION_START, node, \ optional, TRUE, data_set) #define started_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_STARTED, 0) #define started_action(rsc, node, optional) custom_action( \ rsc, started_key(rsc), CRMD_ACTION_STARTED, node, \ optional, TRUE, data_set) #define promote_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_PROMOTE, 0) #define promote_action(rsc, node, optional) custom_action( \ rsc, promote_key(rsc), CRMD_ACTION_PROMOTE, node, \ optional, TRUE, data_set) #define promoted_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_PROMOTED, 0) #define promoted_action(rsc, node, optional) custom_action( \ rsc, promoted_key(rsc), CRMD_ACTION_PROMOTED, node, \ optional, TRUE, data_set) #define demote_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_DEMOTE, 0) #define demote_action(rsc, node, optional) custom_action( \ rsc, demote_key(rsc), CRMD_ACTION_DEMOTE, node, \ optional, TRUE, data_set) #define demoted_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_DEMOTED, 0) #define demoted_action(rsc, node, optional) custom_action( \ rsc, demoted_key(rsc), CRMD_ACTION_DEMOTED, node, \ optional, TRUE, data_set) extern GListPtr find_actions(GListPtr input, const char *key, node_t *on_node); extern GListPtr find_actions_exact( GListPtr input, const char *key, node_t *on_node); extern GListPtr find_recurring_actions(GListPtr input, node_t *not_on_node); -extern void set_id(crm_data_t *xml_obj, const char *prefix, int child); +extern void set_id(xmlNode *xml_obj, const char *prefix, int child); extern void pe_free_action(action_t *action); extern void resource_location(resource_t *rsc, node_t *node, int score, const char *tag, pe_working_set_t *data_set); extern gint sort_op_by_callid(gconstpointer a, gconstpointer b); #endif diff --git a/lib/crm/pengine/variant.h b/lib/crm/pengine/variant.h index 69bdb52087..f0de975802 100644 --- a/lib/crm/pengine/variant.h +++ b/lib/crm/pengine/variant.h @@ -1,90 +1,90 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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_VARIANT__H #define PE_VARIANT__H #if VARIANT_CLONE typedef struct clone_variant_data_s { resource_t *self; int clone_max; int clone_node_max; int master_max; int master_node_max; int active_clones; int max_nodes; int masters_active; int masters_allocated; gboolean interleave; gboolean ordered; gboolean applied_master_prefs; gboolean merged_master_weights; - crm_data_t *xml_obj_child; + xmlNode *xml_obj_child; gboolean notify_confirm; } clone_variant_data_t; # define get_clone_variant_data(data, rsc) \ CRM_ASSERT(rsc != NULL); \ CRM_ASSERT(rsc->variant == pe_clone || rsc->variant == pe_master); \ data = (clone_variant_data_t *)rsc->variant_opaque; #elif VARIANT_GROUP typedef struct group_variant_data_s { int num_children; resource_t *self; resource_t *first_child; resource_t *last_child; gboolean colocated; gboolean ordered; gboolean child_starting; gboolean child_stopping; } group_variant_data_t; # define get_group_variant_data(data, rsc) \ CRM_ASSERT(rsc != NULL); \ CRM_ASSERT(rsc->variant == pe_group); \ CRM_ASSERT(rsc->variant_opaque != NULL); \ data = (group_variant_data_t *)rsc->variant_opaque; \ #elif VARIANT_NATIVE typedef struct native_variant_data_s { int dummy; } native_variant_data_t; # define get_native_variant_data(data, rsc) \ CRM_ASSERT(rsc != NULL); \ CRM_ASSERT(rsc->variant == pe_native); \ CRM_ASSERT(rsc->variant_opaque != NULL); \ data = (native_variant_data_t *)rsc->variant_opaque; #endif #endif diff --git a/lib/crm/transition/unpack.c b/lib/crm/transition/unpack.c index c3fa8bc865..c526a4d8da 100644 --- a/lib/crm/transition/unpack.c +++ b/lib/crm/transition/unpack.c @@ -1,266 +1,266 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include /* #include */ #include #include #include static crm_action_t* -unpack_action(synapse_t *parent, crm_data_t *xml_action) +unpack_action(synapse_t *parent, xmlNode *xml_action) { crm_action_t *action = NULL; - crm_data_t *action_copy = NULL; + xmlNode *action_copy = NULL; const char *value = crm_element_value(xml_action, XML_ATTR_ID); if(value == NULL) { crm_err("Actions must have an id!"); crm_log_xml_debug_3(xml_action, "Action with missing id"); return NULL; } action_copy = copy_xml(xml_action); crm_malloc0(action, sizeof(crm_action_t)); if(action == NULL) { return NULL; } action->id = crm_parse_int(value, NULL); action->type = action_type_rsc; action->xml = action_copy; action->synapse = parent; if(safe_str_eq(crm_element_name(action_copy), XML_GRAPH_TAG_RSC_OP)) { action->type = action_type_rsc; } else if(safe_str_eq(crm_element_name(action_copy), XML_GRAPH_TAG_PSEUDO_EVENT)) { action->type = action_type_pseudo; } else if(safe_str_eq(crm_element_name(action_copy), XML_GRAPH_TAG_CRM_EVENT)) { action->type = action_type_crm; } action->params = xml2list(action_copy); value = g_hash_table_lookup(action->params, "CRM_meta_timeout"); if(value != NULL) { action->timeout = crm_parse_int(value, NULL); } value = g_hash_table_lookup(action->params, "CRM_meta_interval"); if(value != NULL) { action->interval = crm_parse_int(value, NULL); } value = g_hash_table_lookup(action->params, "CRM_meta_can_fail"); if(value != NULL) { cl_str_to_boolean(value, &(action->can_fail)); } crm_debug_3("Action %d has timer set to %dms", action->id, action->timeout); return action; } static synapse_t * -unpack_synapse(crm_graph_t *new_graph, crm_data_t *xml_synapse) +unpack_synapse(crm_graph_t *new_graph, xmlNode *xml_synapse) { const char *value = NULL; synapse_t *new_synapse = NULL; CRM_CHECK(xml_synapse != NULL, return NULL); crm_debug_3("looking in synapse %s", ID(xml_synapse)); crm_malloc0(new_synapse, sizeof(synapse_t)); new_synapse->id = crm_parse_int(ID(xml_synapse), NULL); value = crm_element_value(xml_synapse, XML_CIB_ATTR_PRIORITY); if(value != NULL) { new_synapse->priority = crm_parse_int(value, NULL); } new_graph->num_synapses++; CRM_CHECK(new_synapse->id >= 0, crm_free(new_synapse); return NULL); crm_debug_3("look for actions in synapse %s", crm_element_value(xml_synapse, XML_ATTR_ID)); xml_child_iter_filter( xml_synapse, action_set, "action_set", xml_child_iter( action_set, action, crm_action_t *new_action = unpack_action( new_synapse, action); new_graph->num_actions++; if(new_action == NULL) { continue; } crm_debug_3("Adding action %d to synapse %d", new_action->id, new_synapse->id); new_synapse->actions = g_list_append( new_synapse->actions, new_action); ); ); crm_debug_3("look for inputs in synapse %s", ID(xml_synapse)); xml_child_iter_filter( xml_synapse, inputs, "inputs", xml_child_iter( inputs, trigger, xml_child_iter( trigger, input, crm_action_t *new_input = unpack_action( new_synapse, input); if(new_input == NULL) { continue; } crm_debug_3("Adding input %d to synapse %d", new_input->id, new_synapse->id); new_synapse->inputs = g_list_append( new_synapse->inputs, new_input); ); ); ); return new_synapse; } crm_graph_t * -unpack_graph(crm_data_t *xml_graph) +unpack_graph(xmlNode *xml_graph) { /* id = -1; new_graph->abort_priority = 0; new_graph->network_delay = -1; new_graph->transition_timeout = -1; if(xml_graph != NULL) { t_id = crm_element_value(xml_graph, "transition_id"); CRM_CHECK(t_id != NULL, crm_free(new_graph); return NULL); new_graph->id = crm_parse_int(t_id, "-1"); time = crm_element_value(xml_graph, "cluster-delay"); CRM_CHECK(time != NULL, crm_free(new_graph); return NULL); new_graph->network_delay = crm_get_msec(time); new_graph->transition_timeout = new_graph->network_delay; t_id = crm_element_value(xml_graph, "batch-limit"); new_graph->batch_limit = crm_parse_int(t_id, "0"); } xml_child_iter_filter( xml_graph, synapse, "synapse", synapse_t *new_synapse = unpack_synapse(new_graph, synapse); if(new_synapse != NULL) { new_graph->synapses = g_list_append( new_graph->synapses, new_synapse); } ); crm_info("Unpacked transition %d: %d actions in %d synapses", new_graph->id, new_graph->num_actions,new_graph->num_synapses); return new_graph; } static void destroy_action(crm_action_t *action) { if(action->timer && action->timer->source_id != 0) { crm_warn("Cancelling timer for action %d (src=%d)", action->id, action->timer->source_id); Gmain_timeout_remove(action->timer->source_id); } g_hash_table_destroy(action->params); free_xml(action->xml); crm_free(action->timer); crm_free(action); } static void destroy_synapse(synapse_t *synapse) { while(g_list_length(synapse->actions) > 0) { crm_action_t *action = g_list_nth_data(synapse->actions, 0); synapse->actions = g_list_remove(synapse->actions, action); destroy_action(action); } while(g_list_length(synapse->inputs) > 0) { crm_action_t *action = g_list_nth_data(synapse->inputs, 0); synapse->inputs = g_list_remove(synapse->inputs, action); destroy_action(action); } crm_free(synapse); } void destroy_graph(crm_graph_t *graph) { if(graph == NULL) { return; } while(g_list_length(graph->synapses) > 0) { synapse_t *synapse = g_list_nth_data(graph->synapses, 0); graph->synapses = g_list_remove(graph->synapses, synapse); destroy_synapse(synapse); } crm_free(graph); } diff --git a/pengine/allocate.c b/pengine/allocate.c index 6a15d71b79..a60455bfa7 100644 --- a/pengine/allocate.c +++ b/pengine/allocate.c @@ -1,840 +1,840 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include void set_alloc_actions(pe_working_set_t *data_set); void migrate_reload_madness(pe_working_set_t *data_set); resource_alloc_functions_t resource_class_alloc_functions[] = { { native_merge_weights, native_color, native_create_actions, native_create_probe, native_internal_constraints, native_rsc_colocation_lh, native_rsc_colocation_rh, native_rsc_order_lh, native_rsc_order_rh, native_rsc_location, native_expand, complex_migrate_reload, complex_stonith_ordering, complex_create_notify_element, }, { group_merge_weights, group_color, group_create_actions, native_create_probe, group_internal_constraints, group_rsc_colocation_lh, group_rsc_colocation_rh, group_rsc_order_lh, group_rsc_order_rh, group_rsc_location, group_expand, complex_migrate_reload, complex_stonith_ordering, complex_create_notify_element, }, { native_merge_weights, clone_color, clone_create_actions, clone_create_probe, clone_internal_constraints, clone_rsc_colocation_lh, clone_rsc_colocation_rh, clone_rsc_order_lh, clone_rsc_order_rh, clone_rsc_location, clone_expand, complex_migrate_reload, complex_stonith_ordering, complex_create_notify_element, }, { native_merge_weights, master_color, master_create_actions, clone_create_probe, master_internal_constraints, clone_rsc_colocation_lh, master_rsc_colocation_rh, clone_rsc_order_lh, clone_rsc_order_rh, clone_rsc_location, clone_expand, complex_migrate_reload, complex_stonith_ordering, complex_create_notify_element, } }; static gboolean -check_rsc_parameters(resource_t *rsc, node_t *node, crm_data_t *rsc_entry, +check_rsc_parameters(resource_t *rsc, node_t *node, xmlNode *rsc_entry, pe_working_set_t *data_set) { int attr_lpc = 0; gboolean force_restart = FALSE; gboolean delete_resource = FALSE; const char *value = NULL; const char *old_value = NULL; const char *attr_list[] = { XML_ATTR_TYPE, XML_AGENT_ATTR_CLASS, XML_AGENT_ATTR_PROVIDER }; for(; attr_lpc < DIMOF(attr_list); attr_lpc++) { value = crm_element_value(rsc->xml, attr_list[attr_lpc]); old_value = crm_element_value(rsc_entry, attr_list[attr_lpc]); if(value == old_value /* ie. NULL */ || crm_str_eq(value, old_value, TRUE)) { continue; } force_restart = TRUE; crm_notice("Forcing restart of %s on %s, %s changed: %s -> %s", rsc->id, node->details->uname, attr_list[attr_lpc], crm_str(old_value), crm_str(value)); } if(force_restart) { /* make sure the restart happens */ stop_action(rsc, node, FALSE); set_bit(rsc->flags, pe_rsc_start_pending); delete_resource = TRUE; } return delete_resource; } static gboolean -check_action_definition(resource_t *rsc, node_t *active_node, crm_data_t *xml_op, +check_action_definition(resource_t *rsc, node_t *active_node, xmlNode *xml_op, pe_working_set_t *data_set) { char *key = NULL; int interval = 0; const char *interval_s = NULL; gboolean did_change = FALSE; gboolean start_op = FALSE; - crm_data_t *params_all = NULL; - crm_data_t *params_restart = NULL; + xmlNode *params_all = NULL; + xmlNode *params_restart = NULL; GHashTable *local_rsc_params = NULL; char *digest_all_calc = NULL; const char *digest_all = NULL; const char *restart_list = NULL; const char *digest_restart = NULL; char *digest_restart_calc = NULL; action_t *action = NULL; const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK); const char *op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION); CRM_CHECK(active_node != NULL, return FALSE); interval_s = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL); interval = crm_parse_int(interval_s, "0"); /* we need to reconstruct the key because of the way we used to construct resource IDs */ key = generate_op_key(rsc->id, task, interval); if(interval > 0) { - crm_data_t *op_match = NULL; + xmlNode *op_match = NULL; crm_debug_2("Checking parameters for %s", key); op_match = find_rsc_op_entry(rsc, key); if(op_match == NULL && data_set->stop_action_orphans) { /* create a cancel action */ action_t *cancel = NULL; char *cancel_key = NULL; const char *call_id = crm_element_value(xml_op, XML_LRM_ATTR_CALLID); crm_info("Orphan action will be stopped: %s on %s", key, active_node->details->uname); cancel_key = generate_op_key( rsc->id, CRMD_ACTION_CANCEL, interval); cancel = custom_action( rsc, cancel_key, CRMD_ACTION_CANCEL, active_node, FALSE, TRUE, data_set); add_hash_param(cancel->meta, XML_LRM_ATTR_TASK, task); add_hash_param(cancel->meta, XML_LRM_ATTR_CALLID, call_id); add_hash_param(cancel->meta, XML_LRM_ATTR_INTERVAL, interval_s); custom_action_order( rsc, stop_key(rsc), NULL, rsc, NULL, cancel, pe_order_optional, data_set); crm_free(key); key = NULL; return TRUE; } else if(op_match == NULL) { crm_debug("Orphan action detected: %s on %s", key, active_node->details->uname); crm_free(key); key = NULL; return TRUE; } } action = custom_action(rsc, key, task, active_node, TRUE, FALSE, data_set); local_rsc_params = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); unpack_instance_attributes( rsc->xml, XML_TAG_ATTR_SETS, active_node->details->attrs, local_rsc_params, NULL, data_set->now); params_all = create_xml_node(NULL, XML_TAG_PARAMS); g_hash_table_foreach(action->extra, hash2field, params_all); g_hash_table_foreach(rsc->parameters, hash2field, params_all); g_hash_table_foreach(action->meta, hash2metafield, params_all); g_hash_table_foreach(local_rsc_params, hash2field, params_all); filter_action_parameters(params_all, op_version); digest_all_calc = calculate_xml_digest(params_all, TRUE, FALSE); digest_all = crm_element_value(xml_op, XML_LRM_ATTR_OP_DIGEST); digest_restart = crm_element_value(xml_op, XML_LRM_ATTR_RESTART_DIGEST); restart_list = crm_element_value(xml_op, XML_LRM_ATTR_OP_RESTART); if(crm_str_eq(task, CRMD_ACTION_START, TRUE)) { start_op = TRUE; } if(start_op && digest_restart) { params_restart = copy_xml(params_all); if(restart_list) { filter_reload_parameters(params_restart, restart_list); } digest_restart_calc = calculate_xml_digest(params_restart, TRUE, FALSE); if(safe_str_neq(digest_restart_calc, digest_restart)) { did_change = TRUE; crm_log_xml_info(params_restart, "params:restart"); crm_warn("Parameters to %s on %s changed: recorded %s vs. %s (restart:%s) %s", key, active_node->details->uname, crm_str(digest_restart), digest_restart_calc, op_version, crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC)); key = generate_op_key(rsc->id, task, interval); custom_action(rsc, key, task, NULL, FALSE, TRUE, data_set); goto cleanup; } } if(safe_str_neq(digest_all_calc, digest_all)) { action_t *op = NULL; did_change = TRUE; crm_log_xml_info(params_all, "params:all"); crm_warn("Parameters to %s on %s changed: recorded %s vs. %s (all:%s) %s", key, active_node->details->uname, crm_str(digest_all), digest_all_calc, op_version, crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC)); key = generate_op_key(rsc->id, task, interval); op = custom_action(rsc, key, task, NULL, FALSE, TRUE, data_set); if(start_op && digest_restart) { op->allow_reload_conversion = TRUE; } else if(interval > 0) { custom_action_order(rsc, start_key(rsc), NULL, NULL, crm_strdup(op->task), op, pe_order_runnable_left, data_set); } } cleanup: free_xml(params_all); free_xml(params_restart); crm_free(digest_all_calc); crm_free(digest_restart_calc); g_hash_table_destroy(local_rsc_params); pe_free_action(action); return did_change; } extern gboolean DeleteRsc(resource_t *rsc, node_t *node, gboolean optional, pe_working_set_t *data_set); static void -check_actions_for(crm_data_t *rsc_entry, node_t *node, pe_working_set_t *data_set) +check_actions_for(xmlNode *rsc_entry, node_t *node, pe_working_set_t *data_set) { const char *id = NULL; const char *task = NULL; int interval = 0; const char *interval_s = NULL; GListPtr op_list = NULL; GListPtr sorted_op_list = NULL; const char *rsc_id = ID(rsc_entry); gboolean is_probe = FALSE; int start_index = 0, stop_index = 0; resource_t *rsc = pe_find_resource(data_set->resources, rsc_id); CRM_CHECK(rsc != NULL, return); CRM_CHECK(node != NULL, return); CRM_CHECK(rsc_id != NULL, return); if(is_set(rsc->flags, pe_rsc_orphan)) { crm_debug_2("Skipping param check for %s: orphan", rsc->id); return; } else if(pe_find_node_id(rsc->running_on, node->details->id) == NULL) { crm_debug_2("Skipping param check for %s: no longer active on %s", rsc->id, node->details->uname); return; } crm_debug_3("Processing %s on %s", rsc->id, node->details->uname); if(check_rsc_parameters(rsc, node, rsc_entry, data_set)) { DeleteRsc(rsc, node, FALSE, data_set); } xml_child_iter_filter( rsc_entry, rsc_op, XML_LRM_TAG_RSC_OP, op_list = g_list_append(op_list, rsc_op); ); sorted_op_list = g_list_sort(op_list, sort_op_by_callid); calculate_active_ops(sorted_op_list, &start_index, &stop_index); slist_iter( - rsc_op, crm_data_t, sorted_op_list, lpc, + rsc_op, xmlNode, sorted_op_list, lpc, if(start_index < stop_index) { /* stopped */ continue; } else if(lpc < start_index) { /* action occurred prior to a start */ continue; } id = ID(rsc_op); is_probe = FALSE; task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); interval_s = crm_element_value(rsc_op, XML_LRM_ATTR_INTERVAL); interval = crm_parse_int(interval_s, "0"); if(interval == 0 && safe_str_eq(task, CRMD_ACTION_STATUS)) { is_probe = TRUE; } if(is_probe || safe_str_eq(task, CRMD_ACTION_START) || interval > 0) { check_action_definition(rsc, node, rsc_op, data_set); } ); g_list_free(sorted_op_list); } static void check_actions(pe_working_set_t *data_set) { const char *id = NULL; node_t *node = NULL; - crm_data_t *lrm_rscs = NULL; - crm_data_t *status = get_object_root(XML_CIB_TAG_STATUS, data_set->input); + xmlNode *lrm_rscs = NULL; + xmlNode *status = get_object_root(XML_CIB_TAG_STATUS, data_set->input); xml_child_iter_filter( status, node_state, XML_CIB_TAG_STATE, id = crm_element_value(node_state, XML_ATTR_ID); lrm_rscs = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE); lrm_rscs = find_xml_node(lrm_rscs, XML_LRM_TAG_RESOURCES, FALSE); node = pe_find_node_id(data_set->nodes, id); if(node == NULL) { continue; } else if(can_run_resources(node) == FALSE) { crm_debug_2("Skipping param check for %s: cant run resources", node->details->uname); continue; } crm_debug_2("Processing node %s", node->details->uname); if(node->details->online || data_set->stonith_enabled) { xml_child_iter_filter( lrm_rscs, rsc_entry, XML_LRM_TAG_RESOURCE, if(xml_has_children(rsc_entry)) { check_actions_for(rsc_entry, node, data_set); } ); } ); } static gboolean apply_placement_constraints(pe_working_set_t *data_set) { crm_debug_3("Applying constraints..."); slist_iter( cons, rsc_to_node_t, data_set->placement_constraints, lpc, cons->rsc_lh->cmds->rsc_location(cons->rsc_lh, cons); ); return TRUE; } static void complex_set_cmds(resource_t *rsc) { rsc->cmds = &resource_class_alloc_functions[rsc->variant]; slist_iter( child_rsc, resource_t, rsc->children, lpc, complex_set_cmds(child_rsc); ); } void set_alloc_actions(pe_working_set_t *data_set) { slist_iter( rsc, resource_t, data_set->resources, lpc, complex_set_cmds(rsc); ); } gboolean stage0(pe_working_set_t *data_set) { - crm_data_t * cib_constraints = get_object_root( + xmlNode * cib_constraints = get_object_root( XML_CIB_TAG_CONSTRAINTS, data_set->input); if(data_set->input == NULL) { return FALSE; } cluster_status(data_set); set_alloc_actions(data_set); unpack_constraints(cib_constraints, data_set); return TRUE; } /* * Check nodes for resources started outside of the LRM */ gboolean stage1(pe_working_set_t *data_set) { action_t *probe_complete = NULL; action_t *probe_node_complete = NULL; slist_iter( node, node_t, data_set->nodes, lpc, gboolean force_probe = FALSE; const char *probed = g_hash_table_lookup( node->details->attrs, CRM_OP_PROBED); crm_debug_2("%s probed: %s", node->details->uname, probed); if(node->details->online == FALSE) { continue; } else if(node->details->unclean) { continue; } else if(probe_complete == NULL) { probe_complete = custom_action( NULL, crm_strdup(CRM_OP_PROBED), CRM_OP_PROBED, NULL, FALSE, TRUE, data_set); probe_complete->pseudo = TRUE; probe_complete->optional = TRUE; } if(probed != NULL && crm_is_true(probed) == FALSE) { force_probe = TRUE; } probe_node_complete = custom_action( NULL, crm_strdup(CRM_OP_PROBED), CRM_OP_PROBED, node, FALSE, TRUE, data_set); probe_node_complete->optional = crm_is_true(probed); probe_node_complete->priority = INFINITY; add_hash_param(probe_node_complete->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); custom_action_order(NULL, NULL, probe_node_complete, NULL, NULL, probe_complete, pe_order_optional, data_set); slist_iter( rsc, resource_t, data_set->resources, lpc2, if(rsc->cmds->create_probe( rsc, node, probe_node_complete, force_probe, data_set)) { probe_complete->optional = FALSE; probe_node_complete->optional = FALSE; custom_action_order( NULL, NULL, probe_complete, rsc, start_key(rsc), NULL, pe_order_optional, data_set); } ); ); return TRUE; } /* * Count how many valid nodes we have (so we know the maximum number of * colors we can resolve). * * Apply node constraints (ie. filter the "allowed_nodes" part of resources */ gboolean stage2(pe_working_set_t *data_set) { crm_debug_3("Applying placement constraints"); slist_iter( node, node_t, data_set->nodes, lpc, if(node == NULL) { /* error */ } else if(node->weight >= 0.0 /* global weight */ && node->details->online && node->details->type == node_member) { data_set->max_valid_nodes++; } ); apply_placement_constraints(data_set); return TRUE; } /* * Create internal resource constraints before allocation */ gboolean stage3(pe_working_set_t *data_set) { slist_iter( rsc, resource_t, data_set->resources, lpc, rsc->cmds->internal_constraints(rsc, data_set); ); return TRUE; } /* * Check for orphaned or redefined actions */ gboolean stage4(pe_working_set_t *data_set) { check_actions(data_set); return TRUE; } gboolean stage5(pe_working_set_t *data_set) { /* Take (next) highest resource, assign it and create its actions */ slist_iter( rsc, resource_t, data_set->resources, lpc, rsc->cmds->color(rsc, data_set); rsc->cmds->create_actions(rsc, data_set); ); return TRUE; } /* * Create dependancies for stonith and shutdown operations */ gboolean stage6(pe_working_set_t *data_set) { action_t *dc_down = NULL; action_t *stonith_op = NULL; action_t *last_stonith = NULL; gboolean integrity_lost = FALSE; action_t *ready = get_pseudo_op(STONITH_UP, data_set); action_t *all_stopped = get_pseudo_op(ALL_STOPPED, data_set); crm_debug_3("Processing fencing and shutdown cases"); slist_iter( node, node_t, data_set->nodes, lpc, stonith_op = NULL; if(node->details->unclean && data_set->stonith_enabled && (data_set->have_quorum || data_set->no_quorum_policy == no_quorum_ignore)) { pe_warn("Scheduling Node %s for STONITH", node->details->uname); stonith_op = custom_action( NULL, crm_strdup(CRM_OP_FENCE), CRM_OP_FENCE, node, FALSE, TRUE, data_set); add_hash_param( stonith_op->meta, XML_LRM_ATTR_TARGET, node->details->uname); add_hash_param( stonith_op->meta, XML_LRM_ATTR_TARGET_UUID, node->details->id); add_hash_param( stonith_op->meta, "stonith_action", data_set->stonith_action); stonith_constraints(node, stonith_op, data_set); order_actions(ready, stonith_op, pe_order_implies_left); order_actions(stonith_op, all_stopped, pe_order_implies_right); if(node->details->is_dc) { dc_down = stonith_op; } else { if(last_stonith) { order_actions(last_stonith, stonith_op, pe_order_implies_left); } last_stonith = stonith_op; } } else if(node->details->online && node->details->shutdown) { action_t *down_op = NULL; crm_info("Scheduling Node %s for shutdown", node->details->uname); down_op = custom_action( NULL, crm_strdup(CRM_OP_SHUTDOWN), CRM_OP_SHUTDOWN, node, FALSE, TRUE, data_set); shutdown_constraints(node, down_op, data_set); if(node->details->is_dc) { dc_down = down_op; } } if(node->details->unclean && stonith_op == NULL) { integrity_lost = TRUE; pe_warn("Node %s is unclean!", node->details->uname); } ); if(integrity_lost) { if(data_set->have_quorum == FALSE) { crm_notice("Cannot fence unclean nodes until quorum is" " attained (or no_quorum_policy is set to ignore)"); } else if(data_set->stonith_enabled == FALSE) { pe_warn("YOUR RESOURCES ARE NOW LIKELY COMPROMISED"); pe_err("ENABLE STONITH TO KEEP YOUR RESOURCES SAFE"); } } if(dc_down != NULL) { GListPtr shutdown_matches = find_actions( data_set->actions, CRM_OP_SHUTDOWN, NULL); crm_debug_2("Ordering shutdowns before %s on %s (DC)", dc_down->task, dc_down->node->details->uname); add_hash_param(dc_down->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); slist_iter( node_stop, action_t, shutdown_matches, lpc, if(node_stop->node->details->is_dc) { continue; } crm_debug("Ordering shutdown on %s before %s on %s", node_stop->node->details->uname, dc_down->task, dc_down->node->details->uname); order_actions(node_stop, dc_down, pe_order_implies_left); ); if(last_stonith && dc_down != last_stonith) { order_actions(last_stonith, dc_down, pe_order_implies_left); } g_list_free(shutdown_matches); } return TRUE; } /* * Determin the sets of independant actions and the correct order for the * actions in each set. * * Mark dependencies of un-runnable actions un-runnable * */ gboolean stage7(pe_working_set_t *data_set) { crm_debug_4("Applying ordering constraints"); slist_iter( order, order_constraint_t, data_set->ordering_constraints, lpc, resource_t *rsc = order->lh_rsc; crm_debug_2("Applying ordering constraint: %d", order->id); if(rsc != NULL) { crm_debug_4("rsc_action-to-*"); rsc->cmds->rsc_order_lh(rsc, order, data_set); continue; } rsc = order->rh_rsc; if(rsc != NULL) { crm_debug_4("action-to-rsc_action"); rsc->cmds->rsc_order_rh(order->lh_action, rsc, order); } else { crm_debug_4("action-to-action"); order_actions( order->lh_action, order->rh_action, order->type); } ); update_action_states(data_set->actions); slist_iter( rsc, resource_t, data_set->resources, lpc, rsc->cmds->migrate_reload(rsc, data_set); ); return TRUE; } int transition_id = -1; /* * Create a dependency graph to send to the transitioner (via the CRMd) */ gboolean stage8(pe_working_set_t *data_set) { const char *value = NULL; char *transition_id_s = NULL; transition_id++; transition_id_s = crm_itoa(transition_id); crm_debug_2("Creating transition graph %d.", transition_id); data_set->graph = create_xml_node(NULL, XML_TAG_GRAPH); value = pe_pref(data_set->config_hash, "cluster-delay"); crm_xml_add(data_set->graph, "cluster-delay", value); value = pe_pref(data_set->config_hash, "batch-limit"); crm_xml_add(data_set->graph, "batch-limit", value); crm_xml_add(data_set->graph, "transition_id", transition_id_s); crm_free(transition_id_s); /* errors... slist_iter(action, action_t, action_list, lpc, if(action->optional == FALSE && action->runnable == FALSE) { print_action("Ignoring", action, TRUE); } ); */ slist_iter( rsc, resource_t, data_set->resources, lpc, crm_debug_4("processing actions for rsc=%s", rsc->id); rsc->cmds->expand(rsc, data_set); ); crm_log_xml_debug_3( data_set->graph, "created resource-driven action list"); /* catch any non-resource specific actions */ crm_debug_4("processing non-resource actions"); slist_iter( action, action_t, data_set->actions, lpc, graph_element_from_action(action, data_set); ); crm_log_xml_debug_3(data_set->graph, "created generic action list"); crm_debug_2("Created transition graph %d.", transition_id); return TRUE; } void cleanup_alloc_calculations(pe_working_set_t *data_set) { if(data_set == NULL) { return; } crm_debug_3("deleting order cons: %p", data_set->ordering_constraints); pe_free_ordering(data_set->ordering_constraints); data_set->ordering_constraints = NULL; crm_debug_3("deleting node cons: %p", data_set->placement_constraints); pe_free_rsc_to_node(data_set->placement_constraints); data_set->placement_constraints = NULL; crm_debug_3("deleting inter-resource cons: %p", data_set->colocation_constraints); pe_free_shallow(data_set->colocation_constraints); data_set->colocation_constraints = NULL; cleanup_calculations(data_set); } diff --git a/pengine/allocate.h b/pengine/allocate.h index b1239afd26..5fc5e92460 100644 --- a/pengine/allocate.h +++ b/pengine/allocate.h @@ -1,166 +1,166 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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_PENGINE_COMPLEX_ALLOC__H #define CRM_PENGINE_COMPLEX_ALLOC__H #include #include #include #include #include typedef struct notify_entry_s { resource_t *rsc; node_t *node; } notify_entry_t; typedef struct notify_data_s { GHashTable *keys; GListPtr active; /* notify_entry_t* */ GListPtr inactive; /* notify_entry_t* */ GListPtr start; /* notify_entry_t* */ GListPtr stop; /* notify_entry_t* */ GListPtr demote; /* notify_entry_t* */ GListPtr promote; /* notify_entry_t* */ GListPtr master; /* notify_entry_t* */ GListPtr slave; /* notify_entry_t* */ } notify_data_t; struct resource_alloc_functions_s { GListPtr(*merge_weights)(resource_t*, const char*, GListPtr, int, gboolean); node_t *(*color)(resource_t *, pe_working_set_t *); void (*create_actions)(resource_t *, pe_working_set_t *); gboolean (*create_probe)( resource_t *, node_t *, action_t *, gboolean, pe_working_set_t *); void (*internal_constraints)(resource_t *, pe_working_set_t *); void (*rsc_colocation_lh)(resource_t *, resource_t *, rsc_colocation_t *); void (*rsc_colocation_rh)(resource_t *, resource_t *, rsc_colocation_t *); void (*rsc_order_lh)(resource_t *, order_constraint_t *, pe_working_set_t *); void (*rsc_order_rh)( action_t *, resource_t *, order_constraint_t *); void (*rsc_location)(resource_t *, rsc_to_node_t *); void (*expand)(resource_t *, pe_working_set_t *); void (*migrate_reload)(resource_t *, pe_working_set_t *); void (*stonith_ordering)( resource_t *, action_t *, pe_working_set_t *); void (*create_notify_element)(resource_t*,action_t*, notify_data_t*,pe_working_set_t*); }; extern GListPtr native_merge_weights( resource_t *rsc, const char *rhs, GListPtr nodes, int factor, gboolean allow_rollback); extern node_t * native_color(resource_t *rsc, pe_working_set_t *data_set); extern void native_create_actions( resource_t *rsc, pe_working_set_t *data_set); extern void native_internal_constraints( resource_t *rsc, pe_working_set_t *data_set); extern void native_rsc_colocation_lh( resource_t *lh_rsc, resource_t *rh_rsc, rsc_colocation_t *constraint); extern void native_rsc_colocation_rh( resource_t *lh_rsc, resource_t *rh_rsc, rsc_colocation_t *constraint); extern void native_rsc_order_lh(resource_t *rsc, order_constraint_t *order, pe_working_set_t *data_set); extern void native_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order); extern void native_rsc_location(resource_t *rsc, rsc_to_node_t *constraint); extern void native_expand(resource_t *rsc, pe_working_set_t *data_set); extern void native_dump(resource_t *rsc, const char *pre_text, gboolean details); extern void complex_create_notify_element( resource_t *rsc, action_t *op, notify_data_t *n_data,pe_working_set_t *data_set); extern void native_assign_color(resource_t *rsc, node_t *node); extern gboolean native_create_probe( resource_t *rsc, node_t *node, action_t *complete, gboolean force, pe_working_set_t *data_set); extern void complex_stonith_ordering( resource_t *rsc, action_t *stonith_op, pe_working_set_t *data_set); extern void complex_migrate_reload(resource_t *rsc, pe_working_set_t *data_set); extern GListPtr group_merge_weights( resource_t *rsc, const char *rhs, GListPtr nodes, int factor, gboolean allow_rollback); extern int group_num_allowed_nodes(resource_t *rsc); extern node_t *group_color(resource_t *rsc, pe_working_set_t *data_set); extern void group_create_actions( resource_t *rsc, pe_working_set_t *data_set); extern void group_internal_constraints( resource_t *rsc, pe_working_set_t *data_set); extern void group_rsc_colocation_lh( resource_t *lh_rsc, resource_t *rh_rsc, rsc_colocation_t *constraint); extern void group_rsc_colocation_rh( resource_t *lh_rsc, resource_t *rh_rsc, rsc_colocation_t *constraint); extern void group_rsc_order_lh(resource_t *rsc, order_constraint_t *order, pe_working_set_t *data_set); extern void group_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order); extern void group_rsc_location(resource_t *rsc, rsc_to_node_t *constraint); extern void group_expand(resource_t *rsc, pe_working_set_t *data_set); extern int clone_num_allowed_nodes(resource_t *rsc); extern node_t *clone_color(resource_t *rsc, pe_working_set_t *data_set); extern void clone_create_actions(resource_t *rsc, pe_working_set_t *data_set); extern void clone_internal_constraints( resource_t *rsc, pe_working_set_t *data_set); extern void clone_rsc_colocation_lh( resource_t *lh_rsc, resource_t *rh_rsc, rsc_colocation_t *constraint); extern void clone_rsc_colocation_rh( resource_t *lh_rsc, resource_t *rh_rsc, rsc_colocation_t *constraint); extern void clone_rsc_order_lh(resource_t *rsc, order_constraint_t *order, pe_working_set_t *data_set); extern void clone_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order); extern void clone_rsc_location(resource_t *rsc, rsc_to_node_t *constraint); extern void clone_expand(resource_t *rsc, pe_working_set_t *data_set); extern gboolean clone_create_probe( resource_t *rsc, node_t *node, action_t *complete, gboolean force, pe_working_set_t *data_set); extern gboolean master_unpack(resource_t *rsc, pe_working_set_t *data_set); extern node_t *master_color(resource_t *rsc, pe_working_set_t *data_set); extern void master_create_actions(resource_t *rsc, pe_working_set_t *data_set); extern void master_internal_constraints( resource_t *rsc, pe_working_set_t *data_set); extern void master_rsc_colocation_rh( resource_t *lh_rsc, resource_t *rh_rsc, rsc_colocation_t *constraint); /* extern resource_object_functions_t resource_variants[]; */ extern resource_alloc_functions_t resource_class_alloc_functions[]; extern gboolean is_active(rsc_to_node_t *cons); extern gboolean native_constraint_violated( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint); -extern gboolean unpack_rsc_to_attr(crm_data_t *xml_obj, pe_working_set_t *data_set); +extern gboolean unpack_rsc_to_attr(xmlNode *xml_obj, pe_working_set_t *data_set); -extern gboolean unpack_rsc_to_node(crm_data_t *xml_obj, pe_working_set_t *data_set); +extern gboolean unpack_rsc_to_node(xmlNode *xml_obj, pe_working_set_t *data_set); -extern gboolean unpack_rsc_order(crm_data_t *xml_obj, pe_working_set_t *data_set); +extern gboolean unpack_rsc_order(xmlNode *xml_obj, pe_working_set_t *data_set); -extern gboolean unpack_rsc_colocation(crm_data_t *xml_obj, pe_working_set_t *data_set); +extern gboolean unpack_rsc_colocation(xmlNode *xml_obj, pe_working_set_t *data_set); -extern gboolean unpack_rsc_location(crm_data_t *xml_obj, pe_working_set_t *data_set); +extern gboolean unpack_rsc_location(xmlNode *xml_obj, pe_working_set_t *data_set); extern void cleanup_alloc_calculations(pe_working_set_t *data_set); #endif diff --git a/pengine/constraints.c b/pengine/constraints.c index d3dcf6b9be..80fec2f7e9 100644 --- a/pengine/constraints.c +++ b/pengine/constraints.c @@ -1,695 +1,696 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include +#include #include gboolean -unpack_constraints(crm_data_t * xml_constraints, pe_working_set_t *data_set) +unpack_constraints(xmlNode * xml_constraints, pe_working_set_t *data_set) { - crm_data_t *lifetime = NULL; + xmlNode *lifetime = NULL; xml_child_iter( xml_constraints, xml_obj, const char *id = crm_element_value(xml_obj, XML_ATTR_ID); if(id == NULL) { crm_config_err("Constraint <%s...> must have an id", crm_element_name(xml_obj)); continue; } crm_debug_3("Processing constraint %s %s", crm_element_name(xml_obj),id); - lifetime = cl_get_struct(xml_obj, "lifetime"); + lifetime = first_named_child(xml_obj, "lifetime"); if(test_ruleset(lifetime, NULL, data_set->now) == FALSE) { crm_info("Constraint %s %s is not active", crm_element_name(xml_obj), id); } else if(safe_str_eq(XML_CONS_TAG_RSC_ORDER, crm_element_name(xml_obj))) { unpack_rsc_order(xml_obj, data_set); } else if(safe_str_eq(XML_CONS_TAG_RSC_DEPEND, crm_element_name(xml_obj))) { unpack_rsc_colocation(xml_obj, data_set); } else if(safe_str_eq(XML_CONS_TAG_RSC_LOCATION, crm_element_name(xml_obj))) { unpack_rsc_location(xml_obj, data_set); } else { pe_err("Unsupported constraint type: %s", crm_element_name(xml_obj)); } ); return TRUE; } static const char * invert_action(const char *action) { if(safe_str_eq(action, CRMD_ACTION_START)) { return CRMD_ACTION_STOP; } else if(safe_str_eq(action, CRMD_ACTION_STOP)) { return CRMD_ACTION_START; } else if(safe_str_eq(action, CRMD_ACTION_PROMOTE)) { return CRMD_ACTION_DEMOTE; } else if(safe_str_eq(action, CRMD_ACTION_DEMOTE)) { return CRMD_ACTION_PROMOTE; } else if(safe_str_eq(action, CRMD_ACTION_PROMOTED)) { return CRMD_ACTION_DEMOTED; } else if(safe_str_eq(action, CRMD_ACTION_DEMOTED)) { return CRMD_ACTION_PROMOTED; } else if(safe_str_eq(action, CRMD_ACTION_STARTED)) { return CRMD_ACTION_STOPPED; } else if(safe_str_eq(action, CRMD_ACTION_STOPPED)) { return CRMD_ACTION_STARTED; } crm_config_warn("Unknown action: %s", action); return NULL; } gboolean -unpack_rsc_order(crm_data_t * xml_obj, pe_working_set_t *data_set) +unpack_rsc_order(xmlNode * xml_obj, pe_working_set_t *data_set) { int score_i = 0; int order_id = 0; resource_t *rsc_lh = NULL; resource_t *rsc_rh = NULL; gboolean symmetrical_bool = TRUE; enum pe_ordering cons_weight = pe_order_optional; const char *id_rh = NULL; const char *id_lh = NULL; const char *action = NULL; const char *action_rh = NULL; const char *id = crm_element_value(xml_obj, XML_ATTR_ID); const char *type = crm_element_value(xml_obj, XML_ATTR_TYPE); const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE); const char *symmetrical = crm_element_value( xml_obj, XML_CONS_ATTR_SYMMETRICAL); cl_str_to_boolean(symmetrical, &symmetrical_bool); if(xml_obj == NULL) { crm_config_err("No constraint object to process."); return FALSE; } else if(id == NULL) { crm_config_err("%s constraint must have an id", crm_element_name(xml_obj)); return FALSE; } id_lh = crm_element_value(xml_obj, XML_CONS_ATTR_TO); id_rh = crm_element_value(xml_obj, XML_CONS_ATTR_FROM); action = crm_element_value(xml_obj, XML_CONS_ATTR_ACTION); action_rh = crm_element_value(xml_obj, XML_CONS_ATTR_TOACTION); if(action == NULL) { action = CRMD_ACTION_START; } if(action_rh == NULL) { action_rh = action; } if(safe_str_neq(type, "before")) { /* normalize the input - swap everything over */ const char *tmp = NULL; type = "before"; tmp = id_rh; id_rh = id_lh; id_lh = tmp; tmp = action_rh; action_rh = action; action = tmp; } if(id_lh == NULL || id_rh == NULL) { crm_config_err("Constraint %s needs two sides lh: %s rh: %s", id, crm_str(id_lh), crm_str(id_rh)); return FALSE; } rsc_lh = pe_find_resource(data_set->resources, id_rh); rsc_rh = pe_find_resource(data_set->resources, id_lh); if(rsc_lh == NULL) { crm_config_err("Constraint %s: no resource found for LHS (%s)", id, id_rh); return FALSE; } else if(rsc_rh == NULL) { crm_config_err("Constraint %s: no resource found for RHS of (%s)", id, id_lh); return FALSE; } if(score == NULL) { score = "INFINITY"; } score_i = char2score(score); cons_weight = pe_order_optional; if(score_i == 0 && rsc_rh->restart_type == pe_restart_restart) { crm_debug_2("Upgrade : recovery - implies right"); cons_weight |= pe_order_implies_right; } if(score_i < 0) { crm_debug_2("Upgrade : implies left"); cons_weight |= pe_order_implies_left; } else if(score_i > 0) { crm_debug_2("Upgrade : implies right"); cons_weight |= pe_order_implies_right; if(safe_str_eq(action, CRMD_ACTION_START) || safe_str_eq(action, CRMD_ACTION_PROMOTE)) { crm_debug_2("Upgrade : runnable"); cons_weight |= pe_order_runnable_left; } } order_id = custom_action_order( rsc_lh, generate_op_key(rsc_lh->id, action, 0), NULL, rsc_rh, generate_op_key(rsc_rh->id, action_rh, 0), NULL, cons_weight, data_set); crm_debug("order-%d (%s): %s_%s %s %s_%s flags=0x%.6x", order_id, id, rsc_lh->id, action, type, rsc_rh->id, action_rh, cons_weight); if(symmetrical_bool == FALSE) { return TRUE; } action = invert_action(action); action_rh = invert_action(action_rh); cons_weight = pe_order_optional; if(score_i == 0 && rsc_rh->restart_type == pe_restart_restart) { crm_debug_2("Upgrade : recovery - implies left"); cons_weight |= pe_order_implies_left; } score_i *= -1; if(score_i < 0) { crm_debug_2("Upgrade : implies left"); cons_weight |= pe_order_implies_left; if(safe_str_eq(action_rh, CRMD_ACTION_DEMOTE)) { crm_debug_2("Upgrade : demote"); cons_weight |= pe_order_demote; } } else if(score_i > 0) { crm_debug_2("Upgrade : implies right"); cons_weight |= pe_order_implies_right; if(safe_str_eq(action, CRMD_ACTION_START) || safe_str_eq(action, CRMD_ACTION_PROMOTE)) { crm_debug_2("Upgrade : runnable"); cons_weight |= pe_order_runnable_left; } } if(action == NULL || action_rh == NULL) { crm_config_err("Cannot invert rsc_order constraint %s." " Please specify the inverse manually.", id); return TRUE; } order_id = custom_action_order( rsc_rh, generate_op_key(rsc_rh->id, action_rh, 0), NULL, rsc_lh, generate_op_key(rsc_lh->id, action, 0), NULL, cons_weight, data_set); crm_debug("order-%d (%s): %s_%s %s %s_%s flags=0x%.6x", order_id, id, rsc_rh->id, action_rh, type, rsc_lh->id, action, cons_weight); return TRUE; } gboolean -unpack_rsc_location(crm_data_t * xml_obj, pe_working_set_t *data_set) +unpack_rsc_location(xmlNode * xml_obj, pe_working_set_t *data_set) { gboolean empty = TRUE; const char *id_lh = crm_element_value(xml_obj, "rsc"); const char *id = crm_element_value(xml_obj, XML_ATTR_ID); resource_t *rsc_lh = pe_find_resource(data_set->resources, id_lh); const char *node = crm_element_value(xml_obj, "node"); const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE); if(rsc_lh == NULL) { /* only a warn as BSC adds the constraint then the resource */ crm_config_warn("No resource (con=%s, rsc=%s)", id, id_lh); return FALSE; } else if(is_not_set(rsc_lh->flags, pe_rsc_managed)) { crm_debug_2("Ignoring constraint %s: resource %s not managed", id, id_lh); return FALSE; } if(node != NULL && score != NULL) { int score_i = char2score(score); node_t *match = pe_find_node(data_set->nodes, node); if(match) { rsc2node_new(id, rsc_lh, score_i, match, data_set); return TRUE; } else { return FALSE; } } xml_child_iter_filter( xml_obj, rule_xml, XML_TAG_RULE, empty = FALSE; crm_debug_2("Unpacking %s/%s", id, ID(rule_xml)); generate_location_rule(rsc_lh, rule_xml, data_set); ); if(empty) { crm_config_err("Invalid location constraint %s:" " rsc_location must contain at least one rule", ID(xml_obj)); } return TRUE; } static int get_node_score(const char *rule, const char *score, gboolean raw, node_t *node) { int score_f = 0; if(score == NULL) { pe_err("Rule %s: no score specified. Assuming 0.", rule); } else if(raw) { score_f = char2score(score); } else { const char *attr_score = g_hash_table_lookup( node->details->attrs, score); if(attr_score == NULL) { crm_debug("Rule %s: node %s did not have a value for %s", rule, node->details->uname, score); score_f = -INFINITY; } else { crm_debug("Rule %s: node %s had value %s for %s", rule, node->details->uname, attr_score, score); score_f = char2score(attr_score); } } return score_f; } rsc_to_node_t * generate_location_rule( - resource_t *rsc, crm_data_t *rule_xml, pe_working_set_t *data_set) + resource_t *rsc, xmlNode *rule_xml, pe_working_set_t *data_set) { const char *rule_id = NULL; const char *score = NULL; const char *boolean = NULL; const char *role = NULL; GListPtr match_L = NULL; int score_f = 0; gboolean do_and = TRUE; gboolean accept = TRUE; gboolean raw_score = TRUE; rsc_to_node_t *location_rule = NULL; rule_id = crm_element_value(rule_xml, XML_ATTR_ID); boolean = crm_element_value(rule_xml, XML_RULE_ATTR_BOOLEAN_OP); role = crm_element_value(rule_xml, XML_RULE_ATTR_ROLE); crm_debug_2("Processing rule: %s", rule_id); if(role != NULL && text2role(role) == RSC_ROLE_UNKNOWN) { pe_err("Bad role specified for %s: %s", rule_id, role); return NULL; } score = crm_element_value(rule_xml, XML_RULE_ATTR_SCORE); if(score != NULL) { score_f = char2score(score); } else { score = crm_element_value( rule_xml, XML_RULE_ATTR_SCORE_ATTRIBUTE); if(score == NULL) { score = crm_element_value( rule_xml, XML_RULE_ATTR_SCORE_MANGLED); } if(score != NULL) { raw_score = FALSE; } } if(safe_str_eq(boolean, "or")) { do_and = FALSE; } location_rule = rsc2node_new(rule_id, rsc, 0, NULL, data_set); if(location_rule == NULL) { return NULL; } if(role != NULL) { crm_debug_2("Setting role filter: %s", role); location_rule->role_filter = text2role(role); } if(do_and) { match_L = node_list_dup(data_set->nodes, TRUE, FALSE); slist_iter( node, node_t, match_L, lpc, node->weight = get_node_score(rule_id, score, raw_score, node); ); } xml_child_iter( rule_xml, expr, enum expression_type type = find_expression_type(expr); crm_debug_2("Processing expression: %s", ID(expr)); if(type == not_expr) { pe_err("Expression <%s id=%s...> is not valid", crm_element_name(expr), crm_str(ID(expr))); continue; } slist_iter( node, node_t, data_set->nodes, lpc, if(type == nested_rule) { accept = test_rule( expr, node->details->attrs, RSC_ROLE_UNKNOWN, data_set->now); } else { accept = test_expression( expr, node->details->attrs, RSC_ROLE_UNKNOWN, data_set->now); } score_f = get_node_score(rule_id, score, raw_score, node); /* if(accept && score_f == -INFINITY) { */ /* accept = FALSE; */ /* } */ if(accept) { node_t *local = pe_find_node_id( match_L, node->details->id); if(local == NULL && do_and) { continue; } else if(local == NULL) { local = node_copy(node); match_L = g_list_append(match_L, local); } if(do_and == FALSE) { local->weight = merge_weights( local->weight, score_f); } crm_debug_2("node %s now has weight %d", node->details->uname, local->weight); } else if(do_and && !accept) { /* remove it */ node_t *delete = pe_find_node_id( match_L, node->details->id); if(delete != NULL) { match_L = g_list_remove(match_L,delete); crm_debug_5("node %s did not match", node->details->uname); } crm_free(delete); } ); ); location_rule->node_list_rh = match_L; if(location_rule->node_list_rh == NULL) { crm_debug_2("No matching nodes for rule %s", rule_id); return NULL; } crm_debug_3("%s: %d nodes matched", rule_id, g_list_length(location_rule->node_list_rh)); return location_rule; } static gint sort_cons_priority_lh(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; } CRM_ASSERT(rsc_constraint1->rsc_lh != NULL); CRM_ASSERT(rsc_constraint1->rsc_rh != NULL); if(rsc_constraint1->rsc_lh->priority > rsc_constraint2->rsc_lh->priority) { return -1; } if(rsc_constraint1->rsc_lh->priority < rsc_constraint2->rsc_lh->priority) { return 1; } return strcmp(rsc_constraint1->rsc_lh->id, rsc_constraint2->rsc_lh->id); } static gint sort_cons_priority_rh(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; } CRM_ASSERT(rsc_constraint1->rsc_lh != NULL); CRM_ASSERT(rsc_constraint1->rsc_rh != NULL); if(rsc_constraint1->rsc_rh->priority > rsc_constraint2->rsc_rh->priority) { return -1; } if(rsc_constraint1->rsc_rh->priority < rsc_constraint2->rsc_rh->priority) { return 1; } return strcmp(rsc_constraint1->rsc_rh->id, rsc_constraint2->rsc_rh->id); } gboolean rsc_colocation_new(const char *id, const char *node_attr, int score, resource_t *rsc_lh, resource_t *rsc_rh, const char *state_lh, const char *state_rh, pe_working_set_t *data_set) { rsc_colocation_t *new_con = NULL; if(rsc_lh == NULL){ crm_config_err("No resource found for LHS %s", id); return FALSE; } else if(rsc_rh == NULL){ crm_config_err("No resource found for RHS of %s", id); return FALSE; } crm_malloc0(new_con, sizeof(rsc_colocation_t)); if(new_con == NULL) { return FALSE; } if(state_lh == NULL || safe_str_eq(state_lh, RSC_ROLE_STARTED_S)) { state_lh = RSC_ROLE_UNKNOWN_S; } if(state_rh == NULL || safe_str_eq(state_rh, RSC_ROLE_STARTED_S)) { state_rh = RSC_ROLE_UNKNOWN_S; } new_con->id = id; new_con->rsc_lh = rsc_lh; new_con->rsc_rh = rsc_rh; new_con->score = score; new_con->role_lh = text2role(state_lh); new_con->role_rh = text2role(state_rh); new_con->node_attribute = node_attr; crm_debug_4("%s ==> %s (%d)", rsc_lh->id, rsc_rh->id, score); rsc_lh->rsc_cons = g_list_insert_sorted( rsc_lh->rsc_cons, new_con, sort_cons_priority_rh); rsc_rh->rsc_cons_lhs = g_list_insert_sorted( rsc_rh->rsc_cons_lhs, new_con, sort_cons_priority_lh); data_set->colocation_constraints = g_list_append( data_set->colocation_constraints, new_con); return TRUE; } /* LHS before RHS */ int custom_action_order( resource_t *lh_rsc, char *lh_action_task, action_t *lh_action, resource_t *rh_rsc, char *rh_action_task, action_t *rh_action, enum pe_ordering type, pe_working_set_t *data_set) { order_constraint_t *order = NULL; if(lh_rsc == NULL && lh_action) { lh_rsc = lh_action->rsc; } if(rh_rsc == NULL && rh_action) { rh_rsc = rh_action->rsc; } if((lh_action == NULL && lh_rsc == NULL) || (rh_action == NULL && rh_rsc == NULL)){ crm_config_err("Invalid inputs %p.%p %p.%p", lh_rsc, lh_action, rh_rsc, rh_action); crm_free(lh_action_task); crm_free(rh_action_task); return -1; } crm_malloc0(order, sizeof(order_constraint_t)); crm_debug_3("Creating ordering constraint %d", data_set->order_id); order->id = data_set->order_id++; order->type = type; order->lh_rsc = lh_rsc; order->rh_rsc = rh_rsc; order->lh_action = lh_action; order->rh_action = rh_action; order->lh_action_task = lh_action_task; order->rh_action_task = rh_action_task; data_set->ordering_constraints = g_list_append( data_set->ordering_constraints, order); if(lh_rsc != NULL && rh_rsc != NULL) { crm_debug_4("Created ordering constraint %d (%s):" " %s/%s before %s/%s", order->id, ordering_type2text(order->type), lh_rsc->id, lh_action_task, rh_rsc->id, rh_action_task); } else if(lh_rsc != NULL) { crm_debug_4("Created ordering constraint %d (%s):" " %s/%s before action %d (%s)", order->id, ordering_type2text(order->type), lh_rsc->id, lh_action_task, rh_action->id, rh_action_task); } else if(rh_rsc != NULL) { crm_debug_4("Created ordering constraint %d (%s):" " action %d (%s) before %s/%s", order->id, ordering_type2text(order->type), lh_action->id, lh_action_task, rh_rsc->id, rh_action_task); } else { crm_debug_4("Created ordering constraint %d (%s):" " action %d (%s) before action %d (%s)", order->id, ordering_type2text(order->type), lh_action->id, lh_action_task, rh_action->id, rh_action_task); } return order->id; } gboolean -unpack_rsc_colocation(crm_data_t * xml_obj, pe_working_set_t *data_set) +unpack_rsc_colocation(xmlNode * xml_obj, pe_working_set_t *data_set) { int score_i = 0; const char *id = crm_element_value(xml_obj, XML_ATTR_ID); const char *id_rh = crm_element_value(xml_obj, XML_CONS_ATTR_TO); const char *id_lh = crm_element_value(xml_obj, XML_CONS_ATTR_FROM); const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE); const char *state_lh = crm_element_value(xml_obj, XML_RULE_ATTR_FROMSTATE); const char *state_rh = crm_element_value(xml_obj, XML_RULE_ATTR_TOSTATE); const char *attr = crm_element_value(xml_obj, "node_attribute"); const char *symmetrical = crm_element_value(xml_obj, XML_CONS_ATTR_SYMMETRICAL); resource_t *rsc_lh = pe_find_resource(data_set->resources, id_lh); resource_t *rsc_rh = pe_find_resource(data_set->resources, id_rh); if(rsc_lh == NULL) { crm_config_err("No resource (con=%s, rsc=%s)", id, id_lh); return FALSE; } else if(rsc_rh == NULL) { crm_config_err("No resource (con=%s, rsc=%s)", id, id_rh); return FALSE; } if(score) { score_i = char2score(score); } rsc_colocation_new( id, attr, score_i, rsc_lh, rsc_rh, state_lh, state_rh, data_set); if(crm_is_true(symmetrical)) { rsc_colocation_new( id, attr, score_i, rsc_rh, rsc_lh, state_rh, state_lh, data_set); } return TRUE; } gboolean is_active(rsc_to_node_t *cons) { return TRUE; } diff --git a/pengine/graph.c b/pengine/graph.c index dfd1d43246..45f55481b8 100644 --- a/pengine/graph.c +++ b/pengine/graph.c @@ -1,623 +1,623 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include gboolean update_action(action_t *action); gboolean update_action_states(GListPtr actions) { crm_debug_2("Updating %d actions", g_list_length(actions)); slist_iter( action, action_t, actions, lpc, update_action(action); ); return TRUE; } gboolean update_action(action_t *action) { int local_type = 0; int log_level = LOG_DEBUG_2; gboolean changed = FALSE; do_crm_log(log_level, "Processing action %s: %s %s %s", action->uuid, action->optional?"optional":"required", action->runnable?"runnable":"unrunnable", action->pseudo?"pseudo":action->task); slist_iter( other, action_wrapper_t, action->actions_before, lpc, gboolean other_changed = FALSE; node_t *node = other->action->node; resource_t *other_rsc = other->action->rsc; enum rsc_role_e other_role = RSC_ROLE_UNKNOWN; if(other_rsc) { other_role = other_rsc->fns->state(other_rsc, TRUE); } do_crm_log(log_level, " Checking action %s: %s %s %s (flags=0x%.6x)", other->action->uuid, other->action->optional?"optional":"required", other->action->runnable?"runnable":"unrunnable", other->action->pseudo?"pseudo":other->action->task, other->type); local_type = other->type; if((local_type & pe_order_demote) && other->action->pseudo == FALSE && other_role > RSC_ROLE_SLAVE && node != NULL && node->details->online) { local_type |= pe_order_runnable_left; do_crm_log(log_level,"Upgrading restart constraint to runnable_left"); } if((local_type & pe_order_shutdown) && other->action->optional == FALSE && is_set(other_rsc->flags, pe_rsc_shutdown)) { action->optional = FALSE; changed = TRUE; do_crm_log(log_level-1, " * Marking action %s manditory because of %s (complex)", action->uuid, other->action->uuid); } if((local_type & pe_order_restart) && other_role > RSC_ROLE_STOPPED) { if(other_rsc->variant == pe_native) { local_type |= pe_order_implies_left; do_crm_log(log_level,"Upgrading restart constraint to implies_left"); } if(other->action->optional && other->action->runnable && action->runnable == FALSE) { do_crm_log(log_level-1, " * Marking action %s manditory because %s is unrunnable", other->action->uuid, action->uuid); other->action->optional = FALSE; set_bit(other_rsc->flags, pe_rsc_shutdown); other_changed = TRUE; } } if((local_type & pe_order_runnable_left) && other->action->runnable == FALSE) { if(other->action->implied_by_stonith) { do_crm_log(log_level, "Ignoring un-runnable - implied_by_stonith"); } else if(action->runnable == FALSE) { do_crm_log(log_level+1, "Already un-runnable"); } else { action->runnable = FALSE; do_crm_log(log_level-1, " * Marking action %s un-runnable because of %s", action->uuid, other->action->uuid); changed = TRUE; } } if((local_type & pe_order_runnable_right) && action->runnable == FALSE) { if(action->pseudo) { do_crm_log(log_level, "Ignoring un-runnable - pseudo"); } else if(other->action->runnable == FALSE) { do_crm_log(log_level+1, "Already un-runnable"); } else { other->action->runnable = FALSE; do_crm_log(log_level-1, " * Marking action %s un-runnable because of %s", other->action->uuid, action->uuid); other_changed = TRUE; } } if(local_type & pe_order_implies_left) { if(other->action->optional == FALSE) { /* nothing to do */ do_crm_log(log_level+1, " Ignoring implies left - redundant"); } else if(safe_str_eq(other->action->task, CRMD_ACTION_STOP) && other_role == RSC_ROLE_STOPPED) { do_crm_log(log_level-1, " Ignoring implies left - %s already stopped", other_rsc->id); } else if((local_type & pe_order_demote) && other_rsc->role < RSC_ROLE_MASTER) { do_crm_log(log_level-1, " Ignoring implies left - %s already demoted", other_rsc->id); } else if(action->optional == FALSE) { other->action->optional = FALSE; do_crm_log(log_level-1, " * (implies left) Marking action %s mandatory because of %s", other->action->uuid, action->uuid); other_changed = TRUE; } else { do_crm_log(log_level, " Ignoring implies left"); } } if(local_type & pe_order_implies_right) { if(action->optional == FALSE) { /* nothing to do */ do_crm_log(log_level+1, " Ignoring implies right - redundant"); } else if(other->action->optional == FALSE) { action->optional = FALSE; do_crm_log(log_level-1, " * (implies right) Marking action %s mandatory because of %s", action->uuid, other->action->uuid); changed = TRUE; } else { do_crm_log(log_level, " Ignoring implies right"); } } if(other_changed) { do_crm_log(log_level, "%s changed, processing after list", other->action->uuid); update_action(other->action); slist_iter( before_other, action_wrapper_t, other->action->actions_after, lpc2, do_crm_log(log_level, "%s changed, processing %s", other->action->uuid, before_other->action->uuid); update_action(before_other->action); ); } ); if(changed) { do_crm_log(log_level, "%s changed, processing after list", action->uuid); slist_iter( other, action_wrapper_t, action->actions_after, lpc, do_crm_log(log_level, "%s changed, processing %s", action->uuid, other->action->uuid); update_action(other->action); ); } return FALSE; } gboolean shutdown_constraints( node_t *node, action_t *shutdown_op, pe_working_set_t *data_set) { /* add the stop to the before lists so it counts as a pre-req * for the shutdown */ slist_iter( rsc, resource_t, node->details->running_rsc, lpc, if(is_not_set(rsc->flags, pe_rsc_managed)) { continue; } custom_action_order( rsc, stop_key(rsc), NULL, NULL, crm_strdup(CRM_OP_SHUTDOWN), shutdown_op, pe_order_implies_left, data_set); ); return TRUE; } gboolean stonith_constraints( node_t *node, action_t *stonith_op, pe_working_set_t *data_set) { CRM_CHECK(stonith_op != NULL, return FALSE); /* * Make sure the stonith OP occurs before we start any shared resources */ if(stonith_op != NULL) { slist_iter( rsc, resource_t, data_set->resources, lpc, rsc->cmds->stonith_ordering(rsc, stonith_op, data_set); ); } /* add the stonith OP as a stop pre-req and the mark the stop * as a pseudo op - since its now redundant */ return TRUE; } static void dup_attr(gpointer key, gpointer value, gpointer user_data) { g_hash_table_replace(user_data, crm_strdup(key), crm_strdup(value)); } -crm_data_t * +xmlNode * action2xml(action_t *action, gboolean as_input) { gboolean needs_node_info = TRUE; - crm_data_t * action_xml = NULL; - crm_data_t * args_xml = NULL; + xmlNode * action_xml = NULL; + xmlNode * args_xml = NULL; char *action_id_s = NULL; if(action == NULL) { return NULL; } crm_debug_4("Dumping action %d as XML", action->id); if(safe_str_eq(action->task, CRM_OP_FENCE)) { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); /* needs_node_info = FALSE; */ } else if(safe_str_eq(action->task, CRM_OP_SHUTDOWN)) { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); } else if(safe_str_eq(action->task, CRM_OP_LRM_REFRESH)) { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); /* } else if(safe_str_eq(action->task, CRMD_ACTION_PROBED)) { */ /* action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); */ } else if(action->pseudo) { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_PSEUDO_EVENT); needs_node_info = FALSE; } else { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP); } action_id_s = crm_itoa(action->id); crm_xml_add(action_xml, XML_ATTR_ID, action_id_s); crm_free(action_id_s); crm_xml_add(action_xml, XML_LRM_ATTR_TASK, action->task); if(action->rsc != NULL && action->rsc->clone_name != NULL) { char *clone_key = NULL; const char *interval_s = g_hash_table_lookup(action->meta, "interval"); int interval = crm_parse_int(interval_s, "0"); if(safe_str_eq(action->task, CRMD_ACTION_NOTIFY)) { const char *n_type = g_hash_table_lookup( action->extra, crm_meta_name("notify_type")); const char *n_task = g_hash_table_lookup( action->extra, crm_meta_name("notify_operation")); CRM_CHECK(n_type != NULL, ;); CRM_CHECK(n_task != NULL, ;); clone_key = generate_notify_key(action->rsc->clone_name, n_type, n_task); } else { clone_key = generate_op_key(action->rsc->clone_name, action->task, interval); } crm_xml_add(action_xml, XML_LRM_ATTR_TASK_KEY, clone_key); crm_xml_add(action_xml, "internal_"XML_LRM_ATTR_TASK_KEY, action->uuid); crm_free(clone_key); } else { crm_xml_add(action_xml, XML_LRM_ATTR_TASK_KEY, action->uuid); } if(needs_node_info && action->node != NULL) { crm_xml_add(action_xml, XML_LRM_ATTR_TARGET, action->node->details->uname); crm_xml_add(action_xml, XML_LRM_ATTR_TARGET_UUID, action->node->details->id); } if(action->failure_is_fatal == FALSE) { add_hash_param(action->meta, XML_ATTR_TE_ALLOWFAIL, XML_BOOLEAN_TRUE); } if(as_input) { return action_xml; } if(action->notify_keys != NULL) { g_hash_table_foreach( action->notify_keys, dup_attr, action->meta); } if(action->rsc != NULL && action->pseudo == FALSE) { int lpc = 0; - crm_data_t *rsc_xml = create_xml_node( + xmlNode *rsc_xml = create_xml_node( action_xml, crm_element_name(action->rsc->xml)); const char *attr_list[] = { XML_AGENT_ATTR_CLASS, XML_AGENT_ATTR_PROVIDER, XML_ATTR_TYPE }; if(action->rsc->clone_name != NULL) { crm_debug("Using clone name %s for %s", action->rsc->clone_name, action->rsc->id); crm_xml_add(rsc_xml, XML_ATTR_ID, action->rsc->clone_name); crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->id); } else { crm_xml_add(rsc_xml, XML_ATTR_ID, action->rsc->id); crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->long_name); } for(lpc = 0; lpc < DIMOF(attr_list); lpc++) { crm_xml_add(rsc_xml, attr_list[lpc], g_hash_table_lookup(action->rsc->meta, attr_list[lpc])); } } args_xml = create_xml_node(action_xml, XML_TAG_ATTRS); crm_xml_add(args_xml, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET); g_hash_table_foreach(action->extra, hash2field, args_xml); if(action->rsc != NULL && safe_str_neq(action->task, CRMD_ACTION_STOP)) { g_hash_table_foreach(action->rsc->parameters, hash2field, args_xml); } g_hash_table_foreach(action->meta, hash2metafield, args_xml); if(action->rsc != NULL) { int lpc = 0; const char *key = NULL; const char *value = NULL; const char *meta_list[] = { XML_RSC_ATTR_UNIQUE, XML_RSC_ATTR_INCARNATION, XML_RSC_ATTR_INCARNATION_MAX, XML_RSC_ATTR_INCARNATION_NODEMAX, XML_RSC_ATTR_MASTER_MAX, XML_RSC_ATTR_MASTER_NODEMAX, }; for(lpc = 0; lpc < DIMOF(meta_list); lpc++) { key = meta_list[lpc]; value = g_hash_table_lookup(action->rsc->meta, key); if(value != NULL) { char *crm_name = crm_concat(CRM_META, key, '_'); crm_xml_add(args_xml, crm_name, value); crm_free(crm_name); } } } crm_log_xml_debug_4(action_xml, "dumped action"); return action_xml; } static gboolean should_dump_action(action_t *action) { const char * interval = NULL; CRM_CHECK(action != NULL, return FALSE); interval = g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL); if(action->optional) { crm_debug_5("action %d (%s) was optional", action->id, action->uuid); return FALSE; } else if(action->runnable == FALSE) { crm_debug_5("action %d (%s) was not runnable", action->id, action->uuid); return FALSE; } else if(action->dumped) { crm_debug_5("action %d (%s) was already dumped", action->id, action->uuid); return FALSE; } else if(action->rsc != NULL && is_not_set(action->rsc->flags, pe_rsc_managed)) { /* make sure probes go through */ if(safe_str_neq(action->task, CRMD_ACTION_STATUS)) { pe_warn("action %d (%s) was for an unmanaged resource (%s)", action->id, action->uuid, action->rsc->id); return FALSE; } if(interval != NULL && safe_str_neq(interval, "0")) { pe_warn("action %d (%s) was for an unmanaged resource (%s)", action->id, action->uuid, action->rsc->id); return FALSE; } } if(action->pseudo || safe_str_eq(action->task, CRM_OP_FENCE) || safe_str_eq(action->task, CRM_OP_SHUTDOWN)) { /* skip the next checks */ return TRUE; } if(action->node == NULL) { pe_err("action %d (%s) was not allocated", action->id, action->uuid); log_action(LOG_DEBUG, "Unallocated action", action, FALSE); return FALSE; } else if(action->node->details->online == FALSE) { pe_err("action %d was (%s) scheduled for offline node", action->id, action->uuid); log_action(LOG_DEBUG, "Action for offline node", action, FALSE); return FALSE; #if 0 /* but this would also affect resources that can be safely * migrated before a fencing op */ } else if(action->node->details->unclean == FALSE) { pe_err("action %d was (%s) scheduled for unclean node", action->id, action->uuid); log_action(LOG_DEBUG, "Action for unclean node", action, FALSE); return FALSE; #endif } return TRUE; } /* lowest to highest */ static 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; } static gboolean should_dump_input(int last_action, action_t *action, action_wrapper_t *wrapper) { wrapper->state = pe_link_not_dumped; if(last_action == wrapper->action->id) { crm_debug_2("Input (%d) %s duplicated", wrapper->action->id, wrapper->action->uuid); wrapper->state = pe_link_dup; return FALSE; } else if(wrapper->type == pe_order_none) { crm_debug_2("Input (%d) %s suppressed", wrapper->action->id, wrapper->action->uuid); return FALSE; } else if(wrapper->action->optional == TRUE) { crm_debug_2("Input (%d) %s optional", wrapper->action->id, wrapper->action->uuid); return FALSE; } else if(wrapper->action->runnable == FALSE && wrapper->action->pseudo == FALSE && wrapper->type == pe_order_optional) { crm_debug("Input (%d) %s optional (ordering)", wrapper->action->id, wrapper->action->uuid); return FALSE; } else if(action->pseudo && (wrapper->type & pe_order_stonith_stop)) { crm_debug("Input (%d) %s suppressed", wrapper->action->id, wrapper->action->uuid); return FALSE; } crm_debug_3("Input (%d) %s n=%p p=%d r=%d f=0x%.6x dumped for %s", wrapper->action->id, wrapper->action->uuid, wrapper->action->node, wrapper->action->pseudo, wrapper->action->runnable, wrapper->type, action->uuid); return TRUE; } void graph_element_from_action(action_t *action, pe_working_set_t *data_set) { int last_action = -1; int synapse_priority = 0; - crm_data_t * syn = NULL; - crm_data_t * set = NULL; - crm_data_t * in = NULL; - crm_data_t * input = NULL; - crm_data_t * xml_action = NULL; + xmlNode * syn = NULL; + xmlNode * set = NULL; + xmlNode * in = NULL; + xmlNode * input = NULL; + xmlNode * xml_action = NULL; if(should_dump_action(action) == FALSE) { return; } action->dumped = TRUE; syn = create_xml_node(data_set->graph, "synapse"); set = create_xml_node(syn, "action_set"); in = create_xml_node(syn, "inputs"); crm_xml_add_int(syn, XML_ATTR_ID, data_set->num_synapse); data_set->num_synapse++; if(action->rsc != NULL) { synapse_priority = action->rsc->priority; } if(action->priority > synapse_priority) { synapse_priority = action->priority; } if(synapse_priority > 0) { crm_xml_add_int(syn, XML_CIB_ATTR_PRIORITY, synapse_priority); } xml_action = action2xml(action, FALSE); add_node_nocopy(set, crm_element_name(xml_action), xml_action); action->actions_before = g_list_sort( action->actions_before, sort_action_id); slist_iter(wrapper,action_wrapper_t,action->actions_before,lpc, if(should_dump_input(last_action, action, wrapper) == FALSE) { continue; } wrapper->state = pe_link_dumped; CRM_CHECK(last_action < wrapper->action->id, ;); last_action = wrapper->action->id; input = create_xml_node(in, "trigger"); xml_action = action2xml(wrapper->action, TRUE); add_node_nocopy(input, crm_element_name(xml_action), xml_action); ); } diff --git a/pengine/main.c b/pengine/main.c index 7069a81dba..9a98a49f61 100644 --- a/pengine/main.c +++ b/pengine/main.c @@ -1,159 +1,159 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_LIBXML2 # include #endif #define OPTARGS "hVc" GMainLoop* mainloop = NULL; void usage(const char* cmd, int exit_status); int pe_init(void); gboolean pengine_shutdown(int nsig, gpointer unused); -extern gboolean process_pe_message(crm_data_t * msg, IPC_Channel *sender); +extern gboolean process_pe_message(xmlNode * msg, IPC_Channel *sender); int main(int argc, char ** argv) { int flag; int argerr = 0; gboolean allow_cores = TRUE; crm_log_init(CRM_SYSTEM_PENGINE, LOG_INFO, TRUE, FALSE, 0, NULL); G_main_add_SignalHandler( G_PRIORITY_HIGH, SIGTERM, pengine_shutdown, NULL, NULL); while ((flag = getopt(argc, argv, OPTARGS)) != EOF) { switch(flag) { case 'V': alter_debug(DEBUG_INC); break; case 'h': /* Help message */ usage(crm_system_name, LSB_EXIT_OK); break; case 'c': allow_cores = TRUE; break; default: ++argerr; break; } } if(argc - optind == 1 && safe_str_eq("metadata", argv[optind])) { pe_metadata(); return 0; } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name,LSB_EXIT_GENERIC); } /* read local config file */ crm_debug_4("do start"); return pe_init(); } int pe_init(void) { IPC_Channel *crm_ch = NULL; crm_debug_4("initialize comms"); init_client_ipc_comms( CRM_SYSTEM_CRMD, subsystem_msg_dispatch, (void*)process_pe_message, &crm_ch); if(crm_ch != NULL) { crm_debug_4("sending hello message"); send_hello_message( crm_ch, "1234", CRM_SYSTEM_PENGINE, "0", "1"); /* Create the mainloop and run it... */ crm_info("Starting %s", crm_system_name); mainloop = g_main_new(FALSE); g_main_run(mainloop); return_to_orig_privs(); #if HAVE_LIBXML2 xmlCleanupParser(); #endif crm_info("Exiting %s", crm_system_name); return 0; } crm_err("Could not connect to the CRMd"); return 1; } void usage(const char* cmd, int exit_status) { FILE* stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-srkh]" "[-c configure file]\n", cmd); /* fprintf(stream, "\t-d\tsets debug level\n"); */ /* fprintf(stream, "\t-s\tgets daemon status\n"); */ /* fprintf(stream, "\t-r\trestarts daemon\n"); */ /* fprintf(stream, "\t-k\tstops daemon\n"); */ /* fprintf(stream, "\t-h\thelp message\n"); */ fflush(stream); exit(exit_status); } gboolean pengine_shutdown(int nsig, gpointer unused) { crm_info("Exiting PEngine (SIGTERM)"); exit(LSB_EXIT_OK); } diff --git a/pengine/native.c b/pengine/native.c index 933b4a84f5..9ba86624f5 100644 --- a/pengine/native.c +++ b/pengine/native.c @@ -1,1962 +1,1962 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #define DELETE_THEN_REFRESH 1 /* The crmd will remove the resource from the CIB itself, making this redundant */ #define VARIANT_NATIVE 1 #include gboolean at_stack_bottom(resource_t *rsc); void node_list_update(GListPtr list1, GListPtr list2, int factor); void native_rsc_colocation_rh_must(resource_t *rsc_lh, gboolean update_lh, resource_t *rsc_rh, gboolean update_rh); void native_rsc_colocation_rh_mustnot(resource_t *rsc_lh, gboolean update_lh, resource_t *rsc_rh, gboolean update_rh); void create_notifications(resource_t *rsc, pe_working_set_t *data_set); void Recurring(resource_t *rsc, action_t *start, node_t *node, pe_working_set_t *data_set); void RecurringOp(resource_t *rsc, action_t *start, node_t *node, - crm_data_t *operation, pe_working_set_t *data_set); + xmlNode *operation, pe_working_set_t *data_set); void pe_pre_notify( resource_t *rsc, node_t *node, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set); void pe_post_notify( resource_t *rsc, node_t *node, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set); void NoRoleChange (resource_t *rsc, node_t *current, node_t *next, pe_working_set_t *data_set); gboolean DeleteRsc (resource_t *rsc, node_t *node, gboolean optional, pe_working_set_t *data_set); gboolean StopRsc (resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set); gboolean StartRsc (resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set); gboolean DemoteRsc (resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set); gboolean PromoteRsc(resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set); gboolean RoleError (resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set); gboolean NullOp (resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set); enum rsc_role_e rsc_state_matrix[RSC_ROLE_MAX][RSC_ROLE_MAX] = { /* Current State */ /* Next State: Unknown Stopped Started Slave Master */ /* Unknown */ { RSC_ROLE_UNKNOWN, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, }, /* Stopped */ { RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STARTED, RSC_ROLE_SLAVE, RSC_ROLE_SLAVE, }, /* Started */ { RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STARTED, RSC_ROLE_SLAVE, RSC_ROLE_MASTER, }, /* Slave */ { RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_UNKNOWN, RSC_ROLE_SLAVE, RSC_ROLE_MASTER, }, /* Master */ { RSC_ROLE_STOPPED, RSC_ROLE_SLAVE, RSC_ROLE_UNKNOWN, RSC_ROLE_SLAVE, RSC_ROLE_MASTER, }, }; gboolean (*rsc_action_matrix[RSC_ROLE_MAX][RSC_ROLE_MAX])(resource_t*,node_t*,gboolean,pe_working_set_t*) = { /* Current State */ /* Next State: Unknown Stopped Started Slave Master */ /* Unknown */ { RoleError, StopRsc, RoleError, RoleError, RoleError, }, /* Stopped */ { RoleError, NullOp, StartRsc, StartRsc, RoleError, }, /* Started */ { RoleError, StopRsc, NullOp, NullOp, PromoteRsc, }, /* Slave */ { RoleError, StopRsc, RoleError, NullOp, PromoteRsc, }, /* Master */ { RoleError, RoleError, RoleError, DemoteRsc, NullOp, }, }; static gboolean native_choose_node(resource_t *rsc) { /* 1. Sort by weight 2. color.chosen_node = the node (of those with the highest wieght) with the fewest resources 3. remove color.chosen_node from all other colors */ GListPtr nodes = NULL; node_t *chosen = NULL; if(is_not_set(rsc->flags, pe_rsc_provisional)) { return rsc->allocated_to?TRUE:FALSE; } crm_debug_3("Choosing node for %s from %d candidates", rsc->id, g_list_length(rsc->allowed_nodes)); if(rsc->allowed_nodes) { rsc->allowed_nodes = g_list_sort( rsc->allowed_nodes, sort_node_weight); nodes = rsc->allowed_nodes; chosen = g_list_nth_data(nodes, 0); } return native_assign_node(rsc, nodes, chosen); } GListPtr native_merge_weights( resource_t *rsc, const char *rhs, GListPtr nodes, int factor, gboolean allow_rollback) { GListPtr archive = NULL; if(is_set(rsc->flags, pe_rsc_merging)) { crm_debug("%s: Breaking dependancy loop", rhs); return nodes; } else if(is_not_set(rsc->flags, pe_rsc_provisional) || can_run_any(nodes) == FALSE) { return nodes; } set_bit(rsc->flags, pe_rsc_merging); crm_debug_2("%s: Combining scores from %s", rhs, rsc->id); if(allow_rollback) { archive = node_list_dup(nodes, FALSE, FALSE); } node_list_update(nodes, rsc->allowed_nodes, factor); if(archive && can_run_any(nodes) == FALSE) { crm_debug("%s: Rolling back scores from %s", rhs, rsc->id); pe_free_shallow_adv(nodes, TRUE); nodes = archive; goto bail; } pe_free_shallow_adv(archive, TRUE); slist_iter( constraint, rsc_colocation_t, rsc->rsc_cons_lhs, lpc, nodes = constraint->rsc_lh->cmds->merge_weights( constraint->rsc_lh, rhs, nodes, constraint->score/INFINITY, allow_rollback); ); bail: clear_bit(rsc->flags, pe_rsc_merging); return nodes; } node_t * native_color(resource_t *rsc, pe_working_set_t *data_set) { int alloc_details = LOG_DEBUG_2; if(rsc->parent && is_not_set(rsc->parent->flags, pe_rsc_allocating)) { /* never allocate children on their own */ crm_debug("Escalating allocation of %s to its parent: %s", rsc->id, rsc->parent->id); rsc->parent->cmds->color(rsc->parent, data_set); } if(is_not_set(rsc->flags, pe_rsc_provisional)) { return rsc->allocated_to; } if(is_set(rsc->flags, pe_rsc_allocating)) { crm_debug("Dependancy loop detected involving %s", rsc->id); return NULL; } set_bit(rsc->flags, pe_rsc_allocating); print_resource(alloc_details, "Allocating: ", rsc, FALSE); dump_node_scores(alloc_details, rsc, "Pre-allloc", rsc->allowed_nodes); slist_iter( constraint, rsc_colocation_t, rsc->rsc_cons, lpc, resource_t *rsc_rh = constraint->rsc_rh; crm_debug("%s: Pre-Processing %s (%s)", rsc->id, constraint->id, rsc_rh->id); rsc_rh->cmds->color(rsc_rh, data_set); rsc->cmds->rsc_colocation_lh(rsc, rsc_rh, constraint); ); dump_node_scores(alloc_details, rsc, "Post-coloc", rsc->allowed_nodes); slist_iter( constraint, rsc_colocation_t, rsc->rsc_cons_lhs, lpc, rsc->allowed_nodes = constraint->rsc_lh->cmds->merge_weights( constraint->rsc_lh, rsc->id, rsc->allowed_nodes, constraint->score/INFINITY, TRUE); ); dump_node_scores(alloc_details, rsc, "Post-merge", rsc->allowed_nodes); print_resource(LOG_DEBUG, "Allocating: ", rsc, FALSE); if(rsc->next_role == RSC_ROLE_STOPPED) { crm_debug_2("Making sure %s doesn't get allocated", rsc->id); /* make sure it doesnt come up again */ resource_location( rsc, NULL, -INFINITY, "target_role", data_set); } if(is_set(rsc->flags, pe_rsc_provisional) && native_choose_node(rsc) ) { crm_debug_3("Allocated resource %s to %s", rsc->id, rsc->allocated_to->details->uname); } else if(rsc->allocated_to == NULL) { if(is_not_set(rsc->flags, pe_rsc_orphan)) { pe_warn("Resource %s cannot run anywhere", rsc->id); } else { crm_info("Stopping orphan resource %s", rsc->id); } } else { crm_debug("Pre-Allocated resource %s to %s", rsc->id, rsc->allocated_to->details->uname); } clear_bit(rsc->flags, pe_rsc_allocating); print_resource(LOG_DEBUG_3, "Allocated ", rsc, TRUE); return rsc->allocated_to; } static gboolean is_op_dup( resource_t *rsc, const char *name, const char *interval) { gboolean dup = FALSE; const char *id = NULL; const char *value = NULL; xml_child_iter_filter( rsc->ops_xml, operation, "op", value = crm_element_value(operation, "name"); if(safe_str_neq(value, name)) { continue; } value = crm_element_value(operation, XML_LRM_ATTR_INTERVAL); if(value == NULL) { value = "0"; } if(safe_str_neq(value, interval)) { continue; } if(id == NULL) { id = ID(operation); } else { crm_config_err("Operation %s is a duplicate of %s", ID(operation), id); crm_config_err("Do not use the same (name, interval) combination more than once per resource"); dup = TRUE; } ); return dup; } void RecurringOp(resource_t *rsc, action_t *start, node_t *node, - crm_data_t *operation, pe_working_set_t *data_set) + xmlNode *operation, pe_working_set_t *data_set) { char *key = NULL; const char *name = NULL; const char *value = NULL; const char *interval = NULL; const char *node_uname = NULL; int interval_ms = 0; action_t *mon = NULL; gboolean is_optional = TRUE; GListPtr possible_matches = NULL; crm_debug_2("Creating recurring action %s for %s", ID(operation), rsc->id); if(node != NULL) { node_uname = node->details->uname; } interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL); interval_ms = crm_get_msec(interval); if(interval_ms == 0) { return; } else if(interval_ms < 0) { crm_config_warn("%s contains an invalid interval: %s", ID(operation), interval); return; } value = crm_element_value(operation, "disabled"); if(crm_is_true(value)) { return; } name = crm_element_value(operation, "name"); if(is_op_dup(rsc, name, interval)) { return; } key = generate_op_key(rsc->id, name, interval_ms); if(start != NULL) { crm_debug_3("Marking %s %s due to %s", key, start->optional?"optional":"manditory", start->uuid); is_optional = start->optional; } else { crm_debug_2("Marking %s optional", key); is_optional = TRUE; } /* start a monitor for an already active resource */ possible_matches = find_actions_exact(rsc->actions, key, node); if(possible_matches == NULL) { is_optional = FALSE; crm_debug_3("Marking %s manditory: not active", key); } else { g_list_free(possible_matches); } value = crm_element_value(operation, "role"); if((rsc->next_role == RSC_ROLE_MASTER && value == NULL) || (value != NULL && text2role(value) != rsc->next_role)) { int log_level = LOG_DEBUG_2; const char *result = "Ignoring"; if(is_optional) { char *local_key = crm_strdup(key); log_level = LOG_INFO; result = "Cancelling"; /* its running : cancel it */ mon = custom_action( rsc, local_key, CRMD_ACTION_CANCEL, node, FALSE, TRUE, data_set); crm_free(mon->task); mon->task = crm_strdup(CRMD_ACTION_CANCEL); add_hash_param(mon->meta, XML_LRM_ATTR_INTERVAL, interval); add_hash_param(mon->meta, XML_LRM_ATTR_TASK, name); custom_action_order( rsc, NULL, mon, rsc, promote_key(rsc), NULL, pe_order_runnable_left, data_set); mon = NULL; } do_crm_log(log_level, "%s action %s (%s vs. %s)", result , key, value?value:role2text(RSC_ROLE_SLAVE), role2text(rsc->next_role)); crm_free(key); key = NULL; return; } mon = custom_action(rsc, key, name, node, is_optional, TRUE, data_set); key = mon->uuid; if(is_optional) { crm_debug_2("%s\t %s (optional)", crm_str(node_uname), mon->uuid); } if(start == NULL || start->runnable == FALSE) { crm_debug("%s\t %s (cancelled : start un-runnable)", crm_str(node_uname), mon->uuid); mon->runnable = FALSE; } else if(node == NULL || node->details->online == FALSE || node->details->unclean) { crm_debug("%s\t %s (cancelled : no node available)", crm_str(node_uname), mon->uuid); mon->runnable = FALSE; } else if(mon->optional == FALSE) { crm_notice("%s\t %s", crm_str(node_uname),mon->uuid); } custom_action_order(rsc, start_key(rsc), NULL, NULL, crm_strdup(key), mon, pe_order_implies_right|pe_order_runnable_left, data_set); if(rsc->next_role == RSC_ROLE_MASTER) { char *running_master = crm_itoa(EXECRA_RUNNING_MASTER); add_hash_param(mon->meta, XML_ATTR_TE_TARGET_RC, running_master); custom_action_order( rsc, promote_key(rsc), NULL, rsc, NULL, mon, pe_order_optional|pe_order_runnable_left, data_set); crm_free(running_master); } } void Recurring(resource_t *rsc, action_t *start, node_t *node, pe_working_set_t *data_set) { xml_child_iter_filter( rsc->ops_xml, operation, "op", RecurringOp(rsc, start, node, operation, data_set); ); } void native_create_actions(resource_t *rsc, pe_working_set_t *data_set) { action_t *start = NULL; node_t *chosen = NULL; enum rsc_role_e role = RSC_ROLE_UNKNOWN; enum rsc_role_e next_role = RSC_ROLE_UNKNOWN; crm_debug_2("Creating actions for %s", rsc->id); chosen = rsc->allocated_to; if(chosen != NULL) { CRM_CHECK(rsc->next_role != RSC_ROLE_UNKNOWN, rsc->next_role = RSC_ROLE_STARTED); } unpack_instance_attributes( rsc->xml, XML_TAG_ATTR_SETS, chosen?chosen->details->attrs:NULL, rsc->parameters, NULL, data_set->now); crm_debug_2("%s: %s->%s", rsc->id, role2text(rsc->role), role2text(rsc->next_role)); if(g_list_length(rsc->running_on) > 1) { if(rsc->recovery_type == recovery_stop_start) { pe_proc_err("Attempting recovery of resource %s", rsc->id); StopRsc(rsc, NULL, FALSE, data_set); rsc->role = RSC_ROLE_STOPPED; } } else if(rsc->running_on != NULL) { node_t *current = rsc->running_on->data; NoRoleChange(rsc, current, chosen, data_set); } else if(rsc->role == RSC_ROLE_STOPPED && rsc->next_role == RSC_ROLE_STOPPED) { char *key = start_key(rsc); GListPtr possible_matches = find_actions(rsc->actions, key, NULL); slist_iter( action, action_t, possible_matches, lpc, action->optional = TRUE; /* action->pseudo = TRUE; */ ); g_list_free(possible_matches); crm_debug_2("Stopping a stopped resource"); crm_free(key); return; } role = rsc->role; while(role != rsc->next_role) { next_role = rsc_state_matrix[role][rsc->next_role]; crm_debug_2("Executing: %s->%s (%s)", role2text(role), role2text(next_role), rsc->id); if(rsc_action_matrix[role][next_role]( rsc, chosen, FALSE, data_set) == FALSE) { break; } role = next_role; } if(rsc->next_role != RSC_ROLE_STOPPED && is_set(rsc->flags, pe_rsc_managed)) { start = start_action(rsc, chosen, TRUE); Recurring(rsc, start, chosen, data_set); } } void native_internal_constraints(resource_t *rsc, pe_working_set_t *data_set) { int type = pe_order_optional; const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); action_t *all_stopped = get_pseudo_op(ALL_STOPPED, data_set); if(rsc->variant == pe_native) { type |= pe_order_implies_right; } if(rsc->parent == NULL) { type |= pe_order_restart; } custom_action_order(rsc, stop_key(rsc), NULL, rsc, start_key(rsc), NULL, type, data_set); custom_action_order(rsc, demote_key(rsc), NULL, rsc, stop_key(rsc), NULL, pe_order_optional, data_set); custom_action_order(rsc, start_key(rsc), NULL, rsc, promote_key(rsc), NULL, pe_order_runnable_left, data_set); custom_action_order( rsc, delete_key(rsc), NULL, rsc, start_key(rsc), NULL, pe_order_optional, data_set); if(is_set(rsc->flags, pe_rsc_notify)) { char *key1 = NULL; char *key2 = NULL; key1 = generate_op_key(rsc->id, "confirmed-post_notify_start", 0); key2 = generate_op_key(rsc->id, "pre_notify_promote", 0); custom_action_order( rsc, key1, NULL, rsc, key2, NULL, pe_order_optional, data_set); key1 = generate_op_key(rsc->id, "confirmed-post_notify_demote", 0); key2 = generate_op_key(rsc->id, "pre_notify_stop", 0); custom_action_order( rsc, key1, NULL, rsc, key2, NULL, pe_order_optional, data_set); } if(is_not_set(rsc->flags, pe_rsc_managed)) { crm_debug_3("Skipping fencing constraints for unmanaged resource: %s", rsc->id); return; } if(rsc->variant == pe_native && safe_str_neq(class, "stonith")) { custom_action_order( rsc, stop_key(rsc), NULL, NULL, crm_strdup(all_stopped->task), all_stopped, pe_order_implies_right|pe_order_runnable_left, data_set); } } void native_rsc_colocation_lh( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { if(rsc_lh == NULL) { pe_err("rsc_lh was NULL for %s", constraint->id); return; } else if(constraint->rsc_rh == NULL) { pe_err("rsc_rh was NULL for %s", constraint->id); return; } crm_debug_2("Processing colocation constraint between %s and %s", rsc_lh->id, rsc_rh->id); rsc_rh->cmds->rsc_colocation_rh(rsc_lh, rsc_rh, constraint); } static gboolean filter_colocation_constraint( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { if(constraint->score == 0){ return FALSE; } if(constraint->score > 0 && constraint->role_lh != RSC_ROLE_UNKNOWN && constraint->role_lh != rsc_lh->next_role) { crm_debug_4("LH: Skipping constraint: \"%s\" state filter", role2text(constraint->role_rh)); return FALSE; } if(constraint->score > 0 && constraint->role_rh != RSC_ROLE_UNKNOWN && constraint->role_rh != rsc_rh->next_role) { crm_debug_4("RH: Skipping constraint: \"%s\" state filter", role2text(constraint->role_rh)); return FALSE; } if(constraint->score < 0 && constraint->role_lh != RSC_ROLE_UNKNOWN && constraint->role_lh == rsc_lh->next_role) { crm_debug_4("LH: Skipping -ve constraint: \"%s\" state filter", role2text(constraint->role_rh)); return FALSE; } if(constraint->score < 0 && constraint->role_rh != RSC_ROLE_UNKNOWN && constraint->role_rh == rsc_rh->next_role) { crm_debug_4("RH: Skipping -ve constraint: \"%s\" state filter", role2text(constraint->role_rh)); return FALSE; } return TRUE; } static void colocation_match( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { const char *tmp = NULL; const char *value = NULL; gboolean do_check = FALSE; const char *attribute = "#id"; if(constraint->node_attribute != NULL) { attribute = constraint->node_attribute; } if(rsc_rh->allocated_to) { value = g_hash_table_lookup( rsc_rh->allocated_to->details->attrs, attribute); do_check = TRUE; } else if(constraint->score < 0) { /* nothing to do: * anti-colocation with something thats not running */ return; } slist_iter( node, node_t, rsc_lh->allowed_nodes, lpc, tmp = g_hash_table_lookup(node->details->attrs, attribute); if(do_check && safe_str_eq(tmp, value)) { crm_debug_2("%s: %s.%s += %d", constraint->id, rsc_lh->id, node->details->uname, constraint->score); node->weight = merge_weights( constraint->score, node->weight); } else if(do_check == FALSE || constraint->score >= INFINITY) { crm_debug_2("%s: %s.%s = -INFINITY (%s)", constraint->id, rsc_lh->id, node->details->uname, do_check?"failed":"unallocated"); node->weight = -INFINITY; } ); } void native_rsc_colocation_rh( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { crm_debug_2("%sColocating %s with %s (%s, weight=%d)", constraint->score >= 0?"":"Anti-", rsc_lh->id, rsc_rh->id, constraint->id, constraint->score); if(filter_colocation_constraint(rsc_lh, rsc_rh, constraint) == FALSE) { return; } if(is_set(rsc_rh->flags, pe_rsc_provisional)) { return; } else if(is_not_set(rsc_lh->flags, pe_rsc_provisional)) { /* error check */ struct node_shared_s *details_lh; struct node_shared_s *details_rh; if((constraint->score > -INFINITY) && (constraint->score < INFINITY)) { return; } details_rh = rsc_rh->allocated_to?rsc_rh->allocated_to->details:NULL; details_lh = rsc_lh->allocated_to?rsc_lh->allocated_to->details:NULL; if(constraint->score == INFINITY && details_lh != details_rh) { crm_err("%s and %s are both allocated" " but to different nodes: %s vs. %s", rsc_lh->id, rsc_rh->id, details_lh?details_lh->uname:"n/a", details_rh?details_rh->uname:"n/a"); } else if(constraint->score == -INFINITY && details_lh == details_rh) { crm_err("%s and %s are both allocated" " but to the SAME node: %s", rsc_lh->id, rsc_rh->id, details_rh?details_rh->uname:"n/a"); } return; } else { colocation_match(rsc_lh, rsc_rh, constraint); } } void node_list_update(GListPtr list1, GListPtr list2, int factor) { node_t *other_node = NULL; slist_iter( node, node_t, list1, lpc, if(node == NULL) { continue; } other_node = (node_t*)pe_find_node_id( list2, node->details->id); if(other_node != NULL) { crm_debug_2("%s: %d + %d", node->details->uname, node->weight, other_node->weight); node->weight = merge_weights( factor*other_node->weight, node->weight); } ); } void native_rsc_order_lh(resource_t *lh_rsc, order_constraint_t *order, pe_working_set_t *data_set) { GListPtr lh_actions = NULL; action_t *lh_action = order->lh_action; resource_t *rh_rsc = order->rh_rsc; crm_debug_2("Processing LH of ordering constraint %d", order->id); CRM_ASSERT(lh_rsc != NULL); if(lh_action != NULL) { lh_actions = g_list_append(NULL, lh_action); } else if(lh_action == NULL) { lh_actions = find_actions( lh_rsc->actions, order->lh_action_task, NULL); } if(lh_actions == NULL && lh_rsc != rh_rsc) { char *key = NULL; char *rsc_id = NULL; char *op_type = NULL; int interval = 0; crm_debug_2("No LH-Side (%s/%s) found for constraint %d with %s - creating", lh_rsc->id, order->lh_action_task, order->id, order->rh_action_task); parse_op_key( order->lh_action_task, &rsc_id, &op_type, &interval); key = generate_op_key(lh_rsc->id, op_type, interval); lh_action = custom_action(lh_rsc, key, op_type, NULL, TRUE, TRUE, data_set); if(lh_rsc->fns->state(lh_rsc, TRUE) == RSC_ROLE_STOPPED && safe_str_eq(op_type, CRMD_ACTION_STOP)) { lh_action->pseudo = TRUE; lh_action->runnable = TRUE; } lh_actions = g_list_append(NULL, lh_action); crm_free(op_type); crm_free(rsc_id); } slist_iter( lh_action_iter, action_t, lh_actions, lpc, if(rh_rsc == NULL && order->rh_action) { rh_rsc = order->rh_action->rsc; } if(rh_rsc) { rh_rsc->cmds->rsc_order_rh( lh_action_iter, rh_rsc, order); } else if(order->rh_action) { order_actions( lh_action_iter, order->rh_action, order->type); } ); pe_free_shallow_adv(lh_actions, FALSE); } void native_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order) { GListPtr rh_actions = NULL; action_t *rh_action = NULL; CRM_CHECK(rsc != NULL, return); CRM_CHECK(order != NULL, return); rh_action = order->rh_action; crm_debug_3("Processing RH of ordering constraint %d", order->id); if(rh_action != NULL) { rh_actions = g_list_append(NULL, rh_action); } else if(rsc != NULL) { rh_actions = find_actions( rsc->actions, order->rh_action_task, NULL); } if(rh_actions == NULL) { crm_debug_4("No RH-Side (%s/%s) found for constraint..." " ignoring", rsc->id,order->rh_action_task); if(lh_action) { crm_debug_4("LH-Side was: %s", lh_action->uuid); } return; } slist_iter( rh_action_iter, action_t, rh_actions, lpc, if(lh_action) { order_actions(lh_action, rh_action_iter, order->type); } else if(order->type & pe_order_implies_right) { rh_action_iter->runnable = FALSE; crm_warn("Unrunnable %s 0x%.6x", rh_action_iter->uuid, order->type); } else { crm_warn("neither %s 0x%.6x", rh_action_iter->uuid, order->type); } ); pe_free_shallow_adv(rh_actions, FALSE); } void native_rsc_location(resource_t *rsc, rsc_to_node_t *constraint) { GListPtr or_list; crm_debug_2("Applying %s (%s) to %s", constraint->id, role2text(constraint->role_filter), rsc->id); /* take "lifetime" into account */ if(constraint == NULL) { pe_err("Constraint is NULL"); return; } else if(rsc == NULL) { pe_err("LHS of rsc_to_node (%s) is NULL", constraint->id); return; } else if(constraint->role_filter > 0 && constraint->role_filter != rsc->next_role) { crm_debug("Constraint (%s) is not active (role : %s)", constraint->id, role2text(constraint->role_filter)); return; } else if(is_active(constraint) == FALSE) { crm_debug_2("Constraint (%s) is not active", constraint->id); return; } if(constraint->node_list_rh == NULL) { crm_debug_2("RHS of constraint %s is NULL", constraint->id); return; } or_list = node_list_or( rsc->allowed_nodes, constraint->node_list_rh, FALSE); pe_free_shallow(rsc->allowed_nodes); rsc->allowed_nodes = or_list; slist_iter(node, node_t, or_list, lpc, crm_debug_3("%s + %s : %d", rsc->id, node->details->uname, node->weight); ); } void native_expand(resource_t *rsc, pe_working_set_t *data_set) { crm_debug_3("Processing actions from %s", rsc->id); slist_iter( action, action_t, rsc->actions, lpc, crm_debug_4("processing action %d for rsc=%s", action->id, rsc->id); graph_element_from_action(action, data_set); ); slist_iter( child_rsc, resource_t, rsc->children, lpc, child_rsc->cmds->expand(child_rsc, data_set); ); } void create_notifications(resource_t *rsc, pe_working_set_t *data_set) { } static void register_activity(resource_t *rsc, enum action_tasks task, node_t *node, notify_data_t *n_data) { notify_entry_t *entry = NULL; CRM_CHECK(node != NULL, crm_err("%s has no node for required action %s", rsc->id, task2text(task)); return); crm_malloc0(entry, sizeof(notify_entry_t)); entry->rsc = rsc; entry->node = node; switch(task) { case start_rsc: n_data->start = g_list_append(n_data->start, entry); break; case stop_rsc: n_data->stop = g_list_append(n_data->stop, entry); break; case action_promote: n_data->promote = g_list_append(n_data->promote, entry); break; case action_demote: n_data->demote = g_list_append(n_data->demote, entry); break; default: crm_err("Unsupported notify action: %s", task2text(task)); crm_free(entry); break; } } static void register_state(resource_t *rsc, node_t *on_node, notify_data_t *n_data) { notify_entry_t *entry = NULL; crm_malloc0(entry, sizeof(notify_entry_t)); entry->rsc = rsc; entry->node = on_node; crm_debug_2("%s state: %s", rsc->id, role2text(rsc->next_role)); switch(rsc->next_role) { case RSC_ROLE_STOPPED: /* n_data->inactive = g_list_append(n_data->inactive, entry); */ crm_free(entry); break; case RSC_ROLE_STARTED: n_data->active = g_list_append(n_data->active, entry); break; case RSC_ROLE_SLAVE: n_data->slave = g_list_append(n_data->slave, entry); break; case RSC_ROLE_MASTER: n_data->master = g_list_append(n_data->master, entry); break; default: crm_err("Unsupported notify role"); crm_free(entry); break; } } void complex_create_notify_element(resource_t *rsc, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set) { node_t *next_node = NULL; gboolean registered = FALSE; char *op_key = NULL; GListPtr possible_matches = NULL; enum action_tasks task = text2task(op->task); if(rsc->children) { slist_iter( child_rsc, resource_t, rsc->children, lpc, child_rsc->cmds->create_notify_element( child_rsc, op, n_data, data_set); ); return; } if(op->pre_notify == NULL || op->post_notify == NULL) { /* no notifications required */ crm_debug_4("No notificaitons required for %s", op->task); return; } next_node = rsc->allocated_to; op_key = generate_op_key(rsc->id, op->task, 0); possible_matches = find_actions(rsc->actions, op_key, NULL); crm_debug_2("Creating notificaitons for: %s (%s->%s)", op->uuid, role2text(rsc->role), role2text(rsc->next_role)); if(rsc->role == rsc->next_role) { register_state(rsc, next_node, n_data); } slist_iter( local_op, action_t, possible_matches, lpc, local_op->notify_keys = n_data->keys; if(local_op->optional == FALSE) { registered = TRUE; register_activity(rsc, task, local_op->node, n_data); } ); /* stop / demote */ if(rsc->role != RSC_ROLE_STOPPED) { if(task == stop_rsc || task == action_demote) { slist_iter( current_node, node_t, rsc->running_on, lpc, pe_pre_notify(rsc, current_node, op, n_data, data_set); if(task == action_demote || registered == FALSE) { pe_post_notify(rsc, current_node, op, n_data, data_set); } ); } } /* start / promote */ if(rsc->next_role != RSC_ROLE_STOPPED) { CRM_CHECK(next_node != NULL,;); if(next_node == NULL) { pe_proc_err("next role: %s", role2text(rsc->next_role)); } else if(task == start_rsc || task == action_promote) { if(task != start_rsc || registered == FALSE) { pe_pre_notify(rsc, next_node, op, n_data, data_set); } pe_post_notify(rsc, next_node, op, n_data, data_set); } } crm_free(op_key); g_list_free(possible_matches); } static void dup_attr(gpointer key, gpointer value, gpointer user_data) { char *meta_key = crm_concat(CRM_META, key, '_'); g_hash_table_replace(user_data, meta_key, crm_strdup(value)); } static action_t * pe_notify(resource_t *rsc, node_t *node, action_t *op, action_t *confirm, notify_data_t *n_data, pe_working_set_t *data_set) { char *key = NULL; action_t *trigger = NULL; const char *value = NULL; const char *task = NULL; if(op == NULL || confirm == NULL) { crm_debug_2("Op=%p confirm=%p", op, confirm); return NULL; } CRM_CHECK(node != NULL, return NULL); if(node->details->online == FALSE) { crm_debug_2("Skipping notification for %s: node offline", rsc->id); return NULL; } else if(op->runnable == FALSE) { crm_debug_2("Skipping notification for %s: not runnable", op->uuid); return NULL; } value = g_hash_table_lookup(op->meta, "notify_type"); task = g_hash_table_lookup(op->meta, "notify_operation"); crm_debug("Creating notify actions for %s: %s (%s-%s)", op->uuid, rsc->id, value, task); key = generate_notify_key(rsc->id, value, task); trigger = custom_action(rsc, key, op->task, node, op->optional, TRUE, data_set); g_hash_table_foreach(op->meta, dup_attr, trigger->extra); trigger->notify_keys = n_data->keys; /* pseudo_notify before notify */ crm_debug_3("Ordering %s before %s (%d->%d)", op->uuid, trigger->uuid, trigger->id, op->id); order_actions(op, trigger, pe_order_implies_left); value = g_hash_table_lookup(op->meta, "notify_confirm"); if(crm_is_true(value)) { /* notify before pseudo_notified */ crm_debug_3("Ordering %s before %s (%d->%d)", trigger->uuid, confirm->uuid, confirm->id, trigger->id); order_actions(trigger, confirm, pe_order_implies_left); } return trigger; } void pe_pre_notify(resource_t *rsc, node_t *node, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set) { crm_debug_2("%s: %s", rsc->id, op->uuid); pe_notify(rsc, node, op->pre_notify, op->pre_notified, n_data, data_set); } void pe_post_notify(resource_t *rsc, node_t *node, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set) { action_t *notify = NULL; CRM_CHECK(op != NULL, return); CRM_CHECK(rsc != NULL, return); crm_debug_2("%s: %s", rsc->id, op->uuid); notify = pe_notify(rsc, node, op->post_notify, op->post_notified, n_data, data_set); if(notify != NULL) { /* crm_err("Upgrading priority for %s to INFINITY", notify->uuid); */ notify->priority = INFINITY; } notify = op->post_notified; if(notify != NULL) { slist_iter( mon, action_t, rsc->actions, lpc, const char *interval = g_hash_table_lookup(mon->meta, "interval"); if(interval == NULL || safe_str_eq(interval, "0")) { crm_debug_3("Skipping %s: interval", mon->uuid); continue; } else if(safe_str_eq(mon->task, "cancel")) { crm_debug_3("Skipping %s: cancel", mon->uuid); continue; } order_actions(notify, mon, pe_order_optional); ); } } void NoRoleChange(resource_t *rsc, node_t *current, node_t *next, pe_working_set_t *data_set) { action_t *stop = NULL; action_t *start = NULL; GListPtr possible_matches = NULL; crm_debug_2("Executing: %s (role=%s)",rsc->id, role2text(rsc->next_role)); if(current == NULL || next == NULL) { return; } if(is_set(rsc->flags, pe_rsc_failed) || safe_str_neq(current->details->id, next->details->id)) { if(is_set(rsc->flags, pe_rsc_failed)) { crm_notice("Recover resource %s\t(%s)", rsc->id, next->details->uname); } else { crm_notice("Move resource %s\t(%s -> %s)", rsc->id, current->details->uname, next->details->uname); } if(rsc->next_role > RSC_ROLE_STARTED) { gboolean optional = TRUE; if(rsc->role == RSC_ROLE_MASTER) { optional = FALSE; } DemoteRsc(rsc, current, optional, data_set); } if(rsc->role == RSC_ROLE_MASTER) { DemoteRsc(rsc, current, FALSE, data_set); } StopRsc(rsc, current, FALSE, data_set); StartRsc(rsc, next, FALSE, data_set); if(rsc->next_role == RSC_ROLE_MASTER) { PromoteRsc(rsc, next, FALSE, data_set); } possible_matches = find_recurring_actions(rsc->actions, next); slist_iter(match, action_t, possible_matches, lpc, if(match->optional == FALSE) { crm_debug("Fixing recurring action: %s", match->uuid); match->optional = TRUE; } ); g_list_free(possible_matches); } else if(is_set(rsc->flags, pe_rsc_start_pending)) { action_t *start = start_action(rsc, next, TRUE); if(start->runnable) { /* wait for StartRsc() to be called */ rsc->role = RSC_ROLE_STOPPED; } else { /* wait for StopRsc() to be called */ rsc->next_role = RSC_ROLE_STOPPED; } } else { stop = stop_action(rsc, current, TRUE); start = start_action(rsc, next, TRUE); stop->optional = start->optional; if(rsc->next_role > RSC_ROLE_STARTED) { DemoteRsc(rsc, current, start->optional, data_set); } StopRsc(rsc, current, start->optional, data_set); StartRsc(rsc, current, start->optional, data_set); if(rsc->next_role == RSC_ROLE_MASTER) { PromoteRsc(rsc, next, start->optional, data_set); } if(start->runnable == FALSE) { rsc->next_role = RSC_ROLE_STOPPED; } else if(start->optional) { crm_notice("Leave resource %s\t(%s)", rsc->id, next->details->uname); } else { crm_notice("Restart resource %s\t(%s)", rsc->id, next->details->uname); } } } gboolean StopRsc(resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set) { action_t *stop = NULL; const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); crm_debug_2("Executing: %s", rsc->id); if(rsc->next_role == RSC_ROLE_STOPPED && rsc->variant == pe_native && safe_str_eq(class, "stonith")) { action_t *all_stopped = get_pseudo_op(ALL_STOPPED, data_set); custom_action_order( NULL, crm_strdup(all_stopped->task), all_stopped, rsc, stop_key(rsc), NULL, pe_order_implies_left|pe_order_stonith_stop, data_set); } slist_iter( current, node_t, rsc->running_on, lpc, stop = stop_action(rsc, current, optional); if(stop->runnable && stop->optional == FALSE) { crm_notice(" %s\tStop %s",current->details->uname,rsc->id); } if(data_set->remove_after_stop) { DeleteRsc(rsc, current, optional, data_set); } ); return TRUE; } gboolean StartRsc(resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set) { action_t *start = NULL; crm_debug_2("Executing: %s", rsc->id); start = start_action(rsc, next, TRUE); if(start->runnable && optional == FALSE) { crm_notice(" %s\tStart %s", next->details->uname, rsc->id); start->optional = FALSE; } return TRUE; } gboolean PromoteRsc(resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set) { char *key = NULL; gboolean runnable = TRUE; GListPtr action_list = NULL; crm_debug_2("Executing: %s", rsc->id); CRM_CHECK(rsc->next_role == RSC_ROLE_MASTER, crm_err("Next role: %s", role2text(rsc->next_role)); return FALSE); CRM_CHECK(next != NULL, return FALSE); key = start_key(rsc); action_list = find_actions_exact(rsc->actions, key, next); crm_free(key); slist_iter(start, action_t, action_list, lpc, if(start->runnable == FALSE) { runnable = FALSE; } ); g_list_free(action_list); if(runnable) { promote_action(rsc, next, optional); if(optional == FALSE) { crm_notice("%s\tPromote %s", next->details->uname, rsc->id); } return TRUE; } crm_debug("%s\tPromote %s (canceled)", next->details->uname, rsc->id); key = promote_key(rsc); action_list = find_actions_exact(rsc->actions, key, next); crm_free(key); slist_iter(promote, action_t, action_list, lpc, promote->runnable = FALSE; ); g_list_free(action_list); return TRUE; } gboolean DemoteRsc(resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set) { crm_debug_2("Executing: %s", rsc->id); /* CRM_CHECK(rsc->next_role == RSC_ROLE_SLAVE, return FALSE); */ slist_iter( current, node_t, rsc->running_on, lpc, crm_notice("%s\tDemote %s", current->details->uname, rsc->id); demote_action(rsc, current, optional); ); return TRUE; } gboolean RoleError(resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set) { crm_debug("Executing: %s", rsc->id); CRM_CHECK(FALSE, return FALSE); return FALSE; } gboolean NullOp(resource_t *rsc, node_t *next, gboolean optional, pe_working_set_t *data_set) { crm_debug("Executing: %s", rsc->id); return FALSE; } gboolean DeleteRsc(resource_t *rsc, node_t *node, gboolean optional, pe_working_set_t *data_set) { action_t *delete = NULL; #if DELETE_THEN_REFRESH action_t *refresh = NULL; #endif if(is_set(rsc->flags, pe_rsc_failed)) { crm_debug_2("Resource %s not deleted from %s: failed", rsc->id, node->details->uname); return FALSE; } else if(node == NULL) { crm_debug_2("Resource %s not deleted: NULL node", rsc->id); return FALSE; } else if(node->details->unclean || node->details->online == FALSE) { crm_debug_2("Resource %s not deleted from %s: unrunnable", rsc->id, node->details->uname); return FALSE; } crm_notice("Removing %s from %s", rsc->id, node->details->uname); delete = delete_action(rsc, node, optional); custom_action_order( rsc, stop_key(rsc), NULL, rsc, delete_key(rsc), NULL, optional?pe_order_implies_right:pe_order_implies_left, data_set); #if DELETE_THEN_REFRESH refresh = custom_action( NULL, crm_strdup(CRM_OP_LRM_REFRESH), CRM_OP_LRM_REFRESH, node, FALSE, TRUE, data_set); add_hash_param(refresh->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); order_actions(delete, refresh, pe_order_optional); #endif return TRUE; } gboolean native_create_probe(resource_t *rsc, node_t *node, action_t *complete, gboolean force, pe_working_set_t *data_set) { char *key = NULL; char *target_rc = NULL; action_t *probe = NULL; node_t *running = NULL; CRM_CHECK(node != NULL, return FALSE); if(rsc->children) { gboolean any_created = FALSE; slist_iter( child_rsc, resource_t, rsc->children, lpc, any_created = child_rsc->cmds->create_probe( child_rsc, node, complete, force, data_set) || any_created; ); return any_created; } if(is_set(rsc->flags, pe_rsc_orphan)) { crm_debug_2("Skipping orphan: %s", rsc->id); return FALSE; } running = pe_find_node_id(rsc->known_on, node->details->id); if(force == FALSE && running != NULL) { /* we already know the status of the resource on this node */ crm_debug_3("Skipping active: %s", rsc->id); return FALSE; } key = generate_op_key(rsc->id, CRMD_ACTION_STATUS, 0); probe = custom_action(rsc, key, CRMD_ACTION_STATUS, node, FALSE, TRUE, data_set); probe->optional = FALSE; running = pe_find_node_id(rsc->running_on, node->details->id); if(running == NULL) { target_rc = crm_itoa(EXECRA_NOT_RUNNING); } else if(rsc->role == RSC_ROLE_MASTER) { target_rc = crm_itoa(EXECRA_RUNNING_MASTER); } if(target_rc != NULL) { add_hash_param(probe->meta, XML_ATTR_TE_TARGET_RC, target_rc); crm_free(target_rc); } crm_debug_2("Probing %s on %s (%s)", rsc->id, node->details->uname, role2text(rsc->role)); custom_action_order(rsc, NULL, probe, rsc, NULL, complete, pe_order_implies_right, data_set); return TRUE; } static void native_start_constraints( resource_t *rsc, action_t *stonith_op, gboolean is_stonith, pe_working_set_t *data_set) { node_t *target = stonith_op?stonith_op->node:NULL; if(is_stonith) { char *key = start_key(rsc); action_t *ready = get_pseudo_op(STONITH_UP, data_set); crm_debug_2("Ordering %s action before stonith events", key); custom_action_order( rsc, key, NULL, NULL, crm_strdup(ready->task), ready, pe_order_implies_right, data_set); } else { action_t *all_stopped = get_pseudo_op(ALL_STOPPED, data_set); slist_iter(action, action_t, rsc->actions, lpc2, if(action->needs == rsc_req_stonith) { order_actions(all_stopped, action, pe_order_implies_left); } else if(target != NULL && target->details->expected_up && safe_str_eq(action->task, CRMD_ACTION_START) && NULL == pe_find_node_id( rsc->known_on, target->details->id)) { /* if expected_up == TRUE, then we've seen * the node before and it has failed (as * opposed to just hasn't started up yet) * * if known == NULL, then we dont know if * the resource is active on the node * we're about to shoot * * in this case, regardless of action->needs, * the only safe option is to wait until * the node is shot before doing anything * to with the resource * * its analogous to waiting for all the probes * for rscX to complete before starting rscX * * the most likely explaination is that the * DC died and took its status with it */ crm_info("Ordering %s after %s recovery", action->uuid, target->details->uname); order_actions(all_stopped, action, pe_order_implies_left|pe_order_runnable_left); } ); } } static void native_stop_constraints( resource_t *rsc, action_t *stonith_op, gboolean is_stonith, pe_working_set_t *data_set) { char *key = NULL; GListPtr action_list = NULL; node_t *node = stonith_op->node; key = stop_key(rsc); action_list = find_actions(rsc->actions, key, node); crm_free(key); /* add the stonith OP as a stop pre-req and the mark the stop * as a pseudo op - since its now redundant */ slist_iter( action, action_t, action_list, lpc2, resource_t *parent = NULL; if(node->details->online && node->details->unclean == FALSE && is_set(rsc->flags, pe_rsc_failed)) { continue; } if(is_set(rsc->flags, pe_rsc_failed)) { crm_warn("Stop of failed resource %s is" " implicit after %s is fenced", rsc->id, node->details->uname); } else { crm_info("%s is implicit after %s is fenced", action->uuid, node->details->uname); } /* the stop would never complete and is * now implied by the stonith operation */ action->pseudo = TRUE; action->runnable = TRUE; action->implied_by_stonith = TRUE; if(is_stonith == FALSE) { order_actions(stonith_op, action, pe_order_optional); } /* find the top-most resource */ parent = rsc->parent; while(parent != NULL && parent->parent != NULL) { parent = parent->parent; } if(parent) { crm_info("Re-creating actions for %s", parent->id); parent->cmds->create_actions(parent, data_set); /* make sure we dont mess anything up in create_actions */ CRM_CHECK(action->pseudo, action->pseudo = TRUE); CRM_CHECK(action->runnable, action->runnable = TRUE); } /* From Bug #1601, successful fencing must be an input to a failed resources stop action. However given group(A, B) running on nodeX and B.stop has failed, A := stop healthy resource (A.stop) B := stop failed resource (pseudo operation B.stop) C := stonith nodeX A requires B, B requires C, C requires A This loop would prevent the cluster from making progress. This block creates the "C requires A" dependancy and therefore must (at least for now) be disabled. Instead, run the block above and treat all resources on nodeX as B would be (marked as a pseudo op depending on the STONITH). } else if(is_stonith == FALSE) { crm_info("Moving healthy resource %s" " off %s before fencing", rsc->id, node->details->uname); * stop healthy resources before the * stonith op * custom_action_order( rsc, stop_key(rsc), NULL, NULL,crm_strdup(CRM_OP_FENCE),stonith_op, pe_order_optional, data_set); */ ); g_list_free(action_list); key = demote_key(rsc); action_list = find_actions(rsc->actions, key, node); crm_free(key); slist_iter( action, action_t, action_list, lpc2, if(node->details->online == FALSE || is_set(rsc->flags, pe_rsc_failed)) { crm_info("Demote of failed resource %s is" " implict after %s is fenced", rsc->id, node->details->uname); /* the stop would never complete and is * now implied by the stonith operation */ action->pseudo = TRUE; action->runnable = TRUE; if(is_stonith == FALSE) { order_actions(stonith_op, action, pe_order_optional); } } ); g_list_free(action_list); } void complex_stonith_ordering( resource_t *rsc, action_t *stonith_op, pe_working_set_t *data_set) { gboolean is_stonith = FALSE; const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); if(rsc->children) { slist_iter( child_rsc, resource_t, rsc->children, lpc, child_rsc->cmds->stonith_ordering( child_rsc, stonith_op, data_set); ); return; } if(is_not_set(rsc->flags, pe_rsc_managed)) { crm_debug_3("Skipping fencing constraints for unmanaged resource: %s", rsc->id); return; } if(stonith_op != NULL && safe_str_eq(class, "stonith")) { is_stonith = TRUE; } /* Start constraints */ native_start_constraints(rsc, stonith_op, is_stonith, data_set); /* Stop constraints */ native_stop_constraints(rsc, stonith_op, is_stonith, data_set); } #define ALLOW_WEAK_MIGRATION 0 static gboolean check_stack_element(resource_t *rsc, resource_t *other_rsc, const char *type) { char *key = NULL; int level = LOG_DEBUG; GListPtr action_list = NULL; if(other_rsc == NULL || other_rsc == rsc) { return TRUE; } do_crm_log(level+1, "%s: processing %s (%s)", rsc->id, other_rsc->id, type); if(other_rsc->variant == pe_native) { do_crm_log(level, "%s: depends on %s (mid-stack) %s", rsc->id, other_rsc->id, type); return FALSE; } else if(other_rsc->variant == pe_group) { if(at_stack_bottom(other_rsc) == FALSE) { do_crm_log(level, "%s: depends on group %s (mid-stack) %s", rsc->id, other_rsc->id, type); return FALSE; } return TRUE; } /* is the clone also moving moved around? * * if so, then we can't yet be completely sure the * resource can safely migrate since the node we're * moving too may not have the clone instance started * yet * * in theory we can figure out if the clone instance we * will run on is already there, but there that would * involve too much knowledge of internal clone code. * maybe later... */ do_crm_log(level+1,"%s: start depends on clone %s", rsc->id, other_rsc->id); key = stop_key(other_rsc); action_list = find_actions(other_rsc->actions, key, NULL); crm_free(key); slist_iter( other_stop, action_t, action_list,lpc, if(other_stop && other_stop->optional == FALSE) { do_crm_log(level, "%s: start depends on %s", rsc->id, other_stop->uuid); g_list_free(action_list); return FALSE; } ); g_list_free(action_list); return TRUE; } gboolean at_stack_bottom(resource_t *rsc) { char *key = NULL; action_t *start = NULL; action_t *other = NULL; GListPtr action_list = NULL; key = start_key(rsc); action_list = find_actions(rsc->actions, key, NULL); crm_free(key); crm_debug_3("%s: processing", rsc->id); CRM_CHECK(action_list != NULL, return FALSE); start = action_list->data; g_list_free(action_list); slist_iter( constraint, rsc_colocation_t, rsc->rsc_cons, lpc, resource_t *target = constraint->rsc_rh; crm_debug_4("%s == %s (%d)", rsc->id, target->id, constraint->score); if(constraint->score > 0 && check_stack_element(rsc, target, "coloc") == FALSE) { return FALSE; } ); slist_iter( other_w, action_wrapper_t, start->actions_before, lpc, other = other_w->action; #if ALLOW_WEAK_MIGRATION if((other_w->type & pe_order_implies_right) == 0) { crm_debug_3("%s: depends on %s (optional ordering)", rsc->id, other->uuid); continue; } #endif if(other->optional == FALSE && check_stack_element(rsc, other->rsc, "order") == FALSE) { return FALSE; } ); return TRUE; } void complex_migrate_reload(resource_t *rsc, pe_working_set_t *data_set) { char *key = NULL; int level = LOG_DEBUG; GListPtr action_list = NULL; action_t *stop = NULL; action_t *start = NULL; action_t *other = NULL; action_t *action = NULL; const char *value = NULL; if(rsc->children) { slist_iter( child_rsc, resource_t, rsc->children, lpc, child_rsc->cmds->migrate_reload(child_rsc, data_set); ); other = NULL; return; } do_crm_log(level+1, "Processing %s", rsc->id); CRM_CHECK(rsc->variant == pe_native, return); if(is_not_set(rsc->flags, pe_rsc_managed) || is_set(rsc->flags, pe_rsc_failed) || is_set(rsc->flags, pe_rsc_start_pending) || rsc->next_role != RSC_ROLE_STARTED || g_list_length(rsc->running_on) != 1) { do_crm_log(level+1, "%s: general resource state", rsc->id); return; } key = start_key(rsc); action_list = find_actions(rsc->actions, key, NULL); crm_free(key); if(action_list == NULL) { do_crm_log(level, "%s: no start action", rsc->id); return; } start = action_list->data; g_list_free(action_list); value = g_hash_table_lookup(rsc->meta, "allow_migrate"); if(crm_is_true(value)) { set_bit(rsc->flags, pe_rsc_can_migrate); } if(is_not_set(rsc->flags, pe_rsc_can_migrate) && start->allow_reload_conversion == FALSE) { do_crm_log(level+1, "%s: no need to continue", rsc->id); return; } key = stop_key(rsc); action_list = find_actions(rsc->actions, key, NULL); crm_free(key); if(action_list == NULL) { do_crm_log(level, "%s: no stop action", rsc->id); return; } stop = action_list->data; g_list_free(action_list); action = start; if(action->pseudo || action->optional || action->node == NULL || action->runnable == FALSE) { do_crm_log(level, "%s: %s", rsc->id, action->task); return; } action = stop; if(action->pseudo || action->optional || action->node == NULL || action->runnable == FALSE) { do_crm_log(level, "%s: %s", rsc->id, action->task); return; } if(is_set(rsc->flags, pe_rsc_can_migrate)) { if(start->node == NULL || stop->node == NULL || stop->node->details == start->node->details) { clear_bit(rsc->flags, pe_rsc_can_migrate); } else if(at_stack_bottom(rsc) == FALSE) { crm_notice("Cannot migrate %s from %s to %s" " - %s is not at the bottom of the resource stack", rsc->id, stop->node->details->uname, start->node->details->uname, rsc->id); clear_bit(rsc->flags, pe_rsc_can_migrate); } } if(is_set(rsc->flags, pe_rsc_can_migrate)) { crm_notice("Migrating %s from %s to %s", rsc->id, stop->node->details->uname, start->node->details->uname); crm_free(stop->uuid); crm_free(stop->task); stop->task = crm_strdup(CRMD_ACTION_MIGRATE); stop->uuid = generate_op_key(rsc->id, stop->task, 0); add_hash_param(stop->meta, "migrate_source", stop->node->details->uname); add_hash_param(stop->meta, "migrate_target", start->node->details->uname); /* Hook up to the all_stopped and shutdown actions */ slist_iter( other_w, action_wrapper_t, stop->actions_after, lpc, other = other_w->action; if(other->optional == FALSE && other->rsc == NULL) { order_actions(start, other, other_w->type); } ); slist_iter( other_w, action_wrapper_t, start->actions_before, lpc, other = other_w->action; if(other->optional == FALSE #if ALLOW_WEAK_MIGRATION && (other_w->type & pe_order_implies_right) #endif && other->rsc != NULL && other->rsc != rsc->parent && other->rsc != rsc) { do_crm_log(level, "Ordering %s before %s", other->uuid, stop->uuid); order_actions(other, stop, other_w->type); } ); crm_free(start->uuid); crm_free(start->task); start->task = crm_strdup(CRMD_ACTION_MIGRATED); start->uuid = generate_op_key(rsc->id, start->task, 0); add_hash_param(start->meta, "migrate_source_uuid", stop->node->details->id); add_hash_param(start->meta, "migrate_source", stop->node->details->uname); add_hash_param(start->meta, "migrate_target", start->node->details->uname); } else if(start->allow_reload_conversion && stop->node->details == start->node->details) { crm_info("Rewriting restart of %s on %s as a reload", rsc->id, start->node->details->uname); crm_free(start->uuid); crm_free(start->task); start->task = crm_strdup("reload"); start->uuid = generate_op_key(rsc->id, start->task, 0); stop->pseudo = TRUE; /* easier than trying to delete it from the graph */ } else { do_crm_log(level+1, "%s nothing to do", rsc->id); } } diff --git a/pengine/pengine.c b/pengine/pengine.c index 68978b2d4e..283b62c9a6 100644 --- a/pengine/pengine.c +++ b/pengine/pengine.c @@ -1,316 +1,316 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include -crm_data_t * do_calculations( - pe_working_set_t *data_set, crm_data_t *xml_input, ha_time_t *now); +xmlNode * do_calculations( + pe_working_set_t *data_set, xmlNode *xml_input, ha_time_t *now); #define PE_WORKING_DIR HA_VARLIBDIR"/heartbeat/pengine" extern int transition_id; #define get_series() was_processing_error?1:was_processing_warning?2:3 typedef struct series_s { int id; const char *name; const char *param; int wrap; } series_t; series_t series[] = { { 0, "pe-unknown", "_dont_match_anything_", -1 }, { 0, "pe-error", "pe-error-series-max", -1 }, { 0, "pe-warn", "pe-warn-series-max", 200 }, { 0, "pe-input", "pe-input-series-max", 400 }, }; gboolean -process_pe_message(HA_Message *msg, crm_data_t * xml_data, IPC_Channel *sender) +process_pe_message(xmlNode *msg, xmlNode * xml_data, IPC_Channel *sender) { gboolean send_via_disk = FALSE; - const char *sys_to = cl_get_string(msg, F_CRM_SYS_TO); - const char *op = cl_get_string(msg, F_CRM_TASK); - const char *ref = cl_get_string(msg, XML_ATTR_REFERENCE); + const char *sys_to = crm_element_value(msg, F_CRM_SYS_TO); + const char *op = crm_element_value(msg, F_CRM_TASK); + const char *ref = crm_element_value(msg, XML_ATTR_REFERENCE); crm_debug_3("Processing %s op (ref=%s)...", op, ref); if(op == NULL){ /* error */ } else if(strcasecmp(op, CRM_OP_HELLO) == 0) { /* ignore */ - } else if(safe_str_eq(cl_get_string(msg, F_CRM_MSG_TYPE), + } else if(safe_str_eq(crm_element_value(msg, F_CRM_MSG_TYPE), XML_ATTR_RESPONSE)) { /* ignore */ } else if(sys_to == NULL || strcasecmp(sys_to, CRM_SYSTEM_PENGINE) != 0) { crm_debug_3("Bad sys-to %s", crm_str(sys_to)); return FALSE; } else if(strcasecmp(op, CRM_OP_PECALC) == 0) { int seq = -1; int series_id = 0; int series_wrap = 0; char *filename = NULL; char *graph_file = NULL; const char *value = NULL; pe_working_set_t data_set; - crm_data_t *log_input = copy_xml(xml_data); - HA_Message *reply = NULL; + xmlNode *log_input = copy_xml(xml_data); + xmlNode *reply = NULL; #if HAVE_BZLIB_H gboolean compress = TRUE; #else gboolean compress = FALSE; #endif crm_config_error = FALSE; crm_config_warning = FALSE; was_processing_error = FALSE; was_processing_warning = FALSE; graph_file = crm_strdup(WORKING_DIR"/graph.XXXXXX"); graph_file = mktemp(graph_file); do_calculations(&data_set, xml_data, NULL); series_id = get_series(); series_wrap = series[series_id].wrap; value = pe_pref(data_set.config_hash, series[series_id].param); if(value != NULL) { series_wrap = crm_int_helper(value, NULL); if(errno != 0) { series_wrap = series[series_id].wrap; } } else { crm_config_warn("No value specified for cluster" " preference: %s", series[series_id].param); } seq = get_last_sequence(PE_WORKING_DIR, series[series_id].name); data_set.input = NULL; reply = create_reply(msg, data_set.graph); CRM_ASSERT(reply != NULL); filename = generate_series_filename( PE_WORKING_DIR, series[series_id].name, seq, compress); - ha_msg_add(reply, F_CRM_TGRAPH_INPUT, filename); + crm_xml_add(reply, F_CRM_TGRAPH_INPUT, filename); crm_free(filename); filename = NULL; if(send_ipc_message(sender, reply) == FALSE) { send_via_disk = TRUE; crm_err("Answer could not be sent via IPC, send via the disk instead"); crm_info("Writing the TE graph to %s", graph_file); if(write_xml_file(data_set.graph, graph_file, FALSE) < 0) { crm_err("TE graph could not be written to disk"); } } - crm_msg_del(reply); + free_xml(reply); cleanup_alloc_calculations(&data_set); filename = generate_series_filename( PE_WORKING_DIR, series[series_id].name, seq, compress); write_xml_file(log_input, filename, compress); write_last_sequence(PE_WORKING_DIR, series[series_id].name, seq+1, series_wrap); if(was_processing_error) { crm_err("Transition %d:" " ERRORs found during PE processing." " PEngine Input stored in: %s", transition_id, filename); } else if(was_processing_warning) { crm_warn("Transition %d:" " WARNINGs found during PE processing." " PEngine Input stored in: %s", transition_id, filename); } else { crm_info("Transition %d: PEngine Input stored in: %s", transition_id, filename); } if(crm_config_error) { crm_info("Configuration ERRORs found during PE processing." " Please run \"crm_verify -L\" to identify issues."); } else if(crm_config_warning) { crm_info("Configuration WARNINGs found during PE processing." " Please run \"crm_verify -L\" to identify issues."); } if(send_via_disk) { reply = create_reply(msg, NULL); - ha_msg_add(reply, F_CRM_TGRAPH, graph_file); - ha_msg_add(reply, F_CRM_TGRAPH_INPUT, filename); + crm_xml_add(reply, F_CRM_TGRAPH, graph_file); + crm_xml_add(reply, F_CRM_TGRAPH_INPUT, filename); CRM_ASSERT(reply != NULL); if(send_ipc_message(sender, reply) == FALSE) { crm_err("Answer could not be sent"); } } crm_free(graph_file); free_xml(log_input); crm_free(filename); - crm_msg_del(reply); + free_xml(reply); } else if(strcasecmp(op, CRM_OP_QUIT) == 0) { crm_warn("Received quit message, terminating"); exit(0); } return TRUE; } #define MEMCHECK_STAGE_0 0 #define check_and_exit(stage) cleanup_calculations(data_set); \ crm_mem_stats(NULL); \ crm_err("Exiting: stage %d", stage); \ exit(1); -crm_data_t * -do_calculations(pe_working_set_t *data_set, crm_data_t *xml_input, ha_time_t *now) +xmlNode * +do_calculations(pe_working_set_t *data_set, xmlNode *xml_input, ha_time_t *now) { int rsc_log_level = LOG_NOTICE; /* pe_debug_on(); */ set_working_set_defaults(data_set); data_set->input = xml_input; data_set->now = now; if(data_set->now == NULL) { data_set->now = new_ha_date(TRUE); } #if MEMCHECK_STAGE_SETUP check_and_exit(-1); #endif crm_debug_5("unpack constraints"); stage0(data_set); #if MEMCHECK_STAGE_0 check_and_exit(0); #endif slist_iter(rsc, resource_t, data_set->resources, lpc, if(is_set(rsc->flags, pe_rsc_orphan) && rsc->role == RSC_ROLE_STOPPED) { continue; } rsc->fns->print(rsc, NULL, pe_print_log, &rsc_log_level); ); crm_debug_5("apply placement constraints"); stage1(data_set); #if MEMCHECK_STAGE_1 check_and_exit(1); #endif crm_debug_5("color resources"); stage2(data_set); #if MEMCHECK_STAGE_2 check_and_exit(2); #endif /* unused */ stage3(data_set); #if MEMCHECK_STAGE_3 check_and_exit(3); #endif crm_debug_5("assign nodes to colors"); stage4(data_set); #if MEMCHECK_STAGE_4 check_and_exit(4); #endif crm_debug_5("creating actions and internal ording constraints"); stage5(data_set); #if MEMCHECK_STAGE_5 check_and_exit(5); #endif crm_debug_5("processing fencing and shutdown cases"); stage6(data_set); #if MEMCHECK_STAGE_6 check_and_exit(6); #endif crm_debug_5("applying ordering constraints"); stage7(data_set); #if MEMCHECK_STAGE_7 check_and_exit(7); #endif crm_debug_5("creating transition graph"); stage8(data_set); #if MEMCHECK_STAGE_8 check_and_exit(8); #endif crm_debug_2("=#=#=#=#= Summary =#=#=#=#="); crm_debug_2("\t========= Set %d (Un-runnable) =========", -1); if(crm_log_level > LOG_DEBUG) { slist_iter(action, action_t, data_set->actions, lpc, if(action->optional == FALSE && action->runnable == FALSE && action->pseudo == FALSE) { log_action(LOG_DEBUG_2, "\t", action, TRUE); } ); } return data_set->graph; } diff --git a/pengine/pengine.h b/pengine/pengine.h index c2d5c3c110..38e87904b2 100644 --- a/pengine/pengine.h +++ b/pengine/pengine.h @@ -1,176 +1,176 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 PENGINE__H #define PENGINE__H #include typedef struct rsc_to_node_s rsc_to_node_t; typedef struct rsc_colocation_s rsc_colocation_t; typedef struct lrm_agent_s lrm_agent_t; typedef struct order_constraint_s order_constraint_t; #include #include #include #include #include #include #include #include enum pe_stop_fail { pesf_block, pesf_stonith, pesf_ignore }; enum pe_ordering { pe_order_none = 0x0, /* deleted */ pe_order_implies_left = 0x01, /* was: _mandatory */ pe_order_implies_right = 0x02, /* was: _recover */ pe_order_runnable_left = 0x10, /* needs the LHS side to be runnable */ pe_order_runnable_right = 0x20, /* needs the RHS side to be runnable */ pe_order_optional = 0x100, /* pure ordering, nothing implied */ pe_order_stonith_stop = 0x200, /* only applies if the action is non-pseudo */ pe_order_restart = 0x400, /* stop-start constraint */ pe_order_demote = 0x800, /* stop-start constraint */ pe_order_shutdown = 0x1000, /* combines with pe_order_restart to make a complex resource shut down */ pe_order_test = 0x10000 /* test marker */ }; struct rsc_colocation_s { const char *id; const char *node_attribute; resource_t *rsc_lh; resource_t *rsc_rh; int role_lh; int role_rh; int score; }; struct rsc_to_node_s { const char *id; resource_t *rsc_lh; enum rsc_role_e role_filter; GListPtr node_list_rh; /* node_t* */ }; struct order_constraint_s { int id; enum pe_ordering type; void *lh_opaque; resource_t *lh_rsc; action_t *lh_action; char *lh_action_task; void *rh_opaque; resource_t *rh_rsc; action_t *rh_action; char *rh_action_task; /* (soon to be) variant specific */ /* int lh_rsc_incarnation; */ /* int rh_rsc_incarnation; */ }; enum pe_link_state { pe_link_not_dumped, pe_link_dumped, pe_link_dup, }; typedef struct action_wrapper_s action_wrapper_t; struct action_wrapper_s { enum pe_ordering type; enum pe_link_state state; action_t *action; }; extern gboolean stage0(pe_working_set_t *data_set); extern gboolean stage1(pe_working_set_t *data_set); extern gboolean stage2(pe_working_set_t *data_set); extern gboolean stage3(pe_working_set_t *data_set); extern gboolean stage4(pe_working_set_t *data_set); extern gboolean stage5(pe_working_set_t *data_set); extern gboolean stage6(pe_working_set_t *data_set); extern gboolean stage7(pe_working_set_t *data_set); extern gboolean stage8(pe_working_set_t *data_set); extern gboolean summary(GListPtr resources); extern gboolean pe_msg_dispatch(IPC_Channel *sender, void *user_data); extern gboolean process_pe_message( - HA_Message *msg, crm_data_t *xml_data, IPC_Channel *sender); + xmlNode *msg, xmlNode *xml_data, IPC_Channel *sender); extern gboolean unpack_constraints( - crm_data_t *xml_constraints, pe_working_set_t *data_set); + xmlNode *xml_constraints, pe_working_set_t *data_set); extern gboolean update_action_states(GListPtr actions); extern gboolean shutdown_constraints( node_t *node, action_t *shutdown_op, pe_working_set_t *data_set); extern gboolean stonith_constraints( node_t *node, action_t *stonith_op, pe_working_set_t *data_set); extern int custom_action_order( resource_t *lh_rsc, char *lh_task, action_t *lh_action, resource_t *rh_rsc, char *rh_task, action_t *rh_action, enum pe_ordering type, pe_working_set_t *data_set); #define order_start_start(rsc1,rsc2, type) \ custom_action_order(rsc1, start_key(rsc1), NULL, \ rsc2, start_key(rsc2) ,NULL, \ type, data_set) #define order_stop_stop(rsc1, rsc2, type) \ custom_action_order(rsc1, stop_key(rsc1), NULL, \ rsc2, stop_key(rsc2) ,NULL, \ type, data_set) #define order_stop_start(rsc1, rsc2, type) \ custom_action_order(rsc1, stop_key(rsc1), NULL, \ rsc2, start_key(rsc2) ,NULL, \ type, data_set) #define order_start_stop(rsc1, rsc2, type) \ custom_action_order(rsc1, start_key(rsc1), NULL, \ rsc2, stop_key(rsc2) ,NULL, \ type, data_set) extern void graph_element_from_action( action_t *action, pe_working_set_t *data_set); extern const char* transition_idle_timeout; #endif diff --git a/pengine/ptest.c b/pengine/ptest.c index 96a2fbcee7..53751918bd 100644 --- a/pengine/ptest.c +++ b/pengine/ptest.c @@ -1,500 +1,500 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #define OPTARGS "V?X:D:G:I:Lwxd:aS" #ifdef HAVE_GETOPT_H # include #endif #include #include #include #include #if HAVE_LIBXML2 # include #endif gboolean use_stdin = FALSE; gboolean do_simulation = FALSE; gboolean inhibit_exit = FALSE; gboolean all_actions = FALSE; -extern crm_data_t * do_calculations( - pe_working_set_t *data_set, crm_data_t *xml_input, ha_time_t *now); +extern xmlNode * do_calculations( + pe_working_set_t *data_set, xmlNode *xml_input, ha_time_t *now); extern void cleanup_calculations(pe_working_set_t *data_set); char *use_date = NULL; FILE *dot_strm = NULL; #define DOT_PREFIX "PE_DOT: " /* #define DOT_PREFIX "" */ #define dot_write(fmt...) if(dot_strm != NULL) { \ fprintf(dot_strm, fmt); \ fprintf(dot_strm, "\n"); \ } else { \ crm_debug(DOT_PREFIX""fmt); \ } static void init_dotfile(void) { dot_write(" digraph \"g\" {"); /* dot_write(" size = \"30,30\""); */ /* dot_write(" graph ["); */ /* dot_write(" fontsize = \"12\""); */ /* dot_write(" fontname = \"Times-Roman\""); */ /* dot_write(" fontcolor = \"black\""); */ /* dot_write(" bb = \"0,0,398.922306,478.927856\""); */ /* dot_write(" color = \"black\""); */ /* dot_write(" ]"); */ /* dot_write(" node ["); */ /* dot_write(" fontsize = \"12\""); */ /* dot_write(" fontname = \"Times-Roman\""); */ /* dot_write(" fontcolor = \"black\""); */ /* dot_write(" shape = \"ellipse\""); */ /* dot_write(" color = \"black\""); */ /* dot_write(" ]"); */ /* dot_write(" edge ["); */ /* dot_write(" fontsize = \"12\""); */ /* dot_write(" fontname = \"Times-Roman\""); */ /* dot_write(" fontcolor = \"black\""); */ /* dot_write(" color = \"black\""); */ /* dot_write(" ]"); */ } static void usage(const char *cli, int exitcode) { FILE *out = exitcode?stderr:stdout; fprintf(out, "Usage: %s -(?|L|X|x) [-V] [-D] [-G] [-I]\n", cli); fprintf(out, " --%s (-%c): This text\n\n", "help", '?'); fprintf(out, " --%s (-%c): Increase verbosity (can be supplied multiple times)\n\n", "verbose", 'V'); fprintf(out, " --%s (-%c): Connect to the CIB and use the current contents as input\n", "live-check", 'L'); fprintf(out, " --%s (-%c): Look for xml on stdin\n", "xml-stream", 'x'); fprintf(out, " --%s (-%c)\t : Look for xml in the named file\n\n", "xml-file", 'X'); fprintf(out, " --%s (-%c)\t : Save the transition graph to the named file\n", "save-graph", 'G'); fprintf(out, " --%s (-%c)\t : Save the DOT formatted transition graph to the named file\n", "save-dotfile", 'D'); fprintf(out, " --%s (-%c)\t : Save the input to the named file\n", "save-input", 'I'); exit(exitcode); } static char * create_action_name(action_t *action) { char *action_name = NULL; const char *action_host = NULL; if(action->node) { action_host = action->node->details->uname; action_name = crm_concat(action->uuid, action_host, ' '); } else if(action->pseudo) { action_name = crm_strdup(action->uuid); } else { action_host = ""; action_name = crm_concat(action->uuid, action_host, ' '); } return action_name; } gboolean USE_LIVE_CIB = FALSE; int main(int argc, char **argv) { gboolean all_good = TRUE; enum transition_status graph_rc = -1; crm_graph_t *transition = NULL; ha_time_t *a_date = NULL; cib_t * cib_conn = NULL; - crm_data_t * cib_object = NULL; + xmlNode * cib_object = NULL; int argerr = 0; int flag; char *msg_buffer = NULL; gboolean optional = FALSE; pe_working_set_t data_set; const char *source = NULL; const char *xml_file = NULL; const char *dot_file = NULL; const char *graph_file = NULL; const char *input_file = NULL; cl_log_set_entity("ptest"); cl_log_set_facility(LOG_USER); set_crm_log_level(LOG_CRIT-1); while (1) { #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {"help", 0, 0, '?'}, {"verbose", 0, 0, 'V'}, {"live-check", 0, 0, 'L'}, {"xml-stream", 0, 0, 'x'}, {"xml-file", 1, 0, 'X'}, {"simulate", 0, 0, 'S'}, {"save-graph", 1, 0, 'G'}, {"save-dotfile",1, 0, 'D'}, {"save-input", 1, 0, 'I'}, {0, 0, 0, 0} }; #endif #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"); break; #endif case 'S': do_simulation = TRUE; break; case 'a': all_actions = TRUE; break; case 'w': inhibit_exit = TRUE; break; case 'x': use_stdin = TRUE; break; case 'X': xml_file = optarg; break; case 'd': use_date = optarg; break; case 'D': dot_file = optarg; break; case 'G': graph_file = optarg; break; case 'I': input_file = optarg; break; case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case 'L': USE_LIVE_CIB = TRUE; break; case '?': usage("ptest", 0); break; default: printf("?? getopt returned character code 0%o ??\n", 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) { crm_err("%d errors in option parsing", argerr); usage("ptest", 1); } crm_info("=#=#=#=#= Getting XML =#=#=#=#="); if(USE_LIVE_CIB) { int rc = cib_ok; source = "live cib"; cib_conn = cib_new(); rc = cib_conn->cmds->signon( cib_conn, "ptest", cib_command_synchronous); if(rc == cib_ok) { crm_info("Reading XML from: live cluster"); cib_object = get_cib_copy(cib_conn); } else { fprintf(stderr, "Live CIB query failed: %s\n", cib_error2string(rc)); return 3; } if(cib_object == NULL) { fprintf(stderr, "Live CIB query failed: empty result\n"); return 3; } } else if(xml_file != NULL) { FILE *xml_strm = fopen(xml_file, "r"); source = xml_file; if(xml_strm == NULL) { cl_perror("Could not open %s for reading", xml_file); } else { if(strstr(xml_file, ".bz2") != NULL) { cib_object = file2xml(xml_strm, TRUE); } else { cib_object = file2xml(xml_strm, FALSE); } fclose(xml_strm); } } else if(use_stdin) { source = "stdin"; cib_object = stdin2xml(); } if(cib_object == NULL && source) { fprintf(stderr, "Could not parse configuration input from: %s\n", source); return 4; } else if(cib_object == NULL) { fprintf(stderr, "Not configuration specified\n"); usage("ptest", 1); } crm_notice("Required feature set: %s", feature_set(cib_object)); do_id_check(cib_object, NULL, FALSE, FALSE); if(!validate_with_dtd(cib_object,FALSE,DTD_DIRECTORY"/crm.dtd")) { crm_crit("%s does not contain a valid configuration", xml_file?xml_file:""); all_good = FALSE; } if(input_file != NULL) { FILE *input_strm = fopen(input_file, "w"); if(input_strm == NULL) { cl_perror("Could not open %s for writing", input_file); } else { msg_buffer = dump_xml_formatted(cib_object); if(fprintf(input_strm, "%s\n", msg_buffer) < 0) { cl_perror("Write to %s failed", input_file); } fflush(input_strm); fclose(input_strm); crm_free(msg_buffer); } } if(use_date != NULL) { a_date = parse_date(&use_date); log_date(LOG_WARNING, "Set fake 'now' to", a_date, ha_log_date|ha_log_time); log_date(LOG_WARNING, "Set fake 'now' to (localtime)", a_date, ha_log_date|ha_log_time|ha_log_local); } do_calculations(&data_set, cib_object, a_date); msg_buffer = dump_xml_formatted(data_set.graph); if(safe_str_eq(graph_file, "-")) { fprintf(stdout, "%s\n", msg_buffer); fflush(stdout); } else if(graph_file != NULL) { FILE *graph_strm = fopen(graph_file, "w"); if(graph_strm == NULL) { cl_perror("Could not open %s for writing", graph_file); } else { if(fprintf(graph_strm, "%s\n", msg_buffer) < 0) { cl_perror("Write to %s failed", graph_file); } fflush(graph_strm); fclose(graph_strm); } } crm_free(msg_buffer); if(dot_file != NULL) { dot_strm = fopen(dot_file, "w"); if(dot_strm == NULL) { cl_perror("Could not open %s for writing", dot_file); } } if(dot_strm == NULL) { goto simulate; } init_dotfile(); slist_iter( action, action_t, data_set.actions, lpc, const char *style = "filled"; const char *font = "black"; const char *color = "black"; const char *fill = NULL; char *action_name = create_action_name(action); crm_debug_3("Action %d: %p", action->id, action); if(action->pseudo) { font = "orange"; } style = "dashed"; if(action->dumped) { style = "bold"; color = "green"; } else if(action->rsc != NULL && is_not_set(action->rsc->flags, pe_rsc_managed)) { color = "purple"; if(all_actions == FALSE) { goto dont_write; } } else if(action->optional) { color = "blue"; if(all_actions == FALSE) { goto dont_write; } } else { color = "red"; CRM_CHECK(action->runnable == FALSE, ;); } action->dumped = TRUE; dot_write("\"%s\" [ style=%s color=\"%s\" fontcolor=\"%s\" %s%s]", action_name, style, color, font, fill?"fillcolor=":"", fill?fill:""); dont_write: crm_free(action_name); ); slist_iter( action, action_t, data_set.actions, lpc, slist_iter( before, action_wrapper_t, action->actions_before, lpc2, char *before_name = NULL; char *after_name = NULL; const char *style = "dashed"; optional = TRUE; if(before->state == pe_link_dumped) { optional = FALSE; style = "bold"; } else if(action->pseudo && (before->type & pe_order_stonith_stop)) { continue; } else if(before->state == pe_link_dup) { continue; } else if(action->dumped && before->action->dumped) { optional = FALSE; } if(all_actions || optional == FALSE) { before_name = create_action_name(before->action); after_name = create_action_name(action); dot_write("\"%s\" -> \"%s\" [ style = %s]", before_name, after_name, style); crm_free(before_name); crm_free(after_name); } ); ); dot_write("}"); if(dot_strm != NULL) { fflush(dot_strm); fclose(dot_strm); } simulate: if(do_simulation == FALSE) { goto cleanup; } transition = unpack_graph(data_set.graph); transition->batch_limit = 0; print_graph(LOG_DEBUG, transition); do { graph_rc = run_graph(transition); } while(graph_rc == transition_active); if(graph_rc != transition_complete) { crm_crit("Transition failed: %s", transition_status(graph_rc)); print_graph(LOG_ERR, transition); } destroy_graph(transition); CRM_CHECK(graph_rc == transition_complete, all_good = FALSE; crm_err("An invalid transition was produced")); cleanup: cleanup_alloc_calculations(&data_set); #if HAVE_LIBXML2 xmlCleanupParser(); #endif /* required for MallocDebug.app */ if(inhibit_exit) { GMainLoop* mainloop = g_main_new(FALSE); g_main_run(mainloop); } if(all_good) { return 0; } return 5; } diff --git a/pengine/utils.h b/pengine/utils.h index 1aaf4d6cab..3d79c02f73 100644 --- a/pengine/utils.h +++ b/pengine/utils.h @@ -1,69 +1,69 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 PENGINE_AUTILS__H #define PENGINE_AUTILS__H /* 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); 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 rsc_to_node_t *rsc2node_new( const char *id, resource_t *rsc, int weight, node_t *node, pe_working_set_t *data_set); extern void pe_free_rsc_to_node(GListPtr constraints); extern void pe_free_ordering(GListPtr constraints); extern const char *ordering_type2text(enum pe_ordering type); extern gboolean rsc_colocation_new( const char *id, const char *node_attr, int score, resource_t *rsc_lh, resource_t *rsc_rh, const char *state_lh, const char *state_rh, pe_working_set_t *data_set); extern rsc_to_node_t *generate_location_rule( - resource_t *rsc, crm_data_t *location_rule, pe_working_set_t *data_set); + resource_t *rsc, xmlNode *location_rule, pe_working_set_t *data_set); extern gint sort_node_weight(gconstpointer a, gconstpointer b); extern gboolean can_run_resources(const node_t *node); extern gboolean native_assign_node(resource_t *rsc, GListPtr candidates, node_t *chosen); extern void convert_non_atomic_task(resource_t *rsc, order_constraint_t *order); extern void order_actions( action_t *lh_action, action_t *rh_action, enum pe_ordering order); extern void log_action(unsigned int log_level, const char *pre_text, action_t *action, gboolean details); extern resource_t *uber_parent(resource_t *rsc); extern action_t *get_pseudo_op(const char *name, pe_working_set_t *data_set); extern gboolean can_run_any(GListPtr nodes); #define STONITH_UP "stonith_up" #define ALL_STOPPED "all_stopped" #endif diff --git a/tools/attrd.c b/tools/attrd.c index 5c61db72ab..d345f59648 100644 --- a/tools/attrd.c +++ b/tools/attrd.c @@ -1,638 +1,638 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define OPTARGS "hV" #if SUPPORT_HEARTBEAT ll_cluster_t *attrd_cluster_conn; #endif GMainLoop* mainloop = NULL; char *attrd_uname = NULL; char *attrd_uuid = NULL; gboolean need_shutdown = FALSE; GHashTable *attr_hash = NULL; cib_t *cib_conn = NULL; typedef struct attr_hash_entry_s { char *id; char *set; char *section; char *value; char *last_value; int timeout; char *dampen; guint timer_id; } attr_hash_entry_t; static void free_hash_entry(gpointer data) { attr_hash_entry_t *entry = data; if (entry == NULL) { return; } crm_free(entry->id); crm_free(entry->set); crm_free(entry->dampen); crm_free(entry->section); if(entry->value != entry->last_value) { crm_free(entry->value); crm_free(entry->last_value); } else { crm_free(entry->value); } crm_free(entry); } -void attrd_ha_callback(HA_Message * msg, void* private_data); -void attrd_local_callback(HA_Message * msg); +void attrd_ha_callback(xmlNode * msg, void* private_data); +void attrd_local_callback(xmlNode * msg); gboolean attrd_timer_callback(void *user_data); gboolean attrd_trigger_update(attr_hash_entry_t *hash_entry); void attrd_perform_update(attr_hash_entry_t *hash_entry); static gboolean attrd_shutdown(int nsig, gpointer unused) { need_shutdown = TRUE; crm_info("Exiting"); if (mainloop != NULL && g_main_is_running(mainloop)) { g_main_quit(mainloop); } else { exit(0); } return FALSE; } static void usage(const char* cmd, int exit_status) { FILE* stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-srkh] [-c configure file]\n", cmd); /* fprintf(stream, "\t-d\tsets debug level\n"); */ /* fprintf(stream, "\t-s\tgets daemon status\n"); */ /* fprintf(stream, "\t-r\trestarts daemon\n"); */ /* fprintf(stream, "\t-k\tstops daemon\n"); */ /* fprintf(stream, "\t-h\thelp message\n"); */ fflush(stream); exit(exit_status); } typedef struct attrd_client_s { char *id; char *name; IPC_Channel *channel; GCHSource *source; } attrd_client_t; static void stop_attrd_timer(attr_hash_entry_t *hash_entry) { if(hash_entry != NULL && hash_entry->timer_id != 0) { crm_debug_2("Stopping %s timer", hash_entry->id); Gmain_timeout_remove(hash_entry->timer_id); hash_entry->timer_id = 0; } } static gboolean attrd_ipc_callback(IPC_Channel *client, gpointer user_data) { int lpc = 0; - HA_Message *msg = NULL; + xmlNode *msg = NULL; attrd_client_t *curr_client = (attrd_client_t*)user_data; gboolean stay_connected = TRUE; crm_debug_2("Invoked: %s", curr_client->id); while(IPC_ISRCONN(client)) { if(client->ops->is_message_pending(client) == 0) { break; } - msg = msgfromIPC_noauth(client); + msg = xmlfromIPC(client, 0); if (msg == NULL) { crm_debug("%s: no message this time", curr_client->id); continue; } lpc++; crm_debug_2("Processing msg from %s", curr_client->id); - crm_log_message_adv(LOG_DEBUG_3, __PRETTY_FUNCTION__, msg); + crm_log_xml(LOG_DEBUG_3, __PRETTY_FUNCTION__, msg); attrd_local_callback(msg); - crm_msg_del(msg); + free_xml(msg); msg = NULL; if(client->ch_status != IPC_CONNECT) { break; } } crm_debug_2("Processed %d messages", lpc); if (client->ch_status != IPC_CONNECT) { stay_connected = FALSE; } return stay_connected; } static void attrd_connection_destroy(gpointer user_data) { attrd_client_t *client = user_data; /* cib_process_disconnect */ if(client == NULL) { return; } if(client->source != NULL) { crm_debug_4("Deleting %s (%p) from mainloop", client->name, client->source); G_main_del_IPC_Channel(client->source); client->source = NULL; } crm_debug_3("Destroying %s (%p)", client->name, client); crm_free(client->name); crm_free(client->id); crm_free(client); crm_debug_4("Freed the cib client"); return; } static gboolean attrd_connect(IPC_Channel *channel, gpointer user_data) { attrd_client_t *new_client = NULL; crm_debug_3("Connecting channel"); if(channel == NULL) { crm_err("Channel was NULL"); return FALSE; } else if(channel->ch_status != IPC_CONNECT) { crm_err("Channel was disconnected"); return FALSE; } else if(need_shutdown) { crm_info("Ignoring connection request during shutdown"); return FALSE; } crm_malloc0(new_client, sizeof(attrd_client_t)); new_client->channel = channel; crm_debug_3("Created channel %p for channel %s", new_client, new_client->id); /* channel->ops->set_recv_qlen(channel, 100); */ /* channel->ops->set_send_qlen(channel, 400); */ new_client->source = G_main_add_IPC_Channel( G_PRIORITY_DEFAULT, channel, FALSE, attrd_ipc_callback, new_client, attrd_connection_destroy); crm_debug_3("Client %s connected", new_client->id); return TRUE; } static void attrd_ha_connection_destroy(gpointer user_data) { crm_debug_3("Invoked"); if(need_shutdown) { /* we signed out, so this is expected */ crm_info("Heartbeat disconnection complete"); return; } crm_crit("Lost connection to heartbeat service!"); if (mainloop != NULL && g_main_is_running(mainloop)) { g_main_quit(mainloop); return; } exit(LSB_EXIT_OK); } static gboolean register_with_ha(void) { void *dispatch = attrd_ha_callback; void *destroy = attrd_ha_connection_destroy; if(is_openais_cluster()) { #if SUPPORT_AIS destroy = NULL; dispatch = NULL; #endif } return crm_cluster_connect(&attrd_uname, &attrd_uuid, dispatch, destroy, #if SUPPORT_HEARTBEAT &attrd_cluster_conn #else NULL #endif ); } static void attrd_cib_connection_destroy(gpointer user_data) { if(need_shutdown) { crm_info("Connection to the CIB terminated..."); } else { /* eventually this will trigger a reconnect, not a shutdown */ crm_err("Connection to the CIB terminated..."); exit(1); } return; } int main(int argc, char ** argv) { int flag; int argerr = 0; gboolean was_err = FALSE; char *channel_name = crm_strdup(attrd_channel); crm_log_init(T_ATTRD, LOG_INFO, TRUE, FALSE, 0, NULL); G_main_add_SignalHandler( G_PRIORITY_HIGH, SIGTERM, attrd_shutdown, NULL, NULL); while ((flag = getopt(argc, argv, OPTARGS)) != EOF) { switch(flag) { case 'V': cl_log_enable_stderr(1); alter_debug(DEBUG_INC); break; case 'h': /* Help message */ usage(T_ATTRD, LSB_EXIT_OK); break; default: ++argerr; break; } } if (optind > argc) { ++argerr; } if (argerr) { usage(T_ATTRD, LSB_EXIT_GENERIC); } crm_info("Starting up...."); if(register_with_ha() == FALSE) { crm_err("HA Signon failed"); was_err = TRUE; } if(was_err == FALSE) { int lpc = 0; int max_retry = 20; enum cib_errors rc = cib_not_connected; cib_conn = cib_new(); for(lpc = 0; lpc < max_retry && rc != cib_ok; lpc++) { crm_debug("CIB signon attempt %d", lpc); rc = cib_conn->cmds->signon( cib_conn, T_ATTRD, cib_command); sleep(5); } if(rc != cib_ok) { crm_err("Signon to CIB failed: %s", cib_error2string(rc)); was_err = TRUE; } } if(was_err == FALSE) { enum cib_errors rc = cib_conn->cmds->set_connection_dnotify( cib_conn, attrd_cib_connection_destroy); if(rc != cib_ok) { crm_err("Could not set dnotify callback"); was_err = TRUE; } } if(was_err == FALSE) { int rc = init_server_ipc_comms( channel_name, attrd_connect, default_ipc_connection_destroy); if(rc != 0) { crm_err("Could not start IPC server"); was_err = TRUE; } } if(was_err) { crm_err("Aborting startup"); return 100; } attr_hash = g_hash_table_new_full( g_str_hash, g_str_equal, NULL, free_hash_entry); crm_info("Starting mainloop..."); mainloop = g_main_new(FALSE); g_main_run(mainloop); crm_info("Exiting..."); #if SUPPORT_HEARTBEAT if(is_heartbeat_cluster()) { attrd_cluster_conn->llc_ops->signoff(attrd_cluster_conn, TRUE); attrd_cluster_conn->llc_ops->delete(attrd_cluster_conn); } #endif cib_conn->cmds->signoff(cib_conn); cib_delete(cib_conn); g_hash_table_destroy(attr_hash); crm_free(channel_name); crm_free(attrd_uuid); empty_uuid_cache(); return 0; } static void -attrd_cib_callback(const HA_Message *msg, int call_id, int rc, - crm_data_t *output, void *user_data) +attrd_cib_callback(xmlNode *msg, int call_id, int rc, + xmlNode *output, void *user_data) { char *attr = user_data; if(rc == cib_NOTEXISTS) { rc = cib_ok; } if(rc < cib_ok) { crm_err("Update %d for %s failed: %s", call_id, attr, cib_error2string(rc)); } else { crm_debug("Update %d for %s passed", call_id, attr); } crm_free(attr); } static void log_hash_entry(int level, attr_hash_entry_t *entry, const char *text) { do_crm_log(level, "%s", text); do_crm_log(level, "Set: %s", entry->section); do_crm_log(level, "Name: %s", entry->id); do_crm_log(level, "Value: %s", entry->value); do_crm_log(level, "Timeout: %s", entry->dampen); } static attr_hash_entry_t * -find_hash_entry(HA_Message * msg) +find_hash_entry(xmlNode * msg) { const char *value = NULL; - const char *attr = ha_msg_value(msg, F_ATTRD_ATTRIBUTE); + const char *attr = crm_element_value(msg, F_ATTRD_ATTRIBUTE); attr_hash_entry_t *hash_entry = NULL; if(attr == NULL) { crm_info("Ignoring message with no attribute name"); return NULL; } hash_entry = g_hash_table_lookup(attr_hash, attr); if(hash_entry == NULL) { /* create one and add it */ crm_info("Creating hash entry for %s", attr); crm_malloc0(hash_entry, sizeof(attr_hash_entry_t)); hash_entry->id = crm_strdup(attr); g_hash_table_insert(attr_hash, hash_entry->id, hash_entry); hash_entry = g_hash_table_lookup(attr_hash, attr); CRM_CHECK(hash_entry != NULL, return NULL); } - value = ha_msg_value(msg, F_ATTRD_SET); + value = crm_element_value(msg, F_ATTRD_SET); if(value != NULL) { crm_free(hash_entry->set); hash_entry->set = crm_strdup(value); crm_debug("\t%s->set: %s", attr, value); } - value = ha_msg_value(msg, F_ATTRD_SECTION); + value = crm_element_value(msg, F_ATTRD_SECTION); if(value == NULL) { value = XML_CIB_TAG_STATUS; } crm_free(hash_entry->section); hash_entry->section = crm_strdup(value); crm_debug("\t%s->section: %s", attr, value); - value = ha_msg_value(msg, F_ATTRD_DAMPEN); + value = crm_element_value(msg, F_ATTRD_DAMPEN); if(value != NULL) { crm_free(hash_entry->dampen); hash_entry->dampen = crm_strdup(value); hash_entry->timeout = crm_get_msec(value); crm_debug("\t%s->timeout: %s", attr, value); } log_hash_entry(LOG_DEBUG_2, hash_entry, "Found (and updated) entry:"); return hash_entry; } void -attrd_ha_callback(HA_Message * msg, void* private_data) +attrd_ha_callback(xmlNode * msg, void* private_data) { attr_hash_entry_t *hash_entry = NULL; - const char *from = ha_msg_value(msg, F_ORIG); - const char *op = ha_msg_value(msg, F_ATTRD_TASK); - const char *ignore = ha_msg_value(msg, F_ATTRD_IGNORE_LOCALLY); + const char *from = crm_element_value(msg, F_ORIG); + const char *op = crm_element_value(msg, F_ATTRD_TASK); + const char *ignore = crm_element_value(msg, F_ATTRD_IGNORE_LOCALLY); if(ignore == NULL || safe_str_neq(from, attrd_uname)) { crm_info("%s message from %s", op, from); hash_entry = find_hash_entry(msg); stop_attrd_timer(hash_entry); attrd_perform_update(hash_entry); } } void attrd_perform_update(attr_hash_entry_t *hash_entry) { int rc = cib_ok; if(hash_entry == NULL) { return; } else if(hash_entry->value == NULL) { /* delete the attr */ rc = delete_attr(cib_conn, cib_none, hash_entry->section, attrd_uuid, hash_entry->set, NULL, hash_entry->id, NULL, FALSE); crm_info("Sent delete %d: %s %s %s", rc, hash_entry->id, hash_entry->set, hash_entry->section); } else { /* send update */ rc = update_attr(cib_conn, cib_none, hash_entry->section, attrd_uuid, hash_entry->set, NULL, hash_entry->id, hash_entry->value, FALSE); crm_info("Sent update %d: %s=%s", rc, hash_entry->id, hash_entry->value); } add_cib_op_callback(rc, FALSE, crm_strdup(hash_entry->id), attrd_cib_callback); return; } static void update_for_hash_entry(gpointer key, gpointer value, gpointer user_data) { attrd_timer_callback(value); } void -attrd_local_callback(HA_Message * msg) +attrd_local_callback(xmlNode * msg) { attr_hash_entry_t *hash_entry = NULL; - const char *from = ha_msg_value(msg, F_ORIG); - const char *op = ha_msg_value(msg, F_ATTRD_TASK); - const char *attr = ha_msg_value(msg, F_ATTRD_ATTRIBUTE); - const char *value = ha_msg_value(msg, F_ATTRD_VALUE); + const char *from = crm_element_value(msg, F_ORIG); + const char *op = crm_element_value(msg, F_ATTRD_TASK); + const char *attr = crm_element_value(msg, F_ATTRD_ATTRIBUTE); + const char *value = crm_element_value(msg, F_ATTRD_VALUE); if(safe_str_eq(op, "refresh")) { crm_info("Sending full refresh"); g_hash_table_foreach(attr_hash, update_for_hash_entry, NULL); return; } crm_debug("%s message from %s: %s=%s", op, from, attr, crm_str(value)); hash_entry = find_hash_entry(msg); if(hash_entry == NULL) { return; } crm_free(hash_entry->last_value); hash_entry->last_value = hash_entry->value; if(value != NULL) { hash_entry->value = crm_strdup(value); } else { hash_entry->value = NULL; } if(safe_str_eq(hash_entry->value, hash_entry->last_value)) { crm_debug_2("Ignoring non-change"); return; } stop_attrd_timer(hash_entry); if(hash_entry->timeout > 0) { hash_entry->timer_id = Gmain_timeout_add( hash_entry->timeout, attrd_timer_callback, hash_entry); } else { attrd_trigger_update(hash_entry); } return; } gboolean attrd_timer_callback(void *user_data) { stop_attrd_timer(user_data); attrd_trigger_update(user_data); return TRUE; } gboolean attrd_trigger_update(attr_hash_entry_t *hash_entry) { - HA_Message *msg = NULL; + xmlNode *msg = NULL; /* send HA message to everyone */ crm_info("Sending flush op to all hosts for: %s", hash_entry->id); log_hash_entry(LOG_DEBUG_2, hash_entry, "Sending flush op to all hosts for:"); - msg = ha_msg_new(8); - ha_msg_add(msg, F_TYPE, T_ATTRD); - ha_msg_add(msg, F_ORIG, attrd_uname); - ha_msg_add(msg, F_ATTRD_TASK, "flush"); - ha_msg_add(msg, F_ATTRD_ATTRIBUTE, hash_entry->id); - ha_msg_add(msg, F_ATTRD_SET, hash_entry->set); - ha_msg_add(msg, F_ATTRD_SECTION, hash_entry->section); - ha_msg_add(msg, F_ATTRD_DAMPEN, hash_entry->dampen); - ha_msg_add(msg, F_ATTRD_VALUE, hash_entry->value); + msg = create_xml_node(NULL, __FUNCTION__); + crm_xml_add(msg, F_TYPE, T_ATTRD); + crm_xml_add(msg, F_ORIG, attrd_uname); + crm_xml_add(msg, F_ATTRD_TASK, "flush"); + crm_xml_add(msg, F_ATTRD_ATTRIBUTE, hash_entry->id); + crm_xml_add(msg, F_ATTRD_SET, hash_entry->set); + crm_xml_add(msg, F_ATTRD_SECTION, hash_entry->section); + crm_xml_add(msg, F_ATTRD_DAMPEN, hash_entry->dampen); + crm_xml_add(msg, F_ATTRD_VALUE, hash_entry->value); if(hash_entry->timeout <= 0) { - ha_msg_add(msg, F_ATTRD_IGNORE_LOCALLY, hash_entry->value); + crm_xml_add(msg, F_ATTRD_IGNORE_LOCALLY, hash_entry->value); attrd_perform_update(hash_entry); } send_cluster_message(NULL, crm_proc_attrd, msg, FALSE); - crm_msg_del(msg); + free_xml(msg); return TRUE; } diff --git a/tools/attrd_updater.c b/tools/attrd_updater.c index fe01a29872..6584077fae 100644 --- a/tools/attrd_updater.c +++ b/tools/attrd_updater.c @@ -1,163 +1,163 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #define OPTARGS "hVn:v:d:s:S:" const char *attr_name = NULL; const char *attr_value = NULL; const char *attr_set = NULL; const char *attr_section = NULL; const char *attr_dampen = NULL; void usage(const char* cmd, int exit_status); static gboolean process_attrd_message( - HA_Message *msg, crm_data_t *xml_data, IPC_Channel *sender) + xmlNode *msg, xmlNode *xml_data, IPC_Channel *sender) { crm_err("Why did we get a message?"); - crm_log_message_adv(LOG_WARNING, "attrd:msg", msg); + crm_log_xml(LOG_WARNING, "attrd:msg", msg); return TRUE; } int main(int argc, char ** argv) { - HA_Message *update = NULL; + xmlNode *update = NULL; IPC_Channel *attrd = NULL; int argerr = 0; int flag; crm_log_init("attrd_updater", LOG_ERR, FALSE, FALSE, argc, argv); crm_debug_3("Begining option processing"); while ((flag = getopt(argc, argv, OPTARGS)) != EOF) { switch(flag) { case 'V': alter_debug(DEBUG_INC); break; case 'h': /* Help message */ usage(crm_system_name, LSB_EXIT_OK); break; case 'n': attr_name = crm_strdup(optarg); break; case 'v': attr_value = crm_strdup(optarg); break; case 's': attr_set = crm_strdup(optarg); break; case 'd': attr_dampen = crm_strdup(optarg); break; case 'S': attr_section = crm_strdup(optarg); break; default: ++argerr; break; } } crm_debug_3("Option processing complete"); if (optind > argc) { ++argerr; } if(attr_name == NULL) { ++argerr; } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } /* read local config file */ init_client_ipc_comms(T_ATTRD, subsystem_msg_dispatch, (void*)process_attrd_message, &attrd); if(attrd == NULL) { fprintf(stderr, "Could not connect to "T_ATTRD"\n"); return 1; } - update = ha_msg_new(4); - ha_msg_add(update, F_TYPE, T_ATTRD); - ha_msg_add(update, F_ORIG, crm_system_name); - ha_msg_add(update, F_ATTRD_TASK, "update"); - ha_msg_add(update, F_ATTRD_ATTRIBUTE, attr_name); + update = create_xml_node(NULL, __FUNCTION__); + crm_xml_add(update, F_TYPE, T_ATTRD); + crm_xml_add(update, F_ORIG, crm_system_name); + crm_xml_add(update, F_ATTRD_TASK, "update"); + crm_xml_add(update, F_ATTRD_ATTRIBUTE, attr_name); if(attr_value != NULL) { - ha_msg_add(update, F_ATTRD_VALUE, attr_value); + crm_xml_add(update, F_ATTRD_VALUE, attr_value); } if(attr_set != NULL) { - ha_msg_add(update, F_ATTRD_SET, attr_set); + crm_xml_add(update, F_ATTRD_SET, attr_set); } if(attr_section != NULL) { - ha_msg_add(update, F_ATTRD_SECTION, attr_section); + crm_xml_add(update, F_ATTRD_SECTION, attr_section); } if(attr_dampen != NULL) { - ha_msg_add(update, F_ATTRD_DAMPEN, attr_dampen); + crm_xml_add(update, F_ATTRD_DAMPEN, attr_dampen); } if(send_ipc_message(attrd, update) == FALSE) { fprintf(stderr, "Could not send update\n"); - crm_msg_del(update); + free_xml(update); return 1; } - crm_msg_del(update); + free_xml(update); return 0; } void usage(const char* cmd, int exit_status) { FILE* stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s -n [-vdsS]\n", cmd); fprintf(stream, "\t-n \tthe attribute that changed\n"); fprintf(stream, "\t-v \tthe attribute's value\n"); fprintf(stream, "\t\tIf no value is supplied, the attribute value for this node will be deleted\n"); fprintf(stream, "\t-d \tthe time to wait (dampening) further changes occur\n"); fprintf(stream, "\t-s \tthe attribute set in which to place the value\n"); fprintf(stream, "\t\tMost people have no need to specify this\n"); fprintf(stream, "\t-S \tthe section in which to place the value\n"); fprintf(stream, "\t\tMost people have no need to specify this\n"); fflush(stream); exit(exit_status); } diff --git a/tools/pingd.c b/tools/pingd.c index 2988e996f1..8b35c9fa7d 100644 --- a/tools/pingd.c +++ b/tools/pingd.c @@ -1,468 +1,468 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_GETOPT_H # include #endif #if SUPPORT_HEARTBEAT # include ll_cluster_t *pingd_cluster = NULL; void do_node_walk(ll_cluster_t *hb_cluster); #endif /* GMainLoop *mainloop = NULL; */ #define OPTARGS "V?p:a:d:s:S:h:Dm:" IPC_Channel *attrd = NULL; GMainLoop* mainloop = NULL; GHashTable *ping_nodes = NULL; const char *pingd_attr = "pingd"; gboolean do_filter = FALSE; gboolean need_shutdown = FALSE; const char *attr_set = NULL; const char *attr_section = NULL; const char *attr_dampen = NULL; int attr_multiplier = 1; void pingd_nstatus_callback( const char *node, const char *status, void *private_data); void pingd_lstatus_callback( const char *node, const char *link, const char *status, void *private_data); void send_update(void); static gboolean pingd_shutdown(int nsig, gpointer unused) { need_shutdown = TRUE; send_update(); crm_info("Exiting"); if (mainloop != NULL && g_main_is_running(mainloop)) { g_main_quit(mainloop); } else { exit(0); } return FALSE; } static void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-%s]\n", cmd, OPTARGS); fprintf(stream, "\t--%s (-%c) \t\t\tThis text\n", "help", '?'); fprintf(stream, "\t--%s (-%c) \t\tRun in daemon mode\n", "daemonize", 'D'); fprintf(stream, "\t--%s (-%c) \tFile in which to store the process' PID\n" "\t\t\t\t\t* Default=/tmp/pingd.pid\n", "pid-file", 'p'); fprintf(stream, "\t--%s (-%c) \tName of the node attribute to set\n" "\t\t\t\t\t* Default=pingd\n", "attr-name", 'a'); fprintf(stream, "\t--%s (-%c) \tName of the set in which to set the attribute\n" "\t\t\t\t\t* Default=cib-bootstrap-options\n", "attr-set", 's'); fprintf(stream, "\t--%s (-%c) \tWhich part of the CIB to put the attribute in\n" "\t\t\t\t\t* Default=status\n", "attr-section", 'S'); fprintf(stream, "\t--%s (-%c) \tMonitor a subset of the ping nodes listed in ha.cf (can be specified multiple times)\n", "ping-host", 'h'); fprintf(stream, "\t--%s (-%c) \t\tHow long to wait for no further changes to occur before updating the CIB with a changed attribute\n", "attr-dampen", 'd'); fprintf(stream, "\t--%s (-%c) \tFor every connected node, add to the value set in the CIB\n" "\t\t\t\t\t\t* Default=1\n", "value-multiplier", 'm'); fflush(stream); exit(exit_status); } #if SUPPORT_HEARTBEAT static gboolean pingd_ha_dispatch(IPC_Channel *channel, gpointer user_data) { gboolean stay_connected = TRUE; crm_debug_2("Invoked"); while(pingd_cluster != NULL && IPC_ISRCONN(channel)) { if(pingd_cluster->llc_ops->msgready(pingd_cluster) == 0) { crm_debug_2("no message ready yet"); break; } /* invoke the callbacks but dont block */ pingd_cluster->llc_ops->rcvmsg(pingd_cluster, 0); } if (pingd_cluster == NULL || channel->ch_status != IPC_CONNECT) { if(need_shutdown == FALSE) { crm_crit("Lost connection to heartbeat service."); } else { crm_info("Lost connection to heartbeat service."); } stay_connected = FALSE; } return stay_connected; } static void pingd_ha_connection_destroy(gpointer user_data) { crm_debug_3("Invoked"); if(need_shutdown) { /* we signed out, so this is expected */ crm_info("Heartbeat disconnection complete"); return; } crm_crit("Lost connection to heartbeat service!"); } static gboolean register_with_ha(void) { if(pingd_cluster == NULL) { pingd_cluster = ll_cluster_new("heartbeat"); } if(pingd_cluster == NULL) { crm_err("Cannot create heartbeat object"); return FALSE; } crm_debug("Signing in with Heartbeat"); if (pingd_cluster->llc_ops->signon( pingd_cluster, crm_system_name) != HA_OK) { crm_err("Cannot sign on with heartbeat: %s", pingd_cluster->llc_ops->errmsg(pingd_cluster)); crm_err("REASON: %s", pingd_cluster->llc_ops->errmsg(pingd_cluster)); return FALSE; } do_node_walk(pingd_cluster); crm_debug_3("Be informed of Node Status changes"); if (HA_OK != pingd_cluster->llc_ops->set_nstatus_callback( pingd_cluster, pingd_nstatus_callback, NULL)) { crm_err("Cannot set nstatus callback: %s", pingd_cluster->llc_ops->errmsg(pingd_cluster)); crm_err("REASON: %s", pingd_cluster->llc_ops->errmsg(pingd_cluster)); return FALSE; } if (pingd_cluster->llc_ops->set_ifstatus_callback( pingd_cluster, pingd_lstatus_callback, NULL) != HA_OK) { cl_log(LOG_ERR, "Cannot set if status callback"); crm_err("REASON: %s", pingd_cluster->llc_ops->errmsg(pingd_cluster)); return FALSE; } crm_debug_3("Adding channel to mainloop"); G_main_add_IPC_Channel( G_PRIORITY_HIGH, pingd_cluster->llc_ops->ipcchan( pingd_cluster), FALSE, pingd_ha_dispatch, pingd_cluster, pingd_ha_connection_destroy); return TRUE; } void do_node_walk(ll_cluster_t *hb_cluster) { const char *ha_node = NULL; /* Async get client status information in the cluster */ crm_debug_2("Invoked"); crm_debug_3("Requesting an initial dump of CRMD client_status"); hb_cluster->llc_ops->client_status( hb_cluster, NULL, CRM_SYSTEM_CRMD, -1); crm_info("Requesting the list of configured nodes"); hb_cluster->llc_ops->init_nodewalk(hb_cluster); do { const char *ha_node_type = NULL; const char *ha_node_status = NULL; ha_node = hb_cluster->llc_ops->nextnode(hb_cluster); if(ha_node == NULL) { continue; } ha_node_type = hb_cluster->llc_ops->node_type( hb_cluster, ha_node); if(safe_str_neq("ping", ha_node_type)) { crm_debug("Node %s: skipping '%s'", ha_node, ha_node_type); continue; } if(do_filter && g_hash_table_lookup(ping_nodes, ha_node) == NULL) { crm_debug("Filtering: %s", ha_node); continue; } ha_node_status = hb_cluster->llc_ops->node_status( hb_cluster, ha_node); crm_debug("Adding: %s=%s", ha_node, ha_node_status); g_hash_table_replace(ping_nodes, crm_strdup(ha_node), crm_strdup(ha_node_status)); } while(ha_node != NULL); hb_cluster->llc_ops->end_nodewalk(hb_cluster); crm_debug_2("Complete"); send_update(); } #endif int main(int argc, char **argv) { int lpc; int argerr = 0; int flag; char *pid_file = NULL; gboolean daemonize = FALSE; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"pid-file", 1, 0, 'p'}, {"ping-host", 1, 0, 'h'}, {"attr-name", 1, 0, 'a'}, {"attr-set", 1, 0, 's'}, {"daemonize", 0, 0, 'D'}, {"attr-section", 1, 0, 'S'}, {"attr-dampen", 1, 0, 'd'}, {"value-multiplier", 1, 0, 'm'}, {0, 0, 0, 0} }; #endif pid_file = crm_strdup("/tmp/pingd.pid"); G_main_add_SignalHandler( G_PRIORITY_HIGH, SIGTERM, pingd_shutdown, NULL, NULL); ping_nodes = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); crm_log_init(basename(argv[0]), LOG_INFO, TRUE, FALSE, argc, argv); 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) { case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case 'p': pid_file = crm_strdup(optarg); break; case 'a': pingd_attr = crm_strdup(optarg); break; case 'h': do_filter = TRUE; fprintf(stdout, "Adding ping host %s", optarg); g_hash_table_insert(ping_nodes, crm_strdup(optarg), crm_strdup(optarg)); break; case 's': attr_set = crm_strdup(optarg); break; case 'm': attr_multiplier = crm_parse_int(optarg, "1"); break; case 'S': attr_section = crm_strdup(optarg); break; case 'd': attr_dampen = crm_strdup(optarg); break; case 'D': daemonize = TRUE; break; case '?': usage(crm_system_name, LSB_EXIT_GENERIC); break; default: printf("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag); crm_err("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag); ++argerr; break; } } if (optind < argc) { crm_err("non-option ARGV-elements: "); printf("non-option ARGV-elements: "); while (optind < argc) { crm_err("%s ", argv[optind++]); printf("%s ", argv[optind++]); } printf("\n"); } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } crm_make_daemon(crm_system_name, daemonize, pid_file); for(lpc = 0; attrd == NULL && lpc < 30; lpc++) { crm_debug("attrd registration attempt: %d", lpc); sleep(5); attrd = init_client_ipc_comms_nodispatch(T_ATTRD); } if(attrd == NULL) { crm_err("attrd registration failed"); cl_flush_logs(); exit(LSB_EXIT_GENERIC); } #if SUPPORT_HEARTBEAT if(register_with_ha() == FALSE) { crm_err("HA registration failed"); cl_flush_logs(); exit(LSB_EXIT_GENERIC); } #endif crm_info("Starting %s", crm_system_name); mainloop = g_main_new(FALSE); g_main_run(mainloop); crm_info("Exiting %s", crm_system_name); return 0; } static void count_ping_nodes(gpointer key, gpointer value, gpointer user_data) { int *num_active = user_data; CRM_CHECK(num_active != NULL, return); if(need_shutdown) { return; } if(safe_str_eq(value, "ping")) { (*num_active)++; } else if(safe_str_eq(value, "up")) { (*num_active)++; } } void send_update(void) { int num_active = 0; - HA_Message *update = ha_msg_new(4); - ha_msg_add(update, F_TYPE, T_ATTRD); - ha_msg_add(update, F_ORIG, crm_system_name); - ha_msg_add(update, F_ATTRD_TASK, "update"); - ha_msg_add(update, F_ATTRD_ATTRIBUTE, pingd_attr); + xmlNode *update = create_xml_node(NULL, __FUNCTION__); + crm_xml_add(update, F_TYPE, T_ATTRD); + crm_xml_add(update, F_ORIG, crm_system_name); + crm_xml_add(update, F_ATTRD_TASK, "update"); + crm_xml_add(update, F_ATTRD_ATTRIBUTE, pingd_attr); g_hash_table_foreach(ping_nodes, count_ping_nodes, &num_active); crm_info("%d active ping nodes", num_active); - ha_msg_add_int(update, F_ATTRD_VALUE, attr_multiplier*num_active); + crm_xml_add_int(update, F_ATTRD_VALUE, attr_multiplier*num_active); if(attr_set != NULL) { - ha_msg_add(update, F_ATTRD_SET, attr_set); + crm_xml_add(update, F_ATTRD_SET, attr_set); } if(attr_section != NULL) { - ha_msg_add(update, F_ATTRD_SECTION, attr_section); + crm_xml_add(update, F_ATTRD_SECTION, attr_section); } if(attr_dampen != NULL) { - ha_msg_add(update, F_ATTRD_DAMPEN, attr_dampen); + crm_xml_add(update, F_ATTRD_DAMPEN, attr_dampen); } if(send_ipc_message(attrd, update) == FALSE) { crm_err("Could not send update"); exit(1); } - crm_msg_del(update); + free_xml(update); } void pingd_nstatus_callback( const char *node, const char * status, void* private_data) { crm_notice("Status update: Ping node %s now has status [%s]", node, status); if(g_hash_table_lookup(ping_nodes, node) != NULL) { g_hash_table_replace( ping_nodes, crm_strdup(node), crm_strdup(status)); send_update(); } } void pingd_lstatus_callback(const char *node, const char *lnk, const char *status, void *private) { crm_notice("Status update: Ping node %s now has status [%s]", node, status); pingd_nstatus_callback(node, status, private); } diff --git a/transitioner/actions.c b/transitioner/actions.c index cf96361ffa..f31ad91779 100644 --- a/transitioner/actions.c +++ b/transitioner/actions.c @@ -1,520 +1,520 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include char *te_uuid = NULL; IPC_Channel *crm_ch = NULL; void send_rsc_command(crm_action_t *action); extern crm_action_timer_t *transition_timer; static void te_start_action_timer(crm_action_t *action) { crm_malloc0(action->timer, sizeof(crm_action_timer_t)); action->timer->timeout = action->timeout; action->timer->reason = timeout_action_warn; action->timer->action = action; action->timer->source_id = Gmain_timeout_add( action->timer->timeout, action_timer_callback, (void*)action->timer); CRM_ASSERT(action->timer->source_id != 0); } static gboolean te_pseudo_action(crm_graph_t *graph, crm_action_t *pseudo) { crm_info("Pseudo action %d fired and confirmed", pseudo->id); pseudo->confirmed = TRUE; update_graph(graph, pseudo); trigger_graph(); return TRUE; } #if SUPPORT_HEARTBEAT void send_stonith_update(stonith_ops_t * op) { enum cib_errors rc = cib_ok; const char *target = op->node_name; const char *uuid = op->node_uuid; /* zero out the node-status & remove all LRM status info */ - crm_data_t *node_state = create_xml_node(NULL, XML_CIB_TAG_STATE); + xmlNode *node_state = create_xml_node(NULL, XML_CIB_TAG_STATE); CRM_CHECK(op->node_name != NULL, return); CRM_CHECK(op->node_uuid != NULL, return); crm_xml_add(node_state, XML_ATTR_UUID, uuid); crm_xml_add(node_state, XML_ATTR_UNAME, target); crm_xml_add(node_state, XML_CIB_ATTR_HASTATE, DEADSTATUS); crm_xml_add(node_state, XML_CIB_ATTR_INCCM, XML_BOOLEAN_NO); crm_xml_add(node_state, XML_CIB_ATTR_CRMDSTATE, OFFLINESTATUS); crm_xml_add(node_state, XML_CIB_ATTR_JOINSTATE, CRMD_JOINSTATE_DOWN); crm_xml_add(node_state, XML_CIB_ATTR_EXPSTATE, CRMD_JOINSTATE_DOWN); crm_xml_add(node_state, XML_CIB_ATTR_REPLACE, XML_CIB_TAG_LRM); crm_xml_add(node_state, XML_ATTR_ORIGIN, __FUNCTION__); rc = te_cib_conn->cmds->update( te_cib_conn, XML_CIB_TAG_STATUS, node_state, NULL, cib_quorum_override|cib_scope_local); if(rc < cib_ok) { crm_err("CIB update failed: %s", cib_error2string(rc)); abort_transition( INFINITY, tg_shutdown, "CIB update failed", node_state); } else { /* delay processing the trigger until the update completes */ add_cib_op_callback(rc, FALSE, NULL, cib_fencing_updated); } free_xml(node_state); return; } #endif static gboolean te_fence_node(crm_graph_t *graph, crm_action_t *action) { #if SUPPORT_HEARTBEAT if(is_heartbeat_cluster()) { const char *id = NULL; const char *uuid = NULL; const char *target = NULL; const char *type = NULL; stonith_ops_t * st_op = NULL; id = ID(action->xml); target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); uuid = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID); type = g_hash_table_lookup(action->params, crm_meta_name("stonith_action")); CRM_CHECK(id != NULL, crm_log_xml_warn(action->xml, "BadAction"); return FALSE); CRM_CHECK(uuid != NULL, crm_log_xml_warn(action->xml, "BadAction"); return FALSE); CRM_CHECK(type != NULL, crm_log_xml_warn(action->xml, "BadAction"); return FALSE); CRM_CHECK(target != NULL, crm_log_xml_warn(action->xml, "BadAction"); return FALSE); te_log_action(LOG_INFO, "Executing %s fencing operation (%s) on %s (timeout=%d)", type, id, target, transition_graph->transition_timeout / 2); /* Passing NULL means block until we can connect... */ te_connect_stonith(NULL); crm_malloc0(st_op, sizeof(stonith_ops_t)); if(safe_str_eq(type, "poweroff")) { st_op->optype = POWEROFF; } else { st_op->optype = RESET; } st_op->timeout = transition_graph->transition_timeout / 2; st_op->node_name = crm_strdup(target); st_op->node_uuid = crm_strdup(uuid); st_op->private_data = generate_transition_key( transition_graph->id, action->id, te_uuid); CRM_ASSERT(stonithd_input_IPC_channel() != NULL); if (ST_OK != stonithd_node_fence( st_op )) { crm_err("Cannot fence %s: stonithd_node_fence() call failed ", target); } return TRUE; } #endif return FALSE; } static gboolean te_crm_command(crm_graph_t *graph, crm_action_t *action) { char *value = NULL; char *counter = NULL; - HA_Message *cmd = NULL; + xmlNode *cmd = NULL; const char *id = NULL; const char *task = NULL; const char *on_node = NULL; gboolean ret = TRUE; id = ID(action->xml); task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); on_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); CRM_CHECK(on_node != NULL && strlen(on_node) != 0, te_log_action(LOG_ERR, "Corrupted command (id=%s) %s: no node", crm_str(id), crm_str(task)); return FALSE); te_log_action(LOG_INFO, "Executing crm-event (%s): %s on %s", crm_str(id), crm_str(task), on_node); cmd = create_request(task, NULL, on_node, CRM_SYSTEM_CRMD, CRM_SYSTEM_TENGINE, NULL); counter = generate_transition_key( transition_graph->id, action->id, te_uuid); crm_xml_add(cmd, XML_ATTR_TRANSITION_KEY, counter); ret = send_ipc_message(crm_ch, cmd); crm_free(counter); - crm_msg_del(cmd); + free_xml(cmd); value = g_hash_table_lookup(action->params, crm_meta_name(XML_ATTR_TE_NOWAIT)); if(ret == FALSE) { crm_err("Action %d failed: send", action->id); return FALSE; } else if(crm_is_true(value)) { crm_info("Skipping wait for %d", action->id); action->confirmed = TRUE; update_graph(graph, action); trigger_graph(); } else if(ret && action->timeout > 0) { crm_debug("Setting timer for action %d",action->id); action->timer->reason = timeout_action_warn; te_start_action_timer(action); } return TRUE; } static gboolean te_rsc_command(crm_graph_t *graph, crm_action_t *action) { /* never overwrite stop actions in the CIB with * anything other than completed results * * Writing pending stops makes it look like the * resource is running again */ const char *task = NULL; const char *on_node = NULL; action->executed = FALSE; on_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); CRM_CHECK(on_node != NULL && strlen(on_node) != 0, te_log_action(LOG_ERR, "Corrupted command(id=%s) %s: no node", ID(action->xml), crm_str(task)); return FALSE); send_rsc_command(action); return TRUE; } gboolean cib_action_update(crm_action_t *action, int status) { char *op_id = NULL; char *code = NULL; char *digest = NULL; - crm_data_t *tmp = NULL; - crm_data_t *params = NULL; - crm_data_t *state = NULL; - crm_data_t *rsc = NULL; - crm_data_t *xml_op = NULL; - crm_data_t *action_rsc = NULL; + xmlNode *tmp = NULL; + xmlNode *params = NULL; + xmlNode *state = NULL; + xmlNode *rsc = NULL; + xmlNode *xml_op = NULL; + xmlNode *action_rsc = NULL; enum cib_errors rc = cib_ok; const char *name = NULL; const char *value = NULL; const char *rsc_id = NULL; const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); const char *target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); const char *task_uuid = crm_element_value( action->xml, XML_LRM_ATTR_TASK_KEY); const char *target_uuid = crm_element_value( action->xml, XML_LRM_ATTR_TARGET_UUID); int call_options = cib_quorum_override|cib_scope_local; crm_warn("%s %d: %s on %s timed out", crm_element_name(action->xml), action->id, task_uuid, target); action_rsc = find_xml_node(action->xml, XML_CIB_TAG_RESOURCE, TRUE); if(action_rsc == NULL) { return FALSE; } rsc_id = ID(action_rsc); CRM_CHECK(rsc_id != NULL, crm_log_xml_err(action->xml, "Bad:action"); return FALSE); code = crm_itoa(status); /* update the CIB */ state = create_xml_node(NULL, XML_CIB_TAG_STATE); crm_xml_add(state, XML_ATTR_UUID, target_uuid); crm_xml_add(state, XML_ATTR_UNAME, target); rsc = create_xml_node(state, XML_CIB_TAG_LRM); crm_xml_add(rsc, XML_ATTR_ID, target_uuid); rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCES); rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCE); crm_xml_add(rsc, XML_ATTR_ID, rsc_id); name = XML_ATTR_TYPE; value = crm_element_value(action_rsc, name); crm_xml_add(rsc, name, value); name = XML_AGENT_ATTR_CLASS; value = crm_element_value(action_rsc, name); crm_xml_add(rsc, name, value); name = XML_AGENT_ATTR_PROVIDER; value = crm_element_value(action_rsc, name); crm_xml_add(rsc, name, value); xml_op = create_xml_node(rsc, XML_LRM_TAG_RSC_OP); crm_xml_add(xml_op, XML_ATTR_ID, task); op_id = generate_op_key(rsc_id, task, action->interval); crm_xml_add(xml_op, XML_ATTR_ID, op_id); crm_free(op_id); crm_xml_add(xml_op, XML_LRM_ATTR_TASK, task); crm_xml_add(xml_op, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET); crm_xml_add(xml_op, XML_LRM_ATTR_OPSTATUS, code); crm_xml_add(xml_op, XML_LRM_ATTR_CALLID, "-1"); crm_xml_add_int(xml_op, XML_LRM_ATTR_INTERVAL, action->interval); crm_xml_add(xml_op, XML_LRM_ATTR_RC, code); crm_xml_add(xml_op, XML_ATTR_ORIGIN, __FUNCTION__); crm_free(code); code = generate_transition_key(transition_graph->id, action->id,te_uuid); crm_xml_add(xml_op, XML_ATTR_TRANSITION_KEY, code); crm_free(code); code = generate_transition_magic( crm_element_value(xml_op, XML_ATTR_TRANSITION_KEY), status, status); crm_xml_add(xml_op, XML_ATTR_TRANSITION_MAGIC, code); crm_free(code); tmp = find_xml_node(action->xml, "attributes", TRUE); params = create_xml_node(NULL, XML_TAG_PARAMS); copy_in_properties(params, tmp); filter_action_parameters(params, CRM_FEATURE_SET); digest = calculate_xml_digest(params, TRUE, FALSE); /* info for now as this area has been problematic to debug */ crm_debug("Calculated digest %s for %s (%s)\n", digest, ID(xml_op), crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC)); crm_log_xml(LOG_DEBUG, "digest:source", params); crm_xml_add(xml_op, XML_LRM_ATTR_OP_DIGEST, digest); crm_free(digest); free_xml(params); crm_debug_3("Updating CIB with \"%s\" (%s): %s %s on %s", status<0?"new action":XML_ATTR_TIMEOUT, crm_element_name(action->xml), crm_str(task), rsc_id, target); rc = te_cib_conn->cmds->update( te_cib_conn, XML_CIB_TAG_STATUS, state, NULL, call_options); crm_debug("Updating CIB with %s action %d: %s on %s (call_id=%d)", op_status2text(status), action->id, task_uuid, target, rc); add_cib_op_callback(rc, FALSE, NULL, cib_action_updated); free_xml(state); action->sent_update = TRUE; if(rc < cib_ok) { return FALSE; } return TRUE; } void send_rsc_command(crm_action_t *action) { - HA_Message *cmd = NULL; - crm_data_t *rsc_op = NULL; + xmlNode *cmd = NULL; + xmlNode *rsc_op = NULL; char *counter = NULL; const char *task = NULL; const char *value = NULL; const char *on_node = NULL; const char *task_uuid = NULL; CRM_ASSERT(action != NULL); CRM_ASSERT(action->xml != NULL); rsc_op = action->xml; task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); task_uuid = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY); on_node = crm_element_value(rsc_op, XML_LRM_ATTR_TARGET); counter = generate_transition_key( transition_graph->id, action->id, te_uuid); crm_xml_add(rsc_op, XML_ATTR_TRANSITION_KEY, counter); crm_info("Initiating action %d: %s on %s", action->id, task_uuid, on_node); crm_free(counter); if(rsc_op != NULL) { crm_log_xml_debug_2(rsc_op, "Performing"); } cmd = create_request(CRM_OP_INVOKE_LRM, rsc_op, on_node, CRM_SYSTEM_LRMD, CRM_SYSTEM_TENGINE, NULL); #if 1 send_ipc_message(crm_ch, cmd); #else /* test the TE timer/recovery code */ if((action->id % 11) == 0) { crm_err("Faking lost action %d: %s", action->id, task_uuid); } else { send_ipc_message(crm_ch, cmd); } #endif - crm_msg_del(cmd); + free_xml(cmd); action->executed = TRUE; value = g_hash_table_lookup(action->params, crm_meta_name(XML_ATTR_TE_NOWAIT)); if(crm_is_true(value)) { crm_debug("Skipping wait for %d", action->id); action->confirmed = TRUE; update_graph(transition_graph, action); trigger_graph(); } else if(action->timeout > 0) { int action_timeout = (2 * action->timeout) + transition_graph->network_delay; crm_debug_3("Setting timer for action %s", task_uuid); if(transition_graph->transition_timeout < action_timeout) { crm_debug("Action %d:" " Increasing transition %d timeout to %d (2*%d + %d)", action->id, transition_graph->id, action_timeout, action->timeout, transition_graph->network_delay); transition_graph->transition_timeout = action_timeout; } te_start_action_timer(action); } } crm_graph_functions_t te_graph_fns = { te_pseudo_action, te_rsc_command, te_crm_command, te_fence_node }; extern GMainLoop* mainloop; void notify_crmd(crm_graph_t *graph) { - HA_Message *cmd = NULL; + xmlNode *cmd = NULL; int log_level = LOG_DEBUG; const char *op = CRM_OP_TEABORT; int pending_callbacks = num_cib_op_callbacks(); stop_te_timer(transition_timer); if(pending_callbacks != 0) { crm_warn("Delaying completion until all CIB updates complete"); return; } CRM_CHECK(graph->complete, graph->complete = TRUE); switch(graph->completion_action) { case tg_stop: op = CRM_OP_TECOMPLETE; log_level = LOG_INFO; break; case tg_abort: case tg_restart: op = CRM_OP_TEABORT; break; case tg_shutdown: crm_info("Exiting after transition"); if (mainloop != NULL && g_main_is_running(mainloop)) { g_main_quit(mainloop); return; } exit(LSB_EXIT_OK); } te_log_action(log_level, "Transition %d status: %s - %s", graph->id, op, crm_str(graph->abort_reason)); print_graph(LOG_DEBUG_3, graph); cmd = create_request( op, NULL, NULL, CRM_SYSTEM_DC, CRM_SYSTEM_TENGINE, NULL); if(graph->abort_reason != NULL) { - ha_msg_add(cmd, "message", graph->abort_reason); + crm_xml_add(cmd, "message", graph->abort_reason); } send_ipc_message(crm_ch, cmd); - crm_msg_del(cmd); + free_xml(cmd); graph->abort_reason = NULL; graph->completion_action = tg_restart; } diff --git a/transitioner/callbacks.c b/transitioner/callbacks.c index 63f6e474c1..d0bbf5fc5f 100644 --- a/transitioner/callbacks.c +++ b/transitioner/callbacks.c @@ -1,591 +1,589 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include -void te_update_confirm(const char *event, HA_Message *msg); -void te_update_diff(const char *event, HA_Message *msg); -crm_data_t *need_abort(crm_data_t *update); -void cib_fencing_updated(const HA_Message *msg, int call_id, int rc, - crm_data_t *output, void *user_data); +void te_update_confirm(const char *event, xmlNode *msg); +void te_update_diff(const char *event, xmlNode *msg); +xmlNode *need_abort(xmlNode *update); extern char *te_uuid; gboolean shuttingdown = FALSE; crm_graph_t *transition_graph; GTRIGSource *transition_trigger = NULL; crm_action_timer_t *transition_timer = NULL; static gboolean start_global_timer(crm_action_timer_t *timer, int timeout) { CRM_ASSERT(timer != NULL); CRM_CHECK(timer > 0, return FALSE); CRM_CHECK(timer->source_id == 0, return FALSE); if(timeout <= 0) { crm_err("Tried to start timer with period: %d", timeout); } else if(timer->source_id == 0) { crm_debug_2("Starting abort timer: %dms", timeout); timer->timeout = timeout; timer->source_id = Gmain_timeout_add( timeout, global_timer_callback, (void*)timer); CRM_ASSERT(timer->source_id != 0); return TRUE; } else { crm_err("Timer is already active with period: %d", timer->timeout); } return FALSE; } void -te_update_diff(const char *event, HA_Message *msg) +te_update_diff(const char *event, xmlNode *msg) { int rc = -1; const char *op = NULL; - crm_data_t *diff = NULL; - crm_data_t *aborted = NULL; + xmlNode *diff = NULL; + xmlNode *aborted = NULL; const char *set_name = NULL; int diff_add_updates = 0; int diff_add_epoch = 0; int diff_add_admin_epoch = 0; int diff_del_updates = 0; int diff_del_epoch = 0; int diff_del_admin_epoch = 0; 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); + crm_element_value_int(msg, F_CIB_RC, &rc); + op = crm_element_value(msg, F_CIB_OPERATION); if(rc < cib_ok) { crm_debug_2("Ignoring failed %s operation: %s", op, cib_error2string(rc)); return; } diff = get_message_xml(msg, F_CIB_UPDATE_RESULT); cib_diff_version_details( diff, &diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates, &diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates); crm_debug("Processing diff (%s): %d.%d.%d -> %d.%d.%d", op, diff_del_admin_epoch,diff_del_epoch,diff_del_updates, diff_add_admin_epoch,diff_add_epoch,diff_add_updates); log_cib_diff(LOG_DEBUG_2, diff, op); set_name = "diff-added"; if(diff != NULL) { - crm_data_t *section = NULL; - crm_data_t *change_set = find_xml_node(diff, set_name, FALSE); + xmlNode *section = NULL; + xmlNode *change_set = find_xml_node(diff, set_name, FALSE); change_set = find_xml_node(change_set, XML_TAG_CIB, FALSE); if(change_set != NULL) { crm_debug_2("Checking status changes"); section=get_object_root(XML_CIB_TAG_STATUS,change_set); } if(section != NULL) { extract_event(section); } crm_debug_2("Checking change set: %s", set_name); aborted = need_abort(change_set); } set_name = "diff-removed"; if(diff != NULL && aborted == NULL) { - crm_data_t *attrs = NULL; - crm_data_t *status = NULL; - crm_data_t *change_set = find_xml_node(diff, set_name, FALSE); + xmlNode *attrs = NULL; + xmlNode *status = NULL; + xmlNode *change_set = find_xml_node(diff, set_name, FALSE); change_set = find_xml_node(change_set, XML_TAG_CIB, FALSE); crm_debug_2("Checking change set: %s", set_name); aborted = need_abort(change_set); if(aborted == NULL && change_set != NULL) { status = get_object_root(XML_CIB_TAG_STATUS, change_set); xml_child_iter_filter( status, node_state, XML_CIB_TAG_STATE, attrs = find_xml_node( node_state, XML_TAG_TRANSIENT_NODEATTRS, FALSE); if(attrs != NULL) { crm_info("Aborting on "XML_TAG_TRANSIENT_NODEATTRS" deletions"); abort_transition(INFINITY, tg_restart, XML_TAG_TRANSIENT_NODEATTRS, attrs); } ); } } if(aborted != NULL) { abort_transition( INFINITY, tg_restart, "Non-status change", NULL); } free_xml(diff); return; } gboolean -process_te_message(HA_Message *msg, crm_data_t *xml_data, IPC_Channel *sender) +process_te_message(xmlNode *msg, xmlNode *xml_data, IPC_Channel *sender) { - crm_data_t *xml_obj = NULL; + xmlNode *xml_obj = NULL; - const char *from = cl_get_string(msg, F_ORIG); - const char *sys_to = cl_get_string(msg, F_CRM_SYS_TO); - const char *sys_from = cl_get_string(msg, F_CRM_SYS_FROM); - const char *ref = cl_get_string(msg, XML_ATTR_REFERENCE); - const char *op = cl_get_string(msg, F_CRM_TASK); - const char *type = cl_get_string(msg, F_CRM_MSG_TYPE); + const char *from = crm_element_value(msg, F_ORIG); + const char *sys_to = crm_element_value(msg, F_CRM_SYS_TO); + const char *sys_from = crm_element_value(msg, F_CRM_SYS_FROM); + const char *ref = crm_element_value(msg, XML_ATTR_REFERENCE); + const char *op = crm_element_value(msg, F_CRM_TASK); + const char *type = crm_element_value(msg, F_CRM_MSG_TYPE); crm_debug_2("Processing %s (%s) message", op, ref); - crm_log_message(LOG_DEBUG_3, msg); + crm_log_xml(LOG_DEBUG_3, "ipc", msg); if(op == NULL){ /* error */ } else if(strcasecmp(op, CRM_OP_HELLO) == 0) { /* ignore */ } else if(sys_to == NULL || strcasecmp(sys_to, CRM_SYSTEM_TENGINE) != 0) { crm_debug_2("Bad sys-to %s", crm_str(sys_to)); return FALSE; } else if(safe_str_eq(op, CRM_OP_INVOKE_LRM) && safe_str_eq(sys_from, CRM_SYSTEM_LRMD) /* && safe_str_eq(type, XML_ATTR_RESPONSE) */ ){ #if CRM_DEPRECATED_SINCE_2_0_4 if(safe_str_eq(crm_element_name(xml_data), XML_TAG_CIB)) { xml_obj = xml_data; } else { xml_obj = find_xml_node(xml_data, XML_TAG_CIB, TRUE); } #else xml_obj = xml_data; CRM_CHECK(xml_obj != NULL, - crm_log_message_adv(LOG_ERR, "Invalid (N)ACK", msg); + crm_log_xml(LOG_ERR, "Invalid (N)ACK", msg); return FALSE); #endif CRM_CHECK(xml_obj != NULL, - crm_log_message_adv(LOG_ERR, "Invalid (N)ACK", msg); + crm_log_xml(LOG_ERR, "Invalid (N)ACK", msg); return FALSE); xml_obj = get_object_root(XML_CIB_TAG_STATUS, xml_obj); CRM_CHECK(xml_obj != NULL, - crm_log_message_adv(LOG_ERR, "Invalid (N)ACK", msg); + crm_log_xml(LOG_ERR, "Invalid (N)ACK", msg); return FALSE); - crm_log_message_adv(LOG_DEBUG_2, "Processing (N)ACK", msg); + crm_log_xml(LOG_DEBUG_2, "Processing (N)ACK", msg); crm_info("Processing (N)ACK %s from %s", - cl_get_string(msg, XML_ATTR_REFERENCE), from); + crm_element_value(msg, XML_ATTR_REFERENCE), from); extract_event(xml_obj); } else if(safe_str_eq(type, XML_ATTR_RESPONSE)) { crm_err("Message was a response not a request. Discarding"); return TRUE; } else if(strcasecmp(op, CRM_OP_TRANSITION) == 0) { - const char *graph_file = cl_get_string(msg, F_CRM_TGRAPH); - const char *graph_input = cl_get_string(msg, F_CRM_TGRAPH_INPUT); + const char *graph_file = crm_element_value(msg, F_CRM_TGRAPH); + const char *graph_input = crm_element_value(msg, F_CRM_TGRAPH_INPUT); CRM_CHECK(graph_file != NULL || xml_data != NULL, crm_err("No graph provided"); - crm_log_message(LOG_WARNING, msg); + crm_log_xml(LOG_WARNING, "no graph", msg); return TRUE); if(transition_graph->complete == FALSE) { crm_info("Another transition is already active"); abort_transition( INFINITY, tg_restart, "Transition Active", NULL); } else { - crm_data_t *graph_data = xml_data; + xmlNode *graph_data = xml_data; crm_debug("Processing graph derived from %s", graph_input); if(graph_file != NULL) { FILE *graph_fd = fopen(graph_file, "r"); CRM_CHECK(graph_fd != NULL, cl_perror("Could not open graph file %s", graph_file); return TRUE); graph_data = file2xml(graph_fd, FALSE); unlink(graph_file); fclose(graph_fd); } destroy_graph(transition_graph); transition_graph = unpack_graph(graph_data); start_global_timer(transition_timer, transition_graph->transition_timeout); trigger_graph(); print_graph(LOG_DEBUG_2, transition_graph); if(graph_data != xml_data) { free_xml(graph_data); } } } else if(strcasecmp(op, CRM_OP_TE_HALT) == 0) { abort_transition(INFINITY, tg_stop, "Peer Halt", NULL); } else if(strcasecmp(op, CRM_OP_TEABORT) == 0) { abort_transition(INFINITY, tg_restart, "Peer Cancelled", NULL); } else { crm_err("Unknown command: %s::%s from %s", type, op, sys_from); } crm_debug_3("finished processing message"); return TRUE; } #if SUPPORT_HEARTBEAT void tengine_stonith_callback(stonith_ops_t * op) { const char *allow_fail = NULL; int stonith_id = -1; int transition_id = -1; char *uuid = NULL; crm_action_t *stonith_action = NULL; if(op == NULL) { crm_err("Called with a NULL op!"); return; } crm_info("call=%d, optype=%d, node_name=%s, result=%d, node_list=%s, action=%s", op->call_id, op->optype, op->node_name, op->op_result, (char *)op->node_list, op->private_data); /* this will mark the event complete if a match is found */ CRM_CHECK(op->private_data != NULL, return); /* filter out old STONITH actions */ CRM_CHECK(decode_transition_key( op->private_data, &uuid, &transition_id, &stonith_id), crm_err("Invalid event detected"); goto bail; ); if(transition_graph->complete || stonith_id < 0 || safe_str_neq(uuid, te_uuid) || transition_graph->id != transition_id) { crm_info("Ignoring STONITH action initiated outside" " of the current transition"); } stonith_action = get_action(stonith_id, TRUE); if(stonith_action == NULL) { crm_err("Stonith action not matched"); goto bail; } switch(op->op_result) { case STONITH_SUCCEEDED: send_stonith_update(op); break; case STONITH_CANNOT: case STONITH_TIMEOUT: case STONITH_GENERIC: stonith_action->failed = TRUE; allow_fail = g_hash_table_lookup( stonith_action->params, crm_meta_name(XML_ATTR_TE_ALLOWFAIL)); if(FALSE == crm_is_true(allow_fail)) { crm_err("Stonith of %s failed (%d)..." " aborting transition.", op->node_name, op->op_result); abort_transition(INFINITY, tg_restart, "Stonith failed", NULL); } break; default: crm_err("Unsupported action result: %d", op->op_result); abort_transition(INFINITY, tg_restart, "Unsupport Stonith result", NULL); } update_graph(transition_graph, stonith_action); trigger_graph(); bail: crm_free(uuid); return; } void tengine_stonith_connection_destroy(gpointer user_data) { crm_err("Fencing daemon has left us"); stonith_src = NULL; if(stonith_src == NULL) { G_main_set_trigger(stonith_reconnect); } /* cbchan will be garbage at this point, arrange for it to be reset */ set_stonithd_input_IPC_channel_NULL(); return; } gboolean tengine_stonith_dispatch(IPC_Channel *sender, void *user_data) { int lpc = 0; while(stonithd_op_result_ready()) { if (sender->ch_status == IPC_DISCONNECT) { /* The message which was pending for us is that * the IPC status is now IPC_DISCONNECT */ break; } if(ST_FAIL == stonithd_receive_ops_result(FALSE)) { crm_err("stonithd_receive_ops_result() failed"); } else { lpc++; } } crm_debug_2("Processed %d messages", lpc); if (sender->ch_status == IPC_DISCONNECT) { return FALSE; } return TRUE; } #endif void -cib_fencing_updated(const HA_Message *msg, int call_id, int rc, - crm_data_t *output, void *user_data) +cib_fencing_updated(xmlNode *msg, int call_id, int rc, + xmlNode *output, void *user_data) { trigger_graph(); if(rc < cib_ok) { crm_err("CIB update failed: %s", cib_error2string(rc)); - crm_log_xml_warn(msg, "[Failed Update]"); + crm_log_xml_warn(msg, "Failed update"); } } void -cib_action_updated(const HA_Message *msg, int call_id, int rc, - crm_data_t *output, void *user_data) +cib_action_updated(xmlNode *msg, int call_id, int rc, + xmlNode *output, void *user_data) { trigger_graph(); if(rc < cib_ok) { crm_err("Update %d FAILED: %s", call_id, cib_error2string(rc)); } } gboolean action_timer_callback(gpointer data) { crm_action_timer_t *timer = NULL; if(data == NULL) { crm_err("Timer popped with no data"); return FALSE; } timer = (crm_action_timer_t*)data; stop_te_timer(timer); crm_warn("Timer popped (abort_level=%d, complete=%s)", transition_graph->abort_priority, transition_graph->complete?"true":"false"); CRM_CHECK(timer->action != NULL, return FALSE); if(transition_graph->complete) { crm_warn("Ignoring timeout while not in transition"); } else if(timer->reason == timeout_action_warn) { print_action( LOG_WARNING,"Action missed its timeout", timer->action); } else { /* fail the action */ cib_action_update(timer->action, LRM_OP_TIMEOUT); } return FALSE; } static int unconfirmed_actions(gboolean send_updates) { int unconfirmed = 0; const char *key = NULL; const char *task = NULL; const char *node = NULL; crm_debug_2("Unconfirmed actions..."); slist_iter( synapse, synapse_t, transition_graph->synapses, lpc, /* lookup event */ slist_iter( action, crm_action_t, synapse->actions, lpc2, if(action->executed == FALSE) { continue; } else if(action->confirmed) { continue; } unconfirmed++; task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); key = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY); crm_info("Action %s %d unconfirmed from %s", key, action->id, node); if(action->type != action_type_rsc) { continue; } else if(send_updates == FALSE) { continue; } else if(safe_str_eq(task, "cancel")) { /* we dont need to update the CIB with these */ continue; } else if(safe_str_eq(task, "stop")) { /* *never* update the CIB with these */ continue; } cib_action_update(action, LRM_OP_PENDING); ); ); if(unconfirmed > 0) { crm_warn("Waiting on %d unconfirmed actions", unconfirmed); } return unconfirmed; } gboolean global_timer_callback(gpointer data) { crm_action_timer_t *timer = NULL; if(data == NULL) { crm_err("Timer popped with no data"); return FALSE; } timer = (crm_action_timer_t*)data; stop_te_timer(timer); crm_warn("Timer popped (abort_level=%d, complete=%s)", transition_graph->abort_priority, transition_graph->complete?"true":"false"); CRM_CHECK(timer->action == NULL, return FALSE); if(transition_graph->complete) { crm_err("Ignoring timeout while not in transition"); } else if(timer->reason == timeout_abort) { int unconfirmed = unconfirmed_actions(FALSE); crm_warn("Transition abort timeout reached..." " marking transition complete."); transition_graph->complete = TRUE; abort_transition(INFINITY, tg_restart, "Global Timeout", NULL); if(unconfirmed != 0) { crm_warn("Writing %d unconfirmed actions to the CIB", unconfirmed); unconfirmed_actions(TRUE); } } return FALSE; } gboolean te_graph_trigger(gpointer user_data) { int timeout = 0; enum transition_status graph_rc = -1; if(transition_graph->complete) { notify_crmd(transition_graph); return TRUE; } graph_rc = run_graph(transition_graph); timeout = transition_graph->transition_timeout; print_graph(LOG_DEBUG_3, transition_graph); if(graph_rc == transition_active) { crm_debug_3("Transition not yet complete"); stop_te_timer(transition_timer); start_global_timer(transition_timer, timeout); return TRUE; } else if(graph_rc == transition_pending) { crm_debug_3("Transition not yet complete - no actions fired"); return TRUE; } if(graph_rc != transition_complete) { crm_err("Transition failed: %s", transition_status(graph_rc)); print_graph(LOG_WARNING, transition_graph); } transition_graph->complete = TRUE; notify_crmd(transition_graph); return TRUE; } diff --git a/transitioner/events.c b/transitioner/events.c index 1c146cd991..8590ca8ee8 100644 --- a/transitioner/events.c +++ b/transitioner/events.c @@ -1,542 +1,545 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include -crm_data_t *need_abort(crm_data_t *update); -void process_graph_event(crm_data_t *event, const char *event_node); -int match_graph_event(int action_id, crm_data_t *event, const char *event_node, +xmlNode *need_abort(xmlNode *update); +void process_graph_event(xmlNode *event, const char *event_node); +int match_graph_event(int action_id, xmlNode *event, const char *event_node, int op_status, int op_rc); -crm_data_t * -need_abort(crm_data_t *update) +xmlNode * +need_abort(xmlNode *update) { - crm_data_t *section_xml = NULL; + xmlNode *section_xml = NULL; const char *section = NULL; if(update == NULL) { return NULL; } xml_prop_iter(update, name, value, if(safe_str_eq(name, XML_ATTR_HAVE_QUORUM)) { goto do_abort; /* possibly not required */ } else if(safe_str_eq(name, XML_ATTR_NUMPEERS)) { goto do_abort; } else if(safe_str_eq(name, XML_ATTR_GENERATION)) { goto do_abort; } else if(safe_str_eq(name, XML_ATTR_GENERATION_ADMIN)) { goto do_abort; } continue; do_abort: crm_debug("Aborting on change to %s", name); crm_log_xml_debug(update, "Abort: CIB Attrs"); return update; ); section = XML_CIB_TAG_NODES; section_xml = get_object_root(section, update); xml_child_iter(section_xml, child, return section_xml; ); section = XML_CIB_TAG_RESOURCES; section_xml = get_object_root(section, update); xml_child_iter(section_xml, child, return section_xml; ); section = XML_CIB_TAG_CONSTRAINTS; section_xml = get_object_root(section, update); xml_child_iter(section_xml, child, return section_xml; ); section = XML_CIB_TAG_CRMCONFIG; section_xml = get_object_root(section, update); xml_child_iter(section_xml, child, return section_xml; ); return NULL; } static gboolean fail_incompletable_actions(crm_graph_t *graph, const char *down_node) { const char *target = NULL; - crm_data_t *last_action = NULL; + xmlNode *last_action = NULL; slist_iter( synapse, synapse_t, graph->synapses, lpc, if (synapse->confirmed) { continue; } slist_iter( action, crm_action_t, synapse->actions, lpc, if(action->type == action_type_pseudo || action->confirmed) { continue; } target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); if(safe_str_eq(target, down_node)) { action->failed = TRUE; last_action = action->xml; update_graph(graph, action); crm_notice("Action %d (%s) is scheduled for %s (offline)", action->id, ID(action->xml), down_node); } ); ); if(last_action != NULL) { crm_warn("Node %s shutdown resulted in un-runnable actions", down_node); abort_transition(INFINITY, tg_restart, "Node failure", last_action); return TRUE; } return FALSE; } gboolean -extract_event(crm_data_t *msg) +extract_event(xmlNode *msg) { int shutdown = 0; + const char *shutdown_s = NULL; const char *event_node = NULL; /* [cib fragment] ... */ crm_debug_4("Extracting event from %s", crm_element_name(msg)); xml_child_iter_filter( msg, node_state, XML_CIB_TAG_STATE, - crm_data_t *attrs = NULL; - crm_data_t *resources = NULL; + xmlNode *attrs = NULL; + xmlNode *resources = NULL; const char *ccm_state = crm_element_value( node_state, XML_CIB_ATTR_INCCM); const char *crmd_state = crm_element_value( node_state, XML_CIB_ATTR_CRMDSTATE); /* Transient node attribute changes... */ event_node = crm_element_value(node_state, XML_ATTR_ID); crm_debug_2("Processing state update from %s", event_node); crm_log_xml_debug_3(node_state, "Processing"); attrs = find_xml_node( node_state, XML_TAG_TRANSIENT_NODEATTRS, FALSE); if(attrs != NULL) { crm_info("Aborting on "XML_TAG_TRANSIENT_NODEATTRS" changes for %s", event_node); abort_transition(INFINITY, tg_restart, XML_TAG_TRANSIENT_NODEATTRS, attrs); } resources = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE); resources = find_xml_node( resources, XML_LRM_TAG_RESOURCES, FALSE); /* LRM resource update... */ xml_child_iter( resources, rsc, xml_child_iter( rsc, rsc_op, crm_log_xml_debug_3(rsc_op, "Processing resource update"); process_graph_event(rsc_op, event_node); ); ); /* * node state update... possibly from a shutdown we requested */ if(safe_str_eq(ccm_state, XML_BOOLEAN_FALSE) || safe_str_eq(crmd_state, CRMD_JOINSTATE_DOWN)) { crm_action_t *shutdown = NULL; shutdown = match_down_event(0, event_node, NULL); if(shutdown != NULL) { update_graph(transition_graph, shutdown); trigger_graph(); } else { crm_info("Stonith/shutdown of %s not matched", event_node); abort_transition(INFINITY, tg_restart, "Node failure", node_state); } fail_incompletable_actions(transition_graph, event_node); } - shutdown = 0; - ha_msg_value_int(node_state, XML_CIB_ATTR_SHUTDOWN, &shutdown); - if(shutdown != 0) { + shutdown_s = crm_element_value(node_state, XML_CIB_ATTR_SHUTDOWN); + if(shutdown_s) { + shutdown = crm_parse_int(shutdown_s, NULL); + } + if(shutdown_s && shutdown > 0) { crm_info("Aborting on "XML_CIB_ATTR_SHUTDOWN" attribute for %s", event_node); abort_transition(INFINITY, tg_restart, "Shutdown request", node_state); } ); return TRUE; } static void -update_failcount(crm_data_t *event, const char *event_node, int rc) +update_failcount(xmlNode *event, const char *event_node, int rc) { int interval = 0; char *task = NULL; char *rsc_id = NULL; char *attr_name = NULL; const char *id = ID(event); const char *on_uuid = event_node; const char *value = XML_NVPAIR_ATTR_VALUE"++"; if(rc == 99) { /* this is an internal code for "we're busy, try again" */ return; } CRM_CHECK(on_uuid != NULL, return); CRM_CHECK(parse_op_key(id, &rsc_id, &task, &interval), crm_err("Couldn't parse: %s", ID(event)); goto bail); CRM_CHECK(task != NULL, goto bail); CRM_CHECK(rsc_id != NULL, goto bail); if(safe_str_eq(task, CRMD_ACTION_START) || safe_str_eq(task, CRMD_ACTION_STOP)) { interval = 1; value = "INFINITY"; } if(interval > 0) { attr_name = crm_concat("fail-count", rsc_id, '-'); crm_warn("Updating failcount for %s on %s after failed %s: rc=%d", rsc_id, on_uuid, task, rc); update_attr(te_cib_conn, cib_none, XML_CIB_TAG_STATUS, on_uuid, NULL,NULL, attr_name, value, FALSE); crm_free(attr_name); } bail: crm_free(rsc_id); crm_free(task); } static int status_from_rc(crm_action_t *action, int orig_status, int rc) { int target_rc = 0; int status = orig_status; const char *target_rc_s = g_hash_table_lookup( action->params, crm_meta_name(XML_ATTR_TE_TARGET_RC)); if(target_rc_s != NULL) { crm_debug_2("Target rc: %s vs. %d", target_rc_s, rc); target_rc = crm_parse_int(target_rc_s, NULL); } if(target_rc == rc) { crm_debug_2("Target rc: == %d", rc); if(status != LRM_OP_DONE) { crm_debug_2("Re-mapping op status to" " LRM_OP_DONE for rc=%d", rc); status = LRM_OP_DONE; } } else { crm_debug_2("Target rc: != %d", rc); if(status != LRM_OP_ERROR) { crm_info("Re-mapping op status to" " LRM_OP_ERROR for rc=%d", rc); status = LRM_OP_ERROR; } } /* 99 is the code we use for direct nack's */ if(rc != 99 && status != LRM_OP_DONE) { const char *task, *uname; task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); uname = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); crm_warn("Action %s on %s failed (target: %s vs. rc: %d): %s", task, uname, crm_str(target_rc_s), rc, op_status2text(status)); } return status; } /* * returns the ID of the action if a match is found * returns -1 if a match was not found * returns -2 if a match was found but the action failed (and was * not allowed to) */ int -match_graph_event(int action_id, crm_data_t *event, const char *event_node, +match_graph_event(int action_id, xmlNode *event, const char *event_node, int op_status, int op_rc) { const char *target = NULL; const char *allow_fail = NULL; const char *this_event = ID(event); crm_action_t *action = NULL; action = get_action(action_id, FALSE); if(action == NULL) { return -1; } op_status = status_from_rc(action, op_status, op_rc); if(op_status != LRM_OP_DONE) { update_failcount(event, event_node, op_rc); } /* Process OP status */ switch(op_status) { case LRM_OP_PENDING: crm_debug("Ignoring pending operation"); return action->id; break; case LRM_OP_DONE: break; case LRM_OP_ERROR: case LRM_OP_TIMEOUT: case LRM_OP_NOTSUPPORTED: action->failed = TRUE; break; case LRM_OP_CANCELLED: /* do nothing?? */ crm_err("Dont know what to do for cancelled ops yet"); break; default: action->failed = TRUE; crm_err("Unsupported action result: %d", op_status); } /* stop this event's timer if it had one */ stop_te_timer(action->timer); action->confirmed = TRUE; update_graph(transition_graph, action); trigger_graph(); if(action->failed) { allow_fail = g_hash_table_lookup( action->params, crm_meta_name(XML_ATTR_TE_ALLOWFAIL)); if(crm_is_true(allow_fail)) { action->failed = FALSE; } } if(action->failed) { abort_transition(action->synapse->priority+1, tg_restart, "Event failed", event); } target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); te_log_action(LOG_INFO, "Action %s (%d) confirmed on %s (rc=%d)", crm_str(this_event), action->id, crm_str(target), op_status); return action->id; } crm_action_t * get_action(int id, gboolean confirmed) { slist_iter( synapse, synapse_t, transition_graph->synapses, lpc, slist_iter( action, crm_action_t, synapse->actions, lpc2, if(action->id == id) { if(confirmed) { stop_te_timer(action->timer); action->confirmed = TRUE; } return action; } ) ); return NULL; } crm_action_t * match_down_event(int id, const char *target, const char *filter) { const char *this_action = NULL; const char *this_node = NULL; crm_action_t *match = NULL; slist_iter( synapse, synapse_t, transition_graph->synapses, lpc, /* lookup event */ slist_iter( action, crm_action_t, synapse->actions, lpc2, if(id > 0 && action->id == id) { match = action; break; } this_action = crm_element_value( action->xml, XML_LRM_ATTR_TASK); if(action->type != action_type_crm) { continue; } else if(safe_str_eq(this_action, CRM_OP_LRM_REFRESH)){ continue; } else if(filter != NULL && safe_str_neq(this_action, filter)) { continue; } this_node = crm_element_value( action->xml, XML_LRM_ATTR_TARGET_UUID); if(this_node == NULL) { crm_log_xml_err(action->xml, "No node uuid"); } if(safe_str_neq(this_node, target)) { crm_debug("Action %d : Node mismatch: %s", action->id, this_node); continue; } match = action; break; ); if(match != NULL) { /* stop this event's timer if it had one */ break; } ); if(match != NULL) { /* stop this event's timer if it had one */ crm_debug("Match found for action %d: %s on %s", id, crm_element_value(match->xml, XML_LRM_ATTR_TASK_KEY), target); stop_te_timer(match->timer); match->confirmed = TRUE; } else if(id > 0) { crm_err("No match for action %d", id); } else { crm_warn("No match for shutdown action on %s", target); } return match; } void -process_graph_event(crm_data_t *event, const char *event_node) +process_graph_event(xmlNode *event, const char *event_node) { int rc = -1; int status = -1; int action = -1; int transition_num = -1; char *update_te_uuid = NULL; gboolean passed = FALSE; const char *id = NULL; const char *magic = NULL; CRM_ASSERT(event != NULL); id = ID(event); magic = crm_element_value(event, XML_ATTR_TRANSITION_MAGIC); if(magic == NULL) { /* non-change */ return; } CRM_CHECK(decode_transition_magic( magic, &update_te_uuid, &transition_num, &action, &status, &rc), crm_err("Invalid event %s detected", id); abort_transition(INFINITY, tg_restart,"Bad event", event); ); if(status == LRM_OP_PENDING) { goto bail; } if(transition_num == -1) { crm_err("Action %s initiated outside of a transition", id); abort_transition(INFINITY, tg_restart,"Unexpected event",event); } else if(action < 0 || safe_str_neq(update_te_uuid, te_uuid)) { crm_info("Action %s initiated by a different transitioner", id); abort_transition(INFINITY, tg_restart,"Foreign event", event); } else if(transition_graph->id != transition_num) { crm_info("Detected action %s from a different transition:" " %d vs. %d", id, transition_num, transition_graph->id); abort_transition(INFINITY, tg_restart,"Old event", event); } else if(transition_graph->complete) { crm_info("Action %s arrived after a completed transition", id); abort_transition(INFINITY, tg_restart, "Inactive graph", event); } else if(match_graph_event( action, event, event_node, status, rc) < 0) { crm_err("Unknown graph action %s", id); abort_transition(INFINITY, tg_restart, "Unknown event", event); } else { passed = TRUE; crm_debug_2("Processed update to %s: %s", id, magic); } if(passed == FALSE && rc != EXECRA_OK) { update_failcount(event, event_node, rc); } bail: crm_free(update_te_uuid); return; } diff --git a/transitioner/fsa_data.c b/transitioner/fsa_data.c index 55bfd9f111..818a179322 100644 --- a/transitioner/fsa_data.c +++ b/transitioner/fsa_data.c @@ -1,329 +1,329 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include extern void te_input_free(te_input_t *fsa_data); extern te_input_t* te_input_copy(te_input_t *fsa_data); extern te_input_t* te_input_new(enum te_data_type type, void *data); -extern te_input_t *new_input_command(HA_Message *msg, crm_data_t *xml); +extern te_input_t *new_input_command(xmlNode *msg, xmlNode *xml); -extern te_input_t *new_input_complete(const char *text, crm_data_t *xml, +extern te_input_t *new_input_complete(const char *text, xmlNode *xml, te_reason_t reason, te_fsa_input_t input); -extern te_input_t *new_input_cib(HA_Message *msg, crm_data_t *xml, +extern te_input_t *new_input_cib(xmlNode *msg, xmlNode *xml, int call_id, int rc, void *user_data); extern te_input_t *new_input_null(void); const char* te_data_null_type(void); const char* te_data_null_name(void); void te_data_null_free(te_input_t *fsa_data); void te_data_null_copy(te_input_t *a_copy, te_input_t *fsa_data); const char* te_data_command_type(void); const char* te_data_command_name(void); void te_data_command_free(te_input_t *fsa_data); void te_data_command_copy(te_input_t *a_copy, te_input_t *fsa_data); const char* te_data_cib_type(void); const char* te_data_cib_name(void); void te_data_cib_free(te_input_t *fsa_data); void te_data_cib_copy(te_input_t *a_copy, te_input_t *fsa_data); const char* te_data_complete_type(void); const char* te_data_complete_name(void); void te_data_complete_free(te_input_t *fsa_data); void te_data_complete_copy(te_input_t *a_copy, te_input_t *fsa_data); GListPtr input_queue = NULL; te_data_op_t te_ops_null = { te_data_null_type, te_data_null_name, te_data_null_free, te_data_null_copy }; te_data_op_t te_ops_cib = { te_data_cib_type, te_data_cib_name, te_data_cib_free, te_data_cib_copy }; te_data_op_t te_ops_complete = { te_data_complete_type, te_data_complete_name, te_data_complete_free, te_data_complete_copy }; te_data_op_t te_ops_command = { te_data_command_type, te_data_command_name, te_data_command_free, te_data_command_copy }; void te_input_free(te_input_t *fsa_data) { if(fsa_data == NULL) { return; } fsa_data->ops->free(fsa_data); crm_free(fsa_data); } te_input_t* te_input_copy(te_input_t *fsa_data) { te_input_t *a_copy = NULL; CRM_CHECK(fsa_data != NULL); if(crm_assert_failed) {return NULL;} crm_malloc0(a_copy, sizeof(te_input_t)); *a_copy = *fsa_data; a_copy->data = NULL; a_copy->ops->copy(fsa_data); } te_input_t* te_input_new( te_fsa_input_t input, enum te_data_type type, void *data) { static int input_id = 0; te_input_t *a_copy = NULL; crm_malloc0(a_copy, sizeof(te_input_t)); a_copy->id = input_id++; a_copy->origin = origin; a_copy->input = input; a_copy->data = data; switch(type) { case te_data_cib: a_copy->ops = &te_ops_cib; break; case te_data_complete: a_copy->ops = &te_ops_complete; break; case te_data_command: a_copy->ops = &te_ops_command; break; case te_data_null: a_copy->ops = &te_ops_null; break; } } const char* te_data_null_type(void) { return te_data_null; } const char* te_data_null_name(void) { return "Null"; } void te_data_null_free(te_input_t *fsa_data) { } void te_data_null_copy(te_input_t *a_copy, te_input_t *fsa_data) { a_copy->data = NULL; } const char* te_data_command_type(void) { return te_data_command; } const char* te_data_command_name(void) { return "DC Command"; } void te_data_command_free(te_input_t *fsa_data) { struct te_data_command_s *data = fsa_data->data; CRM_CHECK(fsa_data->ops->type() == te_data_command); ha_msg_del(data->msg); free_xml(data->xml); crm_free(data); } void te_data_command_copy(te_input_t *a_copy, te_input_t *fsa_data) { struct te_data_command_s *data = fsa_data->data; struct te_data_command_s *copy_data = NULL; CRM_CHECK(fsa_data->ops->type() == te_data_command); crm_malloc0(a_copy->data, sizeof(struct te_data_command_s)); copy_data = a_copy->data; copy_data->msg = ha_msg_copy(data->msg); copy_data->xml = copy_xml(data->xml); } const char* te_data_cib_type(void) { return te_data_cib; } const char* te_data_cib_name(void) { return "CIB Callback"; } void te_data_cib_free(te_input_t *fsa_data) { struct te_data_cib_s *data = fsa_data->data; CRM_CHECK(fsa_data->ops->type() == te_data_cib); ha_msg_del(data->msg); free_xml(data->xml); crm_free(data); } void te_data_cib_copy(te_input_t *a_copy, te_input_t *fsa_data) { struct te_data_cib_s *data = fsa_data->data; struct te_data_cib_s *copy_data = NULL; CRM_CHECK(fsa_data->ops->type() == te_data_cib); crm_malloc0(a_copy->data, sizeof(struct te_data_cib_s)); copy_data = a_copy->data; *copy_data = *data; copy_data->msg = ha_msg_copy(data->msg); copy_data->xml = copy_xml(data->xml); } const char* te_data_complete_type(void) { return te_data_complete; } const char* te_data_complete_name(void) { return "Transition Complete"; } void te_data_complete_free(te_input_t *fsa_data) { struct te_data_complete_s *data = fsa_data->data; CRM_CHECK(fsa_data->ops->type() == te_data_complete); ha_msg_del(data->msg); free_xml(data->xml); crm_free(data); } void te_data_complete_copy(te_input_t *a_copy, te_input_t *fsa_data) { struct te_data_complete_s *data = fsa_data->data; struct te_data_complete_s *copy_data = NULL; CRM_CHECK(fsa_data->ops->type() == te_data_complete); crm_malloc0(a_copy->data, sizeof(struct te_data_complete_s)); copy_data = a_copy->data; *copy_data = *data; copy_data->xml = copy_xml(data->xml); } te_input_t * -new_input_command(HA_Message *msg, crm_data_t *xml) +new_input_command(xmlNode *msg, xmlNode *xml) { struct te_data_cib_s *copy_data = NULL; crm_malloc0(a_copy->data, sizeof(struct te_data_cib_s)); copy_data = a_copy->data; copy_data->xml = copy_xml(xml); copy_data->msg = ha_msg_copy(msg); return te_input_new(te_data_command, copy_data); } te_input_t * -new_input_complete(const char *text, crm_data_t *xml, +new_input_complete(const char *text, xmlNode *xml, te_reason_t reason) { struct te_data_complete_s *copy_data = NULL; crm_malloc0(a_copy->data, sizeof(struct te_data_complete_s)); copy_data = a_copy->data; copy_data->text = text; copy_data->reason = reason; copy_data->xml = copy_xml(xml); return te_input_new(te_data_complete, copy_data); } te_input_t * -new_input_cib(HA_Message *msg, crm_data_t *xml, +new_input_cib(xmlNode *msg, xmlNode *xml, int call_id, int rc, void *user_data) { struct te_data_cib_s *copy_data = NULL; crm_malloc0(a_copy->data, sizeof(struct te_data_cib_s)); copy_data = a_copy->data; copy_data->rc = rc; copy_data->call_id = call_id; copy_data->user_data = user_data; copy_data->msg = ha_msg_copy(msg); copy_data->xml = copy_xml(xml); return te_input_new(te_data_cib, copy_data); } te_input_t * new_input_null(const char *origin) { return te_input_new(te_data_null, NULL, origin); } void register_input(te_fsa_input_t input, te_input_t *input_data, gboolean prepend, const char *origin) { input_data->origin = origin; input_data->input = input; crm_debug("%s raised FSA input %d (%s)", origin, input_data->id, input_data->ops->name()); if(prepend) { crm_debug_2("Prepending input"); input_queue = g_list_prepend(input_queue, input_data); } else { input_queue = g_list_append(input_queue, input_data); } G_main_set_trigger(fsa_source); } void register_input_copy(te_fsa_input_t input, te_input_t *input_data, gboolean prepend, const char *origin) { te_input_t *a_copy = input_data->ops->copy(input); crm_debug("%s re-registering FSA input %d (%s/%s)", origin, input_data->id, input_data->ops->name(), input_data->origin); register_input(a_copy, prepend, origin); } te_input_t * get_input(void) { te_input_t* message = g_list_nth_data(input_queue, 0); input_queue = g_list_remove(input_queue, message); return message; } diff --git a/transitioner/main.c b/transitioner/main.c index 7a902fe9cf..b11ff6f52e 100644 --- a/transitioner/main.c +++ b/transitioner/main.c @@ -1,238 +1,238 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define OPTARGS "hVc" GMainLoop* mainloop = NULL; cib_t *te_cib_conn = NULL; void usage(const char* cmd, int exit_status); int te_init(void); gboolean tengine_shutdown(int nsig, gpointer unused); -extern void te_update_confirm(const char *event, HA_Message *msg); -extern void te_update_diff(const char *event, HA_Message *msg); +extern void te_update_confirm(const char *event, xmlNode *msg); +extern void te_update_diff(const char *event, xmlNode *msg); extern crm_graph_functions_t te_graph_fns; int main(int argc, char ** argv) { int flag; int rc = 0; int dummy = 0; int argerr = 0; gboolean allow_cores = TRUE; crm_log_init(CRM_SYSTEM_TENGINE, LOG_INFO, TRUE, FALSE, 0, NULL); G_main_add_SignalHandler( G_PRIORITY_HIGH, SIGTERM, tengine_shutdown, NULL, NULL); transition_trigger = G_main_add_TriggerHandler( G_PRIORITY_LOW, te_graph_trigger, NULL, NULL); stonith_reconnect = G_main_add_TriggerHandler( G_PRIORITY_LOW, te_connect_stonith, &dummy, NULL); crm_debug_3("Begining option processing"); while ((flag = getopt(argc, argv, OPTARGS)) != EOF) { switch(flag) { case 'V': alter_debug(DEBUG_INC); break; case 'h': /* Help message */ usage(crm_system_name, LSB_EXIT_OK); break; case 'c': allow_cores = TRUE; break; default: ++argerr; break; } } crm_debug_3("Option processing complete"); if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name,LSB_EXIT_GENERIC); } /* read local config file */ crm_debug_3("Starting..."); rc = te_init(); return rc; } int te_init(void) { int init_ok = TRUE; init_client_ipc_comms( CRM_SYSTEM_CRMD, subsystem_msg_dispatch, (void*)process_te_message, &crm_ch); if(crm_ch != NULL) { send_hello_message(crm_ch, "1234", CRM_SYSTEM_TENGINE, "0", "1"); } else { init_ok = FALSE; crm_err("Could not connect to the CRMd"); } if(init_ok) { crm_debug_4("Creating CIB connection"); te_cib_conn = cib_new(); if(te_cib_conn == NULL) { init_ok = FALSE; } } if(init_ok) { crm_debug_4("Connecting to the CIB"); if(cib_ok != te_cib_conn->cmds->signon( te_cib_conn, crm_system_name, cib_command)) { crm_err("Could not connect to the CIB"); init_ok = FALSE; } } if(init_ok) { crm_debug_4("Setting CIB notification callback"); if(cib_ok != te_cib_conn->cmds->add_notify_callback( te_cib_conn, T_CIB_DIFF_NOTIFY, te_update_diff)) { crm_err("Could not set CIB notification callback"); init_ok = FALSE; } } if(is_heartbeat_cluster() && init_ok) { G_main_set_trigger(stonith_reconnect); } if(init_ok) { cl_uuid_t new_uuid; char uuid_str[UU_UNPARSE_SIZEOF]; cl_uuid_generate(&new_uuid); cl_uuid_unparse(&new_uuid, uuid_str); te_uuid = crm_strdup(uuid_str); crm_info("Registering TE UUID: %s", te_uuid); set_graph_functions(&te_graph_fns); /* create a blank one */ transition_graph = unpack_graph(NULL); transition_graph->complete = TRUE; transition_graph->abort_reason = "DC Takeover"; transition_graph->completion_action = tg_restart; crm_malloc0(transition_timer, sizeof(crm_action_timer_t)); transition_timer->source_id = 0; transition_timer->reason = timeout_abort; transition_timer->action = NULL; } if(init_ok) { /* Create the mainloop and run it... */ crm_info("Starting %s", crm_system_name); mainloop = g_main_new(FALSE); g_main_run(mainloop); return_to_orig_privs(); crm_info("Exiting %s", crm_system_name); } else { crm_warn("Initialization errors, %s not starting.", crm_system_name); } destroy_graph(transition_graph); crm_free(transition_timer); te_cib_conn->cmds->signoff(te_cib_conn); cib_delete(te_cib_conn); te_cib_conn = NULL; #if SUPPORT_HEARTBEAT if(is_heartbeat_cluster()) { stonithd_signoff(); } #endif crm_free(te_uuid); if(init_ok) { return 0; } return 1; } void usage(const char* cmd, int exit_status) { FILE* stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-srkh]" "[-c configure file]\n", cmd); /* fprintf(stream, "\t-d\tsets debug level\n"); */ /* fprintf(stream, "\t-s\tgets daemon status\n"); */ /* fprintf(stream, "\t-r\trestarts daemon\n"); */ /* fprintf(stream, "\t-k\tstops daemon\n"); */ /* fprintf(stream, "\t-h\thelp message\n"); */ fflush(stream); exit(exit_status); } gboolean shuttingdown; gboolean tengine_shutdown(int nsig, gpointer unused) { shuttingdown = TRUE; abort_transition(INFINITY, tg_shutdown, "Shutdown", NULL); return TRUE; } diff --git a/transitioner/te_callbacks.h b/transitioner/te_callbacks.h index 1e59febafb..2e9244088b 100644 --- a/transitioner/te_callbacks.h +++ b/transitioner/te_callbacks.h @@ -1,39 +1,39 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 TE_CALLBACKS__H #define TE_CALLBACKS__H -extern void cib_fencing_updated(const HA_Message *msg, int call_id, int rc, - crm_data_t *output, void *user_data); +extern void cib_fencing_updated(xmlNode *msg, int call_id, int rc, + xmlNode *output, void *user_data); -extern void cib_action_updated(const HA_Message *msg, int call_id, int rc, - crm_data_t *output, void *user_data); +extern void cib_action_updated(xmlNode *msg, int call_id, int rc, + xmlNode *output, void *user_data); extern gboolean global_timer_callback(gpointer data); extern gboolean action_timer_callback(gpointer data); extern gboolean te_graph_trigger(gpointer user_data); extern void tengine_stonith_connection_destroy(gpointer user_data); #if SUPPORT_HEARTBEAT extern void tengine_stonith_callback(stonith_ops_t * op); extern gboolean tengine_stonith_dispatch(IPC_Channel *sender, void *user_data); #endif #endif diff --git a/transitioner/te_fsa.h b/transitioner/te_fsa.h index dbddb13db2..8962ace5a5 100644 --- a/transitioner/te_fsa.h +++ b/transitioner/te_fsa.h @@ -1,84 +1,84 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 extern GListPtr input_queue; typedef struct te_input_s te_input_t; enum te_data_type { te_data_cib, te_data_complete, te_data_command, te_data_null }; typedef struct te_data_operations_s { enum te_data_type(*type)(void); const char* (*name)(void); void (*free)(te_input_t*); void (*copy)(te_input_t*); } te_data_op_t; struct te_input_s { int id; char *origin; te_fsa_input_t input; te_data_op_t *ops; void *data; }; struct te_data_command_s { - HA_Message *msg; - crm_data_t *xml; + xmlNode *msg; + xmlNode *xml; }; struct te_data_cib_s { - HA_Message *msg; - crm_data_t *xml; + xmlNode *msg; + xmlNode *xml; int call_id; int rc; void *user_data; /* not copied or free'd */ }; struct te_data_complete_s { const char *text; - crm_data_t *xml; + xmlNode *xml; te_reason_t reason; }; extern void te_input_free(te_input_t *fsa_data); extern te_input_t* te_input_copy(te_input_t *fsa_data); extern te_input_t* te_input_new(enum te_data_type type, void *data); -extern te_input_t *new_input_command(HA_Message *msg, crm_data_t *xml); +extern te_input_t *new_input_command(xmlNode *msg, xmlNode *xml); -extern te_input_t *new_input_complete(const char *text, crm_data_t *xml, +extern te_input_t *new_input_complete(const char *text, xmlNode *xml, te_reason_t reason, te_fsa_input_t input); -extern te_input_t *new_input_cib(HA_Message *msg, crm_data_t *xml, +extern te_input_t *new_input_cib(xmlNode *msg, xmlNode *xml, int call_id, int rc, void *user_data); extern te_input_t *new_input_null(void); extern te_input_t *get_input(void); diff --git a/transitioner/tengine.h b/transitioner/tengine.h index 85e6a43e9e..cb96c59cce 100644 --- a/transitioner/tengine.h +++ b/transitioner/tengine.h @@ -1,74 +1,74 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #if SUPPORT_HEARTBEAT # include extern void send_stonith_update(stonith_ops_t * op); #endif extern IPC_Channel *crm_ch; extern GMainLoop* mainloop; /* tengine */ extern crm_action_t *match_down_event( int rc, const char *target, const char *filter); extern gboolean cib_action_update(crm_action_t *action, int status); /* utils */ extern crm_action_t *get_action(int id, gboolean confirmed); extern gboolean stop_te_timer(crm_action_timer_t *timer); extern const char *get_rsc_state(const char *task, op_status_t status); /* unpack */ -extern gboolean extract_event(crm_data_t *msg); +extern gboolean extract_event(xmlNode *msg); extern gboolean process_te_message( - HA_Message * msg, crm_data_t *xml_data, IPC_Channel *sender); + xmlNode * msg, xmlNode *xml_data, IPC_Channel *sender); extern crm_graph_t *transition_graph; extern GTRIGSource *transition_trigger; extern char *te_uuid; extern cib_t *te_cib_conn; extern void notify_crmd(crm_graph_t *graph); #include extern void trigger_graph_processing(const char *fn, int line); extern void abort_transition_graph( int abort_priority, enum transition_action abort_action, - const char *abort_text, crm_data_t *reason, const char *fn, int line); + const char *abort_text, xmlNode *reason, const char *fn, int line); #define trigger_graph() trigger_graph_processing(__FUNCTION__, __LINE__) #define abort_transition(pri, action, text, reason) \ abort_transition_graph(pri, action, text, reason,__FUNCTION__,__LINE__); extern gboolean te_connect_stonith(gpointer user_data); extern GCHSource *stonith_src; extern GTRIGSource *transition_trigger; extern GTRIGSource *stonith_reconnect; extern crm_action_timer_t *transition_timer; #endif diff --git a/transitioner/ttest.c b/transitioner/ttest.c index 413d3c683e..5389594664 100644 --- a/transitioner/ttest.c +++ b/transitioner/ttest.c @@ -1,174 +1,174 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #define OPTARGS "V?X:" #include #include #include GMainLoop* mainloop = NULL; crm_graph_t *transition_graph = NULL; cib_t *te_cib_conn = NULL; static gboolean ttest_pseudo_command(crm_graph_t *graph, crm_action_t *pseudo) { crm_debug("Event handler: action %d executed", pseudo->id); pseudo->confirmed = TRUE; update_graph(graph, pseudo); trigger_graph(); return TRUE; } static gboolean ttest_rsc_command(crm_graph_t *graph, crm_action_t *pseudo) { /* send_rsc_command(action); */ return TRUE; } crm_graph_functions_t ttest_graph_fns = { ttest_pseudo_command, ttest_rsc_command, ttest_pseudo_command, ttest_pseudo_command, }; int main(int argc, char **argv) { int flag; int argerr = 0; const char *xml_file = NULL; - crm_data_t *xml_graph = NULL; + xmlNode *xml_graph = NULL; set_crm_log_level(0); /* crm_log_init("ttest"); */ g_log_set_handler(NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG | G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL, cl_glib_msg_handler, NULL); /* and for good measure... - this enum is a bit field (!) */ g_log_set_always_fatal((GLogLevelFlags)0); /*value out of range*/ set_crm_log_level(LOG_WARNING); transition_trigger = G_main_add_TriggerHandler( G_PRIORITY_LOW, te_graph_trigger, NULL, NULL); set_graph_functions(&ttest_graph_fns); while (1) { flag = getopt(argc, argv, OPTARGS); if (flag == -1) break; switch(flag) { case 'X': xml_file = crm_strdup(optarg); break; case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; default: printf("?? getopt returned character code 0%o ??\n", 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) { crm_err("%d errors in option parsing", argerr); } crm_debug("=#=#=#=#= Getting XML =#=#=#=#="); if(xml_file != NULL) { FILE *xml_strm = fopen(xml_file, "r"); if(xml_strm) { xml_graph = file2xml(xml_strm, FALSE); fclose(xml_strm); } else { cl_perror("Could not open %s for reading", xml_file); xml_file = NULL; } } if(xml_file == NULL) { xml_graph = stdin2xml(); } #ifdef MTRACE mtrace(); #endif transition_graph = unpack_graph(xml_graph); trigger_graph(); print_graph(LOG_DEBUG, transition_graph); transition_graph->completion_action = tg_shutdown; mainloop = g_main_new(FALSE); g_main_run(mainloop); crm_info("Exiting ttest"); #ifdef MTRACE muntrace(); #endif crm_debug_4("Transition complete..."); return 0; } diff --git a/transitioner/utils.c b/transitioner/utils.c index a02a2e39d4..def256a53f 100644 --- a/transitioner/utils.c +++ b/transitioner/utils.c @@ -1,155 +1,155 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include extern cib_t *te_cib_conn; GCHSource *stonith_src = NULL; GTRIGSource *stonith_reconnect = NULL; gboolean te_connect_stonith(gpointer user_data) { #if SUPPORT_HEARTBEAT if(is_heartbeat_cluster()) { int lpc = 0; int rc = ST_OK; IPC_Channel *fence_ch = NULL; if(stonith_src != NULL) { crm_debug("Still connected"); return TRUE; } for(lpc = 0; lpc < 30; lpc++) { crm_info("Attempting connection to fencing daemon..."); sleep(1); rc = stonithd_signon("tengine"); if(rc == ST_OK) { break; } if(user_data != NULL) { crm_err("Sign-in failed: triggered a retry"); G_main_set_trigger(stonith_reconnect); return TRUE; } crm_err("Sign-in failed: pausing and trying again in 2s..."); sleep(1); } CRM_ASSERT(rc == ST_OK); /* If not, we failed 30 times... just get out */ CRM_ASSERT(stonithd_set_stonith_ops_callback( tengine_stonith_callback) == ST_OK); crm_debug_2("Grabbing IPC channel"); fence_ch = stonithd_input_IPC_channel(); CRM_ASSERT(fence_ch != NULL); crm_debug_2("Attaching to mainloop"); stonith_src = G_main_add_IPC_Channel( G_PRIORITY_LOW, fence_ch, FALSE, tengine_stonith_dispatch, NULL, tengine_stonith_connection_destroy); CRM_ASSERT(stonith_src != NULL); crm_info("Connected"); return TRUE; } #endif return FALSE; } gboolean stop_te_timer(crm_action_timer_t *timer) { const char *timer_desc = "action timer"; if(timer == NULL) { return FALSE; } if(timer->reason == timeout_abort) { timer_desc = "global timer"; } if(timer->source_id != 0) { crm_debug_2("Stopping %s", timer_desc); Gmain_timeout_remove(timer->source_id); timer->source_id = 0; } else { return FALSE; } return TRUE; } void trigger_graph_processing(const char *fn, int line) { G_main_set_trigger(transition_trigger); crm_debug_2("%s:%d - Triggered graph processing", fn, line); } void abort_transition_graph( int abort_priority, enum transition_action abort_action, - const char *abort_text, crm_data_t *reason, const char *fn, int line) + const char *abort_text, xmlNode *reason, const char *fn, int line) { int log_level = LOG_DEBUG; /* if(abort_priority >= INFINITY) { log_level = LOG_INFO; } */ update_abort_priority( transition_graph, abort_priority, abort_action, abort_text); do_crm_log(log_level, "%s:%d - Triggered graph processing : %s", fn, line, abort_text); if(reason != NULL) { const char *magic = crm_element_value( reason, XML_ATTR_TRANSITION_MAGIC); if(magic) { do_crm_log(log_level, "Caused by update to %s: %s", ID(reason), magic); } else { crm_log_xml(log_level, "Cause", reason); } } if(transition_graph->complete) { notify_crmd(transition_graph); } else { G_main_set_trigger(transition_trigger); } }