diff --git a/include/crm/transition.h b/include/crm/transition.h index 36f1949c07..200b0113fa 100644 --- a/include/crm/transition.h +++ b/include/crm/transition.h @@ -1,157 +1,160 @@ /* * 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 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; 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_done, tg_stop, tg_restart, tg_shutdown, }; typedef struct crm_graph_s { int id; char *source; 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 stonith_timeout; int transition_timeout; int fired; int pending; int skipped; int completed; int incomplete; 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(xmlNode *xml_graph, const char *reference); 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 + +#include +extern lrm_op_t *convert_graph_action(xmlNode *resource, crm_action_t *action, int status, int rc); diff --git a/lib/transition/unpack.c b/lib/transition/unpack.c index 50cc1d0693..9ace14cdbd 100644 --- a/lib/transition/unpack.c +++ b/lib/transition/unpack.c @@ -1,277 +1,312 @@ /* * 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 static crm_action_t* unpack_action(synapse_t *parent, xmlNode *xml_action) { crm_action_t *action = 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) { crm_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, 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(xmlNode *xml_graph, const char *reference) { /* id = -1; new_graph->abort_priority = 0; new_graph->network_delay = -1; new_graph->transition_timeout = -1; new_graph->stonith_timeout = -1; new_graph->completion_action = tg_done; if(reference) { new_graph->source = crm_strdup(reference); } else { new_graph->source = crm_strdup("unknown"); } 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); time = crm_element_value(xml_graph, "stonith-timeout"); if(time == NULL) { new_graph->stonith_timeout = new_graph->network_delay; } else { new_graph->stonith_timeout = crm_get_msec(time); } 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); g_source_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->source); crm_free(graph); } +lrm_op_t *convert_graph_action(xmlNode *resource, crm_action_t *action, int status, int rc) +{ + lrm_op_t *op = NULL; + xmlNode *action_resource = NULL; + + CRM_CHECK(action != NULL, return NULL); + CRM_CHECK(action->type == action_type_rsc, return NULL); + + crm_malloc0(op, sizeof(lrm_op_t)); + + op->app_name = crm_strdup(crm_system_name); + + action_resource = first_named_child(action->xml, XML_CIB_TAG_RESOURCE); + CRM_CHECK(action_resource != NULL, crm_log_xml_warn(action->xml, "Bad"); return NULL); + + op->rsc_id = crm_strdup(ID(action_resource)); + op->interval = action->interval; + op->op_type = crm_strdup(crm_element_value(action->xml, XML_LRM_ATTR_TASK)); + op->rc = rc; + op->op_status = status; + op->params = action->params; + + op->call_id = 0; + xml_child_iter(resource, xop, + int tmp = 0; + crm_element_value_int(xop, XML_LRM_ATTR_CALLID, &tmp); + crm_info("Got call_id=%d for %s", tmp, ID(resource)); + if(tmp > op->call_id) { + op->call_id = tmp; + } + ); + + op->call_id++; + return op; +} diff --git a/tools/Makefile.am b/tools/Makefile.am index 76eca61f99..46f68fd03b 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,136 +1,140 @@ # # Copyright (C) 2004-2009 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 SUBDIRS = shell INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ -I$(top_builddir)/libltdl -I$(top_srcdir)/libltdl COMMONLIBS = \ $(top_builddir)/lib/common/libcrmcommon.la \ $(top_builddir)/lib/cib/libcib.la \ $(CURSESLIBS) $(CLUSTERLIBS) headerdir = $(pkgincludedir)/crm header_HEADERS = attrd.h EXTRA_DIST = $(sbin_SCRIPTS) halibdir = $(CRM_DAEMON_DIR) halib_SCRIPTS = haresources2cib.py hb2openais.sh halib_PROGRAMS = attrd pingd halib_PYTHON = crm_primitive.py hb2openais-helper.py sbin_PROGRAMS = crm_inject crmadmin cibadmin crm_node crm_attribute crm_resource crm_verify \ crm_uuid crm_shadow attrd_updater crm_diff crm_mon iso8601 if BUILD_SERVICELOG sbin_PROGRAMS += notifyServicelogEvent endif if BUILD_OPENIPMI_SERICELOG sbin_PROGRAMS += ipmiservicelogd endif if BUILD_HELP man8_MANS = $(sbin_PROGRAMS:%=%.8) %.8: % echo Creating $@ help2man --output $@ --no-info --section 8 --name "Part of the Pacemaker cluster resource manager" $(top_builddir)/tools/$< endif sbin_SCRIPTS = crm crm_standby crm_master crm_failcount ## SOURCES #noinst_HEADERS = config.h control.h crmd.h noinst_HEADERS = crmadmin_SOURCES = crmadmin.c crmadmin_LDADD = $(COMMONLIBS) $(CLUSTERLIBS) \ $(top_builddir)/lib/pengine/libpe_status.la crm_uuid_SOURCES = crm_uuid.c crm_uuid_LDADD = $(top_builddir)/lib/common/libcrmcluster.la cibadmin_SOURCES = cibadmin.c cibadmin_LDADD = $(COMMONLIBS) crm_shadow_SOURCES = cib_shadow.c crm_shadow_LDADD = $(COMMONLIBS) crm_node_SOURCES = ccm_epoche.c crm_node_LDADD = $(COMMONLIBS) $(CLUSTERLIBS) \ $(top_builddir)/lib/common/libcrmcluster.la crm_inject_SOURCES = crm_inject.c -crm_inject_LDADD = $(COMMONLIBS) +crm_inject_LDADD = $(COMMONLIBS) \ + $(top_builddir)/lib/pengine/libpe_status.la \ + $(top_builddir)/pengine/libpengine.la \ + $(top_builddir)/lib/cib/libcib.la \ + $(top_builddir)/lib/transition/libtransitioner.la crm_diff_SOURCES = xml_diff.c crm_diff_LDADD = $(COMMONLIBS) crm_mon_SOURCES = crm_mon.c crm_mon_LDADD = $(COMMONLIBS) $(SNMPLIBS) $(ESMTPLIBS) -llrm \ $(top_builddir)/lib/pengine/libpe_status.la # Arguments could be made that this should live in crm/pengine crm_verify_SOURCES = crm_verify.c crm_verify_LDADD = $(COMMONLIBS) \ $(top_builddir)/lib/pengine/libpe_status.la \ $(top_builddir)/pengine/libpengine.la crm_attribute_SOURCES = crm_attribute.c crm_attribute_LDADD = $(COMMONLIBS) crm_resource_SOURCES = crm_resource.c crm_resource_LDADD = $(COMMONLIBS) \ $(top_builddir)/lib/pengine/libpe_rules.la \ $(top_builddir)/lib/pengine/libpe_status.la \ $(top_builddir)/pengine/libpengine.la iso8601_SOURCES = test.iso8601.c iso8601_LDADD = $(COMMONLIBS) attrd_SOURCES = attrd.c attrd_LDADD = $(COMMONLIBS) $(top_builddir)/lib/common/libcrmcluster.la pingd_SOURCES = pingd.c pingd_LDADD = $(COMMONLIBS) attrd_updater_SOURCES = attrd_updater.c attrd_updater_LDADD = $(COMMONLIBS) if BUILD_SERVICELOG notifyServicelogEvent_SOURCES = notifyServicelogEvent.c notifyServicelogEvent_CFLAGS = `pkg-config --cflags servicelog-1` notifyServicelogEvent_LDFLAGS = `pkg-config --libs servicelog-1` $(top_builddir)/lib/common/libcrmcommon.la endif if BUILD_OPENIPMI_SERICELOG ipmiservicelogd_SOURCES = ipmiservicelogd.c ipmiservicelogd_CFLAGS = `pkg-config --cflags OpenIPMI OpenIPMIposix servicelog-1` ipmiservicelogd_LDFLAGS = `pkg-config --libs OpenIPMI OpenIPMIposix servicelog-1` $(top_builddir)/lib/common/libcrmcommon.la endif clean-generic: rm -f *.log *.debug *.xml *~ install-exec-local: uninstall-local: .PHONY: install-exec-hook diff --git a/tools/crm_inject.c b/tools/crm_inject.c index 527933f056..e52f983f9b 100644 --- a/tools/crm_inject.c +++ b/tools/crm_inject.c @@ -1,395 +1,704 @@ /* * Copyright (C) 2009 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 struct crm_option long_options[] = { - /* Top-level Options */ - {"help", 0, 0, '?', "\tThis text"}, - {"version", 0, 0, '$', "\tVersion information" }, - {"verbose", 0, 0, 'V', "\tIncrease debug output\n"}, - - {"-spacer-",0, 0, '-', "\nRequired Options:"}, - {"resource",1, 0, 'r', "The resource to update"}, - {"action", 1, 0, 'a', "The task to inject"}, - {"rc", 1, 0, 'o', "\tThe task's result"}, - - {"-spacer-", 0, 0, '-', "\nAdditional Options:"}, - {"node", 1, 0, 'N', "Host uname (defaults to current host)"}, - {"-spacer-",0, 0, '-', ""}, - {"interval", 1, 0, 'i', "The task's interval (defaults to zero)"}, - {"target-rc",1, 0, 't', "The task's expected result (defaults to zero)"}, - {"digest", 1, 0, 'd', "The task's digest"}, - {"-spacer-",0, 0, '-', ""}, - {"class", 1, 0, 'C', "The resource's class"}, - {"provider", 1, 0, 'P', "The resource's provider"}, - {"type", 1, 0, 'T', "The resource's type"}, - - {"-spacer-",0, 0, '-', "\nData Source:"}, - {"live-check", 0, 0, 'L', "Connect to the CIB and use the current contents as input"}, - {"xml-file", 1, 0, 'x', "Retrieve XML from the named file"}, - {"xml-pipe", 0, 0, 'p', "Retrieve XML from stdin"}, - - {0, 0, 0, 0} -}; - +cib_t *global_cib = NULL; +GListPtr op_fail = NULL; + #define node_template "//"XML_CIB_TAG_STATE"[@uname='%s']" #define rsc_template "//"XML_CIB_TAG_STATE"[@uname='%s']//"XML_LRM_TAG_RESOURCE"[@id='%s']" #define op_template "//"XML_CIB_TAG_STATE"[@uname='%s']//"XML_LRM_TAG_RESOURCE"[@id='%s']/"XML_LRM_TAG_RSC_OP"[@id='%s']" /* #define op_template "//"XML_CIB_TAG_STATE"[@uname='%s']//"XML_LRM_TAG_RESOURCE"[@id='%s']/"XML_LRM_TAG_RSC_OP"[@id='%s' and @"XML_LRM_ATTR_CALLID"='%d']" */ #define FAKE_TE_ID "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" +extern xmlNode * do_calculations( + pe_working_set_t *data_set, xmlNode *xml_input, ha_time_t *now); -static xmlNode *find_node(xmlNode *cib, const char *node) +static xmlNode *find_resource(xmlNode *cib_node, const char *resource) { char *xpath = NULL; xmlNode *match = NULL; - int max = strlen(rsc_template) + strlen(node) + 1; + const char *node = crm_element_value(cib_node, XML_ATTR_UNAME); + int max = strlen(rsc_template) + strlen(resource) + strlen(node) + 1; crm_malloc0(xpath, max); - snprintf(xpath, max, node_template, node); - match = get_xpath_object(xpath, cib, LOG_DEBUG_2); + snprintf(xpath, max, rsc_template, node, resource); + match = get_xpath_object(xpath, cib_node, LOG_DEBUG_2); crm_free(xpath); return match; } -static xmlNode *find_resource(xmlNode *cib, const char *node, const char *resource) +static xmlNode *inject_node(cib_t *cib_conn, char *node) { + int rc = cib_ok; + int max = strlen(rsc_template) + strlen(node) + 1; char *xpath = NULL; - xmlNode *match = NULL; - int max = strlen(rsc_template) + strlen(resource) + strlen(node) + 1; + xmlNode *cib_object = NULL; crm_malloc0(xpath, max); - snprintf(xpath, max, rsc_template, node, resource); - match = get_xpath_object(xpath, cib, LOG_DEBUG_2); + snprintf(xpath, max, node_template, node); + rc = cib_conn->cmds->query(cib_conn, xpath, &cib_object, cib_xpath|cib_sync_call|cib_scope_local); + + if(rc == cib_NOTEXISTS) { + char *uuid = NULL; + + cib_object = create_xml_node(NULL, XML_CIB_TAG_STATE); + determine_host(cib_conn, &node, &uuid); + crm_xml_add(cib_object, XML_ATTR_UUID, uuid); + crm_xml_add(cib_object, XML_ATTR_UNAME, node); + cib_conn->cmds->create(cib_conn, XML_CIB_TAG_STATUS, cib_object, cib_sync_call|cib_scope_local); + + rc = cib_conn->cmds->query(cib_conn, xpath, &cib_object, cib_xpath|cib_sync_call|cib_scope_local); + } - crm_free(xpath); - return match; + CRM_ASSERT(rc == cib_ok); + return cib_object; } -static int inject_node(cib_t *cib_conn, char *node) +static xmlNode *modify_node(cib_t *cib_conn, char *node, gboolean up) { - return 0; + xmlNode *cib_node = inject_node(cib_conn, node); + if(up) { + crm_xml_add(cib_node, XML_CIB_ATTR_HASTATE, ACTIVESTATUS); + crm_xml_add(cib_node, XML_CIB_ATTR_INCCM, XML_BOOLEAN_YES); + crm_xml_add(cib_node, XML_CIB_ATTR_CRMDSTATE, ONLINESTATUS); + crm_xml_add(cib_node, XML_CIB_ATTR_JOINSTATE, CRMD_JOINSTATE_MEMBER); + crm_xml_add(cib_node, XML_CIB_ATTR_EXPSTATE, CRMD_JOINSTATE_MEMBER); + + } else { + crm_xml_add(cib_node, XML_CIB_ATTR_HASTATE, DEADSTATUS); + crm_xml_add(cib_node, XML_CIB_ATTR_INCCM, XML_BOOLEAN_NO); + crm_xml_add(cib_node, XML_CIB_ATTR_CRMDSTATE, OFFLINESTATUS); + crm_xml_add(cib_node, XML_CIB_ATTR_JOINSTATE, CRMD_JOINSTATE_DOWN); + crm_xml_add(cib_node, XML_CIB_ATTR_EXPSTATE, CRMD_JOINSTATE_DOWN); + } + + crm_xml_add(cib_node, XML_ATTR_ORIGIN, crm_system_name); + return cib_node; } -static int inject_resource(cib_t *cib_conn, char *node, const char *resource, const char *rclass, const char *rtype, const char *rprovider) +static xmlNode *inject_resource(xmlNode *cib_node, const char *resource, const char *rclass, const char *rtype, const char *rprovider) { - int rc = 0; - - xmlNode *tmp = NULL; - xmlNode *cib_node = NULL; - xmlNode *cib_object = NULL; + xmlNode *lrm = NULL; + xmlNode *container = NULL; xmlNode *cib_resource = NULL; - rc = cib_conn->cmds->query(cib_conn, NULL, &cib_object, cib_sync_call|cib_scope_local); - CRM_ASSERT(rc == cib_ok); - - cib_resource = find_resource(cib_object, node, resource); + cib_resource = find_resource(cib_node, resource); if(cib_resource != NULL) { - return cib_ok; + return cib_resource; } /* One day, add query for class, provider, type */ if(rclass == NULL || rtype == NULL) { fprintf(stderr, "Resource %s not found in the status section of %s." - " Please supply the class and type to continue\n", resource, node); - return 1; + " Please supply the class and type to continue\n", resource, ID(cib_node)); + return NULL; } else if(safe_str_neq(rclass, "ocf") && safe_str_neq(rclass, "lsb")) { fprintf(stderr, "Invalid class for %s: %s\n", resource, rclass); - return 1; + return NULL; } else if(safe_str_eq(rclass, "ocf") && rprovider == NULL) { fprintf(stderr, "Please specify the provider for resource %s\n", resource); - return 1; + return NULL; } - cib_node = find_node(cib_object, node); - if(cib_node == NULL) { - fprintf(stderr, "Node %s not found in the status section\n", node); - return 1; - } - - crm_info("Injecting new resource %s into %s '%s'", resource, xmlGetNodePath(cib_node), node); + crm_info("Injecting new resource %s into %s '%s'", resource, xmlGetNodePath(cib_node), ID(cib_node)); - tmp = first_named_child(cib_node, XML_CIB_TAG_LRM); - if(tmp == NULL) { - char *node_uuid = NULL; - determine_host(cib_conn, &node, &node_uuid); - - tmp = create_xml_node(cib_node, XML_CIB_TAG_LRM); - crm_xml_add(tmp, XML_ATTR_ID, node_uuid); - - crm_free(node_uuid); + lrm = first_named_child(cib_node, XML_CIB_TAG_LRM); + if(lrm == NULL) { + const char *node_uuid = ID(cib_node); + lrm = create_xml_node(cib_node, XML_CIB_TAG_LRM); + crm_xml_add(lrm, XML_ATTR_ID, node_uuid); } - tmp = first_named_child(tmp, XML_LRM_TAG_RESOURCES); - if(tmp == NULL) { - tmp = create_xml_node(tmp, XML_LRM_TAG_RESOURCES); + container = first_named_child(lrm, XML_LRM_TAG_RESOURCES); + if(container == NULL) { + container = create_xml_node(lrm, XML_LRM_TAG_RESOURCES); } - cib_resource = create_xml_node(tmp, XML_LRM_TAG_RESOURCE); + cib_resource = create_xml_node(container, XML_LRM_TAG_RESOURCE); crm_xml_add(cib_resource, XML_ATTR_ID, resource); crm_xml_add(cib_resource, XML_AGENT_ATTR_CLASS, rclass); crm_xml_add(cib_resource, XML_AGENT_ATTR_PROVIDER, rprovider); crm_xml_add(cib_resource, XML_ATTR_TYPE, rtype); + + return cib_resource; +} - rc = cib_conn->cmds->replace(cib_conn, NULL, cib_object, cib_sync_call|cib_scope_local); - return rc; +static lrm_op_t *create_op( + xmlNode *cib_resource, const char *task, int interval, int outcome) +{ + lrm_op_t *op = NULL; + crm_malloc0(op, sizeof(lrm_op_t)); + + op->app_name = crm_strdup(crm_system_name); + + op->rsc_id = crm_strdup(ID(cib_resource)); + op->interval = interval; + op->op_type = crm_strdup(task); + + op->rc = outcome; + op->op_status = 0; + op->params = NULL; /* TODO: Fill me in */ + + op->call_id = 0; + xml_child_iter(cib_resource, xop, + int tmp = 0; + crm_element_value_int(xop, XML_LRM_ATTR_CALLID, &tmp); + if(tmp > op->call_id) { + op->call_id = tmp; + } + ); + op->call_id++; + + return op; } +static xmlNode *inject_op(xmlNode *cib_resource, lrm_op_t *op, int target_rc) +{ + return create_operation_update(cib_resource, op, CRM_FEATURE_SET, target_rc, crm_system_name); +} -static int inject_op( - cib_t *cib_conn, char *node, const char *resource, const char *task, const char *interval, - const char *outcome, const char *target_outcome, const char *digest) +static gboolean exec_pseudo_action(crm_graph_t *graph, crm_action_t *action) { - int rc = 0; - int max = 0; - int call = 1; + action->confirmed = TRUE; + update_graph(graph, action); + return TRUE; +} - char *key = NULL; - char *xpath = NULL; - char *t_key = NULL; - char *t_magic = NULL; +static gboolean exec_rsc_action(crm_graph_t *graph, crm_action_t *action) +{ + int rc = 0; + lrm_op_t *op = NULL; + int target_outcome = 0; + const char *rtype = NULL; + const char *rclass = NULL; + const char *resource = NULL; + const char *rprovider = NULL; + const char *target_rc_s = crm_meta_value(action->params, XML_ATTR_TE_TARGET_RC); + + xmlNode *cib_op = NULL; + xmlNode *cib_node = NULL; xmlNode *cib_object = NULL; xmlNode *cib_resource = NULL; - xmlNode *cib_operation = NULL; - - rc = cib_conn->cmds->query(cib_conn, NULL, &cib_object, cib_sync_call|cib_scope_local); - CRM_ASSERT(rc == cib_ok); + xmlNode *action_rsc = first_named_child(action->xml, XML_CIB_TAG_RESOURCE); - key = generate_op_key(resource, task, crm_atoi(interval, "0")); - crm_info("Injecting %s=%s on %s", key, outcome, node); + char *node = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET); - max = strlen(op_template) + strlen(resource) + strlen(node) + strlen(key) + 1; - crm_malloc0(xpath, max); + if(safe_str_eq(crm_element_value(action->xml, "operation"), "probe_complete")) { + crm_notice("Skipping %s op for %s", crm_element_value(action->xml, "operation"), node); + goto done; + } - snprintf(xpath, max, op_template, node, resource, key); - cib_operation = get_xpath_object(xpath, cib_object, LOG_DEBUG_2); + if(action_rsc == NULL) { + crm_log_xml_err(action->xml, "Bad"); + return FALSE; + } - crm_free(xpath); + resource = ID(action_rsc); + rclass = crm_element_value(action_rsc, XML_AGENT_ATTR_CLASS); + rtype = crm_element_value(action_rsc, XML_ATTR_TYPE); + rprovider = crm_element_value(action_rsc, XML_AGENT_ATTR_PROVIDER); - cib_resource = find_resource(cib_object, node, resource); - if(cib_resource == NULL) { - fprintf(stderr, "Resource %s not found in %s's status section\n", resource, node); - return 1; + if(target_rc_s != NULL) { + target_outcome = crm_parse_int(target_rc_s, "0"); } - - xml_child_iter(cib_resource, op, - int tmp = 0; - crm_element_value_int(op, XML_LRM_ATTR_CALLID, &tmp); - if(tmp > call) { - call = tmp; - } + + CRM_ASSERT(global_cib->cmds->query(global_cib, NULL, &cib_object, cib_sync_call|cib_scope_local) == cib_ok); + + cib_node = inject_node(global_cib, node); + CRM_ASSERT(cib_node != NULL); + + cib_resource = inject_resource(cib_node, resource, rclass, rtype, rprovider); + CRM_ASSERT(cib_resource != NULL); + + op = convert_graph_action(cib_resource, action, 0, target_outcome); + printf(" * Executing action %d: %s_%s_%d on %s\n", action->id, resource, op->op_type, op->interval, node); + + slist_iter(spec, char, op_fail, lpc, + + char *key = NULL; + crm_malloc0(key, strlen(spec)); + snprintf(key, strlen(spec), "%s_%s_%d@%s=", resource, op->op_type, op->interval, node); + + if(strncasecmp(key, spec, strlen(key)) == 0) { + rc = sscanf(spec, "%*[^=]=%d", &op->rc); + + action->failed = TRUE; + graph->abort_priority = INFINITY; + printf("\tPretending action %d failed with rc=%d\n", action->id, op->rc); + + break; + } ); - - if(cib_operation == NULL) { - char *node_uuid = NULL; - determine_host(cib_conn, &node, &node_uuid); - crm_info("Injecting new operation into %s", resource); - cib_operation = create_xml_node(cib_resource, XML_LRM_TAG_RSC_OP); - crm_xml_add(cib_operation, XML_LRM_ATTR_RSCID, resource); - crm_xml_add(cib_operation, XML_LRM_ATTR_TASK, task); - crm_xml_add(cib_operation, XML_LRM_ATTR_INTERVAL, interval); - crm_xml_add(cib_operation, XML_LRM_ATTR_TARGET, node); - crm_xml_add(cib_operation, XML_LRM_ATTR_TARGET_UUID, node_uuid); - } - - CRM_ASSERT(cib_operation); - - t_key = generate_transition_key(call, 1, crm_atoi(target_outcome, "0"), FAKE_TE_ID); - t_magic = generate_transition_magic(t_key, 0, crm_atoi(outcome, "0")); + cib_op = inject_op(cib_resource, op, target_outcome); - crm_info("Updating operation %d: %s", call, xmlGetNodePath(cib_operation)); - crm_xml_add(cib_operation, XML_ATTR_ID, key); - crm_xml_add(cib_operation, XML_ATTR_ORIGIN, crm_system_name); - crm_xml_add(cib_operation, XML_ATTR_TRANSITION_MAGIC, t_magic); - crm_xml_add(cib_operation, XML_ATTR_TRANSITION_KEY, t_key); + rc = global_cib->cmds->modify(global_cib, XML_CIB_TAG_STATUS, cib_node, cib_sync_call|cib_scope_local); + CRM_ASSERT(rc == cib_ok); + + done: + action->confirmed = TRUE; + update_graph(graph, action); + return TRUE; +} + +static gboolean exec_crmd_action(crm_graph_t *graph, crm_action_t *action) +{ + action->confirmed = TRUE; + update_graph(graph, action); + return TRUE; +} + +#define STATUS_PATH_MAX 512 +static gboolean exec_stonith_action(crm_graph_t *graph, crm_action_t *action) +{ + int rc = 0; + char xpath[STATUS_PATH_MAX]; + char *target = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET); + xmlNode *cib_node = modify_node(global_cib, target, FALSE); + crm_xml_add(cib_node, XML_ATTR_ORIGIN, __FUNCTION__); + CRM_ASSERT(cib_node != NULL); + + printf(" * Fencing %s\n", target); + rc = global_cib->cmds->replace(global_cib, XML_CIB_TAG_STATUS, cib_node, cib_sync_call|cib_scope_local); + CRM_ASSERT(rc == cib_ok); + + snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", target, XML_CIB_TAG_LRM); + rc = global_cib->cmds->delete(global_cib, xpath, NULL, cib_xpath|cib_sync_call|cib_scope_local); + + snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", target, XML_TAG_TRANSIENT_NODEATTRS); + rc = global_cib->cmds->delete(global_cib, xpath, NULL, cib_xpath|cib_sync_call|cib_scope_local); - crm_xml_add(cib_operation, XML_LRM_ATTR_OPSTATUS, "0"); - crm_xml_add(cib_operation, XML_LRM_ATTR_RC, outcome); - crm_xml_add_int(cib_operation, XML_LRM_ATTR_CALLID, call); + action->confirmed = TRUE; + update_graph(graph, action); + return TRUE; +} + +static char * +add_list_element(char *list, const char *value) +{ + int len = 0; + int last = 0; + + if(value == NULL) { + return list; + } + if(list) { + last = strlen(list); + } + len = last + 2; /* +1 space, +1 EOS */ + len += strlen(value); + crm_realloc(list, len); + sprintf(list + last, " %s", value); + return list; +} + +static void print_cluster_status(pe_working_set_t *data_set) +{ + char *online_nodes = NULL; + char *offline_nodes = NULL; + + slist_iter(node, node_t, data_set->nodes, lpc2, + const char *node_mode = NULL; + + if(node->details->unclean) { + if(node->details->online && node->details->unclean) { + node_mode = "UNCLEAN (online)"; + + } else if(node->details->pending) { + node_mode = "UNCLEAN (pending)"; + + } else { + node_mode = "UNCLEAN (offline)"; + } + + } else if(node->details->pending) { + node_mode = "pending"; + + } else if(node->details->standby_onfail && node->details->online) { + node_mode = "standby (on-fail)"; + + } else if(node->details->standby) { + if(node->details->online) { + node_mode = "standby"; + } else { + node_mode = "OFFLINE (standby)"; + } + + } else if(node->details->online) { + node_mode = "online"; + online_nodes = add_list_element(online_nodes, node->details->uname); + continue; + + } else { + node_mode = "OFFLINE"; + offline_nodes = add_list_element(offline_nodes, node->details->uname); + continue; + } + + if(safe_str_eq(node->details->uname, node->details->id)) { + printf("Node %s: %s\n", + node->details->uname, node_mode); + } else { + printf("Node %s (%s): %s\n", + node->details->uname, node->details->id, + node_mode); + } + ); - if(digest) { - crm_xml_add(cib_operation, XML_LRM_ATTR_OP_DIGEST, digest); + if(online_nodes) { + printf("Online: [%s ]\n", online_nodes); + crm_free(online_nodes); + } + if(offline_nodes) { + printf("OFFLINE: [%s ]\n", offline_nodes); + crm_free(offline_nodes); } -/* - crm_xml_add(cib_operation, XML_LRM_ATTR_OP_RESTART, ); - crm_xml_add(cib_operation, XML_LRM_ATTR_RESTART_DIGEST, ); -*/ - rc = cib_conn->cmds->replace(cib_conn, NULL, cib_object, cib_sync_call|cib_scope_local); - return rc; + fprintf(stdout, "\n"); + 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_printf, stdout); + ); + fprintf(stdout, "\n"); } +static struct crm_option long_options[] = { + /* Top-level Options */ + {"help", 0, 0, '?', "\tThis text"}, + {"version", 0, 0, '$', "\tVersion information" }, + {"verbose", 0, 0, 'V', "\tIncrease debug output\n"}, + + {"run", 0, 0, 'r', "Perform a simulation and populate the status section"}, + + {"-spacer-", 0, 0, '-', "\nNode Events:"}, + {"node-up", 1, 0, 'U', "Bring a node online"}, + {"node-down",1, 0, 'D', "Bring a node offline"}, + {"node-fail",1, 0, 'F', "Mark a node as failed"}, + + {"-spacer-", 0, 0, '-', "\nResource Events:"}, + {"op-inject",1, 0, 'i', "\t$node;$rsc_$task_$interval;$rc - Inject the specified task before running the simulation"}, + {"op-fail", 1, 0, 'f', "\t$node;$rsc_$task_$interval;$rc - Fail the specified task while running the simulation"}, + + {"-spacer-", 0, 0, '-', "\nAdditional Options:"}, + {"set-date", 1, 0, 'd', "Set date"}, + {"quorum", 1, 0, 'q', "Specify a value for quorum"}, + + {"-spacer-",0, 0, '-', "\nData Source:"}, + {"live-check", 0, 0, 'L', "Connect to the CIB and use the current contents as input"}, + {"xml-file", 1, 0, 'x', "Retrieve XML from the named file"}, + {"xml-pipe", 0, 0, 'p', "Retrieve XML from stdin"}, + + {0, 0, 0, 0} +}; + int main(int argc, char ** argv) { int rc = 0; cib_t *cib_conn = NULL; + gboolean process = FALSE; + const char *quorum = NULL; + pe_working_set_t data_set; + ha_time_t *a_date = NULL; int flag = 0; int index = 0; int argerr = 0; - char *node = NULL; + char *use_date = NULL; + lrm_op_t *op = NULL; - const char *rclass = NULL; - const char *rtype = NULL; - const char *rprovider = NULL; + xmlNode *cib_object = NULL; + xmlNode *cib_node = NULL; + xmlNode *cib_resource = NULL; + xmlNode *cib_op = NULL; + + GListPtr node_up = NULL; + GListPtr node_down = NULL; + GListPtr node_fail = NULL; + GListPtr op_inject = NULL; - const char *task = NULL; - const char *digest = NULL; - const char *resource = NULL; - const char *interval = "0"; - const char *outcome = NULL; const char *xml_file = NULL; - const char *target_outcome = "0"; - - crm_log_init("crm_inject", LOG_DEBUG, FALSE, TRUE, argc, argv); - crm_set_options("?$Vr:a:o:i:N:Lx:pt:d:C:T:P:", "-r [name] -a [task] -o [outcome] [additional options]", + + crm_log_init("crm_inject", LOG_NOTICE, FALSE, FALSE, argc, argv); + crm_set_options("?$Vpx:U:D:F:i:f:r", "[--run] [additional options]", long_options, "Tool for injecting tasks into a configuration"); if(argc < 2) { crm_help('?', LSB_EXIT_EINVAL); } while (1) { flag = crm_get_option(argc, argv, &index); if (flag == -1) break; switch(flag) { case 'V': alter_debug(DEBUG_INC); break; case '?': case '$': crm_help(flag, LSB_EXIT_OK); break; case 'p': xml_file = "-"; break; case 'x': xml_file = optarg; break; - case 'r': - resource = optarg; - break; - case 'a': - task = optarg; - break; - case 'o': - outcome = optarg; + case 'U': + node_up = g_list_append(node_up, optarg); break; - case 'd': - digest = optarg; + case 'D': + node_down = g_list_append(node_down, optarg); break; - case 't': - target_outcome = optarg; + case 'F': + node_fail = g_list_append(node_fail, optarg); break; case 'i': - interval = optarg; + op_inject = g_list_append(op_inject, optarg); break; - case 'C': - rclass = optarg; + case 'f': + op_fail = g_list_append(op_fail, optarg); break; - case 'T': - rtype = optarg; + case 'q': + quorum = optarg; break; - case 'P': - rprovider = optarg; - break; - case 'N': - node = crm_strdup(optarg); + case 'r': + process = TRUE; break; default: ++argerr; break; } } if (optind > argc) { ++argerr; } - if(resource == NULL) { - fprintf(stderr, "No resource specfied\n"); - ++argerr; - } - if(task == NULL) { - fprintf(stderr, "No task specfied\n"); - ++argerr; - } - if(outcome == NULL) { - fprintf(stderr, "No outcome specfied\n"); - ++argerr; - } - if (argerr) { crm_help('?', LSB_EXIT_GENERIC); } if(xml_file == NULL) { /* Use live CIB */ } else if(safe_str_eq(xml_file, "-")) { crm_err("Piping from stdin is not yet supported"); return 1; /* cib_object = filename2xml(NULL); */ /* write to a temp file */ } else { setenv("CIB_file", xml_file, 1); } cib_conn = cib_new(); + global_cib = cib_conn; cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command); - determine_host(cib_conn, &node, NULL); + if(op_inject || process) { + rc = cib_conn->cmds->query(cib_conn, NULL, &cib_object, cib_sync_call|cib_scope_local); + CRM_ASSERT(rc == cib_ok); + + set_working_set_defaults(&data_set); + data_set.input = cib_object; + data_set.now = new_ha_date(TRUE); + + cluster_status(&data_set); + fprintf(stdout, "\nInitial cluster status:\n\n"); + print_cluster_status(&data_set); + } - rc = inject_node(cib_conn, node); - CRM_ASSERT(rc == cib_ok); + printf("Performing requested modifications\n"); + if(use_date != NULL) { + a_date = parse_date(&use_date); + printf(" + Setting effective cluster time: %s", use_date); + log_date(LOG_WARNING, "Set fake 'now' to", a_date, ha_log_date|ha_log_time); + } + + if(quorum) { + xmlNode *top = create_xml_node(NULL, XML_TAG_CIB); + printf(" + Setting quorum: %s\n", quorum); + /* crm_xml_add(top, XML_ATTR_DC_UUID, dc_uuid); */ + crm_xml_add(top, XML_ATTR_HAVE_QUORUM, quorum); + + rc = global_cib->cmds->modify(cib_conn, NULL, top, cib_sync_call|cib_scope_local); + CRM_ASSERT(rc == cib_ok); + } + + slist_iter(node, char, node_up, lpc, + printf(" + Bringing node %s online\n", node); + cib_node = modify_node(cib_conn, node, TRUE); + CRM_ASSERT(cib_node != NULL); - rc = inject_resource(cib_conn, node, resource, rclass, rtype, rprovider); - CRM_ASSERT(rc == cib_ok); + rc = global_cib->cmds->modify(global_cib, XML_CIB_TAG_STATUS, cib_node, cib_sync_call|cib_scope_local); + CRM_ASSERT(rc == cib_ok); + ); + + slist_iter(node, char, node_down, lpc, + printf(" + Taking node %s offline\n", node); + cib_node = modify_node(cib_conn, node, FALSE); + CRM_ASSERT(cib_node != NULL); + + rc = global_cib->cmds->modify(global_cib, XML_CIB_TAG_STATUS, cib_node, cib_sync_call|cib_scope_local); + CRM_ASSERT(rc == cib_ok); + ); + + slist_iter(node, char, node_fail, lpc, + printf(" + Failing node %s\n", node); + cib_node = modify_node(cib_conn, node, TRUE); + crm_xml_add(cib_node, XML_CIB_ATTR_INCCM, XML_BOOLEAN_NO); + CRM_ASSERT(cib_node != NULL); + + rc = global_cib->cmds->modify(global_cib, XML_CIB_TAG_STATUS, cib_node, cib_sync_call|cib_scope_local); + CRM_ASSERT(rc == cib_ok); + ); + + + slist_iter(spec, char, op_inject, lpc, + + int rc = 0; + int outcome = 0; + int interval = 0; + + char *key = NULL; + char *node = NULL; + char *task = NULL; + char *resource = NULL; + + const char *rtype = NULL; + const char *rclass = NULL; + const char *rprovider = NULL; + + resource_t *rsc = NULL; + printf(" + Injecting %s into the configuration\n", spec); + + crm_malloc0(key, strlen(spec)); + crm_malloc0(node, strlen(spec)); + rc = sscanf(spec, "%[^@]@%[^=]=%d", key, node, &outcome); + CRM_CHECK(rc == 3, fprintf(stderr, "Invalid operation spec: %s. Only found %d fields\n", spec, rc); continue); + + parse_op_key(key, &resource, &task, &interval); + + rsc = pe_find_resource(data_set.resources, resource); + CRM_CHECK(rsc != NULL, fprintf(stderr, "Invalid resource name: %s\n", resource); continue); + + rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); + rtype = crm_element_value(rsc->xml, XML_ATTR_TYPE); + rprovider = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER); + + cib_node = inject_node(cib_conn, node); + CRM_ASSERT(cib_node != NULL); + + cib_resource = inject_resource(cib_node, resource, rclass, rtype, rprovider); + CRM_ASSERT(cib_resource != NULL); + + op = create_op(cib_resource, task, interval, outcome); + CRM_ASSERT(op != NULL); + + cib_op = inject_op(cib_resource, op, 0); + CRM_ASSERT(cib_op != NULL); + + rc = cib_conn->cmds->modify(cib_conn, XML_CIB_TAG_STATUS, cib_node, cib_sync_call|cib_scope_local); + CRM_ASSERT(rc == cib_ok); + ); + + if(process) { + crm_graph_t *transition = NULL; + enum transition_status graph_rc = -1; + + crm_graph_functions_t exec_fns = + { + exec_pseudo_action, + exec_rsc_action, + exec_crmd_action, + exec_stonith_action, + }; + + set_graph_functions(&exec_fns); + printf("\nExecuting cluster transition\n"); + + rc = cib_conn->cmds->query(cib_conn, NULL, &cib_object, cib_sync_call|cib_scope_local); + CRM_ASSERT(rc == cib_ok); + + do_calculations(&data_set, cib_object, a_date); + + transition = unpack_graph(data_set.graph, crm_system_name); + 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) { + printf("Transition failed: %s\n", transition_status(graph_rc)); + print_graph(LOG_ERR, transition); + } + destroy_graph(transition); + CRM_CHECK(graph_rc == transition_complete, crm_err("An invalid transition was produced")); + } - rc = inject_op(cib_conn, node, resource, task, interval, outcome, target_outcome, digest); + + rc = cib_conn->cmds->query(cib_conn, NULL, &cib_object, cib_sync_call|cib_scope_local); CRM_ASSERT(rc == cib_ok); + + printf("\nCalculating revised cluster status\n"); + set_working_set_defaults(&data_set); + data_set.input = cib_object; + data_set.now = a_date; + + cluster_status(&data_set); + print_cluster_status(&data_set); rc = cib_conn->cmds->signoff(cib_conn); + fflush(stderr); + return 0; }