diff --git a/crm/pengine/Makefile.am b/crm/pengine/Makefile.am index 0496bfe33b..2fcee51684 100644 --- a/crm/pengine/Makefile.am +++ b/crm/pengine/Makefile.am @@ -1,74 +1,81 @@ # # 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$(top_builddir)/linux-ha -I$(top_srcdir)/linux-ha \ -I$(top_builddir) -I$(top_srcdir) hadir = $(sysconfdir)/ha.d halibdir = $(libdir)/@HB_PKG@ commmoddir = $(halibdir)/modules/comm havarlibdir = $(localstatedir)/lib/@HB_PKG@ PIDFILE = $(localstatedir)/run/crmd.pid XML_FLAGS = `xml2-config --cflags` XML_LIBS = `xml2-config --libs` # sockets with path crmdir = $(havarlibdir)/crm apigid = @HA_APIGID@ crmuid = @HA_CCMUID@ COMMONLIBS = $(CRM_DEBUG_LIBS) \ $(top_builddir)/lib/clplumbing/libplumb.la \ $(top_builddir)/$(CRM_DIR)/common/libcrmcommon.la \ $(top_builddir)/$(CRM_DIR)/cib/libcib.la \ $(top_builddir)/lib/apphb/libapphb.la \ $(GLIBLIB) \ $(LIBRT) LIBRT = @LIBRT@ AM_CFLAGS = @CFLAGS@ \ -DPIDFILE='"$(PIDFILE)"' \ $(CRM_DEBUG_FLAGS) ## libraries lib_LTLIBRARIES = ## binary progs -halib_PROGRAMS = ptest +halib_PROGRAMS = ptest pengine ## SOURCES noinst_HEADERS = -ptest_SOURCES = pengine.c utils.c ptest.c +ptest_SOURCES = pengine.c utils.c ptest.c ptest_CFLAGS = $(XML_FLAGS) -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' ptest_LDFLAGS = $(XML_LIBS) ptest_LDADD = $(COMMONLIBS) +pengine_SOURCES = pengine.c utils.c messages.c penginemain.c + +pengine_CFLAGS = $(XML_FLAGS) -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' +pengine_LDFLAGS = $(XML_LIBS) +pengine_LDADD = $(COMMONLIBS) \ + $(top_builddir)/lib/hbclient/libhbclient.la + # clean-generic: rm -f *.log *.debug *~ install-exec-local: uninstall-local: diff --git a/crm/pengine/messages.c b/crm/pengine/messages.c new file mode 100644 index 0000000000..98887fb51a --- /dev/null +++ b/crm/pengine/messages.c @@ -0,0 +1,235 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +xmlNodePtr process_pe_message(xmlNodePtr msg); +xmlNodePtr do_calculations(xmlNodePtr msg); + +gboolean +pe_input_dispatch(IPC_Channel *sender, void *user_data) +{ + int lpc = 0; + char *buffer = NULL; + xmlDocPtr doc = NULL; + IPC_Message *msg = NULL; + gboolean all_is_well = TRUE; + xmlNodePtr answer = NULL, root_xml_node = NULL; + const char *sys_to; + const char *type; + + + FNIN(); + + while(sender->ops->is_message_pending(sender)) { + if (sender->ch_status == IPC_DISCONNECT) { + /* The message which was pending for us is that + * the IPC status is now IPC_DISCONNECT */ + break; + } + if (sender->ops->recv(sender, &msg) != IPC_OK) { + perror("Receive failure:"); + FNRET(!all_is_well); + } + if (msg == NULL) { + cl_log(LOG_ERR, "No message this time"); + continue; + } + + lpc++; + + /* the docs say only do this once, but in their code + * they do it every time! + */ +// xmlInitParser(); + + buffer = (char*)msg->msg_body; + cl_log(LOG_DEBUG, "Message %d [text=%s]", lpc, buffer); + doc = xmlParseMemory(cl_strdup(buffer), strlen(buffer)); + + if(doc == NULL) { + cl_log(LOG_INFO, + "XML Buffer was not valid...\n Buffer: (%s)", + buffer); + } + + root_xml_node = xmlDocGetRootElement(doc); + + sys_to= xmlGetProp(root_xml_node, XML_ATTR_SYSTO); + type = xmlGetProp(root_xml_node, XML_ATTR_MSGTYPE); + if (root_xml_node == NULL) { + cl_log(LOG_ERR, "Root node was NULL!!"); + + } else if(sys_to == NULL) { + cl_log(LOG_ERR, "Value of %s was NULL!!", + XML_ATTR_SYSTO); + + } else if(type == NULL) { + cl_log(LOG_ERR, "Value of %s was NULL!!", + XML_ATTR_MSGTYPE); + + } else if(strcmp(type, XML_ATTR_REQUEST) != 0) { + cl_log(LOG_INFO, + "Message was a response not a request." + " Discarding"); + } else if (strcmp(sys_to, CRM_SYSTEM_PENGINE) == 0) { + answer = process_pe_message(root_xml_node); + if (send_xmlipc_message(sender, answer)==FALSE) + cl_log(LOG_WARNING, + "Cib answer could not be sent"); + } else { + cl_log(LOG_WARNING, + "Received a message destined for %s by mistake", + sys_to); + } + + if(answer != NULL) + free_xml(answer); + + msg->msg_done(msg); + msg = NULL; + } + + // clean up after a break + if(msg != NULL) + msg->msg_done(msg); + + if(root_xml_node != NULL) + free_xml(root_xml_node); + + CRM_DEBUG("Processed %d messages", lpc); + if (sender->ch_status == IPC_DISCONNECT) { + cl_log(LOG_ERR, "The server has left us: Shutting down...NOW"); + + exit(1); // shutdown properly later + + FNRET(!all_is_well); + } + FNRET(all_is_well); +} + +xmlNodePtr +process_pe_message(xmlNodePtr msg) +{ + const char *op = get_xml_attr (msg, XML_TAG_OPTIONS,XML_ATTR_OP, TRUE); + + if(op == NULL){ + // error + } else if(strcmp(op, "pecalc")) { + xmlNodePtr fragment = find_xml_node(msg, XML_TAG_FRAGMENT); + xmlNodePtr input_cib = find_xml_node(fragment, XML_TAG_CIB); + return do_calculations(input_cib); + } else if(strcmp(op, "quit")) { + cl_log(LOG_WARNING, "Received quit message, terminating"); + exit(0); + } + + return NULL; +} + +xmlNodePtr +do_calculations(xmlNodePtr cib_object) +{ + int lpc, lpc2; + + pdebug("=#=#=#=#= Stage 0 =#=#=#=#="); + stage0(cib_object); + + pdebug("=#=#=#=#= Stage 1 =#=#=#=#="); + stage1(node_cons_list, node_list, rsc_list); + + pdebug("=#=#=#=#= Stage 2 =#=#=#=#="); + stage2(rsc_list, node_list, NULL); + + pdebug("========= Nodes ========="); + pdebug_action( + slist_iter(node, node_t, node_list, lpc, + print_node(NULL, node, TRUE) + ) + ); + + pdebug("========= Resources ========="); + pdebug_action( + slist_iter(resource, resource_t, rsc_list, lpc, + print_resource(NULL, resource, TRUE) + ) + ); + + pdebug("=#=#=#=#= Stage 3 =#=#=#=#="); + stage3(); + + pdebug("=#=#=#=#= Stage 4 =#=#=#=#="); + stage4(colors); + pdebug("========= Colors ========="); + pdebug_action( + slist_iter(color, color_t, colors, lpc, + print_color(NULL, color, FALSE) + ) + ); + + pdebug("=#=#=#=#= Stage 5 =#=#=#=#="); + stage5(rsc_list); + + pdebug("=#=#=#=#= Stage 6 =#=#=#=#="); + stage6(stonith_list, shutdown_list); + + pdebug("========= Action List ========="); + pdebug_action( + slist_iter(action, action_t, action_list, lpc, + print_action(NULL, action, TRUE) + ) + ); + + pdebug("=#=#=#=#= Stage 7 =#=#=#=#="); + stage7(rsc_list, action_list, action_cons_list); + + pdebug("=#=#=#=#= Summary =#=#=#=#="); + summary(rsc_list); + + pdebug("========= Action Sets ========="); + + pdebug("\t========= Set %d (Un-runnable) =========", -1); + pdebug_action( + slist_iter(action, action_t, action_list, lpc, + if(action->optional == FALSE + && action->runnable == FALSE) { + print_action("\t", action, TRUE); + } + ) + ); + + pdebug_action( + slist_iter(action_set, GSList, action_set_list, lpc, + pdebug("\t========= Set %d =========", lpc); + slist_iter(action, action_t, action_set, lpc2, + print_action("\t", action, TRUE); + ) + ) + ); + + + pdebug("========= Stonith List ========="); + pdebug_action( + slist_iter(node, node_t, stonith_list, lpc, + print_node(NULL, node, FALSE); + ) + ); + + pdebug("========= Shutdown List ========="); + pdebug_action( + slist_iter(node, node_t, shutdown_list, lpc, + print_node(NULL, node, FALSE); + ) + ); + + pdebug("=#=#=#=#= Stage 8 =#=#=#=#="); + stage8(action_set_list); + + return xml_set_of_sets; +} diff --git a/crm/pengine/pe_utils.h b/crm/pengine/pe_utils.h new file mode 100644 index 0000000000..ac76d0a59b --- /dev/null +++ b/crm/pengine/pe_utils.h @@ -0,0 +1,36 @@ + +extern void print_node(const char *pre_text, + node_t *node, + gboolean details); + +extern void print_resource(const char *pre_text, + resource_t *rsc, + gboolean details); + +extern void print_rsc_to_node(const char *pre_text, + rsc_to_node_t *cons, + gboolean details); + +extern void print_rsc_to_rsc(const char *pre_text, + rsc_to_rsc_t *cons, + gboolean details); + +extern void print_color(const char *pre_text, + color_t *color, + gboolean details); + +extern void print_color_details(const char *pre_text, + struct color_shared_s *color, + gboolean details); + +extern void print_action(const char *pre_text, + action_t *action, + gboolean details); + +extern const char *contype2text(enum con_type type); +extern const char *strength2text(enum con_strength strength); +extern const char *modifier2text(enum con_modifier modifier); +extern const char *task2text(enum action_tasks task); + +extern action_t *action_new(int id, resource_t *rsc, enum action_tasks task); +extern xmlNodePtr action2xml(action_t *action); diff --git a/crm/pengine/pengine b/crm/pengine/pengine deleted file mode 100755 index 8d80cef3a7..0000000000 --- a/crm/pengine/pengine +++ /dev/null @@ -1,301 +0,0 @@ -#! /usr/bin/perl -# -# Copyright (C) 2004 Lars Marowsky-Brée -# -# 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. -# - -=head1 Policy Engine - -This does wonders, and stuff. - -Because it's wonderful, error handling ain't done yet. - -=cut - -use strict; -use warnings; -use heartbeat::clplumbing::ipc; -use heartbeat::clplumbing::log; -use Getopt::Std; -use Data::Dumper; -use XML::Simple qw(:strict); -use POSIX qw(setsid); -use vars qw( $ch - $CRM_SOCKET - $DEBUG - %opts - %XMLOpts - $VERSION - ); - -{ - no warnings qw(qw); - ($VERSION) = (qw$Id: pengine,v 1.8 2004/03/18 14:25:07 lars Exp $)[2]; -} - -$CRM_SOCKET = "/var/lib/heartbeat/crm/crmd"; -$DEBUG = 1; - -%XMLOpts = ( - ContentKey => '-content', - KeepRoot => 1, - KeyAttr => { 'hello' => '+client_uuid' }, -); - -####################################################################### -cl_log_set_entity("pengine"); - -getopts("dhvskrS", \%opts); - -if (defined($opts{'v'})) { - print "Policy Engine $VERSION\n"; - exit 0; -} - -if (defined($opts{'d'}) || defined($opts{'S'})) { - cl_log_enable_stderr(1); - $DEBUG++; -} else { - cl_log_enable_stderr(0); -} - -# Stand-alone debugging mode. -if (defined($opts{'S'})) { - &handle_msgs_from_stdin(); - exit 0; -} - -cl_log_set_facility("local0"); -cl_log_set_logfile("/tmp/pengine.log"); - -cl_log('notice', "Policy Engine $VERSION starting..."); - -# First, connect to daddy. Yes, this sets global vars in a sub function, -# but it's documented, and there can only be one connection to the CRM -# at any given time! - -&signin(); - -my %regs = ( hello => 0, ); -while ($ch->isrconn() && $ch->iswconn()) { - $ch->waitin(); - - if ($ch->is_message_pending()) { - if ($ch->status() == $IPC_CONNECT - || $ch->status() == $IPC_DISC_PENDING) { - my $msg = &crm_recv_msg(); - - if (defined($msg)) { - my $reply = &handle_msg($msg); - if (defined($reply)) { - &send_crm_msg($reply); - } - } - } else { - cl_log("info", "Received disconnect event."); - last; - } - } -} - -&shutdown(0, "Mainloop exited."); - -####################################################################### - -sub shutdown { - my ($rc, $msg) = @_; - - my $log = $rc > 0 ? "err" : "info"; - cl_log($log, "Shutting down: $msg"); - if (defined($ch)) { - cl_log($log, "Final connection status: R".$ch->isrconn(). - " W".$ch->iswconn()); - } - exit $rc; -} - -sub handle_msg { - my ($m) = @_; - my $reply; - # Do magic - - if (defined($$m{'hello'})) { - cl_log("info", "hello message received from crmd. No reply sent."); - } elsif (defined($$m{'crm_message'})) { - cl_log("info", "crm_message received"); - $m = $$m{'crm_message'}[0]; - my $op; - - if (defined($op = $$m{'options'}[0]{'operation'})) { - if ($op eq 'ping') { - cl_log("info", "ping_message (mostly implemented"); - $reply = &crm_ping_reply($m); - } elsif ($op eq 'quit') { - &shutdown(0, "Quit request received."); - } else { - cl_log("warn", - "Unknown operation requested: $op"); - } - } else { - cl_log('warn', "crm_message without operation request. Slacking along."); - } - - } else { - cl_log("warn", "unknown message type ignored"); - } - - return $reply; -} - -sub crm_ping_reply { - my ($m) = @_; - my $reply; - - $reply = { - crm_message => { - version => '1', - message_type => 'response', - sys_from => 'pengine', - sys_to => 'crmd', - timestamp => time, - options => { - result => 'ok', - }, - ping_item => { - crm_subsystem => 'pengine', - ping_status => 'running', - }, - }, - }; - - return $reply; -} - -sub handle_msgs_from_stdin { - my ($xml, $ref, $reply, $xmlout); - while ($xml = ) { - $ref = &decapsulate_msg($xml); - $reply = &handle_msg($ref); - $xmlout = &encapsulate_msg($reply); - print $xmlout."\n"; - } - &shutdown(0, "EOF"); -} - -sub signin { - my $rc = 0; - - cl_log('notice', "Connecting to crmd..."); - - $ch = heartbeat::clplumbing::ipc::channel->new($CRM_SOCKET); - - if ($rc = $ch->initiate_connection() != $IPC_OK) { - &shutdown(1, "Connection to crmd failed with $rc"); - } - - cl_log('notice', "Connection to crmd established, signing in"); - - &send_crm_msg( { 'hello' => - { 'client_uuid' => '01234567890abcdef0123456789abcdef', - 'client_name' => 'pengine', - 'major_version' => '1', - 'minor_version' => '0', - } - } ); -} - -sub encapsulate_msg { - my ($ref) = @_; - my $xml = XMLout($ref, - %XMLOpts, - NoIndent => 1); - # Kill all remaining annoying whitespace to make libxml2 more - # happy. (None should be left, but paranoia rules.) - $xml =~ s/>\s+/>/og; - $xml =~ s/\s+ 1, - ForceContent => 1, - NormaliseSpace => 1, ); - - print STDERR "Decapsulated message struct: " - .Data::Dumper->Dump([$ref], [qw(m)]) if $DEBUG > 1; - return $ref; -} - -sub send_crm_msg { - my ($ref) = @_; - - my $xml = &encapsulate_msg($ref); - - cl_log('info', "XML message we are about to sent: ".$xml) if $DEBUG; - - my $msg = heartbeat::clplumbing::ipc::message->new($ch, $xml); - - cl_log('info', "Message constructed."); - my $rc = $ch->send($msg); - cl_log('info', "Message sent: $rc"); -} - -sub crm_recv_msg { - cl_log('info', "Trying to receive message from crmd") if $DEBUG; - - my ($rc, $msg) = $ch->recv(); - - if ($rc != $IPC_OK) { - &shutdown(1, "Error receiving message from crmd: $rc"); - } - - cl_log('info', "XML message received: ".$msg->body()); - - my $ref = &decapsulate_msg($msg->body()); - - return $ref; -} - -=head1 AUTHOR - -Lars Marowsky-Bree, Elmb@suse.deE - -=head1 COPYRIGHT AND LICENSE - -Copyright (C) 2004 by Lars Marowsky-Bree - -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 - -=cut - - diff --git a/crm/pengine/pengine.c b/crm/pengine/pengine.c index ce262d991e..28eb2c70f4 100755 --- a/crm/pengine/pengine.c +++ b/crm/pengine/pengine.c @@ -1,1590 +1,1602 @@ #include #include #include +#include #include #include #include #include color_t *create_color(GSListPtr nodes, gboolean create_only); void add_color_to_rsc(resource_t *rsc, color_t *color); gint sort_rsc_priority(gconstpointer a, gconstpointer b); gint sort_cons_strength(gconstpointer a, gconstpointer b); gint sort_color_weight(gconstpointer a, gconstpointer b); gint sort_node_weight(gconstpointer a, gconstpointer b); gboolean create_rsc_to_rsc(const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh); gboolean create_ordering(const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh); gboolean unpack_constraints(xmlNodePtr constraints); gboolean unpack_resources(xmlNodePtr resources); gboolean unpack_nodes(xmlNodePtr nodes); gboolean unpack_status(xmlNodePtr status); gboolean apply_node_constraints(GSListPtr constraints, GSListPtr resources, GSListPtr nodes); void color_resource(resource_t *lh_resource); color_t *find_color(GSListPtr candidate_colors, color_t *other_color); gboolean is_active(rsc_to_node_t *cons); rsc_to_rsc_t *invert_constraint(rsc_to_rsc_t *constraint); gboolean filter_nodes(resource_t *rsc); resource_t *pe_find_resource(GSListPtr rsc_list, const char *id_rh); node_t *pe_find_node(GSListPtr node_list, const char *id); gboolean choose_node_from_list(color_t *color, GSListPtr nodes); rsc_to_node_t *copy_constraint(rsc_to_node_t *constraint); GSListPtr node_list_dup(GSListPtr list1); GSListPtr node_list_and(GSListPtr list1, GSListPtr list2); GSListPtr node_list_xor(GSListPtr list1, GSListPtr list2); GSListPtr node_list_minus(GSListPtr list1, GSListPtr list2); gboolean node_list_eq(GSListPtr list1, GSListPtr list2); node_t *node_copy(node_t *this_node) ; node_t *find_list_node(GSListPtr list, const char *id); gboolean unpack_rsc_to_attr(xmlNodePtr xml_obj); gboolean unpack_rsc_to_node(xmlNodePtr xml_obj); gboolean unpack_rsc_to_rsc (xmlNodePtr xml_obj); gboolean choose_color(resource_t *lh_resource, GSListPtr candidate_colors); gboolean strict_postproc(rsc_to_rsc_t *constraint, color_t *local_color, color_t *other_color); gboolean strict_preproc(rsc_to_rsc_t *constraint, color_t *local_color, color_t *other_color); gboolean update_node_weight(rsc_to_node_t *cons, node_t *node_rh); gboolean process_node_lrm_state(node_t *node, xmlNodePtr lrm_state); GSListPtr match_attrs(xmlNodePtr attr_exp, GSListPtr node_list); gboolean update_runnable(GSListPtr actions); GSListPtr create_action_set(action_t *action); GSListPtr rsc_list = NULL; GSListPtr node_list = NULL; GSListPtr node_cons_list = NULL; GSListPtr rsc_cons_list = NULL; GSListPtr action_list = NULL; GSListPtr action_set_list = NULL; GSListPtr action_cons_list = NULL; GSListPtr colors = NULL; GSListPtr stonith_list = NULL; GSListPtr shutdown_list = NULL; color_t *current_color = NULL; color_t *no_color = NULL; +xmlNodePtr xml_set_of_sets = NULL; int max_valid_nodes = 0; int order_id = 1; int action_id = 1; gboolean pe_debug = FALSE; gboolean pe_debug_saved = FALSE; gboolean stage0(xmlNodePtr cib) { xmlNodePtr cib_nodes = get_object_root("nodes", cib); xmlNodePtr cib_status = get_object_root("status", cib); xmlNodePtr cib_resources = get_object_root("resources", cib); xmlNodePtr cib_constraints = get_object_root("constraints", cib); unpack_nodes (safe_val(NULL, cib_nodes, children)); unpack_resources (safe_val(NULL, cib_resources, children)); unpack_status (safe_val(NULL, cib_status, children)); unpack_constraints(safe_val(NULL, cib_constraints, children)); return TRUE; } gboolean stage1(GSListPtr node_constraints, GSListPtr nodes, GSListPtr resources) { int lpc = 0; slist_iter( node, node_t, nodes, lpc, if(node == NULL) { // error } else if(node->weight >= 0.0 && node->details->online && node->details->type == node_member) { max_valid_nodes++; } ); apply_node_constraints(node_constraints, nodes, resources); return TRUE; } gboolean stage2(GSListPtr sorted_rsc, GSListPtr sorted_nodes, GSListPtr operations) { int lpc = 0; // Set initial color // Set color.candidate_nodes = all active nodes no_color = create_color(NULL, TRUE); colors = NULL; // leave the "no" color out of the list current_color = create_color(node_list, FALSE); // Set resource.color = color (all resources) // Set resource.provisional = TRUE (all resources) slist_iter( this_resource, resource_t, sorted_rsc, lpc, this_resource->color = current_color; this_resource->provisional = TRUE; ); pdebug("initialized resources to default color"); // Take (next) highest resource for(lpc = 0; lpc < g_slist_length(sorted_rsc); lpc++) { resource_t *lh_resource = (resource_t*)g_slist_nth_data(sorted_rsc, lpc); // if resource.provisional == FALSE, repeat if(lh_resource->provisional == FALSE) { // already processed this resource continue; } color_resource(lh_resource); // next resource } return TRUE; } gboolean stage3(void) { // not sure if this is a good idea or not if(g_slist_length(colors) > max_valid_nodes) { // we need to consolidate some } else if(g_slist_length(colors) < max_valid_nodes) { // we can create a few more } return TRUE; } #define color_n_nodes color_n->details->candidate_nodes #define color_n_plus_1_nodes color_n_plus_1->details->candidate_nodes gboolean stage4(GSListPtr colors) { int lpc = 0; color_t *color_n = NULL; color_t *color_n_plus_1 = NULL; for(lpc = 0; lpc < g_slist_length(colors); lpc++) { color_n = color_n_plus_1; color_n_plus_1 = (color_t*)g_slist_nth_data(colors, lpc); pdebug_action(print_color("Choose node for...", color_n, FALSE)); // print_color(color_n_plus_1, FALSE); if(color_n == NULL) { continue; } GSListPtr xor = node_list_xor(color_n_nodes, color_n_plus_1_nodes); GSListPtr minus = node_list_minus(color_n_nodes, color_n_plus_1_nodes); if(g_slist_length(xor) == 0 || g_slist_length(minus) == 0) { pdebug( "Choose any node from our list"); choose_node_from_list(color_n, color_n_nodes); } else { pdebug("Choose a node not in n+1"); choose_node_from_list(color_n, minus); } } // chose last color if(color_n_plus_1 != NULL) { pdebug_action(print_color("Choose node for last color...", color_n_plus_1, FALSE)); choose_node_from_list(color_n_plus_1, color_n_plus_1_nodes); } pdebug("done %s", __FUNCTION__); return TRUE; } gboolean stage5(GSListPtr resources) { pdebug("filling in the nodes to perform the actions on"); int lpc = 0; slist_iter( rsc, resource_t, resources, lpc, print_resource("Processing", rsc, FALSE); if(safe_val(NULL, rsc, stop) == NULL || safe_val(NULL, rsc, start) == NULL) { // error continue; } if(safe_val4(NULL, rsc, color, details, chosen_node) == NULL) { rsc->stop->node = safe_val(NULL, rsc, cur_node); rsc->start->node = NULL; } else if(safe_str_eq(safe_val4(NULL, rsc, cur_node, details, id), safe_val6(NULL, rsc, color ,details, chosen_node, details, id))){ cl_log(LOG_DEBUG, "No change for Resource %s (%s)", safe_val(NULL, rsc, id), safe_val4(NULL, rsc, cur_node, details, id)); rsc->stop->optional = TRUE; rsc->start->optional = TRUE; rsc->stop->node = safe_val(NULL, rsc, cur_node); rsc->start->node = safe_val4(NULL, rsc, color, details, chosen_node); } else if(safe_val4(NULL, rsc, cur_node, details, id) == NULL) { rsc->stop->optional = TRUE; rsc->start->node = safe_val4(NULL, rsc, color, details, chosen_node); } else { rsc->stop->node = safe_val(NULL, rsc, cur_node); rsc->start->node = safe_val4(NULL, rsc, color, details, chosen_node); } if(rsc->stop->node != NULL) { rsc->stop->runnable = TRUE; } if(rsc->start->node != NULL) { rsc->start->runnable = TRUE; } ); return TRUE; } gboolean stage6(GSListPtr stonith_nodes, GSListPtr shutdown_nodes) { int lpc = 0; int llpc = 0; slist_iter( node, node_t, shutdown_nodes, lpc, action_t *down_node = action_new(action_id++, NULL, shutdown_crm); down_node->node = node; down_node->runnable = TRUE; action_list = g_slist_append(action_list, down_node); slist_iter( rsc, resource_t, node->details->running_rsc, llpc, order_constraint_t *order = (order_constraint_t*) cl_malloc(sizeof(order_constraint_t)); /* stop resources before shutdown */ order->id = order_id++; order->lh_action = rsc->stop; order->rh_action = down_node; order->strength = must; action_cons_list = g_slist_append(action_cons_list, order); ); ); slist_iter( node, node_t, stonith_nodes, lpc, action_t *stonith_node = action_new(action_id++, NULL, stonith_op); stonith_node->node = node; stonith_node->runnable = TRUE; action_list = g_slist_append(action_list, stonith_node); slist_iter( rsc, resource_t, node->details->running_rsc, llpc, order_constraint_t *order = (order_constraint_t*) cl_malloc(sizeof(order_constraint_t)); /* try stopping the resource before stonithing the node * * if the stop succeeds, the transitioner can then * decided if stonith is needed */ order->id = order_id++; order->lh_action = rsc->stop; order->rh_action = stonith_node; order->strength = must; action_cons_list = g_slist_append(action_cons_list, order); /* stonith before start */ order = (order_constraint_t*) cl_malloc(sizeof(order_constraint_t)); // try stopping the node first order->id = order_id++; order->lh_action = stonith_node; order->rh_action = rsc->start; order->strength = must; action_cons_list = g_slist_append(action_cons_list, order); ); ); return TRUE; } gboolean stage7(GSListPtr resources, GSListPtr actions, GSListPtr action_constraints) { int lpc = 0; slist_iter( order, order_constraint_t, action_constraints, lpc, action_wrapper_t *wrapper = (action_wrapper_t*) cl_malloc(sizeof(action_wrapper_t)); wrapper->action = order->rh_action; wrapper->strength = order->strength; order->lh_action->actions_after = g_slist_append(order->lh_action->actions_after, wrapper); wrapper = (action_wrapper_t*) cl_malloc(sizeof(action_wrapper_t)); wrapper->action = order->lh_action; wrapper->strength = order->strength; order->rh_action->actions_before = g_slist_append(order->rh_action->actions_before, wrapper); ); update_runnable(actions); slist_iter( rsc, resource_t, resources, lpc, GSListPtr action_set = NULL; if(rsc->stop->runnable) { action_set = create_action_set(rsc->stop); if(action_set != NULL) { action_set_list = g_slist_append(action_set_list, action_set); } else { pdebug("No actions resulting from %s->stop", rsc->id); } } if(rsc->start->runnable) { action_set = create_action_set(rsc->start); if(action_set != NULL) { action_set_list = g_slist_append(action_set_list, action_set); } else { pdebug("No actions resulting from %s->start", rsc->id); } } ); return TRUE; } gboolean stage8(GSListPtr action_sets) { int lpc = 0; - cl_log(LOG_INFO, "========= Action Sets ========="); + xmlNodePtr xml_action_set = NULL; - cl_log(LOG_INFO, "\t========= Set %d (Un-runnable) =========", -1); + xml_set_of_sets = create_xml_node(NULL, "transition_graph"); + slist_iter(action, action_t, action_list, lpc, if(action->optional == FALSE && action->runnable == FALSE) { - print_action("\t", action, TRUE); + print_action("Ignoring", action, TRUE); } ); int lpc2; slist_iter(action_set, GSList, action_set_list, lpc, - cl_log(LOG_INFO, "\t========= Set %d =========", lpc); + pdebug("Processing Action Set %d", lpc); + xml_action_set = create_xml_node(NULL, "actions"); + set_xml_property_copy(xml_action_set, "id", crm_itoa(lpc)); + slist_iter(action, action_t, action_set, lpc2, - print_action("\t", action, TRUE))); + xmlNodePtr xml_action = action2xml(action); + xmlAddChild(xml_action_set, xml_action); + ) + xmlAddChild(xml_set_of_sets, xml_action_set); + ); + xml_message_debug(xml_set_of_sets, "created action list"); + return TRUE; } gboolean summary(GSListPtr resources) { int lpc = 0; slist_iter( rsc, resource_t, resources, lpc, char *rsc_id = safe_val(NULL, rsc, id); char *node_id = safe_val4(NULL, rsc, cur_node, details, id); char *new_node_id = safe_val6(NULL, rsc, color, details, chosen_node, details, id); if(rsc->runnable == FALSE) { cl_log(LOG_ERR, "Resource %s was not runnable", rsc_id); if(node_id != NULL) { cl_log(LOG_WARNING, "Stopping Resource (%s) on node %s", rsc_id, node_id); } } else if(safe_val4(NULL, rsc, color, details, chosen_node) == NULL) { cl_log(LOG_ERR, "Could not allocate Resource %s", rsc_id); if(node_id != NULL) { cl_log(LOG_WARNING, "Stopping Resource (%s) on node %s", rsc_id, node_id); } } else if(safe_str_eq(node_id, new_node_id)){ cl_log(LOG_DEBUG, "No change for Resource %s (%s)", rsc_id, safe_val4(NULL, rsc, cur_node, details, id)); } else if(node_id == NULL) { cl_log(LOG_INFO, "Starting Resource %s on %s", rsc_id, new_node_id); } else { cl_log(LOG_INFO, "Moving Resource %s from %s to %s", rsc_id, node_id, new_node_id); } ); return TRUE; } gboolean choose_node_from_list(color_t *color, GSListPtr nodes) { /* 1. Sort by weight 2. color.chosen_node = highest wieghted node 3. remove color.chosen_node from all other colors */ int lpc = 0; nodes = g_slist_sort(nodes, sort_node_weight); color->details->chosen_node = (node_t*)g_slist_nth_data(nodes, 0); if(color->details->chosen_node == NULL) { cl_log(LOG_ERR, "Could not allocate a node for color %d", color->id); return FALSE; } slist_iter( color_n, color_t, colors, lpc, node_t *other_node = pe_find_node(color_n->details->candidate_nodes, color->details->chosen_node->details->id); color_n->details->candidate_nodes = g_slist_remove(color_n->details->candidate_nodes, other_node); ); return TRUE; } gboolean unpack_nodes(xmlNodePtr nodes) { pdebug("Begining unpack... %s", __FUNCTION__); while(nodes != NULL) { pdebug("Processing node..."); xmlNodePtr xml_obj = nodes; xmlNodePtr attrs = xml_obj->children; const char *id = xmlGetProp(xml_obj, "id"); const char *type = xmlGetProp(xml_obj, "type"); if(attrs != NULL) { attrs = attrs->children; } nodes = nodes->next; if(id == NULL) { cl_log(LOG_ERR, "Must specify id tag in "); continue; } if(type == NULL) { cl_log(LOG_ERR, "Must specify type tag in "); continue; } node_t *new_node = cl_malloc(sizeof(node_t)); new_node->weight = 1.0; new_node->fixed = FALSE; new_node->details = (struct node_shared_s*) cl_malloc(sizeof(struct node_shared_s*)); new_node->details->online = FALSE; new_node->details->unclean = FALSE; new_node->details->running_rsc = NULL; new_node->details->id = cl_strdup(id); new_node->details->attrs = g_hash_table_new(g_str_hash, g_str_equal); new_node->details->type = node_ping; if(safe_str_eq(type, "node")) { new_node->details->type = node_member; } while(attrs != NULL){ const char *name = xmlGetProp(attrs, "name"); const char *value = xmlGetProp(attrs, "value"); if(name != NULL && value != NULL) { g_hash_table_insert(new_node->details->attrs, cl_strdup(name), cl_strdup(value)); } attrs = attrs->next; } pdebug("Adding node id... %s (%p)", id, new_node); node_list = g_slist_append(node_list, new_node); } node_list = g_slist_sort(node_list, sort_node_weight); return TRUE; } gboolean unpack_resources(xmlNodePtr resources) { pdebug("Begining unpack... %s", __FUNCTION__); while(resources != NULL) { xmlNodePtr xml_obj = resources; const char *id = xmlGetProp(xml_obj, "id"); const char *priority = xmlGetProp(xml_obj, "priority"); float priority_f = atof(priority); resources = resources->next; pdebug("Processing resource..."); if(id == NULL) { cl_log(LOG_ERR, "Must specify id tag in "); continue; } resource_t *new_rsc = cl_malloc(sizeof(resource_t)); new_rsc->xml = xml_obj; // copy first new_rsc->priority = priority_f; new_rsc->candidate_colors = NULL; new_rsc->color = NULL; new_rsc->runnable = TRUE; new_rsc->provisional = TRUE; new_rsc->allowed_nodes = node_list_dup(node_list); new_rsc->rsc_cons = NULL; new_rsc->node_cons = NULL; new_rsc->id = cl_strdup(id); action_t *action_stop = action_new(action_id++, new_rsc, stop_rsc); action_t *action_start = action_new(action_id++, new_rsc, start_rsc); new_rsc->stop = action_stop; action_list = g_slist_append(action_list, action_stop); new_rsc->start = action_start; action_list = g_slist_append(action_list, action_start); order_constraint_t *order = (order_constraint_t*) cl_malloc(sizeof(order_constraint_t)); order->id = order_id++; order->lh_action = action_stop; order->rh_action = action_start; order->strength = startstop; action_cons_list = g_slist_append(action_cons_list, order); pdebug_action(print_resource("Added", new_rsc, FALSE)); rsc_list = g_slist_append(rsc_list, new_rsc); } rsc_list = g_slist_sort(rsc_list, sort_rsc_priority); return TRUE; } gboolean unpack_constraints(xmlNodePtr constraints) { pdebug("Begining unpack... %s", __FUNCTION__); while(constraints != NULL) { const char *id = xmlGetProp(constraints, "id"); xmlNodePtr xml_obj = constraints; constraints = constraints->next; if(id == NULL) { cl_log(LOG_ERR, "Constraint must have an id"); continue; } pdebug("Processing constraint %s %s", xml_obj->name,id); if(safe_str_eq("rsc_to_rsc", xml_obj->name)) { unpack_rsc_to_rsc(xml_obj); } else if(safe_str_eq("rsc_to_node", xml_obj->name)) { unpack_rsc_to_node(xml_obj); } else if(safe_str_eq("rsc_to_attr", xml_obj->name)) { unpack_rsc_to_attr(xml_obj); } else { cl_log(LOG_ERR, "Unsupported constraint type: %s", xml_obj->name); } } return TRUE; } gboolean apply_node_constraints(GSListPtr constraints, GSListPtr resources, GSListPtr nodes) { pdebug("Applying constraints... %s", __FUNCTION__); int lpc = 0; slist_iter( cons, rsc_to_node_t, constraints, lpc, pdebug_action(print_rsc_to_node("Applying", cons, FALSE)); // take "lifetime" into account if(cons == NULL) { cl_log(LOG_ERR, "Constraint (%d) is NULL", lpc); continue; } else if(is_active(cons) == FALSE) { cl_log(LOG_INFO, "Constraint (%d) is not active", lpc); // warning continue; } resource_t *rsc_lh = cons->rsc_lh; if(rsc_lh == NULL) { cl_log(LOG_ERR, "LHS of rsc_to_node (%s) is NULL", cons->id); continue; } cons->rsc_lh->node_cons = g_slist_append(cons->rsc_lh->node_cons, cons); if(cons->node_list_rh == NULL) { cl_log(LOG_ERR, "RHS of rsc_to_node (%s) is NULL", cons->id); continue; } else { int llpc = 0; slist_iter(node_rh, node_t, cons->node_list_rh, llpc, update_node_weight(cons, node_rh)); } /* dont add it to the resource, * the information is in the resouce's node list */ ); 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(xmlNodePtr status) { pdebug("Begining unpack %s", __FUNCTION__); while(status != NULL) { const char *id = xmlGetProp(status, "id"); const char *state = xmlGetProp(status, "state"); const char *exp_state = xmlGetProp(status, "exp_state"); xmlNodePtr lrm_state = find_xml_node(status, "lrm"); xmlNodePtr attrs = find_xml_node(status, "attributes"); lrm_state = find_xml_node(lrm_state, "lrm_resources"); lrm_state = find_xml_node(lrm_state, "rsc_state"); status = status->next; pdebug("Processing node %s", id); if(id == NULL){ // error continue; } pdebug("Processing node attrs"); node_t *this_node = pe_find_node(node_list, id); while(attrs != NULL){ const char *name = xmlGetProp(attrs, "name"); const char *value = xmlGetProp(attrs, "value"); if(name != NULL && value != NULL && safe_val(NULL, this_node, details) != NULL) { pdebug("Adding %s => %s", name, value); g_hash_table_insert(this_node->details->attrs, cl_strdup(name), cl_strdup(value)); } attrs = attrs->next; } pdebug("determining node state"); if(safe_str_eq(exp_state, "active") && safe_str_eq(state, "active")) { // process resource, make +ve preference this_node->details->online = TRUE; } else { pdebug("remove %s", __FUNCTION__); // remove node from contention this_node->weight = -1; this_node->fixed = TRUE; pdebug("state %s, expected %s", state, exp_state); if(safe_str_eq(state, "shutdown")){ // create shutdown req shutdown_list = g_slist_append(shutdown_list, this_node); } else if(safe_str_eq(exp_state, "active") && safe_str_neq(state, "active")) { // mark unclean in the xml state = "unclean"; this_node->details->unclean = TRUE; // remove any running resources from being allocated } if(safe_str_eq(state, "unclean")) { stonith_list = g_slist_append(stonith_list, this_node); } } pdebug("Processing node lrm state"); process_node_lrm_state(this_node, lrm_state); } // node_cons_list too? rsc_cons_list = g_slist_sort(rsc_cons_list, sort_cons_strength); return TRUE; } gboolean is_active(rsc_to_node_t *cons) { return TRUE; } gboolean strict_preproc(rsc_to_rsc_t *constraint, color_t *local_color, color_t *other_color) { resource_t * lh_resource = constraint->rsc_lh; switch(constraint->strength) { case must: if(constraint->rsc_rh->runnable == FALSE) { cl_log(LOG_WARNING, "Resource %s must run on the same node" " as %s (cons %s), but %s is not" " runnable.", constraint->rsc_lh->id, constraint->rsc_rh->id, constraint->id, constraint->rsc_rh->id); constraint->rsc_lh->runnable = FALSE; } break; // x * should * should_not = x case should: if(constraint->rsc_rh->provisional == FALSE) { local_color->local_weight = local_color->local_weight * 2.0; } break; case should_not: if(constraint->rsc_rh->provisional == FALSE) { local_color->local_weight = local_color->local_weight * 0.5; } pdebug("# Colors %d, Nodes %d", g_slist_length(colors), max_valid_nodes); if(g_slist_length(colors) < max_valid_nodes // && g_slist_length(lh_resource->candidate_colors)==1 ) { // create_color(lh_resource->allowed_nodes); // } else if(g_slist_length(lh_resource->candidate_colors)==1) { create_color(lh_resource->allowed_nodes, FALSE); } break; case must_not: if(constraint->rsc_rh->provisional == FALSE) { lh_resource->candidate_colors = g_slist_remove( lh_resource->candidate_colors, local_color); } break; default: // error break; } return TRUE; } gboolean strict_postproc(rsc_to_rsc_t *constraint, color_t *local_color, color_t *other_color) { print_rsc_to_rsc("Post processing", constraint, FALSE); switch(constraint->strength) { case must: if(constraint->rsc_rh->provisional == TRUE) { constraint->rsc_rh->color = other_color; constraint->rsc_rh->provisional = FALSE; color_resource(constraint->rsc_rh); } // else check for error if(constraint->rsc_lh->runnable == FALSE) { cl_log(LOG_WARNING, "Resource %s must run on the same node" " as %s (cons %s), but %s is not" " runnable.", constraint->rsc_rh->id, constraint->rsc_lh->id, constraint->id, constraint->rsc_lh->id); constraint->rsc_rh->runnable = FALSE; } break; case should: break; case should_not: break; case must_not: if(constraint->rsc_rh->provisional == TRUE) { // check for error } break; default: // error break; } return TRUE; } gboolean choose_color(resource_t *lh_resource, GSListPtr candidate_colors) { int lpc = 0; if(lh_resource->runnable == FALSE) { lh_resource->color = no_color; lh_resource->provisional = FALSE; } else { GSListPtr sorted_colors = g_slist_sort(candidate_colors, sort_color_weight); lh_resource->candidate_colors = sorted_colors; pdebug( "Choose a color from %d possibilities", g_slist_length(sorted_colors)); } if(lh_resource->provisional) { slist_iter( this_color, color_t,lh_resource->candidate_colors, lpc, GSListPtr intersection = node_list_and( this_color->details->candidate_nodes, lh_resource->allowed_nodes); if(g_slist_length(intersection) != 0) { // TODO: merge node weights g_slist_free(this_color->details->candidate_nodes); this_color->details->candidate_nodes = intersection; lh_resource->color = this_color; lh_resource->provisional = FALSE; break; } ); } return !lh_resource->provisional; } gboolean unpack_rsc_to_node(xmlNodePtr xml_obj) { xmlNodePtr node_ref = xml_obj->children; rsc_to_node_t *new_con = cl_malloc(sizeof(rsc_to_node_t)); const char *id_lh = xmlGetProp(xml_obj, "from"); const char *id = xmlGetProp(xml_obj, "id"); const char *mod = xmlGetProp(xml_obj, "modifier"); const char *weight = xmlGetProp(xml_obj, "weight"); float weight_f = atof(weight); resource_t *rsc_lh = pe_find_resource(rsc_list, id_lh); if(rsc_lh == NULL) { cl_log(LOG_ERR, "No resource (con=%s, rsc=%s)", id, id_lh); } new_con->id = cl_strdup(id); new_con->rsc_lh = rsc_lh; new_con->weight = weight_f; if(safe_str_eq(mod, "set")){ new_con->modifier = set; } else if(safe_str_eq(mod, "inc")){ new_con->modifier = inc; } else if(safe_str_eq(mod, "dec")){ new_con->modifier = dec; } else { // error } /* */ // while(node_ref != NULL) { const char *id_rh = xmlGetProp(node_ref, "name"); node_t *node_rh = pe_find_node(node_list, id_rh); if(node_rh == NULL) { // error cl_log(LOG_ERR, "node %s (from %s) not found", id_rh, node_ref->name); continue; } new_con->node_list_rh = g_slist_append(new_con->node_list_rh, node_rh); /* dont add it to the resource, * the information is in the resouce's node list */ node_ref = node_ref->next; } node_cons_list = g_slist_append(node_cons_list, new_con); return TRUE; } gboolean unpack_rsc_to_attr(xmlNodePtr xml_obj) { /* Translation: give any node a +ve weight of 20.0 to run rsc2 if: attr "cpu" is set _and_ "kernel"="2.6", _or_ attr "hdd" is set _and_ "kernel"="2.4" Further translation: 2 constraints that give any node a +ve weight of 20.0 to run rsc2 cons1: attr "cpu" is set and "kernel"="2.6" cons2: attr "hdd" is set and "kernel"="2.4" */ xmlNodePtr attr_exp = xml_obj->children; const char *id_lh = xmlGetProp(xml_obj, "from"); const char *mod = xmlGetProp(xml_obj, "modifier"); const char *weight = xmlGetProp(xml_obj, "weight"); const char *id = xmlGetProp(attr_exp, "id"); float weight_f = atof(weight); enum con_modifier a_modifier = modifier_none; resource_t *rsc_lh = pe_find_resource(rsc_list, id_lh); if(rsc_lh == NULL) { cl_log(LOG_ERR, "No resource (con=%s, rsc=%s)", id, id_lh); return FALSE; } if(safe_str_eq(mod, "set")){ a_modifier = set; } else if(safe_str_eq(mod, "inc")){ a_modifier = inc; } else if(safe_str_eq(mod, "dec")){ a_modifier = dec; } else { // error } if(attr_exp == NULL) { cl_log(LOG_WARNING, "no attrs for constraint %s", id); } while(attr_exp != NULL) { const char *id_rh = xmlGetProp(attr_exp, "name"); const char *id = xmlGetProp(attr_exp, "id"); rsc_to_node_t *new_con = cl_malloc(sizeof(rsc_to_node_t)); new_con->id = cl_strdup(id); new_con->rsc_lh = rsc_lh; new_con->weight = weight_f; new_con->modifier = a_modifier; new_con->node_list_rh = match_attrs(attr_exp, node_list); if(new_con->node_list_rh == NULL) { // error cl_log(LOG_ERR, "node %s (from %s) not found", id_rh, attr_exp->name); } pdebug_action(print_rsc_to_node("Added", new_con, FALSE)); node_cons_list = g_slist_append(node_cons_list, new_con); /* dont add it to the resource, * the information is in the resouce's node list */ attr_exp = attr_exp->next; } return TRUE; } gboolean update_node_weight(rsc_to_node_t *cons, node_t *node) { node_t *node_rh = pe_find_node(cons->rsc_lh->allowed_nodes, node->details->id); if(node_rh == NULL) { node_t *node_tmp = pe_find_node(node_list, node->details->id); node_rh = node_copy(node_tmp); cons->rsc_lh->allowed_nodes = g_slist_append(cons->rsc_lh->allowed_nodes, node_rh); } if(node_rh == NULL) { // error return FALSE; } if(node_rh->fixed) { // warning cl_log(LOG_WARNING, "Constraint %s is irrelevant as the" " weight of node %s is fixed as %f.", cons->id, node_rh->details->id, node_rh->weight); return TRUE; } pdebug( "Constraint %s: node %s weight %s %f.", cons->id, node_rh->details->id, modifier2text(cons->modifier), node_rh->weight); switch(cons->modifier) { case set: node_rh->weight = cons->weight; node_rh->fixed = TRUE; break; case inc: node_rh->weight += cons->weight; break; case dec: node_rh->weight -= cons->weight; break; case modifier_none: // warning break; } return TRUE; } gboolean process_node_lrm_state(node_t *node, xmlNodePtr lrm_state) { pdebug("here %s", __FUNCTION__); while(lrm_state != NULL) { const char *id = xmlGetProp(lrm_state, "id"); const char *rsc_id = xmlGetProp(lrm_state, "rsc_id"); const char *node_id = xmlGetProp(lrm_state, "node_id"); const char *rsc_state = xmlGetProp(lrm_state, "rsc_state"); resource_t *rsc_lh = pe_find_resource(rsc_list, rsc_id); rsc_lh->cur_node = node; node->details->running_rsc = g_slist_append(node->details->running_rsc, rsc_lh); /* it is runnable, but depends on a stonith op if(safe_val3(FALSE, node, details, unclean)) { rsc_lh->runnable = FALSE; } */ if((safe_str_eq(rsc_state, "starting")) || (safe_str_eq(rsc_state, "started"))) { node_t *node_rh; rsc_to_node_t *new_cons = cl_malloc(sizeof(rsc_to_node_t)); new_cons->id = cl_strdup(id); // genereate one new_cons->weight = 100.0; new_cons->modifier = inc; new_cons->rsc_lh = rsc_lh; node_rh = pe_find_node(node_list, node_id); new_cons->node_list_rh = g_slist_append(NULL, node_rh); node_cons_list = g_slist_append(node_cons_list, new_cons); pdebug_action(print_rsc_to_node( "Added", new_cons, FALSE)); } else if(safe_str_eq(rsc_state, "stop_fail")) { // do soemthing } // else no preference lrm_state = lrm_state->next; } return TRUE; } GSListPtr match_attrs(xmlNodePtr attr_exp, GSListPtr node_list) { int lpc = 0; GSListPtr result = NULL; slist_iter( node, node_t, node_list, lpc, xmlNodePtr node_match = attr_exp->children; gboolean accept = TRUE; while(accept && node_match != NULL) { const char *type =xmlGetProp(node_match, "type"); const char *value=xmlGetProp(node_match, "value"); const char *name =xmlGetProp(node_match, "target"); node_match = node_match->next; if(name == NULL || type == NULL) { // error continue; } const char *h_val = (const char*) g_hash_table_lookup(node->details->attrs, name); if(h_val != NULL && safe_str_eq(type, "has_attr")){ accept = TRUE; } else if(h_val == NULL && safe_str_eq(type, "not_attr")) { accept = TRUE; } else if(h_val != NULL && safe_str_eq(type, "attr_value") && safe_str_eq(h_val, value)) { accept = TRUE; } else { accept = FALSE; } } if(accept) { result = g_slist_append(result, node); } ); return result; } gboolean create_rsc_to_rsc(const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh) { if(rsc_lh == NULL || rsc_rh == NULL){ // error return FALSE; } rsc_to_rsc_t *new_con = cl_malloc(sizeof(rsc_to_node_t)); rsc_to_rsc_t *inverted_con = NULL; new_con->id = cl_strdup(id); new_con->rsc_lh = rsc_lh; new_con->rsc_rh = rsc_rh; new_con->strength = strength; inverted_con = invert_constraint(new_con); rsc_cons_list = g_slist_insert_sorted(rsc_cons_list, inverted_con, sort_cons_strength); rsc_cons_list = g_slist_insert_sorted(rsc_cons_list, new_con, sort_cons_strength); rsc_lh->rsc_cons = g_slist_insert_sorted(rsc_lh->rsc_cons, inverted_con, sort_cons_strength); rsc_rh->rsc_cons = g_slist_insert_sorted(rsc_rh->rsc_cons, new_con, sort_cons_strength); return TRUE; } gboolean create_ordering(const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh) { if(rsc_lh == NULL || rsc_rh == NULL){ // error return FALSE; } action_t *lh_stop = rsc_lh->stop; action_t *lh_start = rsc_lh->start; action_t *rh_stop = rsc_rh->stop; action_t *rh_start = rsc_rh->start; order_constraint_t *order = (order_constraint_t*) cl_malloc(sizeof(order_constraint_t)); order->id = order_id++; order->lh_action = lh_stop; order->rh_action = rh_stop; order->strength = strength; action_cons_list = g_slist_append(action_cons_list, order); order = (order_constraint_t*) cl_malloc(sizeof(order_constraint_t)); order->id = order_id++; order->lh_action = rh_start; order->rh_action = lh_start; order->strength = strength; action_cons_list = g_slist_append(action_cons_list, order); return TRUE; } gboolean unpack_rsc_to_rsc(xmlNodePtr xml_obj) { const char *id_lh = xmlGetProp(xml_obj, "from"); const char *id = xmlGetProp(xml_obj, "id"); resource_t *rsc_lh = pe_find_resource(rsc_list, id_lh); const char *id_rh = xmlGetProp(xml_obj, "to"); resource_t *rsc_rh = pe_find_resource(rsc_list, id_rh); const char *strength = xmlGetProp(xml_obj, "strength"); const char *type = xmlGetProp(xml_obj, "type"); enum con_strength strength_e = ignore; if(rsc_lh == NULL) { cl_log(LOG_ERR, "No resource (con=%s, rsc=%s)", id, id_lh); return FALSE; } if(safe_str_eq(strength, "must")) { strength_e = must; } else if(safe_str_eq(strength, "should")) { strength_e = should; } else if(safe_str_eq(strength, "should_not")) { strength_e = should_not; } else if(safe_str_eq(strength, "must_not")) { strength_e = must_not; } else { // error } if(safe_str_eq(type, "ordering")) { // make an action_cons instead return create_ordering(id, strength_e, rsc_lh, rsc_rh); } return create_rsc_to_rsc(id, strength_e, rsc_lh, rsc_rh); } GSListPtr create_action_set(action_t *action) { int lpc = 0; GSListPtr result = NULL; GSListPtr tmp = NULL; if(action->processed) { return NULL; } pdebug_action(print_action("Create action set for", action, FALSE)); // process actions_before if(action->seen_count == 0) { pdebug("Processing \"before\" for action %d", action->id); slist_iter( other, action_wrapper_t, action->actions_before, lpc, tmp = create_action_set(other->action); pdebug("%d (%d total) \"before\" actions for %d)", g_slist_length(tmp), g_slist_length(result),action->id); result = g_slist_concat(result, tmp); ); // add ourselves pdebug("Adding self %d", action->id); if(action->processed == FALSE) { result = g_slist_append(result, action); action->processed = TRUE; } } else { pdebug("Already seen action %d", action->id); pdebug("Processing \"before\" for action %d", action->id); slist_iter( other, action_wrapper_t, action->actions_before, lpc, if(other->action->seen_count > action->seen_count && other->strength == must) { tmp = create_action_set(other->action); pdebug("%d (%d total) \"before\" actions for %d)", g_slist_length(tmp), g_slist_length(result),action->id); result = g_slist_concat(result, tmp); } ); // add ourselves pdebug("Adding self %d", action->id); if(action->processed == FALSE) { result = g_slist_append(result, action); action->processed = TRUE; } // add strength == !MUST slist_iter( other, action_wrapper_t, action->actions_before, lpc, tmp = create_action_set(other->action); pdebug("%d (%d total) post-self \"before\" actions for %d)", g_slist_length(tmp), g_slist_length(result),action->id); result = g_slist_concat(result, tmp); ); } action->seen_count = action->seen_count + 1; // process actions_after pdebug("Processing \"after\" for action %d", action->id); slist_iter( other, action_wrapper_t, action->actions_after, lpc, tmp = create_action_set(other->action); pdebug("%d (%d total) \"after\" actions for %d)", g_slist_length(tmp), g_slist_length(result),action->id); result = g_slist_concat(result, tmp); ); return result; } gboolean update_runnable(GSListPtr actions) { int lpc = 0, lpc2 = 0; gboolean change = TRUE; while(change) { change = FALSE; slist_iter( action, action_t, actions, lpc, if(action->runnable) { continue; } else if(action->optional) { continue; } slist_iter( other, action_wrapper_t, action->actions_before, lpc2, if(other->action->runnable) { change = TRUE; } other->action->runnable = FALSE; ); ); } return TRUE; } void color_resource(resource_t *lh_resource) { int lpc = 0; pdebug_action(print_resource("Coloring", lh_resource, FALSE)); if(lh_resource->provisional == FALSE) { // already processed this resource return; } lh_resource->rsc_cons = g_slist_sort(lh_resource->rsc_cons, sort_cons_strength); pdebug("=== Pre-processing"); //------ Pre-processing slist_iter( constraint, rsc_to_rsc_t, lh_resource->rsc_cons, lpc, color_t *other_color = NULL; color_t *local_color = NULL; if(lh_resource->runnable == FALSE) { break; } pdebug_action(print_rsc_to_rsc( "Processing constraint", constraint, FALSE)); if(constraint->rsc_rh == NULL) { cl_log(LOG_ERR, "rsc_rh was NULL for %s", constraint->id); continue; } other_color = constraint->rsc_rh->color; local_color = find_color(lh_resource->candidate_colors, other_color); strict_preproc(constraint, local_color, other_color); ); // filter out nodes with a negative weight filter_nodes(lh_resource); /* Choose a color from the candidates or, * create a new one if no color is suitable * (this may need modification pending further napkin drawings) */ choose_color(lh_resource, lh_resource->candidate_colors); pdebug("* Colors %d, Nodes %d", g_slist_length(colors), max_valid_nodes); if(lh_resource->provisional && g_slist_length(colors) < max_valid_nodes) { // Create new color pdebug("Create a new color"); current_color = create_color(lh_resource->allowed_nodes, FALSE); lh_resource->color = current_color; lh_resource->provisional = FALSE; } else if(lh_resource->provisional) { cl_log(LOG_ERR, "Could not color resource %s", lh_resource->id); print_resource("ERROR: No color", lh_resource, FALSE); lh_resource->color = no_color; lh_resource->provisional = FALSE; } pdebug_action(print_resource("Post-processing", lh_resource, FALSE)); //------ Post-processing color_t *local_color = lh_resource->color; slist_iter( constraint, rsc_to_rsc_t, lh_resource->rsc_cons, lpc, color_t *other_color = find_color(constraint->rsc_rh->candidate_colors, local_color); strict_postproc(constraint, local_color, other_color); ); pdebug_action(print_resource("Colored", lh_resource, FALSE)); } diff --git a/crm/pengine/pengine.h b/crm/pengine/pengine.h index a711ea31d5..c44a67a5ee 100644 --- a/crm/pengine/pengine.h +++ b/crm/pengine/pengine.h @@ -1,243 +1,214 @@ typedef GSList* GSListPtr; typedef struct node_s node_t; typedef struct color_s color_t; typedef struct rsc_to_node_s rsc_to_node_t; typedef struct rsc_to_rsc_s rsc_to_rsc_t; typedef struct resource_s resource_t; typedef struct order_constraint_s order_constraint_t; typedef struct action_s action_t; typedef struct action_wrapper_s action_wrapper_t; enum con_type { type_none, rsc_to_rsc, rsc_to_node, rsc_to_attr, base_weight }; enum node_type { node_ping, node_member }; enum con_strength { ignore, must, should, should_not, must_not, startstop }; enum con_modifier { modifier_none, set, inc, dec }; enum action_tasks { no_action, stop_rsc, start_rsc, shutdown_crm, stonith_op }; enum action_order { dontcare, before, after }; struct node_shared_s { char *id; gboolean online; gboolean unclean; GSListPtr running_rsc; // resource_t* GHashTable *attrs; // char* => char* enum node_type type; }; struct node_s { float weight; gboolean fixed; struct node_shared_s *details; }; struct color_shared_s { int id; GSListPtr candidate_nodes; // node_t* node_t *chosen_node; }; struct color_s { int id; struct color_shared_s *details; float local_weight; }; struct rsc_to_rsc_s { char *id; resource_t *rsc_lh; // gboolean is_placement; resource_t *rsc_rh; enum con_strength strength; }; struct rsc_to_node_s { char *id; resource_t *rsc_lh; float weight; GSListPtr node_list_rh; // node_t* enum con_modifier modifier; }; struct resource_s { char *id; xmlNodePtr xml; int priority; node_t *cur_node; gboolean runnable; gboolean provisional; action_t *stop; action_t *start; GSListPtr candidate_colors; // color_t* GSListPtr allowed_nodes; // node_t* GSListPtr node_cons; // rsc_to_node_t* GSListPtr rsc_cons; // resource_t* color_t *color; }; struct action_wrapper_s { enum con_strength strength; action_t *action; }; struct action_s { int id; resource_t *rsc; node_t *node; enum action_tasks task; gboolean runnable; gboolean processed; gboolean optional; gboolean failed; gboolean complete; int seen_count; GSListPtr actions_before; // action_warpper_t* GSListPtr actions_after; // action_warpper_t* }; struct order_constraint_s { int id; action_t *lh_action; action_t *rh_action; enum con_strength strength; // enum action_order order; }; extern gboolean stage0(xmlNodePtr cib); extern gboolean stage1(GSListPtr node_constraints, GSListPtr nodes, GSListPtr resources); extern gboolean stage2(GSListPtr sorted_rsc, GSListPtr sorted_nodes, GSListPtr operations); extern gboolean stage3(void); extern gboolean stage4(GSListPtr colors); extern gboolean stage5(GSListPtr resources); extern gboolean stage6(GSListPtr stonith, GSListPtr shutdown); extern gboolean stage7(GSListPtr resources, GSListPtr actions, GSListPtr action_constraints); +extern gboolean stage8(GSListPtr action_sets); extern gboolean summary(GSListPtr resources); +extern gboolean pe_input_dispatch(IPC_Channel *sender, void *user_data); + extern GSListPtr rsc_list; extern GSListPtr node_list; extern GSListPtr rsc_cons_list; extern GSListPtr node_cons_list; extern GSListPtr action_list; extern GSListPtr action_cons_list; extern GSListPtr colors; extern GSListPtr stonith_list; extern GSListPtr shutdown_list; extern GSListPtr action_set_list; - -extern void print_node(const char *pre_text, - node_t *node, - gboolean details); - -extern void print_resource(const char *pre_text, - resource_t *rsc, - gboolean details); - -extern void print_rsc_to_node(const char *pre_text, - rsc_to_node_t *cons, - gboolean details); - -extern void print_rsc_to_rsc(const char *pre_text, - rsc_to_rsc_t *cons, - gboolean details); - -extern void print_color(const char *pre_text, - color_t *color, - gboolean details); - -extern void print_color_details(const char *pre_text, - struct color_shared_s *color, - gboolean details); - -extern void print_action(const char *pre_text, - action_t *action, - gboolean details); - -extern const char *contype2text(enum con_type type); -extern const char *strength2text(enum con_strength strength); -extern const char *modifier2text(enum con_modifier modifier); -extern const char *task2text(enum action_tasks task); - -extern action_t *action_new(int id, resource_t *rsc, enum action_tasks task); +extern xmlNodePtr xml_set_of_sets; #define slist_iter(w, x, y, z, a) for(z = 0; z < g_slist_length(y); z++) { \ x *w = (x*)g_slist_nth_data(y, z); \ a; \ } extern gboolean pe_debug; extern gboolean pe_debug_saved; #define pdebug_action(x) if(pe_debug) { \ x; \ } #define pdebug(x...) if(pe_debug) { \ cl_log(LOG_DEBUG, x); \ } #define pe_debug_on() pe_debug_saved = pe_debug; pe_debug = TRUE; #define pe_debug_off() pe_debug_saved = pe_debug; pe_debug = FALSE; #define pe_debug_restore() pe_debug = pe_debug_saved; #define safe_val(def, x,y) (x==NULL?def:x->y) #define safe_val3(def, t,u,v) safe_val(def, safe_val(NULL, t,u),v) #define safe_val4(def, t,u,v,w) safe_val(def, safe_val(NULL, safe_val(NULL, t,u),v),w) #define safe_val5(def, t,u,v,w,x) safe_val(def, safe_val(NULL, safe_val(NULL, safe_val(NULL, t,u),v),w),x) #define safe_val6(def, t,u,v,w,x,y) safe_val(def, safe_val(NULL, safe_val(NULL, safe_val(NULL, safe_val(NULL, t,u),v),w),x),y) #define safe_val7(def, t,u,v,w,x,y,z) safe_val(def, safe_val(NULL, safe_val(NULL, safe_val(NULL, safe_val(NULL, safe_val(NULL, t,u),v),w),x),y),z) + +#include diff --git a/crm/pengine/penginemain.c b/crm/pengine/penginemain.c new file mode 100644 index 0000000000..84eb5b42d8 --- /dev/null +++ b/crm/pengine/penginemain.c @@ -0,0 +1,236 @@ +/* $Id: penginemain.c,v 1.11 2004/05/04 11:51:10 andrew Exp $ */ +/* + * 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 + +#define SYS_NAME "pengine" +#define OPTARGS "skrh" +#define PID_FILE WORKING_DIR "/"SYS_NAME".pid" +#define DAEMON_LOG "/var/log/"SYS_NAME".log" +#define DAEMON_DEBUG "/var/log/"SYS_NAME".debug" + +GMainLoop* mainloop = NULL; +const char* crm_system_name = SYS_NAME; + + +void usage(const char* cmd, int exit_status); +int init_start(void); +void pengine_shutdown(int nsig); +extern gboolean pe_input_dispatch(IPC_Channel *sender, void *user_data); + +int +main(int argc, char ** argv) +{ + int req_restart = FALSE; + int req_status = FALSE; + int req_stop = FALSE; + int argerr = 0; + int flag; + + cl_log_set_entity(crm_system_name); + cl_log_enable_stderr(TRUE); + cl_log_set_facility(LOG_USER); + + + if (0) + { + send_ipc_message(NULL, NULL); + } + + + while ((flag = getopt(argc, argv, OPTARGS)) != EOF) { + switch(flag) { + case 's': /* Status */ + req_status = TRUE; + break; + case 'k': /* Stop (kill) */ + req_stop = TRUE; + break; + case 'r': /* Restart */ + req_restart = TRUE; + break; + case 'h': /* Help message */ + usage(crm_system_name, LSB_EXIT_OK); + break; + default: + ++argerr; + break; + } + } + + if (optind > argc) { + ++argerr; + } + + if (argerr) { + usage(crm_system_name,LSB_EXIT_GENERIC); + } + + // read local config file + + if (req_status){ + return init_status(PID_FILE, crm_system_name); + } + + if (req_stop){ + return init_stop(PID_FILE); + } + + if (req_restart) { + init_stop(PID_FILE); + } + + return init_start(); + +} + + +int +init_start(void) +{ + long pid; + ll_cluster_t* hb_fd = NULL; + int facility; + IPC_Channel *crm_ch = NULL; +#ifdef REALTIME_SUPPORT + static int crm_realtime = 1; +#endif + + if ((pid = get_running_pid(PID_FILE, NULL)) > 0) { + cl_log(LOG_CRIT, "already running: [pid %ld].", pid); + exit(LSB_EXIT_OK); + } + + cl_log_set_logfile(DAEMON_LOG); +// if (crm_debug()) { + cl_log_set_debugfile(DAEMON_DEBUG); +// } + + /* change the logging facility to the one used by heartbeat daemon */ + hb_fd = ll_cluster_new("heartbeat"); + + cl_log(LOG_INFO, "Switching to Heartbeat logger"); + if ((facility = hb_fd->llc_ops->get_logfacility(hb_fd))>0) { + cl_log_set_facility(facility); + } + + cl_log(LOG_INFO, "Register PID"); + register_pid(PID_FILE, FALSE, pengine_shutdown); + + crm_ch = init_client_ipc_comms("crmd", pe_input_dispatch, NULL); + + if(crm_ch != NULL) { + send_hello_message(crm_ch, "1234", CRM_SYSTEM_PENGINE, "0", "1"); + + /* Create the mainloop and run it... */ + mainloop = g_main_new(FALSE); + cl_log(LOG_INFO, "Starting %s", crm_system_name); + + +#ifdef REALTIME_SUPPORT + 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(mainloop); + + } else { + cl_log(LOG_ERR, "Could not connect to the CRMd"); + } + + return_to_orig_privs(); + + if (unlink(PID_FILE) == 0) { + cl_log(LOG_INFO, "[%s] stopped", crm_system_name); + } + + if(crm_ch != NULL) + 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); +} + +void +pengine_shutdown(int nsig) +{ + static int shuttingdown = 0; + CL_SIGNAL(nsig, pengine_shutdown); + + if (!shuttingdown) { + shuttingdown = 1; + } + if (mainloop != NULL && g_main_is_running(mainloop)) { + g_main_quit(mainloop); + }else{ + exit(LSB_EXIT_OK); + } +} diff --git a/crm/pengine/ptest.c b/crm/pengine/ptest.c index 81faa5c98d..5eef8dbaea 100644 --- a/crm/pengine/ptest.c +++ b/crm/pengine/ptest.c @@ -1,239 +1,242 @@ -/* $Id: ptest.c,v 1.11 2004/05/03 12:34:36 andrew Exp $ */ +/* $Id: ptest.c,v 1.12 2004/05/04 11:51:10 andrew Exp $ */ /* * 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 "V?i:o:D:C:S:HA:U:M:I:EWRFt:m:a:d:w:c:r:p:s:" #include #include #include int main(int argc, char **argv) { xmlNodePtr cib_object = NULL; int lpc = 0; int argerr = 0; int flag; cl_log_set_entity("ptest"); cl_log_enable_stderr(TRUE); cl_log_set_facility(LOG_USER); xmlInitParser(); while (1) { int option_index = 0; static struct option long_options[] = { // Top-level Options {"daemon", 0, 0, 0}, {0, 0, 0, 0} }; flag = getopt_long(argc, argv, OPTARGS, long_options, &option_index); if (flag == -1) break; switch(flag) { case 0: printf("option %s", long_options[option_index].name); if (optarg) printf(" with arg %s", optarg); printf("\n"); break; /* 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': printf("option %d", flag); 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) { cl_log(LOG_ERR, "%d errors in option parsing", argerr); } cl_log(LOG_INFO, "=#=#=#=#= Getting XML =#=#=#=#="); cib_object = file2xml(stdin); cl_log(LOG_INFO, "=#=#=#=#= Stage 0 =#=#=#=#="); stage0(cib_object); cl_log(LOG_INFO, "========= Nodes ========="); slist_iter(node, node_t, node_list, lpc, print_node(NULL, node, TRUE)); cl_log(LOG_INFO, "========= Resources ========="); slist_iter(resource, resource_t, rsc_list, lpc, print_resource(NULL, resource, TRUE)); cl_log(LOG_INFO, "========= Constraints ========="); slist_iter(constraint, rsc_to_node_t, node_cons_list, lpc, print_rsc_to_node(NULL, constraint, FALSE)); slist_iter(constraint, rsc_to_rsc_t, rsc_cons_list, lpc, print_rsc_to_rsc(NULL, constraint, FALSE)); cl_log(LOG_INFO, "=#=#=#=#= Stage 1 =#=#=#=#="); stage1(node_cons_list, node_list, rsc_list); cl_log(LOG_INFO, "========= Nodes ========="); slist_iter(node, node_t, node_list, lpc, print_node(NULL, node, TRUE)); cl_log(LOG_INFO, "========= Resources ========="); slist_iter(resource, resource_t, rsc_list, lpc, print_resource(NULL, resource, TRUE)); cl_log(LOG_INFO, "=#=#=#=#= Stage 2 =#=#=#=#="); pe_debug_on(); stage2(rsc_list, node_list, NULL); pe_debug_off(); cl_log(LOG_INFO, "========= Nodes ========="); slist_iter(node, node_t, node_list, lpc, print_node(NULL, node, TRUE)); cl_log(LOG_INFO, "========= Resources ========="); slist_iter(resource, resource_t, rsc_list, lpc, print_resource(NULL, resource, TRUE)); cl_log(LOG_INFO, "========= Colors ========="); slist_iter(color, color_t, colors, lpc, print_color(NULL, color, FALSE)); cl_log(LOG_INFO, "=#=#=#=#= Stage 3 =#=#=#=#="); stage3(); cl_log(LOG_INFO, "========= Colors ========="); slist_iter(color, color_t, colors, lpc, print_color(NULL, color, FALSE)); cl_log(LOG_INFO, "=#=#=#=#= Stage 4 =#=#=#=#="); stage4(colors); cl_log(LOG_INFO, "========= Colors ========="); slist_iter(color, color_t, colors, lpc, print_color(NULL, color, FALSE)); cl_log(LOG_INFO, "=#=#=#=#= Summary =#=#=#=#="); summary(rsc_list); cl_log(LOG_INFO, "========= Action List ========="); slist_iter(action, action_t, action_list, lpc, print_action(NULL, action, FALSE)); cl_log(LOG_INFO, "=#=#=#=#= Stage 5 =#=#=#=#="); stage5(rsc_list); cl_log(LOG_INFO, "=#=#=#=#= Stage 6 =#=#=#=#="); stage6(stonith_list, shutdown_list); cl_log(LOG_INFO, "========= Action List ========="); slist_iter(action, action_t, action_list, lpc, print_action(NULL, action, TRUE)); cl_log(LOG_INFO, "=#=#=#=#= Stage 7 =#=#=#=#="); stage7(rsc_list, action_list, action_cons_list); cl_log(LOG_INFO, "=#=#=#=#= Summary =#=#=#=#="); summary(rsc_list); cl_log(LOG_INFO, "========= All Actions ========="); slist_iter(action, action_t, action_list, lpc, print_action("\t", action, TRUE); ); cl_log(LOG_INFO, "========= Action Sets ========="); cl_log(LOG_INFO, "\t========= Set %d (Un-runnable) =========", -1); slist_iter(action, action_t, action_list, lpc, if(action->optional == FALSE && action->runnable == FALSE) { print_action("\t", action, TRUE); } ); int lpc2; slist_iter(action_set, GSList, action_set_list, lpc, cl_log(LOG_INFO, "\t========= Set %d =========", lpc); slist_iter(action, action_t, action_set, lpc2, print_action("\t", action, TRUE))); cl_log(LOG_INFO, "========= Stonith List ========="); slist_iter(node, node_t, stonith_list, lpc, print_node(NULL, node, FALSE)); cl_log(LOG_INFO, "========= Shutdown List ========="); slist_iter(node, node_t, shutdown_list, lpc, print_node(NULL, node, FALSE)); + cl_log(LOG_INFO, "=#=#=#=#= Stage 8 =#=#=#=#="); + stage8(action_set_list); + return 0; } diff --git a/crm/pengine/utils.c b/crm/pengine/utils.c index e36ee021fe..f9c7daf842 100644 --- a/crm/pengine/utils.c +++ b/crm/pengine/utils.c @@ -1,813 +1,865 @@ #include #include #include +#include #include #include #include #include void print_str_str(gpointer key, gpointer value, gpointer user_data); color_t *create_color(GSListPtr nodes, gboolean create_only); void add_color_to_rsc(resource_t *rsc, color_t *color); gint sort_rsc_priority(gconstpointer a, gconstpointer b); gint sort_cons_strength(gconstpointer a, gconstpointer b); gint sort_color_weight(gconstpointer a, gconstpointer b); gint sort_node_weight(gconstpointer a, gconstpointer b); gboolean is_active(rsc_to_node_t *cons); rsc_to_rsc_t *invert_constraint(rsc_to_rsc_t *constraint); gboolean filter_nodes(resource_t *rsc); color_t *find_color(GSListPtr candidate_colors, color_t *other_color); resource_t *pe_find_resource(GSListPtr rsc_list, const char *id_rh); node_t *pe_find_node(GSListPtr node_list, const char *id); gboolean choose_node_from_list(GSListPtr colors, color_t *color, GSListPtr nodes); rsc_to_node_t *copy_constraint(rsc_to_node_t *constraint); GSListPtr node_list_dup(GSListPtr list1); GSListPtr node_list_and(GSListPtr list1, GSListPtr list2); GSListPtr node_list_xor(GSListPtr list1, GSListPtr list2); GSListPtr node_list_minus(GSListPtr list1, GSListPtr list2); gboolean node_list_eq(GSListPtr list1, GSListPtr list2); node_t *node_copy(node_t *this_node) ; node_t *find_list_node(GSListPtr list, const char *id); gboolean unpack_rsc_to_attr(xmlNodePtr xml_obj); gboolean unpack_rsc_to_node(xmlNodePtr xml_obj); gboolean choose_color(resource_t *lh_resource, GSListPtr candidate_colors); gboolean strict_postproc(rsc_to_node_t *constraint, color_t *local_color, color_t *other_color); gboolean strict_preproc(rsc_to_node_t *constraint, color_t *local_color, color_t *other_color); gboolean update_node_weight(rsc_to_node_t *cons, node_t *node_rh); gboolean process_node_lrm_state(xmlNodePtr lrm_state); /* only for rsc_to_rsc constraints */ rsc_to_rsc_t * invert_constraint(rsc_to_rsc_t *constraint) { pdebug("Inverting constraint"); rsc_to_rsc_t *inverted_con = cl_malloc(sizeof(rsc_to_node_t)); inverted_con->id = cl_strdup(constraint->id); inverted_con->strength = constraint->strength; // inverted_con->is_placement = constraint->is_placement; // swap the direction inverted_con->rsc_lh = constraint->rsc_rh; inverted_con->rsc_rh = constraint->rsc_lh; pdebug_action(print_rsc_to_rsc( "Inverted constraint", inverted_con, FALSE)); return inverted_con; } rsc_to_node_t * copy_constraint(rsc_to_node_t *constraint) { rsc_to_node_t *copied_con = cl_malloc(sizeof(rsc_to_node_t)); copied_con->id = cl_strdup(constraint->id); copied_con->rsc_lh = constraint->rsc_lh; copied_con->node_list_rh = constraint->node_list_rh; copied_con->modifier = constraint->modifier; copied_con->weight = constraint->weight; return copied_con; } /* are the contents of list1 and list2 equal */ /* nodes with weight < 0 are ignored */ gboolean node_list_eq(GSListPtr list1, GSListPtr list2) { GSListPtr result = NULL; if(g_slist_length(list1) != g_slist_length(list2)) { return FALSE; } // do stuff return g_slist_length(result) != 0; } /* the intersection of list1 and list2 */ /* nodes with weight < 0 are ignored */ GSListPtr node_list_and(GSListPtr list1, GSListPtr list2) { GSListPtr result = NULL; int lpc = 0; for(lpc = 0; lpc < g_slist_length(list1); lpc++) { node_t *node = (node_t*)g_slist_nth_data(list1, lpc); node_t *new_node = node_copy(node); node_t *other_node = find_list_node(list2, node->details->id); if(node == NULL || other_node == NULL) { continue; // merge node weights } else if(node->weight < 0 || other_node->weight < 0) { new_node->weight = -1; } else { new_node->weight = node->weight + other_node->weight; if(new_node->weight != 0) { new_node->weight = new_node->weight /2.0; } } result = g_slist_append(result, new_node); } return result; } node_t * find_list_node(GSListPtr list, const char *id) { int lpc = 0; slist_iter( thing, node_t, list, lpc, if(safe_str_eq(thing->details->id, id)) { return thing; } ); return NULL; } /* list1 - list2 */ /* nodes with weight < 0 are ignored */ GSListPtr node_list_minus(GSListPtr list1, GSListPtr list2) { GSListPtr result = NULL; int lpc = 0; slist_iter( node, node_t, list1, lpc, node_t *other_node = find_list_node(list2, node->details->id); if(node == NULL || other_node != NULL) { continue; // merge node weights } node_t *new_node = node_copy(node); result = g_slist_append(result, new_node); ); pdebug("Minus result len: %d", g_slist_length(result)); return result; } /* list1 + list2 - (intersection of list1 and list2) */ /* nodes with weight < 0 are ignored */ GSListPtr node_list_xor(GSListPtr list1, GSListPtr list2) { GSListPtr result = NULL; int lpc = 0; slist_iter( node, node_t, list1, lpc, node_t *other_node = (node_t*)find_list_node(list2, node->details->id); if(node == NULL || other_node != NULL) { continue; // merge node weights } node_t *new_node = node_copy(node); result = g_slist_append(result, new_node); ); slist_iter( node, node_t, list1, lpc, node_t *other_node = (node_t*)find_list_node(list1, node->details->id); if(node == NULL || other_node != NULL) { continue; // merge node weights } node_t *new_node = node_copy(node); result = g_slist_append(result, new_node); ); pdebug("Xor result len: %d", g_slist_length(result)); return result; } GSListPtr node_list_dup(GSListPtr list1) { GSListPtr result = NULL; int lpc = 0; slist_iter( this_node, node_t, list1, lpc, node_t *new_node = node_copy(this_node); if(new_node != NULL) { result = g_slist_append(result, new_node); } ); return result; } node_t * node_copy(node_t *this_node) { if(this_node == NULL) { print_node("Failed copy of", this_node, TRUE); return NULL; } node_t *new_node = cl_malloc(sizeof(node_t)); new_node->weight = this_node->weight; new_node->fixed = this_node->fixed; new_node->details = this_node->details; return new_node; } static int color_id = 0; color_t * create_color(GSListPtr nodes, gboolean create_only) { int lpc = 0; color_t *new_color = cl_malloc(sizeof(color_t)); new_color->id = color_id++; new_color->local_weight = 1.0; new_color->details = cl_malloc(sizeof(struct color_shared_s)); new_color->details->chosen_node = NULL; new_color->details->candidate_nodes = node_list_dup(nodes); pdebug_action(print_color("Created color", new_color, TRUE)); if(create_only == FALSE) { colors = g_slist_append(colors, new_color); /* Add any new color to the list of candidate_colors for * resources that havent been decided yet */ slist_iter( rsc, resource_t, rsc_list, lpc, if(rsc->provisional && rsc->runnable) { add_color_to_rsc(rsc, new_color); } ); } return new_color; } void add_color_to_rsc(resource_t *rsc, color_t *color) { if(rsc->provisional) { color_t *color_copy = cl_malloc(sizeof(color_t)); color_copy->id = color->id; color_copy->local_weight = 1.0; color_copy->details = color->details; rsc->candidate_colors = g_slist_append(rsc->candidate_colors, color_copy); } } gboolean filter_nodes(resource_t *rsc) { int lpc2 = 0; pdebug_action(print_resource("Filtering nodes for", rsc, FALSE)); slist_iter( node, node_t, rsc->allowed_nodes, lpc2, if(node == NULL) { cl_log(LOG_ERR, "Invalid NULL node"); } else if(node->weight < 0.0 || node->details->online == FALSE || node->details->type == node_ping) { pdebug_action(print_node("Removing", node, FALSE)); rsc->allowed_nodes = g_slist_remove(rsc->allowed_nodes,node); lpc2--; } ); return TRUE; } resource_t * pe_find_resource(GSListPtr rsc_list, const char *id_rh) { int lpc = 0; for(lpc = 0; lpc < g_slist_length(rsc_list); lpc++) { resource_t *rsc = g_slist_nth_data(rsc_list, lpc); if(rsc != NULL && safe_str_eq(rsc->id, id_rh)){ return rsc; } } // error return NULL; } node_t * pe_find_node(GSListPtr nodes, const char *id) { int lpc = 0; for(lpc = 0; lpc < g_slist_length(nodes); lpc++) { node_t *node = g_slist_nth_data(nodes, lpc); if(safe_str_eq(node->details->id, id)) { return node; } } // error return NULL; } color_t * find_color(GSListPtr candidate_colors, color_t *other_color) { int lpc = 0; if(other_color == NULL) { cl_log(LOG_ERR, "Cannot find NULL color"); return NULL; } slist_iter(color, color_t, candidate_colors, lpc, if(color->id == other_color->id) { return color; } ); return NULL; } 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) return 1; if(b == NULL) return -1; if(resource1->priority > resource2->priority) return -1; if(resource1->priority < resource2->priority) return 1; return 0; } gint sort_cons_strength(gconstpointer a, gconstpointer b) { const rsc_to_rsc_t *rsc_constraint1 = (const rsc_to_rsc_t*)a; const rsc_to_rsc_t *rsc_constraint2 = (const rsc_to_rsc_t*)b; if(a == NULL) return 1; if(b == NULL) return -1; if(rsc_constraint1->strength > rsc_constraint2->strength) return 1; if(rsc_constraint1->strength < rsc_constraint2->strength) return -1; return 0; } gint sort_color_weight(gconstpointer a, gconstpointer b) { const color_t *color1 = (const color_t*)a; const color_t *color2 = (const color_t*)b; if(a == NULL) return 1; if(b == NULL) return -1; if(color1->local_weight > color2->local_weight) return -1; if(color1->local_weight < color2->local_weight) return 1; return 0; } gint sort_node_weight(gconstpointer a, gconstpointer b) { const node_t *node1 = (const node_t*)a; const node_t *node2 = (const node_t*)b; if(a == NULL) return 1; if(b == NULL) return -1; if(node1->weight > node2->weight) return -1; if(node1->weight < node2->weight) return 1; return 0; } +action_t * +action_new(int id, resource_t *rsc, enum action_tasks task) +{ + action_t *action = (action_t*)cl_malloc(sizeof(action_t)); + action->id = id; + action->rsc = rsc; + action->task = task; + action->actions_before = NULL; + action->actions_after = NULL; + action->node = NULL; // fill node in later + action->runnable = FALSE; + action->processed = FALSE; + action->optional = FALSE; + action->failed = FALSE; // here? + action->complete = FALSE; // here? + action->seen_count = 0; + + return action; +} + const char * contype2text(enum con_type type) { const char *result = ""; switch(type) { case type_none: result = "none"; break; case rsc_to_rsc: result = "rsc_to_rsc"; break; case rsc_to_node: result = "rsc_to_node"; break; case rsc_to_attr: result = "rsc_to_attr"; break; case base_weight: result = "base_weight"; break; } return result; }; const char * strength2text(enum con_strength strength) { const char *result = ""; switch(strength) { case ignore: result = "ignore"; break; case must: result = "must"; break; case should: result = "should"; break; case should_not: result = "should_not"; break; case must_not: result = "must_not"; break; case startstop: result = "start/stop"; break; } return result; }; const char * modifier2text(enum con_modifier modifier) { const char *result = ""; switch(modifier) { case modifier_none: result = "modifier_none"; break; case set: result = "set"; break; case inc: result = "inc"; break; case dec: result = "dec"; break; } return result; }; const char * task2text(enum action_tasks task) { const char *result = ""; switch(task) { case no_action: result = "no_action"; break; case stop_rsc: result = "stop"; break; case start_rsc: result = "start"; break; case shutdown_crm: result = "shutdown_crm"; break; case stonith_op: result = "stonith"; break; } return result; }; void print_node(const char *pre_text, node_t *node, gboolean details) { if(node == NULL) { cl_log(LOG_DEBUG, "%s%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", __FUNCTION__); return; } cl_log(LOG_DEBUG, "%s%s%sNode %s: (weight=%f, fixed=%s)", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", node->details==NULL?"error ":node->details->online?"":"Unavailable/Unclean ", node->details->id, node->weight, node->fixed?"True":"False"); if(details && node->details != NULL) { cl_log(LOG_DEBUG, "\t\t===Node Attributes"); g_hash_table_foreach(node->details->attrs, print_str_str, cl_strdup("\t\t")); } if(details) { int lpc = 0; cl_log(LOG_DEBUG, "\t\t===Node Attributes"); slist_iter( rsc, resource_t, node->details->running_rsc, lpc, print_resource("\t\t", rsc, FALSE); ); } }; void print_str_str(gpointer key, gpointer value, gpointer user_data) { cl_log(LOG_DEBUG, "%s%s %s ==> %s", user_data==NULL?"":(char*)user_data, user_data==NULL?"":": ", (char*)key, (char*)value); } void print_color_details(const char *pre_text, struct color_shared_s *color, gboolean details) { if(color == NULL) { cl_log(LOG_DEBUG, "%s%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", __FUNCTION__); return; } cl_log(LOG_DEBUG, "%s%sColor %d: node=%s (from %d candidates)", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", color->id, color->chosen_node==NULL?"":color->chosen_node->details->id, g_slist_length(color->candidate_nodes)); if(details) { int lpc = 0; slist_iter(node, node_t, color->candidate_nodes, lpc, print_node("\t", node, FALSE)); } } void print_color(const char *pre_text, color_t *color, gboolean details) { if(color == NULL) { cl_log(LOG_DEBUG, "%s%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", __FUNCTION__); return; } cl_log(LOG_DEBUG, "%s%sColor %d: (weight=%f, node=%s, possible=%d)", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", color->id, color->local_weight, color->details->chosen_node==NULL?"":color->details->chosen_node->details->id, g_slist_length(color->details->candidate_nodes)); if(details) { print_color_details("\t", color->details, details); } } void print_rsc_to_node(const char *pre_text, rsc_to_node_t *cons, gboolean details) { if(cons == NULL) { cl_log(LOG_DEBUG, "%s%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", __FUNCTION__); return; } cl_log(LOG_DEBUG, "%s%s%s Constraint %s (%p):", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", "rsc_to_node", cons->id, cons); if(details == FALSE) { cl_log(LOG_DEBUG, "\t%s --> %s, %f (node placement rule)", cons->rsc_lh->id, modifier2text(cons->modifier), cons->weight); int lpc = 0; slist_iter( node, node_t, cons->node_list_rh, lpc, print_node("\t\t-->", node, FALSE) ); } }; void print_rsc_to_rsc(const char *pre_text, rsc_to_rsc_t *cons, gboolean details) { if(cons == NULL) { cl_log(LOG_DEBUG, "%s%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", __FUNCTION__); return; } cl_log(LOG_DEBUG, "%s%s%s Constraint %s (%p):", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", "rsc_to_rsc", cons->id, cons); if(details == FALSE) { cl_log(LOG_DEBUG, "\t%s --> %s, %s", cons->rsc_lh==NULL?"null":cons->rsc_lh->id, cons->rsc_rh==NULL?"null":cons->rsc_rh->id, strength2text(cons->strength)); } }; void print_resource(const char *pre_text, resource_t *rsc, gboolean details) { if(rsc == NULL) { cl_log(LOG_DEBUG, "%s%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", __FUNCTION__); return; } cl_log(LOG_DEBUG, "%s%s%s%sResource %s: (priority=%f, color=%d, now=%s)", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", rsc->provisional?"Provisional ":"", rsc->runnable?"":"(Non-Startable) ", rsc->id, (double)rsc->priority, safe_val3(-1, rsc, color, id), safe_val4(NULL, rsc, cur_node, details, id)); cl_log(LOG_DEBUG, "\t%d candidate colors, %d allowed nodes, %d rsc_cons and %d node_cons", g_slist_length(rsc->candidate_colors), g_slist_length(rsc->allowed_nodes), g_slist_length(rsc->rsc_cons), g_slist_length(rsc->node_cons)); if(details) { int lpc = 0; cl_log(LOG_DEBUG, "\t=== Colors"); slist_iter( color, color_t, rsc->candidate_colors, lpc, print_color("\t", color, FALSE) ); cl_log(LOG_DEBUG, "\t=== Allowed Nodes"); slist_iter( node, node_t, rsc->allowed_nodes, lpc, print_node("\t", node, FALSE); ); } } void print_action(const char *pre_text, action_t *action, gboolean details) { if(action == NULL) { cl_log(LOG_DEBUG, "%s%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", __FUNCTION__); return; } switch(action->task) { case stonith_op: case shutdown_crm: cl_log(LOG_DEBUG, "%s%s%sAction %d: %s @ %s", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", action->runnable?action->optional?"Optional ":action->processed?"":"(Provisional) ":"!!Non-Startable!! ", action->id, task2text(action->task), safe_val4(NULL, action, node, details, id)); break; default: cl_log(LOG_DEBUG, "%s%s%sAction %d: %s %s @ %s", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", action->runnable?action->optional?"Optional ":action->processed?"":"(Provisional) ":"!!Non-Startable!! ", action->id, task2text(action->task), safe_val3(NULL, action, rsc, id), safe_val7(NULL, action, rsc, color, details, chosen_node, details, id)); break; } if(details) { int lpc = 0; #if 0 - cl_log(LOG_DEBUG, "\t\t====== Before"); + cl_log(LOG_DEBUG, "\t\t====== Preceeding Actions"); slist_iter( other, action_wrapper_t, action->actions_before, lpc, print_action("\t\t", other->action, FALSE); ); #else - cl_log(LOG_DEBUG, "\t\t====== After"); + cl_log(LOG_DEBUG, "\t\t====== Subsequent Actions"); slist_iter( other, action_wrapper_t, action->actions_after, lpc, print_action("\t\t", other->action, FALSE); ); #endif cl_log(LOG_DEBUG, "\t\t====== End"); } else { cl_log(LOG_DEBUG, "\t\t(seen=%d, before=%d, after=%d)", action->seen_count, g_slist_length(action->actions_before), g_slist_length(action->actions_after)); } +} + + +xmlNodePtr +action2xml(action_t *action) +{ + xmlNodePtr action_xml = NULL; + if(action == NULL) { + return NULL; + } + switch(action->task) { + case stonith_op: + action_xml = create_xml_node(NULL, "pseduo_event"); + set_xml_property_copy(action_xml, + "on_node", + safe_val4(NULL, action, node, details, id)); + break; + case shutdown_crm: + action_xml = create_xml_node(NULL, "crm_event"); + set_xml_property_copy(action_xml, + "on_node", + safe_val4(NULL, action, node, details, id)); + break; + default: + action_xml = create_xml_node(NULL, "rsc_op"); + set_xml_property_copy(action_xml, + "on_node", + safe_val7(NULL, action, rsc, color, + details, chosen_node, details, id)); + add_node_copy(action_xml, action->rsc->xml); + + break; + } -} + set_xml_property_copy(action_xml, + "id", + crm_itoa(action->id)); + set_xml_property_copy(action_xml, + "runnable", + action->runnable?"true":"false"); -action_t * -action_new(int id, resource_t *rsc, enum action_tasks task) -{ - action_t *action = (action_t*)cl_malloc(sizeof(action_t)); - action->id = id; - action->rsc = rsc; - action->task = task; - action->actions_before = NULL; - action->actions_after = NULL; - action->node = NULL; // fill node in later - action->runnable = FALSE; - action->processed = FALSE; - action->optional = FALSE; - action->failed = FALSE; // here? - action->complete = FALSE; // here? - action->seen_count = 0; + set_xml_property_copy(action_xml, + "optional", + action->optional?"true":"false"); + + set_xml_property_copy(action_xml, + "task", + task2text(action->task)); + + return action_xml; }