diff --git a/crm/admin/Makefile.am b/crm/admin/Makefile.am index ab98e1fb25..48d836a828 100644 --- a/crm/admin/Makefile.am +++ b/crm/admin/Makefile.am @@ -1,114 +1,116 @@ # # 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) hasbindir = $(sbindir) LIBRT = @LIBRT@ AM_CFLAGS = @CFLAGS@ $(CRM_DEBUG_FLAGS) COMMONLIBS = $(CRM_DEBUG_LIBS) \ $(top_builddir)/lib/clplumbing/libplumb.la \ $(top_builddir)/lib/pils/libpils.la \ $(top_builddir)/lib/crm/common/libcrmcommon.la \ $(top_builddir)/lib/crm/cib/libcib.la \ $(top_builddir)/lib/apphb/libapphb.la \ $(top_builddir)/lib/hbclient/libhbclient.la \ $(GLIBLIB) \ $(CURSESLIBS) \ $(LIBRT) hasbin_SCRIPTS = crm_primitive.py ## binary progs hasbin_PROGRAMS = crmadmin cibadmin ccm_tool crm_diff crm_mon iso8601 \ crm_master crm_standby crm_failcount crm_attribute \ crm_resource crm_verify crm_uuid ## SOURCES #noinst_HEADERS = config.h control.h crmd.h noinst_HEADERS = crmadmin_SOURCES = crmadmin.c crmadmin_CFLAGS = -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' crmadmin_LDADD = $(COMMONLIBS) \ - $(top_builddir)/crm/pengine/libpengine.la + $(top_builddir)/lib/crm/pengine/libpe_status.la crm_uuid_SOURCES = crm_uuid.c crm_uuid_CFLAGS = -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' crm_uuid_LDADD = $(GLIBLIB) $(top_builddir)/lib/clplumbing/libplumb.la cibadmin_SOURCES = cibadmin.c cibadmin_CFLAGS = -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' cibadmin_LDADD = $(COMMONLIBS) ccm_tool_SOURCES = ccm_epoche.c ccm_tool_CFLAGS = -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' ccm_tool_LDADD = $(COMMONLIBS) \ $(top_builddir)/membership/ccm/libccmclient.la crm_diff_SOURCES = xml_diff.c crm_diff_CFLAGS = -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' crm_diff_LDADD = $(COMMONLIBS) crm_mon_SOURCES = crm_mon.c crm_mon_CFLAGS = -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' crm_mon_LDADD = $(COMMONLIBS) \ - $(top_builddir)/crm/pengine/libpengine.la + $(top_builddir)/lib/crm/pengine/libpe_status.la +# Arguments could be made that this should live in crm/pengine crm_verify_SOURCES = crm_verify.c crm_verify_CFLAGS = -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' crm_verify_LDADD = $(COMMONLIBS) \ + $(top_builddir)/lib/crm/pengine/libpe_status.la \ $(top_builddir)/crm/pengine/libpengine.la crm_master_SOURCES = crm_attribute.c crm_master_CFLAGS = -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' crm_master_LDADD = $(COMMONLIBS) crm_standby_SOURCES = crm_attribute.c crm_standby_CFLAGS = -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' crm_standby_LDADD = $(COMMONLIBS) crm_attribute_SOURCES = crm_attribute.c crm_attribute_CFLAGS = -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' crm_attribute_LDADD = $(COMMONLIBS) crm_failcount_SOURCES = crm_attribute.c crm_failcount_CFLAGS = -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' crm_failcount_LDADD = $(COMMONLIBS) crm_resource_SOURCES = crm_resource.c crm_resource_CFLAGS = -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' crm_resource_LDADD = $(COMMONLIBS) \ - $(top_builddir)/crm/pengine/libpengine.la + $(top_builddir)/lib/crm/pengine/libpe_status.la iso8601_SOURCES = test.iso8601.c iso8601_CFLAGS = -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' iso8601_LDADD = $(COMMONLIBS) clean-generic: rm -f *.log *.debug *.xml *~ install-exec-local: uninstall-local: diff --git a/crm/admin/crm_mon.c b/crm/admin/crm_mon.c index 1d009a93af..4196c3dedb 100644 --- a/crm/admin/crm_mon.c +++ b/crm/admin/crm_mon.c @@ -1,675 +1,676 @@ -/* $Id: crm_mon.c,v 1.25 2006/05/25 18:18:39 lars Exp $ */ +/* $Id: crm_mon.c,v 1.26 2006/06/07 12:46:57 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 #ifdef HAVE_GETOPT_H # include #endif #include /* GMainLoop *mainloop = NULL; */ const char *crm_system_name = "crm_mon"; #define OPTARGS "V?i:nrh:cdp:1" + void usage(const char *cmd, int exit_status); void blank_screen(void); int print_status(crm_data_t *cib); /* #define printw_at(line, fmt...) move(line, 0); printw(fmt); line++ */ void wait_for_refresh(int offset, const char *prefix, int msec); int print_html_status(crm_data_t *cib, const char *filename); void make_daemon(gboolean daemonize, const char *pidfile); gboolean mon_timer_popped(gpointer data); void mon_update(const HA_Message*, int, int, crm_data_t*,void*); char *as_html_file = NULL; char *pid_file = NULL; gboolean as_console = FALSE; gboolean group_by_node = FALSE; gboolean inactive_resources = FALSE; int interval = 15000; gboolean daemonize = FALSE; GMainLoop* mainloop = NULL; guint timer_id = 0; cib_t *cib_conn = NULL; int failed_connections = 0; gboolean one_shot = FALSE; #if CURSES_ENABLED # define print_as(fmt...) if(as_console) { \ printw(fmt); \ } else { \ fprintf(stdout, fmt); \ } #else # define print_as(fmt...) fprintf(stdout, fmt); #endif int main(int argc, char **argv) { int argerr = 0; int flag; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"interval", 1, 0, 'i'}, {"group-by-node", 0, 0, 'n'}, {"inactive", 0, 0, 'r'}, {"as-html", 1, 0, 'h'}, {"as-console", 0, 0, 'c'}, {"one-shot", 0, 0, '1'}, {"daemonize", 0, 0, 'd'}, {"pid-file", 0, 0, 'p'}, {0, 0, 0, 0} }; #endif pid_file = crm_strdup("/tmp/ClusterMon.pid"); crm_system_name = basename(argv[0]); crm_log_init(crm_system_name); crm_log_level = LOG_ERR -1; while (1) { #ifdef HAVE_GETOPT_H flag = getopt_long(argc, argv, OPTARGS, long_options, &option_index); #else flag = getopt(argc, argv, OPTARGS); #endif if (flag == -1) break; switch(flag) { case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case 'i': interval = crm_get_msec(optarg); break; case 'n': group_by_node = TRUE; break; case 'r': inactive_resources = TRUE; break; case 'd': daemonize = TRUE; break; case 'p': pid_file = crm_strdup(optarg); break; case 'h': as_html_file = crm_strdup(optarg); break; case 'c': #if CURSES_ENABLED as_console = TRUE; #else printf("You need to have curses available at compile time to enable console mode\n"); argerr++; #endif break; case '1': one_shot = TRUE; break; default: printf("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag); ++argerr; break; } } if (optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) printf("%s ", argv[optind++]); printf("\n"); } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } if(as_html_file == NULL) { #if CURSES_ENABLED as_console = TRUE; #else printf("Defaulting to one-shot mode\n"); printf("You need to have curses available at compile time to enable console mode\n"); one_shot = TRUE; #endif } if(daemonize) { as_console = FALSE; } if(one_shot) { daemonize = FALSE; as_console = FALSE; as_html_file = NULL; } if(daemonize && as_html_file == NULL) { usage(crm_system_name, LSB_EXIT_GENERIC); } make_daemon(daemonize, pid_file); if(as_console) { initscr(); cbreak(); noecho(); } crm_info("Starting %s", crm_system_name); mainloop = g_main_new(FALSE); if(one_shot == FALSE) { timer_id = Gmain_timeout_add( interval, mon_timer_popped, NULL); } mon_timer_popped(NULL); g_main_run(mainloop); return_to_orig_privs(); crm_info("Exiting %s", crm_system_name); if(as_console) { echo(); nocbreak(); endwin(); } return 0; } gboolean mon_timer_popped(gpointer data) { int rc = cib_ok; int options = cib_scope_local; if(timer_id > 0) { Gmain_timeout_remove(timer_id); } if(as_console) { #if CURSES_ENABLED move(0, 0); printw("Updating...\n"); clrtoeol(); refresh(); #endif } else { crm_notice("Updating..."); } if(cib_conn == NULL) { crm_debug_4("Creating CIB connection"); cib_conn = cib_new(); } CRM_DEV_ASSERT(cib_conn != NULL); if(crm_assert_failed) { return FALSE; } else if(cib_conn->state != cib_connected_query){ crm_debug_4("Connecting to the CIB"); #if CURSES_ENABLED if(as_console) { printw("Signing on...\n"); clrtoeol(); refresh(); } #endif if(cib_ok == cib_conn->cmds->signon( cib_conn, crm_system_name, cib_query)) { failed_connections = 0; } else { failed_connections++; CRM_DEV_ASSERT(cib_conn->cmds->signoff(cib_conn) == cib_ok); wait_for_refresh(0, "Not connected: ", 2*interval); return FALSE; } #if CURSES_ENABLED if(as_console) { printw("Querying...\n"); clrtoeol(); refresh(); } #endif } if(as_console) { blank_screen(); } rc = cib_conn->cmds->query(cib_conn, NULL, NULL, options); add_cib_op_callback(rc, FALSE, NULL, mon_update); return FALSE; } void mon_update(const HA_Message *msg, int call_id, int rc, crm_data_t *output, void*user_data) { const char *prefix = NULL; if(rc == cib_ok) { crm_data_t *cib = NULL; #if CRM_DEPRECATED_SINCE_2_0_4 if( safe_str_eq(crm_element_name(output), XML_TAG_CIB) ) { cib = output; } else { cib = find_xml_node(output,XML_TAG_CIB,TRUE); } #else cib = output; CRM_DEV_ASSERT(safe_str_eq(crm_element_name(cib), XML_TAG_CIB)); #endif if(as_html_file) { print_html_status(cib, as_html_file); } else { print_status(cib); } } else if(one_shot) { fprintf(stderr, "Query failed: %s", cib_error2string(rc)); exit(LSB_EXIT_OK); } else { CRM_DEV_ASSERT(cib_conn->cmds->signoff(cib_conn) == cib_ok); crm_err("Query failed: %s", cib_error2string(rc)); prefix = "Query failed! "; } wait_for_refresh(0, prefix, interval); } void wait_for_refresh(int offset, const char *prefix, int msec) { int lpc = msec / 1000; if(as_console == FALSE) { timer_id = Gmain_timeout_add(msec, mon_timer_popped, NULL); return; } crm_notice("%sRefresh in %ds...", prefix?prefix:"", lpc); while(lpc > 0) { #if CURSES_ENABLED move(0, 0); /* printw("%sRefresh in \033[01;32m%ds\033[00m...", prefix?prefix:"", lpc); */ printw("%sRefresh in %ds...\n", prefix?prefix:"", lpc); clrtoeol(); refresh(); #endif lpc--; if(lpc == 0) { timer_id = Gmain_timeout_add( 1000, mon_timer_popped, NULL); } else { sleep(1); } } } int print_status(crm_data_t *cib) { node_t *dc = NULL; static int updates = 0; pe_working_set_t data_set; char *since_epoch = NULL; time_t a_time = time(NULL); int print_opts = pe_print_ncurses; if(as_console) { blank_screen(); } else { print_opts = pe_print_printf; } updates++; set_working_set_defaults(&data_set); data_set.input = cib; - stage0(&data_set); + cluster_status(&data_set); dc = data_set.dc_node; print_as("\n\n============\n"); if(a_time == (time_t)-1) { cl_perror("set_node_tstamp(): Invalid time returned"); return 1; } since_epoch = ctime(&a_time); if(since_epoch != NULL) { print_as("Last updated: %s", since_epoch); } if(dc == NULL) { print_as("Current DC: NONE\n"); } else { print_as("Current DC: %s (%s)\n", dc->details->uname, dc->details->id); } print_as("%d Nodes configured.\n", g_list_length(data_set.nodes)); print_as("%d Resources configured.\n", g_list_length(data_set.resources)); print_as("============\n\n"); slist_iter(node, node_t, data_set.nodes, lpc2, const char *node_mode = "OFFLINE"; if(node->details->standby) { node_mode = "standby"; } else if(node->details->online) { node_mode = "online"; } print_as("Node: %s (%s): %s\n", node->details->uname, node->details->id, node_mode); if(group_by_node) { slist_iter(rsc, resource_t, node->details->running_rsc, lpc2, rsc->fns->print( rsc, "\t", print_opts|pe_print_rsconly, stdout); ); } ); if(group_by_node == FALSE && inactive_resources) { print_as("\nFull list of resources:\n"); } else if(inactive_resources) { print_as("\nInactive resources:\n"); } if(group_by_node == FALSE || inactive_resources) { print_as("\n"); slist_iter(rsc, resource_t, data_set.resources, lpc2, gboolean is_active = rsc->fns->active(rsc, TRUE); gboolean partially_active = rsc->fns->active(rsc, FALSE); if(rsc->orphan && is_active == FALSE) { continue; } else if(group_by_node == FALSE) { if(partially_active || inactive_resources) { rsc->fns->print(rsc, NULL, print_opts, stdout); } } else if(is_active == FALSE && inactive_resources) { rsc->fns->print(rsc, NULL, print_opts, stdout); } ); } if(one_shot) { exit(LSB_EXIT_OK); } refresh(); data_set.input = NULL; cleanup_calculations(&data_set); return 0; } int print_html_status(crm_data_t *cib, const char *filename) { static int updates = 0; pe_working_set_t data_set; node_t *dc = NULL; char *filename_tmp = crm_concat(filename, "tmp", '.'); FILE *stream = fopen(filename_tmp, "w"); if(stream == NULL) { crm_free(filename_tmp); return -1; } updates++; set_working_set_defaults(&data_set); data_set.input = cib; - stage0(&data_set); + cluster_status(&data_set); dc = data_set.dc_node; fprintf(stream, ""); fprintf(stream, ""); fprintf(stream, "Cluster status"); /* content="%d;url=http://webdesign.about.com" */ fprintf(stream, "", interval); fprintf(stream, ""); /*** SUMMARY ***/ fprintf(stream, "

Cluster summary

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

Config Options

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

Node List

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

(Partially) Inactive Resources

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

Resource List

\n"); } if(group_by_node == FALSE || inactive_resources) { slist_iter(rsc, resource_t, data_set.resources, lpc2, if(group_by_node && rsc->fns->active(rsc, TRUE)) { continue; } rsc->fns->print(rsc, NULL, pe_print_html, stream); ); } data_set.input = NULL; cleanup_calculations(&data_set); fprintf(stream, ""); fflush(stream); fclose(stream); if(rename(filename_tmp, filename) != 0) { cl_perror("Unable to rename %s->%s", filename_tmp, filename); } crm_free(filename_tmp); return 0; } void blank_screen(void) { #if CURSES_ENABLED int lpc = 0; for(lpc = 0; lpc < LINES; lpc++) { move(lpc, 0); clrtoeol(); } move(0, 0); #endif } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-%s]\n", cmd, OPTARGS); fprintf(stream, "\t--%s (-%c) \t: This text\n", "help", '?'); fprintf(stream, "\t--%s (-%c) \t: Increase the debug output\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c) \t: Update frequency\n", "interval", 'i'); fprintf(stream, "\t--%s (-%c) \t:Group resources by node\n", "group-by-node", 'n'); fprintf(stream, "\t--%s (-%c) \t:Display inactive resources\n", "inactive", 'r'); fprintf(stream, "\t--%s (-%c) \t: Display cluster status on the console\n", "as-console", 'c'); fprintf(stream, "\t--%s (-%c) \t: Display the cluster status once on " "the console and exit (doesnt use ncurses)\n", "one-shot", '1'); fprintf(stream, "\t--%s (-%c) \t: Write cluster status to the named file\n", "as-html", 'h'); fprintf(stream, "\t--%s (-%c) \t: Run in the background as a daemon\n", "daemonize", 'd'); fprintf(stream, "\t--%s (-%c) \t: Daemon pid file location\n", "pid-file", 'p'); fflush(stream); exit(exit_status); } void make_daemon(gboolean daemonize, const char *pidfile) { long pid; const char *devnull = "/dev/null"; if (daemonize == FALSE){ return; } pid = fork(); if (pid < 0) { fprintf(stderr, "%s: could not start daemon\n", crm_system_name); perror("fork"); exit(LSB_EXIT_GENERIC); } else if (pid > 0) { exit(LSB_EXIT_OK); } if (cl_lock_pidfile(pidfile) < 0 ){ pid = cl_read_pidfile(pidfile); fprintf(stderr, "%s: already running [pid %ld].\n", crm_system_name, pid); exit(LSB_EXIT_OK); } umask(022); close(FD_STDIN); (void)open(devnull, O_RDONLY); /* Stdin: fd 0 */ close(FD_STDOUT); (void)open(devnull, O_WRONLY); /* Stdout: fd 1 */ close(FD_STDERR); (void)open(devnull, O_WRONLY); /* Stderr: fd 2 */ } diff --git a/crm/admin/crm_resource.c b/crm/admin/crm_resource.c index 858c70f155..8e7712372d 100644 --- a/crm/admin/crm_resource.c +++ b/crm/admin/crm_resource.c @@ -1,1035 +1,1035 @@ -/* $Id: crm_resource.c,v 1.34 2006/06/06 06:17:53 andrew Exp $ */ +/* $Id: crm_resource.c,v 1.35 2006/06/07 12:46:57 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 #ifdef HAVE_GETOPT_H # include #endif #include void usage(const char *cmd, int exit_status); gboolean do_force = FALSE; gboolean BE_QUIET = FALSE; char *host_id = NULL; const char *rsc_id = NULL; const char *host_uname = NULL; const char *crm_system_name = NULL; const char *prop_name = NULL; const char *prop_value = NULL; const char *rsc_type = NULL; const char *prop_id = NULL; const char *prop_set = NULL; char rsc_cmd = 'L'; char *our_pid = NULL; IPC_Channel *crmd_channel = NULL; #define OPTARGS "V?LRQXDCPp:WMUr:H:v:t:p:g:d:i:s:G:S:f" static int do_find_resource(const char *rsc, pe_working_set_t *data_set) { int found = 0; resource_t *the_rsc = pe_find_resource(data_set->resources, rsc); if(the_rsc == NULL) { return cib_NOTEXISTS; } slist_iter(node, node_t, the_rsc->running_on, lpc, crm_debug_3("resource %s is running on: %s", rsc, node->details->uname); if(BE_QUIET) { fprintf(stdout, "%s\n ", node->details->uname); } else { fprintf(stdout, "resource %s is running on: %s\n", rsc, node->details->uname); } found++; ); if(BE_QUIET == FALSE && found == 0) { fprintf(stderr, "resource %s is NOT running\n", rsc); } return 0; } static int do_find_resource_list(pe_working_set_t *data_set) { int found = 0; slist_iter( rsc, resource_t, data_set->resources, lpc, if(rsc->orphan && rsc->fns->active(rsc, TRUE) == FALSE) { continue; } rsc->fns->print( rsc, NULL, pe_print_printf|pe_print_rsconly, stdout); found++; ); if(found == 0) { printf("NO resources configured\n"); return cib_NOTEXISTS; } return 0; } static int dump_resource(const char *rsc, pe_working_set_t *data_set) { char *rsc_xml = NULL; resource_t *the_rsc = pe_find_resource(data_set->resources, rsc); if(the_rsc == NULL) { return cib_NOTEXISTS; } the_rsc->fns->print(the_rsc, NULL, pe_print_printf, stdout); rsc_xml = dump_xml_formatted(the_rsc->xml); fprintf(stdout, "raw xml:\n%s", rsc_xml); crm_free(rsc_xml); return 0; } static int dump_resource_attr( const char *rsc, const char *attr, pe_working_set_t *data_set) { node_t *current = NULL; resource_t *the_rsc = pe_find_resource(data_set->resources, rsc); const char *value = NULL; if(the_rsc == NULL) { return cib_NOTEXISTS; } if(g_list_length(the_rsc->running_on) == 1) { current = the_rsc->running_on->data; } else if(g_list_length(the_rsc->running_on) > 1) { fprintf(stderr, "%s is active on more than one node," " returning the default value for %s\n", the_rsc->id, value); } unpack_instance_attributes( - the_rsc->xml, XML_TAG_ATTR_SETS, current, the_rsc->parameters, - NULL, 0, data_set); + the_rsc->xml, XML_TAG_ATTR_SETS, current->details->attrs, + the_rsc->parameters, NULL, data_set->now); if(the_rsc->parameters != NULL) { crm_debug("Looking up %s in %s", attr, the_rsc->id); value = g_hash_table_lookup(the_rsc->parameters, attr); } if(value != NULL) { fprintf(stdout, "%s\n", value); return 0; } return cib_NOTEXISTS; } static int set_resource_attr(const char *rsc_id, const char *attr_set, const char *attr_id, const char *attr_name, const char *attr_value, cib_t *cib, pe_working_set_t *data_set) { int rc = cib_ok; int cib_options = cib_sync_call; crm_data_t *xml_top = NULL; crm_data_t *xml_obj = NULL; resource_t *rsc = pe_find_resource(data_set->resources, rsc_id); char *local_attr_id = NULL; char *local_attr_set = NULL; if(do_force) { crm_debug("Forcing..."); cib_options |= cib_scope_local|cib_quorum_override; } if(rsc == NULL) { return cib_NOTEXISTS; } if(attr_set == NULL) { local_attr_set = crm_strdup(rsc->id); attr_set = local_attr_set; } if(attr_id == NULL) { local_attr_id = crm_concat(attr_set, attr_name, '-'); attr_id = local_attr_id; } xml_top = create_xml_node(NULL, crm_element_name(rsc->xml)); crm_xml_add(xml_top, XML_ATTR_ID, rsc->id); xml_obj = create_xml_node(xml_top, XML_TAG_ATTR_SETS); crm_xml_add(xml_obj, XML_ATTR_ID, attr_set); xml_obj = create_xml_node(xml_obj, XML_TAG_ATTRS); xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_NVPAIR); crm_xml_add(xml_obj, XML_ATTR_ID, attr_id); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, attr_value); crm_log_xml_debug(xml_top, "Update"); rc = cib->cmds->modify(cib, XML_CIB_TAG_RESOURCES, xml_top, NULL, cib_options); free_xml(xml_top); crm_free(local_attr_id); crm_free(local_attr_set); return rc; } static int delete_resource_attr( const char *rsc_id, const char *attr_set, const char *attr_id, const char *attr_name, cib_t *cib, pe_working_set_t *data_set) { int rc = cib_ok; int cib_options = cib_sync_call; crm_data_t *xml_obj = NULL; resource_t *rsc = pe_find_resource(data_set->resources, rsc_id); char *local_attr_id = NULL; char *local_attr_set = NULL; if(do_force) { crm_debug("Forcing..."); cib_options |= cib_scope_local|cib_quorum_override; } if(rsc == NULL) { return cib_NOTEXISTS; } if(attr_set == NULL) { local_attr_set = crm_strdup(rsc->id); attr_set = local_attr_set; } if(attr_id == NULL) { local_attr_id = crm_concat(attr_set, attr_name, '-'); attr_id = local_attr_id; } xml_obj = create_xml_node(NULL, XML_CIB_TAG_NVPAIR); crm_xml_add(xml_obj, XML_ATTR_ID, attr_id); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name); crm_log_xml_debug(xml_obj, "Delete"); rc = cib->cmds->delete(cib, XML_CIB_TAG_RESOURCES, xml_obj, NULL, cib_options); crm_free(local_attr_id); crm_free(local_attr_set); free_xml(xml_obj); return rc; } static int dump_resource_prop( const char *rsc, const char *attr, pe_working_set_t *data_set) { const char *value = NULL; resource_t *the_rsc = pe_find_resource(data_set->resources, rsc); if(the_rsc == NULL) { return cib_NOTEXISTS; } value = crm_element_value(the_rsc->xml, attr); if(value != NULL) { fprintf(stdout, "%s\n", value); return 0; } return cib_NOTEXISTS; } static void resource_ipc_connection_destroy(gpointer user_data) { crm_info("Connection to CRMd was terminated"); exit(1); } static gboolean crmd_msg_callback(IPC_Channel * server, void *private_data) { int lpc = 0; IPC_Message *msg = NULL; ha_msg_input_t *new_input = NULL; gboolean hack_return_good = TRUE; while (server->ch_status != IPC_DISCONNECT && server->ops->is_message_pending(server) == TRUE) { if(new_input != NULL) { delete_ha_msg_input(new_input); } if (server->ops->recv(server, &msg) != IPC_OK) { perror("Receive failure:"); return !hack_return_good; } if (msg == NULL) { crm_debug_4("No message this time"); continue; } lpc++; new_input = new_ipc_msg_input(msg); crm_log_message(LOG_MSG, new_input->msg); msg->msg_done(msg); if (validate_crm_message( new_input->msg, crm_system_name, our_pid, XML_ATTR_RESPONSE) == FALSE) { crm_info("Message was not a CRM response. Discarding."); continue; } /* result = cl_get_string(new_input->msg, XML_ATTR_RESULT); */ /* if(result == NULL || strcasecmp(result, "ok") == 0) { */ /* result = "pass"; */ /* } else { */ /* result = "fail"; */ /* } */ } if (server->ch_status == IPC_DISCONNECT) { crm_debug_2("admin_msg_callback: received HUP"); return !hack_return_good; } return hack_return_good; } static int delete_lrm_rsc( IPC_Channel *crmd_channel, const char *host_uname, const char *rsc_id, const char *rsc_long_id) { HA_Message *cmd = NULL; crm_data_t *msg_data = NULL; crm_data_t *rsc = NULL; HA_Message *params = NULL; char *key = crm_concat(crm_system_name, our_pid, '-'); CRM_DEV_ASSERT(rsc_id != NULL); msg_data = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP); crm_xml_add(msg_data, XML_ATTR_TRANSITION_KEY, key); rsc = create_xml_node(msg_data, XML_CIB_TAG_RESOURCE); crm_xml_add(rsc, XML_ATTR_ID, rsc_id); crm_xml_add(rsc, XML_ATTR_ID_LONG, rsc_long_id); params = create_xml_node(msg_data, XML_TAG_ATTRS); crm_xml_add(params, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET); cmd = create_request(CRM_OP_LRM_DELETE, msg_data, host_uname, CRM_SYSTEM_CRMD, crm_system_name, our_pid); free_xml(msg_data); crm_free(key); if(send_ipc_message(crmd_channel, cmd)) { return 0; } return cib_send_failed; } static int refresh_lrm(IPC_Channel *crmd_channel, const char *host_uname) { HA_Message *cmd = NULL; cmd = create_request(CRM_OP_LRM_REFRESH, NULL, host_uname, CRM_SYSTEM_CRMD, crm_system_name, our_pid); if(send_ipc_message(crmd_channel, cmd)) { return 0; } return cib_send_failed; } static int migrate_resource( const char *rsc_id, const char *existing_node, const char *preferred_node, cib_t * cib_conn) { enum cib_errors rc = cib_ok; char *id = NULL; crm_data_t *cib = NULL; crm_data_t *rule = NULL; crm_data_t *expr = NULL; crm_data_t *constraints = NULL; crm_data_t *fragment = NULL; crm_data_t *can_run = NULL; crm_data_t *dont_run = NULL; fragment = create_cib_fragment(NULL, NULL); cib = fragment; CRM_DEV_ASSERT(safe_str_eq(crm_element_name(cib), XML_TAG_CIB)); constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); id = crm_concat("cli-prefer", rsc_id, '-'); can_run = create_xml_node(constraints, XML_CONS_TAG_RSC_LOCATION); crm_xml_add(can_run, XML_ATTR_ID, id); crm_free(id); id = crm_concat("cli-standby", rsc_id, '-'); dont_run = create_xml_node(constraints, XML_CONS_TAG_RSC_LOCATION); crm_xml_add(dont_run, XML_ATTR_ID, id); crm_free(id); if(existing_node == NULL) { crm_log_xml_notice(can_run, "Deleting"); rc = cib_conn->cmds->delete(cib_conn, XML_CIB_TAG_CONSTRAINTS, dont_run, NULL, cib_sync_call); if(rc == cib_NOTEXISTS) { rc = cib_ok; } else if(rc != cib_ok) { return rc; } } else { if(BE_QUIET == FALSE) { fprintf(stderr, "WARNING: Creating rsc_location constraint '%s'" " with a score of -INFINITY for resource %s" " on %s.\n", ID(dont_run), rsc_id, existing_node); fprintf(stderr, "\tThis will prevent %s from running" " on %s until the constraint is removed using" " the 'crm_resource -U' command or manually" " with cibadmin\n", rsc_id, existing_node); fprintf(stderr, "\tThis will be the case even if %s is" " the last node in the cluster\n", existing_node); fprintf(stderr, "\tThis messgae can be disabled with -S\n"); } crm_xml_add(dont_run, "rsc", rsc_id); rule = create_xml_node(dont_run, XML_TAG_RULE); expr = create_xml_node(rule, XML_TAG_EXPRESSION); id = crm_concat("cli-standby-rule", rsc_id, '-'); crm_xml_add(rule, XML_ATTR_ID, id); crm_free(id); crm_xml_add(rule, XML_RULE_ATTR_SCORE, MINUS_INFINITY_S); id = crm_concat("cli-standby-expr", rsc_id, '-'); crm_xml_add(expr, XML_ATTR_ID, id); crm_free(id); crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, "#uname"); crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq"); crm_xml_add(expr, XML_EXPR_ATTR_VALUE, existing_node); crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string"); } if(preferred_node == NULL) { crm_log_xml_notice(can_run, "Deleting"); rc = cib_conn->cmds->delete(cib_conn, XML_CIB_TAG_CONSTRAINTS, can_run, NULL, cib_sync_call); if(rc == cib_NOTEXISTS) { rc = cib_ok; } else if(rc != cib_ok) { return rc; } } else { crm_xml_add(can_run, "rsc", rsc_id); rule = create_xml_node(can_run, XML_TAG_RULE); expr = create_xml_node(rule, XML_TAG_EXPRESSION); id = crm_concat("cli-prefer-rule", rsc_id, '-'); crm_xml_add(rule, XML_ATTR_ID, id); crm_free(id); crm_xml_add(rule, XML_RULE_ATTR_SCORE, INFINITY_S); id = crm_concat("cli-prefer-expr", rsc_id, '-'); crm_xml_add(expr, XML_ATTR_ID, id); crm_free(id); crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, "#uname"); crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq"); crm_xml_add(expr, XML_EXPR_ATTR_VALUE, preferred_node); crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string"); } if(preferred_node != NULL || existing_node != NULL) { crm_log_xml_notice(fragment, "CLI Update"); rc = cib_conn->cmds->update(cib_conn, XML_CIB_TAG_CONSTRAINTS, fragment, NULL, cib_sync_call); } free_xml(fragment); return rc; } int main(int argc, char **argv) { pe_working_set_t data_set; crm_data_t *cib_xml_copy = NULL; cib_t * cib_conn = NULL; enum cib_errors rc = cib_ok; int argerr = 0; int flag; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"quiet", 0, 0, 'Q'}, {"list", 0, 0, 'L'}, {"refresh", 0, 0, 'R'}, {"reprobe", 0, 0, 'P'}, {"query-xml", 0, 0, 'X'}, {"delete", 0, 0, 'D'}, {"cleanup", 0, 0, 'C'}, {"locate", 0, 0, 'W'}, {"migrate", 0, 0, 'M'}, {"un-migrate", 0, 0, 'U'}, {"resource", 1, 0, 'r'}, {"host-uname", 1, 0, 'H'}, {"host-uuid", 1, 0, 'h'}, {"force", 0, 0, 'f'}, {"set-parameter", 1, 0, 'p'}, {"get-parameter", 1, 0, 'g'}, {"delete-parameter",1, 0, 'd'}, {"property-value", 1, 0, 'v'}, {"get-property", 1, 0, 'G'}, {"set-property", 1, 0, 'S'}, {"resource-type", 1, 0, 't'}, {0, 0, 0, 0} }; #endif crm_system_name = basename(argv[0]); crm_log_init(crm_system_name); crm_log_level = LOG_ERR; cl_log_enable_stderr(TRUE); if(argc < 2) { usage(crm_system_name, LSB_EXIT_EINVAL); } while (1) { #ifdef HAVE_GETOPT_H flag = getopt_long(argc, argv, OPTARGS, long_options, &option_index); #else flag = getopt(argc, argv, OPTARGS); #endif if (flag == -1) break; switch(flag) { case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case '?': usage(crm_system_name, LSB_EXIT_OK); break; case 'Q': BE_QUIET = TRUE; break; case 'L': rsc_cmd = flag; break; case 'R': rsc_cmd = flag; break; case 'X': rsc_cmd = flag; break; case 'D': rsc_cmd = flag; break; case 'C': rsc_cmd = flag; break; case 'P': rsc_cmd = flag; break; case 'p': crm_debug_2("Option %c => %s", flag, optarg); prop_name = optarg; rsc_cmd = flag; break; case 'g': crm_debug_2("Option %c => %s", flag, optarg); prop_name = optarg; rsc_cmd = flag; break; case 'd': crm_debug_2("Option %c => %s", flag, optarg); prop_name = optarg; rsc_cmd = flag; break; case 'S': crm_debug_2("Option %c => %s", flag, optarg); prop_name = optarg; rsc_cmd = flag; break; case 'G': crm_debug_2("Option %c => %s", flag, optarg); prop_name = optarg; rsc_cmd = flag; break; case 'W': rsc_cmd = flag; break; case 'M': rsc_cmd = flag; break; case 'U': rsc_cmd = flag; break; case 'f': do_force = TRUE; break; case 'i': crm_debug_2("Option %c => %s", flag, optarg); prop_id = optarg; break; case 's': crm_debug_2("Option %c => %s", flag, optarg); prop_set = optarg; break; case 'r': crm_debug_2("Option %c => %s", flag, optarg); rsc_id = optarg; break; case 'v': crm_debug_2("Option %c => %s", flag, optarg); prop_value = optarg; break; case 't': crm_debug_2("Option %c => %s", flag, optarg); rsc_type = optarg; break; case 'H': crm_debug_2("Option %c => %s", flag, optarg); host_uname = optarg; break; case 'h': crm_debug_2("Option %c => %s", flag, optarg); host_id = crm_strdup(optarg); break; default: fprintf(stderr, "Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag); ++argerr; break; } } if (optind < argc) { fprintf(stderr, "non-option ARGV-elements: "); while (optind < argc) { fprintf(stderr, "%s ", argv[optind++]); } fprintf(stderr, "\n"); } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } crm_malloc0(our_pid, 11); if(our_pid != NULL) { snprintf(our_pid, 10, "%d", getpid()); our_pid[10] = '\0'; } if(rsc_cmd == 'L' || rsc_cmd == 'W' || rsc_cmd == 'D' || rsc_cmd == 'X' || rsc_cmd == 'M' || rsc_cmd == 'U' || rsc_cmd == 'C' || rsc_cmd == 'p' || rsc_cmd == 'd' || rsc_cmd == 'g' || rsc_cmd == 'G' || rsc_cmd == 'S') { resource_t *rsc = NULL; cib_conn = cib_new(); rc = cib_conn->cmds->signon( cib_conn, crm_system_name, cib_command_synchronous); if(rc != cib_ok) { fprintf(stderr, "Error signing on to the CIB service: %s\n", cib_error2string(rc)); return rc; } cib_xml_copy = get_cib_copy(cib_conn); set_working_set_defaults(&data_set); data_set.input = cib_xml_copy; data_set.now = new_ha_date(TRUE); - stage0(&data_set); + cluster_status(&data_set); rsc = pe_find_resource(data_set.resources, rsc_id); if(rsc != NULL) { rsc_id = rsc->id; } else { rc = cib_NOTEXISTS; } } if(rsc_cmd == 'R' || rsc_cmd == 'C' || rsc_cmd == 'P') { GCHSource *src = NULL; src = init_client_ipc_comms(CRM_SYSTEM_CRMD, crmd_msg_callback, NULL, &crmd_channel); if(src == NULL) { fprintf(stderr, "Error signing on to the CRMd service\n"); return 1; } send_hello_message( crmd_channel, our_pid, crm_system_name, "0", "1"); set_IPC_Channel_dnotify(src, resource_ipc_connection_destroy); } if(rsc_cmd == 'L') { rc = cib_ok; do_find_resource_list(&data_set); } else if(rsc_cmd == 'C') { resource_t *rsc = pe_find_resource(data_set.resources, rsc_id); delete_lrm_rsc(crmd_channel, host_uname, rsc?rsc->id:rsc_id, rsc?rsc->long_name:NULL); sleep(5); refresh_lrm(crmd_channel, host_uname); if(rsc != NULL) { char *now_s = NULL; time_t now = time(NULL); /* force the TE to start a transition */ sleep(5); /* wait for the refresh */ now_s = crm_itoa(now); update_attr(cib_conn, cib_sync_call, NULL, NULL, NULL, NULL, "last-lrm-refresh", now_s); crm_free(now_s); } } else if(rc == cib_NOTEXISTS) { fprintf(stderr, "Resource %s not found: %s\n", crm_str(rsc_id), cib_error2string(rc)); } else if(rsc_cmd == 'W') { CRM_DEV_ASSERT(rsc_id != NULL); rc = do_find_resource(rsc_id, &data_set); } else if(rsc_cmd == 'X') { CRM_DEV_ASSERT(rsc_id != NULL); rc = dump_resource(rsc_id, &data_set); } else if(rsc_cmd == 'U') { rc = migrate_resource(rsc_id, NULL, NULL, cib_conn); } else if(rsc_cmd == 'M') { const char *current_uname = NULL; resource_t *rsc = pe_find_resource(data_set.resources, rsc_id); if(rsc != NULL && rsc->running_on != NULL) { node_t *current = rsc->running_on->data; if(current != NULL) { current_uname = current->details->uname; } } if(rsc == NULL) { fprintf(stderr, "Resource %s not migrated:" " not found\n", rsc_id); } else if(g_list_length(rsc->running_on) > 1) { fprintf(stderr, "Resource %s not migrated:" " active on multiple nodes\n", rsc_id); } else if(host_uname != NULL && safe_str_eq(current_uname, host_uname)) { fprintf(stderr, "Error performing operation: " "%s is already active on %s", rsc_id, host_uname); } else if(current_uname != NULL && (do_force || host_uname == NULL)) { rc = migrate_resource(rsc_id, current_uname, host_uname, cib_conn); } else if(host_uname != NULL) { rc = migrate_resource( rsc_id, NULL, host_uname, cib_conn); } else { fprintf(stderr, "Resource %s not migrated: " "not-active and no prefered location" " specified.\n", rsc_id); } } else if(rsc_cmd == 'G') { CRM_DEV_ASSERT(rsc_id != NULL); rc = dump_resource_prop(rsc_id, prop_name, &data_set); } else if(rsc_cmd == 'S') { crm_data_t *msg_data = NULL; if(prop_value == NULL) { fprintf(stderr, "You need to supply a value with the -v option\n"); return CIBRES_MISSING_FIELD; } CRM_DEV_ASSERT(rsc_id != NULL); CRM_DEV_ASSERT(rsc_type != NULL); CRM_DEV_ASSERT(prop_name != NULL); CRM_DEV_ASSERT(prop_value != NULL); msg_data = create_xml_node(NULL, rsc_type); crm_xml_add(msg_data, XML_ATTR_ID, rsc_id); crm_xml_add(msg_data, prop_name, prop_value); rc = cib_conn->cmds->modify(cib_conn, XML_CIB_TAG_RESOURCES, msg_data, NULL, cib_sync_call); free_xml(msg_data); } else if(rsc_cmd == 'g') { CRM_DEV_ASSERT(rsc_id != NULL); rc = dump_resource_attr(rsc_id, prop_name, &data_set); } else if(rsc_cmd == 'p') { CRM_DEV_ASSERT(rsc_id != NULL); if(prop_value == NULL) { fprintf(stderr, "You need to supply a value with the -v option\n"); return CIBRES_MISSING_FIELD; } rc = set_resource_attr(rsc_id, prop_set, prop_id, prop_name, prop_value, cib_conn, &data_set); } else if(rsc_cmd == 'd') { CRM_DEV_ASSERT(rsc_id != NULL); rc = delete_resource_attr(rsc_id, prop_id, prop_set, prop_name, cib_conn, &data_set); } else if(rsc_cmd == 'P') { HA_Message *cmd = NULL; cmd = create_request(CRM_OP_REPROBE, NULL, host_uname, CRM_SYSTEM_CRMD, crm_system_name, our_pid); send_ipc_message(crmd_channel, cmd); } else if(rsc_cmd == 'R') { refresh_lrm(crmd_channel, host_uname); } else if(rsc_cmd == 'D') { crm_data_t *msg_data = NULL; int cib_options = cib_sync_call; CRM_CHECK(rsc_id != NULL, return cib_NOTEXISTS); if(rsc_type == NULL) { fprintf(stderr, "You need to specify a resource type with -t"); return cib_NOTEXISTS; } if(do_force) { cib_options |= cib_scope_local|cib_quorum_override; } msg_data = create_xml_node(NULL, rsc_type); crm_xml_add(msg_data, XML_ATTR_ID, rsc_id); rc = cib_conn->cmds->delete(cib_conn, XML_CIB_TAG_RESOURCES, msg_data, NULL, cib_options); free_xml(msg_data); } else { fprintf(stderr, "Unknown command: %c\n", rsc_cmd); } if(cib_conn != NULL) { cleanup_calculations(&data_set); cib_conn->cmds->signoff(cib_conn); } if(rc == cib_no_quorum) { fprintf(stderr, "Error performing operation: %s\n", cib_error2string(rc)); fprintf(stderr, "Try using -f\n"); } else if(rc != cib_ok) { fprintf(stderr, "Error performing operation: %s\n", cib_error2string(rc)); } return rc; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-?VS] -(L|Q|W|D|C|P|p) [options]\n", cmd); fprintf(stream, "\t--%s (-%c)\t: this help message\n", "help", '?'); fprintf(stream, "\t--%s (-%c)\t: " "turn on debug info. additional instances increase verbosity\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c)\t: Print only the value on stdout (for use with -W)\n", "quiet", 'Q'); fprintf(stream, "\nCommands\n"); fprintf(stream, "\t--%s (-%c)\t: List all resources\n", "list", 'L'); fprintf(stream, "\t--%s (-%c)\t: Query a resource\n" "\t\t\t Requires: -r\n", "query-xml", 'X'); fprintf(stream, "\t--%s (-%c)\t: Locate a resource\n" "\t\t\t Requires: -r\n", "locate", 'W'); fprintf(stream, "\t--%s (-%c)\t: Migrate a resource from it current" " location. Use -H to specify a destination\n" "\t\tIf -H is not specified, we will force the resource to move by" " creating a rule for the current location and a score of -INFINITY\n" "\t\tNOTE: This will prevent the resource from running on this" " node until the constraint is removed with -U\n" "\t\t\t Requires: -r, Optional: -H, -f\n", "migrate", 'M'); fprintf(stream, "\t--%s (-%c)\t: Remove all constraints created by -M\n" "\t\t\t Requires: -r\n", "un-migrate", 'U'); fprintf(stream, "\t--%s (-%c)\t: Delete a resource from the CIB\n" "\t\t\t Requires: -r, -t\n", "delete", 'D'); fprintf(stream, "\t--%s (-%c)\t: Delete a resource from the LRM\n" "\t\t\t Requires: -r. Optional: -H\n", "cleanup", 'C'); fprintf(stream, "\t--%s (-%c)\t: Recheck for resources started outside of the CRM\n" "\t\t\t Optional: -H\n", "reprobe", 'P'); fprintf(stream, "\t--%s (-%c)\t: Refresh the CIB from the LRM\n" "\t\t\t Optional: -H\n", "refresh", 'R'); fprintf(stream, "\t--%s (-%c) \t: " "Set the named parameter for a resource\n" "\t\t\t Requires: -r, -v. Optional: -i, -s\n", "set-parameter", 'p'); fprintf(stream, "\t--%s (-%c) \t: " "Get the named parameter for a resource\n" "\t\t\t Requires: -r. Optional: -i, -s\n", "get-parameter", 'g'); fprintf(stream, "\t--%s (-%c) : " "Delete the named parameter for a resource\n" "\t\t\t Requires: -r. Optional: -i\n", "delete-parameter", 'd'); fprintf(stream, "\t--%s (-%c) \t: " "Get the named property (eg. class, type, is_managed) a resource\n" "\t\t\t Requires: -r\n", "get-property", 'G'); fprintf(stream, "\t--%s (-%c) \t: " "Set the named property (not parameter) for a resource\n" "\t\t\t Requires: -r, -t, -v", "set-property", 'S'); fprintf(stream, "\nOptions\n"); fprintf(stream, "\t--%s (-%c) \t: Resource ID\n", "resource", 'r'); fprintf(stream, "\t--%s (-%c) \t: " "Resource type (primitive, clone, group, ...)\n", "resource-type", 't'); fprintf(stream, "\t--%s (-%c) \t: " "Property value\n", "property-value", 'v'); fprintf(stream, "\t--%s (-%c) \t: " "Host name\n", "host-uname", 'H'); fprintf(stream, "\t--%s (-%c)\t: " "Force the resource to move by creating a rule for the" " current location and a score of -INFINITY\n" "\t\tThis should be used if the resource's stickiness and" " constraint scores total more than INFINITY (Currently 10,000)\n" "\t\tNOTE: This will prevent the resource from running on this" " node until the constraint is removed with -U\n", "force-relocation", 'f'); fprintf(stream, "\t-%c \t: (Advanced Use Only) ID of the instance_attributes object to change\n", 's'); fprintf(stream, "\t-%c \t: (Advanced Use Only) ID of the nvpair object to change/delete\n", 'i'); fflush(stream); exit(exit_status); } diff --git a/crm/admin/crm_verify.c b/crm/admin/crm_verify.c index 130205b1a1..44fb5dd7d5 100644 --- a/crm/admin/crm_verify.c +++ b/crm/admin/crm_verify.c @@ -1,287 +1,286 @@ -/* $Id: crm_verify.c,v 1.11 2006/05/15 10:21:05 andrew Exp $ */ +/* $Id: crm_verify.c,v 1.12 2006/06/07 12:46:57 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 #define OPTARGS "V?X:LS:" #ifdef HAVE_GETOPT_H # include #endif #include -#include -#include +#include gboolean USE_LIVE_CIB = FALSE; char *cib_save = NULL; const char *crm_system_name = NULL; void usage(const char *cmd, int exit_status); -extern void cleanup_calculations(pe_working_set_t *data_set); +extern gboolean stage0(pe_working_set_t *data_set); int main(int argc, char **argv) { crm_data_t *cib_object = NULL; crm_data_t *status = NULL; int argerr = 0; int flag; pe_working_set_t data_set; cib_t * cib_conn = NULL; enum cib_errors rc = cib_ok; const char *xml_file = NULL; crm_system_name = basename(argv[0]); g_log_set_handler(NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG | G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL, cl_glib_msg_handler, NULL); /* and for good measure... - this enum is a bit field (!) */ g_log_set_always_fatal((GLogLevelFlags)0); /*value out of range*/ cl_log_set_entity(crm_system_name); cl_log_set_facility(LOG_LOCAL7); cl_log_enable_stderr(TRUE); set_crm_log_level(LOG_ERR); CL_SIGNAL(DEBUG_INC, alter_debug); CL_SIGNAL(DEBUG_DEC, alter_debug); while (1) { #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {"xml-file", 1, 0, 'X'}, {"save-xml", 1, 0, 'S'}, {"live-check", 0, 0, 'L'}, {"help", 0, 0, '?'}, {0, 0, 0, 0} }; #endif #ifdef HAVE_GETOPT_H flag = getopt_long(argc, argv, OPTARGS, long_options, &option_index); #else flag = getopt(argc, argv, OPTARGS); #endif if (flag == -1) break; switch(flag) { #ifdef HAVE_GETOPT_H case 0: printf("option %s", long_options[option_index].name); if (optarg) printf(" with arg %s", optarg); printf("\n"); break; #endif case 'X': xml_file = crm_strdup(optarg); break; case 'S': cib_save = crm_strdup(optarg); break; case 'V': alter_debug(DEBUG_INC); break; case 'L': USE_LIVE_CIB = TRUE; break; case '?': usage(crm_system_name, LSB_EXIT_GENERIC); break; default: printf("?? getopt returned character code 0%o ??\n", flag); ++argerr; break; } } if (optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) { printf("%s ", argv[optind++]); } printf("\n"); } if (optind > argc) { ++argerr; } if (argerr) { crm_err("%d errors in option parsing", argerr); usage(crm_system_name, LSB_EXIT_GENERIC); } crm_info("=#=#=#=#= Getting XML =#=#=#=#="); if(USE_LIVE_CIB) { cib_conn = cib_new(); rc = cib_conn->cmds->signon( cib_conn, crm_system_name, cib_command_synchronous); } crm_zero_mem_stats(NULL); if(USE_LIVE_CIB) { if(rc == cib_ok) { int options = cib_scope_local|cib_sync_call; crm_info("Reading XML from: live cluster"); rc = cib_conn->cmds->query( cib_conn, NULL, &cib_object, options); } if(rc != cib_ok) { fprintf(stderr, "Live CIB query failed: %s\n", cib_error2string(rc)); return 3; } if(cib_object == NULL) { fprintf(stderr, "Live CIB query failed: empty result\n"); return 3; } } else if(xml_file != NULL) { FILE *xml_strm = fopen(xml_file, "r"); crm_info("Reading XML from: %s", xml_file); cib_object = file2xml(xml_strm); } else { fprintf(stderr, "Reading XML from: stdin"); cib_object = stdin2xml(); } CRM_CHECK(cib_object != NULL, fprintf(stderr, "No config supplied\n"); return 3; ); if(cib_save != NULL) { write_xml_file(cib_object, cib_save, FALSE); } status = get_object_root(XML_CIB_TAG_STATUS, cib_object); #if CRM_DEPRECATED_SINCE_2_0_4 xml_child_iter_filter(status, node_state, XML_CIB_TAG_STATE, xml_remove_prop(node_state, XML_CIB_TAG_LRM); ); #endif crm_notice("Required feature set: %s", feature_set(cib_object)); if(do_id_check(cib_object, NULL, FALSE, FALSE)) { pe_config_err("ID Check failed"); } if(validate_with_dtd(cib_object, HA_LIBDIR"/heartbeat/crm.dtd") == FALSE) { pe_config_err("CIB did not pass DTD validation"); } set_working_set_defaults(&data_set); data_set.input = cib_object; data_set.now = new_ha_date(TRUE); stage0(&data_set); cleanup_calculations(&data_set); if(USE_LIVE_CIB) { /* Calling msg2ipcchan() seems to initialize something * which isn't free'd when we disconnect and free the * CIB connection. * Fake this extra free and move along. */ volatile cl_mem_stats_t *active_stats = cl_malloc_getstats(); active_stats->numfree++; } CRM_CHECK(crm_mem_stats(NULL) == FALSE, ; ); if(was_config_error) { fprintf(stderr, "Errors found during check: config not valid\n"); if(crm_log_level < LOG_WARNING) { fprintf(stderr, " -V may provide more details\n"); } return 2; } else if(was_config_warning) { fprintf(stderr, "Warnings found during check: config may not be valid\n"); if(crm_log_level < LOG_WARNING) { fprintf(stderr, " Use -V for more details\n"); } return 1; } if(USE_LIVE_CIB) { cib_conn->cmds->signoff(cib_conn); cib_delete(cib_conn); } return 0; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-V] -(?|L|X)\n", cmd); fprintf(stream, "\t--%s (-%c)\t: this help message\n", "help", '?'); fprintf(stream, "\t--%s (-%c)\t: " "turn on debug info. additional instances increase verbosity\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c)\t: Connect to the running cluster\n", "live-check", 'L'); fprintf(stream, "\t--%s (-%c) \t: Use the configuration in the named file\n", "xml-file", 'X'); fflush(stream); exit(exit_status); } diff --git a/crm/admin/crmadmin.c b/crm/admin/crmadmin.c index 099f2a3737..fd1f471076 100644 --- a/crm/admin/crmadmin.c +++ b/crm/admin/crmadmin.c @@ -1,723 +1,721 @@ -/* $Id: crmadmin.c,v 1.72 2006/05/30 12:21:40 andrew Exp $ */ +/* $Id: crmadmin.c,v 1.73 2006/06/07 12:46:57 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 #ifdef HAVE_GETOPT_H # include #endif #include int message_timer_id = -1; int message_timeout_ms = 30*1000; GMainLoop *mainloop = NULL; IPC_Channel *crmd_channel = NULL; char *admin_uuid = NULL; void usage(const char *cmd, int exit_status); ll_cluster_t *do_init(void); int do_work(ll_cluster_t * hb_cluster); void crmd_ipc_connection_destroy(gpointer user_data); gboolean admin_msg_callback(IPC_Channel * source_data, void *private_data); char *pluralSection(const char *a_section); crm_data_t *handleCibMod(void); int do_find_node_list(crm_data_t *xml_node); gboolean admin_message_timeout(gpointer data); gboolean is_node_online(crm_data_t *node_state); enum debug { debug_none, debug_dec, debug_inc }; gboolean BE_VERBOSE = FALSE; int expected_responses = 1; gboolean BASH_EXPORT = FALSE; gboolean DO_HEALTH = FALSE; gboolean DO_RESET = FALSE; gboolean DO_RESOURCE = FALSE; gboolean DO_ELECT_DC = FALSE; gboolean DO_WHOIS_DC = FALSE; gboolean DO_NODE_LIST = FALSE; gboolean BE_SILENT = FALSE; gboolean DO_RESOURCE_LIST = FALSE; enum debug DO_DEBUG = debug_none; const char *crmd_operation = NULL; crm_data_t *msg_options = NULL; const char *standby_on_off = "on"; const char *admin_verbose = XML_BOOLEAN_FALSE; char *id = NULL; char *this_msg_reference = NULL; char *disconnect = NULL; char *dest_node = NULL; char *rsc_name = NULL; char *crm_option = NULL; int operation_status = 0; const char *sys_to = NULL; const char *crm_system_name = NULL; #define OPTARGS "V?K:S:HE:Dd:i:RNqt:B" int main(int argc, char **argv) { int argerr = 0; int flag; ll_cluster_t *hb_cluster = NULL; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"quiet", 0, 0, 'q'}, {"reference", 1, 0, 0}, {XML_ATTR_TIMEOUT, 1, 0, 't'}, {"bash-export", 0, 0, 'B'}, /* daemon options */ {"kill", 1, 0, 'K'}, /* stop a node */ {"die", 0, 0, 0}, /* kill a node, no respawn */ {"debug_inc", 1, 0, 'i'}, {"debug_dec", 1, 0, 'd'}, {"status", 1, 0, 'S'}, {"standby", 1, 0, 's'}, {"active", 1, 0, 'a'}, {"health", 0, 0, 'H'}, {"election", 0, 0, 'E'}, {"dc_lookup", 0, 0, 'D'}, {"nodes", 0, 0, 'N'}, {"option", 1, 0, 'o'}, {0, 0, 0, 0} }; #endif crm_system_name = basename(argv[0]); crm_log_init(crm_system_name); if(argc < 2) { usage(crm_system_name, LSB_EXIT_EINVAL); } while (1) { #ifdef HAVE_GETOPT_H flag = getopt_long(argc, argv, OPTARGS, long_options, &option_index); #else flag = getopt(argc, argv, OPTARGS); #endif if (flag == -1) break; switch(flag) { #ifdef HAVE_GETOPT_H case 0: printf("option %s", long_options[option_index].name); if (optarg) printf(" with arg %s", optarg); printf("\n"); if (strcasecmp("reference", long_options[option_index].name) == 0) { this_msg_reference = crm_strdup(optarg); } else if (strcasecmp("die", long_options[option_index].name) == 0) { DO_RESET = TRUE; crmd_operation = CRM_OP_DIE; } else { printf( "?? Long option (--%s) is not yet properly supported ??\n", long_options[option_index].name); ++argerr; } break; #endif /* a sample test for multiple instance if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); */ case 'V': BE_VERBOSE = TRUE; admin_verbose = XML_BOOLEAN_TRUE; cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case 't': message_timeout_ms = atoi(optarg); if(message_timeout_ms < 1) { message_timeout_ms = 30*1000; } break; case '?': usage(crm_system_name, LSB_EXIT_OK); break; case 'D': DO_WHOIS_DC = TRUE; break; case 'B': BASH_EXPORT = TRUE; break; case 'K': DO_RESET = TRUE; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); crmd_operation = CRM_OP_LOCAL_SHUTDOWN; break; case 'q': BE_SILENT = TRUE; break; case 'i': DO_DEBUG = debug_inc; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 'd': DO_DEBUG = debug_dec; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 'S': DO_HEALTH = TRUE; crm_debug_2("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 'E': DO_ELECT_DC = TRUE; break; case 'N': DO_NODE_LIST = TRUE; break; case 'H': DO_HEALTH = TRUE; break; default: printf("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag); ++argerr; break; } } if (optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) printf("%s ", argv[optind++]); printf("\n"); } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } hb_cluster = do_init(); if (hb_cluster != NULL) { int res = do_work(hb_cluster); if(res == 0) { } else if (res > 0) { /* wait for the reply by creating a mainloop and running it until * the callbacks are invoked... */ mainloop = g_main_new(FALSE); expected_responses++; crm_debug_2("Waiting for %d replies from the local CRM", expected_responses); message_timer_id = Gmain_timeout_add( message_timeout_ms, admin_message_timeout, NULL); g_main_run(mainloop); return_to_orig_privs(); } else { crm_err("No message to send"); operation_status = -1; } } else { crm_warn("Init failed, could not perform requested operations"); operation_status = -2; } crm_debug_2("%s exiting normally", crm_system_name); return operation_status; } int do_work(ll_cluster_t * hb_cluster) { int ret = 1; /* construct the request */ crm_data_t *msg_data = NULL; gboolean all_is_good = TRUE; msg_options = create_xml_node(NULL, XML_TAG_OPTIONS); crm_xml_add(msg_options, XML_ATTR_VERBOSE, admin_verbose); crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0"); if (DO_HEALTH == TRUE) { crm_debug_2("Querying the system"); sys_to = CRM_SYSTEM_DC; if (dest_node != NULL) { sys_to = CRM_SYSTEM_CRMD; crmd_operation = CRM_OP_PING; if (BE_VERBOSE) { expected_responses = 1; } crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0"); } else { crm_info("Cluster-wide health not available yet"); all_is_good = FALSE; } } else if(DO_ELECT_DC) { /* tell the local node to initiate an election */ sys_to = CRM_SYSTEM_CRMD; crmd_operation = CRM_OP_VOTE; crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0"); dest_node = NULL; ret = 0; /* no return message */ } else if(DO_WHOIS_DC) { sys_to = CRM_SYSTEM_DC; crmd_operation = CRM_OP_PING; crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0"); dest_node = NULL; } else if(DO_NODE_LIST) { cib_t * the_cib = cib_new(); crm_data_t *output = NULL; enum cib_errors rc = the_cib->cmds->signon( the_cib, crm_system_name, cib_command_synchronous); if(rc != cib_ok) { return -1; } output = get_cib_copy(the_cib); do_find_node_list(output); free_xml(output); the_cib->cmds->signoff(the_cib); exit(rc); } else if(DO_RESET) { /* tell dest_node to initiate the shutdown proceedure * * if dest_node is NULL, the request will be sent to the * local node */ sys_to = CRM_SYSTEM_CRMD; crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0"); ret = 0; /* no return message */ } else if(DO_DEBUG == debug_inc) { /* tell dest_node to increase its debug level * * if dest_node is NULL, the request will be sent to the * local node */ sys_to = CRM_SYSTEM_CRMD; crmd_operation = CRM_OP_DEBUG_UP; ret = 0; /* no return message */ } else if(DO_DEBUG == debug_dec) { /* tell dest_node to increase its debug level * * if dest_node is NULL, the request will be sent to the * local node */ sys_to = CRM_SYSTEM_CRMD; crmd_operation = CRM_OP_DEBUG_DOWN; ret = 0; /* no return message */ } else { crm_err("Unknown options"); all_is_good = FALSE; } if(all_is_good == FALSE) { crm_err("Creation of request failed. No message to send"); return -1; } /* send it */ if (crmd_channel == NULL) { crm_err("The IPC connection is not valid, cannot send anything"); return -1; } if(sys_to == NULL) { if (dest_node != NULL) { sys_to = CRM_SYSTEM_CRMD; } else { sys_to = CRM_SYSTEM_DC; } } { HA_Message *cmd = create_request( crmd_operation, msg_data, dest_node, sys_to, crm_system_name, admin_uuid); if(this_msg_reference != NULL) { ha_msg_mod(cmd, XML_ATTR_REFERENCE, this_msg_reference); } send_ipc_message(crmd_channel, cmd); } return ret; } void crmd_ipc_connection_destroy(gpointer user_data) { crm_info("Connection to CRMd was terminated"); exit(1); } ll_cluster_t * do_init(void) { int facility; GCHSource *src = NULL; ll_cluster_t *hb_cluster = NULL; /* change the logging facility to the one used by heartbeat daemon */ hb_cluster = ll_cluster_new("heartbeat"); crm_debug_2("Switching to Heartbeat logger"); if (( facility = hb_cluster->llc_ops->get_logfacility(hb_cluster)) > 0) { cl_log_set_facility(facility); } crm_malloc0(admin_uuid, 11); if(admin_uuid != NULL) { snprintf(admin_uuid, 10, "%d", getpid()); admin_uuid[10] = '\0'; } src = init_client_ipc_comms( CRM_SYSTEM_CRMD, admin_msg_callback, NULL, &crmd_channel); if(DO_RESOURCE || DO_RESOURCE_LIST || DO_NODE_LIST) { return hb_cluster; } else if(crmd_channel != NULL) { send_hello_message( crmd_channel, admin_uuid, crm_system_name,"0", "1"); set_IPC_Channel_dnotify(src, crmd_ipc_connection_destroy); return hb_cluster; } return NULL; } gboolean admin_msg_callback(IPC_Channel * server, void *private_data) { int lpc = 0; IPC_Message *msg = NULL; ha_msg_input_t *new_input = NULL; gboolean hack_return_good = TRUE; static int received_responses = 0; char *filename = NULL; int filename_len = 0; const char *result = NULL; Gmain_timeout_remove(message_timer_id); while (server->ch_status != IPC_DISCONNECT && server->ops->is_message_pending(server) == TRUE) { if(new_input != NULL) { delete_ha_msg_input(new_input); } if (server->ops->recv(server, &msg) != IPC_OK) { perror("Receive failure:"); return !hack_return_good; } if (msg == NULL) { crm_debug_4("No message this time"); continue; } lpc++; received_responses++; new_input = new_ipc_msg_input(msg); crm_log_message(LOG_MSG, new_input->msg); msg->msg_done(msg); if (new_input->xml == NULL) { crm_info("XML in IPC message was not valid... " "discarding."); continue; } else if (validate_crm_message( new_input->msg, crm_system_name, admin_uuid, XML_ATTR_RESPONSE) == FALSE) { crm_debug_2("Message was not a CRM response. Discarding."); continue; } result = cl_get_string(new_input->msg, XML_ATTR_RESULT); if(result == NULL || strcasecmp(result, "ok") == 0) { result = "pass"; } else { result = "fail"; } if(DO_HEALTH) { const char *state = crm_element_value( new_input->xml, "crmd_state"); printf("Status of %s@%s: %s (%s)\n", crm_element_value(new_input->xml,XML_PING_ATTR_SYSFROM), cl_get_string(new_input->msg, F_CRM_HOST_FROM), state, crm_element_value(new_input->xml,XML_PING_ATTR_STATUS)); if(BE_SILENT && state != NULL) { fprintf(stderr, "%s\n", state); } } else if(DO_WHOIS_DC) { const char *dc = cl_get_string( new_input->msg, F_CRM_HOST_FROM); printf("Designated Controller is: %s\n", dc); if(BE_SILENT && dc != NULL) { fprintf(stderr, "%s\n", dc); } } if (this_msg_reference != NULL) { /* in testing mode... */ /* 31 = "test-_.xml" + an_int_as_string + '\0' */ filename_len = 31 + strlen(this_msg_reference); crm_malloc0(filename, filename_len); if(filename != NULL) { sprintf(filename, "%s-%s_%d.xml", result, this_msg_reference, received_responses); filename[filename_len - 1] = '\0'; if (0 > write_xml_file( new_input->xml, filename, FALSE)) { crm_crit("Could not save response to" " %s", filename); } } } } if (server->ch_status == IPC_DISCONNECT) { crm_debug_2("admin_msg_callback: received HUP"); return !hack_return_good; } if (received_responses >= expected_responses) { crm_debug_2( "Recieved expected number (%d) of messages from Heartbeat." " Exiting normally.", expected_responses); g_main_quit(mainloop); return !hack_return_good; } message_timer_id = Gmain_timeout_add( message_timeout_ms, admin_message_timeout, NULL); return hack_return_good; } gboolean admin_message_timeout(gpointer data) { fprintf(stderr, "No messages received in %d seconds.. aborting\n", (int)message_timeout_ms/1000); crm_err("No messages received in %d seconds", (int)message_timeout_ms/1000); g_main_quit(mainloop); return FALSE; } gboolean is_node_online(crm_data_t *node_state) { const char *uname = crm_element_value(node_state,XML_ATTR_UNAME); const char *join_state = crm_element_value(node_state,XML_CIB_ATTR_JOINSTATE); const char *exp_state = crm_element_value(node_state,XML_CIB_ATTR_EXPSTATE); const char *crm_state = crm_element_value(node_state,XML_CIB_ATTR_CRMDSTATE); const char *ha_state = crm_element_value(node_state,XML_CIB_ATTR_HASTATE); const char *ccm_state = crm_element_value(node_state,XML_CIB_ATTR_INCCM); if(safe_str_neq(join_state, CRMD_JOINSTATE_DOWN) && (ha_state == NULL || safe_str_eq(ha_state, ACTIVESTATUS)) && crm_is_true(ccm_state) && safe_str_eq(crm_state, ONLINESTATUS)) { crm_debug_3("Node %s is online", uname); return TRUE; } crm_debug_3("Node %s: ha=%s ccm=%s join=%s exp=%s crm=%s", uname, crm_str(ha_state), crm_str(ccm_state), crm_str(join_state), crm_str(exp_state), crm_str(crm_state)); crm_debug_3("Node %s is offline", uname); return FALSE; } int do_find_node_list(crm_data_t *xml_node) { int found = 0; crm_data_t *nodes = get_object_root(XML_CIB_TAG_NODES, xml_node); xml_child_iter_filter( nodes, node, XML_CIB_TAG_NODE, if(BASH_EXPORT) { printf("export %s=%s\n", crm_element_value(node, XML_ATTR_UNAME), crm_element_value(node, XML_ATTR_ID)); } else { printf("%s node: %s (%s)\n", crm_element_value(node, XML_ATTR_TYPE), crm_element_value(node, XML_ATTR_UNAME), crm_element_value(node, XML_ATTR_ID)); } found++; ); if(found == 0) { printf("NO nodes configured\n"); } return found; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-?vs] [command] [command args]\n", cmd); fprintf(stream, "Options\n"); fprintf(stream, "\t--%s (-%c)\t: this help message\n", "help", '?'); fprintf(stream, "\t--%s (-%c)\t: " "turn on debug info. additional instances increase verbosity\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c)\t: be very *very* quiet\n", "quiet", 'q'); fprintf(stream, "\t--%s (-%c)\t: Only applies to -N.\n" "\t\tCreate Bash export entries of the form \"export uname=uuid\"\n", "bash-export", 'B'); fprintf(stream, "\nCommands\n"); fprintf(stream, "\t--%s (-%c) \t: " "increment the CRMd debug level on \n", CRM_OP_DEBUG_UP,'i'); fprintf(stream, "\t--%s (-%c) \t: " "decrement the CRMd debug level on \n", CRM_OP_DEBUG_DOWN,'d'); fprintf(stream, "\t--%s (-%c) \t: " "shutdown the CRMd on \n", "kill", 'K'); fprintf(stream, "\t--%s (-%c) \t: " "request the status of \n", "status", 'S'); #if 0 fprintf(stream, "\t--%s (-%c)\t\t: " "request the status of all nodes\n", "health", 'H'); #endif fprintf(stream, "\t--%s (-%c) \t: " "initiate an election from \n", "election", 'E'); fprintf(stream, "\t--%s (-%c)\t: " "request the uname of the DC\n", "dc_lookup", 'D'); fprintf(stream, "\t--%s (-%c)\t\t: " "request the uname of all member nodes\n", "nodes", 'N'); /* fprintf(stream, "\t--%s (-%c)\t\n", "disconnect", 'D'); */ fflush(stream); exit(exit_status); } diff --git a/crm/admin/xml_diff.c b/crm/admin/xml_diff.c index 9b37f05dad..2a942326e0 100644 --- a/crm/admin/xml_diff.c +++ b/crm/admin/xml_diff.c @@ -1,263 +1,263 @@ -/* $Id: xml_diff.c,v 1.8 2006/04/12 08:22:50 andrew Exp $ */ +/* $Id: xml_diff.c,v 1.9 2006/06/07 12:46:57 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 #ifdef HAVE_GETOPT_H #include #endif #include /* someone complaining about _ha_msg_mod not being found */ #include const char *crm_system_name = "diff"; void usage(const char *cmd, int exit_status); #define OPTARGS "V?o:n:p:scfO:N:" int main(int argc, char **argv) { gboolean apply = FALSE; gboolean raw_1 = FALSE; gboolean raw_2 = FALSE; gboolean filter = FALSE; gboolean use_stdin = FALSE; gboolean as_cib = FALSE; int argerr = 0; int flag; crm_data_t *object_1 = NULL; crm_data_t *object_2 = NULL; crm_data_t *output = NULL; const char *xml_file_1 = NULL; const char *xml_file_2 = NULL; #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {"original", 1, 0, 'o'}, {"new", 1, 0, 'n'}, {"original-string", 1, 0, 'O'}, {"new-string", 1, 0, 'N'}, {"patch", 1, 0, 'p'}, {"stdin", 0, 0, 's'}, {"cib", 0, 0, 'c'}, {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {0, 0, 0, 0} }; #endif cl_log_set_entity(crm_system_name); cl_log_set_facility(LOG_USER); set_crm_log_level(LOG_CRIT-1); if(argc < 2) { usage(crm_system_name, LSB_EXIT_EINVAL); } while (1) { #ifdef HAVE_GETOPT_H flag = getopt_long(argc, argv, OPTARGS, long_options, &option_index); #else flag = getopt(argc, argv, OPTARGS); #endif if (flag == -1) break; switch(flag) { case 'o': xml_file_1 = optarg; break; case 'O': xml_file_1 = optarg; raw_1 = TRUE; break; case 'n': xml_file_2 = optarg; break; case 'N': xml_file_2 = optarg; raw_2 = TRUE; break; case 'p': xml_file_2 = optarg; apply = TRUE; break; case 'f': filter = TRUE; break; case 's': use_stdin = TRUE; break; case 'c': as_cib = TRUE; break; case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; default: printf("Argument code 0%o (%c)" " is not (?yet?) supported\n", flag, flag); ++argerr; break; } } if (optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) printf("%s ", argv[optind++]); printf("\n"); } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } crm_zero_mem_stats(NULL); if(raw_1) { object_1 = string2xml(xml_file_1); } else if(use_stdin) { fprintf(stderr, "Input first XML fragment:"); object_1 = stdin2xml(); } else if(xml_file_1 != NULL) { FILE *xml_strm = fopen(xml_file_1, "r"); if(xml_strm != NULL) { crm_debug("Reading: %s", xml_file_1); object_1 = file2xml(xml_strm); } else { cl_perror("File not found: %s", xml_file_1); } } if(raw_2) { object_2 = string2xml(xml_file_2); } else if(use_stdin) { fprintf(stderr, "Input second XML fragment:"); object_2 = stdin2xml(); } else if(xml_file_2 != NULL) { FILE *xml_strm = fopen(xml_file_2, "r"); if(xml_strm != NULL) { crm_debug("Reading: %s", xml_file_2); object_2 = file2xml(xml_strm); } else { cl_perror("File not found: %s", xml_file_2); } } - + CRM_ASSERT(object_1 != NULL); CRM_ASSERT(object_2 != NULL); if(as_cib == FALSE) { if(apply) { apply_xml_diff(object_1, object_2, &output); } else { output = diff_xml_object(object_1, object_2, filter); } } else { if(apply) { apply_cib_diff(object_1, object_2, &output); } else { output = diff_cib_object(object_1, object_2, filter); } } if(output != NULL) { char *buffer = dump_xml_formatted(output); fprintf(stdout, "%s", crm_str(buffer)); crm_free(buffer); } free_xml(object_1); free_xml(object_2); free_xml(output); crm_mem_stats(NULL); if(apply == FALSE && output != NULL) { return 1; } return 0; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status != 0 ? stderr : stdout; fprintf(stream, "usage: %s [-?V] [oO] [pnN]\n", cmd); fprintf(stream, "Options\n"); fprintf(stream, "\t--%s (-%c)\tthis help message\n", "help", '?'); fprintf(stream, "\t--%s (-%c) \t\n", "original", 'o'); fprintf(stream, "\t--%s (-%c) \t\n", "new", 'n'); fprintf(stream, "\t--%s (-%c) \t\n", "original-string", 'O'); fprintf(stream, "\t--%s (-%c) \t\n", "new-string", 'N'); fprintf(stream, "\t--%s (-%c) \tApply a patch to the original XML\n", "patch", 'p'); fprintf(stream, "\t--%s (-%c)\tCompare/patch the inputs as a CIB\n", "cib", 'c'); fprintf(stream, "\t--%s (-%c)\tRead the inputs from stdin\n", "stdin", 's'); fflush(stream); exit(exit_status); } diff --git a/crm/pengine/Makefile.am b/crm/pengine/Makefile.am index 62fd6a8b3c..55f1a557b9 100644 --- a/crm/pengine/Makefile.am +++ b/crm/pengine/Makefile.am @@ -1,95 +1,88 @@ # # 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@ pe_varlibdir = $(HA_VARLIBDIR)/$(HB_PKG)/pengine # sockets with path crmdir = $(havarlibdir)/crm apigid = @HA_APIGID@ crmuid = @HA_CCMUID@ COMMONLIBS = $(CRM_DEBUG_LIBS) \ $(top_builddir)/lib/clplumbing/libplumb.la \ $(top_builddir)/lib/pils/libpils.la \ $(top_builddir)/lib/crm/common/libcrmcommon.la \ + $(top_builddir)/lib/crm/pengine/libpe_status.la \ libpengine.la \ - $(top_builddir)/lib/crm/cib/libcib.la \ - $(top_builddir)/lib/apphb/libapphb.la \ $(GLIBLIB) \ $(CURSESLIBS) \ $(LIBRT) LIBRT = @LIBRT@ AM_CFLAGS = @CFLAGS@ $(CRM_DEBUG_FLAGS) ## libraries lib_LTLIBRARIES = libpengine.la ## binary progs halib_PROGRAMS = ptest pengine ## SOURCES +noinst_HEADERS = allocate.h +#utils.h pengine.h -libpengine_la_SOURCES = color.c unpack.c graph.c rules.c pengine.c \ - utils.c complex.c native.c stages.c \ - group.c incarnation.c master.c - -libpengine_la_LDFLAGS = -version-info 2:0:1 - -noinst_HEADERS = pe_utils.h pengine.h complex.h pe_rules.h - -ptest_SOURCES = ptest.c - -ptest_CFLAGS = -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' -ptest_LDFLAGS = -ptest_LDADD = $(COMMONLIBS) \ - $(top_builddir)/lib/crm/transition/libtransitioner.la +libpengine_la_LDFLAGS = -version-info 3:0:0 +# -L$(top_builddir)/lib/pils -lpils -export-dynamic -module -avoid-version +libpengine_la_SOURCES = pengine.c allocate.c \ + native.c group.c clone.c master.c graph.c pengine_SOURCES = main.c - pengine_CFLAGS = -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' -pengine_LDFLAGS = -pengine_LDADD = $(COMMONLIBS) \ - $(top_builddir)/lib/crm/transition/libtransitioner.la \ - $(top_builddir)/lib/hbclient/libhbclient.la +pengine_LDADD = $(COMMONLIBS) $(top_builddir)/lib/crm/cib/libcib.la +# libcib for get_object_root() +# $(top_builddir)/lib/hbclient/libhbclient.la -# +ptest_SOURCES = ptest.c +ptest_CFLAGS = -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' +ptest_LDADD = $(COMMONLIBS) \ + $(top_builddir)/lib/crm/cib/libcib.la \ + $(top_builddir)/lib/crm/transition/libtransitioner.la clean-generic: - rm -f *.log *.debug *~ + rm -f *.log *.debug *~ .gres.* testcases/.gres.* install-exec-local: $(mkinstalldirs) $(DESTDIR)/$(pe_varlibdir) -chown $(HA_CCMUSER) $(DESTDIR)/$(pe_varlibdir) -chgrp $(HA_APIGROUP) $(DESTDIR)/$(pe_varlibdir) -chmod 750 $(DESTDIR)/$(pe_varlibdir) uninstall-local: diff --git a/crm/pengine/stages.c b/crm/pengine/allocate.c similarity index 77% rename from crm/pengine/stages.c rename to crm/pengine/allocate.c index 9ae0fd21f9..b56cb28fc6 100644 --- a/crm/pengine/stages.c +++ b/crm/pengine/allocate.c @@ -1,582 +1,652 @@ -/* $Id: stages.c,v 1.105 2006/06/07 09:01:00 andrew Exp $ */ +/* $Id: allocate.c,v 1.1 2006/06/07 12:46:57 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 node_t *choose_fencer(action_t *stonith, node_t *node, GListPtr resources); +void set_alloc_actions(pe_working_set_t *data_set); + +resource_alloc_functions_t resource_class_alloc_functions[] = { + { + native_set_cmds, + native_num_allowed_nodes, + native_color, + native_create_actions, + native_create_probe, + native_internal_constraints, + native_agent_constraints, + native_rsc_colocation_lh, + native_rsc_colocation_rh, + native_rsc_order_lh, + native_rsc_order_rh, + native_rsc_location, + native_expand, + native_stonith_ordering, + native_create_notify_element, + }, + { + group_set_cmds, + group_num_allowed_nodes, + group_color, + group_create_actions, + group_create_probe, + group_internal_constraints, + group_agent_constraints, + group_rsc_colocation_lh, + group_rsc_colocation_rh, + group_rsc_order_lh, + group_rsc_order_rh, + group_rsc_location, + group_expand, + group_stonith_ordering, + group_create_notify_element, + }, + { + clone_set_cmds, + clone_num_allowed_nodes, + clone_color, + clone_create_actions, + clone_create_probe, + clone_internal_constraints, + clone_agent_constraints, + clone_rsc_colocation_lh, + clone_rsc_colocation_rh, + clone_rsc_order_lh, + clone_rsc_order_rh, + clone_rsc_location, + clone_expand, + clone_stonith_ordering, + clone_create_notify_element, + }, + { + clone_set_cmds, + clone_num_allowed_nodes, + clone_color, + master_create_actions, + clone_create_probe, + master_internal_constraints, + clone_agent_constraints, + clone_rsc_colocation_lh, + clone_rsc_colocation_rh, + clone_rsc_order_lh, + clone_rsc_order_rh, + clone_rsc_location, + clone_expand, + clone_stonith_ordering, + clone_create_notify_element, + } +}; -/* - * Unpack everything - * At the end you'll have: - * - A list of nodes - * - A list of resources (each with any dependencies on other resources) - * - A list of constraints between resources and nodes - * - A list of constraints between start/stop actions - * - A list of nodes that need to be stonith'd - * - A list of nodes that need to be shutdown - * - A list of the possible stop/start actions (without dependencies) - */ -gboolean -stage0(pe_working_set_t *data_set) +color_t *add_color(resource_t *rh_resource, color_t *color); + +gboolean +apply_placement_constraints(pe_working_set_t *data_set) { -/* int lpc; */ - crm_data_t * config = get_object_root( - XML_CIB_TAG_CRMCONFIG, data_set->input); - crm_data_t * cib_nodes = get_object_root( - XML_CIB_TAG_NODES, data_set->input); - crm_data_t * cib_resources = get_object_root( - XML_CIB_TAG_RESOURCES, data_set->input); - crm_data_t * cib_status = get_object_root( - XML_CIB_TAG_STATUS, data_set->input); - crm_data_t * cib_constraints = get_object_root( - XML_CIB_TAG_CONSTRAINTS, data_set->input); - const char *value = crm_element_value( - data_set->input, XML_ATTR_HAVE_QUORUM); - - crm_debug_3("Beginning unpack"); + crm_debug_3("Applying constraints..."); + slist_iter( + cons, rsc_to_node_t, data_set->placement_constraints, lpc, + + cons->rsc_lh->cmds->rsc_location(cons->rsc_lh, cons); + ); - /* reset remaining global variables */ + return TRUE; - if(data_set->input == NULL) { - return FALSE; - } +} - if(data_set->input != NULL - && crm_element_value(data_set->input, XML_ATTR_DC_UUID) != NULL) { - /* this should always be present */ - data_set->dc_uuid = crm_element_value_copy( - data_set->input, XML_ATTR_DC_UUID); - } +color_t * +add_color(resource_t *resource, color_t *color) +{ + color_t *local_color = NULL; + + if(color == NULL) { + pe_err("Cannot add NULL color"); + return NULL; + } - data_set->no_color = create_color(data_set, NULL, NULL); + local_color = find_color(resource->candidate_colors, color); - unpack_config(config, data_set); + if(local_color == NULL) { + crm_debug_4("Adding color %d", color->id); + + local_color = copy_color(color); + resource->candidate_colors = + g_list_append(resource->candidate_colors, local_color); - if(value != NULL) { - cl_str_to_boolean(value, &data_set->have_quorum); + } else { + crm_debug_4("Color %d already present", color->id); } - - if(data_set->have_quorum == FALSE - && data_set->no_quorum_policy != no_quorum_ignore) { - crm_warn("We do not have quorum" - " - fencing and resource management disabled"); + + return local_color; +} + +void +set_alloc_actions(pe_working_set_t *data_set) +{ + slist_iter( + rsc, resource_t, data_set->resources, lpc, + rsc->cmds = &resource_class_alloc_functions[rsc->variant]; + rsc->cmds->set_cmds(rsc); + ); +} + +gboolean +stage0(pe_working_set_t *data_set) +{ + crm_data_t * cib_constraints = get_object_root( + XML_CIB_TAG_CONSTRAINTS, data_set->input); + + if(data_set->input == NULL) { + return FALSE; } + + cluster_status(data_set); - unpack_nodes(cib_nodes, data_set); - unpack_resources(cib_resources, data_set); - unpack_status(cib_status, data_set); + set_alloc_actions(data_set); unpack_constraints(cib_constraints, data_set); - return TRUE; } /* * Count how many valid nodes we have (so we know the maximum number of * colors we can resolve). * * Apply node constraints (ie. filter the "allowed_nodes" part of resources */ gboolean stage1(pe_working_set_t *data_set) { - crm_debug_3("Applying placement constraints"); + crm_debug_3("Applying placement constraints"); slist_iter( node, node_t, data_set->nodes, lpc, if(node == NULL) { /* error */ } else if(node->weight >= 0.0 /* global weight */ && node->details->online && node->details->type == node_member) { data_set->max_valid_nodes++; } ); apply_placement_constraints(data_set); return TRUE; -} - - +} /* * Choose a color for all resources from highest priority and XML_STRENGTH_VAL_MUST * dependencies to lowest, creating new colors as necessary (returned * as "colors"). * * Some nodes may be colored as a "no_color" meaning that it was unresolvable * given the current node stati and constraints. */ gboolean stage2(pe_working_set_t *data_set) { crm_debug_3("Coloring resources"); crm_debug_5("create \"no color\""); /* Take (next) highest resource */ slist_iter( lh_resource, resource_t, data_set->resources, lpc, - lh_resource->fns->color(lh_resource, data_set); + lh_resource->cmds->color(lh_resource, data_set); ); return TRUE; } /* * Check nodes for resources started outside of the LRM */ gboolean stage3(pe_working_set_t *data_set) { action_t *probe_complete = NULL; action_t *probe_node_complete = NULL; slist_iter( node, node_t, data_set->nodes, lpc, gboolean force_probe = FALSE; const char *probed = g_hash_table_lookup( node->details->attrs, CRM_OP_PROBED); crm_debug_2("%s probed: %s", node->details->uname, probed); if(node->details->online == FALSE) { continue; } else if(node->details->unclean) { continue; } else if(probe_complete == NULL) { probe_complete = custom_action( NULL, crm_strdup(CRM_OP_PROBED), CRM_OP_PROBED, NULL, FALSE, TRUE, data_set); probe_complete->pseudo = TRUE; probe_complete->optional = TRUE; } if(probed != NULL && crm_is_true(probed) == FALSE) { force_probe = TRUE; } probe_node_complete = custom_action( NULL, crm_strdup(CRM_OP_PROBED), CRM_OP_PROBED, node, FALSE, TRUE, data_set); probe_node_complete->optional = crm_is_true(probed); probe_node_complete->priority = INFINITY; add_hash_param(probe_node_complete->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); custom_action_order(NULL, NULL, probe_node_complete, NULL, NULL, probe_complete, pe_ordering_optional, data_set); slist_iter( rsc, resource_t, data_set->resources, lpc2, - if(rsc->fns->create_probe( + if(rsc->cmds->create_probe( rsc, node, probe_node_complete, force_probe, data_set)) { probe_complete->optional = FALSE; probe_node_complete->optional = FALSE; custom_action_order( NULL, NULL, probe_complete, rsc, start_key(rsc), NULL, pe_ordering_manditory, data_set); } ); ); return TRUE; } /* * Choose a node for each (if possible) color */ gboolean stage4(pe_working_set_t *data_set) { node_t *chosen = NULL; crm_debug_3("Assigning nodes to colors"); slist_iter( color, color_t, data_set->colors, lpc, crm_debug_4("assigning node to color %d", color->id); if(color == NULL) { pe_err("NULL color detected"); continue; } else if(color->details->pending == FALSE) { continue; } choose_node_from_list(color); chosen = color->details->chosen_node; slist_iter( rsc, resource_t, color->details->allocated_resources, lpc2, crm_debug_2("Processing colocation constraints for %s" " now that color %d is allocated", rsc->id, color->details->id); if(chosen == NULL) { rsc->next_role = RSC_ROLE_STOPPED; } else if(rsc->next_role == RSC_ROLE_UNKNOWN) { rsc->next_role = RSC_ROLE_STARTED; } slist_iter( constraint, rsc_colocation_t, rsc->rsc_cons, lpc, - rsc->fns->rsc_colocation_lh( + rsc->cmds->rsc_colocation_lh( rsc, constraint->rsc_rh, constraint); ); ); ); crm_debug_3("done"); return TRUE; } /* * Attach nodes to the actions that need to be taken * * Mark actions XML_LRM_ATTR_OPTIONAL if possible (Ie. if the start and stop are * for the same node) * * Mark unrunnable actions */ gboolean stage5(pe_working_set_t *data_set) { crm_debug_3("Creating actions and internal ording constraints"); slist_iter( rsc, resource_t, data_set->resources, lpc, - rsc->fns->create_actions(rsc, data_set); - rsc->fns->internal_constraints(rsc, data_set); + rsc->cmds->create_actions(rsc, data_set); + rsc->cmds->internal_constraints(rsc, data_set); ); return TRUE; } /* * Create dependacies for stonith and shutdown operations */ gboolean stage6(pe_working_set_t *data_set) { action_t *dc_down = NULL; action_t *stonith_op = NULL; - gboolean integrity_lost = FALSE; crm_debug_3("Processing fencing and shutdown cases"); slist_iter( node, node_t, data_set->nodes, lpc, stonith_op = NULL; - if(node->details->unclean && data_set->stonith_enabled && (data_set->have_quorum || data_set->no_quorum_policy == no_quorum_ignore)) { pe_warn("Scheduling Node %s for STONITH", node->details->uname); stonith_op = custom_action( NULL, crm_strdup(CRM_OP_FENCE), CRM_OP_FENCE, node, FALSE, TRUE, data_set); add_hash_param( stonith_op->meta, XML_LRM_ATTR_TARGET, node->details->uname); add_hash_param( stonith_op->meta, XML_LRM_ATTR_TARGET_UUID, node->details->id); add_hash_param( stonith_op->meta, "stonith_action", data_set->stonith_action); stonith_constraints(node, stonith_op, data_set); if(node->details->is_dc) { dc_down = stonith_op; } } else if(node->details->online && node->details->shutdown) { action_t *down_op = NULL; crm_info("Scheduling Node %s for shutdown", node->details->uname); down_op = custom_action( NULL, crm_strdup(CRM_OP_SHUTDOWN), CRM_OP_SHUTDOWN, node, FALSE, TRUE, data_set); shutdown_constraints(node, down_op, data_set); if(node->details->is_dc) { dc_down = down_op; } } + if(node->details->unclean && stonith_op == NULL) { - integrity_lost = TRUE; - pe_warn("Node %s is unclean!", node->details->uname); + pe_err("Node %s is unclean!", node->details->uname); + pe_warn("YOUR RESOURCES ARE NOW LIKELY COMPROMISED"); + if(data_set->stonith_enabled == FALSE) { + pe_warn("ENABLE STONITH TO KEEP YOUR RESOURCES SAFE"); + } else { + CRM_CHECK(data_set->have_quorum == FALSE, ;); + crm_notice("Cannot fence until quorum is attained (or no_quorum_policy is set to ignore)"); + } } ); - if(integrity_lost) { - if(data_set->have_quorum == FALSE) { - crm_notice("Cannot fence unclean nodes until quorum is" - " attained (or no_quorum_policy is set to ignore)"); - - } else if(data_set->stonith_enabled == FALSE) { - pe_warn("YOUR RESOURCES ARE NOW LIKELY COMPROMISED"); - pe_err("ENABLE STONITH TO KEEP YOUR RESOURCES SAFE"); - } - } - if(dc_down != NULL) { GListPtr shutdown_matches = find_actions( data_set->actions, CRM_OP_SHUTDOWN, NULL); crm_debug_2("Ordering shutdowns before %s on %s (DC)", dc_down->task, dc_down->node->details->uname); add_hash_param(dc_down->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); slist_iter( node_stop, action_t, shutdown_matches, lpc, if(node_stop->node->details->is_dc) { continue; } crm_debug("Ordering shutdown on %s before %s on %s", node_stop->node->details->uname, dc_down->task, dc_down->node->details->uname); order_actions(node_stop, dc_down, pe_ordering_manditory); ); } return TRUE; } /* * Determin the sets of independant actions and the correct order for the * actions in each set. * * Mark dependencies of un-runnable actions un-runnable * */ gboolean stage7(pe_working_set_t *data_set) { crm_debug_3("Applying ordering constraints"); slist_iter( order, order_constraint_t, data_set->ordering_constraints, lpc, /* try rsc_action-to-rsc_action */ resource_t *rsc = order->lh_rsc; if(rsc == NULL && order->lh_action) { rsc = order->lh_action->rsc; } if(rsc != NULL) { - rsc->fns->rsc_order_lh(rsc, order); + rsc->cmds->rsc_order_lh(rsc, order); continue; } /* try action-to-rsc_action */ /* que off the rh resource */ rsc = order->rh_rsc; if(rsc == NULL && order->rh_action) { rsc = order->rh_action->rsc; } if(rsc != NULL) { - rsc->fns->rsc_order_rh(order->lh_action, rsc, order); + rsc->cmds->rsc_order_rh(order->lh_action, rsc, order); } else { /* fall back to action-to-action */ order_actions( order->lh_action, order->rh_action, order->type); } ); update_action_states(data_set->actions); return TRUE; } int transition_id = -1; /* * Create a dependency graph to send to the transitioner (via the CRMd) */ gboolean stage8(pe_working_set_t *data_set) { char *transition_id_s = NULL; transition_id++; transition_id_s = crm_itoa(transition_id); crm_debug("Creating transition graph %d.", transition_id); data_set->graph = create_xml_node(NULL, XML_TAG_GRAPH); crm_xml_add(data_set->graph, "global_timeout", data_set->transition_idle_timeout); crm_xml_add(data_set->graph, "transition_id", transition_id_s); crm_free(transition_id_s); /* errors... slist_iter(action, action_t, action_list, lpc, if(action->optional == FALSE && action->runnable == FALSE) { print_action("Ignoring", action, TRUE); } ); */ slist_iter( rsc, resource_t, data_set->resources, lpc, crm_debug_4("processing actions for rsc=%s", rsc->id); - rsc->fns->expand(rsc, data_set); + rsc->cmds->expand(rsc, data_set); ); crm_log_xml_debug_3( data_set->graph, "created resource-driven action list"); /* catch any non-resource specific actions */ crm_debug_4("processing non-resource actions"); slist_iter( action, action_t, data_set->actions, lpc, graph_element_from_action(action, data_set); ); crm_log_xml_debug_3(data_set->graph, "created generic action list"); crm_notice("Created transition graph %d.", transition_id); return TRUE; } gboolean choose_node_from_list(color_t *color) { /* 1. Sort by weight 2. color.chosen_node = the node (of those with the highest wieght) with the fewest resources 3. remove color.chosen_node from all other colors */ GListPtr nodes = color->details->candidate_nodes; node_t *chosen = NULL; int multiple = 0; crm_debug_3("Choosing node for color %d", color->id); color->details->candidate_nodes = g_list_sort(nodes, sort_node_weight); nodes = color->details->candidate_nodes; chosen = g_list_nth_data(nodes, 0); color->details->chosen_node = NULL; color->details->pending = FALSE; if(chosen == NULL) { if(color->id != 0) { crm_debug("Could not allocate a node for color %d", color->id); } return FALSE; } else if(chosen->details->unclean || chosen->details->standby || chosen->details->shutdown) { crm_debug("All nodes for color %d are unavailable" ", unclean or shutting down", color->id); color->details->chosen_node = NULL; return FALSE; } else if(chosen->weight < 0) { crm_debug_2("Even highest ranked node for color %d, had weight %d", color->id, chosen->weight); color->details->chosen_node = NULL; return FALSE; } slist_iter(candidate, node_t, nodes, lpc, crm_debug_2("Color %d, Node[%d] %s: %d", color->id, lpc, candidate->details->uname, candidate->weight); if(chosen->weight > 0 && candidate->details->unclean == FALSE && candidate->weight == chosen->weight) { multiple++; } else { break; } ); if(multiple > 1) { int log_level = LOG_INFO; char *score = score2char(chosen->weight); if(chosen->weight >= INFINITY) { log_level = LOG_WARNING; } crm_log_maybe(log_level, "%d nodes with equal score (%s) for" " running the listed resources (chose %s):", multiple, score, chosen->details->uname); slist_iter(rsc, resource_t, color->details->allocated_resources, lpc, rsc->fns->print( rsc, "\t", pe_print_log|pe_print_rsconly, &log_level); ); crm_free(score); } /* todo: update the old node for each resource to reflect its * new resource count */ chosen->details->num_resources += color->details->num_resources; color->details->chosen_node = node_copy(chosen); return TRUE; } diff --git a/crm/pengine/complex.h b/crm/pengine/allocate.h similarity index 63% rename from crm/pengine/complex.h rename to crm/pengine/allocate.h index e4ff4eac17..1f8d2e25e0 100644 --- a/crm/pengine/complex.h +++ b/crm/pengine/allocate.h @@ -1,260 +1,174 @@ -/* $Id: complex.h,v 1.36 2006/05/30 07:47:44 andrew Exp $ */ +/* $Id: allocate.h,v 1.1 2006/06/07 12:46:57 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 */ -#ifndef CRM_PENGINE_COMPLEX__H -#define CRM_PENGINE_COMPLEX__H +#ifndef CRM_PENGINE_COMPLEX_ALLOC__H +#define CRM_PENGINE_COMPLEX_ALLOC__H -#include -#include #include - -#define n_object_classes 3 - -/*#define PE_OBJ_F_ ""*/ - -#define PE_OBJ_T_NATIVE "native" -#define PE_OBJ_T_GROUP "group" -#define PE_OBJ_T_INCARNATION "clone" -#define PE_OBJ_T_MASTER "master" - -enum pe_obj_types -{ - pe_unknown = -1, - pe_native = 0, - pe_group = 1, - pe_clone = 2, - pe_master = 3 -}; - -extern int get_resource_type(const char *name); - +#include +#include +#include +#include typedef struct notify_entry_s { resource_t *rsc; node_t *node; } notify_entry_t; typedef struct notify_data_s { GHashTable *keys; GListPtr active; /* notify_entry_t* */ GListPtr inactive; /* notify_entry_t* */ GListPtr start; /* notify_entry_t* */ GListPtr stop; /* notify_entry_t* */ GListPtr demote; /* notify_entry_t* */ GListPtr promote; /* notify_entry_t* */ GListPtr master; /* notify_entry_t* */ GListPtr slave; /* notify_entry_t* */ } notify_data_t; -typedef struct resource_object_functions_s +struct resource_alloc_functions_s { - gboolean (*unpack)(resource_t *, pe_working_set_t *); - resource_t *(*find_child)(resource_t *, const char *); + void (*set_cmds)(resource_t *); int (*num_allowed_nodes)(resource_t *); color_t *(*color)(resource_t *, pe_working_set_t *); void (*create_actions)(resource_t *, pe_working_set_t *); gboolean (*create_probe)( resource_t *, node_t *, action_t *, gboolean, pe_working_set_t *); void (*internal_constraints)(resource_t *, pe_working_set_t *); void (*agent_constraints)(resource_t *); void (*rsc_colocation_lh)(resource_t *, resource_t *, rsc_colocation_t *); void (*rsc_colocation_rh)(resource_t *, resource_t *, rsc_colocation_t *); void (*rsc_order_lh)(resource_t *, order_constraint_t *); void (*rsc_order_rh)( action_t *, resource_t *, order_constraint_t *); void (*rsc_location)(resource_t *, rsc_to_node_t *); void (*expand)(resource_t *, pe_working_set_t *); - GListPtr (*children)(resource_t *); void (*stonith_ordering)( resource_t *, action_t *, pe_working_set_t *); - /* parameter result must be free'd */ - char *(*parameter)( - resource_t *, node_t *, gboolean, const char *, - pe_working_set_t *); - - void (*print)(resource_t *, const char *, long, void *); - gboolean (*active)(resource_t *,gboolean); - enum rsc_role_e (*state)(resource_t *); void (*create_notify_element)(resource_t*,action_t*, notify_data_t*,pe_working_set_t*); - void (*free)(resource_t *); -} resource_object_functions_t; +}; -extern char *native_parameter( - resource_t *rsc, node_t *node, gboolean create, const char *name, - pe_working_set_t *data_set); -extern gboolean native_unpack(resource_t *rsc, pe_working_set_t *data_set); -extern GListPtr native_children(resource_t *rsc); -extern resource_t *native_find_child(resource_t *rsc, const char *id); +extern void native_set_cmds(resource_t *rsc); +extern void group_set_cmds(resource_t *rsc); +extern void clone_set_cmds(resource_t *rsc); extern int native_num_allowed_nodes(resource_t *rsc); extern color_t * native_color(resource_t *rsc, pe_working_set_t *data_set); extern void native_create_actions( resource_t *rsc, pe_working_set_t *data_set); extern void native_internal_constraints( resource_t *rsc, pe_working_set_t *data_set); extern void native_agent_constraints(resource_t *rsc); extern void native_rsc_colocation_lh( resource_t *lh_rsc, resource_t *rh_rsc, rsc_colocation_t *constraint); extern void native_rsc_colocation_rh( resource_t *lh_rsc, resource_t *rh_rsc, rsc_colocation_t *constraint); extern void native_rsc_order_lh(resource_t *rsc, order_constraint_t *order); extern void native_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order); extern void native_rsc_location(resource_t *rsc, rsc_to_node_t *constraint); extern void native_expand(resource_t *rsc, pe_working_set_t *data_set); extern void native_dump(resource_t *rsc, const char *pre_text, gboolean details); -extern gboolean native_active(resource_t *rsc, gboolean all); -extern void native_print(resource_t *rsc, const char *pre_text, long options, void *print_data); -extern void native_print(resource_t *rsc, const char *pre_text, long options, void *print_data); - -extern void native_html(resource_t *rsc, const char *pre_text, FILE *stream); -extern void native_free(resource_t *rsc); -extern enum rsc_role_e native_resource_state(resource_t *rsc); extern void native_create_notify_element( resource_t *rsc, action_t *op, notify_data_t *n_data,pe_working_set_t *data_set); extern void native_assign_color(resource_t *rsc, color_t *color); extern gboolean native_create_probe( resource_t *rsc, node_t *node, action_t *complete, gboolean force, pe_working_set_t *data_set); extern void native_stonith_ordering( resource_t *rsc, action_t *stonith_op, pe_working_set_t *data_set); -extern gboolean group_unpack(resource_t *rsc, pe_working_set_t *data_set); -extern GListPtr group_children(resource_t *rsc); -extern resource_t *group_find_child(resource_t *rsc, const char *id); extern int group_num_allowed_nodes(resource_t *rsc); extern color_t *group_color(resource_t *rsc, pe_working_set_t *data_set); extern void group_create_actions( resource_t *rsc, pe_working_set_t *data_set); extern void group_internal_constraints( resource_t *rsc, pe_working_set_t *data_set); extern void group_agent_constraints(resource_t *rsc); extern void group_rsc_colocation_lh( resource_t *lh_rsc, resource_t *rh_rsc, rsc_colocation_t *constraint); extern void group_rsc_colocation_rh( resource_t *lh_rsc, resource_t *rh_rsc, rsc_colocation_t *constraint); extern void group_rsc_order_lh(resource_t *rsc, order_constraint_t *order); extern void group_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order); extern void group_rsc_location(resource_t *rsc, rsc_to_node_t *constraint); extern void group_expand(resource_t *rsc, pe_working_set_t *data_set); -extern gboolean group_active(resource_t *rsc, gboolean all); -extern void group_print(resource_t *rsc, const char *pre_text, long options, void *print_data); -extern void group_free(resource_t *rsc); extern enum rsc_role_e group_resource_state(resource_t *rsc); extern void group_create_notify_element( resource_t *rsc, action_t *op, notify_data_t *n_data,pe_working_set_t *data_set); extern gboolean group_create_probe( resource_t *rsc, node_t *node, action_t *complete, gboolean force, pe_working_set_t *data_set); extern void group_stonith_ordering( resource_t *rsc, action_t *stonith_op, pe_working_set_t *data_set); -extern gboolean clone_unpack(resource_t *rsc, pe_working_set_t *data_set); -extern GListPtr clone_children(resource_t *rsc); -extern resource_t *clone_find_child(resource_t *rsc, const char *id); extern int clone_num_allowed_nodes(resource_t *rsc); extern color_t *clone_color(resource_t *rsc, pe_working_set_t *data_set); extern void clone_create_actions(resource_t *rsc, pe_working_set_t *data_set); extern void clone_internal_constraints( resource_t *rsc, pe_working_set_t *data_set); extern void clone_agent_constraints(resource_t *rsc); extern void clone_rsc_colocation_lh( resource_t *lh_rsc, resource_t *rh_rsc, rsc_colocation_t *constraint); extern void clone_rsc_colocation_rh( resource_t *lh_rsc, resource_t *rh_rsc, rsc_colocation_t *constraint); extern void clone_rsc_order_lh(resource_t *rsc, order_constraint_t *order); extern void clone_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order); extern void clone_rsc_location(resource_t *rsc, rsc_to_node_t *constraint); extern void clone_expand(resource_t *rsc, pe_working_set_t *data_set); -extern gboolean clone_active(resource_t *rsc, gboolean all); -extern void clone_print(resource_t *rsc, const char *pre_text, long options, void *print_data); -extern void clone_free(resource_t *rsc); extern enum rsc_role_e clone_resource_state(resource_t *rsc); extern void clone_create_notify_element( resource_t *rsc, action_t *op, notify_data_t *n_data,pe_working_set_t *data_set); extern gboolean clone_create_probe( resource_t *rsc, node_t *node, action_t *complete, gboolean force, pe_working_set_t *data_set); extern void clone_stonith_ordering( resource_t *rsc, action_t *stonith_op, pe_working_set_t *data_set); extern gboolean master_unpack(resource_t *rsc, pe_working_set_t *data_set); extern void master_create_actions(resource_t *rsc, pe_working_set_t *data_set); extern void master_internal_constraints( resource_t *rsc, pe_working_set_t *data_set); /* extern resource_object_functions_t resource_variants[]; */ -extern resource_object_functions_t resource_class_functions[]; -extern gboolean common_unpack(crm_data_t * xml_obj, resource_t **rsc, - resource_t *parent, pe_working_set_t *data_set); - -extern void common_print(resource_t *rsc, const char *pre_text, long options, void *print_data); - -extern void common_free(resource_t *rsc); -extern void native_add_running( - resource_t *rsc, node_t *node, pe_working_set_t *data_set); +extern resource_alloc_functions_t resource_class_alloc_functions[]; extern gboolean is_active(rsc_to_node_t *cons); extern gboolean native_constraint_violated( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint); extern void common_agent_constraints( GListPtr node_list, lrm_agent_t *agent, const char *id); -extern void unpack_instance_attributes( - crm_data_t *xml_obj, const char *set_name, node_t *node, GHashTable *hash, - const char **attr_filter, int attrs_length, pe_working_set_t *data_set); -extern void add_hash_param(GHashTable *hash, const char *name, const char *value); - -#if CURSES_ENABLED -# define status_printw(fmt...) printw(fmt) -#else -# define status_printw(fmt...) \ - crm_err("printw support requires ncurses to be available during configure"); \ - do_crm_log(LOG_WARNING, NULL, NULL, fmt); -#endif - -#define status_print(fmt...) \ - if(options & pe_print_html) { \ - FILE *stream = print_data; \ - fprintf(stream, fmt); \ - } else if(options & pe_print_ncurses) { \ - status_printw(fmt); \ - } else if(options & pe_print_printf) { \ - FILE *stream = print_data; \ - fprintf(stream, fmt); \ - } else if(options & pe_print_log) { \ - int log_level = *(int*)print_data; \ - do_crm_log(log_level, NULL, NULL, fmt); \ - } #endif diff --git a/crm/pengine/incarnation.c b/crm/pengine/clone.c similarity index 82% rename from crm/pengine/incarnation.c rename to crm/pengine/clone.c index 61a5fcef2b..94d355c1ac 100644 --- a/crm/pengine/incarnation.c +++ b/crm/pengine/clone.c @@ -1,1485 +1,1257 @@ -/* $Id: incarnation.c,v 1.96 2006/06/02 10:00:43 andrew Exp $ */ +/* $Id: clone.c,v 1.1 2006/06/07 12:46:57 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 void clone_create_notifications( resource_t *rsc, action_t *action, action_t *action_complete, pe_working_set_t *data_set); extern gboolean rsc_colocation_new( const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh, const char *state_lh, const char *state_rh); typedef struct clone_variant_data_s { resource_t *self; int clone_max; int clone_node_max; int active_clones; int max_nodes; gboolean interleave; gboolean ordered; crm_data_t *xml_obj_child; gboolean notify_confirm; GListPtr child_list; /* resource_t* */ } clone_variant_data_t; void child_stopping_constraints( clone_variant_data_t *clone_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set); void child_starting_constraints( clone_variant_data_t *clone_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set); #define get_clone_variant_data(data, rsc) \ CRM_ASSERT(rsc->variant == pe_clone || rsc->variant == pe_master); \ data = (clone_variant_data_t *)rsc->variant_opaque; -static gboolean -create_child_clone(resource_t *rsc, int sub_id, pe_working_set_t *data_set) -{ - char *inc_num = NULL; - char *inc_max = NULL; - resource_t *child_rsc = NULL; - crm_data_t * child_copy = NULL; - clone_variant_data_t *clone_data = NULL; - get_clone_variant_data(clone_data, rsc); - - CRM_CHECK(clone_data->xml_obj_child != NULL, return FALSE); - - inc_num = crm_itoa(sub_id); - inc_max = crm_itoa(clone_data->clone_max); - - child_copy = copy_xml(clone_data->xml_obj_child); - - crm_xml_add(child_copy, XML_RSC_ATTR_INCARNATION, inc_num); - - if(common_unpack(child_copy, &child_rsc, - rsc, data_set) == FALSE) { - pe_err("Failed unpacking resource %s", - crm_element_value(child_copy, XML_ATTR_ID)); - return FALSE; - } -/* child_rsc->parent = clone_data->self; */ - - crm_debug_3("Setting clone attributes for: %s", child_rsc->id); - clone_data->child_list = g_list_append( - clone_data->child_list, child_rsc); - - add_hash_param(child_rsc->meta, XML_RSC_ATTR_INCARNATION_MAX, inc_max); - - print_resource(LOG_DEBUG_3, "Added", child_rsc, FALSE); - - crm_free(inc_num); - crm_free(inc_max); - - return TRUE; -} - -gboolean clone_unpack(resource_t *rsc, pe_working_set_t *data_set) -{ - int lpc = 0; - crm_data_t *xml_tmp = NULL; - crm_data_t *xml_self = NULL; - crm_data_t *xml_obj = rsc->xml; - clone_variant_data_t *clone_data = NULL; - resource_t *self = NULL; - - const char *ordered = g_hash_table_lookup( - rsc->meta, XML_RSC_ATTR_ORDERED); - const char *interleave = g_hash_table_lookup( - rsc->meta, XML_RSC_ATTR_INTERLEAVE); - const char *max_clones = g_hash_table_lookup( - rsc->meta, XML_RSC_ATTR_INCARNATION_MAX); - const char *max_clones_node = g_hash_table_lookup( - rsc->meta, XML_RSC_ATTR_INCARNATION_NODEMAX); - - crm_debug_3("Processing resource %s...", rsc->id); - - crm_malloc0(clone_data, sizeof(clone_variant_data_t)); - rsc->variant_opaque = clone_data; - clone_data->child_list = NULL; - clone_data->interleave = FALSE; - clone_data->ordered = FALSE; - - clone_data->active_clones = 0; - clone_data->xml_obj_child = NULL; - clone_data->clone_node_max = crm_parse_int(max_clones_node,"1"); - - clone_data->clone_max = crm_parse_int(max_clones, "-1"); - if(clone_data->clone_max < 0) { - clone_data->clone_max = g_list_length(data_set->nodes); - } - if(crm_is_true(interleave)) { - clone_data->interleave = TRUE; - } - if(crm_is_true(ordered)) { - clone_data->ordered = TRUE; - } - crm_debug_2("Options for %s", rsc->id); - crm_debug_2("\tClone max: %d", clone_data->clone_max); - crm_debug_2("\tClone node max: %d", clone_data->clone_node_max); - - clone_data->xml_obj_child = find_xml_node( - xml_obj, XML_CIB_TAG_GROUP, FALSE); - - if(clone_data->xml_obj_child == NULL) { - clone_data->xml_obj_child = find_xml_node( - xml_obj, XML_CIB_TAG_RESOURCE, TRUE); - } - - if(clone_data->xml_obj_child == NULL) { - pe_config_err("%s has nothing to clone", rsc->id); - return FALSE; - } - - xml_self = copy_xml(rsc->xml); - /* this is a bit of a hack - but simplifies everything else */ - ha_msg_mod(xml_self, F_XML_TAGNAME, XML_CIB_TAG_RESOURCE); -/* set_id(xml_self, "self", -1); */ - xml_tmp = find_xml_node(xml_obj, "operations", FALSE); - if(xml_tmp != NULL) { - add_node_copy(xml_self, xml_tmp); - } - - if(common_unpack(xml_self, &self, NULL, data_set)) { - clone_data->self = self; - - } else { - crm_log_xml_err(xml_self, "Couldnt unpack dummy child"); - clone_data->self = self; - return FALSE; - } - - clone_data->notify_confirm = clone_data->self->notify; - - for(lpc = 0; lpc < clone_data->clone_max; lpc++) { - create_child_clone(rsc, lpc, data_set); - } - - crm_debug_3("Added %d children to resource %s...", - clone_data->clone_max, rsc->id); - return TRUE; -} - -resource_t * -clone_find_child(resource_t *rsc, const char *id) +void clone_set_cmds(resource_t *rsc) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); - return pe_find_resource(clone_data->child_list, id); -} - -GListPtr clone_children(resource_t *rsc) -{ - clone_variant_data_t *clone_data = NULL; - get_clone_variant_data(clone_data, rsc); - return clone_data->child_list; + clone_data->self->cmds = &resource_class_alloc_functions[clone_data->self->variant]; + slist_iter( + child_rsc, resource_t, clone_data->child_list, lpc, + child_rsc->cmds = &resource_class_alloc_functions[child_rsc->variant]; + child_rsc->cmds->set_cmds(child_rsc); + ); } int clone_num_allowed_nodes(resource_t *rsc) { int num_nodes = 0; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); /* what *should* we return here? */ slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, - int tmp_num_nodes = child_rsc->fns->num_allowed_nodes(child_rsc); + int tmp_num_nodes = child_rsc->cmds->num_allowed_nodes(child_rsc); if(tmp_num_nodes > num_nodes) { num_nodes = tmp_num_nodes; } ); return num_nodes; } static gint sort_rsc_provisional(gconstpointer a, gconstpointer b) { const resource_t *resource1 = (const resource_t*)a; const resource_t *resource2 = (const resource_t*)b; CRM_ASSERT(resource1 != NULL); CRM_ASSERT(resource2 != NULL); if(resource1->provisional == resource2->provisional) { return 0; } else if(resource1->provisional) { return 1; } else if(resource2->provisional) { return -1; } CRM_CHECK(FALSE, return 0); return 0; } static gboolean can_run_resources(node_t *node) { if(node->details->online == FALSE || node->details->unclean || node->details->standby) { return FALSE; } return TRUE; } static GListPtr next_color(GListPtr head, GListPtr iter, int max) { color_t *color = NULL; GListPtr local_iter = iter; crm_debug_4("Checking iter: %p", iter); if(local_iter != NULL) { local_iter = local_iter->next; } for(; local_iter != NULL; local_iter = local_iter->next) { color = local_iter->data; crm_debug_5("Color %d: %d", color->details->id, color->details->num_resources); if(color->details->num_resources < max) { return local_iter; } } local_iter = head; crm_debug_4("Now checking head: %p", head); for(; local_iter != NULL; local_iter = local_iter->next) { color = local_iter->data; crm_debug_5("Color %d: %d", color->details->id, color->details->num_resources); if(color->details->num_resources < max) { return local_iter; } } crm_debug_3("Nothing available: %p", head); return NULL; } extern void group_assign_color(resource_t *rsc, color_t *group_color); color_t * clone_color(resource_t *rsc, pe_working_set_t *data_set) { GListPtr color_ptr = NULL; GListPtr child_colors = NULL; int local_node_max = 0; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); if(clone_data->self->provisional == FALSE) { return NULL; } local_node_max = clone_data->clone_node_max; - clone_data->max_nodes = rsc->fns->num_allowed_nodes(rsc); + clone_data->max_nodes = rsc->cmds->num_allowed_nodes(rsc); /* give already allocated resources every chance to run on the node * specified. other resources can be moved/started where we want * as required */ clone_data->child_list = g_list_sort( clone_data->child_list, sort_rsc_provisional); crm_debug_2("Coloring children of: %s", rsc->id); if(rsc->stickiness <= 0) { while(local_node_max > 1 && clone_data->max_nodes * (local_node_max -1) >= clone_data->clone_max) { local_node_max--; crm_debug("Dropped the effective value of" " clone_node_max to: %d", local_node_max); } } clone_data->self->allowed_nodes = g_list_sort( clone_data->self->allowed_nodes, sort_node_weight); slist_iter(a_node, node_t, clone_data->self->allowed_nodes, lpc, color_t *new_color = NULL; if(can_run_resources(a_node) == FALSE) { crm_debug_2("Node cant run resources: %s", a_node->details->uname); continue; } crm_debug_3("Processing node %s for: %s", a_node->details->uname, rsc->id); new_color = create_color(data_set, NULL, NULL); new_color->details->candidate_nodes = g_list_append( NULL, node_copy(a_node)); slist_iter(child, resource_t, clone_data->child_list, lpc2, node_t *current = NULL; if(child->provisional == FALSE) { CRM_CHECK(child->color != NULL, continue); current = child->color->details->chosen_node; } else if(child->running_on != NULL) { current = child->running_on->data; } if(current == NULL) { crm_debug_2("Not active: %s", child->id); continue; } else if(current->details->online == FALSE || current->details->unclean || current->details->shutdown) { crm_debug_2("Unavailable node: %s", child->id); continue; } else if(current->details != a_node->details) { crm_debug_2("Wrong node: %s", child->id); continue; } else if(child->provisional == FALSE) { /* make sure it shows up */ native_assign_color(child, new_color); crm_debug("Previously colored: %s", child->id); continue; } else if(g_list_length(child->running_on) != 1) { crm_debug("active != 1: %s", child->id); continue; } else if(new_color->details->num_resources >= local_node_max) { crm_warn("Node %s too full for: %s", a_node->details->uname, child->id); continue; } crm_debug_2("Assigning color: %s", child->id); native_assign_color(child, new_color); ); native_assign_color(rsc, new_color); child_colors = g_list_append(child_colors, new_color); ); while(local_node_max > 1 && clone_data->max_nodes * (local_node_max -1) >= clone_data->clone_max) { local_node_max--; crm_debug("Dropped the effective value of clone_node_max to: %d", local_node_max); } /* allocate the rest */ slist_iter(child, resource_t, clone_data->child_list, lpc2, if(child->provisional == FALSE) { crm_debug_2("Skipping allocated resource: %s", child->id); continue; } crm_debug_2("Processing unalloc'd resource: %s", child->id); color_ptr = next_color( child_colors, color_ptr, local_node_max); if(child->variant == pe_native) { native_assign_color(child, color_ptr?color_ptr->data:data_set->no_color); } else if(child->variant == pe_group) { group_assign_color(child, color_ptr?color_ptr->data:data_set->no_color); } else { crm_err("Bad variant: %d", child->variant); } ); clone_data->self->provisional = FALSE; return NULL; } static void clone_update_pseudo_status( resource_t *child, gboolean *stopping, gboolean *starting) { CRM_ASSERT(stopping != NULL); CRM_ASSERT(starting != NULL); slist_iter( action, action_t, child->actions, lpc, if(*starting && *stopping) { return; } else if(action->optional) { crm_debug_3("Skipping optional: %s", action->uuid); continue; } else if(action->pseudo == FALSE && action->runnable == FALSE){ crm_debug_3("Skipping unrunnable: %s", action->uuid); continue; } else if(safe_str_eq(CRMD_ACTION_STOP, action->task)) { crm_debug_2("Stopping due to: %s", action->uuid); *stopping = TRUE; } else if(safe_str_eq(CRMD_ACTION_START, action->task)) { if(action->runnable == FALSE) { crm_debug_3("Skipping pseduo-op: %s run=%d, pseudo=%d", action->uuid, action->runnable, action->pseudo); } else { crm_debug_2("Starting due to: %s", action->uuid); crm_debug_3("%s run=%d, pseudo=%d", action->uuid, action->runnable, action->pseudo); *starting = TRUE; } } ); } void clone_create_actions(resource_t *rsc, pe_working_set_t *data_set) { gboolean child_starting = FALSE; gboolean child_stopping = FALSE; action_t *stop = NULL; action_t *start = NULL; action_t *action_complete = NULL; resource_t *last_start_rsc = NULL; resource_t *last_stop_rsc = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, - child_rsc->fns->create_actions(child_rsc, data_set); + child_rsc->cmds->create_actions(child_rsc, data_set); clone_update_pseudo_status( child_rsc, &child_stopping, &child_starting); if(child_rsc->starting) { last_start_rsc = child_rsc; } if(child_rsc->stopping) { last_stop_rsc = child_rsc; } ); /* start */ start = start_action(clone_data->self, NULL, !child_starting); action_complete = custom_action( clone_data->self, started_key(rsc), CRMD_ACTION_STARTED, NULL, !child_starting, TRUE, data_set); start->pseudo = TRUE; action_complete->pseudo = TRUE; action_complete->priority = INFINITY; child_starting_constraints(clone_data, pe_ordering_optional, NULL, last_start_rsc, data_set); clone_create_notifications( rsc, start, action_complete, data_set); /* stop */ stop = stop_action(clone_data->self, NULL, !child_stopping); action_complete = custom_action( clone_data->self, stopped_key(rsc), CRMD_ACTION_STOPPED, NULL, !child_stopping, TRUE, data_set); stop->pseudo = TRUE; action_complete->pseudo = TRUE; action_complete->priority = INFINITY; child_stopping_constraints(clone_data, pe_ordering_optional, NULL, last_stop_rsc, data_set); clone_create_notifications(rsc, stop, action_complete, data_set); rsc->actions = clone_data->self->actions; if(stop->post_notified != NULL && start->pre_notify != NULL) { order_actions(stop->post_notified, start->pre_notify, pe_ordering_optional); } } void clone_create_notifications( resource_t *rsc, action_t *action, action_t *action_complete, pe_working_set_t *data_set) { /* * pre_notify -> pre_notify_complete -> pseudo_action * -> (real actions) -> pseudo_action_complete * -> post_notify -> post_notify_complete * * if the pre_noitfy requires confirmation, * then a list of confirmations will be added as triggers * to pseudo_action in clone_expand() */ action_t *notify = NULL; action_t *notify_complete = NULL; enum action_tasks task; char *notify_key = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); if(rsc->notify == FALSE) { return; } task = text2task(action->task); /* create pre_notify */ notify_key = generate_notify_key( clone_data->self->id, "pre", action->task); notify = custom_action(clone_data->self, notify_key, CRMD_ACTION_NOTIFY, NULL, action->optional, TRUE, data_set); add_hash_param(notify->meta, "notify_type", "pre"); add_hash_param(notify->meta, "notify_operation", action->task); if(clone_data->notify_confirm) { add_hash_param(notify->meta, "notify_confirm", "yes"); } else { add_hash_param(notify->meta, "notify_confirm", "no"); } notify->pseudo = TRUE; /* create pre_notify_complete */ notify_key = generate_notify_key( clone_data->self->id, "confirmed-pre", action->task); notify_complete = custom_action(clone_data->self, notify_key, CRMD_ACTION_NOTIFIED, NULL, action->optional, TRUE, data_set); add_hash_param(notify_complete->meta, "notify_type", "pre"); add_hash_param(notify_complete->meta, "notify_operation", action->task); if(clone_data->notify_confirm) { add_hash_param(notify->meta, "notify_confirm", "yes"); } else { add_hash_param(notify->meta, "notify_confirm", "no"); } notify->pseudo = TRUE; notify_complete->pseudo = TRUE; /* pre_notify before pre_notify_complete */ custom_action_order( clone_data->self, NULL, notify, clone_data->self, NULL, notify_complete, pe_ordering_manditory, data_set); /* pre_notify_complete before action */ custom_action_order( clone_data->self, NULL, notify_complete, clone_data->self, NULL, action, pe_ordering_manditory, data_set); action->pre_notify = notify; action->pre_notified = notify_complete; /* create post_notify */ notify_key = generate_notify_key (clone_data->self->id, "post", action->task); notify = custom_action(clone_data->self, notify_key, CRMD_ACTION_NOTIFY, NULL, action_complete->optional, TRUE, data_set); add_hash_param(notify->meta, "notify_type", "post"); add_hash_param(notify->meta, "notify_operation", action->task); if(clone_data->notify_confirm) { add_hash_param(notify->meta, "notify_confirm", "yes"); } else { add_hash_param(notify->meta, "notify_confirm", "no"); } notify->pseudo = TRUE; /* action_complete before post_notify */ custom_action_order( clone_data->self, NULL, action_complete, clone_data->self, NULL, notify, pe_ordering_postnotify, data_set); /* create post_notify_complete */ notify_key = generate_notify_key( clone_data->self->id, "confirmed-post", action->task); notify_complete = custom_action(clone_data->self, notify_key, CRMD_ACTION_NOTIFIED, NULL, action->optional, TRUE, data_set); add_hash_param(notify_complete->meta, "notify_type", "pre"); add_hash_param(notify_complete->meta, "notify_operation", action->task); if(clone_data->notify_confirm) { add_hash_param(notify->meta, "notify_confirm", "yes"); } else { add_hash_param(notify->meta, "notify_confirm", "no"); } notify_complete->pseudo = TRUE; /* post_notify before post_notify_complete */ custom_action_order( clone_data->self, NULL, notify, clone_data->self, NULL, notify_complete, pe_ordering_manditory, data_set); action->post_notify = notify; action->post_notified = notify_complete; if(safe_str_eq(action->task, CRMD_ACTION_STOP)) { /* post_notify_complete before start */ custom_action_order( clone_data->self, NULL, notify_complete, clone_data->self, start_key(clone_data->self), NULL, pe_ordering_optional, data_set); } else if(safe_str_eq(action->task, CRMD_ACTION_START)) { /* post_notify_complete before promote */ custom_action_order( clone_data->self, NULL, notify_complete, clone_data->self, promote_key(clone_data->self), NULL, pe_ordering_optional, data_set); } else if(safe_str_eq(action->task, CRMD_ACTION_DEMOTE)) { /* post_notify_complete before promote */ custom_action_order( clone_data->self, NULL, notify_complete, clone_data->self, stop_key(clone_data->self), NULL, pe_ordering_optional, data_set); } } void child_starting_constraints( clone_variant_data_t *clone_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set) { if(clone_data->ordered || clone_data->self->restart_type == pe_restart_restart) { type = pe_ordering_manditory; } if(child == NULL) { if(clone_data->ordered && last != NULL) { crm_debug_4("Ordered version (last node)"); /* last child start before global started */ custom_action_order( last, start_key(last), NULL, clone_data->self, started_key(clone_data->self), NULL, type, data_set); } } else if(clone_data->ordered) { crm_debug_4("Ordered version"); if(last == NULL) { /* global start before first child start */ last = clone_data->self; } /* else: child/child relative start */ order_start_start(last, child, type); } else { crm_debug_4("Un-ordered version"); /* child start before global started */ custom_action_order( child, start_key(child), NULL, clone_data->self, started_key(clone_data->self), NULL, type, data_set); /* global start before child start */ /* order_start_start(clone_data->self, child, type); */ order_start_start( clone_data->self, child, pe_ordering_manditory); } } void child_stopping_constraints( clone_variant_data_t *clone_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set) { if(clone_data->ordered || clone_data->self->restart_type == pe_restart_restart) { type = pe_ordering_manditory; } if(child == NULL) { if(clone_data->ordered && last != NULL) { crm_debug_4("Ordered version (last node)"); /* global stop before first child stop */ order_stop_stop(clone_data->self, last, pe_ordering_manditory); } } else if(clone_data->ordered && last != NULL) { crm_debug_4("Ordered version"); /* child/child relative stop */ order_stop_stop(child, last, type); } else if(clone_data->ordered) { crm_debug_4("Ordered version (1st node)"); /* first child stop before global stopped */ custom_action_order( child, stop_key(child), NULL, clone_data->self, stopped_key(clone_data->self), NULL, type, data_set); } else { crm_debug_4("Un-ordered version"); /* child stop before global stopped */ custom_action_order( child, stop_key(child), NULL, clone_data->self, stopped_key(clone_data->self), NULL, type, data_set); /* global stop before child stop */ order_stop_stop(clone_data->self, child, type); } } void clone_internal_constraints(resource_t *rsc, pe_working_set_t *data_set) { resource_t *last_rsc = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); - clone_data->self->fns->internal_constraints(clone_data->self, data_set); + clone_data->self->cmds->internal_constraints(clone_data->self, data_set); /* global stop before stopped */ custom_action_order( clone_data->self, stop_key(clone_data->self), NULL, clone_data->self, stopped_key(clone_data->self), NULL, pe_ordering_optional, data_set); /* global start before started */ custom_action_order( clone_data->self, start_key(clone_data->self), NULL, clone_data->self, started_key(clone_data->self), NULL, pe_ordering_optional, data_set); /* global stopped before start */ custom_action_order( clone_data->self, stopped_key(clone_data->self), NULL, clone_data->self, start_key(clone_data->self), NULL, pe_ordering_optional, data_set); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, - child_rsc->fns->internal_constraints(child_rsc, data_set); + child_rsc->cmds->internal_constraints(child_rsc, data_set); child_starting_constraints( clone_data, pe_ordering_optional, child_rsc, last_rsc, data_set); child_stopping_constraints( clone_data, pe_ordering_optional, child_rsc, last_rsc, data_set); last_rsc = child_rsc; ); child_starting_constraints( clone_data, pe_ordering_optional, NULL, last_rsc, data_set); child_stopping_constraints( clone_data, pe_ordering_optional, NULL, last_rsc, data_set); } void clone_rsc_colocation_lh( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { gboolean do_interleave = FALSE; resource_t *rsc = constraint->rsc_lh; clone_variant_data_t *clone_data = NULL; clone_variant_data_t *clone_data_rh = NULL; if(rsc == NULL) { pe_err("rsc_lh was NULL for %s", constraint->id); return; } else if(constraint->rsc_rh == NULL) { pe_err("rsc_rh was NULL for %s", constraint->id); return; } else { crm_debug_4("Processing constraints from %s", rsc->id); } get_clone_variant_data(clone_data, rsc); if(constraint->rsc_rh->variant == pe_clone) { get_clone_variant_data( clone_data_rh, constraint->rsc_rh); if(clone_data->clone_node_max != clone_data_rh->clone_node_max) { pe_err("Cannot interleave "XML_CIB_TAG_INCARNATION " %s and %s because" " they do not support the same number of" " resources per node", constraint->rsc_lh->id, constraint->rsc_rh->id); /* only the LHS side needs to be labeled as interleave */ } else if(clone_data->interleave) { do_interleave = TRUE; } else if(constraint->strength != pecs_must_not) { pe_warn("rsc_colocations other than \"-INFINITY\"" " are not supported for non-interleaved " XML_CIB_TAG_INCARNATION" resources"); return; } } else if(constraint->strength != pecs_must_not) { pe_warn("Co-location scores other than \"-INFINITY\" are not " " allowed for non-"XML_CIB_TAG_INCARNATION" resources"); return; } if(do_interleave) { resource_t *child_lh = NULL; resource_t *child_rh = NULL; GListPtr iter_lh = clone_data->child_list; GListPtr iter_rh = clone_data_rh->child_list; crm_debug_2("Interleaving %s with %s", constraint->rsc_lh->id, constraint->rsc_rh->id); /* If the resource have different numbers of incarnations, * then just do as many as are available */ while(iter_lh != NULL && iter_rh != NULL) { child_lh = iter_lh->data; child_rh = iter_rh->data; iter_lh = iter_lh->next; iter_rh = iter_rh->next; crm_debug_3("Colocating %s with %s", child_lh->id, child_rh->id); - child_lh->fns->rsc_colocation_lh(child_lh, child_rh, constraint); + child_lh->cmds->rsc_colocation_lh(child_lh, child_rh, constraint); } return; } slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, print_resource(LOG_DEBUG_3, "LHS", child_rsc, TRUE); - child_rsc->fns->rsc_colocation_lh(child_rsc, constraint->rsc_rh, constraint); + child_rsc->cmds->rsc_colocation_lh(child_rsc, constraint->rsc_rh, constraint); ); } void clone_rsc_colocation_rh( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { clone_variant_data_t *clone_data = NULL; CRM_CHECK(rsc_lh != NULL, return); CRM_CHECK(rsc_lh->variant == pe_native, return); crm_debug_3("Processing RH of constraint %s", constraint->id); if(rsc_rh == NULL) { pe_err("rsc_rh was NULL for %s", constraint->id); return; } else if(constraint->strength != pecs_must_not) { pe_warn("rsc_dependencies other than \"must_not\" " "are not supported for clone resources"); return; } else { print_resource(LOG_DEBUG_3, "LHS", rsc_lh, FALSE); } get_clone_variant_data(clone_data, rsc_rh); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, print_resource(LOG_DEBUG_3, "RHS", child_rsc, FALSE); - child_rsc->fns->rsc_colocation_rh(rsc_lh, child_rsc, constraint); + child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint); ); } void clone_rsc_order_lh(resource_t *rsc, order_constraint_t *order) { char *stop_id = NULL; char *start_id = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); crm_debug_3("Processing LH of ordering constraint %d", order->id); stop_id = stop_key(rsc); start_id = start_key(rsc); if(safe_str_eq(order->lh_action_task, start_id)) { crm_free(order->lh_action_task); order->lh_action_task = started_key(rsc); } else if(safe_str_eq(order->lh_action_task, stop_id)) { crm_free(order->lh_action_task); order->lh_action_task = stopped_key(rsc); } crm_free(start_id); crm_free(stop_id); - clone_data->self->fns->rsc_order_lh(clone_data->self, order); + clone_data->self->cmds->rsc_order_lh(clone_data->self, order); } void clone_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); crm_debug_3("Processing RH of ordering constraint %d", order->id); - clone_data->self->fns->rsc_order_rh(lh_action, clone_data->self, order); + clone_data->self->cmds->rsc_order_rh(lh_action, clone_data->self, order); } void clone_rsc_location(resource_t *rsc, rsc_to_node_t *constraint) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); crm_debug_3("Processing actions from %s", rsc->id); - clone_data->self->fns->rsc_location(clone_data->self, constraint); + clone_data->self->cmds->rsc_location(clone_data->self, constraint); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, - child_rsc->fns->rsc_location(child_rsc, constraint); + child_rsc->cmds->rsc_location(child_rsc, constraint); ); } static gint sort_notify_entries(gconstpointer a, gconstpointer b) { int tmp; const notify_entry_t *entry_a = a; const notify_entry_t *entry_b = b; if(entry_a == NULL && entry_b == NULL) { return 0; } if(entry_a == NULL) { return 1; } if(entry_b == NULL) { return -1; } if(entry_a->rsc == NULL && entry_b->rsc == NULL) { return 0; } if(entry_a->rsc == NULL) { return 1; } if(entry_b->rsc == NULL) { return -1; } tmp = strcmp(entry_a->rsc->id, entry_b->rsc->id); if(tmp != 0) { return tmp; } if(entry_a->node == NULL && entry_b->node == NULL) { return 0; } if(entry_a->node == NULL) { return 1; } if(entry_b->node == NULL) { return -1; } return strcmp(entry_a->node->details->id, entry_b->node->details->id); } static void expand_list(GListPtr list, int clones, char **rsc_list, char **node_list, char **uuid_list) { int rsc_len = 0; int node_len = 0; int list_len = 100 * clones; char *rsc_list_s = NULL; char *node_list_s = NULL; const char *uname = NULL; const char *rsc_id = NULL; const char *last_rsc_id = NULL; clone_expand_reallocate: if(rsc_list != NULL) { crm_free(*rsc_list); crm_malloc0(*rsc_list, list_len); CRM_ASSERT(*rsc_list != NULL); rsc_list_s = *rsc_list; rsc_len = 0; } if(node_list != NULL) { crm_free(*node_list); crm_malloc0(*node_list, list_len); CRM_ASSERT(*node_list != NULL); node_list_s = *node_list; node_len = 0; } /* keep BEAM extra happy */ if(rsc_list_s == NULL || node_list_s == NULL) { return; } slist_iter(entry, notify_entry_t, list, lpc, rsc_id = entry->rsc->id; CRM_CHECK(rsc_id != NULL, rsc_id = "__none__"); uname = NULL; if(entry->node) { uname = entry->node->details->uname; } CRM_CHECK(uname != NULL, uname = "__none__"); /* filter dups */ if(safe_str_eq(rsc_id, last_rsc_id)) { continue; } last_rsc_id = rsc_id; if(rsc_list != NULL) { if(rsc_len + 1 + strlen(rsc_id) >= list_len) { list_len *= 2; goto clone_expand_reallocate; } sprintf(rsc_list_s, "%s ", rsc_id); rsc_list_s += strlen(rsc_id); rsc_len += strlen(rsc_id); rsc_list_s++; rsc_len++; } if(node_list != NULL) { if(node_len + 1 + strlen(uname) >= list_len) { list_len *= 2; goto clone_expand_reallocate; } sprintf(node_list_s, "%s ", uname); node_list_s += strlen(uname); node_len += strlen(uname); node_list_s++; node_len++; } ); } void clone_expand(resource_t *rsc, pe_working_set_t *data_set) { char *rsc_list = NULL; char *node_list = NULL; char *uuid_list = NULL; notify_data_t *n_data = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); crm_malloc0(n_data, sizeof(notify_data_t)); n_data->keys = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); crm_debug_2("Processing actions from %s", rsc->id); if(rsc->notify) { slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, slist_iter( op, action_t, clone_data->self->actions, lpc2, - child_rsc->fns->create_notify_element( + child_rsc->cmds->create_notify_element( child_rsc, op, n_data, data_set); ); ); } /* expand the notify data */ if(rsc->notify && n_data->stop) { n_data->stop = g_list_sort( n_data->stop, sort_notify_entries); rsc_list = NULL; node_list = NULL; expand_list(n_data->stop, clone_data->clone_max, &rsc_list, &node_list, &uuid_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_stop_resource"), rsc_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_stop_uname"), node_list); } if(rsc->notify && n_data->start) { n_data->start = g_list_sort( n_data->start, sort_notify_entries); rsc_list = NULL; node_list = NULL; expand_list(n_data->start, clone_data->clone_max, &rsc_list, &node_list, &uuid_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_start_resource"), rsc_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_start_uname"), node_list); } if(rsc->notify && n_data->demote) { n_data->demote = g_list_sort( n_data->demote, sort_notify_entries); rsc_list = NULL; node_list = NULL; expand_list(n_data->demote, clone_data->clone_max, &rsc_list, &node_list, &uuid_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_demote_resource"), rsc_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_demote_uname"), node_list); } if(rsc->notify && n_data->promote) { n_data->promote = g_list_sort( n_data->promote, sort_notify_entries); rsc_list = NULL; node_list = NULL; uuid_list = NULL; expand_list(n_data->promote, clone_data->clone_max, &rsc_list, &node_list, &uuid_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_promote_resource"), rsc_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_promote_uname"), node_list); } if(rsc->notify && n_data->active) { n_data->active = g_list_sort( n_data->active, sort_notify_entries); rsc_list = NULL; node_list = NULL; uuid_list = NULL; expand_list(n_data->active, clone_data->clone_max, &rsc_list, &node_list, &uuid_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_active_resource"), rsc_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_active_uname"), node_list); } if(rsc->notify && n_data->slave) { n_data->slave = g_list_sort( n_data->slave, sort_notify_entries); rsc_list = NULL; node_list = NULL; uuid_list = NULL; expand_list(n_data->slave, clone_data->clone_max, &rsc_list, &node_list, &uuid_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_slave_resource"), rsc_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_slave_uname"), node_list); } if(rsc->notify && n_data->master) { n_data->master = g_list_sort( n_data->master, sort_notify_entries); rsc_list = NULL; node_list = NULL; uuid_list = NULL; expand_list(n_data->master, clone_data->clone_max, &rsc_list, &node_list, &uuid_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_master_resource"), rsc_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_master_uname"), node_list); } if(rsc->notify && n_data->inactive) { n_data->inactive = g_list_sort( n_data->inactive, sort_notify_entries); rsc_list = NULL; node_list = NULL; uuid_list = NULL; expand_list(n_data->inactive, clone_data->clone_max, &rsc_list, &node_list, &uuid_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_inactive_resource"), rsc_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_inactive_uname"), node_list); } /* yes, we DO need this second loop */ slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, - child_rsc->fns->expand(child_rsc, data_set); + child_rsc->cmds->expand(child_rsc, data_set); ); /* slist_iter( */ /* action, action_t, clone_data->self->actions, lpc2, */ /* if(safe_str_eq(action->task, CRMD_ACTION_NOTIFY)) { */ /* action->meta_xml = notify_xml; */ /* } */ /* ); */ - clone_data->self->fns->expand(clone_data->self, data_set); + clone_data->self->cmds->expand(clone_data->self, data_set); /* destroy the notify_data */ pe_free_shallow(n_data->stop); pe_free_shallow(n_data->start); pe_free_shallow(n_data->demote); pe_free_shallow(n_data->promote); pe_free_shallow(n_data->master); pe_free_shallow(n_data->slave); pe_free_shallow(n_data->active); pe_free_shallow(n_data->inactive); g_hash_table_destroy(n_data->keys); crm_free(n_data); } -gboolean clone_active(resource_t *rsc, gboolean all) -{ - clone_variant_data_t *clone_data = NULL; - get_clone_variant_data(clone_data, rsc); - - slist_iter( - child_rsc, resource_t, clone_data->child_list, lpc, - gboolean child_active = child_rsc->fns->active(child_rsc, all); - if(all == FALSE && child_active) { - return TRUE; - } else if(all && child_active == FALSE) { - return FALSE; - } - ); - if(all) { - return TRUE; - } else { - return FALSE; - } -} - -void clone_print( - resource_t *rsc, const char *pre_text, long options, void *print_data) -{ - const char *child_text = NULL; - clone_variant_data_t *clone_data = NULL; - get_clone_variant_data(clone_data, rsc); - if(pre_text != NULL) { - child_text = " "; - } else { - child_text = " "; - } - - if(rsc->variant == pe_master) { - status_print("%sMaster/Slave Set: %s", - pre_text?pre_text:"", clone_data->self->id); - - } else { - status_print("%sClone Set: %s", - pre_text?pre_text:"", clone_data->self->id); - } - - if(options & pe_print_html) { - status_print("\n
    \n"); - - } else if((options & pe_print_log) == 0) { - status_print("\n"); - } - - slist_iter( - child_rsc, resource_t, clone_data->child_list, lpc, - - if(options & pe_print_html) { - status_print("
  • \n"); - } - child_rsc->fns->print( - child_rsc, child_text, options, print_data); - if(options & pe_print_html) { - status_print("
  • \n"); - } - ); - - if(options & pe_print_html) { - status_print("
\n"); - } -} - -void clone_free(resource_t *rsc) -{ - clone_variant_data_t *clone_data = NULL; - get_clone_variant_data(clone_data, rsc); - - crm_debug_3("Freeing %s", rsc->id); - - slist_iter( - child_rsc, resource_t, clone_data->child_list, lpc, - - crm_debug_3("Freeing child %s", child_rsc->id); - free_xml(child_rsc->xml); - child_rsc->fns->free(child_rsc); - ); - - crm_debug_3("Freeing child list"); - pe_free_shallow_adv(clone_data->child_list, FALSE); - - if(clone_data->self) { - free_xml(clone_data->self->xml); - clone_data->self->fns->free(clone_data->self); - } - common_free(rsc); -} - void clone_agent_constraints(resource_t *rsc) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, - child_rsc->fns->agent_constraints(child_rsc); + child_rsc->cmds->agent_constraints(child_rsc); ); } -enum rsc_role_e -clone_resource_state(resource_t *rsc) -{ - return RSC_ROLE_UNKNOWN; -} - void clone_create_notify_element(resource_t *rsc, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, - child_rsc->fns->create_notify_element( + child_rsc->cmds->create_notify_element( child_rsc, op, n_data, data_set); ); } static gint sort_rsc_id(gconstpointer a, gconstpointer b) { const resource_t *resource1 = (const resource_t*)a; const resource_t *resource2 = (const resource_t*)b; CRM_ASSERT(resource1 != NULL); CRM_ASSERT(resource2 != NULL); return strcmp(resource1->id, resource2->id); } gboolean clone_create_probe(resource_t *rsc, node_t *node, action_t *complete, gboolean force, pe_working_set_t *data_set) { gboolean any_created = FALSE; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); clone_data->child_list = g_list_sort( clone_data->child_list, sort_rsc_id); if(rsc->globally_unique == FALSE && clone_data->clone_node_max == 1) { /* only look for one copy */ slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, if(pe_find_node_id(child_rsc->running_on, node->details->id)) { - return child_rsc->fns->create_probe( + return child_rsc->cmds->create_probe( child_rsc, node, complete, force, data_set); } ); } slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, - if(child_rsc->fns->create_probe( + if(child_rsc->cmds->create_probe( child_rsc, node, complete, force, data_set)) { any_created = TRUE; } if(any_created && rsc->globally_unique == FALSE && clone_data->clone_node_max == 1) { /* only look for one copy (clone :0) */ break; } ); return any_created; } void clone_stonith_ordering( resource_t *rsc, action_t *stonith_op, pe_working_set_t *data_set) { gboolean is_fencing = FALSE; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, const char *class = crm_element_value( child_rsc->xml, XML_AGENT_ATTR_CLASS); if(safe_str_eq(class, "stonith")) { is_fencing = TRUE; break; } ); if(is_fencing && stonith_op != NULL) { char *key = started_key(rsc); crm_debug("Ordering %s before stonith op", key); custom_action_order( rsc, key, NULL, NULL, crm_strdup(CRM_OP_FENCE), stonith_op, pe_ordering_optional, data_set); } } diff --git a/crm/pengine/color.c b/crm/pengine/color.c deleted file mode 100644 index e7dcb3d85c..0000000000 --- a/crm/pengine/color.c +++ /dev/null @@ -1,79 +0,0 @@ -/* $Id: color.c,v 1.35 2005/10/24 07:48:00 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 - -color_t *add_color(resource_t *rh_resource, color_t *color); - -gboolean -apply_placement_constraints(pe_working_set_t *data_set) -{ - crm_debug_3("Applying constraints..."); - slist_iter( - cons, rsc_to_node_t, data_set->placement_constraints, lpc, - - cons->rsc_lh->fns->rsc_location(cons->rsc_lh, cons); - ); - - return TRUE; - -} - -color_t * -add_color(resource_t *resource, color_t *color) -{ - color_t *local_color = NULL; - - if(color == NULL) { - pe_err("Cannot add NULL color"); - return NULL; - } - - local_color = find_color(resource->candidate_colors, color); - - if(local_color == NULL) { - crm_debug_4("Adding color %d", color->id); - - local_color = copy_color(color); - resource->candidate_colors = - g_list_append(resource->candidate_colors, local_color); - - } else { - crm_debug_4("Color %d already present", color->id); - } - - return local_color; -} - - - - - diff --git a/crm/pengine/complex.c b/crm/pengine/complex.c deleted file mode 100644 index 2c4c016bc1..0000000000 --- a/crm/pengine/complex.c +++ /dev/null @@ -1,622 +0,0 @@ -/* $Id: complex.c,v 1.95 2006/05/30 09:24:03 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 - -gboolean update_node_weight(rsc_to_node_t *cons,const char *id,GListPtr nodes); -gboolean is_active(rsc_to_node_t *cons); -gboolean constraint_violated( - resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint); - -extern gboolean rsc_colocation_new(const char *id, enum con_strength strength, - resource_t *rsc_lh, resource_t *rsc_rh); -rsc_to_node_t *generate_location_rule( - resource_t *rsc, crm_data_t *location_rule, pe_working_set_t *data_set); - -void populate_hash(crm_data_t *nvpair_list, GHashTable *hash, - const char **attrs, int attrs_length); - -resource_object_functions_t resource_class_functions[] = { - { - native_unpack, - native_find_child, - native_num_allowed_nodes, - native_color, - native_create_actions, - native_create_probe, - native_internal_constraints, - native_agent_constraints, - native_rsc_colocation_lh, - native_rsc_colocation_rh, - native_rsc_order_lh, - native_rsc_order_rh, - native_rsc_location, - native_expand, - native_children, - native_stonith_ordering, - native_parameter, - native_print, - native_active, - native_resource_state, - native_create_notify_element, - native_free - }, - { - group_unpack, - group_find_child, - group_num_allowed_nodes, - group_color, - group_create_actions, - group_create_probe, - group_internal_constraints, - group_agent_constraints, - group_rsc_colocation_lh, - group_rsc_colocation_rh, - group_rsc_order_lh, - group_rsc_order_rh, - group_rsc_location, - group_expand, - group_children, - group_stonith_ordering, - native_parameter, - group_print, - group_active, - group_resource_state, - group_create_notify_element, - group_free - }, - { - clone_unpack, - clone_find_child, - clone_num_allowed_nodes, - clone_color, - clone_create_actions, - clone_create_probe, - clone_internal_constraints, - clone_agent_constraints, - clone_rsc_colocation_lh, - clone_rsc_colocation_rh, - clone_rsc_order_lh, - clone_rsc_order_rh, - clone_rsc_location, - clone_expand, - clone_children, - clone_stonith_ordering, - native_parameter, - clone_print, - clone_active, - clone_resource_state, - clone_create_notify_element, - clone_free - }, - { - master_unpack, - clone_find_child, - clone_num_allowed_nodes, - clone_color, - master_create_actions, - clone_create_probe, - master_internal_constraints, - clone_agent_constraints, - clone_rsc_colocation_lh, - clone_rsc_colocation_rh, - clone_rsc_order_lh, - clone_rsc_order_rh, - clone_rsc_location, - clone_expand, - clone_children, - clone_stonith_ordering, - native_parameter, - clone_print, - clone_active, - clone_resource_state, - clone_create_notify_element, - clone_free - } -}; - -int get_resource_type(const char *name) -{ - if(safe_str_eq(name, XML_CIB_TAG_RESOURCE)) { - return pe_native; - - } else if(safe_str_eq(name, XML_CIB_TAG_GROUP)) { - return pe_group; - - } else if(safe_str_eq(name, XML_CIB_TAG_INCARNATION)) { - return pe_clone; - - } else if(safe_str_eq(name, XML_CIB_TAG_MASTER)) { - return pe_master; - } - - return pe_unknown; -} - -gboolean -is_active(rsc_to_node_t *cons) -{ - /* todo: check constraint lifetime */ - return TRUE; -} - -static void dup_attr(gpointer key, gpointer value, gpointer user_data) -{ - add_hash_param(user_data, key, value); -} - -gboolean -common_unpack(crm_data_t * xml_obj, resource_t **rsc, - resource_t *parent, pe_working_set_t *data_set) -{ - const char *value = NULL; - const char *id = crm_element_value(xml_obj, XML_ATTR_ID); - - crm_log_xml_debug_3(xml_obj, "Processing resource input..."); - - if(id == NULL) { - pe_err("Must specify id tag in "); - return FALSE; - - } else if(rsc == NULL) { - pe_err("Nowhere to unpack resource into"); - return FALSE; - - } - crm_malloc0(*rsc, sizeof(resource_t)); - - if(*rsc == NULL) { - return FALSE; - } - - (*rsc)->xml = xml_obj; - (*rsc)->parent = parent; - (*rsc)->ops_xml = find_xml_node(xml_obj, "operations", FALSE); - (*rsc)->variant = get_resource_type(crm_element_name(xml_obj)); - if((*rsc)->variant == pe_unknown) { - pe_err("Unknown resource type: %s", crm_element_name(xml_obj)); - crm_free(*rsc); - return FALSE; - } - - (*rsc)->parameters = g_hash_table_new_full( - g_str_hash,g_str_equal, g_hash_destroy_str,g_hash_destroy_str); - - (*rsc)->meta = g_hash_table_new_full( - g_str_hash,g_str_equal, g_hash_destroy_str,g_hash_destroy_str); - - value = crm_element_value(xml_obj, XML_RSC_ATTR_INCARNATION); - if(value) { - (*rsc)->id = crm_concat(id, value, ':'); - add_hash_param((*rsc)->meta, XML_RSC_ATTR_INCARNATION, value); - - } else { - (*rsc)->id = crm_strdup(id); - } - - if(parent) { - (*rsc)->long_name = crm_concat(parent->long_name, (*rsc)->id, ':'); - } else { - (*rsc)->long_name = crm_strdup((*rsc)->id); - } - - (*rsc)->fns = &resource_class_functions[(*rsc)->variant]; - crm_debug_3("Unpacking resource..."); - - /* meta attributes */ - xml_prop_iter( - xml_obj, prop_name, prop_value, - add_hash_param((*rsc)->meta, prop_name, prop_value); - ); - - unpack_instance_attributes( - xml_obj, XML_TAG_META_SETS, NULL, (*rsc)->meta, - NULL, 0, data_set); - - if(parent != NULL) { - g_hash_table_foreach(parent->meta, dup_attr, (*rsc)->meta); - } - - /* populate from the regular attributes until the GUI can create - * meta attributes - */ - unpack_instance_attributes( - xml_obj, XML_TAG_ATTR_SETS, NULL, (*rsc)->meta, - NULL, 0, data_set); - - if(parent != NULL) { - g_hash_table_foreach( - parent->parameters, dup_attr, (*rsc)->parameters); - } - - if((*rsc)->fns->unpack(*rsc, data_set) == FALSE) { - return FALSE; - } - (*rsc)->runnable = TRUE; - (*rsc)->provisional = TRUE; - (*rsc)->starting = FALSE; - (*rsc)->stopping = FALSE; - - (*rsc)->candidate_colors = NULL; - (*rsc)->rsc_cons = NULL; - (*rsc)->actions = NULL; - (*rsc)->failed = FALSE; - (*rsc)->start_pending = FALSE; - (*rsc)->globally_unique = TRUE; - (*rsc)->role = RSC_ROLE_STOPPED; - (*rsc)->next_role = RSC_ROLE_UNKNOWN; - (*rsc)->is_managed = data_set->is_managed_default; - - (*rsc)->recovery_type = recovery_stop_start; - (*rsc)->stickiness = data_set->default_resource_stickiness; - (*rsc)->fail_stickiness = data_set->default_resource_fail_stickiness; - - value = g_hash_table_lookup((*rsc)->meta, XML_CIB_ATTR_PRIORITY); - (*rsc)->priority = crm_parse_int(value, "0"); - (*rsc)->effective_priority = (*rsc)->priority; - - value = g_hash_table_lookup((*rsc)->meta, XML_RSC_ATTR_NOTIFY); - (*rsc)->notify = crm_is_true(value); - - value = g_hash_table_lookup((*rsc)->meta, "is_managed"); - if(value != NULL && safe_str_neq("default", value)) { - cl_str_to_boolean(value, &((*rsc)->is_managed)); - } - - crm_debug_2("Options for %s", (*rsc)->id); - value = g_hash_table_lookup((*rsc)->meta, "globally_unique"); - if(value != NULL) { - cl_str_to_boolean(value, &((*rsc)->globally_unique)); - } - - value = g_hash_table_lookup((*rsc)->meta, XML_RSC_ATTR_RESTART); - if(safe_str_eq(value, "restart")) { - (*rsc)->restart_type = pe_restart_restart; - crm_debug_2("\tDependancy restart handling: restart"); - - } else { - (*rsc)->restart_type = pe_restart_ignore; - crm_debug_2("\tDependancy restart handling: ignore"); - } - - value = g_hash_table_lookup((*rsc)->meta, "multiple_active"); - if(safe_str_eq(value, "stop_only")) { - (*rsc)->recovery_type = recovery_stop_only; - crm_debug_2("\tMultiple running resource recovery: stop only"); - - } else if(safe_str_eq(value, "block")) { - (*rsc)->recovery_type = recovery_block; - crm_debug_2("\tMultiple running resource recovery: block"); - - } else { - (*rsc)->recovery_type = recovery_stop_start; - crm_debug_2("\tMultiple running resource recovery: stop/start"); - } - - value = g_hash_table_lookup((*rsc)->meta, "resource_stickiness"); - if(value != NULL && safe_str_neq("default", value)) { - (*rsc)->stickiness = char2score(value); - } - if((*rsc)->stickiness > 0) { - crm_debug_2("\tPlacement: prefer current location%s", - value == NULL?" (default)":""); - } else if((*rsc)->stickiness < 0) { - crm_warn("\tPlacement: always move from the current location%s", - value == NULL?" (default)":""); - } else { - crm_debug_2("\tPlacement: optimal%s", - value == NULL?" (default)":""); - } - - value = g_hash_table_lookup( - (*rsc)->meta, XML_RSC_ATTR_FAIL_STICKINESS); - if(value != NULL) { - (*rsc)->fail_stickiness = char2score(value); - } - crm_debug_2("\tNode score per failure: %d%s", - (*rsc)->fail_stickiness, value == NULL?" (default)":""); - - value = g_hash_table_lookup( - (*rsc)->meta, XML_RSC_ATTR_TARGET_ROLE); - - if(value != NULL && safe_str_neq("default", value)) { - (*rsc)->is_managed = TRUE; - (*rsc)->next_role = text2role(value); - if((*rsc)->next_role == RSC_ROLE_UNKNOWN) { - pe_config_err("%s: Unknown value for " - XML_RSC_ATTR_TARGET_ROLE": %s", - (*rsc)->id, value); - } else if((*rsc)->next_role == RSC_ROLE_STOPPED) { - native_assign_color(*rsc, data_set->no_color); - } - } - - crm_debug_2("\tDesired next state: %s", - (*rsc)->next_role!=RSC_ROLE_UNKNOWN?role2text((*rsc)->next_role):"default"); - - if((*rsc)->is_managed == FALSE) { - crm_warn("Resource %s is currently not managed", (*rsc)->id); - - } else if(data_set->symmetric_cluster) { - rsc_to_node_t *new_con = rsc2node_new( - "symmetric_default", *rsc, 0, NULL, data_set); - new_con->node_list_rh = node_list_dup(data_set->nodes, TRUE, FALSE); - } - - crm_debug_2("\tAction notification: %s", - (*rsc)->notify?"required":"not required"); - -/* data_set->resources = g_list_append(data_set->resources, (*rsc)); */ - return TRUE; -} - -void -order_actions( - action_t *lh_action, action_t *rh_action, enum pe_ordering order) -{ - action_wrapper_t *wrapper = NULL; - GListPtr list = NULL; - - crm_debug_2("Ordering Action %s before %s", - lh_action->uuid, rh_action->uuid); - - log_action(LOG_DEBUG_4, "LH (order_actions)", lh_action, FALSE); - log_action(LOG_DEBUG_4, "RH (order_actions)", rh_action, FALSE); - - - crm_malloc0(wrapper, sizeof(action_wrapper_t)); - if(wrapper != NULL) { - wrapper->action = rh_action; - wrapper->type = order; - - list = lh_action->actions_after; - list = g_list_append(list, wrapper); - lh_action->actions_after = list; - wrapper = NULL; - } - if(order != pe_ordering_recover) { - crm_malloc0(wrapper, sizeof(action_wrapper_t)); - if(wrapper != NULL) { - wrapper->action = lh_action; - wrapper->type = order; - list = rh_action->actions_before; - list = g_list_append(list, wrapper); - rh_action->actions_before = list; - } - } -} - - -void common_free(resource_t *rsc) -{ - if(rsc == NULL) { - return; - } - - crm_debug_5("Freeing %s", rsc->id); - - while(rsc->rsc_cons) { - pe_free_rsc_colocation( - (rsc_colocation_t*)rsc->rsc_cons->data); - rsc->rsc_cons = rsc->rsc_cons->next; - } - if(rsc->rsc_cons != NULL) { - g_list_free(rsc->rsc_cons); - } - if(rsc->parameters != NULL) { - g_hash_table_destroy(rsc->parameters); - } - if(rsc->meta != NULL) { - g_hash_table_destroy(rsc->meta); - } - if(rsc->orphan) { - free_xml(rsc->xml); - } - pe_free_shallow_adv(rsc->running_on, FALSE); - pe_free_shallow_adv(rsc->known_on, FALSE); - pe_free_shallow_adv(rsc->candidate_colors, TRUE); - pe_free_shallow_adv(rsc->rsc_location, FALSE); - pe_free_shallow_adv(rsc->allowed_nodes, TRUE); - crm_free(rsc->id); - crm_free(rsc->long_name); - crm_free(rsc->variant_opaque); - crm_free(rsc); - crm_debug_5("Resource freed"); -} - -typedef struct sorted_set_s -{ - const char *name; - int score; - crm_data_t *attr_set; - node_t *node; - GHashTable *hash; - pe_working_set_t *data_set; - int attrs_length; - const char **attrs; -} sorted_set_t; - -static gint -sort_pairs(gconstpointer a, gconstpointer b) -{ - const sorted_set_t *pair_a = a; - const sorted_set_t *pair_b = b; - - if(a == NULL && b == NULL) { - return 0; - } else if(a == NULL) { - return 1; - } else if(b == NULL) { - return -1; - } - - if(safe_str_eq(pair_a->name, CIB_OPTIONS_FIRST)) { - return -1; - - } else if(safe_str_eq(pair_b->name, CIB_OPTIONS_FIRST)) { - return 1; - } - - if(pair_a->score < pair_b->score) { - return 1; - } else if(pair_a->score > pair_b->score) { - return -1; - } - return 0; -} - -static void -unpack_attr_set(gpointer data, gpointer user_data) -{ - sorted_set_t *pair = data; - sorted_set_t *unpack_data = user_data; - crm_data_t *attributes = NULL; - - if(test_ruleset(pair->attr_set, - unpack_data->node, unpack_data->data_set) == FALSE) { - return; - } - - crm_debug_3("Adding attributes from %s", pair->name); - attributes = cl_get_struct(pair->attr_set, XML_TAG_ATTRS); - populate_hash(attributes, unpack_data->hash, - unpack_data->attrs, unpack_data->attrs_length); -} - -static void -free_pair(gpointer data, gpointer user_data) -{ - sorted_set_t *pair = data; - crm_free(pair); -} - -void -unpack_instance_attributes( - crm_data_t *xml_obj, const char *set_name, node_t *node, - GHashTable *hash, const char **attrs, int attrs_length, - pe_working_set_t *data_set) -{ - GListPtr sorted = NULL; - const char *score = NULL; - sorted_set_t *pair = NULL; - - if(xml_obj == NULL) { - crm_debug_4("No instance attributes"); - return; - } - - if(attrs != NULL && attrs[0] == NULL) { - /* none allowed */ - crm_debug_2("No instance attributes allowed"); - return; - } - - crm_debug_4("Checking for attributes"); - xml_child_iter_filter( - xml_obj, attr_set, set_name, - - pair = NULL; - crm_malloc0(pair, sizeof(sorted_set_t)); - pair->name = ID(attr_set); - pair->attr_set = attr_set; - score = crm_element_value(attr_set, XML_RULE_ATTR_SCORE); - pair->score = char2score(score); - - sorted = g_list_prepend(sorted, pair); - - ); - - if(pair != NULL) { - pair->hash = hash; - pair->node = node; - pair->attrs = attrs; - pair->data_set = data_set; - pair->attrs_length = attrs_length; - } - - sorted = g_list_sort(sorted, sort_pairs); - g_list_foreach(sorted, unpack_attr_set, pair); - g_list_foreach(sorted, free_pair, NULL); - g_list_free(sorted); -} - -void -populate_hash(crm_data_t *nvpair_list, GHashTable *hash, - const char **attrs, int attrs_length) -{ - int lpc = 0; - gboolean set_attr = FALSE; - const char *name = NULL; - const char *value = NULL; - xml_child_iter_filter( - nvpair_list, an_attr, XML_CIB_TAG_NVPAIR, - - name = crm_element_value(an_attr, XML_NVPAIR_ATTR_NAME); - - set_attr = TRUE; - - if(attrs != NULL) { - set_attr = FALSE; - } - - for(lpc = 0; set_attr == FALSE && lpc < attrs_length - && attrs[lpc] != NULL; lpc++) { - if(safe_str_eq(name, attrs[lpc])) { - set_attr = TRUE; - } - } - - if(set_attr) { - crm_debug_4("Setting attribute: %s", name); - value = crm_element_value( - an_attr, XML_NVPAIR_ATTR_VALUE); - - add_hash_param(hash, name, value); - - } else { - crm_debug_4("Skipping attribute: %s", name); - } - - ); -} - -void -add_hash_param(GHashTable *hash, const char *name, const char *value) -{ - CRM_CHECK(hash != NULL, return); - - crm_debug_3("adding: name=%s value=%s", crm_str(name), crm_str(value)); - if(name == NULL || value == NULL) { - return; - - } else if(safe_str_eq(value, "#default")) { - return; - - } else if(g_hash_table_lookup(hash, name) == NULL) { - g_hash_table_insert(hash, crm_strdup(name), crm_strdup(value)); - } -} - diff --git a/crm/pengine/graph.c b/crm/pengine/graph.c index 7b6513bcc0..d2eb685da9 100644 --- a/crm/pengine/graph.c +++ b/crm/pengine/graph.c @@ -1,594 +1,591 @@ -/* $Id: graph.c,v 1.96 2006/06/07 07:34:38 andrew Exp $ */ +/* $Id: graph.c,v 1.97 2006/06/07 12:46:57 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 gboolean update_action(action_t *action); gboolean update_action_states(GListPtr actions) { crm_debug_2("Updating %d actions", g_list_length(actions)); slist_iter( action, action_t, actions, lpc, update_action(action); ); return TRUE; } -#define UPDATE_THEM 1 - gboolean update_action(action_t *action) { enum action_tasks task = no_action; crm_debug_3("Processing action %s: %s", action->uuid, action->optional?"optional":"required"); slist_iter( other, action_wrapper_t, action->actions_before, lpc, crm_debug_3("\tChecking action %s: %s/%s", other->action->uuid, ordering_type2text(other->type), other->action->optional?"optional":"required"); if(other->type == pe_ordering_restart && action->rsc->role > RSC_ROLE_STOPPED) { crm_debug_3("Upgrading %s constraint to %s", ordering_type2text(other->type), ordering_type2text(pe_ordering_manditory)); other->type = pe_ordering_manditory; } if(other->type != pe_ordering_manditory) { crm_debug_3("\t Ignoring: %s", ordering_type2text(other->type)); continue; } else if(action->optional || other->action->optional == FALSE){ crm_debug_3("\t Ignoring: %s/%s", other->action->optional?"-":"they are not optional", action->optional?"we are optional":"-"); continue; } else if(safe_str_eq(other->action->task, CRMD_ACTION_START)) { const char *interval = g_hash_table_lookup( action->meta, XML_LRM_ATTR_INTERVAL); int interval_i = 0; if(interval != NULL) { interval_i = crm_parse_int(interval, NULL); if(interval_i > 0) { crm_debug_3("Ignoring: start + recurring"); continue; } } } other->action->optional = FALSE; crm_debug_2("* Marking action %s mandatory because of %s", other->action->uuid, action->uuid); update_action(other->action); ); slist_iter( other, action_wrapper_t, action->actions_after, lpc, if(action->pseudo == FALSE && action->runnable == FALSE) { if(other->action->runnable == FALSE) { crm_debug_2("Action %s already un-runnable", other->action->uuid); } else if(action->optional == FALSE) { other->action->runnable = FALSE; crm_debug_2("Marking action %s un-runnable" " because of %s", other->action->uuid, action->uuid); update_action(other->action); } } crm_debug_3("\t(Recover) Checking action %s: %s/%s", other->action->uuid, ordering_type2text(other->type), other->action->optional?"optional":"required"); if(other->action->rsc == NULL) { continue; } else if(other->type == pe_ordering_recover) { if(other->action->rsc->restart_type != pe_restart_restart) { crm_debug_3("\t Ignoring: restart type %d", other->action->rsc->restart_type); continue; } } else if(other->type == pe_ordering_restart) { } else if(other->type == pe_ordering_postnotify) { CRM_CHECK(action->rsc == other->action->rsc, continue); } else { crm_debug_3("\t Ignoring: ordering %s", ordering_type2text(other->type)); continue; } if(other->action->optional == FALSE || action->optional) { crm_debug_3("\t Ignoring: %s/%s", action->optional?"we are optional":"-", other->action->optional?"-":"they are not optional"); continue; } task = text2task(action->task); switch(task) { case stop_rsc: case stopped_rsc: crm_debug_3("\t Ignoring: action %s", action->uuid); break; case start_rsc: case started_rsc: crm_debug_2("* (Recover) Marking action %s" " mandatory because of %s", other->action->uuid, action->uuid); other->action->optional = FALSE; update_action(other->action); break; default: crm_debug_3("\t Ignoring: action %s", action->uuid); break; } ); return FALSE; } gboolean shutdown_constraints( node_t *node, action_t *shutdown_op, pe_working_set_t *data_set) { /* add the stop to the before lists so it counts as a pre-req * for the shutdown */ slist_iter( rsc, resource_t, node->details->running_rsc, lpc, if(rsc->is_managed == FALSE) { continue; } custom_action_order( rsc, stop_key(rsc), NULL, NULL, crm_strdup(CRM_OP_SHUTDOWN), shutdown_op, pe_ordering_manditory, data_set); ); return TRUE; } gboolean stonith_constraints( node_t *node, action_t *stonith_op, pe_working_set_t *data_set) { char *key = NULL; GListPtr action_list = NULL; CRM_CHECK(stonith_op != NULL, return FALSE); /* * Make sure the stonith OP occurs before we start any shared resources */ if(stonith_op != NULL) { slist_iter( rsc, resource_t, data_set->resources, lpc, - rsc->fns->stonith_ordering(rsc, stonith_op, data_set); + rsc->cmds->stonith_ordering(rsc, stonith_op, data_set); ); } /* add the stonith OP as a stop pre-req and the mark the stop * as a pseudo op - since its now redundant */ slist_iter( rsc, resource_t, node->details->running_rsc, lpc, if(rsc->is_managed == FALSE) { crm_debug_2("Skipping fencing constraints for unmanaged resource: %s", rsc->id); continue; - } key = stop_key(rsc); action_list = find_actions(rsc->actions, key, node); crm_free(key); slist_iter( action, action_t, action_list, lpc2, if(node->details->online == FALSE || rsc->failed) { resource_t *parent = NULL; crm_info("Stop of failed resource %s is" " implict after %s is fenced", rsc->id, node->details->uname); /* the stop would never complete and is * now implied by the stonith operation */ action->pseudo = TRUE; action->runnable = TRUE; if(action->optional) { /* does this case ever happen? */ custom_action_order( NULL, crm_strdup(CRM_OP_FENCE),stonith_op, rsc, start_key(rsc), NULL, pe_ordering_manditory, data_set); } else { custom_action_order( NULL, crm_strdup(CRM_OP_FENCE),stonith_op, rsc, NULL, action, pe_ordering_manditory, data_set); } /* find the top-most resource */ parent = rsc->parent; while(parent != NULL && parent->parent != NULL) { parent = parent->parent; } if(parent) { crm_info("Re-creating actions for %s", parent->id); - parent->fns->create_actions( + parent->cmds->create_actions( parent, data_set); } } else { crm_info("Moving healthy resource %s" " off %s before fencing", rsc->id, node->details->uname); /* stop healthy resources before the * stonith op */ custom_action_order( rsc, stop_key(rsc), NULL, NULL,crm_strdup(CRM_OP_FENCE),stonith_op, pe_ordering_manditory, data_set); } ); key = demote_key(rsc); action_list = find_actions(rsc->actions, key, node); crm_free(key); slist_iter( action, action_t, action_list, lpc2, if(node->details->online == FALSE || rsc->failed) { crm_info("Demote of failed resource %s is" " implict after %s is fenced", rsc->id, node->details->uname); /* the stop would never complete and is * now implied by the stonith operation */ action->pseudo = TRUE; action->runnable = TRUE; custom_action_order( NULL, crm_strdup(CRM_OP_FENCE),stonith_op, rsc, demote_key(rsc), NULL, pe_ordering_manditory, data_set); } ); /* crm_debug_4("Adding stonith (%d) as an input to stop", */ /* stonith_op->id); */ /* } else if((rsc->unclean || node->details->unclean) */ /* && rsc->stopfail_type == pesf_block) { */ /* /\* depend on the stop action which will fail *\/ */ /* pe_err("SHARED RESOURCE %s WILL REMAIN BLOCKED" */ /* " ON NODE %s UNTIL %s", */ /* rsc->id, node->details->uname, */ /* data_set->stonith_enabled?"QUORUM RETURNS":"CLEANED UP MANUALLY"); */ /* continue; */ /* } else if((rsc->unclean || node->details->unclean) */ /* && rsc->stopfail_type == pesf_ignore) { */ /* /\* nothing to do here *\/ */ /* pe_err("SHARED RESOURCE %s IS NOT PROTECTED", rsc->id); */ /* continue; */ ); return TRUE; } static void dup_attr(gpointer key, gpointer value, gpointer user_data) { g_hash_table_replace(user_data, crm_strdup(key), crm_strdup(value)); } crm_data_t * action2xml(action_t *action, gboolean as_input) { gboolean needs_node_info = TRUE; crm_data_t * action_xml = NULL; crm_data_t * args_xml = NULL; char *action_id_s = NULL; if(action == NULL) { return NULL; } crm_debug_4("Dumping action %d as XML", action->id); if(safe_str_eq(action->task, CRM_OP_FENCE)) { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); /* needs_node_info = FALSE; */ } else if(safe_str_eq(action->task, CRM_OP_SHUTDOWN)) { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); } else if(safe_str_eq(action->task, CRM_OP_LRM_REFRESH)) { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); /* } else if(safe_str_eq(action->task, CRMD_ACTION_PROBED)) { */ /* action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); */ } else if(action->pseudo) { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_PSEUDO_EVENT); needs_node_info = FALSE; } else { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP); } action_id_s = crm_itoa(action->id); crm_xml_add(action_xml, XML_ATTR_ID, action_id_s); crm_free(action_id_s); crm_xml_add(action_xml, XML_LRM_ATTR_TASK, action->task); crm_xml_add(action_xml, XML_LRM_ATTR_TASK_KEY, action->uuid); if(needs_node_info && action->node != NULL) { crm_xml_add(action_xml, XML_LRM_ATTR_TARGET, action->node->details->uname); crm_xml_add(action_xml, XML_LRM_ATTR_TARGET_UUID, action->node->details->id); } if(action->failure_is_fatal == FALSE) { add_hash_param(action->meta, XML_ATTR_TE_ALLOWFAIL, XML_BOOLEAN_TRUE); } if(as_input) { return action_xml; } if(action->notify_keys != NULL) { g_hash_table_foreach( action->notify_keys, dup_attr, action->meta); } if(action->rsc != NULL && action->pseudo == FALSE) { int lpc = 0; crm_data_t *rsc_xml = create_xml_node( action_xml, crm_element_name(action->rsc->xml)); const char *attr_list[] = { XML_AGENT_ATTR_CLASS, XML_AGENT_ATTR_PROVIDER, XML_ATTR_TYPE }; crm_xml_add(rsc_xml, XML_ATTR_ID, action->rsc->id); crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->long_name); for(lpc = 0; lpc < DIMOF(attr_list); lpc++) { crm_xml_add(rsc_xml, attr_list[lpc], g_hash_table_lookup(action->rsc->meta, attr_list[lpc])); } } args_xml = create_xml_node(action_xml, XML_TAG_ATTRS); crm_xml_add(args_xml, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET); g_hash_table_foreach(action->extra, hash2field, args_xml); if(action->rsc != NULL) { g_hash_table_foreach(action->rsc->parameters, hash2field, args_xml); } g_hash_table_foreach(action->meta, hash2metafield, args_xml); if(action->rsc != NULL) { int lpc = 0; const char *key = NULL; const char *value = NULL; const char *meta_list[] = { XML_RSC_ATTR_UNIQUE, XML_RSC_ATTR_INCARNATION, XML_RSC_ATTR_INCARNATION_MAX, XML_RSC_ATTR_INCARNATION_NODEMAX, XML_RSC_ATTR_MASTER_MAX, XML_RSC_ATTR_MASTER_NODEMAX, }; for(lpc = 0; lpc < DIMOF(meta_list); lpc++) { key = meta_list[lpc]; value = g_hash_table_lookup(action->rsc->meta, key); if(value != NULL) { char *crm_name = crm_concat(CRM_META, key, '_'); crm_xml_add(args_xml, crm_name, value); crm_free(crm_name); } } } crm_log_xml_debug_4(action_xml, "dumped action"); return action_xml; } static gboolean should_dump_action(action_t *action) { const char * interval = NULL; CRM_CHECK(action != NULL, return FALSE); interval = g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL); if(action->optional) { crm_debug_5("action %d was optional", action->id); return FALSE; } else if(action->pseudo == FALSE && action->runnable == FALSE) { crm_debug_5("action %d was not runnable", action->id); return FALSE; } else if(action->dumped) { crm_debug_5("action %d was already dumped", action->id); return FALSE; } else if(action->rsc != NULL && action->rsc->is_managed == FALSE) { /* make sure probes go through */ if(safe_str_neq(action->task, CRMD_ACTION_STATUS)) { pe_warn("action %d (%s) was for an unmanaged resource (%s)", action->id, action->uuid, action->rsc->id); return FALSE; } if(interval != NULL && safe_str_neq(interval, "0")) { pe_warn("action %d (%s) was for an unmanaged resource (%s)", action->id, action->uuid, action->rsc->id); return FALSE; } } if(action->pseudo || safe_str_eq(action->task, CRM_OP_FENCE) || safe_str_eq(action->task, CRM_OP_SHUTDOWN)) { /* skip the next checks */ return TRUE; } if(action->node == NULL) { pe_err("action %d (%s) was not allocated", action->id, action->uuid); log_action(LOG_DEBUG, "Unallocated action", action, FALSE); return FALSE; } else if(action->node->details->online == FALSE) { pe_err("action %d was (%s) scheduled for offline node", action->id, action->uuid); log_action(LOG_DEBUG, "Action for offline node", action, FALSE); return FALSE; #if 0 /* but this would also affect resources that can be safely * migrated before a fencing op */ } else if(action->node->details->unclean == FALSE) { pe_err("action %d was (%s) scheduled for unclean node", action->id, action->uuid); log_action(LOG_DEBUG, "Action for unclean node", action, FALSE); return FALSE; #endif } return TRUE; } void graph_element_from_action(action_t *action, pe_working_set_t *data_set) { int last_action = -1; int synapse_priority = 0; crm_data_t * syn = NULL; crm_data_t * set = NULL; crm_data_t * in = NULL; crm_data_t * input = NULL; crm_data_t * xml_action = NULL; if(should_dump_action(action) == FALSE) { return; } action->dumped = TRUE; syn = create_xml_node(data_set->graph, "synapse"); set = create_xml_node(syn, "action_set"); in = create_xml_node(syn, "inputs"); crm_xml_add_int(syn, XML_ATTR_ID, data_set->num_synapse); data_set->num_synapse++; if(action->rsc != NULL) { synapse_priority = action->rsc->priority; } if(action->priority > synapse_priority) { synapse_priority = action->priority; } if(synapse_priority > 0) { crm_xml_add_int(syn, XML_CIB_ATTR_PRIORITY, synapse_priority); } xml_action = action2xml(action, FALSE); add_node_copy(set, xml_action); free_xml(xml_action); action->actions_before = g_list_sort( action->actions_before, sort_action_id); slist_iter(wrapper,action_wrapper_t,action->actions_before,lpc, if(last_action == wrapper->action->id) { crm_debug_2("Input (%d) %s duplicated", wrapper->action->id, wrapper->action->uuid); continue; } else if(wrapper->action->optional == TRUE) { crm_debug_2("Input (%d) %s optional", wrapper->action->id, wrapper->action->uuid); continue; } CRM_CHECK(last_action < wrapper->action->id, ;); last_action = wrapper->action->id; input = create_xml_node(in, "trigger"); xml_action = action2xml(wrapper->action, TRUE); add_node_copy(input, xml_action); free_xml(xml_action); ); } diff --git a/crm/pengine/group.c b/crm/pengine/group.c index 2ba8666be9..4ce60b8955 100644 --- a/crm/pengine/group.c +++ b/crm/pengine/group.c @@ -1,672 +1,471 @@ -/* $Id: group.c,v 1.63 2006/05/30 07:47:44 andrew Exp $ */ +/* $Id: group.c,v 1.64 2006/06/07 12:46:57 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 extern gboolean rsc_colocation_new( const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh, const char *state_lh, const char *state_rh); typedef struct group_variant_data_s { int num_children; GListPtr child_list; /* resource_t* */ resource_t *self; resource_t *first_child; resource_t *last_child; gboolean colocated; gboolean ordered; gboolean child_starting; gboolean child_stopping; } group_variant_data_t; #define get_group_variant_data(data, rsc) \ CRM_ASSERT(rsc != NULL); \ CRM_ASSERT(rsc->variant == pe_group); \ CRM_ASSERT(rsc->variant_opaque != NULL); \ data = (group_variant_data_t *)rsc->variant_opaque; \ void group_assign_color(resource_t *rsc, color_t *group_color); -gboolean group_unpack(resource_t *rsc, pe_working_set_t *data_set) -{ - resource_t *self = NULL; - crm_data_t *xml_obj = rsc->xml; - crm_data_t *xml_self = copy_xml(rsc->xml); - group_variant_data_t *group_data = NULL; - const char *group_ordered = g_hash_table_lookup( - rsc->meta, XML_RSC_ATTR_ORDERED); - const char *group_colocated = g_hash_table_lookup( - rsc->meta, "collocated"); - const char *clone_id = NULL; - - crm_debug_3("Processing resource %s...", rsc->id); -/* rsc->id = "dummy_group_rsc_id"; */ - - crm_malloc0(group_data, sizeof(group_variant_data_t)); - group_data->num_children = 0; - group_data->self = NULL; - group_data->child_list = NULL; - group_data->first_child = NULL; - group_data->last_child = NULL; - rsc->variant_opaque = group_data; - - group_data->ordered = TRUE; - group_data->colocated = TRUE; - - if(group_ordered != NULL) { - cl_str_to_boolean(group_ordered, &(group_data->ordered)); - } - if(group_colocated != NULL) { - cl_str_to_boolean(group_colocated, &(group_data->colocated)); - } - - /* this is a bit of a hack - but simplifies everything else */ - ha_msg_mod(xml_self, F_XML_TAGNAME, XML_CIB_TAG_RESOURCE); -/* set_id(xml_self, "self", -1); */ - - if(common_unpack(xml_self, &self, NULL, data_set)) { - group_data->self = self; - self->restart_type = pe_restart_restart; - - } else { - crm_log_xml_err(xml_self, "Couldnt unpack dummy child"); - return FALSE; - } - - clone_id = crm_element_value(rsc->xml, XML_RSC_ATTR_INCARNATION); - - xml_child_iter_filter( - xml_obj, xml_native_rsc, XML_CIB_TAG_RESOURCE, - - resource_t *new_rsc = NULL; - crm_xml_add(xml_native_rsc, XML_RSC_ATTR_INCARNATION, clone_id); - if(common_unpack(xml_native_rsc, &new_rsc, - rsc, data_set) == FALSE) { - pe_err("Failed unpacking resource %s", - crm_element_value(xml_obj, XML_ATTR_ID)); - if(new_rsc != NULL && new_rsc->fns != NULL) { - new_rsc->fns->free(new_rsc); - } - } - - group_data->num_children++; - group_data->child_list = g_list_append( - group_data->child_list, new_rsc); - - if(group_data->first_child == NULL) { - group_data->first_child = new_rsc; - - } else if(group_data->colocated) { - rsc_colocation_new( - "pe_group_internal_colo", pecs_must, - group_data->first_child, new_rsc, - NULL, NULL); - } - group_data->last_child = new_rsc; - print_resource(LOG_DEBUG_3, "Added", new_rsc, FALSE); - ); - - if(group_data->num_children == 0) { - pe_config_err("Group %s did not have any children", rsc->id); - return FALSE; - } - - crm_debug_3("Added %d children to resource %s...", - group_data->num_children, rsc->id); - - return TRUE; -} - - -resource_t * -group_find_child(resource_t *rsc, const char *id) +void group_set_cmds(resource_t *rsc) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); - return pe_find_resource(group_data->child_list, id); -} - -GListPtr group_children(resource_t *rsc) -{ - group_variant_data_t *group_data = NULL; - get_group_variant_data(group_data, rsc); - return group_data->child_list; + group_data->self->cmds = &resource_class_alloc_functions[group_data->self->variant]; + slist_iter( + child_rsc, resource_t, group_data->child_list, lpc, + child_rsc->cmds = &resource_class_alloc_functions[child_rsc->variant]; + child_rsc->cmds->set_cmds(child_rsc); + ); } int group_num_allowed_nodes(resource_t *rsc) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); if(group_data->colocated == FALSE) { pe_config_err("Cannot clone non-colocated group: %s", rsc->id); return 0; } - return group_data->self->fns->num_allowed_nodes(group_data->self); + return group_data->self->cmds->num_allowed_nodes(group_data->self); } color_t * group_color(resource_t *rsc, pe_working_set_t *data_set) { color_t *group_color = NULL; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_3("Coloring children of: %s", rsc->id); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, - group_color = child_rsc->fns->color(child_rsc, data_set); + group_color = child_rsc->cmds->color(child_rsc, data_set); CRM_CHECK(group_color != NULL, continue); native_assign_color(rsc, group_color); ); return group_color; } void group_assign_color(resource_t *rsc, color_t *group_color) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_3("Coloring children of: %s", rsc->id); CRM_CHECK(group_color != NULL, return); native_assign_color(rsc, group_color); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, native_assign_color(child_rsc, group_color); ); } void group_update_pseudo_status(resource_t *parent, resource_t *child); void group_create_actions(resource_t *rsc, pe_working_set_t *data_set) { action_t *op = NULL; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, - child_rsc->fns->create_actions(child_rsc, data_set); + child_rsc->cmds->create_actions(child_rsc, data_set); group_update_pseudo_status(rsc, child_rsc); ); op = start_action(group_data->self, NULL, !group_data->child_starting); op->pseudo = TRUE; op = custom_action(group_data->self, started_key(group_data->self), CRMD_ACTION_STARTED, NULL, !group_data->child_starting, TRUE, data_set); op->pseudo = TRUE; op = stop_action(group_data->self, NULL, !group_data->child_stopping); op->pseudo = TRUE; op = custom_action(group_data->self, stopped_key(group_data->self), CRMD_ACTION_STOPPED, NULL, !group_data->child_stopping, TRUE, data_set); op->pseudo = TRUE; rsc->actions = group_data->self->actions; } void group_update_pseudo_status(resource_t *parent, resource_t *child) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, parent); if(group_data->child_stopping && group_data->child_starting) { return; } slist_iter( action, action_t, child->actions, lpc, if(action->optional) { continue; } if(safe_str_eq(CRMD_ACTION_STOP, action->task) && action->runnable) { group_data->child_stopping = TRUE; } else if(safe_str_eq(CRMD_ACTION_START, action->task) && action->runnable) { group_data->child_starting = TRUE; } ); } void group_internal_constraints(resource_t *rsc, pe_working_set_t *data_set) { resource_t *last_rsc = NULL; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); - group_data->self->fns->internal_constraints(group_data->self, data_set); + group_data->self->cmds->internal_constraints(group_data->self, data_set); custom_action_order( group_data->self, stopped_key(group_data->self), NULL, group_data->self, start_key(group_data->self), NULL, pe_ordering_optional, data_set); custom_action_order( group_data->self, stop_key(group_data->self), NULL, group_data->self, stopped_key(group_data->self), NULL, pe_ordering_optional, data_set); custom_action_order( group_data->self, start_key(group_data->self), NULL, group_data->self, started_key(group_data->self), NULL, pe_ordering_optional, data_set); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, - child_rsc->fns->internal_constraints(child_rsc, data_set); + child_rsc->cmds->internal_constraints(child_rsc, data_set); if(group_data->ordered == FALSE) { order_start_start( group_data->self, child_rsc, pe_ordering_optional); custom_action_order( child_rsc, start_key(child_rsc), NULL, group_data->self, started_key(group_data->self), NULL, pe_ordering_optional, data_set); order_stop_stop( group_data->self, child_rsc, pe_ordering_optional); custom_action_order( child_rsc, stop_key(child_rsc), NULL, group_data->self, stopped_key(group_data->self), NULL, pe_ordering_optional, data_set); continue; } if(last_rsc != NULL) { order_start_start( last_rsc, child_rsc, pe_ordering_optional); order_stop_stop( child_rsc, last_rsc, pe_ordering_optional); /* recovery */ child_rsc->restart_type = pe_restart_restart; order_start_start( last_rsc, child_rsc, pe_ordering_recover); order_stop_stop( child_rsc, last_rsc, pe_ordering_recover); } else { custom_action_order( child_rsc, stop_key(child_rsc), NULL, group_data->self, stopped_key(group_data->self), NULL, pe_ordering_optional, data_set); order_start_start(group_data->self, child_rsc, pe_ordering_optional); } last_rsc = child_rsc; ); if(group_data->ordered && last_rsc != NULL) { custom_action_order( last_rsc, start_key(last_rsc), NULL, group_data->self, started_key(group_data->self), NULL, pe_ordering_optional, data_set); order_stop_stop( group_data->self, last_rsc, pe_ordering_optional); } } void group_rsc_colocation_lh( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { group_variant_data_t *group_data = NULL; if(rsc_lh == NULL) { pe_err("rsc_lh was NULL for %s", constraint->id); return; } else if(rsc_rh == NULL) { pe_err("rsc_rh was NULL for %s", constraint->id); return; } crm_debug_4("Processing constraints from %s", rsc_lh->id); get_group_variant_data(group_data, rsc_lh); CRM_CHECK(group_data->self != NULL, return); if(group_data->colocated) { - group_data->first_child->fns->rsc_colocation_lh( + group_data->first_child->cmds->rsc_colocation_lh( group_data->first_child, rsc_rh, constraint); return; } if(constraint->strength != pecs_must_not) { pe_config_err("Cannot colocate resources with" " non-colocated group: %s", rsc_lh->id); return; } slist_iter( child_rsc, resource_t, group_data->child_list, lpc, - child_rsc->fns->rsc_colocation_lh( + child_rsc->cmds->rsc_colocation_lh( child_rsc, rsc_rh, constraint); ); } void group_rsc_colocation_rh( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc_rh); CRM_CHECK(group_data->self != NULL, return); CRM_CHECK(rsc_lh->variant == pe_native, return); crm_debug_3("Processing RH of constraint %s", constraint->id); print_resource(LOG_DEBUG_3, "LHS", rsc_lh, TRUE); if(group_data->colocated) { - group_data->first_child->fns->rsc_colocation_rh( + group_data->first_child->cmds->rsc_colocation_rh( rsc_lh, group_data->first_child, constraint); return; } if(constraint->strength != pecs_must_not) { pe_config_err("Cannot colocate resources with" " non-colocated group: %s", rsc_rh->id); return; } slist_iter( child_rsc, resource_t, group_data->child_list, lpc, - child_rsc->fns->rsc_colocation_rh( + child_rsc->cmds->rsc_colocation_rh( rsc_lh, child_rsc, constraint); ); } void group_rsc_order_lh(resource_t *rsc, order_constraint_t *order) { char *stop_id = NULL; char *start_id = NULL; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_3("Processing LH of ordering constraint %d", order->id); if(group_data->self == NULL) { return; } stop_id = stop_key(group_data->self); start_id = start_key(group_data->self); if(safe_str_eq(order->lh_action_task, start_id)) { crm_free(order->lh_action_task); order->lh_action_task = started_key(group_data->self); } else if(safe_str_eq(order->lh_action_task, stop_id)) { crm_free(order->lh_action_task); order->lh_action_task = stopped_key(group_data->self); } crm_free(start_id); crm_free(stop_id); - group_data->self->fns->rsc_order_lh(group_data->self, order); + group_data->self->cmds->rsc_order_lh(group_data->self, order); } void group_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_3("Processing RH of ordering constraint %d", order->id); if(group_data->self == NULL) { return; } - group_data->self->fns->rsc_order_rh(lh_action, group_data->self, order); + group_data->self->cmds->rsc_order_rh(lh_action, group_data->self, order); } void group_rsc_location(resource_t *rsc, rsc_to_node_t *constraint) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_3("Processing actions from %s", group_data->self->id); - group_data->self->fns->rsc_location(group_data->self, constraint); + group_data->self->cmds->rsc_location(group_data->self, constraint); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, - child_rsc->fns->rsc_location(child_rsc, constraint); + child_rsc->cmds->rsc_location(child_rsc, constraint); ); } void group_expand(resource_t *rsc, pe_working_set_t *data_set) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_3("Processing actions from %s", rsc->id); CRM_CHECK(group_data->self != NULL, return); - group_data->self->fns->expand(group_data->self, data_set); + group_data->self->cmds->expand(group_data->self, data_set); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, - child_rsc->fns->expand(child_rsc, data_set); + child_rsc->cmds->expand(child_rsc, data_set); ); } -gboolean group_active(resource_t *rsc, gboolean all) -{ - group_variant_data_t *group_data = NULL; - get_group_variant_data(group_data, rsc); - - slist_iter( - child_rsc, resource_t, group_data->child_list, lpc, - gboolean child_active = child_rsc->fns->active(child_rsc, all); - if(all == FALSE && child_active) { - return TRUE; - } else if(child_active == FALSE) { - return FALSE; - } - ); - if(all) { - return TRUE; - } else { - return FALSE; - } -} - -void group_print( - resource_t *rsc, const char *pre_text, long options, void *print_data) -{ - const char *child_text = NULL; - group_variant_data_t *group_data = NULL; - get_group_variant_data(group_data, rsc); - if(pre_text != NULL) { - child_text = " "; - } else { - child_text = " "; - } - - status_print("%sResource Group: %s", - pre_text?pre_text:"", rsc->id); - - if(options & pe_print_html) { - status_print("\n
    \n"); - - } else if((options & pe_print_log) == 0) { - status_print("\n"); - } - - slist_iter( - child_rsc, resource_t, group_data->child_list, lpc, - - if(options & pe_print_html) { - status_print("
  • \n"); - } - child_rsc->fns->print( - child_rsc, child_text, options, print_data); - if(options & pe_print_html) { - status_print("
  • \n"); - } - ); - - if(options & pe_print_html) { - status_print("
\n"); - } -} - -void group_free(resource_t *rsc) -{ - group_variant_data_t *group_data = NULL; - CRM_CHECK(rsc != NULL, return); - get_group_variant_data(group_data, rsc); - - crm_debug_3("Freeing %s", rsc->id); - - slist_iter( - child_rsc, resource_t, group_data->child_list, lpc, - - crm_debug_3("Freeing child %s", child_rsc->id); - child_rsc->fns->free(child_rsc); - ); - - crm_debug_3("Freeing child list"); - pe_free_shallow_adv(group_data->child_list, FALSE); - - if(group_data->self != NULL) { - free_xml(group_data->self->xml); - group_data->self->fns->free(group_data->self); - } - - common_free(rsc); -} - - void group_agent_constraints(resource_t *rsc) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, - child_rsc->fns->agent_constraints(child_rsc); - ); -} - -enum rsc_role_e -group_resource_state(resource_t *rsc) -{ - enum rsc_role_e group_role = RSC_ROLE_UNKNOWN; - group_variant_data_t *group_data = NULL; - get_group_variant_data(group_data, rsc); - - slist_iter( - child_rsc, resource_t, group_data->child_list, lpc, - - if(child_rsc->next_role > group_role) { - group_role = rsc->next_role; - } - if(child_rsc->failed) { - rsc->failed = TRUE; - } + child_rsc->cmds->agent_constraints(child_rsc); ); - return group_role; } void group_create_notify_element(resource_t *rsc, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, - child_rsc->fns->create_notify_element( + child_rsc->cmds->create_notify_element( child_rsc, op, n_data, data_set); ); } gboolean group_create_probe(resource_t *rsc, node_t *node, action_t *complete, gboolean force, pe_working_set_t *data_set) { gboolean any_created = FALSE; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, - any_created = child_rsc->fns->create_probe( + any_created = child_rsc->cmds->create_probe( child_rsc, node, complete, force, data_set) || any_created; ); return any_created; } void group_stonith_ordering( resource_t *rsc, action_t *stonith_op, pe_working_set_t *data_set) { #if 0 /* I dont think it is a good idea to be poking inside groups */ group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, - child_rsc->fns->stonith_ordering( + child_rsc->cmds->stonith_ordering( child_rsc, stonith_op, data_set); ); #endif native_stonith_ordering(rsc, stonith_op, data_set); } diff --git a/crm/pengine/master.c b/crm/pengine/master.c index 24af588784..8366e887ab 100644 --- a/crm/pengine/master.c +++ b/crm/pengine/master.c @@ -1,526 +1,519 @@ -/* $Id: master.c,v 1.21 2006/06/07 10:09:32 andrew Exp $ */ +/* $Id: master.c,v 1.22 2006/06/07 12:46:58 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 extern void clone_create_notifications( resource_t *rsc, action_t *action, action_t *action_complete, pe_working_set_t *data_set); typedef struct clone_variant_data_s { resource_t *self; int clone_max; int clone_node_max; int active_clones; int max_nodes; gboolean interleave; gboolean ordered; crm_data_t *xml_obj_child; gboolean notify_confirm; GListPtr child_list; /* resource_t* */ } clone_variant_data_t; #define NO_MASTER_PREFS 0 #define get_clone_variant_data(data, rsc) \ CRM_ASSERT(rsc->variant == pe_master); \ data = (clone_variant_data_t *)rsc->variant_opaque; -gboolean master_unpack(resource_t *rsc, pe_working_set_t *data_set) -{ - add_hash_param(rsc->parameters, crm_meta_name("stateful"), - XML_BOOLEAN_TRUE); - return clone_unpack(rsc, data_set); -} - static void child_promoting_constraints( clone_variant_data_t *clone_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set) { /* if(clone_data->ordered */ /* || clone_data->self->restart_type == pe_restart_restart) { */ /* type = pe_ordering_manditory; */ /* } */ if(child == NULL) { if(clone_data->ordered && last != NULL) { crm_debug_4("Ordered version (last node)"); /* last child promote before promoted started */ custom_action_order( last, promote_key(last), NULL, clone_data->self, promoted_key(clone_data->self), NULL, type, data_set); } } else if(clone_data->ordered) { crm_debug_4("Ordered version"); if(last == NULL) { /* global promote before first child promote */ last = clone_data->self; } /* else: child/child relative promote */ order_start_start(last, child, type); custom_action_order( last, promote_key(last), NULL, child, promote_key(child), NULL, type, data_set); } else { crm_debug_4("Un-ordered version"); /* child promote before global promoted */ custom_action_order( child, promote_key(child), NULL, clone_data->self, promoted_key(clone_data->self), NULL, type, data_set); /* global promote before child promote */ custom_action_order( clone_data->self, promote_key(clone_data->self), NULL, child, promote_key(child), NULL, type, data_set); } } static void child_demoting_constraints( clone_variant_data_t *clone_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set) { /* if(clone_data->ordered */ /* || clone_data->self->restart_type == pe_restart_restart) { */ /* type = pe_ordering_manditory; */ /* } */ if(child == NULL) { if(clone_data->ordered && last != NULL) { crm_debug_4("Ordered version (last node)"); /* global demote before first child demote */ custom_action_order( clone_data->self, demote_key(clone_data->self), NULL, last, demote_key(last), NULL, pe_ordering_manditory, data_set); } } else if(clone_data->ordered && last != NULL) { crm_debug_4("Ordered version"); /* child/child relative demote */ custom_action_order(child, demote_key(child), NULL, last, demote_key(last), NULL, type, data_set); } else if(clone_data->ordered) { crm_debug_4("Ordered version (1st node)"); /* first child stop before global stopped */ custom_action_order( child, demote_key(child), NULL, clone_data->self, demoted_key(clone_data->self), NULL, type, data_set); } else { crm_debug_4("Un-ordered version"); /* child demote before global demoted */ custom_action_order( child, demote_key(child), NULL, clone_data->self, demoted_key(clone_data->self), NULL, type, data_set); /* global demote before child demote */ custom_action_order( clone_data->self, demote_key(clone_data->self), NULL, child, demote_key(child), NULL, type, data_set); } } static void master_update_pseudo_status( resource_t *child, gboolean *demoting, gboolean *promoting) { CRM_ASSERT(demoting != NULL); CRM_ASSERT(promoting != NULL); slist_iter( action, action_t, child->actions, lpc, if(*promoting && *demoting) { return; } else if(action->optional) { continue; } else if(safe_str_eq(CRMD_ACTION_DEMOTE, action->task)) { *demoting = TRUE; } else if(safe_str_eq(CRMD_ACTION_PROMOTE, action->task)) { *promoting = TRUE; } ); } #define apply_master_location(list) \ slist_iter( \ cons, rsc_to_node_t, list, lpc2, \ cons_node = NULL; \ if(cons->role_filter == RSC_ROLE_MASTER) { \ crm_debug("Applying %s to %s", \ cons->id, child_rsc->id); \ cons_node = pe_find_node_id( \ cons->node_list_rh, chosen->details->id); \ } \ if(cons_node != NULL) { \ int new_priority = merge_weights( \ child_rsc->priority, cons_node->weight); \ crm_debug("\t%s: %d->%d", child_rsc->id, \ child_rsc->priority, new_priority); \ child_rsc->priority = new_priority; \ } \ ); struct masters_s { node_t *node; int num_masters; }; void master_create_actions(resource_t *rsc, pe_working_set_t *data_set) { int len = 0; node_t *chosen = NULL; char *attr_name = NULL; const char *attr_value = NULL; node_t *cons_node = NULL; action_t *action = NULL; action_t *action_complete = NULL; gboolean any_promoting = FALSE; gboolean any_demoting = FALSE; resource_t *last_promote_rsc = NULL; resource_t *last_demote_rsc = NULL; const char *master_max_s = g_hash_table_lookup( rsc->meta, XML_RSC_ATTR_MASTER_MAX); const char *master_node_max_s = g_hash_table_lookup( rsc->meta, XML_RSC_ATTR_MASTER_NODEMAX); int promoted = 0; int master_max = crm_parse_int(master_max_s, "1"); int master_node_max = crm_parse_int(master_node_max_s, "1"); struct masters_s *master_hash_obj = NULL; GHashTable *master_hash = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); /* how many can we have? */ if(master_max > clone_data->max_nodes * clone_data->clone_node_max) { master_max = clone_data->max_nodes * clone_data->clone_node_max; crm_info("Limited to %d masters (potential slaves)",master_max); } if(master_max > clone_data->max_nodes * master_node_max) { master_max = clone_data->max_nodes * master_node_max; crm_info("Limited to %d masters (available nodes)", master_max); } /* * assign priority */ slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, crm_debug_2("Assigning priority for %s", child_rsc->id); CRM_CHECK(child_rsc->color != NULL, crm_err("Resource %s is uncolored", child_rsc->id); continue); chosen = child_rsc->color->details->chosen_node; if(child_rsc->role == RSC_ROLE_STARTED) { child_rsc->role = RSC_ROLE_SLAVE; } switch(child_rsc->next_role) { case RSC_ROLE_STARTED: if(NO_MASTER_PREFS) { child_rsc->priority = clone_data->clone_max - lpc; break; } child_rsc->priority = -1; CRM_CHECK(chosen != NULL, break); len = 8 + strlen(child_rsc->id); crm_malloc0(attr_name, len); sprintf(attr_name, "master-%s", child_rsc->id); crm_debug_2("looking for %s on %s", attr_name, chosen->details->uname); attr_value = g_hash_table_lookup( chosen->details->attrs, attr_name); if(attr_value == NULL) { crm_free(attr_name); len = 8 + strlen(child_rsc->long_name); crm_malloc0(attr_name, len); sprintf(attr_name, "master-%s", child_rsc->long_name); crm_debug_2("looking for %s on %s", attr_name, chosen->details->uname); attr_value = g_hash_table_lookup( chosen->details->attrs, attr_name); } if(attr_value != NULL) { crm_debug("%s=%s for %s", attr_name, crm_str(attr_value), chosen->details->uname); child_rsc->priority = char2score( attr_value); } crm_free(attr_name); apply_master_location(child_rsc->rsc_location); apply_master_location(rsc->rsc_location); break; case RSC_ROLE_SLAVE: case RSC_ROLE_STOPPED: child_rsc->priority = -INFINITY; break; case RSC_ROLE_MASTER: /* the only reason we should be here is if * we're re-creating actions after a stonith */ promoted++; break; default: CRM_CHECK(FALSE/* unhandled */, crm_err("Unknown resource role: %d for %s", child_rsc->next_role, child_rsc->id)); } ); /* sort based on the new "promote" priority */ clone_data->child_list = g_list_sort( clone_data->child_list, sort_rsc_priority); /* mark the first N as masters */ slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, CRM_CHECK(child_rsc->color != NULL, crm_err("Resource %s is uncolored", child_rsc->id); continue); chosen = child_rsc->color->details->chosen_node; switch(child_rsc->next_role) { case RSC_ROLE_STARTED: master_hash_obj = g_hash_table_lookup( master_hash, chosen->details->id); if(master_hash_obj == NULL) { crm_malloc0(master_hash_obj, sizeof(struct masters_s)); master_hash_obj->node = chosen; g_hash_table_insert( master_hash, crm_strdup(chosen->details->id), master_hash_obj); } if(master_hash_obj->num_masters >= master_node_max) { crm_info("Demoting %s (node master max)", child_rsc->id); child_rsc->next_role = RSC_ROLE_SLAVE; } else if(child_rsc->priority < 0) { crm_info("Demoting %s (priority)", child_rsc->id); child_rsc->next_role = RSC_ROLE_SLAVE; } else if(master_max <= promoted) { crm_info("Demoting %s (masters max)", child_rsc->id); child_rsc->next_role = RSC_ROLE_SLAVE; } else { crm_info("Promoting %s", child_rsc->id); child_rsc->next_role = RSC_ROLE_MASTER; promoted++; master_hash_obj->num_masters++; } break; case RSC_ROLE_SLAVE: if(child_rsc->priority < 0 ||master_max <= lpc){ pe_warn("Cannot promote %s (slave)", child_rsc->id); lpc--; } break; case RSC_ROLE_STOPPED: if(child_rsc->priority < 0 ||master_max <= lpc){ crm_debug("Cannot promote %s (stopping)", child_rsc->id); lpc--; } break; case RSC_ROLE_MASTER: /* the only reason we should be here is if * we're re-creating actions after a stonith */ promoted++; break; default: CRM_CHECK(FALSE/* unhandled */, crm_err("Unknown resource role: %d for %s", child_rsc->next_role, child_rsc->id)); } add_hash_param(child_rsc->parameters, crm_meta_name("role"), role2text(child_rsc->next_role)); ); crm_info("Promoted %d (of %d) slaves to master", promoted, master_max); g_hash_table_destroy(master_hash); /* create actions as normal */ clone_create_actions(rsc, data_set); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, gboolean child_promoting = FALSE; gboolean child_demoting = FALSE; master_update_pseudo_status( child_rsc, &child_demoting, &child_promoting); any_demoting = any_demoting || child_demoting; any_promoting = any_promoting || child_promoting; ); /* promote */ action = promote_action(clone_data->self, NULL, !any_promoting); action_complete = custom_action( clone_data->self, promoted_key(rsc), CRMD_ACTION_PROMOTED, NULL, !any_promoting, TRUE, data_set); action->pseudo = TRUE; action_complete->pseudo = TRUE; action_complete->priority = INFINITY; child_promoting_constraints(clone_data, pe_ordering_optional, NULL, last_promote_rsc, data_set); clone_create_notifications(rsc, action, action_complete, data_set); /* demote */ action = demote_action(clone_data->self, NULL, !any_demoting); action_complete = custom_action( clone_data->self, demoted_key(rsc), CRMD_ACTION_DEMOTED, NULL, !any_demoting, TRUE, data_set); action_complete->priority = INFINITY; action->pseudo = TRUE; action_complete->pseudo = TRUE; child_demoting_constraints(clone_data, pe_ordering_optional, NULL, last_demote_rsc, data_set); clone_create_notifications(rsc, action, action_complete, data_set); } void master_internal_constraints(resource_t *rsc, pe_working_set_t *data_set) { resource_t *last_rsc = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); clone_internal_constraints(rsc, data_set); /* global demoted before start */ custom_action_order( clone_data->self, demoted_key(clone_data->self), NULL, clone_data->self, start_key(clone_data->self), NULL, pe_ordering_optional, data_set); /* global started before promote */ custom_action_order( clone_data->self, started_key(clone_data->self), NULL, clone_data->self, promote_key(clone_data->self), NULL, pe_ordering_optional, data_set); /* global demoted before stop */ custom_action_order( clone_data->self, demoted_key(clone_data->self), NULL, clone_data->self, stop_key(clone_data->self), NULL, pe_ordering_optional, data_set); /* global demote before demoted */ custom_action_order( clone_data->self, demote_key(clone_data->self), NULL, clone_data->self, demoted_key(clone_data->self), NULL, pe_ordering_optional, data_set); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, /* child demote before promote */ custom_action_order( child_rsc, demote_key(child_rsc), NULL, child_rsc, promote_key(child_rsc), NULL, pe_ordering_restart, data_set); child_promoting_constraints(clone_data, pe_ordering_optional, child_rsc, last_rsc, data_set); child_demoting_constraints(clone_data, pe_ordering_optional, child_rsc, last_rsc, data_set); last_rsc = child_rsc; ); } diff --git a/crm/pengine/native.c b/crm/pengine/native.c index e2fed23839..6512f14976 100644 --- a/crm/pengine/native.c +++ b/crm/pengine/native.c @@ -1,2160 +1,1751 @@ -/* $Id: native.c,v 1.148 2006/06/02 15:36:21 andrew Exp $ */ +/* $Id: native.c,v 1.149 2006/06/07 12:46:59 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 #define DELETE_THEN_REFRESH 1 extern color_t *add_color(resource_t *rh_resource, color_t *color); gboolean native_choose_color(resource_t *lh_resource, color_t *no_color); void native_update_node_weight(resource_t *rsc, rsc_to_node_t *cons, node_t *cons_node, GListPtr nodes); void native_rsc_colocation_rh_must(resource_t *rsc_lh, gboolean update_lh, resource_t *rsc_rh, gboolean update_rh); void native_rsc_colocation_rh_mustnot(resource_t *rsc_lh, gboolean update_lh, resource_t *rsc_rh, gboolean update_rh); void filter_nodes(resource_t *rsc); int num_allowed_nodes4color(color_t *color); void create_notifications(resource_t *rsc, pe_working_set_t *data_set); void Recurring(resource_t *rsc, action_t *start, node_t *node, pe_working_set_t *data_set); void pe_pre_notify( resource_t *rsc, node_t *node, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set); void pe_post_notify( resource_t *rsc, node_t *node, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set); gboolean DeleteRsc(resource_t *rsc, node_t *node, pe_working_set_t *data_set); void NoRoleChange(resource_t *rsc, node_t *current, node_t *next, pe_working_set_t *data_set); gboolean StopRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set); gboolean StartRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set); -gboolean DemoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set); +extern gboolean DemoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set); gboolean PromoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set); gboolean RoleError(resource_t *rsc, node_t *next, pe_working_set_t *data_set); gboolean NullOp(resource_t *rsc, node_t *next, pe_working_set_t *data_set); enum rsc_role_e rsc_state_matrix[RSC_ROLE_MAX][RSC_ROLE_MAX] = { /* Current State */ /* Next State: Unknown Stopped Started Slave Master */ /* Unknown */ { RSC_ROLE_UNKNOWN, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, }, /* Stopped */ { RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STARTED, RSC_ROLE_SLAVE, RSC_ROLE_SLAVE, }, /* Started */ { RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STARTED, RSC_ROLE_SLAVE, RSC_ROLE_MASTER, }, /* Slave */ { RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_UNKNOWN, RSC_ROLE_SLAVE, RSC_ROLE_MASTER, }, /* Master */ { RSC_ROLE_STOPPED, RSC_ROLE_SLAVE, RSC_ROLE_UNKNOWN, RSC_ROLE_SLAVE, RSC_ROLE_MASTER, }, }; gboolean (*rsc_action_matrix[RSC_ROLE_MAX][RSC_ROLE_MAX])(resource_t*,node_t*,pe_working_set_t*) = { /* Current State */ /* Next State: Unknown Stopped Started Slave Master */ /* Unknown */ { RoleError, StopRsc, RoleError, RoleError, RoleError, }, /* Stopped */ { RoleError, NullOp, StartRsc, StartRsc, RoleError, }, /* Started */ { RoleError, StopRsc, NullOp, NullOp, PromoteRsc, }, /* Slave */ { RoleError, StopRsc, RoleError, NullOp, PromoteRsc, }, /* Master */ { RoleError, RoleError, RoleError, DemoteRsc, NullOp, }, }; typedef struct native_variant_data_s { /* GListPtr allowed_nodes; /\* node_t* *\/ */ } native_variant_data_t; #define get_native_variant_data(data, rsc) \ CRM_ASSERT(rsc->variant == pe_native); \ CRM_ASSERT(rsc->variant_opaque != NULL); \ data = (native_variant_data_t *)rsc->variant_opaque; -void -native_add_running(resource_t *rsc, node_t *node, pe_working_set_t *data_set) -{ - CRM_CHECK(node != NULL, return); - - slist_iter( - a_node, node_t, rsc->running_on, lpc, - CRM_CHECK(a_node != NULL, return); - if(safe_str_eq(a_node->details->id, node->details->id)) { - return; - } - ); - - rsc->running_on = g_list_append(rsc->running_on, node); - if(rsc->variant == pe_native) { - node->details->running_rsc = g_list_append( - node->details->running_rsc, rsc); - } - - if(rsc->variant != pe_native) { - } else if(rsc->is_managed == FALSE) { - crm_info("resource %s isnt managed", rsc->id); - rsc2node_new( - "not_managed_default", rsc, INFINITY, node, data_set); - return; - -#if 0 - } else if(rsc->failed) { - crm_info("Skipping resource stickiness for failed resource %s", - rsc->id); -#endif - } else if(rsc->stickiness > 0 || rsc->stickiness < 0) { - rsc2node_new("stickiness", rsc, rsc->stickiness, node,data_set); - crm_debug("Resource %s: preferring current location (%s/%s)", - rsc->id, node->details->uname, node->details->id); - } - - if(rsc->variant == pe_native && g_list_length(rsc->running_on) > 1) { - const char *type = crm_element_value(rsc->xml, XML_ATTR_TYPE); - const char *class = crm_element_value( - rsc->xml, XML_AGENT_ATTR_CLASS); - - - /* these are errors because hardly any gets it right - * at the moment and this way the might notice - */ - pe_err("Resource %s::%s:%s appears to be active on %d nodes.", - class, type, rsc->id, g_list_length(rsc->running_on)); - cl_log(LOG_ERR, "See %s for more information.", - HAURL("v2/faq/resource_too_active")); - - if(rsc->recovery_type == recovery_stop_only) { - native_assign_color(rsc, data_set->no_color); - - } else if(rsc->recovery_type == recovery_block) { - rsc->is_managed = FALSE; - } - - } else { - crm_debug_2("Resource %s is active on: %s", - rsc->id, node->details->uname); - } - - if(rsc->parent != NULL) { - native_add_running(rsc->parent, node, data_set); - } - -} - - -gboolean native_unpack(resource_t *rsc, pe_working_set_t *data_set) -{ - native_variant_data_t *native_data = NULL; - - crm_debug_3("Processing resource %s...", rsc->id); - - crm_malloc0(native_data, sizeof(native_variant_data_t)); - - rsc->allowed_nodes = NULL; - rsc->running_on = NULL; - - rsc->variant_opaque = native_data; - return TRUE; -} - - -resource_t * -native_find_child(resource_t *rsc, const char *id) -{ - return NULL; -} - -GListPtr native_children(resource_t *rsc) +void native_set_cmds(resource_t *rsc) { - return NULL; -} - -static void -hash_copy_field(gpointer key, gpointer value, gpointer user_data) -{ - const char *name = key; - const char *s_value = value; - - GHashTable *hash_copy = user_data; - g_hash_table_insert(hash_copy, crm_strdup(name), crm_strdup(s_value)); -} - -char * -native_parameter( - resource_t *rsc, node_t *node, gboolean create, const char *name, - pe_working_set_t *data_set) -{ - char *value_copy = NULL; - const char *value = NULL; - GHashTable *hash = rsc->parameters; - GHashTable *local_hash = NULL; - - CRM_CHECK(rsc != NULL, return NULL); - CRM_CHECK(name != NULL && strlen(name) != 0, return NULL); - - crm_debug_2("Looking up %s in %s", name, rsc->id); - - if(create) { - if(node != NULL) { - crm_debug_2("Creating hash with node %s", - node->details->uname); - } else { - crm_debug_2("Creating default hash"); - } - - local_hash = g_hash_table_new_full( - g_str_hash, g_str_equal, - g_hash_destroy_str, g_hash_destroy_str); - - g_hash_table_foreach( - rsc->parameters, hash_copy_field, local_hash); - unpack_instance_attributes( - rsc->xml, XML_TAG_ATTR_SETS, node, local_hash, - NULL, 0, data_set); - - hash = local_hash; - } - - value = g_hash_table_lookup(hash, name); - if(value == NULL) { - /* try meta attributes instead */ - value = g_hash_table_lookup(rsc->meta, name); - } - - if(value != NULL) { - value_copy = crm_strdup(value); - } - if(local_hash != NULL) { - g_hash_table_destroy(local_hash); - } - return value_copy; } int native_num_allowed_nodes(resource_t *rsc) { int num_nodes = 0; + if(rsc->next_role == RSC_ROLE_STOPPED) { + return 0; + } + if(rsc->color) { crm_debug_4("Colored case"); num_nodes = num_allowed_nodes4color(rsc->color); } else if(rsc->candidate_colors) { /* TODO: sort colors first */ color_t *color = g_list_nth_data(rsc->candidate_colors, 0); crm_debug_4("Candidate colors case"); num_nodes = num_allowed_nodes4color(color); } else { crm_debug_4("Default case"); slist_iter( this_node, node_t, rsc->allowed_nodes, lpc, crm_debug_3("Rsc %s Checking %s: %d", rsc->id, this_node->details->uname, this_node->weight); if(this_node->details->shutdown || this_node->details->online == FALSE) { this_node->weight = -INFINITY; } if(this_node->weight < 0) { continue; /* } else if(this_node->details->unclean) { */ /* continue; */ } num_nodes++; ); } crm_debug_2("Resource %s can run on %d nodes", rsc->id, num_nodes); return num_nodes; } int num_allowed_nodes4color(color_t *color) { int num_nodes = 0; if(color->details->pending == FALSE) { if(color->details->chosen_node) { return 1; } return 0; } slist_iter( this_node, node_t, color->details->candidate_nodes, lpc, crm_debug_3("Checking %s: %d", this_node->details->uname, this_node->weight); if(this_node->details->shutdown || this_node->details->online == FALSE) { this_node->weight = -INFINITY; } if(this_node->weight < 0) { continue; /* } else if(this_node->details->unclean) { */ /* continue; */ } num_nodes++; ); return num_nodes; } color_t * native_color(resource_t *rsc, pe_working_set_t *data_set) { color_t *new_color = NULL; print_resource(LOG_DEBUG_2, "Coloring: ", rsc, FALSE); if(rsc->provisional == FALSE) { return rsc->color; } - + rsc->rsc_cons = g_list_sort( rsc->rsc_cons, sort_cons_strength); /*------ Pre-processing */ slist_iter( constraint, rsc_colocation_t, rsc->rsc_cons, lpc, crm_action_debug_3( print_rsc_colocation( "Pre-Processing constraint", constraint,FALSE)); - rsc->fns->rsc_colocation_lh( + rsc->cmds->rsc_colocation_lh( rsc, constraint->rsc_rh, constraint); ); - + if( native_choose_color(rsc, data_set->no_color) ) { crm_debug_3("Colored resource %s with color %d", rsc->id, rsc->color->id); new_color = rsc->color; } else { if(rsc->allowed_nodes != NULL) { /* filter out nodes with a negative weight */ filter_nodes(rsc); new_color = create_color(data_set, rsc, rsc->allowed_nodes); native_assign_color(rsc, new_color); } if(new_color == NULL) { pe_warn("Resource %s cannot run anywhere", rsc->id); print_resource(LOG_ERR, "No color: ", rsc, FALSE); native_assign_color(rsc, data_set->no_color); new_color = data_set->no_color; } } rsc->provisional = FALSE; /*------ Post-processing */ #if 1 slist_iter( constraint, rsc_colocation_t, rsc->rsc_cons, lpc, crm_action_debug_3( print_rsc_colocation( "Post-Processing constraint",constraint,FALSE)); - rsc->fns->rsc_colocation_lh( + rsc->cmds->rsc_colocation_lh( rsc, constraint->rsc_rh, constraint); ); #endif print_resource(LOG_DEBUG_3, "Colored", rsc, TRUE); return new_color; } void Recurring(resource_t *rsc, action_t *start, node_t *node, pe_working_set_t *data_set) { char *key = NULL; const char *name = NULL; const char *value = NULL; const char *interval = NULL; const char *node_uname = NULL; int interval_ms = 0; action_t *mon = NULL; gboolean is_optional = TRUE; GListPtr possible_matches = NULL; crm_debug_2("Creating recurring actions for %s", rsc->id); if(node != NULL) { node_uname = node->details->uname; } xml_child_iter_filter( rsc->ops_xml, operation, "op", is_optional = TRUE; name = crm_element_value(operation, "name"); interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL); interval_ms = crm_get_msec(interval); if(interval_ms <= 0) { continue; } value = crm_element_value(operation, "disabled"); if(crm_is_true(value)) { continue; } key = generate_op_key(rsc->id, name, interval_ms); if(start != NULL) { crm_debug_3("Marking %s %s due to %s", key, start->optional?"optional":"manditory", start->uuid); is_optional = start->optional; } else { crm_debug_2("Marking %s optional", key); is_optional = TRUE; } /* start a monitor for an already active resource */ possible_matches = find_actions_exact(rsc->actions, key, node); if(possible_matches == NULL) { is_optional = FALSE; crm_debug_3("Marking %s manditory: not active", key); } value = crm_element_value(operation, "role"); if((rsc->next_role == RSC_ROLE_MASTER && value == NULL) || (value != NULL && text2role(value) != rsc->next_role)) { int log_level = LOG_DEBUG_2; const char *foo = "Ignoring"; if(is_optional) { log_level = LOG_INFO; foo = "Cancelling"; /* its running : cancel it */ mon = custom_action( rsc, crm_strdup(key), CRMD_ACTION_CANCEL, node, FALSE, TRUE, data_set); mon->task = CRMD_ACTION_CANCEL; add_hash_param(mon->meta, XML_LRM_ATTR_INTERVAL, interval); add_hash_param(mon->meta, XML_LRM_ATTR_TASK, name); custom_action_order( rsc, NULL, mon, rsc, promote_key(rsc), NULL, pe_ordering_optional, data_set); mon = NULL; } crm_log_maybe(log_level, "%s action %s (%s vs. %s)", foo , key, value?value:role2text(RSC_ROLE_SLAVE), role2text(rsc->next_role)); crm_free(key); key = NULL; continue; } mon = custom_action(rsc, key, name, node, is_optional, TRUE, data_set); if(is_optional) { crm_debug("%s\t %s (optional)", crm_str(node_uname), mon->uuid); } if(start == NULL || start->runnable == FALSE) { crm_debug("%s\t %s (cancelled : start un-runnable)", crm_str(node_uname), mon->uuid); mon->runnable = FALSE; } else if(node == NULL || node->details->online == FALSE || node->details->unclean) { crm_debug("%s\t %s (cancelled : no node available)", crm_str(node_uname), mon->uuid); mon->runnable = FALSE; } else if(mon->optional == FALSE) { crm_notice("%s\t %s", crm_str(node_uname),mon->uuid); } custom_action_order(rsc, start_key(rsc), NULL, NULL, crm_strdup(key), mon, pe_ordering_restart, data_set); if(rsc->next_role == RSC_ROLE_MASTER) { char *running_master = crm_itoa(EXECRA_RUNNING_MASTER); add_hash_param(mon->meta, XML_ATTR_TE_TARGET_RC, running_master); custom_action_order( rsc, promote_key(rsc), NULL, rsc, NULL, mon, pe_ordering_optional, data_set); crm_free(running_master); } ); } void native_create_actions(resource_t *rsc, pe_working_set_t *data_set) { action_t *start = NULL; node_t *chosen = NULL; enum rsc_role_e role = RSC_ROLE_UNKNOWN; enum rsc_role_e next_role = RSC_ROLE_UNKNOWN; CRM_CHECK(rsc->color != NULL, return); chosen = rsc->color->details->chosen_node; if(chosen != NULL) { CRM_CHECK(rsc->next_role != RSC_ROLE_UNKNOWN, rsc->next_role = RSC_ROLE_STARTED); } unpack_instance_attributes( - rsc->xml, XML_TAG_ATTR_SETS, chosen, rsc->parameters, - NULL, 0, data_set); + rsc->xml, XML_TAG_ATTR_SETS, + chosen?chosen->details->attrs:NULL, + rsc->parameters, NULL, data_set->now); crm_debug("%s: %s->%s", rsc->id, role2text(rsc->role), role2text(rsc->next_role)); if(g_list_length(rsc->running_on) > 1) { if(rsc->recovery_type == recovery_stop_start) { pe_err("Attempting recovery of resource %s", rsc->id); StopRsc(rsc, NULL, data_set); rsc->role = RSC_ROLE_STOPPED; } } else if(rsc->running_on != NULL) { node_t *current = rsc->running_on->data; NoRoleChange(rsc, current, chosen, data_set); } else if(rsc->role == RSC_ROLE_STOPPED && rsc->next_role == RSC_ROLE_STOPPED) { char *key = start_key(rsc); GListPtr possible_matches = find_actions(rsc->actions, key, NULL); slist_iter( action, action_t, possible_matches, lpc, action->optional = TRUE; /* action->pseudo = TRUE; */ ); crm_debug_2("Stopping a stopped resource"); crm_free(key); return; } role = rsc->role; while(role != rsc->next_role) { next_role = rsc_state_matrix[role][rsc->next_role]; crm_debug_2("Executing: %s->%s (%s)", role2text(role), role2text(next_role), rsc->id); if(rsc_action_matrix[role][next_role]( rsc, chosen, data_set) == FALSE) { break; } role = next_role; } if(rsc->next_role != RSC_ROLE_STOPPED && rsc->is_managed) { start = start_action(rsc, chosen, TRUE); Recurring(rsc, start, chosen, data_set); } } void native_internal_constraints(resource_t *rsc, pe_working_set_t *data_set) { order_restart(rsc); custom_action_order(rsc, demote_key(rsc), NULL, rsc, stop_key(rsc), NULL, pe_ordering_manditory, data_set); custom_action_order(rsc, start_key(rsc), NULL, rsc, promote_key(rsc), NULL, pe_ordering_optional, data_set); } void native_rsc_colocation_lh( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { if(rsc_lh == NULL) { pe_err("rsc_lh was NULL for %s", constraint->id); return; } else if(constraint->rsc_rh == NULL) { pe_err("rsc_rh was NULL for %s", constraint->id); return; } crm_debug_2("Processing colocation constraint between %s and %s", rsc_lh->id, rsc_rh->id); - rsc_rh->fns->rsc_colocation_rh(rsc_lh, rsc_rh, constraint); + rsc_rh->cmds->rsc_colocation_rh(rsc_lh, rsc_rh, constraint); } static gboolean filter_colocation_constraint( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { if(constraint->strength == pecs_ignore || constraint->strength == pecs_startstop){ crm_debug_4("Skipping constraint type %d", constraint->strength); return FALSE; } if(constraint->state_lh != NULL && text2role(constraint->state_lh) != rsc_lh->next_role) { crm_debug_4("RH: Skipping constraint: \"%s\" state filter", constraint->state_rh); return FALSE; } if(constraint->state_rh != NULL && text2role(constraint->state_rh) != rsc_rh->next_role) { crm_debug_4("RH: Skipping constraint: \"%s\" state filter", constraint->state_rh); return FALSE; } return TRUE; } void native_rsc_colocation_rh( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { gboolean do_check = FALSE; gboolean update_lh = FALSE; gboolean update_rh = FALSE; crm_debug_2("%sColocating %s with %s (%s)", constraint->strength == pecs_must?"":"Anti-", rsc_lh->id, rsc_rh->id, constraint->id); if(filter_colocation_constraint(rsc_lh, rsc_rh, constraint) == FALSE) { return; } if(rsc_lh->provisional && rsc_rh->provisional) { if(constraint->strength == pecs_must) { /* update effective_priorities */ crm_debug_3("Priority update"); native_rsc_colocation_rh_must( rsc_lh, update_lh, rsc_rh, update_rh); } else { /* nothing */ crm_debug_4( "Skipping constraint, both sides provisional"); } return; } else if( (!rsc_lh->provisional) && (!rsc_rh->provisional) && (!rsc_lh->color->details->pending) && (!rsc_rh->color->details->pending) ) { /* error check */ do_check = TRUE; if(rsc_lh->effective_priority < rsc_rh->effective_priority) { update_lh = TRUE; } else if(rsc_lh->effective_priority > rsc_rh->effective_priority) { update_rh = TRUE; } else { update_lh = TRUE; update_rh = TRUE; } } else if(rsc_lh->provisional == FALSE && rsc_lh->color->details->pending == FALSE) { /* update _them_ : postproc color version */ update_rh = TRUE; } else if(rsc_rh->provisional == FALSE && rsc_rh->color->details->pending == FALSE) { /* update _us_ : postproc color alt version */ update_lh = TRUE; } else if(rsc_lh->provisional == FALSE) { /* update _them_ : preproc version */ update_rh = TRUE; } else if(rsc_rh->provisional == FALSE) { /* update _us_ : postproc version */ update_lh = TRUE; } else { pe_warn("Un-expected combination of inputs"); return; } if(update_lh) { crm_debug_4("Updating LHS"); } if(update_rh) { crm_debug_4("Updating RHS"); } if(do_check) { if(native_constraint_violated( rsc_lh, rsc_rh, constraint) == FALSE) { crm_debug_4("Constraint satisfied"); return; } /* else constraint cant be satisified */ pe_warn("Constraint %s could not be satisfied", constraint->id); if(update_lh) { pe_warn("Marking resource %s unrunnable as a result", rsc_lh->id); rsc_lh->runnable = FALSE; } if(update_rh) { pe_warn("Marking resource %s unrunnable as a result", rsc_rh->id); rsc_rh->runnable = FALSE; } } if(constraint->strength == pecs_must) { native_rsc_colocation_rh_must( rsc_lh, update_lh, rsc_rh, update_rh); return; } else if(constraint->strength != pecs_must_not) { /* unknown type */ pe_err("Unknown constraint type %d", constraint->strength); return; } native_rsc_colocation_rh_mustnot(rsc_lh, update_lh,rsc_rh, update_rh); } void native_rsc_order_lh(resource_t *lh_rsc, order_constraint_t *order) { GListPtr lh_actions = NULL; action_t *lh_action = order->lh_action; crm_debug_3("Processing LH of ordering constraint %d", order->id); if(lh_action != NULL) { lh_actions = g_list_append(NULL, lh_action); } else if(lh_action == NULL && lh_rsc != NULL) { #if 0 /* this should be safe to remove */ if(order->strength == pecs_must) { crm_debug_4("No LH-Side (%s/%s) found for constraint..." " creating", lh_rsc->id, order->lh_action_task); pe_err("BROKEN CODE"); custom_action( lh_rsc, order->lh_action_task, NULL, NULL); } #endif lh_actions = find_actions( lh_rsc->actions, order->lh_action_task, NULL); if(lh_actions == NULL) { crm_debug_4("No LH-Side (%s/%s) found for constraint", lh_rsc->id, order->lh_action_task); if(order->rh_rsc != NULL) { crm_debug_4("RH-Side was: (%s/%s)", order->rh_rsc->id, order->rh_action_task); } else if(order->rh_action != NULL && order->rh_action->rsc != NULL) { crm_debug_4("RH-Side was: (%s/%s)", order->rh_action->rsc->id, order->rh_action_task); } else if(order->rh_action != NULL) { crm_debug_4("RH-Side was: %s", order->rh_action_task); } else { crm_debug_4("RH-Side was NULL"); } return; } } else { pe_warn("No LH-Side (%s) specified for constraint", order->lh_action_task); if(order->rh_rsc != NULL) { crm_debug_4("RH-Side was: (%s/%s)", order->rh_rsc->id, order->rh_action_task); } else if(order->rh_action != NULL && order->rh_action->rsc != NULL) { crm_debug_4("RH-Side was: (%s/%s)", order->rh_action->rsc->id, order->rh_action_task); } else if(order->rh_action != NULL) { crm_debug_4("RH-Side was: %s", order->rh_action_task); } else { crm_debug_4("RH-Side was NULL"); } return; } slist_iter( lh_action_iter, action_t, lh_actions, lpc, resource_t *rh_rsc = order->rh_rsc; if(rh_rsc == NULL && order->rh_action) { rh_rsc = order->rh_action->rsc; } if(rh_rsc) { - rh_rsc->fns->rsc_order_rh( + rh_rsc->cmds->rsc_order_rh( lh_action_iter, rh_rsc, order); } else if(order->rh_action) { order_actions(lh_action_iter, order->rh_action, order->type); } ); pe_free_shallow_adv(lh_actions, FALSE); } void native_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order) { GListPtr rh_actions = NULL; action_t *rh_action = order->rh_action; crm_debug_3("Processing RH of ordering constraint %d", order->id); if(rh_action != NULL) { rh_actions = g_list_append(NULL, rh_action); } else if(rh_action == NULL && rsc != NULL) { rh_actions = find_actions( rsc->actions, order->rh_action_task, NULL); if(rh_actions == NULL) { crm_debug_4("No RH-Side (%s/%s) found for constraint..." " ignoring", rsc->id, order->rh_action_task); crm_debug_4("LH-Side was: (%s/%s)", order->lh_rsc?order->lh_rsc->id:order->lh_action?order->lh_action->rsc->id:"", order->lh_action_task); return; } } else if(rh_action == NULL) { crm_debug_4("No RH-Side (%s) specified for constraint..." " ignoring", order->rh_action_task); crm_debug_4("LH-Side was: (%s/%s)", order->lh_rsc?order->lh_rsc->id:order->lh_action?order->lh_action->rsc->id:"", order->lh_action_task); return; } slist_iter( rh_action_iter, action_t, rh_actions, lpc, order_actions(lh_action, rh_action_iter, order->type); ); pe_free_shallow_adv(rh_actions, FALSE); } void native_rsc_location(resource_t *rsc, rsc_to_node_t *constraint) { GListPtr or_list; crm_debug_2("Applying %s (%s) to %s", constraint->id, role2text(constraint->role_filter), rsc->id); /* take "lifetime" into account */ if(constraint == NULL) { pe_err("Constraint is NULL"); return; } else if(rsc == NULL) { pe_err("LHS of rsc_to_node (%s) is NULL", constraint->id); return; } else if(constraint->role_filter > 0 && constraint->role_filter != rsc->next_role) { crm_debug("Constraint (%s) is not active (role : %s)", constraint->id, role2text(constraint->role_filter)); return; } else if(is_active(constraint) == FALSE) { crm_debug_2("Constraint (%s) is not active", constraint->id); return; } if(constraint->node_list_rh == NULL) { crm_debug_2("RHS of constraint %s is NULL", constraint->id); return; } print_resource(LOG_DEBUG_3, "before update: ", rsc, TRUE); or_list = node_list_or( rsc->allowed_nodes, constraint->node_list_rh, FALSE); pe_free_shallow(rsc->allowed_nodes); rsc->allowed_nodes = or_list; print_resource(LOG_DEBUG_3, "after update: ", rsc, TRUE); } void native_expand(resource_t *rsc, pe_working_set_t *data_set) { slist_iter( action, action_t, rsc->actions, lpc, crm_debug_4("processing action %d for rsc=%s", action->id, rsc->id); graph_element_from_action(action, data_set); ); } -gboolean native_active(resource_t *rsc, gboolean all) -{ - slist_iter( - a_node, node_t, rsc->running_on, lpc, - - if(a_node->details->online == FALSE) { - crm_debug("Resource %s: node %s is offline", - rsc->id, a_node->details->uname); - } else if(a_node->details->unclean) { - crm_debug("Resource %s: node %s is unclean", - rsc->id, a_node->details->uname); - } else { - crm_debug("Resource %s active on %s", - rsc->id, a_node->details->uname); - return TRUE; - } - ); - - return FALSE; -} - -struct print_data_s -{ - long options; - void *print_data; -}; - -static void native_print_attr(gpointer key, gpointer value, gpointer user_data) -{ - long options = ((struct print_data_s*)user_data)->options; - void *print_data = ((struct print_data_s*)user_data)->print_data; - status_print("Option: %s = %s\n", (char*)key, (char*)value); -} - -void -native_print( - resource_t *rsc, const char *pre_text, long options, void *print_data) -{ - node_t *node = NULL; - const char *prov = NULL; - const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); - - if(safe_str_eq(class, "ocf")) { - prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER); - } - - if(rsc->running_on != NULL) { - node = rsc->running_on->data; - } - - if(options & pe_print_html) { - if(rsc->is_managed == FALSE) { - status_print(""); - - } else if(rsc->failed) { - status_print(""); - - } else if(rsc->variant == pe_native - && g_list_length(rsc->running_on) == 0) { - status_print(""); - - } else if(g_list_length(rsc->running_on) > 1) { - status_print(""); - - } else { - status_print(""); - } - } - - if((options & pe_print_rsconly) || g_list_length(rsc->running_on) > 1) { - const char *desc = NULL; - desc = crm_element_value(rsc->xml, XML_ATTR_DESC); - status_print("%s%s\t(%s%s%s:%s)%s%s", - pre_text?pre_text:"", rsc->id, - prov?prov:"", prov?"::":"", - class, crm_element_value(rsc->xml, XML_ATTR_TYPE), - desc?": ":"", desc?desc:""); - - } else { - status_print("%s%s\t(%s%s%s:%s):\t%s %s%s%s", - pre_text?pre_text:"", rsc->id, - prov?prov:"", prov?"::":"", - class, crm_element_value(rsc->xml, XML_ATTR_TYPE), - (rsc->variant!=pe_native)?"":role2text(rsc->role), - (rsc->variant!=pe_native)?"":node!=NULL?node->details->uname:"", - rsc->is_managed?"":" (unmanaged)", rsc->failed?" FAILED":""); - -#if CURSES_ENABLED - if(options & pe_print_ncurses) { - move(-1, 0); - } -#endif - } - - if(options & pe_print_html) { - status_print(" "); - } - - if((options & pe_print_rsconly)) { - - } else if(g_list_length(rsc->running_on) > 1) { - if(options & pe_print_html) { - status_print("
    \n"); - } else if((options & pe_print_printf) - || (options & pe_print_ncurses)) { - status_print("["); - } - - slist_iter(node, node_t, rsc->running_on, lpc, - if(options & pe_print_html) { - status_print("
  • \n%s", - node->details->uname); - - } else if((options & pe_print_printf) - || (options & pe_print_ncurses)) { - status_print("\t%s", node->details->uname); - - } else if((options & pe_print_log)) { - status_print("\t%d : %s", - lpc, node->details->uname); - - } else { - status_print("%s", node->details->uname); - } - if(options & pe_print_html) { - status_print("
  • \n"); - - } - ); - - if(options & pe_print_html) { - status_print("
\n"); - } else if((options & pe_print_printf) - || (options & pe_print_ncurses)) { - status_print(" ]"); - } - } - - if(options & pe_print_html) { - status_print("
\n"); - } else if((options & pe_print_printf) || (options & pe_print_ncurses)) { - status_print("\n"); - } - - if(options & pe_print_details) { - struct print_data_s pdata; - pdata.options = options; - pdata.print_data = print_data; - g_hash_table_foreach(rsc->parameters, native_print_attr, &pdata); - } - - if(options & pe_print_dev) { - status_print("%s\t(%s%svariant=%s, priority=%f)", - pre_text, rsc->provisional?"provisional, ":"", - rsc->runnable?"":"non-startable, ", - crm_element_name(rsc->xml), - (double)rsc->priority); - - status_print("%s\t%d candidate colors, %d allowed nodes," - " %d rsc_cons", - pre_text, g_list_length(rsc->candidate_colors), - g_list_length(rsc->allowed_nodes), - g_list_length(rsc->rsc_cons)); - } - - if(options & pe_print_max_details) { - status_print("%s\t=== Actions.\n", pre_text); - slist_iter( - action, action_t, rsc->actions, lpc, - log_action(LOG_DEBUG_4, "\trsc action: ", action, FALSE); - ); - - status_print("%s\t=== Colors\n", pre_text); - slist_iter( - color, color_t, rsc->candidate_colors, lpc, - print_color("\t", color, FALSE) - ); - - status_print("%s\t=== Allowed Nodes\n", pre_text); - slist_iter( - node, node_t, rsc->allowed_nodes, lpc, - print_node("\t", node, FALSE); - ); - } -} - -void native_free(resource_t *rsc) -{ - crm_debug_4("Freeing Allowed Nodes"); - crm_free(rsc->color); - common_free(rsc); -} void native_rsc_colocation_rh_must(resource_t *rsc_lh, gboolean update_lh, resource_t *rsc_rh, gboolean update_rh) { gboolean do_merge = FALSE; GListPtr old_list = NULL; GListPtr merged_node_list = NULL; int max_pri = rsc_lh->effective_priority; if(max_pri < rsc_rh->effective_priority) { max_pri = rsc_rh->effective_priority; } rsc_lh->effective_priority = max_pri; rsc_rh->effective_priority = max_pri; crm_debug_2("Colocating %s with %s." " Update LHS: %s, Update RHS: %s", rsc_lh->id, rsc_rh->id, update_lh?"true":"false", update_rh?"true":"false"); if(rsc_lh->color && rsc_rh->color) { do_merge = TRUE; merged_node_list = node_list_and( rsc_lh->color->details->candidate_nodes, rsc_rh->color->details->candidate_nodes, TRUE); } else if(rsc_lh->color) { do_merge = TRUE; merged_node_list = node_list_and( rsc_lh->color->details->candidate_nodes, rsc_rh->allowed_nodes, TRUE); } else if(rsc_rh->color) { do_merge = TRUE; merged_node_list = node_list_and( rsc_lh->allowed_nodes, rsc_rh->color->details->candidate_nodes, TRUE); } if(update_lh && rsc_rh != rsc_lh) { CRM_CHECK(rsc_lh->color != rsc_rh->color, return); crm_free(rsc_lh->color); rsc_lh->runnable = rsc_rh->runnable; rsc_lh->provisional = rsc_rh->provisional; CRM_CHECK(rsc_rh->color != NULL, return); native_assign_color(rsc_lh, rsc_rh->color); } if(update_rh && rsc_rh != rsc_lh) { CRM_CHECK(rsc_lh->color != rsc_rh->color, return); crm_free(rsc_rh->color); rsc_rh->runnable = rsc_lh->runnable; rsc_rh->provisional = rsc_lh->provisional; CRM_CHECK(rsc_lh->color != NULL, return); native_assign_color(rsc_rh, rsc_lh->color); } if((update_rh || update_lh) && do_merge) { crm_debug_4("Merging candidate nodes"); old_list = rsc_rh->color->details->candidate_nodes; rsc_rh->color->details->candidate_nodes = merged_node_list; pe_free_shallow(old_list); } crm_debug_4("Finished processing pecs_must constraint"); } void native_rsc_colocation_rh_mustnot(resource_t *rsc_lh, gboolean update_lh, resource_t *rsc_rh, gboolean update_rh) { color_t *color_lh = NULL; color_t *color_rh = NULL; crm_debug_4("Processing pecs_must_not constraint"); /* pecs_must_not */ color_rh = rsc_rh->color; color_lh = rsc_lh->color; if(update_lh) { if(rsc_lh->provisional && color_rh != NULL) { color_lh = add_color(rsc_lh, color_rh); color_lh->local_weight = -INFINITY; crm_debug_2("LH: Removed color %d from resource %s", color_lh->id, rsc_lh->id); crm_action_debug_3( print_color("Removed LH", color_lh, FALSE)); print_resource(LOG_DEBUG_3, "Modified LH", rsc_lh,TRUE); } else if(rsc_lh->provisional) { } else if(color_lh && color_lh->details->pending) { node_t *node_lh = NULL; node_lh = pe_find_node_id( color_lh->details->candidate_nodes, safe_val5(NULL, color_rh, details, chosen_node, details, id)); if(node_lh != NULL) { node_lh->weight = -INFINITY; crm_debug_2("LH: Removed node %s from color %d", node_lh->details->uname, color_lh->id); crm_action_debug_3( print_node("Removed LH", node_lh, FALSE)); crm_action_debug_3( print_color("Modified LH", color_lh, FALSE)); } } else { /* error, rsc marked as unrunnable above */ pe_warn("lh else"); } } /* in case anything was modified */ color_rh = rsc_rh->color; color_lh = rsc_lh->color; if(update_rh) { if(rsc_rh->provisional && color_lh != NULL) { color_rh = add_color(rsc_lh, color_lh); color_rh->local_weight = -INFINITY; crm_debug_2("RH: Removed color %d from resource %s", color_rh->id, rsc_rh->id); crm_action_debug_3( print_color("Removed RH", color_rh, FALSE)); print_resource(LOG_DEBUG_3, "Modified RH", rsc_rh, TRUE); } else if(rsc_rh->provisional) { } else if(color_rh && color_rh->details->pending) { node_t *node_rh = NULL; node_rh = pe_find_node_id( color_rh->details->candidate_nodes, safe_val5(NULL, color_lh, details, chosen_node, details, id)); if(node_rh != NULL) { node_rh->weight = -INFINITY; crm_debug_2("RH: Removed node %s from color %d", node_rh->details->uname, color_rh->id); crm_action_debug_3( print_node("Removed RH", node_rh, FALSE)); crm_action_debug_3( print_color("Modified RH", color_rh, FALSE)); } } else { /* error, rsc marked as unrunnable above */ pe_warn("rh else"); } } } void native_agent_constraints(resource_t *rsc) { } gboolean native_choose_color(resource_t *rsc, color_t *no_color) { GListPtr sorted_colors = NULL; if(rsc->runnable == FALSE) { native_assign_color(rsc, no_color); } if(rsc->provisional == FALSE) { return !rsc->provisional; } sorted_colors = g_list_sort( rsc->candidate_colors, sort_color_weight); rsc->candidate_colors = sorted_colors; crm_debug_2("Choose a color from %d possibilities", g_list_length(sorted_colors)); slist_iter( this_color, color_t, rsc->candidate_colors, lpc, GListPtr intersection = NULL; GListPtr minus = NULL; int len = 0; if(this_color == NULL) { pe_err("color was NULL"); continue; } else if(this_color->local_weight < 0) { /* no valid color available */ crm_debug("no valid color available"); break; } else if(rsc->effective_priority < this_color->details->highest_priority) { minus = node_list_minus( this_color->details->candidate_nodes, rsc->allowed_nodes, TRUE); len = g_list_length(minus); pe_free_shallow(minus); } else { intersection = node_list_and( this_color->details->candidate_nodes, rsc->allowed_nodes, TRUE); len = g_list_length(intersection); pe_free_shallow(intersection); } if(len > 0) { crm_debug("Assigning color to %s", rsc->id); native_assign_color(rsc, this_color); break; } ); return !rsc->provisional; } void native_assign_color(resource_t *rsc, color_t *color) { color_t *local_color = add_color(rsc, color); GListPtr intersection = NULL; GListPtr old_list = NULL; rsc->provisional = FALSE; CRM_CHECK(local_color != NULL, return); local_color->details->allocated_resources = g_list_append(local_color->details->allocated_resources,rsc); if(rsc->variant == pe_native) { (local_color->details->num_resources)++; rsc->color = copy_color(local_color); crm_debug_3("Created intersection for color %d", local_color->id); intersection = node_list_and( local_color->details->candidate_nodes, rsc->allowed_nodes, FALSE); old_list = local_color->details->candidate_nodes; pe_free_shallow(old_list); local_color->details->candidate_nodes = intersection; } crm_debug_2("Colored resource %s with color %d", rsc->id, local_color->id); return; } void native_update_node_weight(resource_t *rsc, rsc_to_node_t *cons, node_t *cons_node, GListPtr nodes) { node_t *node_rh = NULL; CRM_CHECK(cons_node != NULL, return); node_rh = pe_find_node_id( rsc->allowed_nodes, cons_node->details->id); if(node_rh == NULL) { pe_err("Node not found - adding %s to %s", cons_node->details->id, rsc->id); node_rh = node_copy(cons_node); rsc->allowed_nodes = g_list_append( rsc->allowed_nodes, node_rh); node_rh = pe_find_node_id( rsc->allowed_nodes, cons_node->details->id); CRM_CHECK(node_rh != NULL, return); return; } CRM_CHECK(node_rh != NULL, return); if(node_rh == NULL) { pe_err("Node not found - cant update"); return; } if(node_rh->weight >= INFINITY && cons_node->weight <= -INFINITY) { pe_err("Constraint \"%s\" mixes +/- INFINITY (%s)", cons->id, rsc->id); } else if(node_rh->details->shutdown == TRUE || node_rh->details->online == FALSE || node_rh->details->unclean == TRUE) { } else if(node_rh->weight <= -INFINITY && cons_node->weight >= INFINITY) { pe_err("Constraint \"%s\" mixes +/- INFINITY (%s)", cons->id, rsc->id); } if(node_rh->fixed) { /* warning */ crm_debug_2("Constraint %s is irrelevant as the" " weight of node %s is fixed as %d (%s).", cons->id, node_rh->details->uname, node_rh->weight, rsc->id); return; } crm_debug_3("Constraint %s, node %s, rsc %s: %d + %d", cons->id, node_rh->details->uname, rsc->id, node_rh->weight, cons_node->weight); node_rh->weight = merge_weights(node_rh->weight, cons_node->weight); if(node_rh->weight <= -INFINITY) { crm_debug_3("Constraint %s (-INFINITY): node %s weight %d (%s).", cons->id, node_rh->details->uname, node_rh->weight, rsc->id); } else if(node_rh->weight >= INFINITY) { crm_debug_3("Constraint %s (+INFINITY): node %s weight %d (%s).", cons->id, node_rh->details->uname, node_rh->weight, rsc->id); } else { crm_debug_3("Constraint %s (%d): node %s weight %d (%s).", cons->id, cons_node->weight, node_rh->details->uname, node_rh->weight, rsc->id); } if(node_rh->weight < 0) { node_rh->fixed = TRUE; } crm_action_debug_3(print_node("Updated", node_rh, FALSE)); return; } gboolean native_constraint_violated( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { GListPtr result = NULL; color_t *color_lh = NULL; color_t *color_rh = NULL; GListPtr candidate_nodes_lh = NULL; GListPtr candidate_nodes_rh = NULL; gboolean matched = FALSE; color_lh = rsc_lh->color; color_rh = rsc_rh->color; if(constraint->strength == pecs_must_not) { matched = TRUE; } if(rsc_lh->provisional || rsc_rh->provisional) { return FALSE; } if(color_lh == NULL && color_rh == NULL) { return matched; } else if(color_lh == NULL || color_rh == NULL) { return !matched; } else if(color_lh->details->pending && color_rh->details->pending) { candidate_nodes_lh = color_lh->details->candidate_nodes; candidate_nodes_rh = color_rh->details->candidate_nodes; } else if(color_lh->details->pending == FALSE && color_rh->details->pending == FALSE) { if(color_lh->details->chosen_node == NULL && color_rh->details->chosen_node == NULL) { return matched; } else if(color_lh->details->chosen_node == NULL || color_rh->details->chosen_node == NULL) { return !matched; } else if(safe_str_eq( color_lh->details->chosen_node->details->id, color_rh->details->chosen_node->details->id)) { return matched; } return !matched; } else if(color_lh->details->pending) { candidate_nodes_lh = color_lh->details->candidate_nodes; candidate_nodes_rh = g_list_append( NULL, color_rh->details->chosen_node); } else if(color_rh->details->pending) { candidate_nodes_rh = color_rh->details->candidate_nodes; candidate_nodes_lh = g_list_append( NULL, color_lh->details->chosen_node); } result = node_list_and(candidate_nodes_lh, candidate_nodes_rh, TRUE); if(g_list_length(result) == 0 && constraint->strength == pecs_must) { /* free result */ return TRUE; } return FALSE; } /* * Remove any nodes with a -ve weight */ void filter_nodes(resource_t *rsc) { print_resource(LOG_DEBUG_3, "Filtering nodes for: ", rsc, FALSE); slist_iter( node, node_t, rsc->allowed_nodes, lpc, if(node == NULL) { pe_err("Invalid NULL node"); } else if(node->weight < 0.0 || node->details->shutdown || node->details->online == FALSE || node->details->type == node_ping) { crm_action_debug_3(print_node("Removing", node, FALSE)); rsc->allowed_nodes = g_list_remove(rsc->allowed_nodes, node); crm_free(node); lpc = -1; /* restart the loop */ } ); } - -enum rsc_role_e -native_resource_state(resource_t *rsc) -{ - if(rsc->next_role != RSC_ROLE_UNKNOWN) { - return rsc->next_role; - } - if(rsc->role != RSC_ROLE_UNKNOWN) { - return rsc->role; - } - - return RSC_ROLE_STOPPED; -} - void create_notifications(resource_t *rsc, pe_working_set_t *data_set) { if(rsc->notify == FALSE) { return; } /* slist_iter( */ /* action, action_t, rsc->actions, lpc, */ /* ); */ } static void register_activity(resource_t *rsc, enum action_tasks task, node_t *node, notify_data_t *n_data) { notify_entry_t *entry = NULL; crm_malloc0(entry, sizeof(notify_entry_t)); entry->rsc = rsc; entry->node = node; switch(task) { case start_rsc: n_data->start = g_list_append(n_data->start, entry); break; case stop_rsc: n_data->stop = g_list_append(n_data->stop, entry); break; case action_promote: n_data->promote = g_list_append(n_data->promote, entry); break; case action_demote: n_data->demote = g_list_append(n_data->demote, entry); break; default: crm_err("Unsupported notify action: %s", task2text(task)); break; } } static void register_state(resource_t *rsc, node_t *on_node, notify_data_t *n_data) { notify_entry_t *entry = NULL; crm_malloc0(entry, sizeof(notify_entry_t)); entry->rsc = rsc; entry->node = on_node; crm_debug_2("%s state: %s", rsc->id, role2text(rsc->next_role)); switch(rsc->next_role) { case RSC_ROLE_STOPPED: /* n_data->inactive = g_list_append(n_data->inactive, entry); */ crm_free(entry); break; case RSC_ROLE_STARTED: n_data->active = g_list_append(n_data->active, entry); break; case RSC_ROLE_SLAVE: n_data->slave = g_list_append(n_data->slave, entry); break; case RSC_ROLE_MASTER: n_data->master = g_list_append(n_data->master, entry); break; default: crm_err("Unsupported notify role"); break; } } void native_create_notify_element(resource_t *rsc, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set) { node_t *next_node = NULL; gboolean registered = FALSE; char *op_key = NULL; GListPtr possible_matches = NULL; enum action_tasks task = text2task(op->task); if(op->pre_notify == NULL || op->post_notify == NULL) { /* no notifications required */ crm_debug_4("No notificaitons required for %s", op->task); return; } if(rsc->color != NULL) { next_node = rsc->color->details->chosen_node; } op_key = generate_op_key(rsc->id, op->task, 0); possible_matches = find_actions(rsc->actions, op_key, NULL); crm_debug_2("Creating notificaitons for: %s (%s->%s)", op->uuid, role2text(rsc->role), role2text(rsc->next_role)); if(rsc->role == rsc->next_role) { register_state(rsc, next_node, n_data); } slist_iter( local_op, action_t, possible_matches, lpc, local_op->notify_keys = n_data->keys; if(local_op->optional == FALSE) { registered = TRUE; register_activity(rsc, task, local_op->node, n_data); } ); /* stop / demote */ if(rsc->role != RSC_ROLE_STOPPED) { if(task == stop_rsc || task == action_demote) { slist_iter( current_node, node_t, rsc->running_on, lpc, pe_pre_notify(rsc, current_node, op, n_data, data_set); if(task == action_demote || registered == FALSE) { pe_post_notify(rsc, current_node, op, n_data, data_set); } ); } } /* start / promote */ if(rsc->next_role != RSC_ROLE_STOPPED) { CRM_CHECK(next_node != NULL,;); if(next_node == NULL) { pe_proc_err("next role: %s", role2text(rsc->next_role)); } else if(task == start_rsc || task == action_promote) { if(task != start_rsc || registered == FALSE) { pe_pre_notify(rsc, next_node, op, n_data, data_set); } pe_post_notify(rsc, next_node, op, n_data, data_set); } } crm_free(op_key); pe_free_shallow_adv(possible_matches, FALSE); } static void dup_attr(gpointer key, gpointer value, gpointer user_data) { char *meta_key = crm_concat(CRM_META, key, '_'); g_hash_table_replace(user_data, meta_key, crm_strdup(value)); } static action_t * pe_notify(resource_t *rsc, node_t *node, action_t *op, action_t *confirm, notify_data_t *n_data, pe_working_set_t *data_set) { char *key = NULL; action_t *trigger = NULL; const char *value = NULL; const char *task = NULL; if(op == NULL || confirm == NULL) { crm_debug_2("Op=%p confirm=%p", op, confirm); return NULL; } CRM_CHECK(node != NULL, return NULL); if(node->details->online == FALSE) { - crm_debug("Skipping notification for %s on %s", - rsc->id, node->details->uname); + crm_info("Skipping notification for %s", rsc->id); return NULL; } value = g_hash_table_lookup(op->meta, "notify_type"); task = g_hash_table_lookup(op->meta, "notify_operation"); crm_debug_2("Creating actions for %s: %s (%s-%s)", op->uuid, rsc->id, value, task); key = generate_notify_key(rsc->id, value, task); trigger = custom_action(rsc, key, op->task, node, op->optional, TRUE, data_set); g_hash_table_foreach(op->meta, dup_attr, trigger->extra); trigger->notify_keys = n_data->keys; /* pseudo_notify before notify */ crm_debug_3("Ordering %s before %s (%d->%d)", op->uuid, trigger->uuid, trigger->id, op->id); order_actions(op, trigger, pe_ordering_manditory); value = g_hash_table_lookup(op->meta, "notify_confirm"); if(crm_is_true(value)) { /* notify before pseudo_notified */ crm_debug_3("Ordering %s before %s (%d->%d)", trigger->uuid, confirm->uuid, confirm->id, trigger->id); order_actions(trigger, confirm, pe_ordering_manditory); } return trigger; } void pe_pre_notify(resource_t *rsc, node_t *node, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set) { crm_debug_2("%s: %s", rsc->id, op->uuid); pe_notify(rsc, node, op->pre_notify, op->pre_notified, n_data, data_set); } void pe_post_notify(resource_t *rsc, node_t *node, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set) { action_t *notify = NULL; CRM_CHECK(op != NULL, return); CRM_CHECK(rsc != NULL, return); crm_debug_2("%s: %s", rsc->id, op->uuid); notify = pe_notify(rsc, node, op->post_notify, op->post_notified, n_data, data_set); if(notify != NULL) { notify->priority = INFINITY; } notify = op->post_notified; if(notify != NULL) { notify->priority = INFINITY; slist_iter( mon, action_t, rsc->actions, lpc, const char *interval = g_hash_table_lookup(mon->meta, "interval"); if(interval == NULL || safe_str_eq(interval, "0")) { crm_debug_3("Skipping %s: interval", mon->uuid); continue; } else if(safe_str_eq(mon->task, "cancel")) { crm_debug_3("Skipping %s: cancel", mon->uuid); continue; } order_actions(notify, mon, pe_ordering_optional); ); } } void NoRoleChange(resource_t *rsc, node_t *current, node_t *next, pe_working_set_t *data_set) { action_t *start = NULL; action_t *stop = NULL; GListPtr possible_matches = NULL; crm_debug("Executing: %s (role=%s)",rsc->id, role2text(rsc->next_role)); if(current == NULL || next == NULL) { return; } /* use StartRsc/StopRsc */ if(safe_str_neq(current->details->id, next->details->id)) { crm_notice("Move resource %s\t(%s -> %s)", rsc->id, current->details->uname, next->details->uname); stop = stop_action(rsc, current, FALSE); start = start_action(rsc, next, FALSE); possible_matches = find_recurring_actions(rsc->actions, next); slist_iter(match, action_t, possible_matches, lpc, if(match->optional == FALSE) { crm_err("Found bad recurring action: %s", match->uuid); match->optional = TRUE; } ); if(data_set->remove_after_stop) { DeleteRsc(rsc, current, data_set); } } else { if(rsc->failed) { crm_notice("Recover resource %s\t(%s)", rsc->id, next->details->uname); stop = stop_action(rsc, current, FALSE); start = start_action(rsc, next, FALSE); /* /\* make the restart required *\/ */ /* order_stop_start(rsc, rsc, pe_ordering_manditory); */ } else if(rsc->start_pending) { start = start_action(rsc, next, TRUE); if(start->runnable) { /* wait for StartRsc() to be called */ rsc->role = RSC_ROLE_STOPPED; } else { /* wait for StopRsc() to be called */ rsc->next_role = RSC_ROLE_STOPPED; } } else { stop = stop_action(rsc, current, TRUE); start = start_action(rsc, next, TRUE); stop->optional = start->optional; if(start->runnable == FALSE) { rsc->next_role = RSC_ROLE_STOPPED; } else if(start->optional) { crm_notice("Leave resource %s\t(%s)", rsc->id, next->details->uname); } else { crm_notice("Restart resource %s\t(%s)", rsc->id, next->details->uname); } } } } gboolean StopRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set) { action_t *stop = NULL; crm_debug_2("Executing: %s", rsc->id); slist_iter( current, node_t, rsc->running_on, lpc, crm_notice(" %s\tStop %s", current->details->uname, rsc->id); stop = stop_action(rsc, current, FALSE); if(data_set->remove_after_stop) { DeleteRsc(rsc, current, data_set); } ); return TRUE; } -gboolean -DeleteRsc(resource_t *rsc, node_t *node, pe_working_set_t *data_set) -{ - action_t *delete = NULL; - action_t *refresh = NULL; - - char *stop = NULL; - char *start = NULL; - - if(rsc->failed) { - crm_debug_2("Resource %s not deleted from %s: failed", - rsc->id, node->details->uname); - return FALSE; - - } else if(node == NULL) { - crm_debug_2("Resource %s not deleted: NULL node", rsc->id); - return FALSE; - - } else if(node->details->unclean || node->details->online == FALSE) { - crm_debug_2("Resource %s not deleted from %s: unrunnable", - rsc->id, node->details->uname); - return FALSE; - } - - stop = stop_key(rsc); - start = start_key(rsc); - - crm_notice("Removing %s from %s", - rsc->id, node->details->uname); - - delete = delete_action(rsc, node); - - custom_action_order( - rsc, stop, NULL, rsc, NULL, delete, - pe_ordering_optional, data_set); - - custom_action_order( - rsc, NULL, delete, rsc, start, NULL, - pe_ordering_manditory, data_set); - -#if DELETE_THEN_REFRESH - refresh = custom_action( - NULL, crm_strdup(CRM_OP_LRM_REFRESH), CRM_OP_LRM_REFRESH, - node, FALSE, TRUE, data_set); - add_hash_param(refresh->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); - - custom_action_order( - rsc, NULL, delete, NULL, NULL, refresh, - pe_ordering_optional, data_set); -#endif - - - return TRUE; -} - gboolean StartRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set) { action_t *start = NULL; crm_debug_2("Executing: %s", rsc->id); start = start_action(rsc, next, TRUE); if(start->runnable) { crm_notice(" %s\tStart %s", next->details->uname, rsc->id); start->optional = FALSE; } return TRUE; } gboolean PromoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set) { char *key = NULL; gboolean runnable = TRUE; GListPtr action_list = NULL; crm_debug_2("Executing: %s", rsc->id); CRM_CHECK(rsc->next_role == RSC_ROLE_MASTER, return FALSE); key = start_key(rsc); action_list = find_actions_exact(rsc->actions, key, next); crm_free(key); slist_iter(start, action_t, action_list, lpc, if(start->runnable == FALSE) { runnable = FALSE; } ); if(runnable) { promote_action(rsc, next, FALSE); crm_notice("%s\tPromote %s", next->details->uname, rsc->id); return TRUE; } crm_debug("%s\tPromote %s (canceled)", next->details->uname, rsc->id); key = promote_key(rsc); action_list = find_actions_exact(rsc->actions, key, next); crm_free(key); slist_iter(promote, action_t, action_list, lpc, promote->runnable = FALSE; ); return TRUE; } gboolean DemoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set) { crm_debug_2("Executing: %s", rsc->id); /* CRM_CHECK(rsc->next_role == RSC_ROLE_SLAVE, return FALSE); */ slist_iter( current, node_t, rsc->running_on, lpc, crm_notice("%s\tDeomote %s", current->details->uname, rsc->id); demote_action(rsc, current, FALSE); ); return TRUE; } gboolean RoleError(resource_t *rsc, node_t *next, pe_working_set_t *data_set) { crm_debug("Executing: %s", rsc->id); CRM_CHECK(FALSE, return FALSE); return FALSE; } gboolean NullOp(resource_t *rsc, node_t *next, pe_working_set_t *data_set) { crm_debug("Executing: %s", rsc->id); return FALSE; } gboolean native_create_probe(resource_t *rsc, node_t *node, action_t *complete, gboolean force, pe_working_set_t *data_set) { char *key = NULL; char *target_rc = NULL; action_t *probe = NULL; node_t *running = NULL; CRM_CHECK(node != NULL, return FALSE); if(rsc->orphan) { crm_debug_2("Skipping orphan: %s", rsc->id); return FALSE; } running = pe_find_node_id(rsc->known_on, node->details->id); if(force == FALSE && running != NULL) { /* we already know the status of the resource on this node */ crm_debug_3("Skipping active: %s", rsc->id); return FALSE; } key = generate_op_key(rsc->id, CRMD_ACTION_STATUS, 0); probe = custom_action(rsc, key, CRMD_ACTION_STATUS, node, FALSE, TRUE, data_set); probe->priority = INFINITY; running = pe_find_node_id(rsc->running_on, node->details->id); if(running == NULL) { target_rc = crm_itoa(EXECRA_NOT_RUNNING); add_hash_param(probe->meta, XML_ATTR_TE_TARGET_RC, target_rc); crm_free(target_rc); } crm_notice("%s: Created probe for %s", node->details->uname, rsc->id); custom_action_order(rsc, NULL, probe, rsc, NULL, complete, pe_ordering_manditory, data_set); return TRUE; } void native_stonith_ordering( resource_t *rsc, action_t *stonith_op, pe_working_set_t *data_set) { gboolean run_unprotected = TRUE; const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); if(stonith_op != NULL && safe_str_eq(class, "stonith")) { char *key = start_key(rsc); crm_debug("Ordering %s before stonith op", key); custom_action_order( rsc, key, NULL, NULL, crm_strdup(CRM_OP_FENCE), stonith_op, pe_ordering_optional, data_set); return; } slist_iter(action, action_t, rsc->actions, lpc2, if(action->needs != rsc_req_stonith) { continue; } if(stonith_op != NULL) { custom_action_order( NULL, crm_strdup(CRM_OP_FENCE), stonith_op, rsc, NULL, action, pe_ordering_manditory, data_set); } else if(run_unprotected == FALSE) { /* mark the start unrunnable */ action->runnable = FALSE; } else { pe_err("SHARED RESOURCE %s IS NOT PROTECTED:" " Stonith disabled", rsc->id); } ); } diff --git a/crm/pengine/pe_rules.h b/crm/pengine/pe_rules.h deleted file mode 100644 index 0dc0c7e15f..0000000000 --- a/crm/pengine/pe_rules.h +++ /dev/null @@ -1,42 +0,0 @@ -/* $Id: pe_rules.h,v 1.5 2005/09/15 08:05:24 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 - */ -#ifndef PENGINE_RULES__H -#define PENGINE_RULES__H - -enum expression_type { - not_expr, - nested_rule, - attr_expr, - loc_expr, - role_expr, - time_expr -}; - -extern enum expression_type find_expression_type(crm_data_t *expr); - -extern gboolean test_ruleset( - crm_data_t *ruleset, node_t *node, pe_working_set_t *data_set); - -extern gboolean test_rule(crm_data_t *rule, node_t *node, resource_t *rsc, - pe_working_set_t *data_set); - -extern gboolean test_expression(crm_data_t *expr, node_t *node, resource_t *rsc, - pe_working_set_t *data_set); - -#endif diff --git a/crm/pengine/pe_utils.h b/crm/pengine/pe_utils.h deleted file mode 100644 index 326461cabb..0000000000 --- a/crm/pengine/pe_utils.h +++ /dev/null @@ -1,196 +0,0 @@ -/* $Id: pe_utils.h,v 1.46 2006/05/30 08:54:32 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 - */ -#ifndef PE_UTILS__H -#define PE_UTILS__H - - -/* General utilities */ -extern resource_t *pe_find_resource(GListPtr rsc_list, const char *id_rh); - -extern int merge_weights(int w1, int w2); - -/* Constraint helper functions */ -extern rsc_colocation_t *invert_constraint(rsc_colocation_t *constraint); - -extern rsc_to_node_t *copy_constraint(rsc_to_node_t *constraint); - -/* Color helper functions */ -extern void add_color_to_rsc(resource_t *rsc, color_t *color); - -extern color_t *find_color(GListPtr candidate_colors, color_t *other_color); - -extern color_t *create_color( - pe_working_set_t *data_set, resource_t *resource, GListPtr resources); - -extern color_t *copy_color(color_t *a_color); - -/* Node helper functions */ -extern node_t *pe_find_node_id(GListPtr node_list, const char *id); - -extern node_t *node_copy(node_t *this_node) ; - - -/* Binary like operators for lists of nodes */ -extern GListPtr node_list_dup(GListPtr list1, gboolean reset, gboolean filter); - -extern GListPtr node_list_and(GListPtr list1, GListPtr list2, gboolean filter); - -extern GListPtr node_list_xor(GListPtr list1, GListPtr list2, gboolean filter); - -extern GListPtr node_list_minus(GListPtr list1,GListPtr list2,gboolean filter); - -extern gboolean node_list_eq(GListPtr list1, GListPtr list2, gboolean filter); - -extern GListPtr node_list_or(GListPtr list1, GListPtr list2, gboolean filter); - - - -/* For creating the transition graph */ -extern crm_data_t *action2xml(action_t *action, gboolean as_input); - -/* Printing functions for debug */ -extern void print_node( - const char *pre_text, node_t *node, gboolean details); - -extern void print_resource( - int log_level, const char *pre_text, resource_t *rsc, gboolean details); - -extern void print_rsc_to_node( - const char *pre_text, rsc_to_node_t *cons, gboolean details); - -extern void print_rsc_colocation( - const char *pre_text, rsc_colocation_t *cons, gboolean details); - -extern void print_color( - const char *pre_text, color_t *color, gboolean details); - -extern void print_color_details( - const char *pre_text, struct color_shared_s *color, gboolean details); - -extern void log_action( - unsigned int log_level, const char *pre_text, action_t *action, gboolean details); - -/* Sorting functions */ -extern gint sort_rsc_priority(gconstpointer a, gconstpointer b); -extern gint sort_rsc_node_weight(gconstpointer a, gconstpointer b); -extern gint sort_cons_strength(gconstpointer a, gconstpointer b); -extern gint sort_color_weight(gconstpointer a, gconstpointer b); -extern gint sort_node_weight(gconstpointer a, gconstpointer b); -extern gint sort_action_id(gconstpointer a, gconstpointer b); - -/* enum 2 text functions (mostly used by print_*) */ -extern const char *contype2text(enum con_type type); -extern const char *strength2text(enum con_strength strength); - -extern const char *task2text(enum action_tasks task); -extern enum action_tasks text2task(const char *task); - -extern enum rsc_role_e text2role(const char *role); -extern const char *role2text(enum rsc_role_e role); - -extern crm_data_t *find_rsc_op_entry(resource_t *rsc, const char *key); - -extern action_t *custom_action( - resource_t *rsc, char *key, const char *task, node_t *on_node, - gboolean optional, gboolean foo, pe_working_set_t *data_set); - -extern rsc_to_node_t *rsc2node_new( - const char *id, resource_t *rsc, int weight, node_t *node, - pe_working_set_t *data_set); - -#define delete_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_DELETE, 0) -#define delete_action(rsc, node) custom_action( \ - rsc, delete_key(rsc), CRMD_ACTION_DELETE, node, \ - FALSE, TRUE, data_set); - -#define stopped_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_STOPPED, 0) -#define stopped_action(rsc, node, optional) custom_action( \ - rsc, stopped_key(rsc), CRMD_ACTION_STOPPED, node, \ - optional, TRUE, data_set); - -#define stop_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_STOP, 0) -#define stop_action(rsc, node, optional) custom_action( \ - rsc, stop_key(rsc), CRMD_ACTION_STOP, node, \ - optional, TRUE, data_set); - -#define start_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_START, 0) -#define start_action(rsc, node, optional) custom_action( \ - rsc, start_key(rsc), CRMD_ACTION_START, node, \ - optional, TRUE, data_set) - -#define started_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_STARTED, 0) -#define started_action(rsc, node, optional) custom_action( \ - rsc, started_key(rsc), CRMD_ACTION_STARTED, node, \ - optional, TRUE, data_set) - -#define promote_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_PROMOTE, 0) -#define promote_action(rsc, node, optional) custom_action( \ - rsc, promote_key(rsc), CRMD_ACTION_PROMOTE, node, \ - optional, TRUE, data_set) - -#define promoted_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_PROMOTED, 0) -#define promoted_action(rsc, node, optional) custom_action( \ - rsc, promoted_key(rsc), CRMD_ACTION_PROMOTED, node, \ - optional, TRUE, data_set) - -#define demote_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_DEMOTE, 0) -#define demote_action(rsc, node, optional) custom_action( \ - rsc, demote_key(rsc), CRMD_ACTION_DEMOTE, node, \ - optional, TRUE, data_set) - -#define demoted_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_DEMOTED, 0) -#define demoted_action(rsc, node, optional) custom_action( \ - rsc, demoted_key(rsc), CRMD_ACTION_DEMOTED, node, \ - optional, TRUE, data_set) - -extern GListPtr find_actions(GListPtr input, const char *key, node_t *on_node); -extern GListPtr find_actions_exact( - GListPtr input, const char *key, node_t *on_node); -extern GListPtr find_recurring_actions(GListPtr input, node_t *not_on_node); - -extern void set_id(crm_data_t *xml_obj, const char *prefix, int child); - -extern const char *ordering_type2text(enum pe_ordering type); -extern const char *fail2text(enum action_fail_response fail); - -extern int char2score(const char *score); -extern char *score2char(int score); - - -/* free the various structures */ -extern void pe_free_nodes(GListPtr nodes); -extern void pe_free_colors(GListPtr colors); -extern void pe_free_rsc_colocation(rsc_colocation_t *cons); -extern void pe_free_rsc_to_node(rsc_to_node_t *cons); -extern void pe_free_shallow(GListPtr alist); -extern void pe_free_shallow_adv(GListPtr alist, gboolean with_data); -extern void pe_free_resources(GListPtr resources); -extern void pe_free_action(action_t *action); -extern void pe_free_actions(GListPtr actions); -extern void pe_free_ordering(GListPtr constraints); - -/* Helper macros to avoid NULL pointers */ -#define safe_val(def, x,y) (x?x->y:def) -#define safe_val3(def, t,u,v) (t?t->u?t->u->v:def:def) -#define safe_val4(def, t,u,v,w) (t?t->u?t->u->v?t->u->v->w:def:def:def) -#define safe_val5(def, t,u,v,w,x) (t?t->u?t->u->v?t->u->v->w?t->u->v->w->x:def:def:def:def) -#define safe_val6(def, t,u,v,w,x,y) (t?t->u?t->u->v?t->u->v->w?t->u->v->w->x?t->u->v->w->x->y:def:def:def:def:def) -#define safe_val7(def, t,u,v,w,x,y,z) (t?t->u?t->u->v?t->u->v->w?t->u->v->w->x?t->u->v->w->x->y?t->u->v->w->x->y->z:def:def:def:def:def:def) - -#endif diff --git a/crm/pengine/pengine.c b/crm/pengine/pengine.c index 7bc9f816bc..82a394982b 100755 --- a/crm/pengine/pengine.c +++ b/crm/pengine/pengine.c @@ -1,402 +1,295 @@ -/* $Id: pengine.c,v 1.113 2006/06/02 15:39:14 andrew Exp $ */ +/* $Id: pengine.c,v 1.114 2006/06/07 12:46:59 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 crm_data_t * do_calculations( pe_working_set_t *data_set, crm_data_t *xml_input, ha_time_t *now); -gboolean was_processing_error = FALSE; -gboolean was_processing_warning = FALSE; -gboolean was_config_error = FALSE; -gboolean was_config_warning = FALSE; -unsigned int pengine_input_loglevel = LOG_INFO; - #define PE_WORKING_DIR HA_VARLIBDIR"/heartbeat/pengine" extern int transition_id; #define get_series() was_processing_error?1:was_processing_warning?2:3 typedef struct series_s { int id; const char *name; const char *param; int wrap; } series_t; series_t series[] = { { 0, "pe-unknown", "_dont_match_anything_", -1 }, { 0, "pe-error", "pe-error-series-max", -1 }, { 0, "pe-warn", "pe-warn-series-max", 200 }, { 0, "pe-input", "pe-input-series-max", 400 }, }; gboolean process_pe_message(HA_Message *msg, crm_data_t * xml_data, IPC_Channel *sender) { const char *sys_to = cl_get_string(msg, F_CRM_SYS_TO); const char *op = cl_get_string(msg, F_CRM_TASK); const char *ref = cl_get_string(msg, XML_ATTR_REFERENCE); crm_debug_3("Processing %s op (ref=%s)...", op, ref); if(op == NULL){ /* error */ } else if(strcasecmp(op, CRM_OP_HELLO) == 0) { /* ignore */ } else if(safe_str_eq(cl_get_string(msg, F_CRM_MSG_TYPE), XML_ATTR_RESPONSE)) { /* ignore */ } else if(sys_to == NULL || strcasecmp(sys_to, CRM_SYSTEM_PENGINE) != 0) { crm_debug_3("Bad sys-to %s", crm_str(sys_to)); return FALSE; } else if(strcasecmp(op, CRM_OP_PECALC) == 0) { int seq = -1; int series_id = 0; int series_wrap = 0; char *filename = NULL; const char *value = NULL; pe_working_set_t data_set; crm_data_t *generation = create_xml_node(NULL, XML_TAG_CIB); crm_data_t *log_input = copy_xml(xml_data); #if HAVE_BZLIB_H gboolean compress = TRUE; #else gboolean compress = FALSE; #endif copy_in_properties(generation, xml_data); crm_log_xml_info(generation, "[generation]"); was_processing_error = FALSE; was_processing_warning = FALSE; crm_zero_mem_stats(NULL); do_calculations(&data_set, xml_data, NULL); crm_log_xml_debug_3(data_set.graph, "[out]"); -#if 1 if(send_ipc_reply(sender, msg, data_set.graph) == FALSE) { crm_err("Answer could not be sent"); } -#else - HA_Message *reply = NULL; - - reply = create_reply(msg, NULL); - if (reply != NULL) { - char *tmp_file = mktemp(HA_VARRUNHBDIR"/tgraph-XXXXXX"); - write_xml_file(data_set.graph, tmp_file, FALSE); - ha_msg_add(reply, "on-disk-graph", tmp_file); - crm_free(tmp_file); - if(send_ipc_message(sender, reply) == FALSE) { - crm_err("Answer could not be sent"); - } - } -#endif + series_id = get_series(); series_wrap = series[series_id].wrap; value = g_hash_table_lookup( data_set.config_hash, series[series_id].param); if(value != NULL) { series_wrap = crm_int_helper(value, NULL); if(errno != 0) { series_wrap = series[series_id].wrap; } } else { pe_config_warn("No value specified for cluster" " preference: %s", series[series_id].param); } data_set.input = NULL; cleanup_calculations(&data_set); if(is_ipc_empty(sender) && crm_mem_stats(NULL)) { pe_warn("Unfree'd memory"); } seq = get_last_sequence(PE_WORKING_DIR, series[series_id].name); filename = generate_series_filename( PE_WORKING_DIR, series[series_id].name, seq, compress); write_xml_file(log_input, filename, compress); write_last_sequence(PE_WORKING_DIR, series[series_id].name, seq+1, series_wrap); if(was_processing_error) { crm_err("Transition %d:" " ERRORs found during PE processing." " PEngine Input stored in: %s", transition_id, filename); } else if(was_processing_warning) { crm_warn("Transition %d:" " WARNINGs found during PE processing." " PEngine Input stored in: %s", transition_id, filename); } else { crm_info("Transition %d: PEngine Input stored in: %s", transition_id, filename); } if(was_config_error) { crm_info("Configuration ERRORs found during PE processing." " Please run \"crm_verify -L\" to identify issues."); } else if(was_processing_warning) { crm_info("Configuration WARNINGs found during PE processing." " Please run \"crm_verify -L\" to identify issues."); } free_xml(generation); free_xml(log_input); crm_free(filename); } else if(strcasecmp(op, CRM_OP_QUIT) == 0) { crm_warn("Received quit message, terminating"); exit(0); } return TRUE; } #define MEMCHECK_STAGE_0 0 #define check_and_exit(stage) cleanup_calculations(data_set); \ crm_mem_stats(NULL); \ crm_err("Exiting: stage %d", stage); \ exit(1); crm_data_t * do_calculations(pe_working_set_t *data_set, crm_data_t *xml_input, ha_time_t *now) { int rsc_log_level = LOG_INFO; /* pe_debug_on(); */ set_working_set_defaults(data_set); data_set->input = xml_input; data_set->now = now; if(data_set->now == NULL) { data_set->now = new_ha_date(TRUE); } #if MEMCHECK_STAGE_SETUP check_and_exit(-1); #endif - crm_debug_5("unpack"); + crm_debug_5("unpack constraints"); stage0(data_set); #if MEMCHECK_STAGE_0 check_and_exit(0); #endif slist_iter(rsc, resource_t, data_set->resources, lpc, rsc->fns->print(rsc, NULL, pe_print_log, &rsc_log_level); ); crm_debug_5("apply placement constraints"); stage1(data_set); #if MEMCHECK_STAGE_1 check_and_exit(1); #endif crm_debug_5("color resources"); stage2(data_set); #if MEMCHECK_STAGE_2 check_and_exit(2); #endif /* unused */ stage3(data_set); #if MEMCHECK_STAGE_3 check_and_exit(3); #endif crm_debug_5("assign nodes to colors"); stage4(data_set); #if MEMCHECK_STAGE_4 check_and_exit(4); #endif crm_debug_5("creating actions and internal ording constraints"); stage5(data_set); #if MEMCHECK_STAGE_5 check_and_exit(5); #endif crm_debug_5("processing fencing and shutdown cases"); stage6(data_set); #if MEMCHECK_STAGE_6 check_and_exit(6); #endif crm_debug_5("applying ordering constraints"); stage7(data_set); #if MEMCHECK_STAGE_7 check_and_exit(7); #endif crm_debug_5("creating transition graph"); stage8(data_set); #if MEMCHECK_STAGE_8 check_and_exit(8); #endif crm_debug_2("=#=#=#=#= Summary =#=#=#=#="); crm_debug_2("========= All Actions ========="); slist_iter(action, action_t, data_set->actions, lpc, log_action(LOG_DEBUG_2, "\t", action, TRUE) ); crm_debug_2("\t========= Set %d (Un-runnable) =========", -1); crm_action_debug_2( slist_iter(action, action_t, data_set->actions, lpc, if(action->optional == FALSE && action->runnable == FALSE && action->pseudo == FALSE) { log_action(LOG_DEBUG_2, "\t", action, TRUE); } ) ); return data_set->graph; } - -void -cleanup_calculations(pe_working_set_t *data_set) -{ - GListPtr iterator = NULL; - - if(data_set == NULL) { - return; - } - - if(data_set->config_hash != NULL) { - g_hash_table_destroy(data_set->config_hash); - } - - crm_free(data_set->dc_uuid); - crm_free(data_set->transition_idle_timeout); - - crm_debug_3("deleting order cons"); - pe_free_ordering(data_set->ordering_constraints); - - crm_debug_3("deleting actions"); - pe_free_actions(data_set->actions); - - crm_debug_3("deleting resources"); - pe_free_resources(data_set->resources); - - crm_debug_3("deleting nodes"); - pe_free_nodes(data_set->nodes); - - crm_debug_3("deleting colors"); - pe_free_colors(data_set->colors); - - crm_debug_3("deleting node cons"); - iterator = data_set->placement_constraints; - while(iterator) { - pe_free_rsc_to_node(iterator->data); - iterator = iterator->next; - } - if(data_set->placement_constraints != NULL) { - g_list_free(data_set->placement_constraints); - } - free_xml(data_set->graph); - free_ha_date(data_set->now); - free_xml(data_set->input); - data_set->stonith_action = NULL; -} - - -void -set_working_set_defaults(pe_working_set_t *data_set) -{ - data_set->input = NULL; - data_set->now = NULL; - data_set->graph = NULL; - - data_set->transition_idle_timeout = crm_strdup("60s"); - data_set->dc_uuid = NULL; - data_set->dc_node = NULL; - data_set->have_quorum = FALSE; - data_set->stonith_enabled = FALSE; - data_set->stonith_action = NULL; - data_set->symmetric_cluster = TRUE; - data_set->is_managed_default = TRUE; - data_set->no_quorum_policy = no_quorum_freeze; - - data_set->remove_after_stop = FALSE; - data_set->stop_action_orphans = TRUE; - data_set->stop_rsc_orphans = TRUE; - - data_set->config_hash = NULL; - data_set->nodes = NULL; - data_set->resources = NULL; - data_set->ordering_constraints = NULL; - data_set->placement_constraints = NULL; - - data_set->no_color = NULL; - data_set->colors = NULL; - data_set->actions = NULL; - - data_set->num_synapse = 0; - data_set->max_valid_nodes = 0; - data_set->order_id = 1; - data_set->action_id = 1; - data_set->color_id = 0; - - data_set->default_resource_stickiness = 0; - data_set->default_resource_fail_stickiness = 0; -} diff --git a/crm/pengine/ptest.c b/crm/pengine/ptest.c index f9a703cad5..212e3997aa 100644 --- a/crm/pengine/ptest.c +++ b/crm/pengine/ptest.c @@ -1,422 +1,422 @@ -/* $Id: ptest.c,v 1.75 2006/05/17 07:59:02 andrew Exp $ */ +/* $Id: ptest.c,v 1.76 2006/06/07 12:46:59 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 #define OPTARGS "V?X:D:G:I:Lwx" #ifdef HAVE_GETOPT_H # include #endif #include -#include -#include +#include +#include gboolean use_stdin = FALSE; gboolean inhibit_exit = FALSE; extern crm_data_t * do_calculations( pe_working_set_t *data_set, crm_data_t *xml_input, ha_time_t *now); extern void cleanup_calculations(pe_working_set_t *data_set); FILE *dot_strm = NULL; #define DOT_PREFIX "PE_DOT: " /* #define DOT_PREFIX "" */ #define dot_write(fmt...) if(dot_strm != NULL) { \ fprintf(dot_strm, fmt); \ fprintf(dot_strm, "\n"); \ fflush(dot_strm); \ } else { \ crm_debug(DOT_PREFIX""fmt); \ } static void init_dotfile(void) { dot_write("digraph \"g\" {"); dot_write(" size = \"30,30\""); /* dot_write(" graph ["); */ /* dot_write(" fontsize = \"12\""); */ /* dot_write(" fontname = \"Times-Roman\""); */ /* dot_write(" fontcolor = \"black\""); */ /* dot_write(" bb = \"0,0,398.922306,478.927856\""); */ /* dot_write(" color = \"black\""); */ /* dot_write(" ]"); */ /* dot_write(" node ["); */ /* dot_write(" fontsize = \"12\""); */ /* dot_write(" fontname = \"Times-Roman\""); */ /* dot_write(" fontcolor = \"black\""); */ /* dot_write(" shape = \"ellipse\""); */ /* dot_write(" color = \"black\""); */ /* dot_write(" ]"); */ /* dot_write(" edge ["); */ /* dot_write(" fontsize = \"12\""); */ /* dot_write(" fontname = \"Times-Roman\""); */ /* dot_write(" fontcolor = \"black\""); */ /* dot_write(" color = \"black\""); */ /* dot_write(" ]"); */ } static void usage(const char *cli, int exitcode) { FILE *out = exitcode?stderr:stdout; fprintf(out, "Usage: %s -(?|L|X|x) [-V] [-D] [-G] [-I]\n", cli); fprintf(out, " --%s (-%c): This text\n\n", "help", '?'); fprintf(out, " --%s (-%c): Increase verbosity (can be supplied multiple times)\n\n", "verbose", 'V'); fprintf(out, " --%s (-%c): Connect to the CIB and use the current contents as input\n", "live-check", 'L'); fprintf(out, " --%s (-%c): Look for xml on stdin\n", "xml-stream", 'x'); fprintf(out, " --%s (-%c)\t : Look for xml in the named file\n\n", "xml-file", 'X'); fprintf(out, " --%s (-%c)\t : Save the transition graph to the named file\n", "save-graph", 'G'); fprintf(out, " --%s (-%c)\t : Save the DOT formatted transition graph to the named file\n", "save-dotfile", 'D'); fprintf(out, " --%s (-%c)\t : Save the input to the named file\n", "save-input", 'I'); exit(exitcode); } static char * create_action_name(action_t *action) { char *action_name = NULL; const char *action_host = NULL; if(action->node) { action_host = action->node->details->uname; action_name = crm_concat(action->uuid, action_host, ' '); } else if(action->pseudo) { action_name = crm_strdup(action->uuid); } else { action_host = ""; action_name = crm_concat(action->uuid, action_host, ' '); } return action_name; } gboolean USE_LIVE_CIB = FALSE; int main(int argc, char **argv) { enum transition_status graph_rc = -1; crm_graph_t *transition = NULL; const char *fake_now = NULL; ha_time_t *a_date = NULL; cib_t * cib_conn = NULL; crm_data_t * cib_object = NULL; int argerr = 0; int flag; char *msg_buffer = NULL; gboolean optional = FALSE; pe_working_set_t data_set; const char *xml_file = NULL; const char *dot_file = NULL; const char *graph_file = NULL; const char *input_file = NULL; cl_log_set_entity("ptest"); cl_log_set_facility(LOG_USER); set_crm_log_level(LOG_CRIT-1); while (1) { #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {"help", 0, 0, '?'}, {"verbose", 0, 0, 'V'}, {"live-check", 0, 0, 'L'}, {"xml-stream", 0, 0, 'x'}, {"xml-file", 1, 0, 'X'}, {"save-graph", 1, 0, 'G'}, {"save-dotfile",1, 0, 'D'}, {"save-input", 1, 0, 'I'}, {0, 0, 0, 0} }; #endif #ifdef HAVE_GETOPT_H flag = getopt_long(argc, argv, OPTARGS, long_options, &option_index); #else flag = getopt(argc, argv, OPTARGS); #endif if (flag == -1) break; switch(flag) { #ifdef HAVE_GETOPT_H case 0: printf("option %s", long_options[option_index].name); if (optarg) printf(" with arg %s", optarg); printf("\n"); break; #endif case 'w': inhibit_exit = TRUE; break; case 'x': use_stdin = TRUE; break; case 'X': xml_file = crm_strdup(optarg); break; case 'D': dot_file = crm_strdup(optarg); break; case 'G': graph_file = crm_strdup(optarg); break; case 'I': input_file = crm_strdup(optarg); break; case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case 'L': USE_LIVE_CIB = TRUE; break; case '?': usage("ptest", 0); break; default: printf("?? getopt returned character code 0%o ??\n", flag); ++argerr; break; } } if (optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) { printf("%s ", argv[optind++]); } printf("\n"); } if (optind > argc) { ++argerr; } if (argerr) { crm_err("%d errors in option parsing", argerr); usage("ptest", 1); } crm_info("=#=#=#=#= Getting XML =#=#=#=#="); if(USE_LIVE_CIB) { int rc = cib_ok; cib_conn = cib_new(); rc = cib_conn->cmds->signon( cib_conn, "ptest", cib_command_synchronous); if(rc == cib_ok) { crm_info("Reading XML from: live cluster"); cib_object = get_cib_copy(cib_conn); } else { fprintf(stderr, "Live CIB query failed: %s\n", cib_error2string(rc)); return 3; } if(cib_object == NULL) { fprintf(stderr, "Live CIB query failed: empty result\n"); return 3; } } else if(xml_file != NULL) { FILE *xml_strm = fopen(xml_file, "r"); cib_object = file2xml(xml_strm); } else if(use_stdin) { cib_object = stdin2xml(); } else { usage("ptest", 1); } #ifdef MCHECK mtrace(); #endif CRM_CHECK(cib_object != NULL, return 4); crm_notice("Required feature set: %s", feature_set(cib_object)); do_id_check(cib_object, NULL, FALSE, FALSE); if(input_file != NULL) { FILE *input_strm = fopen(input_file, "w"); msg_buffer = dump_xml_formatted(cib_object); fprintf(input_strm, "%s\n", msg_buffer); fflush(input_strm); fclose(input_strm); crm_free(msg_buffer); } crm_zero_mem_stats(NULL); fake_now = crm_element_value(cib_object, "fake_now"); if(fake_now != NULL) { char *fake_now_copy = crm_strdup(fake_now); char *fake_now_mutable = fake_now_copy; a_date = parse_date(&fake_now_mutable); log_date(LOG_WARNING, "Set fake 'now' to", a_date, ha_log_date|ha_log_time); log_date(LOG_WARNING, "Set fake 'now' to (localtime)", a_date, ha_log_date|ha_log_time|ha_log_local); crm_free(fake_now_copy); } do_calculations(&data_set, cib_object, a_date); msg_buffer = dump_xml_formatted(data_set.graph); if(graph_file != NULL) { FILE *graph_strm = fopen(graph_file, "w"); fprintf(graph_strm, "%s\n", msg_buffer); fflush(graph_strm); fclose(graph_strm); } else { fprintf(stdout, "%s\n", msg_buffer); fflush(stdout); } crm_free(msg_buffer); dot_strm = fopen(dot_file, "w"); init_dotfile(); slist_iter( action, action_t, data_set.actions, lpc, char *action_name = create_action_name(action); crm_debug_3("Action %d: %p", action->id, action); if(action->dumped == FALSE) { if(action->rsc != NULL && action->rsc->is_managed == FALSE) { dot_write("\"%s\" [ font_color=black style=filled fillcolor=%s ]", action_name, "purple"); } else if(action->optional) { dot_write("\"%s\" [ style=\"dashed\" color=\"%s\" fontcolor=\"%s\" ]", action_name, "blue", action->pseudo?"orange":"black"); } else { dot_write("\"%s\" [ font_color=purple style=filled fillcolor=%s ]", action_name, "red"); CRM_CHECK(action->runnable == FALSE, ;); } } else { dot_write("\"%s\" [ style=bold color=\"%s\" fontcolor=\"%s\" ]", action_name, "green", action->pseudo?"orange":"black"); } crm_free(action_name); ); slist_iter( action, action_t, data_set.actions, lpc, int last_action = -1; slist_iter( before, action_wrapper_t, action->actions_before, lpc2, char *before_name = NULL; char *after_name = NULL; optional = FALSE; if(last_action == before->action->id) { continue; } last_action = before->action->id; if(action->dumped && before->action->dumped) { } else if(action->optional || before->action->optional) { optional = TRUE; } before_name = create_action_name(before->action); after_name = create_action_name(action); dot_write("\"%s\" -> \"%s\" [ style = %s]", before_name, after_name, optional?"dashed":"bold"); crm_free(before_name); crm_free(after_name); ); ); dot_write("}"); transition = unpack_graph(data_set.graph); print_graph(LOG_NOTICE, transition); do { graph_rc = run_graph(transition); } while(graph_rc == transition_active); if(graph_rc != transition_complete) { crm_crit("Transition failed: %s", transition_status(graph_rc)); print_graph(LOG_ERR, transition); } data_set.input = NULL; cleanup_calculations(&data_set); destroy_graph(transition); crm_mem_stats(NULL); CRM_CHECK(crm_mem_stats(NULL) == FALSE, crm_err("Memory leak detected")); CRM_CHECK(graph_rc == transition_complete, crm_err("An invalid transition was produced")); crm_free(cib_object); #ifdef MCHECK muntrace(); #endif /* required for MallocDebug.app */ if(inhibit_exit) { GMainLoop* mainloop = g_main_new(FALSE); g_main_run(mainloop); } return 0; } diff --git a/crm/pengine/rules.c b/crm/pengine/rules.c deleted file mode 100644 index 99b25b28cf..0000000000 --- a/crm/pengine/rules.c +++ /dev/null @@ -1,481 +0,0 @@ -/* $Id: rules.c,v 1.26 2006/05/30 09:24:03 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 - -ha_time_t *parse_xml_duration(ha_time_t *start, crm_data_t *duration_spec); - -gboolean test_date_expression(crm_data_t *time_expr, pe_working_set_t *data_set); -gboolean cron_range_satisfied(ha_time_t *now, crm_data_t *cron_spec); -gboolean test_attr_expression( - crm_data_t *expr, GHashTable *hash, pe_working_set_t *data_set); -gboolean test_role_expression( - crm_data_t *expr, resource_t *rsc, pe_working_set_t *data_set); - -gboolean -test_ruleset(crm_data_t *ruleset, node_t *node, pe_working_set_t *data_set) -{ - gboolean ruleset_default = TRUE; - xml_child_iter_filter( - ruleset, rule, XML_TAG_RULE, - - ruleset_default = FALSE; - if(test_rule(rule, node, NULL, data_set)) { - return TRUE; - } - ); - - return ruleset_default; -} - -gboolean -test_rule(crm_data_t *rule, node_t *node, resource_t *rsc, - pe_working_set_t *data_set) -{ - gboolean test = TRUE; - gboolean passed = TRUE; - gboolean do_and = TRUE; - - const char *value = crm_element_value(rule, "boolean_op"); - if(safe_str_eq(value, "or")) { - do_and = FALSE; - passed = FALSE; - } - - crm_debug_2("Testing rule %s", ID(rule)); - xml_child_iter( - rule, expr, - test = test_expression(expr, node, rsc, data_set); - - if(test && do_and == FALSE) { - crm_debug_3("Expression %s/%s passed", - ID(rule), ID(expr)); - return TRUE; - - } else if(test == FALSE && do_and) { - crm_debug_3("Expression %s/%s failed", - ID(rule), ID(expr)); - return FALSE; - } - ); - - crm_debug_2("Rule %s %s", ID(rule), passed?"passed":"failed"); - return passed; -} - -gboolean -test_expression(crm_data_t *expr, node_t *node, resource_t *rsc, - pe_working_set_t *data_set) -{ - gboolean accept = FALSE; - - switch(find_expression_type(expr)) { - case nested_rule: - accept = test_rule(expr, node, rsc, data_set); - break; - case attr_expr: - case loc_expr: - /* these expressions can never succeed if there is - * no node to compare with - */ - if(node != NULL) { - accept = test_attr_expression( - expr, node->details->attrs, data_set); - } - break; - - case time_expr: - accept = test_date_expression(expr, data_set); - break; - - case role_expr: - if(rsc != NULL) { - accept = test_role_expression(expr, rsc, data_set); - } - break; - - default: - CRM_CHECK(FALSE /* bad type */, return FALSE); - accept = FALSE; - } - - crm_debug_2("Expression %s %s on %s for %s", - ID(expr), accept?"passed":"failed", - node?node->details->uname:"all ndoes", - rsc?rsc->id:"all resources"); - return accept; -} - -enum expression_type -find_expression_type(crm_data_t *expr) -{ - const char *tag = NULL; - const char *attr = NULL; - attr = crm_element_value(expr, XML_EXPR_ATTR_ATTRIBUTE); - tag = crm_element_name(expr); - - if(safe_str_eq(tag, "date_expression")) { - return time_expr; - - } else if(safe_str_eq(tag, XML_TAG_RULE)) { - return nested_rule; - - } else if(safe_str_neq(tag, "expression")) { - return not_expr; - - } else if(safe_str_eq(attr, "#uname") || safe_str_eq(attr, "#id")) { - return loc_expr; - - } else if(safe_str_eq(attr, "#role")) { - return role_expr; - } - - return attr_expr; -} - -gboolean -test_role_expression( - crm_data_t *expr, resource_t *rsc, pe_working_set_t *data_set) -{ - gboolean accept = FALSE; - const char *op = NULL; - const char *value = NULL; - - if(rsc == NULL) { - return accept; - } - - value = crm_element_value(expr, XML_EXPR_ATTR_VALUE); - op = crm_element_value(expr, XML_EXPR_ATTR_OPERATION); - - if(safe_str_eq(op, "defined")) { - if(rsc->next_role > RSC_ROLE_STARTED) { - accept = TRUE; - } - - } else if(safe_str_eq(op, "not_defined")) { - if(rsc->next_role < RSC_ROLE_SLAVE - && rsc->next_role > RSC_ROLE_UNKNOWN) { - accept = TRUE; - } - - } else if(safe_str_eq(op, "eq")) { - if(text2role(value) == rsc->next_role) { - accept = TRUE; - } - - } else if(safe_str_eq(op, "ne")) { - /* we will only test "ne" wtih master/slave roles style */ - if(rsc->next_role < RSC_ROLE_SLAVE - && rsc->next_role > RSC_ROLE_UNKNOWN) { - accept = FALSE; - - } else if(text2role(value) != rsc->next_role) { - accept = TRUE; - } - } - return accept; -} - -gboolean -test_attr_expression(crm_data_t *expr, GHashTable *hash, pe_working_set_t *data_set) -{ - gboolean accept = FALSE; - int cmp = 0; - const char *h_val = NULL; - - const char *op = NULL; - const char *type = NULL; - const char *attr = NULL; - const char *value = NULL; - - attr = crm_element_value(expr, XML_EXPR_ATTR_ATTRIBUTE); - op = crm_element_value(expr, XML_EXPR_ATTR_OPERATION); - value = crm_element_value(expr, XML_EXPR_ATTR_VALUE); - type = crm_element_value(expr, XML_EXPR_ATTR_TYPE); - - if(attr == NULL || op == NULL) { - pe_err("Invlaid attribute or operation in expression" - " (\'%s\' \'%s\' \'%s\')", - crm_str(attr), crm_str(op), crm_str(value)); - return FALSE; - } - - if(hash != NULL) { - h_val = (const char*)g_hash_table_lookup(hash, attr); - } - - if(value != NULL && h_val != NULL) { - if(type == NULL || (safe_str_eq(type, "string"))) { - cmp = strcmp(h_val, value); - - } else if(safe_str_eq(type, "number")) { - int h_val_f = crm_parse_int(h_val, NULL); - int value_f = crm_parse_int(value, NULL); - - if(h_val_f < value_f) { - cmp = -1; - } else if(h_val_f > value_f) { - cmp = 1; - } else { - cmp = 0; - } - - } else if(safe_str_eq(type, "version")) { - cmp = compare_version(h_val, value); - - } - - } else if(value == NULL && h_val == NULL) { - cmp = 0; - } else if(value == NULL) { - cmp = 1; - } else { - cmp = -1; - } - - if(safe_str_eq(op, "defined")) { - if(h_val != NULL) { accept = TRUE; } - - } else if(safe_str_eq(op, "not_defined")) { - if(h_val == NULL) { accept = TRUE; } - - } else if(safe_str_eq(op, "eq")) { - if((h_val == value) || cmp == 0) { - accept = TRUE; - } - - } else if(safe_str_eq(op, "ne")) { - if((h_val == NULL && value != NULL) - || (h_val != NULL && value == NULL) - || cmp != 0) { - accept = TRUE; - } - - } else if(value == NULL || h_val == NULL) { - /* the comparision is meaningless from this point on */ - accept = FALSE; - - } else if(safe_str_eq(op, "lt")) { - if(cmp < 0) { accept = TRUE; } - - } else if(safe_str_eq(op, "lte")) { - if(cmp <= 0) { accept = TRUE; } - - } else if(safe_str_eq(op, "gt")) { - if(cmp > 0) { accept = TRUE; } - - } else if(safe_str_eq(op, "gte")) { - if(cmp >= 0) { accept = TRUE; } - } - - return accept; -} - -/* As per the nethack rules: - * - * moon period = 29.53058 days ~= 30, year = 365.2422 days - * days moon phase advances on first day of year compared to preceding year - * = 365.2422 - 12*29.53058 ~= 11 - * years in Metonic cycle (time until same phases fall on the same days of - * the month) = 18.6 ~= 19 - * moon phase on first day of year (epact) ~= (11*(year%19) + 29) % 30 - * (29 as initial condition) - * current phase in days = first day phase + days elapsed in year - * 6 moons ~= 177 days - * 177 ~= 8 reported phases * 22 - * + 11/22 for rounding - * - * 0-7, with 0: new, 4: full - */ - -static int -phase_of_the_moon(ha_time_t *now) -{ - int epact, diy, goldn; - - diy = now->yeardays; - goldn = (now->years % 19) + 1; - epact = (11 * goldn + 18) % 30; - if ((epact == 25 && goldn > 11) || epact == 24) - epact++; - - return( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 ); -} - -#define cron_check(xml_field, time_field) \ - value = crm_element_value(cron_spec, xml_field); \ - if(value != NULL) { \ - gboolean pass = TRUE; \ - decodeNVpair(value, '-', &value_low, &value_high); \ - if(value_low == NULL) { \ - value_low = crm_strdup(value); \ - } \ - value_low_i = crm_parse_int(value_low, "0"); \ - value_high_i = crm_parse_int(value_high, "-1"); \ - if(value_low_i > time_field) { \ - pass = FALSE; \ - } else if(value_high_i < 0) { \ - } else if(value_high_i < time_field) { \ - pass = FALSE; \ - } \ - crm_free(value_low); \ - crm_free(value_high); \ - if(pass == FALSE) { \ - crm_debug("Condition '%s' in %s: failed", value, xml_field); \ - return pass; \ - } \ - crm_debug("Condition '%s' in %s: passed", value, xml_field); \ - } - -gboolean -cron_range_satisfied(ha_time_t *now, crm_data_t *cron_spec) -{ - const char *value = NULL; - char *value_low = NULL; - char *value_high = NULL; - - int value_low_i = 0; - int value_high_i = 0; - - cron_check("seconds", now->seconds); - cron_check("minutes", now->minutes); - cron_check("hours", now->hours); - cron_check("monthdays", now->days); - cron_check("weekdays", now->weekdays); - cron_check("yeardays", now->yeardays); - cron_check("weeks", now->weeks); - cron_check("months", now->months); - cron_check("years", now->years); - cron_check("weekyears", now->weekyears); - cron_check("moon", phase_of_the_moon(now)); - - return TRUE; -} - -#define update_field(xml_field, time_fn) \ - value = crm_element_value(duration_spec, xml_field); \ - if(value != NULL) { \ - int value_i = crm_parse_int(value, "0"); \ - time_fn(end, value_i); \ - } - -ha_time_t * -parse_xml_duration(ha_time_t *start, crm_data_t *duration_spec) -{ - ha_time_t *end = NULL; - const char *value = NULL; - - end = new_ha_date(FALSE); - ha_set_time(end, start, TRUE); - - update_field("years", add_years); - update_field("months", add_months); - update_field("weeks", add_weeks); - update_field("days", add_days); - update_field("hours", add_hours); - update_field("minutes", add_minutes); - update_field("seconds", add_seconds); - - return end; -} - - -gboolean -test_date_expression(crm_data_t *time_expr, pe_working_set_t *data_set) -{ - ha_time_t *start = NULL; - ha_time_t *end = NULL; - const char *value = NULL; - char *value_copy = NULL; - char *value_copy_start = NULL; - const char *op = crm_element_value(time_expr, "operation"); - - crm_data_t *duration_spec = NULL; - crm_data_t *date_spec = NULL; - - gboolean passed = FALSE; - - crm_debug_2("Testing expression: %s", ID(time_expr)); - - duration_spec = cl_get_struct(time_expr, "duration"); - date_spec = cl_get_struct(time_expr, "date_spec"); - - value = crm_element_value(time_expr, "start"); - if(value != NULL) { - value_copy = crm_strdup(value); - value_copy_start = value_copy; - start = parse_date(&value_copy); - crm_free(value_copy_start); - } - value = crm_element_value(time_expr, "end"); - if(value != NULL) { - value_copy = crm_strdup(value); - value_copy_start = value_copy; - end = parse_date(&value_copy); - crm_free(value_copy_start); - } - - if(start != NULL && end == NULL) { - end = parse_xml_duration(start, duration_spec); - } - if(op == NULL) { - op = "in_range"; - } - - if(safe_str_eq(op, "date_spec") || safe_str_eq(op, "in_range")) { - if(start != NULL && compare_date(start, data_set->now) > 0) { - passed = FALSE; - } else if(end != NULL && compare_date(end, data_set->now) < 0) { - passed = FALSE; - } else if(safe_str_eq(op, "in_range")) { - passed = TRUE; - } else { - passed = cron_range_satisfied(data_set->now, date_spec); - } - - } else if(safe_str_eq(op, "gt") && compare_date(start, data_set->now) < 0) { - passed = TRUE; - - - } else if(safe_str_eq(op, "lt") && compare_date(end, data_set->now) > 0) { - passed = TRUE; - - } else if(safe_str_eq(op, "eq") && compare_date(start, data_set->now) == 0) { - passed = TRUE; - - } else if(safe_str_eq(op, "neq") && compare_date(start, data_set->now) != 0) { - passed = TRUE; - } - - free_ha_date(start); - free_ha_date(end); - return passed; -} diff --git a/crm/pengine/unpack.c b/crm/pengine/unpack.c deleted file mode 100644 index ba45beaa86..0000000000 --- a/crm/pengine/unpack.c +++ /dev/null @@ -1,2081 +0,0 @@ -/* $Id: unpack.c,v 1.201 2006/06/02 09:58:12 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 /* for ONLINESTATUS */ - -#include -#include -#include - -gint sort_op_by_callid(gconstpointer a, gconstpointer b); - -gboolean unpack_rsc_to_attr(crm_data_t *xml_obj, pe_working_set_t *data_set); - -gboolean unpack_rsc_to_node(crm_data_t *xml_obj, pe_working_set_t *data_set); - -gboolean unpack_rsc_order(crm_data_t *xml_obj, pe_working_set_t *data_set); - -gboolean unpack_rsc_colocation(crm_data_t *xml_obj, pe_working_set_t *data_set); - -gboolean unpack_rsc_location(crm_data_t *xml_obj, pe_working_set_t *data_set); - -gboolean unpack_lrm_resources( - node_t *node, crm_data_t * lrm_state, pe_working_set_t *data_set); - -gboolean add_node_attrs( - crm_data_t * attrs, node_t *node, pe_working_set_t *data_set); - -gboolean unpack_rsc_op( - resource_t *rsc, node_t *node, crm_data_t *xml_op, - int *max_call_id, enum action_fail_response *failed, pe_working_set_t *data_set); - -gboolean determine_online_status( - crm_data_t * node_state, node_t *this_node, pe_working_set_t *data_set); - -gboolean rsc_colocation_new( - const char *id, enum con_strength strength, - resource_t *rsc_lh, resource_t *rsc_rh, - const char *state_lh, const char *state_rh); - -gboolean create_ordering( - const char *id, enum con_strength strength, - resource_t *rsc_lh, resource_t *rsc_rh, pe_working_set_t *data_set); - -const char *param_value( - GHashTable *hash, crm_data_t * parent, const char *name); - -rsc_to_node_t *generate_location_rule( - resource_t *rsc, crm_data_t *location_rule, pe_working_set_t *data_set); - -#define get_cluster_pref(pref) value = g_hash_table_lookup(config_hash, pref); \ - if(value == NULL) { \ - pe_config_warn("No value specified for cluster preference: %s", pref); \ - } - -gboolean -unpack_config(crm_data_t * config, pe_working_set_t *data_set) -{ - const char *name = NULL; - const char *value = NULL; - GHashTable *config_hash = g_hash_table_new_full( - g_str_hash,g_str_equal, g_hash_destroy_str,g_hash_destroy_str); - - data_set->config_hash = config_hash; - - unpack_instance_attributes( - config, XML_CIB_TAG_PROPSET, NULL, config_hash, - NULL, 0, data_set); - -#if CRM_DEPRECATED_SINCE_2_0_1 - xml_child_iter_filter( - config, a_child, XML_CIB_TAG_NVPAIR, - - name = crm_element_value(a_child, XML_NVPAIR_ATTR_NAME); - - value = crm_element_value(a_child, XML_NVPAIR_ATTR_VALUE); - if(g_hash_table_lookup(config_hash, name) == NULL) { - g_hash_table_insert( - config_hash,crm_strdup(name),crm_strdup(value)); - } - pe_config_err("Creating directly" - "beneath has been depreciated since" - " 2.0.1", ID(a_child), name); - ); -#else - xml_child_iter_filter( - config, a_child, XML_CIB_TAG_NVPAIR, - - name = crm_element_value(a_child, XML_NVPAIR_ATTR_NAME); - pe_config_err("Creating directly" - "beneath has been depreciated since" - " 2.0.1 and is now disabled", ID(a_child), name); - ); -#endif - - get_cluster_pref("default_action_timeout"); - if(value == NULL) { - get_cluster_pref("transition_idle_timeout"); - } - if(value != NULL) { - long tmp = crm_get_msec(value); - if(tmp > 0) { - crm_free(data_set->transition_idle_timeout); - data_set->transition_idle_timeout = crm_strdup(value); - } else { - crm_err("Invalid value for default_action_timeout: %s", - value); - } - } - - crm_debug("default_action_timeout set to: %s", data_set->transition_idle_timeout); - - get_cluster_pref("default_"XML_RSC_ATTR_STICKINESS); - data_set->default_resource_stickiness = char2score(value); - crm_info("Default stickiness: %d", - data_set->default_resource_stickiness); - - get_cluster_pref("default_"XML_RSC_ATTR_FAIL_STICKINESS); - data_set->default_resource_fail_stickiness = char2score(value); - crm_info("Default failure stickiness: %d", - data_set->default_resource_fail_stickiness); - - get_cluster_pref("stonith_enabled"); - if(value != NULL) { - cl_str_to_boolean(value, &data_set->stonith_enabled); - } - crm_info("STONITH of failed nodes is %s", - data_set->stonith_enabled?"enabled":"disabled"); - - get_cluster_pref("stonith_action"); - if(value == NULL || safe_str_neq(value, "poweroff")) { - value = "reboot"; - } - data_set->stonith_action = value; - crm_info("STONITH will %s nodes", data_set->stonith_action); - - get_cluster_pref("symmetric_cluster"); - if(value != NULL) { - cl_str_to_boolean(value, &data_set->symmetric_cluster); - } - if(data_set->symmetric_cluster) { - crm_info("Cluster is symmetric" - " - resources can run anywhere by default"); - } - - get_cluster_pref("no_quorum_policy"); - if(safe_str_eq(value, "ignore")) { - data_set->no_quorum_policy = no_quorum_ignore; - - } else if(safe_str_eq(value, "freeze")) { - data_set->no_quorum_policy = no_quorum_freeze; - - } else { - data_set->no_quorum_policy = no_quorum_stop; - } - - switch (data_set->no_quorum_policy) { - case no_quorum_freeze: - crm_info("On loss of CCM Quorum: Freeze resources"); - break; - case no_quorum_stop: - crm_info("On loss of CCM Quorum: Stop ALL resources"); - break; - case no_quorum_ignore: - crm_notice("On loss of CCM Quorum: Ignore"); - break; - } - - get_cluster_pref("stop_orphan_resources"); - if(value != NULL) { - cl_str_to_boolean(value, &data_set->stop_rsc_orphans); - } - crm_info("Orphan resources are %s", - data_set->stop_rsc_orphans?"stopped":"ignored"); - - get_cluster_pref("stop_orphan_actions"); - if(value != NULL) { - cl_str_to_boolean(value, &data_set->stop_action_orphans); - } - crm_info("Orphan resource actions are %s", - data_set->stop_action_orphans?"stopped":"ignored"); - - get_cluster_pref("remove_after_stop"); - if(value != NULL) { - cl_str_to_boolean(value, &data_set->remove_after_stop); - } - crm_info("Stopped resources are removed from the status section: %s", - data_set->remove_after_stop?"true":"false"); - - get_cluster_pref("is_managed_default"); - if(value != NULL) { - cl_str_to_boolean(value, &data_set->is_managed_default); - } - crm_info("By default resources are %smanaged", - data_set->is_managed_default?"":"not "); - - return TRUE; -} - -gboolean -unpack_nodes(crm_data_t * xml_nodes, pe_working_set_t *data_set) -{ - node_t *new_node = NULL; - const char *id = NULL; - const char *uname = NULL; - const char *type = NULL; - - crm_debug_2("Begining unpack... %s", - xml_nodes?crm_element_name(xml_nodes):""); - xml_child_iter_filter( - xml_nodes, xml_obj, XML_CIB_TAG_NODE, - - new_node = NULL; - - id = crm_element_value(xml_obj, XML_ATTR_ID); - uname = crm_element_value(xml_obj, XML_ATTR_UNAME); - type = crm_element_value(xml_obj, XML_ATTR_TYPE); - crm_debug_3("Processing node %s/%s", uname, id); - - if(id == NULL) { - pe_config_err("Must specify id tag in "); - continue; - } - if(type == NULL) { - pe_config_err("Must specify type tag in "); - continue; - } - crm_malloc0(new_node, sizeof(node_t)); - if(new_node == NULL) { - return FALSE; - } - - new_node->weight = 0; - new_node->fixed = FALSE; - crm_malloc0(new_node->details, - sizeof(struct node_shared_s)); - - if(new_node->details == NULL) { - crm_free(new_node); - return FALSE; - } - - crm_debug_3("Creaing node for entry %s/%s", uname, id); - new_node->details->id = id; - new_node->details->uname = uname; - new_node->details->type = node_ping; - new_node->details->online = FALSE; - new_node->details->shutdown = FALSE; - new_node->details->running_rsc = NULL; - new_node->details->attrs = g_hash_table_new_full( - g_str_hash, g_str_equal, - g_hash_destroy_str, g_hash_destroy_str); - -/* if(data_set->have_quorum == FALSE */ -/* && data_set->no_quorum_policy == no_quorum_stop) { */ -/* /\* start shutting resources down *\/ */ -/* new_node->weight = -INFINITY; */ -/* } */ - - if(data_set->stonith_enabled) { - /* all nodes are unclean until we've seen their - * status entry - */ - new_node->details->unclean = TRUE; - } else { - /* blind faith... */ - new_node->details->unclean = FALSE; - } - - - if(type == NULL - || safe_str_eq(type, "member") - || safe_str_eq(type, NORMALNODE)) { - new_node->details->type = node_member; - } - - add_node_attrs(xml_obj, new_node, data_set); - - if(crm_is_true(g_hash_table_lookup( - new_node->details->attrs, "standby"))) { - crm_info("Node %s is in standby-mode", - new_node->details->uname); - new_node->weight = -INFINITY; - new_node->details->standby = TRUE; - } - - data_set->nodes = g_list_append(data_set->nodes, new_node); - crm_debug_3("Done with node %s", - crm_element_value(xml_obj, XML_ATTR_UNAME)); - - crm_action_debug_3(print_node("Added", new_node, FALSE)); - ); - -/* data_set->nodes = g_list_sort(data_set->nodes, sort_node_weight); */ - - return TRUE; -} - -gboolean -unpack_resources(crm_data_t * xml_resources, pe_working_set_t *data_set) -{ - crm_debug_2("Begining unpack... %s", - xml_resources?crm_element_name(xml_resources):""); - xml_child_iter( - xml_resources, xml_obj, - - resource_t *new_rsc = NULL; - crm_debug_2("Begining unpack... %s", - xml_obj?crm_element_name(xml_obj):""); - if(common_unpack(xml_obj, &new_rsc, NULL, data_set)) { - data_set->resources = g_list_append( - data_set->resources, new_rsc); - - print_resource(LOG_DEBUG_3, "Added", new_rsc, FALSE); - - } else { - pe_config_err("Failed unpacking %s %s", - crm_element_name(xml_obj), - crm_element_value(xml_obj, XML_ATTR_ID)); - if(new_rsc != NULL && new_rsc->fns != NULL) { - new_rsc->fns->free(new_rsc); - } - } - ); - - data_set->resources = g_list_sort( - data_set->resources, sort_rsc_priority); - - return TRUE; -} - -gboolean -unpack_constraints(crm_data_t * xml_constraints, pe_working_set_t *data_set) -{ - crm_data_t *lifetime = NULL; - crm_debug_2("Begining unpack... %s", - xml_constraints?crm_element_name(xml_constraints):""); - xml_child_iter( - xml_constraints, xml_obj, - - const char *id = crm_element_value(xml_obj, XML_ATTR_ID); - if(id == NULL) { - pe_config_err("Constraint <%s...> must have an id", - crm_element_name(xml_obj)); - continue; - } - - crm_debug_3("Processing constraint %s %s", - crm_element_name(xml_obj),id); - - lifetime = cl_get_struct(xml_obj, "lifetime"); - - if(test_ruleset(lifetime, NULL, data_set) == FALSE) { - crm_info("Constraint %s %s is not active", - crm_element_name(xml_obj), id); - - } else if(safe_str_eq(XML_CONS_TAG_RSC_ORDER, - crm_element_name(xml_obj))) { - unpack_rsc_order(xml_obj, data_set); - - } else if(safe_str_eq(XML_CONS_TAG_RSC_DEPEND, - crm_element_name(xml_obj))) { - unpack_rsc_colocation(xml_obj, data_set); - - } else if(safe_str_eq(XML_CONS_TAG_RSC_LOCATION, - crm_element_name(xml_obj))) { - unpack_rsc_location(xml_obj, data_set); - - } else { - pe_err("Unsupported constraint type: %s", - crm_element_name(xml_obj)); - } - ); - - return TRUE; -} - -/* remove nodes that are down, stopping */ -/* create +ve rsc_to_node constraints between resources and the nodes they are running on */ -/* anything else? */ -gboolean -unpack_status(crm_data_t * status, pe_working_set_t *data_set) -{ - const char *id = NULL; - const char *uname = NULL; - - crm_data_t * lrm_rsc = NULL; - crm_data_t * attrs = NULL; - node_t *this_node = NULL; - - crm_debug_3("Begining unpack"); - xml_child_iter_filter( - status, node_state, XML_CIB_TAG_STATE, - - id = crm_element_value(node_state, XML_ATTR_ID); - uname = crm_element_value(node_state, XML_ATTR_UNAME); - attrs = find_xml_node( - node_state, XML_TAG_TRANSIENT_NODEATTRS, FALSE); - - lrm_rsc = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE); - lrm_rsc = find_xml_node(lrm_rsc, XML_LRM_TAG_RESOURCES, FALSE); - - crm_debug_3("Processing node %s", uname); - this_node = pe_find_node_id(data_set->nodes, id); - - if(uname == NULL) { - /* error */ - continue; - - } else if(this_node == NULL) { - pe_config_warn("Node %s in status section no longer exists", - uname); - continue; - } - - /* Mark the node as provisionally clean - * - at least we have seen it in the current cluster's lifetime - */ - this_node->details->unclean = FALSE; - - crm_debug_3("Adding runtime node attrs"); - add_node_attrs(attrs, this_node, data_set); - - crm_debug_3("determining node state"); - determine_online_status(node_state, this_node, data_set); - - if(this_node->details->online || data_set->stonith_enabled) { - /* offline nodes run no resources... - * unless stonith is enabled in which case we need to - * make sure rsc start events happen after the stonith - */ - crm_debug_3("Processing lrm resource entries"); - unpack_lrm_resources(this_node, lrm_rsc, data_set); - } - ); - - return TRUE; - -} - -static gboolean -determine_online_status_no_fencing(crm_data_t * node_state, node_t *this_node) -{ - gboolean online = FALSE; - const char *join_state = crm_element_value(node_state, - XML_CIB_ATTR_JOINSTATE); - const char *crm_state = crm_element_value(node_state, - XML_CIB_ATTR_CRMDSTATE); - const char *ccm_state = crm_element_value(node_state, - XML_CIB_ATTR_INCCM); - const char *ha_state = crm_element_value(node_state, - XML_CIB_ATTR_HASTATE); - const char *exp_state = crm_element_value(node_state, - XML_CIB_ATTR_EXPSTATE); - - if(!crm_is_true(ccm_state) || safe_str_eq(ha_state,DEADSTATUS)){ - crm_debug_2("Node is down: ha_state=%s, ccm_state=%s", - crm_str(ha_state), crm_str(ccm_state)); - - } else if(!crm_is_true(ccm_state) - || safe_str_eq(ha_state, DEADSTATUS)) { - - } else if(safe_str_neq(join_state, CRMD_JOINSTATE_DOWN) - && safe_str_eq(crm_state, ONLINESTATUS)) { - online = TRUE; - - } else if(this_node->details->expected_up == FALSE) { - crm_debug_2("CRMd is down: ha_state=%s, ccm_state=%s", - crm_str(ha_state), crm_str(ccm_state)); - crm_debug_2("\tcrm_state=%s, join_state=%s, expected=%s", - crm_str(crm_state), crm_str(join_state), - crm_str(exp_state)); - - } else { - /* mark it unclean */ - this_node->details->unclean = TRUE; - - crm_warn("Node %s is partially & un-expectedly down", - this_node->details->uname); - crm_info("\tha_state=%s, ccm_state=%s," - " crm_state=%s, join_state=%s, expected=%s", - crm_str(ha_state), crm_str(ccm_state), - crm_str(crm_state), crm_str(join_state), - crm_str(exp_state)); - } - return online; -} - -static gboolean -determine_online_status_fencing(crm_data_t * node_state, node_t *this_node) -{ - gboolean online = FALSE; - const char *join_state = crm_element_value(node_state, - XML_CIB_ATTR_JOINSTATE); - const char *crm_state = crm_element_value(node_state, - XML_CIB_ATTR_CRMDSTATE); - const char *ccm_state = crm_element_value(node_state, - XML_CIB_ATTR_INCCM); - const char *ha_state = crm_element_value(node_state, - XML_CIB_ATTR_HASTATE); - const char *exp_state = crm_element_value(node_state, - XML_CIB_ATTR_EXPSTATE); - - if(crm_is_true(ccm_state) - && (ha_state == NULL || safe_str_eq(ha_state, ACTIVESTATUS)) - && safe_str_eq(crm_state, ONLINESTATUS) - && safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER)) { - online = TRUE; - - } else if(crm_is_true(ccm_state) == FALSE -/* && safe_str_eq(ha_state, DEADSTATUS) */ - && safe_str_eq(crm_state, OFFLINESTATUS) - && this_node->details->expected_up == FALSE) { - crm_debug("Node %s is down: join_state=%s, expected=%s", - this_node->details->uname, - crm_str(join_state), crm_str(exp_state)); - - } else if(this_node->details->expected_up == FALSE) { - crm_info("Node %s is comming up", this_node->details->uname); - crm_debug("\tha_state=%s, ccm_state=%s," - " crm_state=%s, join_state=%s, expected=%s", - crm_str(ha_state), crm_str(ccm_state), - crm_str(crm_state), crm_str(join_state), - crm_str(exp_state)); - - } else { - /* mark it unclean */ - this_node->details->unclean = TRUE; - - crm_warn("Node %s (%s) is un-expectedly down", - this_node->details->uname, this_node->details->id); - crm_info("\tha_state=%s, ccm_state=%s," - " crm_state=%s, join_state=%s, expected=%s", - crm_str(ha_state), crm_str(ccm_state), - crm_str(crm_state), crm_str(join_state), - crm_str(exp_state)); - } - return online; -} - -gboolean -determine_online_status( - crm_data_t * node_state, node_t *this_node, pe_working_set_t *data_set) -{ - int shutdown = 0; - gboolean online = FALSE; - const char *exp_state = - crm_element_value(node_state, XML_CIB_ATTR_EXPSTATE); - - if(this_node == NULL) { - pe_config_err("No node to check"); - return online; - } - - ha_msg_value_int(node_state, XML_CIB_ATTR_SHUTDOWN, &shutdown); - - this_node->details->expected_up = FALSE; - if(safe_str_eq(exp_state, CRMD_JOINSTATE_MEMBER)) { - this_node->details->expected_up = TRUE; - } - - this_node->details->shutdown = FALSE; - if(shutdown != 0) { - this_node->details->shutdown = TRUE; - this_node->details->expected_up = FALSE; - } - - if(data_set->stonith_enabled == FALSE) { - online = determine_online_status_no_fencing( - node_state, this_node); - - } else { - online = determine_online_status_fencing( - node_state, this_node); - } - - if(online) { - this_node->details->online = TRUE; - - } else { - /* remove node from contention */ - this_node->fixed = TRUE; - this_node->weight = -INFINITY; - } - - if(online && this_node->details->shutdown) { - /* dont run resources here */ - this_node->fixed = TRUE; - this_node->weight = -INFINITY; - } - - if(this_node->details->unclean) { - pe_proc_warn("Node %s is unclean", this_node->details->uname); - - } else if(this_node->details->online) { - crm_info("Node %s is %s", this_node->details->uname, - this_node->details->shutdown?"shutting down":"online"); - - } else { - crm_debug_2("Node %s is offline", this_node->details->uname); - } - - - - return online; -} - -#define set_char(x) last_rsc_id[len] = x; complete = TRUE; - -static void -increment_clone(char *last_rsc_id) -{ - gboolean complete = FALSE; - int len = 0; - - CRM_CHECK(last_rsc_id != NULL, return); - if(last_rsc_id != NULL) { - len = strlen(last_rsc_id); - } - len--; - while(complete == FALSE && len > 0) { - switch (last_rsc_id[len]) { - case 0: - len--; - break; - case '0': - set_char('1'); - break; - case '1': - set_char('2'); - break; - case '2': - set_char('3'); - break; - case '3': - set_char('4'); - break; - case '4': - set_char('5'); - break; - case '5': - set_char('6'); - break; - case '6': - set_char('7'); - break; - case '7': - set_char('8'); - break; - case '8': - set_char('9'); - break; - case '9': - last_rsc_id[len] = '0'; - len--; - break; - default: - crm_err("Unexpected char: %c (%d)", - last_rsc_id[len], len); - break; - } - } -} - -extern gboolean DeleteRsc(resource_t *rsc, node_t *node, pe_working_set_t *data_set); - -static resource_t * -unpack_find_resource( - pe_working_set_t *data_set, node_t *node, const char *rsc_id) -{ - resource_t *rsc = NULL; - gboolean is_duped_clone = FALSE; - char *alt_rsc_id = crm_strdup(rsc_id); - - while(rsc == NULL) { - crm_debug_3("looking for: %s", alt_rsc_id); - rsc = pe_find_resource(data_set->resources, alt_rsc_id); - /* no match */ - if(rsc == NULL) { - crm_debug_3("not found"); - break; - - /* not running anywhere else */ - } else if(rsc->running_on == NULL) { - crm_debug_3("not active yet"); - break; - - /* always unique */ - } else if(rsc->globally_unique) { - crm_debug_3("unique"); - break; - - /* running somewhere already but we dont care - * find another clone instead - */ - } else { - crm_debug_2("find another one"); - rsc = NULL; - is_duped_clone = TRUE; - increment_clone(alt_rsc_id); - } - } - crm_free(alt_rsc_id); - if(is_duped_clone && rsc != NULL) { - crm_info("Internally renamed %s on %s to %s", - rsc_id, node->details->uname, rsc->id); -/* rsc->name = rsc_id; */ - } - return rsc; -} - -static resource_t * -process_orphan_resource(crm_data_t *rsc_entry, node_t *node, pe_working_set_t *data_set) -{ - resource_t *rsc = NULL; - gboolean is_duped_clone = FALSE; - const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID); - crm_data_t *xml_rsc = create_xml_node(NULL, XML_CIB_TAG_RESOURCE); - - crm_log_xml_info(rsc_entry, "Orphan resource"); - - pe_config_warn("Nothing known about resource %s running on %s", - rsc_id, node->details->uname); - - if(pe_find_resource(data_set->resources, rsc_id) != NULL) { - is_duped_clone = TRUE; - } - - copy_in_properties(xml_rsc, rsc_entry); - - common_unpack(xml_rsc, &rsc, NULL, data_set); - rsc->orphan = TRUE; - - data_set->resources = g_list_append(data_set->resources, rsc); - - if(data_set->stop_rsc_orphans == FALSE && is_duped_clone == FALSE) { - rsc->is_managed = FALSE; - - } else { - crm_info("Making sure orphan %s is stopped", rsc_id); - - print_resource(LOG_DEBUG_3, "Added orphan", rsc, FALSE); - - CRM_CHECK(rsc != NULL, return NULL); - slist_iter( - any_node, node_t, data_set->nodes, lpc, - rsc2node_new( - "__orphan_dont_run__", rsc, - -INFINITY, any_node, data_set); - ); - } - return rsc; -} - -static gboolean -check_rsc_parameters(resource_t *rsc, node_t *node, crm_data_t *rsc_entry, - pe_working_set_t *data_set) -{ - int attr_lpc = 0; - gboolean force_restart = FALSE; - gboolean delete_resource = FALSE; - - const char *value = NULL; - const char *old_value = NULL; - const char *attr_list[] = { - XML_ATTR_TYPE, - XML_AGENT_ATTR_CLASS, - XML_AGENT_ATTR_PROVIDER - }; - - for(; attr_lpc < DIMOF(attr_list); attr_lpc++) { - value = crm_element_value(rsc->xml, attr_list[attr_lpc]); - old_value = crm_element_value(rsc_entry, attr_list[attr_lpc]); - if(safe_str_eq(value, old_value)) { - continue; - } - - force_restart = TRUE; - crm_notice("Forcing restart of %s on %s, %s changed: %s -> %s", - rsc->id, node->details->uname, attr_list[attr_lpc], - crm_str(old_value), crm_str(value)); - } - if(force_restart) { - /* make sure the restart happens */ - stop_action(rsc, node, FALSE); - rsc->start_pending = TRUE; - delete_resource = TRUE; - } - return delete_resource; -} - -static void -process_rsc_state(resource_t *rsc, node_t *node, - enum action_fail_response on_fail, - pe_working_set_t *data_set) -{ - crm_debug_2("Resource %s is %s on %s", - rsc->id, role2text(rsc->role), - node->details->uname); - - rsc->known_on = g_list_append(rsc->known_on, node); - - if(rsc->role != RSC_ROLE_STOPPED) { - if(on_fail != action_fail_ignore) { - rsc->failed = TRUE; - crm_debug_2("Force stop"); - } - - crm_debug_2("Adding %s to %s", - rsc->id, node->details->uname); - native_add_running(rsc, node, data_set); - - if(on_fail == action_fail_ignore) { - /* nothing to do */ - } else if(node->details->unclean) { - stop_action(rsc, node, FALSE); - - } else if(on_fail == action_fail_fence) { - /* treat it as if it is still running - * but also mark the node as unclean - */ - node->details->unclean = TRUE; - stop_action(rsc, node, FALSE); - - } else if(on_fail == action_fail_block) { - /* is_managed == FALSE will prevent any - * actions being sent for the resource - */ - rsc->is_managed = FALSE; - - } else if(on_fail == action_fail_migrate) { - stop_action(rsc, node, FALSE); - - /* make sure it comes up somewhere else - * or not at all - */ - rsc2node_new("__action_migration_auto__", - rsc, -INFINITY, node, data_set); - - } else { - stop_action(rsc, node, FALSE); - } - - } else { - char *key = stop_key(rsc); - GListPtr possible_matches = find_actions(rsc->actions, key, node); - slist_iter(stop, action_t, possible_matches, lpc, - stop->optional = TRUE; - ); - crm_free(key); - -/* if(rsc->failed == FALSE && node->details->online) { */ -/* delete_resource = TRUE; */ -/* } */ - } -} - -static const char * -get_interval(crm_data_t *xml_op) -{ - const char *interval_s = NULL; - interval_s = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL); -#if CRM_DEPRECATED_SINCE_2_0_4 - if(interval_s == NULL) { - crm_data_t *params = NULL; - params = find_xml_node(xml_op, XML_TAG_PARAMS, FALSE); - if(params != NULL) { - interval_s = crm_element_value( - params, XML_LRM_ATTR_INTERVAL); - } - } -#endif - - CRM_CHECK(interval_s != NULL, - crm_err("Invalid rsc op: %s", ID(xml_op)); return "0"); - - return interval_s; -} - -static void -unpack_lrm_rsc_state( - node_t *node, crm_data_t * rsc_entry, pe_working_set_t *data_set) -{ - int fail_count = 0; - char *fail_attr = NULL; - const char *value = NULL; - const char *fail_val = NULL; - gboolean delete_resource = FALSE; - - const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID); - - int max_call_id = -1; - GListPtr op_list = NULL; - GListPtr sorted_op_list = NULL; - - enum action_fail_response on_fail = FALSE; - enum rsc_role_e saved_role = RSC_ROLE_UNKNOWN; - - resource_t *rsc = unpack_find_resource(data_set, node, rsc_id); - - crm_debug_3("[%s] Processing %s on %s", - crm_element_name(rsc_entry), rsc_id, node->details->uname); - - if(rsc == NULL) { - rsc = process_orphan_resource(rsc_entry, node, data_set); - } - CRM_ASSERT(rsc != NULL); - - delete_resource = check_rsc_parameters(rsc, node, rsc_entry, data_set); - - /* process failure stickiness */ - fail_count = 0; - fail_attr = crm_concat("fail-count", rsc->id, '-'); - fail_val = g_hash_table_lookup(node->details->attrs, fail_attr); - if(fail_val != NULL) { - crm_debug("%s: %s", fail_attr, fail_val); - fail_count = crm_parse_int(fail_val, "0"); - } - crm_free(fail_attr); - if(fail_count > 0 && rsc->fail_stickiness != 0) { - rsc2node_new("fail_stickiness", rsc, - fail_count * rsc->fail_stickiness, - node, data_set); - crm_debug("Setting failure stickiness for %s on %s: %d", - rsc->id, node->details->uname, - fail_count * rsc->fail_stickiness); - } - - /* process operations */ - max_call_id = -1; - - op_list = NULL; - sorted_op_list = NULL; - - xml_child_iter_filter( - rsc_entry, rsc_op, XML_LRM_TAG_RSC_OP, - op_list = g_list_append(op_list, rsc_op); - ); - - if(op_list != NULL) { - int stop_index = -1; - int start_index = -1; - const char *task = NULL; - const char *status = NULL; - saved_role = rsc->role; - on_fail = action_fail_ignore; - rsc->role = RSC_ROLE_STOPPED; - sorted_op_list = g_list_sort(op_list, sort_op_by_callid); - - slist_iter( - rsc_op, crm_data_t, sorted_op_list, lpc, - task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); - status = crm_element_value(rsc_op, XML_LRM_ATTR_OPSTATUS); - if(safe_str_eq(task, CRMD_ACTION_STOP) - && safe_str_eq(status, "0")) { - stop_index = lpc; - - } else if(safe_str_eq(task, CRMD_ACTION_START)) { - start_index = lpc; - - } else if(start_index <= stop_index - && safe_str_eq(task, CRMD_ACTION_STATUS)) { - const char *rc = crm_element_value(rsc_op, XML_LRM_ATTR_RC); - if(safe_str_eq(rc, "0") - || safe_str_eq(rc, "8")) { - start_index = lpc; - } - } - - unpack_rsc_op(rsc, node, rsc_op, - &max_call_id, &on_fail, data_set); - ); - - crm_debug_2("%s: Start index %d, stop index = %d", - rsc->id, start_index, stop_index); - slist_iter(rsc_op, crm_data_t, sorted_op_list, lpc, - int interval = 0; - char *key = NULL; - const char *id = ID(rsc_op); - const char *interval_s = NULL; - if(node->details->online == FALSE) { - crm_debug_4("Skipping %s/%s: node is offline", - rsc->id, node->details->uname); - break; - - } else if(start_index < stop_index) { - crm_debug_4("Skipping %s/%s: not active", - rsc->id, node->details->uname); - break; - - } else if(lpc <= start_index) { - crm_debug_4("Skipping %s/%s: old", - id, node->details->uname); - continue; - } - - interval_s = get_interval(rsc_op); - interval = crm_parse_int(interval_s, "0"); - if(interval == 0) { - crm_debug_4("Skipping %s/%s: non-recurring", - id, node->details->uname); - continue; - } - - status = crm_element_value(rsc_op, XML_LRM_ATTR_OPSTATUS); - if(safe_str_eq(status, "-1")) { - crm_debug_4("Skipping %s/%s: status", - id, node->details->uname); - continue; - } - task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); - /* create the action */ - key = generate_op_key(rsc->id, task, interval); - crm_debug_3("Creating %s/%s", key, node->details->uname); - custom_action(rsc, key, task, node, - TRUE, TRUE, data_set); - ); - - /* no need to free the contents */ - g_list_free(sorted_op_list); - - process_rsc_state(rsc, node, on_fail, data_set); - } - - value = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE); - if(value != NULL && safe_str_neq("default", value)) { - enum rsc_role_e req_role = text2role(value); - if(req_role != RSC_ROLE_UNKNOWN && req_role != rsc->next_role){ - if(rsc->next_role != RSC_ROLE_UNKNOWN) { - crm_debug("%s: Overwriting calculated next role %s" - " with requested next role %s", - rsc->id, role2text(rsc->next_role), - role2text(req_role)); - } - rsc->next_role = req_role; - } - } - - if(delete_resource) { - DeleteRsc(rsc, node, data_set); - } - - if(saved_role > rsc->role) { - rsc->role = saved_role; - } -} - -gboolean -unpack_lrm_resources(node_t *node, crm_data_t * lrm_rsc_list, pe_working_set_t *data_set) -{ - CRM_CHECK(node != NULL, return FALSE); - - crm_debug_3("Unpacking resources on %s", node->details->uname); - - xml_child_iter_filter( - lrm_rsc_list, rsc_entry, XML_LRM_TAG_RESOURCE, - unpack_lrm_rsc_state(node, rsc_entry, data_set); - ); - - return TRUE; -} - -#define sort_return(an_int) crm_free(a_uuid); crm_free(b_uuid); return an_int - -gint -sort_op_by_callid(gconstpointer a, gconstpointer b) -{ - char *a_uuid = NULL; - char *b_uuid = NULL; - const char *a_task_id = cl_get_string(a, XML_LRM_ATTR_CALLID); - const char *b_task_id = cl_get_string(b, XML_LRM_ATTR_CALLID); - - const char *a_key = cl_get_string(a, XML_ATTR_TRANSITION_MAGIC); - const char *b_key = cl_get_string(b, XML_ATTR_TRANSITION_MAGIC); - - const char *a_xml_id = ID(a); - const char *b_xml_id = ID(b); - - int a_id = -1; - int b_id = -1; - - int a_rc = -1; - int b_rc = -1; - - int a_status = -1; - int b_status = -1; - - int a_call_id = -1; - int b_call_id = -1; - - if(safe_str_eq(a_xml_id, b_xml_id)) { - /* We have duplicate lrm_rsc_op entries in the status - * section which is unliklely to be a good thing - * - we can handle it easily enough, but we need to get - * to the bottom of why its happening. - */ - pe_err("Duplicate lrm_rsc_op entries named %s", a_xml_id); - sort_return(0); - } - - CRM_CHECK(a_task_id != NULL && b_task_id != NULL, sort_return(0)); - a_call_id = crm_parse_int(a_task_id, NULL); - b_call_id = crm_parse_int(b_task_id, NULL); - - if(a_call_id == -1 && b_call_id == -1) { - /* both are pending ops so it doesnt matter since - * stops are never pending - */ - sort_return(0); - - } else if(a_call_id >= 0 && a_call_id < b_call_id) { - crm_debug_4("%s (%d) < %s (%d) : call id", - ID(a), a_call_id, ID(b), b_call_id); - sort_return(-1); - - } else if(b_call_id >= 0 && a_call_id > b_call_id) { - crm_debug_4("%s (%d) > %s (%d) : call id", - ID(a), a_call_id, ID(b), b_call_id); - sort_return(1); - } - - crm_debug_5("%s (%d) == %s (%d) : continuing", - ID(a), a_call_id, ID(b), b_call_id); - - /* now process pending ops */ - CRM_CHECK(a_key != NULL && b_key != NULL, sort_return(0)); - CRM_CHECK(decode_transition_magic( - a_key,&a_uuid,&a_id,&a_status, &a_rc), sort_return(0)); - CRM_CHECK(decode_transition_magic( - b_key,&b_uuid,&b_id,&b_status, &b_rc), sort_return(0)); - - /* try and determin the relative age of the operation... - * some pending operations (ie. a start) may have been supuerceeded - * by a subsequent stop - * - * [a|b]_id == -1 means its a shutdown operation and _always_ comes last - */ - if(safe_str_neq(a_uuid, b_uuid) || a_id == b_id) { - /* - * some of the logic in here may be redundant... - * - * if the UUID from the TE doesnt match then one better - * be a pending operation. - * pending operations dont survive between elections and joins - * because we query the LRM directly - */ - - CRM_CHECK(a_call_id == -1 || b_call_id == -1, sort_return(0)); - CRM_CHECK(a_call_id >= 0 || b_call_id >= 0, sort_return(0)); - - if(b_call_id == -1) { - crm_debug_2("%s (%d) < %s (%d) : transition + call id", - ID(a), a_call_id, ID(b), b_call_id); - sort_return(-1); - } - - if(a_call_id == -1) { - crm_debug_2("%s (%d) > %s (%d) : transition + call id", - ID(a), a_call_id, ID(b), b_call_id); - sort_return(1); - } - - } else if((a_id >= 0 && a_id < b_id) || b_id == -1) { - crm_debug_3("%s (%d) < %s (%d) : transition", - ID(a), a_id, ID(b), b_id); - sort_return(-1); - - } else if((b_id >= 0 && a_id > b_id) || a_id == -1) { - crm_debug_3("%s (%d) > %s (%d) : transition", - ID(a), a_id, ID(b), b_id); - sort_return(1); - } - - /* we should never end up here */ - crm_err("%s (%d:%d:%s) ?? %s (%d:%d:%s) : default", - ID(a), a_call_id, a_id, a_uuid, ID(b), b_call_id, b_id, b_uuid); - CRM_CHECK(FALSE, sort_return(0)); -} - -static gboolean -check_action_definition(resource_t *rsc, node_t *active_node, crm_data_t *xml_op, - pe_working_set_t *data_set) -{ - char *key = NULL; - int interval = 0; - const char *interval_s = NULL; - - gboolean did_change = FALSE; - - crm_data_t *pnow = NULL; - GHashTable *local_rsc_params = NULL; - - char *pnow_digest = NULL; - const char *param_digest = NULL; - char *local_param_digest = NULL; - -#if CRM_DEPRECATED_SINCE_2_0_4 - crm_data_t *params = NULL; -#endif - - action_t *action = NULL; - const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK); - const char *op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION); - - CRM_CHECK(active_node != NULL, return FALSE); - - interval_s = get_interval(xml_op); - interval = crm_parse_int(interval_s, "0"); - key = generate_op_key(rsc->id, task, interval); - - if(interval > 0) { - crm_data_t *op_match = NULL; - - crm_debug_2("Checking parameters for %s %s", key, task); - op_match = find_rsc_op_entry(rsc, key); - - if(op_match == NULL && data_set->stop_action_orphans) { - /* create a cancel action */ - action_t *cancel = NULL; - crm_info("Orphan action will be stopped: %s on %s", - key, active_node->details->uname); - - crm_free(key); - key = generate_op_key(rsc->id, CRMD_ACTION_CANCEL, interval); - - cancel = custom_action( - rsc, key, CRMD_ACTION_CANCEL, active_node, - FALSE, TRUE, data_set); - - add_hash_param(cancel->meta, XML_LRM_ATTR_TASK, task); - add_hash_param(cancel->meta, - XML_LRM_ATTR_INTERVAL, interval_s); - - custom_action_order( - rsc, NULL, cancel, - rsc, stop_key(rsc), NULL, - pe_ordering_optional, data_set); - } - if(op_match == NULL) { - crm_debug("Orphan action detected: %s on %s", - key, active_node->details->uname); - return TRUE; - } - } - - action = custom_action(rsc, key, task, active_node, TRUE, FALSE, data_set); - - local_rsc_params = g_hash_table_new_full( - g_str_hash, g_str_equal, - g_hash_destroy_str, g_hash_destroy_str); - - unpack_instance_attributes( - rsc->xml, XML_TAG_ATTR_SETS, active_node, local_rsc_params, - NULL, 0, data_set); - - pnow = create_xml_node(NULL, XML_TAG_PARAMS); - g_hash_table_foreach(action->extra, hash2field, pnow); - g_hash_table_foreach(rsc->parameters, hash2field, pnow); - g_hash_table_foreach(local_rsc_params, hash2field, pnow); - - filter_action_parameters(pnow, op_version); - pnow_digest = calculate_xml_digest(pnow, TRUE); - param_digest = crm_element_value(xml_op, XML_LRM_ATTR_OP_DIGEST); - -#if CRM_DEPRECATED_SINCE_2_0_4 - if(param_digest == NULL) { - params = find_xml_node(xml_op, XML_TAG_PARAMS, TRUE); - } - if(params != NULL) { - crm_data_t *local_params = copy_xml(params); - - crm_warn("Faking parameter digest creation for %s", ID(xml_op)); - filter_action_parameters(local_params, op_version); - xml_remove_prop(local_params, "interval"); - xml_remove_prop(local_params, "timeout"); - crm_log_xml_warn(local_params, "params:used"); - - local_param_digest = calculate_xml_digest(local_params, TRUE); - param_digest = local_param_digest; - - free_xml(local_params); - } -#endif - - if(safe_str_neq(pnow_digest, param_digest)) { -#if CRM_DEPRECATED_SINCE_2_0_4 - if(params) { - crm_data_t *local_params = copy_xml(params); - filter_action_parameters(local_params, op_version); - xml_remove_prop(local_params, "interval"); - xml_remove_prop(local_params, "timeout"); - - free_xml(local_params); - } -#endif - did_change = TRUE; - crm_log_xml_info(pnow, "params:calc"); - crm_warn("Parameters to %s on %s changed: recorded %s vs. calculated %s", - ID(xml_op), active_node->details->uname, - crm_str(param_digest), pnow_digest); - - key = generate_op_key(rsc->id, task, interval); - custom_action(rsc, key, task, NULL, FALSE, TRUE, data_set); - } - - free_xml(pnow); - crm_free(pnow_digest); - crm_free(local_param_digest); - g_hash_table_destroy(local_rsc_params); - - pe_free_action(action); - - return did_change; -} - -gboolean -unpack_rsc_op(resource_t *rsc, node_t *node, crm_data_t *xml_op, - int *max_call_id, enum action_fail_response *on_fail, - pe_working_set_t *data_set) -{ - const char *id = NULL; - const char *task = NULL; - const char *task_id = NULL; - const char *actual_rc = NULL; -/* const char *target_rc = NULL; */ - const char *task_status = NULL; - const char *interval_s = NULL; - const char *op_digest = NULL; - - int interval = 0; - int task_id_i = -1; - int task_status_i = -2; - int actual_rc_i = 0; - - action_t *action = NULL; - gboolean is_probe = FALSE; - gboolean is_stop_action = FALSE; - - CRM_CHECK(rsc != NULL, return FALSE); - CRM_CHECK(node != NULL, return FALSE); - CRM_CHECK(xml_op != NULL, return FALSE); - - id = ID(xml_op); - task = crm_element_value(xml_op, XML_LRM_ATTR_TASK); - task_id = crm_element_value(xml_op, XML_LRM_ATTR_CALLID); - task_status = crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS); - op_digest = crm_element_value(xml_op, XML_LRM_ATTR_OP_DIGEST); - - CRM_CHECK(id != NULL, return FALSE); - CRM_CHECK(task != NULL, return FALSE); - CRM_CHECK(task_status != NULL, return FALSE); - - task_status_i = crm_parse_int(task_status, NULL); - - CRM_CHECK(task_status_i <= LRM_OP_ERROR, return FALSE); - CRM_CHECK(task_status_i >= LRM_OP_PENDING, return FALSE); - - if(safe_str_eq(task, CRMD_ACTION_NOTIFY)) { - /* safe to ignore these */ - return TRUE; - } - - crm_debug_2("Unpacking task %s/%s (call_id=%s, status=%s) on %s (role=%s)", - id, task, task_id, task_status, node->details->uname, - role2text(rsc->role)); - - interval_s = get_interval(xml_op); - interval = crm_parse_int(interval_s, "0"); - - if(interval == 0 && safe_str_eq(task, CRMD_ACTION_STATUS)) { - is_probe = TRUE; - - } else if(interval > 0 && rsc->role < RSC_ROLE_STARTED) { - crm_debug_2("Skipping recurring action %s for stopped resource", id); - return FALSE; - } - - if(rsc->orphan) { - crm_debug_2("Skipping param check for orphan: %s %s", - rsc->id, task); - - } else if(safe_str_eq(task, CRMD_ACTION_STOP)) { - crm_debug_2("Ignoring stop params: %s", id); - - } else if(is_probe || safe_str_eq(task, CRMD_ACTION_START) || interval > 0) { - crm_debug_3("Checking resource definition: %s", rsc->id); - check_action_definition(rsc, node, xml_op, data_set); - } - - if(safe_str_eq(task, CRMD_ACTION_STOP)) { - is_stop_action = TRUE; - } - - if(task_status_i != LRM_OP_PENDING) { - task_id_i = crm_parse_int(task_id, "-1"); - - CRM_CHECK(task_id != NULL, return FALSE); - CRM_CHECK(task_id_i >= 0, return FALSE); - CRM_CHECK(task_id_i > *max_call_id, return FALSE); - } - - if(*max_call_id < task_id_i) { - *max_call_id = task_id_i; - } - - if(node->details->unclean) { - crm_debug_2("Node %s (where %s is running) is unclean." - " Further action depends on the value of %s", - node->details->uname, rsc->id, XML_RSC_ATTR_STOPFAIL); - } - - actual_rc = crm_element_value(xml_op, XML_LRM_ATTR_RC); - CRM_CHECK(actual_rc != NULL, return FALSE); - actual_rc_i = crm_parse_int(actual_rc, NULL); - - if(EXECRA_NOT_RUNNING == actual_rc_i) { - if(is_probe) { - /* treat these like stops */ - is_stop_action = TRUE; - } - if(is_stop_action) { - task_status_i = LRM_OP_DONE; - } else { - CRM_CHECK(task_status_i == LRM_OP_ERROR, - task_status_i = LRM_OP_ERROR); - } - - } else if(EXECRA_RUNNING_MASTER == actual_rc_i) { - if(is_probe - || (rsc->role == RSC_ROLE_MASTER - && safe_str_eq(task, CRMD_ACTION_STATUS))) { - task_status_i = LRM_OP_DONE; - } else { - if(rsc->role != RSC_ROLE_MASTER) { - crm_err("%s reported %s in master mode on %s", - id, rsc->id, - node->details->uname); - } - - CRM_CHECK(task_status_i == LRM_OP_ERROR, - task_status_i = LRM_OP_ERROR); - } - rsc->role = RSC_ROLE_MASTER; - - } else if(EXECRA_FAILED_MASTER == actual_rc_i) { - rsc->role = RSC_ROLE_MASTER; - task_status_i = LRM_OP_ERROR; - - } else if(EXECRA_OK == actual_rc_i - && interval > 0 - && rsc->role == RSC_ROLE_MASTER) { - /* catch status ops that return 0 instead of 8 while they - * are supposed to be in master mode - */ - task_status_i = LRM_OP_ERROR; - } - - if(task_status_i == LRM_OP_ERROR - || task_status_i == LRM_OP_TIMEOUT - || task_status_i == LRM_OP_NOTSUPPORTED) { - action = custom_action(rsc, crm_strdup(id), task, NULL, - TRUE, FALSE, data_set); - if(action->on_fail == action_fail_ignore) { - task_status_i = LRM_OP_DONE; - } - } - - switch(task_status_i) { - case LRM_OP_PENDING: - if(safe_str_eq(task, CRMD_ACTION_START)) { - rsc->start_pending = TRUE; - rsc->role = RSC_ROLE_STARTED; - - } else if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) { - rsc->role = RSC_ROLE_MASTER; - } - break; - - case LRM_OP_DONE: - crm_debug_3("%s/%s completed on %s", - rsc->id, task, node->details->uname); - - if(is_stop_action) { - rsc->role = RSC_ROLE_STOPPED; - - /* clear any previous failure actions */ - *on_fail = action_fail_ignore; - rsc->next_role = RSC_ROLE_UNKNOWN; - - } else if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) { - rsc->role = RSC_ROLE_MASTER; - - } else if(safe_str_eq(task, CRMD_ACTION_DEMOTE)) { - rsc->role = RSC_ROLE_SLAVE; - - } else if(rsc->role < RSC_ROLE_STARTED) { - crm_debug_3("%s active on %s", - rsc->id, node->details->uname); - rsc->role = RSC_ROLE_STARTED; - } - break; - - case LRM_OP_ERROR: - case LRM_OP_TIMEOUT: - case LRM_OP_NOTSUPPORTED: - crm_warn("Processing failed op (%s) for %s on %s", - id, rsc->id, node->details->uname); - - if(*on_fail < action->on_fail) { - *on_fail = action->on_fail; - } - - if(task_status_i == LRM_OP_NOTSUPPORTED - || is_stop_action - || safe_str_eq(task, CRMD_ACTION_START) ) { - crm_warn("Handling failed %s for %s on %s", - task, rsc->id, node->details->uname); - rsc2node_new("dont_run__failed_stopstart", - rsc, -INFINITY, node, data_set); - } - - if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) { - rsc->role = RSC_ROLE_MASTER; - - } else if(safe_str_eq(task, CRMD_ACTION_DEMOTE)) { - rsc->role = RSC_ROLE_MASTER; - - } else if(rsc->role < RSC_ROLE_STARTED) { - rsc->role = RSC_ROLE_STARTED; - } - - crm_debug_2("Resource %s: role=%s, unclean=%s, on_fail=%s, fail_role=%s", - rsc->id, role2text(rsc->role), - node->details->unclean?"true":"false", - fail2text(action->on_fail), - role2text(action->fail_role)); - - if(action->fail_role != RSC_ROLE_STARTED - && rsc->next_role < action->fail_role) { - rsc->next_role = action->fail_role; - } - - if(action->fail_role == RSC_ROLE_STOPPED) { - /* make sure it doesnt come up again */ - native_assign_color(rsc, data_set->no_color); - } - - pe_free_action(action); - action = NULL; - break; - case LRM_OP_CANCELLED: - /* do nothing?? */ - pe_err("Dont know what to do for cancelled ops yet"); - break; - } - - crm_debug_3("Resource %s after %s: role=%s", - rsc->id, task, role2text(rsc->role)); - - pe_free_action(action); - - return TRUE; -} - -gboolean -rsc_colocation_new(const char *id, enum con_strength strength, - resource_t *rsc_lh, resource_t *rsc_rh, - const char *state_lh, const char *state_rh) -{ - rsc_colocation_t *new_con = NULL; - rsc_colocation_t *inverted_con = NULL; - - if(rsc_lh == NULL){ - pe_config_err("No resource found for LHS %s", id); - return FALSE; - - } else if(rsc_rh == NULL){ - pe_config_err("No resource found for RHS of %s", id); - return FALSE; - } - - crm_malloc0(new_con, sizeof(rsc_colocation_t)); - if(new_con == NULL) { - return FALSE; - } - if(safe_str_eq(state_lh, CRMD_ACTION_STARTED)) { - state_lh = NULL; - } - if(safe_str_eq(state_rh, CRMD_ACTION_STARTED)) { - state_rh = NULL; - } - - new_con->id = id; - new_con->rsc_lh = rsc_lh; - new_con->rsc_rh = rsc_rh; - new_con->strength = strength; - new_con->state_lh = state_lh; - new_con->state_rh = state_rh; - - inverted_con = invert_constraint(new_con); - - crm_debug_4("Adding constraint %s (%p) to %s", - new_con->id, new_con, rsc_lh->id); - - rsc_lh->rsc_cons = g_list_insert_sorted( - rsc_lh->rsc_cons, new_con, sort_cons_strength); - - crm_debug_4("Adding constraint %s (%p) to %s", - inverted_con->id, inverted_con, rsc_rh->id); - - rsc_rh->rsc_cons = g_list_insert_sorted( - rsc_rh->rsc_cons, inverted_con, sort_cons_strength); - - return TRUE; -} - -/* LHS before RHS */ -gboolean -custom_action_order( - resource_t *lh_rsc, char *lh_action_task, action_t *lh_action, - resource_t *rh_rsc, char *rh_action_task, action_t *rh_action, - enum pe_ordering type, pe_working_set_t *data_set) -{ - order_constraint_t *order = NULL; - - if((lh_action == NULL && lh_rsc == NULL) - || (rh_action == NULL && rh_rsc == NULL)){ - pe_config_err("Invalid inputs lh_rsc=%p, lh_a=%p," - " rh_rsc=%p, rh_a=%p", - lh_rsc, lh_action, rh_rsc, rh_action); - crm_free(lh_action_task); - crm_free(rh_action_task); - return FALSE; - } - - crm_malloc0(order, sizeof(order_constraint_t)); - if(order == NULL) { return FALSE; } - - order->id = data_set->order_id++; - order->type = type; - order->lh_rsc = lh_rsc; - order->rh_rsc = rh_rsc; - order->lh_action = lh_action; - order->rh_action = rh_action; - order->lh_action_task = lh_action_task; - order->rh_action_task = rh_action_task; - - data_set->ordering_constraints = g_list_append( - data_set->ordering_constraints, order); - - if(lh_rsc != NULL && rh_rsc != NULL) { - crm_debug_4("Created ordering constraint %d (%s):" - " %s/%s before %s/%s", - order->id, ordering_type2text(order->type), - lh_rsc->id, lh_action_task, - rh_rsc->id, rh_action_task); - - } else if(lh_rsc != NULL) { - crm_debug_4("Created ordering constraint %d (%s):" - " %s/%s before action %d (%s)", - order->id, ordering_type2text(order->type), - lh_rsc->id, lh_action_task, - rh_action->id, rh_action_task); - - } else if(rh_rsc != NULL) { - crm_debug_4("Created ordering constraint %d (%s):" - " action %d (%s) before %s/%s", - order->id, ordering_type2text(order->type), - lh_action->id, lh_action_task, - rh_rsc->id, rh_action_task); - - } else { - crm_debug_4("Created ordering constraint %d (%s):" - " action %d (%s) before action %d (%s)", - order->id, ordering_type2text(order->type), - lh_action->id, lh_action_task, - rh_action->id, rh_action_task); - } - - return TRUE; -} - -gboolean -unpack_rsc_colocation(crm_data_t * xml_obj, pe_working_set_t *data_set) -{ - enum con_strength strength_e = pecs_ignore; - - const char *id = crm_element_value(xml_obj, XML_ATTR_ID); - const char *id_rh = crm_element_value(xml_obj, XML_CONS_ATTR_TO); - const char *id_lh = crm_element_value(xml_obj, XML_CONS_ATTR_FROM); - const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE); - const char *state_lh = crm_element_value(xml_obj, XML_RULE_ATTR_FROMSTATE); - const char *state_rh = crm_element_value(xml_obj, XML_RULE_ATTR_TOSTATE); - - resource_t *rsc_lh = pe_find_resource(data_set->resources, id_lh); - resource_t *rsc_rh = pe_find_resource(data_set->resources, id_rh); - - if(rsc_lh == NULL) { - pe_config_err("No resource (con=%s, rsc=%s)", id, id_lh); - return FALSE; - - } else if(rsc_rh == NULL) { - pe_config_err("No resource (con=%s, rsc=%s)", id, id_rh); - return FALSE; - } - - /* the docs indicate that only +/- INFINITY are allowed, - * but no-one ever reads the docs so all positive values will - * count as "must" and negative values as "must not" - */ - if(score == NULL || score[0] != '-') { - strength_e = pecs_must; - } else { - strength_e = pecs_must_not; - } - return rsc_colocation_new(id, strength_e, rsc_lh, rsc_rh, - state_lh, state_rh); -} - -static const char * -invert_action(const char *action) -{ - if(safe_str_eq(action, CRMD_ACTION_START)) { - return CRMD_ACTION_STOP; - - } else if(safe_str_eq(action, CRMD_ACTION_STOP)) { - return CRMD_ACTION_START; - - } else if(safe_str_eq(action, CRMD_ACTION_PROMOTE)) { - return CRMD_ACTION_DEMOTE; - - } else if(safe_str_eq(action, CRMD_ACTION_DEMOTE)) { - return CRMD_ACTION_PROMOTE; - - } else if(safe_str_eq(action, CRMD_ACTION_STARTED)) { - return CRMD_ACTION_STOPPED; - - } else if(safe_str_eq(action, CRMD_ACTION_STOPPED)) { - return CRMD_ACTION_STARTED; - - } - pe_err("Unknown action: %s", action); - return NULL; -} - - -gboolean -unpack_rsc_order(crm_data_t * xml_obj, pe_working_set_t *data_set) -{ - gboolean symmetrical_bool = TRUE; - - const char *id = crm_element_value(xml_obj, XML_ATTR_ID); - const char *type = crm_element_value(xml_obj, XML_ATTR_TYPE); - const char *id_rh = crm_element_value(xml_obj, XML_CONS_ATTR_TO); - const char *id_lh = crm_element_value(xml_obj, XML_CONS_ATTR_FROM); - const char *action = crm_element_value(xml_obj, XML_CONS_ATTR_ACTION); - const char *action_rh = crm_element_value(xml_obj, XML_CONS_ATTR_TOACTION); - - const char *symmetrical = crm_element_value( - xml_obj, XML_CONS_ATTR_SYMMETRICAL); - - resource_t *rsc_lh = NULL; - resource_t *rsc_rh = NULL; - - if(xml_obj == NULL) { - pe_config_err("No constraint object to process."); - return FALSE; - - } else if(id == NULL) { - pe_config_err("%s constraint must have an id", - crm_element_name(xml_obj)); - return FALSE; - - } else if(id_lh == NULL || id_rh == NULL) { - pe_config_err("Constraint %s needs two sides lh: %s rh: %s", - id, crm_str(id_lh), crm_str(id_rh)); - return FALSE; - } - - if(action == NULL) { - action = CRMD_ACTION_START; - } - if(action_rh == NULL) { - action_rh = action; - } - CRM_CHECK(action != NULL, return FALSE); - CRM_CHECK(action_rh != NULL, return FALSE); - - if(safe_str_eq(type, "before")) { - id_lh = crm_element_value(xml_obj, XML_CONS_ATTR_TO); - id_rh = crm_element_value(xml_obj, XML_CONS_ATTR_FROM); - action = crm_element_value(xml_obj, XML_CONS_ATTR_TOACTION); - action_rh = crm_element_value(xml_obj, XML_CONS_ATTR_ACTION); - if(action_rh == NULL) { - action_rh = CRMD_ACTION_START; - } - if(action == NULL) { - action = action_rh; - } - } - - CRM_CHECK(action != NULL, return FALSE); - CRM_CHECK(action_rh != NULL, return FALSE); - - rsc_lh = pe_find_resource(data_set->resources, id_rh); - rsc_rh = pe_find_resource(data_set->resources, id_lh); - - if(rsc_lh == NULL) { - pe_config_err("Constraint %s: no resource found for LHS of %s", id, id_lh); - return FALSE; - - } else if(rsc_rh == NULL) { - pe_config_err("Constraint %s: no resource found for RHS of %s", id, id_rh); - return FALSE; - } - - custom_action_order( - rsc_lh, generate_op_key(rsc_lh->id, action, 0), NULL, - rsc_rh, generate_op_key(rsc_rh->id, action_rh, 0), NULL, - pe_ordering_optional, data_set); - - if(rsc_rh->restart_type == pe_restart_restart - && safe_str_eq(action, action_rh)) { - if(safe_str_eq(action, CRMD_ACTION_START)) { - crm_debug_2("Recover start-start: %s-%s", - rsc_lh->id, rsc_rh->id); - order_start_start(rsc_lh, rsc_rh, pe_ordering_recover); - } else if(safe_str_eq(action, CRMD_ACTION_STOP)) { - crm_debug_2("Recover stop-stop: %s-%s", - rsc_rh->id, rsc_lh->id); - order_stop_stop(rsc_rh, rsc_lh, pe_ordering_recover); - } - } - - cl_str_to_boolean(symmetrical, &symmetrical_bool); - if(symmetrical_bool == FALSE) { - return TRUE; - } - - action = invert_action(action); - action_rh = invert_action(action_rh); - - custom_action_order( - rsc_rh, generate_op_key(rsc_rh->id, action_rh, 0), NULL, - rsc_lh, generate_op_key(rsc_lh->id, action, 0), NULL, - pe_ordering_optional, data_set); - - if(rsc_lh->restart_type == pe_restart_restart - && safe_str_eq(action, action_rh)) { - if(safe_str_eq(action, CRMD_ACTION_START)) { - crm_debug_2("Recover start-start (2): %s-%s", - rsc_lh->id, rsc_rh->id); - order_start_start(rsc_lh, rsc_rh, pe_ordering_recover); - } else if(safe_str_eq(action, CRMD_ACTION_STOP)) { - crm_debug_2("Recover stop-stop (2): %s-%s", - rsc_rh->id, rsc_lh->id); - order_stop_stop(rsc_rh, rsc_lh, pe_ordering_recover); - } - } - - return TRUE; -} - -gboolean -add_node_attrs(crm_data_t *xml_obj, node_t *node, pe_working_set_t *data_set) -{ - g_hash_table_insert(node->details->attrs, - crm_strdup("#"XML_ATTR_UNAME), - crm_strdup(node->details->uname)); - g_hash_table_insert(node->details->attrs, - crm_strdup("#"XML_ATTR_ID), - crm_strdup(node->details->id)); - if(safe_str_eq(node->details->id, data_set->dc_uuid)) { - data_set->dc_node = node; - node->details->is_dc = TRUE; - g_hash_table_insert(node->details->attrs, - crm_strdup("#"XML_ATTR_DC), - crm_strdup(XML_BOOLEAN_TRUE)); - } else { - g_hash_table_insert(node->details->attrs, - crm_strdup("#"XML_ATTR_DC), - crm_strdup(XML_BOOLEAN_FALSE)); - } - - unpack_instance_attributes( - xml_obj, XML_TAG_ATTR_SETS, node, node->details->attrs, - NULL, 0, data_set); - - return TRUE; -} - -gboolean -unpack_rsc_location(crm_data_t * xml_obj, pe_working_set_t *data_set) -{ - const char *id_lh = crm_element_value(xml_obj, "rsc"); - const char *id = crm_element_value(xml_obj, XML_ATTR_ID); - resource_t *rsc_lh = pe_find_resource(data_set->resources, id_lh); - - if(rsc_lh == NULL) { - /* only a warn as BSC adds the constraint then the resource */ - pe_config_warn("No resource (con=%s, rsc=%s)", id, id_lh); - return FALSE; - - } else if(rsc_lh->is_managed == FALSE) { - crm_debug_2("Ignoring constraint %s: resource %s not managed", - id, id_lh); - return FALSE; - } - - xml_child_iter_filter( - xml_obj, rule_xml, XML_TAG_RULE, - crm_debug_2("Unpacking %s/%s", id, ID(rule_xml)); - generate_location_rule(rsc_lh, rule_xml, data_set); - ); - return TRUE; -} - -rsc_to_node_t * -generate_location_rule( - resource_t *rsc, crm_data_t *rule_xml, pe_working_set_t *data_set) -{ - const char *rule_id = NULL; - const char *score = NULL; - const char *boolean = NULL; - const char *role = NULL; - const char *attr_score = NULL; - - GListPtr match_L = NULL; - - int score_f = 0; - gboolean do_and = TRUE; - gboolean accept = TRUE; - gboolean raw_score = TRUE; - - rsc_to_node_t *location_rule = NULL; - - rule_id = crm_element_value(rule_xml, XML_ATTR_ID); - boolean = crm_element_value(rule_xml, XML_RULE_ATTR_BOOLEAN_OP); - role = crm_element_value(rule_xml, XML_RULE_ATTR_ROLE); - - crm_debug_2("Processing rule: %s", rule_id); - - if(role != NULL && text2role(role) == RSC_ROLE_UNKNOWN) { - pe_err("Bad role specified for %s: %s", rule_id, role); - return NULL; - } - - score = crm_element_value(rule_xml, XML_RULE_ATTR_SCORE); - if(score != NULL) { - score_f = char2score(score); - - } else { - score = crm_element_value( - rule_xml, XML_RULE_ATTR_SCORE_ATTRIBUTE); - if(score == NULL) { - score = crm_element_value( - rule_xml, XML_RULE_ATTR_SCORE_MANGLED); - } - if(score != NULL) { - raw_score = FALSE; - } - } - - if(safe_str_eq(boolean, "or")) { - do_and = FALSE; - } - - location_rule = rsc2node_new(rule_id, rsc, 0, NULL, data_set); - - if(location_rule == NULL) { - return NULL; - } - if(role != NULL) { - crm_debug_2("Setting role filter: %s", role); - location_rule->role_filter = text2role(role); - } - if(do_and) { - match_L = node_list_dup(data_set->nodes, TRUE, FALSE); - slist_iter( - node, node_t, match_L, lpc, - node->weight = score_f; - ); - } - - xml_child_iter( - rule_xml, expr, - - enum expression_type type = find_expression_type(expr); - if(type == not_expr) { - pe_err("Expression <%s id=%s...> is not valid", - crm_element_name(expr), crm_str(ID(expr))); - continue; - - } - - slist_iter( - node, node_t, data_set->nodes, lpc, - - if(type == nested_rule) { - accept = test_rule(expr, node, rsc, data_set); - } else { - accept = test_expression( - expr, node, rsc, data_set); - } - - if(raw_score == FALSE) { - attr_score = g_hash_table_lookup( - node->details->attrs, score); - if(attr_score == NULL) { - accept = FALSE; - pe_warn("node %s did not have a value" - " for %s", - node->details->uname, score); - } else { - score_f = char2score(score); - } - } - - if(!do_and && accept) { - node_t *local = pe_find_node_id( - match_L, node->details->id); - if(local == NULL) { - local = node_copy(node); - match_L = g_list_append(match_L, local); - } - local->weight = merge_weights( - local->weight, score_f); - crm_debug_5("node %s already matched", - node->details->uname); - - } else if(do_and && !accept) { - /* remove it */ - node_t *delete = pe_find_node_id( - match_L, node->details->id); - if(delete != NULL) { - match_L = g_list_remove(match_L,delete); - crm_debug_5("node %s did not match", - node->details->uname); - } - crm_free(delete); - } - ); - ); - - location_rule->node_list_rh = match_L; - if(location_rule->node_list_rh == NULL) { - crm_debug_2("No matching nodes for rule %s", rule_id); - return NULL; - } - - crm_debug_3("%s: %d nodes matched", - rule_id, g_list_length(location_rule->node_list_rh)); - crm_action_debug_3(print_rsc_to_node("Added", location_rule, FALSE)); - return location_rule; -} diff --git a/crm/pengine/utils.c b/crm/pengine/utils.c deleted file mode 100644 index 0626d44ffb..0000000000 --- a/crm/pengine/utils.c +++ /dev/null @@ -1,1945 +0,0 @@ -/* $Id: utils.c,v 1.143 2006/06/01 16:41:23 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 - -void print_str_str(gpointer key, gpointer value, gpointer user_data); -gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data); -void unpack_operation( - action_t *action, crm_data_t *xml_obj, pe_working_set_t* data_set); - -/* only for rsc_colocation constraints */ -rsc_colocation_t * -invert_constraint(rsc_colocation_t *constraint) -{ - rsc_colocation_t *inverted_con = NULL; - - crm_debug_3("Inverting constraint"); - if(constraint == NULL) { - pe_err("Cannot invert NULL constraint"); - return NULL; - } - - crm_malloc0(inverted_con, sizeof(rsc_colocation_t)); - - if(inverted_con == NULL) { - return NULL; - } - - inverted_con->id = constraint->id; - inverted_con->strength = constraint->strength; - - /* swap the direction */ - inverted_con->rsc_lh = constraint->rsc_rh; - inverted_con->rsc_rh = constraint->rsc_lh; - inverted_con->state_lh = constraint->state_rh; - inverted_con->state_rh = constraint->state_lh; - - crm_action_debug_3( - print_rsc_colocation("Inverted constraint", inverted_con, FALSE)); - - return inverted_con; -} - - -/* are the contents of list1 and list2 equal - * nodes with weight < 0 are ignored if filter == TRUE - * - * slow but linear - * - */ -gboolean -node_list_eq(GListPtr list1, GListPtr list2, gboolean filter) -{ - node_t *other_node; - - GListPtr lhs = list1; - GListPtr rhs = list2; - - slist_iter( - node, node_t, lhs, lpc, - - if(node == NULL || (filter && node->weight < 0)) { - continue; - } - - other_node = (node_t*) - pe_find_node_id(rhs, node->details->id); - - if(other_node == NULL || other_node->weight < 0) { - return FALSE; - } - ); - - lhs = list2; - rhs = list1; - - slist_iter( - node, node_t, lhs, lpc, - - if(node == NULL || (filter && node->weight < 0)) { - continue; - } - - other_node = (node_t*) - pe_find_node_id(rhs, node->details->id); - - if(other_node == NULL || other_node->weight < 0) { - return FALSE; - } - ); - - return TRUE; -} - -/* the intersection of list1 and list2 - */ -GListPtr -node_list_and(GListPtr list1, GListPtr list2, gboolean filter) -{ - GListPtr result = NULL; - unsigned lpc = 0; - - for(lpc = 0; lpc < g_list_length(list1); lpc++) { - node_t *node = (node_t*)g_list_nth_data(list1, lpc); - node_t *other_node = pe_find_node_id(list2, node->details->id); - node_t *new_node = NULL; - - if(other_node != NULL) { - new_node = node_copy(node); - } - - if(new_node != NULL) { - crm_debug_4("%s: %d + %d", node->details->uname, - other_node->weight, new_node->weight); - new_node->weight = merge_weights( - new_node->weight, other_node->weight); - - crm_debug_3("New node weight for %s: %d", - new_node->details->uname, new_node->weight); - - if(filter && new_node->weight < 0) { - crm_free(new_node); - new_node = NULL; - } - } - - if(new_node != NULL) { - result = g_list_append(result, new_node); - } - } - - return result; -} - - -/* list1 - list2 */ -GListPtr -node_list_minus(GListPtr list1, GListPtr list2, gboolean filter) -{ - GListPtr result = NULL; - - slist_iter( - node, node_t, list1, lpc, - node_t *other_node = pe_find_node_id(list2, node->details->id); - node_t *new_node = NULL; - - if(node == NULL || other_node != NULL - || (filter && node->weight < 0)) { - continue; - - } - new_node = node_copy(node); - result = g_list_append(result, new_node); - ); - - crm_debug_3("Minus result len: %d", g_list_length(result)); - - return result; -} - -/* list1 + list2 - (intersection of list1 and list2) */ -GListPtr -node_list_xor(GListPtr list1, GListPtr list2, gboolean filter) -{ - GListPtr result = NULL; - - slist_iter( - node, node_t, list1, lpc, - node_t *new_node = NULL; - node_t *other_node = (node_t*) - pe_find_node_id(list2, node->details->id); - - if(node == NULL || other_node != NULL - || (filter && node->weight < 0)) { - continue; - } - new_node = node_copy(node); - result = g_list_append(result, new_node); - ); - - - slist_iter( - node, node_t, list2, lpc, - node_t *new_node = NULL; - node_t *other_node = (node_t*) - pe_find_node_id(list1, node->details->id); - - if(node == NULL || other_node != NULL - || (filter && node->weight < 0)) { - continue; - } - new_node = node_copy(node); - result = g_list_append(result, new_node); - ); - - crm_debug_3("Xor result len: %d", g_list_length(result)); - return result; -} - -GListPtr -node_list_or(GListPtr list1, GListPtr list2, gboolean filter) -{ - node_t *other_node = NULL; - GListPtr result = NULL; - gboolean needs_filter = FALSE; - - result = node_list_dup(list1, FALSE, filter); - - slist_iter( - node, node_t, list2, lpc, - - if(node == NULL) { - continue; - } - - other_node = (node_t*)pe_find_node_id( - result, node->details->id); - - if(other_node != NULL) { - crm_debug_4("%s + %s: %d + %d", - node->details->uname, - other_node->details->uname, - node->weight, other_node->weight); - other_node->weight = merge_weights( - other_node->weight, node->weight); - - if(filter && node->weight < 0) { - needs_filter = TRUE; - } - - } else if(filter == FALSE || node->weight >= 0) { - node_t *new_node = node_copy(node); - result = g_list_append(result, new_node); - } - ); - - /* not the neatest way, but the most expedient for now */ - if(filter && needs_filter) { - GListPtr old_result = result; - result = node_list_dup(old_result, FALSE, filter); - pe_free_shallow_adv(old_result, TRUE); - } - - - return result; -} - -GListPtr -node_list_dup(GListPtr list1, gboolean reset, gboolean filter) -{ - GListPtr result = NULL; - - slist_iter( - this_node, node_t, list1, lpc, - node_t *new_node = NULL; - if(filter && this_node->weight < 0) { - continue; - } - - new_node = node_copy(this_node); - if(reset) { - new_node->weight = 0; - } - if(new_node != NULL) { - result = g_list_append(result, new_node); - } - ); - - return result; -} - -node_t * -node_copy(node_t *this_node) -{ - node_t *new_node = NULL; - - CRM_CHECK(this_node != NULL, return NULL); - crm_malloc0(new_node, sizeof(node_t)); - - CRM_CHECK(new_node != NULL, return NULL); - - crm_debug_5("Copying %p (%s) to %p", - this_node, this_node->details->uname, new_node); - new_node->weight = this_node->weight; - new_node->fixed = this_node->fixed; - new_node->details = this_node->details; - - return new_node; -} - -/* - * Create a new color with the contents of "nodes" as the list of - * possible nodes that resources with this color can be run on. - * - * Typically, when creating a color you will provide the node list from - * the resource you will first assign the color to. - * - * If "colors" != NULL, it will be added to that list - * If "resources" != NULL, it will be added to every provisional resource - * in that list - */ -color_t * -create_color( - pe_working_set_t *data_set, resource_t *resource, GListPtr node_list) -{ - color_t *new_color = NULL; - - crm_debug_5("Creating color"); - crm_malloc0(new_color, sizeof(color_t)); - if(new_color == NULL) { - return NULL; - } - - new_color->id = data_set->color_id++; - new_color->local_weight = 1.0; - - crm_debug_5("Creating color details"); - crm_malloc0(new_color->details, sizeof(struct color_shared_s)); - - if(new_color->details == NULL) { - crm_free(new_color); - return NULL; - } - - new_color->details->id = new_color->id; - new_color->details->highest_priority = -1; - new_color->details->chosen_node = NULL; - new_color->details->candidate_nodes = NULL; - new_color->details->allocated_resources = NULL; - new_color->details->pending = TRUE; - - if(resource != NULL) { - crm_debug_5("populating node list"); - new_color->details->highest_priority = resource->priority; - new_color->details->candidate_nodes = - node_list_dup(node_list, TRUE, TRUE); - } - - crm_action_debug_3(print_color("Created color", new_color, TRUE)); - - CRM_CHECK(data_set != NULL, return NULL); - data_set->colors = g_list_append(data_set->colors, new_color); - return new_color; -} - -color_t * -copy_color(color_t *a_color) -{ - color_t *color_copy = NULL; - - if(a_color == NULL) { - pe_err("Cannot copy NULL"); - return NULL; - } - - crm_malloc0(color_copy, sizeof(color_t)); - if(color_copy != NULL) { - color_copy->id = a_color->id; - color_copy->details = a_color->details; - color_copy->local_weight = 1.0; - } - return color_copy; -} - - - -resource_t * -pe_find_resource(GListPtr rsc_list, const char *id) -{ - unsigned lpc = 0; - resource_t *rsc = NULL; - resource_t *child_rsc = NULL; - - if(id == NULL) { - return NULL; - } - - crm_debug_4("Looking for %s in %d objects", id, g_list_length(rsc_list)); - for(lpc = 0; lpc < g_list_length(rsc_list); lpc++) { - rsc = g_list_nth_data(rsc_list, lpc); - if(rsc == NULL) { - } else if(safe_str_eq(rsc->id, id)){ - crm_debug_4("Found a match for %s", id); - return rsc; - - } else if(safe_str_eq(rsc->long_name, id)) { - crm_debug_4("Found a match for %s", id); - return rsc; - } - } - for(lpc = 0; lpc < g_list_length(rsc_list); lpc++) { - rsc = g_list_nth_data(rsc_list, lpc); - - child_rsc = rsc->fns->find_child(rsc, id); - if(child_rsc != NULL) { - crm_debug_4("Found a match for %s in %s", - id, rsc->id); - - return child_rsc; - } - } - crm_debug_2("No match for %s", id); - return NULL; -} - - -node_t * -pe_find_node_id(GListPtr nodes, const char *id) -{ - unsigned lpc = 0; - node_t *node = NULL; - - for(lpc = 0; lpc < g_list_length(nodes); lpc++) { - node = g_list_nth_data(nodes, lpc); - if(safe_str_eq(node->details->id, id)) { - return node; - } - } - /* error */ - return NULL; -} - -gint gslist_color_compare(gconstpointer a, gconstpointer b); -color_t * -find_color(GListPtr candidate_colors, color_t *other_color) -{ - GListPtr tmp = g_list_find_custom(candidate_colors, other_color, - gslist_color_compare); - if(tmp != NULL) { - return (color_t *)tmp->data; - } - return NULL; -} - - -gint gslist_color_compare(gconstpointer a, gconstpointer b) -{ - const color_t *color_a = (const color_t*)a; - const color_t *color_b = (const color_t*)b; - -/* crm_debug_5("%d vs. %d", a?color_a->id:-2, b?color_b->id:-2); */ - if(a == b) { - return 0; - } else if(a == NULL || b == NULL) { - return 1; - } else if(color_a->id == color_b->id) { - return 0; - } - return 1; -} - -gint sort_rsc_priority(gconstpointer a, gconstpointer b) -{ - const resource_t *resource1 = (const resource_t*)a; - const resource_t *resource2 = (const resource_t*)b; - - if(a == NULL && b == NULL) { return 0; } - if(a == NULL) { return 1; } - if(b == NULL) { return -1; } - - if(resource1->priority > resource2->priority) { - return -1; - } - - if(resource1->priority < resource2->priority) { - return 1; - } - - return 0; -} - -gint sort_rsc_node_weight(gconstpointer a, gconstpointer b) -{ - const resource_t *resource1 = (const resource_t*)a; - const resource_t *resource2 = (const resource_t*)b; - - const color_t *color1 = NULL; - const color_t *color2 = NULL; - - const node_t *node1 = NULL; - const node_t *node2 = NULL; - - CRM_ASSERT(resource1 != NULL); - CRM_ASSERT(resource2 != NULL); - - color1 = resource1->color; - color2 = resource2->color; - - CRM_CHECK(color1 != NULL, return 0); - CRM_CHECK(color2 != NULL, return 0); - node1 = color1->details->chosen_node; - node2 = color2->details->chosen_node; - - if(node1 == NULL && node2 == NULL) { return 0; } - if(node1 == NULL) { return 1; } - if(node2 == NULL) { return -1; } - - CRM_ASSERT(node1 != NULL); - CRM_ASSERT(node2 != NULL); - if(node1->weight > node2->weight) { - crm_debug("%s (%d) > %s (%d) : %s vs. %s", - node1->details->id, node1->weight, - node2->details->id, node2->weight, - resource1->id, resource2->id); - return -1; - } - - if(node1->weight < node2->weight) { - crm_debug("%s (%d) < %s (%d) : %s vs. %s", - node1->details->id, node1->weight, - node2->details->id, node2->weight, - resource1->id, resource2->id); - return 1; - } - crm_debug("%s (%d) == %s (%d) : %s vs. %s", - node1->details->id, node1->weight, - node2->details->id, node2->weight, - resource1->id, resource2->id); - - return 0; -} - -/* lowest to highest */ -gint sort_action_id(gconstpointer a, gconstpointer b) -{ - const action_wrapper_t *action_wrapper2 = (const action_wrapper_t*)a; - const action_wrapper_t *action_wrapper1 = (const action_wrapper_t*)b; - - if(a == NULL) { return 1; } - if(b == NULL) { return -1; } - - if(action_wrapper1->action->id > action_wrapper2->action->id) { - return -1; - } - - if(action_wrapper1->action->id < action_wrapper2->action->id) { - return 1; - } - return 0; -} - -gint sort_cons_strength(gconstpointer a, gconstpointer b) -{ - const rsc_colocation_t *rsc_constraint1 = (const rsc_colocation_t*)a; - const rsc_colocation_t *rsc_constraint2 = (const rsc_colocation_t*)b; - - if(a == NULL) { return 1; } - if(b == NULL) { return -1; } - - if(rsc_constraint1->strength > rsc_constraint2->strength) { - return 1; - } - - if(rsc_constraint1->strength < rsc_constraint2->strength) { - return -1; - } - return 0; -} - -gint sort_color_weight(gconstpointer a, gconstpointer b) -{ - const color_t *color1 = (const color_t*)a; - const color_t *color2 = (const color_t*)b; - - if(a == NULL) { return 1; } - if(b == NULL) { return -1; } - - if(color1->local_weight > color2->local_weight) { - return -1; - } - - if(color1->local_weight < color2->local_weight) { - return 1; - } - - return 0; -} - -/* return -1 if 'a' is more preferred - * return 1 if 'b' is more preferred - */ -gint sort_node_weight(gconstpointer a, gconstpointer b) -{ - const node_t *node1 = (const node_t*)a; - const node_t *node2 = (const node_t*)b; - - int node1_weight = 0; - int node2_weight = 0; - - if(a == NULL) { return 1; } - if(b == NULL) { return -1; } - - node1_weight = node1->weight; - node2_weight = node2->weight; - - if(node1->details->unclean - || node1->details->standby - || node1->details->shutdown) { - node1_weight = -INFINITY; - } - if(node2->details->unclean - || node2->details->standby - || node2->details->shutdown) { - node2_weight = -INFINITY; - } - - if(node1_weight > node2_weight) { - crm_debug_3("%s (%d) > %s (%d) : weight", - node1->details->uname, node1_weight, - node2->details->uname, node2_weight); - return -1; - } - - if(node1_weight < node2_weight) { - crm_debug_3("%s (%d) < %s (%d) : weight", - node1->details->uname, node1_weight, - node2->details->uname, node2_weight); - return 1; - } - - crm_debug_3("%s (%d) == %s (%d) : weight", - node1->details->uname, node1_weight, - node2->details->uname, node2_weight); - - /* now try to balance resources across the cluster */ - if(node1->details->num_resources - < node2->details->num_resources) { - crm_debug_3("%s (%d) < %s (%d) : resources", - node1->details->uname, node1->details->num_resources, - node2->details->uname, node2->details->num_resources); - return -1; - - } else if(node1->details->num_resources - > node2->details->num_resources) { - crm_debug_3("%s (%d) > %s (%d) : resources", - node1->details->uname, node1->details->num_resources, - node2->details->uname, node2->details->num_resources); - return 1; - } - - crm_debug_4("%s = %s", node1->details->uname, node2->details->uname); - return 0; -} - -action_t * -custom_action(resource_t *rsc, char *key, const char *task, - node_t *on_node, gboolean optional, gboolean save_action, - pe_working_set_t *data_set) -{ - action_t *action = NULL; - GListPtr possible_matches = NULL; - CRM_CHECK(key != NULL, return NULL); - CRM_CHECK(task != NULL, return NULL); - - if(save_action && rsc != NULL) { - possible_matches = find_actions(rsc->actions, key, on_node); - } - - if(possible_matches != NULL) { - crm_free(key); - - if(g_list_length(possible_matches) > 1) { - pe_warn("Action %s for %s on %s exists %d times", - task, rsc?rsc->id:"", - on_node?on_node->details->uname:"", - g_list_length(possible_matches)); - } - - action = g_list_nth_data(possible_matches, 0); - crm_debug_4("Found existing action (%d) %s for %s on %s", - action->id, task, rsc?rsc->id:"", - on_node?on_node->details->uname:""); - } - - if(action == NULL) { - if(save_action) { - crm_debug_2("Creating%s action %d: %s for %s on %s", - optional?"":" manditory", data_set->action_id, key, rsc?rsc->id:"", - on_node?on_node->details->uname:""); - } - - crm_malloc0(action, sizeof(action_t)); - if(action != NULL) { - if(save_action) { - action->id = data_set->action_id++; - } else { - action->id = 0; - } - action->rsc = rsc; - action->task = task; - action->node = on_node; - - action->actions_before = NULL; - action->actions_after = NULL; - action->failure_is_fatal = TRUE; - - action->pseudo = FALSE; - action->dumped = FALSE; - action->runnable = TRUE; - action->processed = FALSE; - action->optional = optional; - action->seen_count = 0; - - action->extra = g_hash_table_new_full( - g_str_hash, g_str_equal, - g_hash_destroy_str, g_hash_destroy_str); - - action->meta = g_hash_table_new_full( - g_str_hash, g_str_equal, - g_hash_destroy_str, g_hash_destroy_str); - - if(save_action) { - data_set->actions = g_list_append( - data_set->actions, action); - } - - action->uuid = key; - - if(rsc != NULL) { - action->op_entry = find_rsc_op_entry(rsc, key); - - unpack_operation( - action, action->op_entry, data_set); - - if(save_action) { - rsc->actions = g_list_append( - rsc->actions, action); - } - } - if(save_action) { - crm_debug_4("Action %d created", action->id); - } - } - } - - if(optional == FALSE && action->optional) { - crm_debug_2("Action %d (%s) marked manditory", - action->id, action->uuid); - action->optional = FALSE; - } - - if(rsc != NULL) { - enum action_tasks a_task = text2task(action->task); - int warn_level = LOG_DEBUG_3; - if(save_action) { - warn_level = LOG_WARNING; - } - - if(action->node != NULL && action->op_entry != NULL) { - unpack_instance_attributes( - action->op_entry, XML_TAG_ATTR_SETS, - action->node, action->extra, NULL,0, data_set); - } - - if(action->node == NULL) { - action->runnable = FALSE; - - } else if(rsc->is_managed == FALSE) { - crm_log_maybe(warn_level, "Action %s %s is for %s (unmanaged)", - action->uuid, task, rsc->id); - action->optional = TRUE; -/* action->runnable = FALSE; */ - -#if 0 - } else if(action->node->details->unclean) { - crm_log_maybe(warn_level, "Action %s on %s is unrunnable (unclean)", - action->uuid, action->node?action->node->details->uname:""); - - action->runnable = FALSE; -#endif - } else if(action->node->details->online == FALSE) { - action->runnable = FALSE; - crm_log_maybe(warn_level, "Action %s on %s is unrunnable (offline)", - action->uuid, action->node->details->uname); - if(action->rsc->is_managed - && save_action - && a_task == stop_rsc) { - crm_log_maybe(warn_level, "Marking node %s unclean", - action->node->details->uname); - action->node->details->unclean = TRUE; - } - - } else if(action->needs == rsc_req_nothing) { - crm_debug_3("Action %s doesnt require anything", - action->uuid); - action->runnable = TRUE; -#if 0 - /* - * No point checking this - * - if we dont have quorum we cant stonith anyway - */ - } else if(action->needs == rsc_req_stonith) { - crm_debug_3("Action %s requires only stonith", action->uuid); - action->runnable = TRUE; -#endif - } else if(data_set->have_quorum == FALSE - && data_set->no_quorum_policy == no_quorum_stop) { - action->runnable = FALSE; - crm_debug("%s\t%s %s (cancelled : quorum)", - action->node->details->uname, - action->task, rsc->id); - - } else if(data_set->have_quorum == FALSE - && data_set->no_quorum_policy == no_quorum_freeze) { - crm_debug_3("Check resource is already active"); - if(rsc->fns->active(rsc, TRUE) == FALSE) { - action->runnable = FALSE; - crm_debug("%s\t%s %s (cancelled : quorum freeze)", - action->node->details->uname, - action->task, rsc->id); - } - - } else { - crm_debug_3("Action %s is runnable", action->uuid); - action->runnable = TRUE; - } - - if(save_action) { - switch(a_task) { - case stop_rsc: - rsc->stopping = TRUE; - break; - case start_rsc: - rsc->starting = FALSE; - if(action->runnable) { - rsc->starting = TRUE; - } - break; - default: - break; - } - } - } - return action; -} - -void -unpack_operation( - action_t *action, crm_data_t *xml_obj, pe_working_set_t* data_set) -{ - int lpc = 0; - const char *value = NULL; - const char *fields[] = { - XML_LRM_ATTR_INTERVAL, - "timeout", - "start_delay", - }; - - CRM_CHECK(action->rsc != NULL, return); - - if(xml_obj != NULL) { - value = crm_element_value(xml_obj, "prereq"); - } - if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_START)) { - value = g_hash_table_lookup( - action->rsc->meta, "start_prereq"); - } - - if(value == NULL && safe_str_neq(action->task, CRMD_ACTION_START)) { - /* todo: integrate stop as an option? */ - action->needs = rsc_req_nothing; - value = "nothing (default)"; - - } else if(safe_str_eq(value, "nothing")) { - action->needs = rsc_req_nothing; - - } else if(safe_str_eq(value, "quorum")) { - action->needs = rsc_req_quorum; - - } else if(safe_str_eq(value, "fencing")) { - action->needs = rsc_req_stonith; - - } else if(data_set->no_quorum_policy == no_quorum_ignore) { - action->needs = rsc_req_nothing; - value = "nothing (default)"; - - } else if(data_set->no_quorum_policy == no_quorum_freeze - && data_set->stonith_enabled) { - action->needs = rsc_req_stonith; - value = "fencing (default)"; - - } else { - action->needs = rsc_req_quorum; - value = "quorum (default)"; - } - crm_debug_3("\tAction %s requires: %s", action->task, value); - - value = NULL; - if(xml_obj != NULL) { - value = crm_element_value(xml_obj, "on_fail"); - } - if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_STOP)) { - value = g_hash_table_lookup( - action->rsc->meta, "on_stopfail"); - if(value != NULL) { -#if CRM_DEPRECATED_SINCE_2_0_2 - pe_config_err("The \"on_stopfail\" attribute used in" - " %s has been deprecated since 2.0.2", - action->rsc->id); -#else - pe_config_err("The \"on_stopfail\" attribute used in" - " %s has been deprecated since 2.0.2" - " and is now disabled", action->rsc->id); - value = NULL; -#endif - pe_config_err("Please use specify the \"on_fail\"" - " attribute on the \"stop\" operation" - " instead"); - } - } - if(value == NULL) { - - } else if(safe_str_eq(value, "block")) { - action->on_fail = action_fail_block; - - } else if(safe_str_eq(value, "fence")) { - action->on_fail = action_fail_fence; - value = "node fencing"; - - } else if(safe_str_eq(value, "ignore")) { - action->on_fail = action_fail_ignore; - value = "ignore"; - - } else if(safe_str_eq(value, "migrate")) { - action->on_fail = action_fail_migrate; - value = "force migration"; - - } else if(safe_str_eq(value, "stop")) { - action->fail_role = RSC_ROLE_STOPPED; - value = "stop resource"; - - } else if(safe_str_eq(value, "restart") - || safe_str_eq(value, "nothing")) { - action->on_fail = action_fail_recover; - value = "restart (and possibly migrate)"; - - } else { - pe_err("Resource %s: Unknown failure type (%s)", - action->rsc->id, value); - value = NULL; - } - - /* defaults */ - if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_STOP)) { - if(data_set->stonith_enabled) { - action->on_fail = action_fail_fence; - value = "resource fence (default)"; - - } else { - action->on_fail = action_fail_block; - value = "resource block (default)"; - } - - } else if(value == NULL) { - action->on_fail = action_fail_recover; - value = "restart (and possibly migrate) (default)"; - } - - crm_debug_3("\t%s failure handling: %s", action->task, value); - - value = NULL; - if(xml_obj != NULL) { - value = crm_element_value(xml_obj, "role_after_failure"); - } - if(value != NULL && action->fail_role == RSC_ROLE_UNKNOWN) { - action->fail_role = text2role(value); - } - /* defaults */ - if(action->fail_role == RSC_ROLE_UNKNOWN) { - if(safe_str_eq(action->task, CRMD_ACTION_PROMOTE)) { - action->fail_role = RSC_ROLE_SLAVE; - } else { - action->fail_role = RSC_ROLE_STARTED; - } - } - crm_debug_3("\t%s failure results in: %s", - action->task, role2text(action->fail_role)); - - if(xml_obj == NULL) { - return; - } - - xml_prop_iter(xml_obj, p_name, p_value, - if(p_value != NULL) { - g_hash_table_insert(action->meta, crm_strdup(p_name), - crm_strdup(p_value)); - } - ); - - unpack_instance_attributes(xml_obj, XML_TAG_META_SETS, - NULL, action->meta, NULL,0, data_set); - - unpack_instance_attributes(xml_obj, XML_TAG_ATTR_SETS, - NULL, action->meta, NULL,0, data_set); - - if(g_hash_table_lookup(action->meta, "timeout") == NULL) { - g_hash_table_insert(action->meta, crm_strdup("timeout"), - crm_strdup(data_set->transition_idle_timeout)); - } - - for(;lpc < DIMOF(fields); lpc++) { - value = g_hash_table_lookup(action->meta, fields[lpc]); - if(value != NULL) { - char *tmp_ms = NULL; - int tmp_i = crm_get_msec(value); - if(tmp_i < 0) { - tmp_i = 0; - } - tmp_ms = crm_itoa(tmp_i); - g_hash_table_replace( - action->meta, crm_strdup(fields[lpc]), tmp_ms); - } - } - -/* if(safe_str_eq(native_data->agent->class, "stonith")) { */ -/* if(rsc->start_needs == rsc_req_stonith) { */ -/* pe_err("Stonith resources (eg. %s) cannot require" */ -/* " fencing to start", rsc->id); */ -/* } */ -/* rsc->start_needs = rsc_req_quorum; */ -/* } */ - -} - -crm_data_t * -find_rsc_op_entry(resource_t *rsc, const char *key) -{ - const char *name = NULL; - const char *value = NULL; - const char *interval = NULL; - char *match_key = NULL; - crm_data_t *op = NULL; - - xml_child_iter_filter( - rsc->ops_xml, operation, "op", - - name = crm_element_value(operation, "name"); - interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL); - value = crm_element_value(operation, "disabled"); - if(crm_is_true(value)) { - crm_debug_2("%s disabled", ID(operation)); - continue; - } - - match_key = generate_op_key( - rsc->id, name, crm_get_msec(interval)); - - if(safe_str_eq(key, match_key)) { - op = operation; - } - crm_free(match_key); - - if(op != NULL) { - return op; - } - ); - crm_debug_3("No match for %s", key); - return op; -} - - -const char * -fail2text(enum action_fail_response fail) -{ - const char *result = ""; - switch(fail) - { - case action_fail_ignore: - result = "ignore"; - break; - case action_fail_block: - result = "block"; - break; - case action_fail_recover: - result = "recover"; - break; - case action_fail_migrate: - result = "migrate"; - break; - case action_fail_fence: - result = "fence"; - break; - } - return result; -} - - -const char * -strength2text(enum con_strength strength) -{ - const char *result = ""; - switch(strength) - { - case pecs_ignore: - result = "ignore"; - break; - case pecs_must: - result = XML_STRENGTH_VAL_MUST; - break; - case pecs_must_not: - result = XML_STRENGTH_VAL_MUSTNOT; - break; - case pecs_startstop: - result = "start/stop"; - break; - } - return result; -} - -const char * -ordering_type2text(enum pe_ordering type) -{ - const char *result = ""; - switch(type) - { - case pe_ordering_manditory: - result = "manditory"; - break; - case pe_ordering_restart: - result = "restart"; - break; - case pe_ordering_recover: - result = "recover"; - break; - case pe_ordering_optional: - result = "optional"; - break; - case pe_ordering_postnotify: - result = "post_notify"; - break; - } - return result; -} - -enum action_tasks -text2task(const char *task) -{ - if(safe_str_eq(task, CRMD_ACTION_STOP)) { - return stop_rsc; - } else if(safe_str_eq(task, CRMD_ACTION_STOPPED)) { - return stopped_rsc; - } else if(safe_str_eq(task, CRMD_ACTION_START)) { - return start_rsc; - } else if(safe_str_eq(task, CRMD_ACTION_STARTED)) { - return started_rsc; - } else if(safe_str_eq(task, CRM_OP_SHUTDOWN)) { - return shutdown_crm; - } else if(safe_str_eq(task, CRM_OP_FENCE)) { - return stonith_node; - } else if(safe_str_eq(task, CRMD_ACTION_MON)) { - return monitor_rsc; - } else if(safe_str_eq(task, CRMD_ACTION_NOTIFY)) { - return action_notify; - } else if(safe_str_eq(task, CRMD_ACTION_NOTIFIED)) { - return action_notified; - } else if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) { - return action_promote; - } else if(safe_str_eq(task, CRMD_ACTION_DEMOTE)) { - return action_demote; - } else if(safe_str_eq(task, CRMD_ACTION_PROMOTED)) { - return action_promoted; - } else if(safe_str_eq(task, CRMD_ACTION_DEMOTED)) { - return action_demoted; - } else if(safe_str_eq(task, CRMD_ACTION_CANCEL)) { - return no_action; - } else if(safe_str_eq(task, CRMD_ACTION_DELETE)) { - return no_action; - } else if(safe_str_eq(task, CRMD_ACTION_STATUS)) { - return no_action; - } else if(safe_str_eq(task, CRM_OP_PROBED)) { - return no_action; - } else if(safe_str_eq(task, CRM_OP_LRM_REFRESH)) { - return no_action; - } - pe_err("Unsupported action: %s", task); - return no_action; -} - - -const char * -task2text(enum action_tasks task) -{ - const char *result = ""; - switch(task) - { - case no_action: - result = "no_action"; - break; - case stop_rsc: - result = CRMD_ACTION_STOP; - break; - case stopped_rsc: - result = CRMD_ACTION_STOPPED; - break; - case start_rsc: - result = CRMD_ACTION_START; - break; - case started_rsc: - result = CRMD_ACTION_STARTED; - break; - case shutdown_crm: - result = CRM_OP_SHUTDOWN; - break; - case stonith_node: - result = CRM_OP_FENCE; - break; - case monitor_rsc: - result = CRMD_ACTION_MON; - break; - case action_notify: - result = CRMD_ACTION_NOTIFY; - break; - case action_notified: - result = CRMD_ACTION_NOTIFIED; - break; - case action_promote: - result = CRMD_ACTION_PROMOTE; - break; - case action_promoted: - result = CRMD_ACTION_PROMOTED; - break; - case action_demote: - result = CRMD_ACTION_DEMOTE; - break; - case action_demoted: - result = CRMD_ACTION_DEMOTED; - break; - } - - return result; -} - -const char * -role2text(enum rsc_role_e role) -{ - CRM_CHECK(role >= RSC_ROLE_UNKNOWN, return RSC_ROLE_UNKNOWN_S); - CRM_CHECK(role < RSC_ROLE_MAX, return RSC_ROLE_UNKNOWN_S); - switch(role) { - case RSC_ROLE_UNKNOWN: - return RSC_ROLE_UNKNOWN_S; - case RSC_ROLE_STOPPED: - return RSC_ROLE_STOPPED_S; - case RSC_ROLE_STARTED: - return RSC_ROLE_STARTED_S; - case RSC_ROLE_SLAVE: - return RSC_ROLE_SLAVE_S; - case RSC_ROLE_MASTER: - return RSC_ROLE_MASTER_S; - } - return RSC_ROLE_UNKNOWN_S; -} - -enum rsc_role_e -text2role(const char *role) -{ - if(safe_str_eq(role, RSC_ROLE_STOPPED_S)) { - return RSC_ROLE_STOPPED; - } else if(safe_str_eq(role, RSC_ROLE_STARTED_S)) { - return RSC_ROLE_STARTED; - } else if(safe_str_eq(role, RSC_ROLE_SLAVE_S)) { - return RSC_ROLE_SLAVE; - } else if(safe_str_eq(role, RSC_ROLE_MASTER_S)) { - return RSC_ROLE_MASTER; - } else if(safe_str_eq(role, RSC_ROLE_UNKNOWN_S)) { - return RSC_ROLE_UNKNOWN; - } else if(safe_str_eq(role, "default")) { - return RSC_ROLE_UNKNOWN; - } - crm_err("Unknown role: %s", role); - return RSC_ROLE_UNKNOWN; -} - - -void -print_node(const char *pre_text, node_t *node, gboolean details) -{ - if(node == NULL) { - crm_debug_4("%s%s: ", - pre_text==NULL?"":pre_text, - pre_text==NULL?"":": "); - return; - } - - crm_debug_4("%s%s%sNode %s: (weight=%d, fixed=%s)", - pre_text==NULL?"":pre_text, - pre_text==NULL?"":": ", - node->details==NULL?"error ":node->details->online?"":"Unavailable/Unclean ", - node->details->uname, - node->weight, - node->fixed?"True":"False"); - - if(details && node != NULL && node->details != NULL) { - char *pe_mutable = crm_strdup("\t\t"); - crm_debug_4("\t\t===Node Attributes"); - g_hash_table_foreach(node->details->attrs, - print_str_str, pe_mutable); - crm_free(pe_mutable); - - crm_debug_4("\t\t=== Resources"); - slist_iter( - rsc, resource_t, node->details->running_rsc, lpc, - print_resource(LOG_DEBUG_4, "\t\t", rsc, FALSE); - ); - } -} - -/* - * Used by the HashTable for-loop - */ -void print_str_str(gpointer key, gpointer value, gpointer user_data) -{ - crm_debug_4("%s%s %s ==> %s", - user_data==NULL?"":(char*)user_data, - user_data==NULL?"":": ", - (char*)key, - (char*)value); -} - -void -print_color_details(const char *pre_text, - struct color_shared_s *color, - gboolean details) -{ - if(color == NULL) { - crm_debug_4("%s%s: ", - pre_text==NULL?"":pre_text, - pre_text==NULL?"":": "); - return; - } - crm_debug_4("%s%sColor %d: node=%s (from %d candidates)", - pre_text==NULL?"":pre_text, - pre_text==NULL?"":": ", - color->id, - color->chosen_node==NULL?"":color->chosen_node->details->uname, - g_list_length(color->candidate_nodes)); - if(details) { - slist_iter(node, node_t, color->candidate_nodes, lpc, - print_node("\t", node, FALSE)); - } -} - -void -print_color(const char *pre_text, color_t *color, gboolean details) -{ - if(color == NULL) { - crm_debug_4("%s%s: ", - pre_text==NULL?"":pre_text, - pre_text==NULL?"":": "); - return; - } - crm_debug_4("%s%sColor %d: (weight=%d, node=%s, possible=%d)", - pre_text==NULL?"":pre_text, - pre_text==NULL?"":": ", - color->id, - color->local_weight, - safe_val5("",color,details,chosen_node,details,uname), - g_list_length(color->details->candidate_nodes)); - if(details) { - print_color_details("\t", color->details, details); - } -} - -void -print_rsc_to_node(const char *pre_text, rsc_to_node_t *cons, gboolean details) -{ - if(cons == NULL) { - crm_debug_4("%s%s: ", - pre_text==NULL?"":pre_text, - pre_text==NULL?"":": "); - return; - } - crm_debug_4("%s%s%s Constraint %s (%p) - %d nodes:", - pre_text==NULL?"":pre_text, - pre_text==NULL?"":": ", - "rsc_to_node", - cons->id, cons, - g_list_length(cons->node_list_rh)); - - if(details == FALSE) { - crm_debug_4("\t%s (node placement rule)", - safe_val3(NULL, cons, rsc_lh, id)); - - slist_iter( - node, node_t, cons->node_list_rh, lpc, - print_node("\t\t-->", node, FALSE) - ); - } -} - -void -print_rsc_colocation(const char *pre_text, rsc_colocation_t *cons, gboolean details) -{ - if(cons == NULL) { - crm_debug_4("%s%s: ", - pre_text==NULL?"":pre_text, - pre_text==NULL?"":": "); - return; - } - crm_debug_4("%s%s%s Constraint %s (%p):", - pre_text==NULL?"":pre_text, - pre_text==NULL?"":": ", - XML_CONS_TAG_RSC_DEPEND, cons->id, cons); - - if(details == FALSE) { - - crm_debug_4("\t%s --> %s, %s", - safe_val3(NULL, cons, rsc_lh, id), - safe_val3(NULL, cons, rsc_rh, id), - strength2text(cons->strength)); - } -} - -void -print_resource( - int log_level, const char *pre_text, resource_t *rsc, gboolean details) -{ - long options = pe_print_log; - - if(rsc == NULL) { - crm_log_maybe(log_level-1, "%s%s: ", - pre_text==NULL?"":pre_text, - pre_text==NULL?"":": "); - return; - } - if(details) { - options |= pe_print_details; - } - rsc->fns->print(rsc, pre_text, options, &log_level); -} - -void -log_action(unsigned int log_level, const char *pre_text, action_t *action, gboolean details) -{ - const char *node_uname = NULL; - const char *node_uuid = NULL; - - if(action == NULL) { - - crm_log_maybe(log_level, "%s%s: ", - pre_text==NULL?"":pre_text, - pre_text==NULL?"":": "); - return; - } - - - if(action->pseudo) { - node_uname = NULL; - node_uuid = NULL; - - } else if(action->node != NULL) { - node_uname = action->node->details->uname; - node_uuid = action->node->details->id; - } else { - node_uname = ""; - node_uuid = NULL; - } - - switch(text2task(action->task)) { - case stonith_node: - case shutdown_crm: - crm_log_maybe(log_level, - "%s%s%sAction %d: %s%s%s%s%s%s", - pre_text==NULL?"":pre_text, - pre_text==NULL?"":": ", - action->pseudo?"Pseduo ":action->optional?"Optional ":action->runnable?action->processed?"":"(Provisional) ":"!!Non-Startable!! ", - action->id, action->uuid, - node_uname?"\ton ":"", - node_uname?node_uname:"", - node_uuid?"\t\t(":"", - node_uuid?node_uuid:"", - node_uuid?")":""); - break; - default: - crm_log_maybe(log_level, - "%s%s%sAction %d: %s %s%s%s%s%s%s", - pre_text==NULL?"":pre_text, - pre_text==NULL?"":": ", - action->optional?"Optional ":action->pseudo?"Pseduo ":action->runnable?action->processed?"":"(Provisional) ":"!!Non-Startable!! ", - action->id, action->uuid, - safe_val3("", action, rsc, id), - node_uname?"\ton ":"", - node_uname?node_uname:"", - node_uuid?"\t\t(":"", - node_uuid?node_uuid:"", - node_uuid?")":""); - - break; - } - - if(details) { - crm_log_maybe(log_level+1, "\t\t====== Preceeding Actions"); - slist_iter( - other, action_wrapper_t, action->actions_before, lpc, - log_action(log_level+1, "\t\t", other->action, FALSE); - ); -#if 1 - crm_log_maybe(log_level+1, "\t\t====== Subsequent Actions"); - slist_iter( - other, action_wrapper_t, action->actions_after, lpc, - log_action(log_level+1, "\t\t", other->action, FALSE); - ); -#endif - crm_log_maybe(log_level+1, "\t\t====== End"); - - } else { - crm_log_maybe(log_level, "\t\t(seen=%d, before=%d, after=%d)", - action->seen_count, - g_list_length(action->actions_before), - g_list_length(action->actions_after)); - } -} - - -void -pe_free_nodes(GListPtr nodes) -{ - GListPtr iterator = nodes; - while(iterator != NULL) { - node_t *node = (node_t*)iterator->data; - struct node_shared_s *details = node->details; - iterator = iterator->next; - - crm_debug_5("deleting node"); - crm_debug_5("%s is being deleted", details->uname); - print_node("delete", node, FALSE); - - if(details != NULL) { - if(details->attrs != NULL) { - g_hash_table_destroy(details->attrs); - } - pe_free_shallow_adv(details->running_rsc, FALSE); - crm_free(details); - } - crm_free(node); - } - if(nodes != NULL) { - g_list_free(nodes); - } -} - -void -pe_free_colors(GListPtr colors) -{ - GListPtr iterator = colors; - while(iterator != NULL) { - color_t *color = (color_t *)iterator->data; - struct color_shared_s *details = color->details; - iterator = iterator->next; - - if(details != NULL) { - pe_free_shallow(details->candidate_nodes); - pe_free_shallow_adv(details->allocated_resources, FALSE); - crm_free(details->chosen_node); - crm_free(details); - } - crm_free(color); - } - if(colors != NULL) { - g_list_free(colors); - } -} - -void -pe_free_shallow(GListPtr alist) -{ - pe_free_shallow_adv(alist, TRUE); -} - -void -pe_free_shallow_adv(GListPtr alist, gboolean with_data) -{ - GListPtr item; - GListPtr item_next = alist; - while(item_next != NULL) { - item = item_next; - item_next = item_next->next; - - if(with_data) { -/* crm_debug_5("freeing %p", item->data); */ - crm_free(item->data); - } - - item->data = NULL; - item->next = NULL; - g_list_free(item); - } -} - -void -pe_free_resources(GListPtr resources) -{ - resource_t *rsc = NULL; - GListPtr iterator = resources; - while(iterator != NULL) { - iterator = iterator; - rsc = (resource_t *)iterator->data; - iterator = iterator->next; - rsc->fns->free(rsc); - } - if(resources != NULL) { - g_list_free(resources); - } -} - -void -pe_free_action(action_t *action) -{ - if(action == NULL) { - return; - } - pe_free_shallow(action->actions_before);/* action_warpper_t* */ - pe_free_shallow(action->actions_after); /* action_warpper_t* */ - g_hash_table_destroy(action->extra); - g_hash_table_destroy(action->meta); - crm_free(action->uuid); - crm_free(action); -} - -void -pe_free_actions(GListPtr actions) -{ - GListPtr iterator = actions; - while(iterator != NULL) { - pe_free_action(iterator->data); - iterator = iterator->next; - } - if(actions != NULL) { - g_list_free(actions); - } -} - -void -pe_free_ordering(GListPtr constraints) -{ - GListPtr iterator = constraints; - while(iterator != NULL) { - order_constraint_t *order = iterator->data; - iterator = iterator->next; - - crm_free(order->lh_action_task); - crm_free(order->rh_action_task); - crm_free(order); - } - if(constraints != NULL) { - g_list_free(constraints); - } -} - - -void -pe_free_rsc_colocation(rsc_colocation_t *cons) -{ - if(cons != NULL) { - crm_debug_4("Freeing constraint %s (%p)", cons->id, cons); - crm_free(cons); - } -} - -void -pe_free_rsc_to_node(rsc_to_node_t *cons) -{ - if(cons != NULL) { - pe_free_shallow(cons->node_list_rh); - crm_free(cons); - } -} - -GListPtr -find_recurring_actions(GListPtr input, node_t *not_on_node) -{ - const char *value = NULL; - GListPtr result = NULL; - CRM_CHECK(input != NULL, return NULL); - - slist_iter( - action, action_t, input, lpc, - value = g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL); - if(value == NULL) { - /* skip */ - } else if(safe_str_eq(CRMD_ACTION_CANCEL, action->task)) { - /* skip */ - } else if(not_on_node == NULL) { - crm_debug_5("(null) Found: %s", action->uuid); - result = g_list_append(result, action); - - } else if(action->node == NULL) { - /* skip */ - } else if(action->node->details != not_on_node->details) { - crm_debug_5("Found: %s", action->uuid); - result = g_list_append(result, action); - } - ); - - return result; -} - -GListPtr -find_actions(GListPtr input, const char *key, node_t *on_node) -{ - GListPtr result = NULL; - CRM_CHECK(key != NULL, return NULL); - - slist_iter( - action, action_t, input, lpc, - crm_debug_5("Matching %s against %s", key, action->uuid); - if(safe_str_neq(key, action->uuid)) { - continue; - - } else if(on_node == NULL) { - result = g_list_append(result, action); - - } else if(action->node == NULL) { - /* skip */ - crm_debug_2("While looking for %s action on %s, " - "found an unallocated one. Assigning" - " it to the requested node...", - key, on_node->details->uname); - - action->node = on_node; - result = g_list_append(result, action); - - } else if(safe_str_eq(on_node->details->id, - action->node->details->id)) { - result = g_list_append(result, action); - } - ); - - return result; -} - - -GListPtr -find_actions_exact(GListPtr input, const char *key, node_t *on_node) -{ - GListPtr result = NULL; - CRM_CHECK(key != NULL, return NULL); - - slist_iter( - action, action_t, input, lpc, - crm_debug_5("Matching %s against %s", key, action->uuid); - if(safe_str_neq(key, action->uuid)) { - crm_debug_3("Key mismatch: %s vs. %s", - key, action->uuid); - continue; - - } else if(on_node == NULL || action->node == NULL) { - crm_debug_3("on_node=%p, action->node=%p", - on_node, action->node); - continue; - - } else if(safe_str_eq(on_node->details->id, - action->node->details->id)) { - result = g_list_append(result, action); - } - crm_debug_2("Node mismatch: %s vs. %s", - on_node->details->id, action->node->details->id); - ); - - return result; -} - -void -set_id(crm_data_t * xml_obj, const char *prefix, int child) -{ - int id_len = 0; - gboolean use_prefix = TRUE; - gboolean use_child = TRUE; - - char *new_id = NULL; - const char *id = crm_element_value(xml_obj, XML_ATTR_ID); - - id_len = 1 + strlen(id); - - if(child > 999) { - pe_err("Are you insane?!?" - " The CRM does not support > 1000 children per resource"); - return; - - } else if(child < 0) { - use_child = FALSE; - - } else { - id_len += 4; /* child */ - } - - if(prefix == NULL || safe_str_eq(id, prefix)) { - use_prefix = FALSE; - } else { - id_len += (1 + strlen(prefix)); - } - - crm_malloc0(new_id, id_len); - - if(use_child) { - snprintf(new_id, id_len, "%s%s%s:%d", - use_prefix?prefix:"", use_prefix?":":"", id, child); - } else { - snprintf(new_id, id_len, "%s%s%s", - use_prefix?prefix:"", use_prefix?":":"", id); - } - - crm_xml_add(xml_obj, XML_ATTR_ID, new_id); - crm_free(new_id); -} - -int -merge_weights(int w1, int w2) -{ - int result = w1 + w2; - - if(w1 <= -INFINITY || w2 <= -INFINITY) { - if(w1 >= INFINITY || w2 >= INFINITY) { - crm_debug_2("-INFINITY + INFINITY == -INFINITY"); - } - return -INFINITY; - - } else if(w1 >= INFINITY || w2 >= INFINITY) { - return INFINITY; - } - - /* detect wrap-around */ - if(result > 0) { - if(w1 <= 0 && w2 < 0) { - result = -INFINITY; - } - - } else if(w1 > 0 && w2 > 0) { - result = INFINITY; - } - - /* detect +/- INFINITY */ - if(result >= INFINITY) { - result = INFINITY; - - } else if(result <= -INFINITY) { - result = -INFINITY; - } - - crm_debug_5("%d + %d = %d", w1, w2, result); - return result; -} - - -int -char2score(const char *score) -{ - int score_f = 0; - - if(score == NULL) { - - } else if(safe_str_eq(score, MINUS_INFINITY_S)) { - score_f = -INFINITY; - - } else if(safe_str_eq(score, INFINITY_S)) { - score_f = INFINITY; - - } else if(safe_str_eq(score, "+"INFINITY_S)) { - score_f = INFINITY; - - } else { - score_f = crm_parse_int(score, NULL); - if(score_f > 0 && score_f > INFINITY) { - score_f = INFINITY; - - } else if(score_f < 0 && score_f < -INFINITY) { - score_f = -INFINITY; - } - } - - return score_f; -} - - -char * -score2char(int score) -{ - - if(score >= INFINITY) { - return crm_strdup("+"INFINITY_S); - - } else if(score <= -INFINITY) { - return crm_strdup("-"INFINITY_S); - } - return crm_itoa(score); -} - -rsc_to_node_t * -rsc2node_new(const char *id, resource_t *rsc, - int node_weight, node_t *foo_node, pe_working_set_t *data_set) -{ - rsc_to_node_t *new_con = NULL; - - if(rsc == NULL || id == NULL) { - pe_err("Invalid constraint %s for rsc=%p", crm_str(id), rsc); - return NULL; - } - - crm_malloc0(new_con, sizeof(rsc_to_node_t)); - if(new_con != NULL) { - new_con->id = id; - new_con->rsc_lh = rsc; - new_con->node_list_rh = NULL; - new_con->role_filter = RSC_ROLE_UNKNOWN; - - if(foo_node != NULL) { - node_t *copy = node_copy(foo_node); - copy->weight = node_weight; - new_con->node_list_rh = g_list_append(NULL, copy); - } else { - CRM_CHECK(node_weight == 0, return NULL); - } - - data_set->placement_constraints = g_list_append( - data_set->placement_constraints, new_con); - rsc->rsc_location = g_list_append( - rsc->rsc_location, new_con); - } - - return new_con; -} diff --git a/include/crm/Makefile.am b/include/crm/Makefile.am index d81e1868da..78e214c929 100644 --- a/include/crm/Makefile.am +++ b/include/crm/Makefile.am @@ -1,24 +1,24 @@ # # 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 includedir=$(base_includedir)/heartbeat include_HEADERS = crm.h cib.h msg_xml.h transition.h -SUBDIRS = common +SUBDIRS = common pengine diff --git a/lib/crm/Makefile.am b/include/crm/pengine/Makefile.am similarity index 86% copy from lib/crm/Makefile.am copy to include/crm/pengine/Makefile.am index b30f6e9e0a..d8d8347266 100644 --- a/lib/crm/Makefile.am +++ b/include/crm/pengine/Makefile.am @@ -1,22 +1,25 @@ # # 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 -## Subdirectories... -SUBDIRS = common cib transition -DIST_SUBDIRS = common cib transition +includedir=$(base_includedir)/heartbeat + +include_HEADERS = common.h complex.h rules.h status.h + +clean-generic: + rm -f *~ diff --git a/lib/crm/pengine/common.h b/include/crm/pengine/common.h similarity index 98% rename from lib/crm/pengine/common.h rename to include/crm/pengine/common.h index 22e54bb338..2e907785be 100644 --- a/lib/crm/pengine/common.h +++ b/include/crm/pengine/common.h @@ -1,150 +1,150 @@ -/* $Id: common.h,v 1.1 2006/05/31 14:59:12 andrew Exp $ */ +/* $Id: common.h,v 1.1 2006/06/07 12:46:55 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 */ #ifndef PE_COMMON__H #define PE_COMMON__H /* * The man pages for both curses and ncurses suggest inclusion of "curses.h". * We believe the following to be acceptable and portable. */ #if defined(HAVE_LIBNCURSES) || defined(HAVE_LIBCURSES) #if defined(HAVE_NCURSES_H) && !defined(HAVE_INCOMPATIBLE_PRINTW) # include # define CURSES_ENABLED 1 #elif defined(HAVE_NCURSES_NCURSES_H) && !defined(HAVE_INCOMPATIBLE_PRINTW) # include # define CURSES_ENABLED 1 #elif defined(HAVE_CURSES_H) && !defined(HAVE_INCOMPATIBLE_PRINTW) # include # define CURSES_ENABLED 1 #elif defined(HAVE_CURSES_CURSES_H) && !defined(HAVE_INCOMPATIBLE_PRINTW) # include # define CURSES_ENABLED 1 #else # define CURSES_ENABLED 0 #endif #else # define CURSES_ENABLED 0 #endif extern gboolean was_processing_error; extern gboolean was_processing_warning; extern gboolean was_config_error; extern gboolean was_config_warning; extern unsigned int pengine_input_loglevel; /* order is significant here * items listed in order of accending severeness * more severe actions take precedent over lower ones */ enum action_fail_response { action_fail_ignore, action_fail_recover, action_fail_migrate, action_fail_block, /* action_fail_stop, */ action_fail_fence }; enum action_tasks { no_action, monitor_rsc, stop_rsc, stopped_rsc, start_rsc, started_rsc, action_notify, action_notified, action_promote, action_promoted, action_demote, action_demoted, shutdown_crm, stonith_node }; enum rsc_recovery_type { recovery_stop_start, recovery_stop_only, recovery_block }; enum rsc_start_requirement { rsc_req_nothing, rsc_req_quorum, rsc_req_stonith }; enum rsc_role_e { RSC_ROLE_UNKNOWN, RSC_ROLE_STOPPED, RSC_ROLE_STARTED, RSC_ROLE_SLAVE, RSC_ROLE_MASTER, }; #define RSC_ROLE_MAX RSC_ROLE_MASTER+1 #define RSC_ROLE_UNKNOWN_S "Unknown" #define RSC_ROLE_STOPPED_S "Stopped" #define RSC_ROLE_STARTED_S "Started" #define RSC_ROLE_SLAVE_S "Slave" #define RSC_ROLE_MASTER_S "Master" enum pe_print_options { pe_print_log = 0x0001, pe_print_html = 0x0002, pe_print_ncurses = 0x0004, pe_print_printf = 0x0008, pe_print_dev = 0x0010, pe_print_details = 0x0020, pe_print_max_details = 0x0040, pe_print_rsconly = 0x0080, }; extern int merge_weights(int w1, int w2); extern const char *task2text(enum action_tasks task); extern enum action_tasks text2task(const char *task); extern enum rsc_role_e text2role(const char *role); extern const char *role2text(enum rsc_role_e role); extern const char *fail2text(enum action_fail_response fail); extern int char2score(const char *score); extern char *score2char(int score); extern void add_hash_param(GHashTable *hash, const char *name, const char *value); /* Helper macros to avoid NULL pointers */ #define safe_val3(def, t,u,v) (t?t->u?t->u->v:def:def) #define safe_val5(def, t,u,v,w,x) (t?t->u?t->u->v?t->u->v->w?t->u->v->w->x:def:def:def:def) #define pe_err(fmt...) { was_processing_error = TRUE; was_config_error = TRUE; crm_err(fmt); } #define pe_warn(fmt...) { was_processing_warning = TRUE; was_config_warning = TRUE; crm_warn(fmt); } #define pe_proc_err(fmt...) { was_processing_error = TRUE; crm_err(fmt); } #define pe_proc_warn(fmt...) { was_processing_warning = TRUE; crm_warn(fmt); } #define pe_config_err(fmt...) { was_config_error = TRUE; crm_err(fmt); } #define pe_config_warn(fmt...) { was_config_warning = TRUE; crm_warn(fmt); } #endif diff --git a/lib/crm/pengine/complex.h b/include/crm/pengine/complex.h similarity index 98% rename from lib/crm/pengine/complex.h rename to include/crm/pengine/complex.h index 14105bfa14..a5abb28e10 100644 --- a/lib/crm/pengine/complex.h +++ b/include/crm/pengine/complex.h @@ -1,136 +1,136 @@ -/* $Id: complex.h,v 1.1 2006/05/31 15:00:38 andrew Exp $ */ +/* $Id: complex.h,v 1.1 2006/06/07 12:46:55 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 */ #ifndef PENGINE_COMPLEX__H #define PENGINE_COMPLEX__H #define n_object_classes 3 /*#define PE_OBJ_F_ ""*/ #define PE_OBJ_T_NATIVE "native" #define PE_OBJ_T_GROUP "group" #define PE_OBJ_T_INCARNATION "clone" #define PE_OBJ_T_MASTER "master" enum pe_obj_types { pe_unknown = -1, pe_native = 0, pe_group = 1, pe_clone = 2, pe_master = 3 }; extern int get_resource_type(const char *name); typedef struct resource_object_functions_s { gboolean (*unpack)(resource_t *, pe_working_set_t *); resource_t *(*find_child)(resource_t *, const char *); GListPtr (*children)(resource_t *); /* parameter result must be free'd */ char *(*parameter)( resource_t *, node_t *, gboolean, const char *, pe_working_set_t *); void (*print)(resource_t *, const char *, long, void *); gboolean (*active)(resource_t *,gboolean); enum rsc_role_e (*state)(resource_t *); void (*free)(resource_t *); } resource_object_functions_t; extern char *native_parameter( resource_t *rsc, node_t *node, gboolean create, const char *name, pe_working_set_t *data_set); extern gboolean native_unpack(resource_t *rsc, pe_working_set_t *data_set); extern gboolean group_unpack(resource_t *rsc, pe_working_set_t *data_set); extern gboolean clone_unpack(resource_t *rsc, pe_working_set_t *data_set); extern gboolean master_unpack(resource_t *rsc, pe_working_set_t *data_set); extern GListPtr native_children(resource_t *rsc); extern GListPtr group_children(resource_t *rsc); extern GListPtr clone_children(resource_t *rsc); extern GListPtr master_children(resource_t *rsc); extern resource_t *native_find_child(resource_t *rsc, const char *id); extern resource_t *group_find_child(resource_t *rsc, const char *id); extern resource_t *clone_find_child(resource_t *rsc, const char *id); extern resource_t *master_find_child(resource_t *rsc, const char *id); extern gboolean native_active(resource_t *rsc, gboolean all); extern gboolean group_active(resource_t *rsc, gboolean all); extern gboolean clone_active(resource_t *rsc, gboolean all); extern gboolean master_active(resource_t *rsc, gboolean all); extern void native_print( resource_t *rsc, const char *pre_text, long options, void *print_data); extern void group_print( resource_t *rsc, const char *pre_text, long options, void *print_data); extern void clone_print( resource_t *rsc, const char *pre_text, long options, void *print_data); extern void master_print( resource_t *rsc, const char *pre_text, long options, void *print_data); extern void native_free(resource_t *rsc); extern void group_free(resource_t *rsc); extern void clone_free(resource_t *rsc); extern void master_free(resource_t *rsc); extern enum rsc_role_e native_resource_state(resource_t *rsc); extern enum rsc_role_e group_resource_state(resource_t *rsc); extern enum rsc_role_e clone_resource_state(resource_t *rsc); extern enum rsc_role_e master_resource_state(resource_t *rsc); extern resource_object_functions_t resource_class_functions[]; extern gboolean common_unpack(crm_data_t * xml_obj, resource_t **rsc, resource_t *parent, pe_working_set_t *data_set); extern void common_print(resource_t *rsc, const char *pre_text, long options, void *print_data); extern void common_free(resource_t *rsc); extern void native_add_running( resource_t *rsc, node_t *node, pe_working_set_t *data_set); #if CURSES_ENABLED # define status_printw(fmt...) printw(fmt) #else # define status_printw(fmt...) \ crm_err("printw support requires ncurses to be available during configure"); \ do_crm_log(LOG_WARNING, NULL, NULL, fmt); #endif #define status_print(fmt...) \ if(options & pe_print_html) { \ FILE *stream = print_data; \ fprintf(stream, fmt); \ } else if(options & pe_print_ncurses) { \ status_printw(fmt); \ } else if(options & pe_print_printf) { \ FILE *stream = print_data; \ fprintf(stream, fmt); \ } else if(options & pe_print_log) { \ int log_level = *(int*)print_data; \ do_crm_log(log_level, NULL, NULL, fmt); \ } typedef struct resource_alloc_functions_s resource_alloc_functions_t; #endif diff --git a/lib/crm/pengine/rules.h b/include/crm/pengine/rules.h similarity index 94% rename from lib/crm/pengine/rules.h rename to include/crm/pengine/rules.h index bd717d5e8e..9e3e0690c6 100644 --- a/lib/crm/pengine/rules.h +++ b/include/crm/pengine/rules.h @@ -1,50 +1,50 @@ -/* $Id: rules.h,v 1.1 2006/05/31 14:59:12 andrew Exp $ */ +/* $Id: rules.h,v 1.1 2006/06/07 12:46:55 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 */ #ifndef PENGINE_RULES__H #define PENGINE_RULES__H #include #include -#include +#include enum expression_type { not_expr, nested_rule, attr_expr, loc_expr, role_expr, time_expr }; extern enum expression_type find_expression_type(crm_data_t *expr); extern gboolean test_ruleset( crm_data_t *ruleset, GHashTable *node_hash, ha_time_t *now); extern gboolean test_rule(crm_data_t *rule, GHashTable *node_hash, enum rsc_role_e role, ha_time_t *now); extern gboolean test_expression(crm_data_t *expr, GHashTable *node_hash, enum rsc_role_e role, ha_time_t *now); extern void unpack_instance_attributes( crm_data_t *xml_obj, const char *set_name, GHashTable *node_hash, GHashTable *hash, const char *always_first, ha_time_t *now); #endif diff --git a/lib/crm/pengine/status.h b/include/crm/pengine/status.h similarity index 96% rename from lib/crm/pengine/status.h rename to include/crm/pengine/status.h index 3ac447b309..0d8bed7ddc 100644 --- a/lib/crm/pengine/status.h +++ b/include/crm/pengine/status.h @@ -1,175 +1,175 @@ -/* $Id: status.h,v 1.1 2006/05/31 14:59:12 andrew Exp $ */ +/* $Id: status.h,v 1.1 2006/06/07 12:46:55 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 */ #ifndef PENGINE_STATUS__H #define PENGINE_STATUS__H #include #include -#include +#include typedef struct node_s node_t; typedef struct color_s color_t; typedef struct resource_s resource_t; typedef enum no_quorum_policy_e { no_quorum_freeze, no_quorum_stop, no_quorum_ignore } no_quorum_policy_t; enum node_type { node_ping, node_member }; enum pe_restart { pe_restart_restart, pe_restart_ignore }; typedef struct pe_working_set_s { crm_data_t *input; ha_time_t *now; /* options extracted from the input */ char *transition_idle_timeout; char *dc_uuid; node_t *dc_node; gboolean have_quorum; gboolean stonith_enabled; const char *stonith_action; gboolean symmetric_cluster; gboolean is_managed_default; gboolean remove_after_stop; gboolean stop_rsc_orphans; gboolean stop_action_orphans; int default_resource_stickiness; int default_resource_fail_stickiness; no_quorum_policy_t no_quorum_policy; GHashTable *config_hash; /* intermediate steps */ color_t *no_color; GListPtr nodes; GListPtr resources; GListPtr placement_constraints; GListPtr ordering_constraints; GListPtr colors; GListPtr actions; /* stats */ int num_synapse; int max_valid_nodes; int order_id; int action_id; int color_id; /* final output */ crm_data_t *graph; } pe_working_set_t; struct node_shared_s { const char *id; const char *uname; gboolean online; gboolean standby; gboolean unclean; gboolean shutdown; gboolean expected_up; gboolean is_dc; int num_resources; GListPtr running_rsc; /* resource_t* */ GHashTable *attrs; /* char* => char* */ enum node_type type; }; struct node_s { int weight; gboolean fixed; struct node_shared_s *details; }; -#include +#include struct resource_s { char *id; char *long_name; crm_data_t *xml; crm_data_t *ops_xml; resource_t *parent; void *variant_opaque; enum pe_obj_types variant; resource_object_functions_t *fns; resource_alloc_functions_t *cmds; enum rsc_recovery_type recovery_type; enum pe_restart restart_type; int priority; int stickiness; int fail_stickiness; int effective_priority; gboolean notify; gboolean is_managed; gboolean starting; gboolean stopping; gboolean runnable; gboolean provisional; gboolean globally_unique; gboolean failed; gboolean start_pending; gboolean orphan; GListPtr candidate_colors; /* color_t* */ GListPtr rsc_cons; /* rsc_colocation_t* */ GListPtr rsc_location; /* rsc_to_node_t* */ GListPtr actions; /* action_t* */ color_t *color; GListPtr colors; /* color_t* */ GListPtr running_on; /* node_t* */ GListPtr known_on; /* node_t* */ GListPtr allowed_nodes; /* node_t* */ enum rsc_role_e role; enum rsc_role_e next_role; GHashTable *meta; GHashTable *parameters; }; gboolean cluster_status(pe_working_set_t *data_set); extern void set_working_set_defaults(pe_working_set_t *data_set); extern void cleanup_calculations(pe_working_set_t *data_set); extern resource_t *pe_find_resource(GListPtr rsc_list, const char *id_rh); #endif diff --git a/lib/crm/Makefile.am b/lib/crm/Makefile.am index b30f6e9e0a..03bf43d6ce 100644 --- a/lib/crm/Makefile.am +++ b/lib/crm/Makefile.am @@ -1,22 +1,22 @@ # # 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 ## Subdirectories... -SUBDIRS = common cib transition -DIST_SUBDIRS = common cib transition +SUBDIRS = common pengine cib transition +DIST_SUBDIRS = common pengine cib transition diff --git a/lib/crm/pengine/Makefile.am b/lib/crm/pengine/Makefile.am index 0e7ecb54ef..dac5ca500c 100644 --- a/lib/crm/pengine/Makefile.am +++ b/lib/crm/pengine/Makefile.am @@ -1,88 +1,68 @@ # # 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@ pe_varlibdir = $(HA_VARLIBDIR)/$(HB_PKG)/pengine # sockets with path crmdir = $(havarlibdir)/crm apigid = @HA_APIGID@ crmuid = @HA_CCMUID@ COMMONLIBS = $(CRM_DEBUG_LIBS) \ $(top_builddir)/lib/clplumbing/libplumb.la \ $(top_builddir)/lib/crm/common/libcrmcommon.la \ $(GLIBLIB) \ $(CURSESLIBS) \ $(LIBRT) LIBRT = @LIBRT@ AM_CFLAGS = @CFLAGS@ $(CRM_DEBUG_FLAGS) ## libraries -lib_LTLIBRARIES = libpe_rules.la libpe_status.la libpengine.la - -## binary progs -#halib_PROGRAMS = ptest +lib_LTLIBRARIES = libpe_rules.la libpe_status.la ## SOURCES rule_files = rules.c common.c status_files = status.c unpack.c utils.c complex.c native.c group.c clone.c libpe_rules_la_LDFLAGS = -version-info 1:0:0 libpe_rules_la_SOURCES = $(rule_files) libpe_status_la_LDFLAGS = -version-info 1:0:0 libpe_status_la_SOURCES = $(rule_files) $(status_files) -libpengine_la_LDFLAGS = -version-info 3:0:0 -# -L$(top_builddir)/lib/pils -lpils -export-dynamic -module -avoid-version -libpengine_la_SOURCES = pengine.c allocate.c \ - native_allocate.c group_allocate.c \ - clone_allocate.c master.c graph.c - -noinst_HEADERS = utils.h allocate.h pengine.h - -#ptest_SOURCES = ptest.c - -#ptest_CFLAGS = -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' -#ptest_LDADD = $(COMMONLIBS) \ -# libpe_status.la \ -# libpengine.la \ -# $(top_builddir)/lib/crm/cib/libcib.la \ -# $(top_builddir)/lib/crm/transition/libtransitioner.la - clean-generic: rm -f *.log *.debug *~ install-exec-local: uninstall-local: diff --git a/lib/crm/pengine/clone.c b/lib/crm/pengine/clone.c index bdbe115730..0dc7cb84ca 100644 --- a/lib/crm/pengine/clone.c +++ b/lib/crm/pengine/clone.c @@ -1,316 +1,316 @@ -/* $Id: clone.c,v 1.2 2006/06/02 15:34:18 andrew Exp $ */ +/* $Id: clone.c,v 1.3 2006/06/07 12:46:55 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 void clone_create_notifications( resource_t *rsc, action_t *action, action_t *action_complete, pe_working_set_t *data_set); extern gboolean rsc_colocation_new( const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh, const char *state_lh, const char *state_rh); typedef struct clone_variant_data_s { resource_t *self; int clone_max; int clone_node_max; int active_clones; int max_nodes; gboolean interleave; gboolean ordered; crm_data_t *xml_obj_child; gboolean notify_confirm; GListPtr child_list; /* resource_t* */ } clone_variant_data_t; void child_stopping_constraints( clone_variant_data_t *clone_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set); void child_starting_constraints( clone_variant_data_t *clone_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set); #define get_clone_variant_data(data, rsc) \ CRM_ASSERT(rsc->variant == pe_clone || rsc->variant == pe_master); \ data = (clone_variant_data_t *)rsc->variant_opaque; static gboolean create_child_clone(resource_t *rsc, int sub_id, pe_working_set_t *data_set) { char *inc_num = NULL; char *inc_max = NULL; resource_t *child_rsc = NULL; crm_data_t * child_copy = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); CRM_CHECK(clone_data->xml_obj_child != NULL, return FALSE); inc_num = crm_itoa(sub_id); inc_max = crm_itoa(clone_data->clone_max); child_copy = copy_xml(clone_data->xml_obj_child); crm_xml_add(child_copy, XML_RSC_ATTR_INCARNATION, inc_num); if(common_unpack(child_copy, &child_rsc, rsc, data_set) == FALSE) { pe_err("Failed unpacking resource %s", crm_element_value(child_copy, XML_ATTR_ID)); return FALSE; } /* child_rsc->parent = clone_data->self; */ crm_debug_3("Setting clone attributes for: %s", child_rsc->id); clone_data->child_list = g_list_append( clone_data->child_list, child_rsc); add_hash_param(child_rsc->meta, XML_RSC_ATTR_INCARNATION_MAX, inc_max); print_resource(LOG_DEBUG_3, "Added", child_rsc, FALSE); crm_free(inc_num); crm_free(inc_max); return TRUE; } gboolean master_unpack(resource_t *rsc, pe_working_set_t *data_set) { add_hash_param(rsc->parameters, crm_meta_name("stateful"), XML_BOOLEAN_TRUE); return clone_unpack(rsc, data_set); } gboolean clone_unpack(resource_t *rsc, pe_working_set_t *data_set) { int lpc = 0; crm_data_t *xml_tmp = NULL; crm_data_t *xml_self = NULL; crm_data_t *xml_obj = rsc->xml; clone_variant_data_t *clone_data = NULL; resource_t *self = NULL; const char *ordered = g_hash_table_lookup( rsc->meta, XML_RSC_ATTR_ORDERED); const char *interleave = g_hash_table_lookup( rsc->meta, XML_RSC_ATTR_INTERLEAVE); const char *max_clones = g_hash_table_lookup( rsc->meta, XML_RSC_ATTR_INCARNATION_MAX); const char *max_clones_node = g_hash_table_lookup( rsc->meta, XML_RSC_ATTR_INCARNATION_NODEMAX); crm_debug_3("Processing resource %s...", rsc->id); crm_malloc0(clone_data, sizeof(clone_variant_data_t)); rsc->variant_opaque = clone_data; clone_data->child_list = NULL; clone_data->interleave = FALSE; clone_data->ordered = FALSE; clone_data->active_clones = 0; clone_data->xml_obj_child = NULL; clone_data->clone_node_max = crm_parse_int(max_clones_node,"1"); clone_data->clone_max = crm_parse_int(max_clones, "-1"); if(clone_data->clone_max < 0) { clone_data->clone_max = g_list_length(data_set->nodes); } if(crm_is_true(interleave)) { clone_data->interleave = TRUE; } if(crm_is_true(ordered)) { clone_data->ordered = TRUE; } crm_debug("Options for %s", rsc->id); crm_debug("\tClone max: %d", clone_data->clone_max); crm_debug("\tClone node max: %d", clone_data->clone_node_max); clone_data->xml_obj_child = find_xml_node( xml_obj, XML_CIB_TAG_GROUP, FALSE); if(clone_data->xml_obj_child == NULL) { clone_data->xml_obj_child = find_xml_node( xml_obj, XML_CIB_TAG_RESOURCE, TRUE); } if(clone_data->xml_obj_child == NULL) { pe_config_err("%s has nothing to clone", rsc->id); return FALSE; } xml_self = copy_xml(rsc->xml); /* this is a bit of a hack - but simplifies everything else */ ha_msg_mod(xml_self, F_XML_TAGNAME, XML_CIB_TAG_RESOURCE); /* set_id(xml_self, "self", -1); */ xml_tmp = find_xml_node(xml_obj, "operations", FALSE); if(xml_tmp != NULL) { add_node_copy(xml_self, xml_tmp); } if(common_unpack(xml_self, &self, NULL, data_set)) { clone_data->self = self; } else { crm_log_xml_err(xml_self, "Couldnt unpack dummy child"); clone_data->self = self; return FALSE; } clone_data->notify_confirm = clone_data->self->notify; for(lpc = 0; lpc < clone_data->clone_max; lpc++) { create_child_clone(rsc, lpc, data_set); } crm_debug_3("Added %d children to resource %s...", clone_data->clone_max, rsc->id); return TRUE; } resource_t * clone_find_child(resource_t *rsc, const char *id) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); return pe_find_resource(clone_data->child_list, id); } GListPtr clone_children(resource_t *rsc) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); return clone_data->child_list; } gboolean clone_active(resource_t *rsc, gboolean all) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, gboolean child_active = child_rsc->fns->active(child_rsc, all); if(all == FALSE && child_active) { return TRUE; } else if(all && child_active == FALSE) { return FALSE; } ); if(all) { return TRUE; } else { return FALSE; } } void clone_print( resource_t *rsc, const char *pre_text, long options, void *print_data) { const char *child_text = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); if(pre_text != NULL) { child_text = " "; } else { child_text = " "; } if(rsc->variant == pe_master) { status_print("%sMaster/Slave Set: %s", pre_text?pre_text:"", clone_data->self->id); } else { status_print("%sClone Set: %s", pre_text?pre_text:"", clone_data->self->id); } if(options & pe_print_html) { status_print("\n
    \n"); } else if((options & pe_print_log) == 0) { status_print("\n"); } slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, if(options & pe_print_html) { status_print("
  • \n"); } child_rsc->fns->print( child_rsc, child_text, options, print_data); if(options & pe_print_html) { status_print("
  • \n"); } ); if(options & pe_print_html) { status_print("
\n"); } } void clone_free(resource_t *rsc) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); crm_debug_3("Freeing %s", rsc->id); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, crm_debug_3("Freeing child %s", child_rsc->id); free_xml(child_rsc->xml); child_rsc->fns->free(child_rsc); ); crm_debug_3("Freeing child list"); pe_free_shallow_adv(clone_data->child_list, FALSE); if(clone_data->self) { free_xml(clone_data->self->xml); clone_data->self->fns->free(clone_data->self); } common_free(rsc); } enum rsc_role_e clone_resource_state(resource_t *rsc) { return RSC_ROLE_UNKNOWN; } diff --git a/lib/crm/pengine/common.c b/lib/crm/pengine/common.c index cddf0e5bf5..95641b8bbc 100644 --- a/lib/crm/pengine/common.c +++ b/lib/crm/pengine/common.c @@ -1,297 +1,297 @@ -/* $Id: common.c,v 1.1 2006/05/31 14:59:12 andrew Exp $ */ +/* $Id: common.c,v 1.2 2006/06/07 12:46:56 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 gboolean was_processing_error = FALSE; gboolean was_processing_warning = FALSE; gboolean was_config_error = FALSE; gboolean was_config_warning = FALSE; const char * fail2text(enum action_fail_response fail) { const char *result = ""; switch(fail) { case action_fail_ignore: result = "ignore"; break; case action_fail_block: result = "block"; break; case action_fail_recover: result = "recover"; break; case action_fail_migrate: result = "migrate"; break; case action_fail_fence: result = "fence"; break; } return result; } enum action_tasks text2task(const char *task) { if(safe_str_eq(task, CRMD_ACTION_STOP)) { return stop_rsc; } else if(safe_str_eq(task, CRMD_ACTION_STOPPED)) { return stopped_rsc; } else if(safe_str_eq(task, CRMD_ACTION_START)) { return start_rsc; } else if(safe_str_eq(task, CRMD_ACTION_STARTED)) { return started_rsc; } else if(safe_str_eq(task, CRM_OP_SHUTDOWN)) { return shutdown_crm; } else if(safe_str_eq(task, CRM_OP_FENCE)) { return stonith_node; } else if(safe_str_eq(task, CRMD_ACTION_MON)) { return monitor_rsc; } else if(safe_str_eq(task, CRMD_ACTION_NOTIFY)) { return action_notify; } else if(safe_str_eq(task, CRMD_ACTION_NOTIFIED)) { return action_notified; } else if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) { return action_promote; } else if(safe_str_eq(task, CRMD_ACTION_DEMOTE)) { return action_demote; } else if(safe_str_eq(task, CRMD_ACTION_PROMOTED)) { return action_promoted; } else if(safe_str_eq(task, CRMD_ACTION_DEMOTED)) { return action_demoted; } else if(safe_str_eq(task, CRMD_ACTION_CANCEL)) { return no_action; } else if(safe_str_eq(task, CRMD_ACTION_DELETE)) { return no_action; } else if(safe_str_eq(task, CRMD_ACTION_STATUS)) { return no_action; } else if(safe_str_eq(task, CRM_OP_PROBED)) { return no_action; } else if(safe_str_eq(task, CRM_OP_LRM_REFRESH)) { return no_action; } pe_err("Unsupported action: %s", task); return no_action; } const char * task2text(enum action_tasks task) { const char *result = ""; switch(task) { case no_action: result = "no_action"; break; case stop_rsc: result = CRMD_ACTION_STOP; break; case stopped_rsc: result = CRMD_ACTION_STOPPED; break; case start_rsc: result = CRMD_ACTION_START; break; case started_rsc: result = CRMD_ACTION_STARTED; break; case shutdown_crm: result = CRM_OP_SHUTDOWN; break; case stonith_node: result = CRM_OP_FENCE; break; case monitor_rsc: result = CRMD_ACTION_MON; break; case action_notify: result = CRMD_ACTION_NOTIFY; break; case action_notified: result = CRMD_ACTION_NOTIFIED; break; case action_promote: result = CRMD_ACTION_PROMOTE; break; case action_promoted: result = CRMD_ACTION_PROMOTED; break; case action_demote: result = CRMD_ACTION_DEMOTE; break; case action_demoted: result = CRMD_ACTION_DEMOTED; break; } return result; } const char * role2text(enum rsc_role_e role) { CRM_CHECK(role >= RSC_ROLE_UNKNOWN, return RSC_ROLE_UNKNOWN_S); CRM_CHECK(role < RSC_ROLE_MAX, return RSC_ROLE_UNKNOWN_S); switch(role) { case RSC_ROLE_UNKNOWN: return RSC_ROLE_UNKNOWN_S; case RSC_ROLE_STOPPED: return RSC_ROLE_STOPPED_S; case RSC_ROLE_STARTED: return RSC_ROLE_STARTED_S; case RSC_ROLE_SLAVE: return RSC_ROLE_SLAVE_S; case RSC_ROLE_MASTER: return RSC_ROLE_MASTER_S; } return RSC_ROLE_UNKNOWN_S; } enum rsc_role_e text2role(const char *role) { if(safe_str_eq(role, RSC_ROLE_STOPPED_S)) { return RSC_ROLE_STOPPED; } else if(safe_str_eq(role, RSC_ROLE_STARTED_S)) { return RSC_ROLE_STARTED; } else if(safe_str_eq(role, RSC_ROLE_SLAVE_S)) { return RSC_ROLE_SLAVE; } else if(safe_str_eq(role, RSC_ROLE_MASTER_S)) { return RSC_ROLE_MASTER; } else if(safe_str_eq(role, RSC_ROLE_UNKNOWN_S)) { return RSC_ROLE_UNKNOWN; } crm_err("Unknown role: %s", role); return RSC_ROLE_UNKNOWN; } int merge_weights(int w1, int w2) { int result = w1 + w2; if(w1 <= -INFINITY || w2 <= -INFINITY) { if(w1 >= INFINITY || w2 >= INFINITY) { crm_debug_2("-INFINITY + INFINITY == -INFINITY"); } return -INFINITY; } else if(w1 >= INFINITY || w2 >= INFINITY) { return INFINITY; } /* detect wrap-around */ if(result > 0) { if(w1 <= 0 && w2 < 0) { result = -INFINITY; } } else if(w1 > 0 && w2 > 0) { result = INFINITY; } /* detect +/- INFINITY */ if(result >= INFINITY) { result = INFINITY; } else if(result <= -INFINITY) { result = -INFINITY; } crm_debug_5("%d + %d = %d", w1, w2, result); return result; } int char2score(const char *score) { int score_f = 0; if(score == NULL) { } else if(safe_str_eq(score, MINUS_INFINITY_S)) { score_f = -INFINITY; } else if(safe_str_eq(score, INFINITY_S)) { score_f = INFINITY; } else if(safe_str_eq(score, "+"INFINITY_S)) { score_f = INFINITY; } else { score_f = crm_parse_int(score, NULL); if(score_f > 0 && score_f > INFINITY) { score_f = INFINITY; } else if(score_f < 0 && score_f < -INFINITY) { score_f = -INFINITY; } } return score_f; } char * score2char(int score) { if(score >= INFINITY) { return crm_strdup("+"INFINITY_S); } else if(score <= -INFINITY) { return crm_strdup("-"INFINITY_S); } return crm_itoa(score); } void add_hash_param(GHashTable *hash, const char *name, const char *value) { CRM_CHECK(hash != NULL, return); crm_debug_3("adding: name=%s value=%s", crm_str(name), crm_str(value)); if(name == NULL || value == NULL) { return; } else if(safe_str_eq(value, "#default")) { return; } else if(g_hash_table_lookup(hash, name) == NULL) { g_hash_table_insert(hash, crm_strdup(name), crm_strdup(value)); } } diff --git a/lib/crm/pengine/complex.c b/lib/crm/pengine/complex.c index 6d34c724bd..9db78bd9f3 100644 --- a/lib/crm/pengine/complex.c +++ b/lib/crm/pengine/complex.c @@ -1,391 +1,403 @@ -/* $Id: complex.c,v 1.1 2006/05/31 15:00:38 andrew Exp $ */ +/* $Id: complex.c,v 1.2 2006/06/07 12:46:56 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 gboolean update_node_weight(rsc_to_node_t *cons,const char *id,GListPtr nodes); gboolean is_active(rsc_to_node_t *cons); gboolean constraint_violated( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint); extern gboolean rsc_colocation_new(const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh); rsc_to_node_t *generate_location_rule( resource_t *rsc, crm_data_t *location_rule, pe_working_set_t *data_set); void populate_hash(crm_data_t *nvpair_list, GHashTable *hash, const char **attrs, int attrs_length); resource_object_functions_t resource_class_functions[] = { { native_unpack, native_find_child, native_children, native_parameter, native_print, native_active, native_resource_state, native_free }, { group_unpack, group_find_child, group_children, native_parameter, group_print, group_active, group_resource_state, group_free }, { clone_unpack, clone_find_child, clone_children, native_parameter, clone_print, clone_active, clone_resource_state, clone_free }, { master_unpack, clone_find_child, clone_children, native_parameter, clone_print, clone_active, clone_resource_state, clone_free } }; int get_resource_type(const char *name) { if(safe_str_eq(name, XML_CIB_TAG_RESOURCE)) { return pe_native; } else if(safe_str_eq(name, XML_CIB_TAG_GROUP)) { return pe_group; } else if(safe_str_eq(name, XML_CIB_TAG_INCARNATION)) { return pe_clone; } else if(safe_str_eq(name, XML_CIB_TAG_MASTER)) { return pe_master; } return pe_unknown; } gboolean is_active(rsc_to_node_t *cons) { /* todo: check constraint lifetime */ return TRUE; } static void dup_attr(gpointer key, gpointer value, gpointer user_data) { add_hash_param(user_data, key, value); } gboolean common_unpack(crm_data_t * xml_obj, resource_t **rsc, resource_t *parent, pe_working_set_t *data_set) { const char *value = NULL; const char *id = crm_element_value(xml_obj, XML_ATTR_ID); crm_log_xml_debug_3(xml_obj, "Processing resource input..."); if(id == NULL) { pe_err("Must specify id tag in "); return FALSE; } else if(rsc == NULL) { pe_err("Nowhere to unpack resource into"); return FALSE; } crm_malloc0(*rsc, sizeof(resource_t)); if(*rsc == NULL) { return FALSE; } (*rsc)->xml = xml_obj; (*rsc)->parent = parent; (*rsc)->ops_xml = find_xml_node(xml_obj, "operations", FALSE); (*rsc)->variant = get_resource_type(crm_element_name(xml_obj)); if((*rsc)->variant == pe_unknown) { pe_err("Unknown resource type: %s", crm_element_name(xml_obj)); crm_free(*rsc); return FALSE; } (*rsc)->parameters = g_hash_table_new_full( g_str_hash,g_str_equal, g_hash_destroy_str,g_hash_destroy_str); (*rsc)->meta = g_hash_table_new_full( g_str_hash,g_str_equal, g_hash_destroy_str,g_hash_destroy_str); value = crm_element_value(xml_obj, XML_RSC_ATTR_INCARNATION); if(value) { (*rsc)->id = crm_concat(id, value, ':'); add_hash_param((*rsc)->meta, XML_RSC_ATTR_INCARNATION, value); } else { (*rsc)->id = crm_strdup(id); } if(parent) { (*rsc)->long_name = crm_concat(parent->long_name, (*rsc)->id, ':'); } else { (*rsc)->long_name = crm_strdup((*rsc)->id); } (*rsc)->fns = &resource_class_functions[(*rsc)->variant]; crm_debug_3("Unpacking resource..."); /* meta attributes */ xml_prop_iter( xml_obj, prop_name, prop_value, add_hash_param((*rsc)->meta, prop_name, prop_value); ); unpack_instance_attributes( xml_obj, XML_TAG_META_SETS, NULL, (*rsc)->meta, NULL, data_set->now); if(parent != NULL) { g_hash_table_foreach(parent->meta, dup_attr, (*rsc)->meta); } /* populate from the regular attributes until the GUI can create * meta attributes */ unpack_instance_attributes( xml_obj, XML_TAG_ATTR_SETS, NULL, (*rsc)->meta, NULL, data_set->now); if(parent != NULL) { g_hash_table_foreach( parent->parameters, dup_attr, (*rsc)->parameters); } if((*rsc)->fns->unpack(*rsc, data_set) == FALSE) { return FALSE; } (*rsc)->runnable = TRUE; (*rsc)->provisional = TRUE; (*rsc)->starting = FALSE; (*rsc)->stopping = FALSE; (*rsc)->candidate_colors = NULL; (*rsc)->rsc_cons = NULL; (*rsc)->actions = NULL; (*rsc)->failed = FALSE; (*rsc)->start_pending = FALSE; (*rsc)->globally_unique = TRUE; (*rsc)->role = RSC_ROLE_STOPPED; (*rsc)->next_role = RSC_ROLE_UNKNOWN; (*rsc)->is_managed = data_set->is_managed_default; (*rsc)->recovery_type = recovery_stop_start; (*rsc)->stickiness = data_set->default_resource_stickiness; (*rsc)->fail_stickiness = data_set->default_resource_fail_stickiness; value = g_hash_table_lookup((*rsc)->meta, XML_CIB_ATTR_PRIORITY); (*rsc)->priority = crm_parse_int(value, "0"); (*rsc)->effective_priority = (*rsc)->priority; value = g_hash_table_lookup((*rsc)->meta, XML_RSC_ATTR_NOTIFY); (*rsc)->notify = crm_is_true(value); value = g_hash_table_lookup((*rsc)->meta, "is_managed"); if(value != NULL && safe_str_neq("default", value)) { cl_str_to_boolean(value, &((*rsc)->is_managed)); } crm_debug_2("Options for %s", (*rsc)->id); value = g_hash_table_lookup((*rsc)->meta, "globally_unique"); if(value != NULL) { cl_str_to_boolean(value, &((*rsc)->globally_unique)); } value = g_hash_table_lookup((*rsc)->meta, XML_RSC_ATTR_RESTART); if(safe_str_eq(value, "restart")) { (*rsc)->restart_type = pe_restart_restart; crm_debug_2("\tDependancy restart handling: restart"); } else { (*rsc)->restart_type = pe_restart_ignore; crm_debug_2("\tDependancy restart handling: ignore"); } value = g_hash_table_lookup((*rsc)->meta, "multiple_active"); if(safe_str_eq(value, "stop_only")) { (*rsc)->recovery_type = recovery_stop_only; crm_debug_2("\tMultiple running resource recovery: stop only"); } else if(safe_str_eq(value, "block")) { (*rsc)->recovery_type = recovery_block; crm_debug_2("\tMultiple running resource recovery: block"); } else { (*rsc)->recovery_type = recovery_stop_start; crm_debug_2("\tMultiple running resource recovery: stop/start"); } value = g_hash_table_lookup((*rsc)->meta, "resource_stickiness"); if(value != NULL && safe_str_neq("default", value)) { (*rsc)->stickiness = char2score(value); } if((*rsc)->stickiness > 0) { crm_debug_2("\tPlacement: prefer current location%s", value == NULL?" (default)":""); } else if((*rsc)->stickiness < 0) { crm_warn("\tPlacement: always move from the current location%s", value == NULL?" (default)":""); } else { crm_debug_2("\tPlacement: optimal%s", value == NULL?" (default)":""); } value = g_hash_table_lookup( (*rsc)->meta, XML_RSC_ATTR_FAIL_STICKINESS); if(value != NULL) { (*rsc)->fail_stickiness = char2score(value); } crm_debug_2("\tNode score per failure: %d%s", (*rsc)->fail_stickiness, value == NULL?" (default)":""); value = g_hash_table_lookup( (*rsc)->meta, XML_RSC_ATTR_TARGET_ROLE); if(value != NULL && safe_str_neq("default", value)) { (*rsc)->is_managed = TRUE; (*rsc)->next_role = text2role(value); if((*rsc)->next_role == RSC_ROLE_UNKNOWN) { pe_config_err("%s: Unknown value for " XML_RSC_ATTR_TARGET_ROLE": %s", (*rsc)->id, value); } } crm_debug_2("\tDesired next state: %s", (*rsc)->next_role!=RSC_ROLE_UNKNOWN?role2text((*rsc)->next_role):"default"); + if((*rsc)->next_role == RSC_ROLE_STOPPED) { + crm_debug_2("Making sure %s doesn't get colored", (*rsc)->id); + /* make sure it doesnt come up again */ + pe_free_shallow_adv((*rsc)->allowed_nodes, TRUE); + (*rsc)->allowed_nodes = node_list_dup( + data_set->nodes, FALSE, FALSE); + slist_iter( + node, node_t, (*rsc)->allowed_nodes, lpc, + node->weight = -INFINITY; + ); + } + if((*rsc)->is_managed == FALSE) { crm_warn("Resource %s is currently not managed", (*rsc)->id); } else if(data_set->symmetric_cluster) { rsc_to_node_t *new_con = rsc2node_new( "symmetric_default", *rsc, 0, NULL, data_set); new_con->node_list_rh = node_list_dup(data_set->nodes, TRUE, FALSE); } crm_debug_2("\tAction notification: %s", (*rsc)->notify?"required":"not required"); /* data_set->resources = g_list_append(data_set->resources, (*rsc)); */ return TRUE; } void order_actions( action_t *lh_action, action_t *rh_action, enum pe_ordering order) { action_wrapper_t *wrapper = NULL; GListPtr list = NULL; crm_debug_2("Ordering Action %s before %s", lh_action->uuid, rh_action->uuid); log_action(LOG_DEBUG_4, "LH (order_actions)", lh_action, FALSE); log_action(LOG_DEBUG_4, "RH (order_actions)", rh_action, FALSE); crm_malloc0(wrapper, sizeof(action_wrapper_t)); if(wrapper != NULL) { wrapper->action = rh_action; wrapper->type = order; list = lh_action->actions_after; list = g_list_append(list, wrapper); lh_action->actions_after = list; wrapper = NULL; } if(order != pe_ordering_recover) { crm_malloc0(wrapper, sizeof(action_wrapper_t)); if(wrapper != NULL) { wrapper->action = lh_action; wrapper->type = order; list = rh_action->actions_before; list = g_list_append(list, wrapper); rh_action->actions_before = list; } } } void common_free(resource_t *rsc) { if(rsc == NULL) { return; } crm_debug_5("Freeing %s", rsc->id); while(rsc->rsc_cons) { pe_free_rsc_colocation( (rsc_colocation_t*)rsc->rsc_cons->data); rsc->rsc_cons = rsc->rsc_cons->next; } if(rsc->rsc_cons != NULL) { g_list_free(rsc->rsc_cons); } if(rsc->parameters != NULL) { g_hash_table_destroy(rsc->parameters); } if(rsc->meta != NULL) { g_hash_table_destroy(rsc->meta); } if(rsc->orphan) { free_xml(rsc->xml); } pe_free_shallow_adv(rsc->running_on, FALSE); pe_free_shallow_adv(rsc->known_on, FALSE); pe_free_shallow_adv(rsc->candidate_colors, TRUE); pe_free_shallow_adv(rsc->rsc_location, FALSE); pe_free_shallow_adv(rsc->allowed_nodes, TRUE); crm_free(rsc->id); crm_free(rsc->long_name); crm_free(rsc->variant_opaque); crm_free(rsc); crm_debug_5("Resource freed"); } diff --git a/lib/crm/pengine/group.c b/lib/crm/pengine/group.c index 585639067d..00227c2f7d 100644 --- a/lib/crm/pengine/group.c +++ b/lib/crm/pengine/group.c @@ -1,269 +1,269 @@ -/* $Id: group.c,v 1.1 2006/05/31 14:59:12 andrew Exp $ */ +/* $Id: group.c,v 1.2 2006/06/07 12:46:56 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 extern gboolean rsc_colocation_new( const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh, const char *state_lh, const char *state_rh); typedef struct group_variant_data_s { int num_children; GListPtr child_list; /* resource_t* */ resource_t *self; resource_t *first_child; resource_t *last_child; gboolean colocated; gboolean ordered; gboolean child_starting; gboolean child_stopping; } group_variant_data_t; #define get_group_variant_data(data, rsc) \ CRM_ASSERT(rsc != NULL); \ CRM_ASSERT(rsc->variant == pe_group); \ CRM_ASSERT(rsc->variant_opaque != NULL); \ data = (group_variant_data_t *)rsc->variant_opaque; \ void group_assign_color(resource_t *rsc, color_t *group_color); gboolean group_unpack(resource_t *rsc, pe_working_set_t *data_set) { resource_t *self = NULL; crm_data_t *xml_obj = rsc->xml; crm_data_t *xml_self = copy_xml(rsc->xml); group_variant_data_t *group_data = NULL; const char *group_ordered = g_hash_table_lookup( rsc->meta, XML_RSC_ATTR_ORDERED); const char *group_colocated = g_hash_table_lookup( rsc->meta, "collocated"); const char *clone_id = NULL; crm_debug_3("Processing resource %s...", rsc->id); /* rsc->id = "dummy_group_rsc_id"; */ crm_malloc0(group_data, sizeof(group_variant_data_t)); group_data->num_children = 0; group_data->self = NULL; group_data->child_list = NULL; group_data->first_child = NULL; group_data->last_child = NULL; rsc->variant_opaque = group_data; group_data->ordered = TRUE; group_data->colocated = TRUE; if(group_ordered != NULL) { cl_str_to_boolean(group_ordered, &(group_data->ordered)); } if(group_colocated != NULL) { cl_str_to_boolean(group_colocated, &(group_data->colocated)); } /* this is a bit of a hack - but simplifies everything else */ ha_msg_mod(xml_self, F_XML_TAGNAME, XML_CIB_TAG_RESOURCE); /* set_id(xml_self, "self", -1); */ if(common_unpack(xml_self, &self, NULL, data_set)) { group_data->self = self; self->restart_type = pe_restart_restart; } else { crm_log_xml_err(xml_self, "Couldnt unpack dummy child"); return FALSE; } clone_id = crm_element_value(rsc->xml, XML_RSC_ATTR_INCARNATION); xml_child_iter_filter( xml_obj, xml_native_rsc, XML_CIB_TAG_RESOURCE, resource_t *new_rsc = NULL; crm_xml_add(xml_native_rsc, XML_RSC_ATTR_INCARNATION, clone_id); if(common_unpack(xml_native_rsc, &new_rsc, rsc, data_set) == FALSE) { pe_err("Failed unpacking resource %s", crm_element_value(xml_obj, XML_ATTR_ID)); if(new_rsc != NULL && new_rsc->fns != NULL) { new_rsc->fns->free(new_rsc); } } group_data->num_children++; group_data->child_list = g_list_append( group_data->child_list, new_rsc); if(group_data->first_child == NULL) { group_data->first_child = new_rsc; } else if(group_data->colocated) { rsc_colocation_new( "pe_group_internal_colo", pecs_must, group_data->first_child, new_rsc, NULL, NULL); } group_data->last_child = new_rsc; print_resource(LOG_DEBUG_3, "Added", new_rsc, FALSE); ); if(group_data->num_children == 0) { pe_config_err("Group %s did not have any children", rsc->id); return FALSE; } crm_debug_3("Added %d children to resource %s...", group_data->num_children, rsc->id); return TRUE; } resource_t * group_find_child(resource_t *rsc, const char *id) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); return pe_find_resource(group_data->child_list, id); } GListPtr group_children(resource_t *rsc) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); return group_data->child_list; } gboolean group_active(resource_t *rsc, gboolean all) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, gboolean child_active = child_rsc->fns->active(child_rsc, all); if(all == FALSE && child_active) { return TRUE; } else if(child_active == FALSE) { return FALSE; } ); if(all) { return TRUE; } else { return FALSE; } } void group_print( resource_t *rsc, const char *pre_text, long options, void *print_data) { const char *child_text = NULL; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); if(pre_text != NULL) { child_text = " "; } else { child_text = " "; } status_print("%sResource Group: %s", pre_text?pre_text:"", rsc->id); if(options & pe_print_html) { status_print("\n
    \n"); } else if((options & pe_print_log) == 0) { status_print("\n"); } slist_iter( child_rsc, resource_t, group_data->child_list, lpc, if(options & pe_print_html) { status_print("
  • \n"); } child_rsc->fns->print( child_rsc, child_text, options, print_data); if(options & pe_print_html) { status_print("
  • \n"); } ); if(options & pe_print_html) { status_print("
\n"); } } void group_free(resource_t *rsc) { group_variant_data_t *group_data = NULL; CRM_CHECK(rsc != NULL, return); get_group_variant_data(group_data, rsc); crm_debug_3("Freeing %s", rsc->id); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, crm_debug_3("Freeing child %s", child_rsc->id); child_rsc->fns->free(child_rsc); ); crm_debug_3("Freeing child list"); pe_free_shallow_adv(group_data->child_list, FALSE); if(group_data->self != NULL) { free_xml(group_data->self->xml); group_data->self->fns->free(group_data->self); } common_free(rsc); } enum rsc_role_e group_resource_state(resource_t *rsc) { enum rsc_role_e group_role = RSC_ROLE_UNKNOWN; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); slist_iter( child_rsc, resource_t, group_data->child_list, lpc, if(child_rsc->next_role > group_role) { group_role = rsc->next_role; } if(child_rsc->failed) { rsc->failed = TRUE; } ); return group_role; } diff --git a/lib/crm/pengine/native.c b/lib/crm/pengine/native.c index 8b0146a2dd..82b4bbfeb2 100644 --- a/lib/crm/pengine/native.c +++ b/lib/crm/pengine/native.c @@ -1,467 +1,469 @@ -/* $Id: native.c,v 1.1 2006/05/31 14:59:12 andrew Exp $ */ +/* $Id: native.c,v 1.2 2006/06/07 12:46:56 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 #define DELETE_THEN_REFRESH 1 typedef struct native_variant_data_s { /* GListPtr allowed_nodes; /\* node_t* *\/ */ } native_variant_data_t; gboolean DeleteRsc(resource_t *rsc, node_t *node, pe_working_set_t *data_set); #define get_native_variant_data(data, rsc) \ CRM_ASSERT(rsc->variant == pe_native); \ CRM_ASSERT(rsc->variant_opaque != NULL); \ data = (native_variant_data_t *)rsc->variant_opaque; void native_add_running(resource_t *rsc, node_t *node, pe_working_set_t *data_set) { CRM_CHECK(node != NULL, return); slist_iter( a_node, node_t, rsc->running_on, lpc, CRM_CHECK(a_node != NULL, return); if(safe_str_eq(a_node->details->id, node->details->id)) { return; } ); rsc->running_on = g_list_append(rsc->running_on, node); if(rsc->variant == pe_native) { node->details->running_rsc = g_list_append( node->details->running_rsc, rsc); } if(rsc->variant != pe_native) { } else if(rsc->is_managed == FALSE) { crm_info("resource %s isnt managed", rsc->id); rsc2node_new( "not_managed_default", rsc, INFINITY, node, data_set); return; #if 0 } else if(rsc->failed) { crm_info("Skipping resource stickiness for failed resource %s", rsc->id); #endif } else if(rsc->stickiness > 0 || rsc->stickiness < 0) { rsc2node_new("stickiness", rsc, rsc->stickiness, node,data_set); crm_debug("Resource %s: preferring current location (%s/%s)", rsc->id, node->details->uname, node->details->id); } if(rsc->variant == pe_native && g_list_length(rsc->running_on) > 1) { const char *type = crm_element_value(rsc->xml, XML_ATTR_TYPE); const char *class = crm_element_value( rsc->xml, XML_AGENT_ATTR_CLASS); /* these are errors because hardly any gets it right * at the moment and this way the might notice */ pe_err("Resource %s::%s:%s appears to be active on %d nodes.", class, type, rsc->id, g_list_length(rsc->running_on)); cl_log(LOG_ERR, "See %s for more information.", HAURL("v2/faq/resource_too_active")); if(rsc->recovery_type == recovery_stop_only) { + crm_debug("Making sure %s doesn't come up again", rsc->id); + /* make sure it doesnt come up again */ pe_free_shallow_adv(rsc->allowed_nodes, TRUE); rsc->allowed_nodes = node_list_dup( data_set->nodes, FALSE, FALSE); slist_iter( node, node_t, rsc->allowed_nodes, lpc, node->weight = -INFINITY; ); } else if(rsc->recovery_type == recovery_block) { rsc->is_managed = FALSE; } } else { crm_debug_2("Resource %s is active on: %s", rsc->id, node->details->uname); } if(rsc->parent != NULL) { native_add_running(rsc->parent, node, data_set); } } gboolean native_unpack(resource_t *rsc, pe_working_set_t *data_set) { native_variant_data_t *native_data = NULL; crm_debug_3("Processing resource %s...", rsc->id); crm_malloc0(native_data, sizeof(native_variant_data_t)); rsc->allowed_nodes = NULL; rsc->running_on = NULL; rsc->variant_opaque = native_data; return TRUE; } resource_t * native_find_child(resource_t *rsc, const char *id) { return NULL; } GListPtr native_children(resource_t *rsc) { return NULL; } static void hash_copy_field(gpointer key, gpointer value, gpointer user_data) { const char *name = key; const char *s_value = value; GHashTable *hash_copy = user_data; g_hash_table_insert(hash_copy, crm_strdup(name), crm_strdup(s_value)); } char * native_parameter( resource_t *rsc, node_t *node, gboolean create, const char *name, pe_working_set_t *data_set) { char *value_copy = NULL; const char *value = NULL; GHashTable *hash = rsc->parameters; GHashTable *local_hash = NULL; CRM_CHECK(rsc != NULL, return NULL); CRM_CHECK(name != NULL && strlen(name) != 0, return NULL); crm_debug_2("Looking up %s in %s", name, rsc->id); if(create) { if(node != NULL) { crm_debug_2("Creating hash with node %s", node->details->uname); } else { crm_debug_2("Creating default hash"); } local_hash = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); g_hash_table_foreach( rsc->parameters, hash_copy_field, local_hash); unpack_instance_attributes( rsc->xml, XML_TAG_ATTR_SETS, node?node->details->attrs:NULL, local_hash, NULL, data_set->now); hash = local_hash; } value = g_hash_table_lookup(hash, name); if(value == NULL) { /* try meta attributes instead */ value = g_hash_table_lookup(rsc->meta, name); } if(value != NULL) { value_copy = crm_strdup(value); } if(local_hash != NULL) { g_hash_table_destroy(local_hash); } return value_copy; } gboolean native_active(resource_t *rsc, gboolean all) { slist_iter( a_node, node_t, rsc->running_on, lpc, if(a_node->details->online == FALSE) { crm_debug("Resource %s: node %s is offline", rsc->id, a_node->details->uname); } else if(a_node->details->unclean) { crm_debug("Resource %s: node %s is unclean", rsc->id, a_node->details->uname); } else { crm_debug("Resource %s active on %s", rsc->id, a_node->details->uname); return TRUE; } ); return FALSE; } struct print_data_s { long options; void *print_data; }; static void native_print_attr(gpointer key, gpointer value, gpointer user_data) { long options = ((struct print_data_s*)user_data)->options; void *print_data = ((struct print_data_s*)user_data)->print_data; status_print("Option: %s = %s\n", (char*)key, (char*)value); } void native_print( resource_t *rsc, const char *pre_text, long options, void *print_data) { node_t *node = NULL; const char *prov = NULL; const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); if(safe_str_eq(class, "ocf")) { prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER); } if(rsc->running_on != NULL) { node = rsc->running_on->data; } if(options & pe_print_html) { if(rsc->is_managed == FALSE) { status_print(""); } else if(rsc->failed) { status_print(""); } else if(rsc->variant == pe_native && g_list_length(rsc->running_on) == 0) { status_print(""); } else if(g_list_length(rsc->running_on) > 1) { status_print(""); } else { status_print(""); } } if((options & pe_print_rsconly) || g_list_length(rsc->running_on) > 1) { const char *desc = NULL; desc = crm_element_value(rsc->xml, XML_ATTR_DESC); status_print("%s%s\t(%s%s%s:%s)%s%s", pre_text?pre_text:"", rsc->id, prov?prov:"", prov?"::":"", class, crm_element_value(rsc->xml, XML_ATTR_TYPE), desc?": ":"", desc?desc:""); } else { status_print("%s%s\t(%s%s%s:%s):\t%s %s%s%s", pre_text?pre_text:"", rsc->id, prov?prov:"", prov?"::":"", class, crm_element_value(rsc->xml, XML_ATTR_TYPE), (rsc->variant!=pe_native)?"":role2text(rsc->role), (rsc->variant!=pe_native)?"":node!=NULL?node->details->uname:"", rsc->is_managed?"":" (unmanaged)", rsc->failed?" FAILED":""); #if CURSES_ENABLED if(options & pe_print_ncurses) { move(-1, 0); } #endif } if(options & pe_print_html) { status_print(" "); } if((options & pe_print_rsconly)) { } else if(g_list_length(rsc->running_on) > 1) { if(options & pe_print_html) { status_print("
    \n"); } else if((options & pe_print_printf) || (options & pe_print_ncurses)) { status_print("["); } slist_iter(node, node_t, rsc->running_on, lpc, if(options & pe_print_html) { status_print("
  • \n%s", node->details->uname); } else if((options & pe_print_printf) || (options & pe_print_ncurses)) { status_print("\t%s", node->details->uname); } else if((options & pe_print_log)) { status_print("\t%d : %s", lpc, node->details->uname); } else { status_print("%s", node->details->uname); } if(options & pe_print_html) { status_print("
  • \n"); } ); if(options & pe_print_html) { status_print("
\n"); } else if((options & pe_print_printf) || (options & pe_print_ncurses)) { status_print(" ]"); } } if(options & pe_print_html) { status_print("
\n"); } else if((options & pe_print_printf) || (options & pe_print_ncurses)) { status_print("\n"); } if(options & pe_print_details) { struct print_data_s pdata; pdata.options = options; pdata.print_data = print_data; g_hash_table_foreach(rsc->parameters, native_print_attr, &pdata); } if(options & pe_print_dev) { status_print("%s\t(%s%svariant=%s, priority=%f)", pre_text, rsc->provisional?"provisional, ":"", rsc->runnable?"":"non-startable, ", crm_element_name(rsc->xml), (double)rsc->priority); status_print("%s\t%d candidate colors, %d allowed nodes," " %d rsc_cons", pre_text, g_list_length(rsc->candidate_colors), g_list_length(rsc->allowed_nodes), g_list_length(rsc->rsc_cons)); } if(options & pe_print_max_details) { status_print("%s\t=== Actions.\n", pre_text); slist_iter( action, action_t, rsc->actions, lpc, log_action(LOG_DEBUG_4, "\trsc action: ", action, FALSE); ); status_print("%s\t=== Colors\n", pre_text); slist_iter( color, color_t, rsc->candidate_colors, lpc, print_color("\t", color, FALSE) ); status_print("%s\t=== Allowed Nodes\n", pre_text); slist_iter( node, node_t, rsc->allowed_nodes, lpc, print_node("\t", node, FALSE); ); } } void native_free(resource_t *rsc) { crm_debug_4("Freeing Allowed Nodes"); crm_free(rsc->color); common_free(rsc); } enum rsc_role_e native_resource_state(resource_t *rsc) { if(rsc->next_role != RSC_ROLE_UNKNOWN) { return rsc->next_role; } if(rsc->role != RSC_ROLE_UNKNOWN) { return rsc->role; } return RSC_ROLE_STOPPED; } gboolean DeleteRsc(resource_t *rsc, node_t *node, pe_working_set_t *data_set) { action_t *delete = NULL; action_t *refresh = NULL; char *stop = NULL; char *start = NULL; if(rsc->failed) { crm_debug_2("Resource %s not deleted from %s: failed", rsc->id, node->details->uname); return FALSE; } else if(node == NULL) { crm_debug_2("Resource %s not deleted: NULL node", rsc->id); return FALSE; } else if(node->details->unclean || node->details->online == FALSE) { crm_debug_2("Resource %s not deleted from %s: unrunnable", rsc->id, node->details->uname); return FALSE; } stop = stop_key(rsc); start = start_key(rsc); crm_notice("Removing %s from %s", rsc->id, node->details->uname); delete = delete_action(rsc, node); custom_action_order( rsc, stop, NULL, rsc, NULL, delete, pe_ordering_optional, data_set); custom_action_order( rsc, NULL, delete, rsc, start, NULL, pe_ordering_manditory, data_set); #if DELETE_THEN_REFRESH refresh = custom_action( NULL, crm_strdup(CRM_OP_LRM_REFRESH), CRM_OP_LRM_REFRESH, node, FALSE, TRUE, data_set); add_hash_param(refresh->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); custom_action_order( rsc, NULL, delete, NULL, NULL, refresh, pe_ordering_optional, data_set); #endif return TRUE; } diff --git a/crm/pengine/pengine.h b/lib/crm/pengine/pengine.h similarity index 51% rename from crm/pengine/pengine.h rename to lib/crm/pengine/pengine.h index cc67522780..49a0652288 100644 --- a/crm/pengine/pengine.h +++ b/lib/crm/pengine/pengine.h @@ -1,496 +1,246 @@ -/* $Id: pengine.h,v 1.113 2006/06/07 07:34:38 andrew Exp $ */ +/* $Id: pengine.h,v 1.1 2006/06/07 12:46:56 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 */ #ifndef PENGINE__H #define PENGINE__H #include -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_colocation_s rsc_colocation_t; -typedef struct resource_s resource_t; typedef struct lrm_agent_s lrm_agent_t; typedef struct order_constraint_s order_constraint_t; typedef struct action_s action_t; typedef struct action_wrapper_s action_wrapper_t; #include #include #include #include +#include +#include +#include #include -/* - * The man pages for both curses and ncurses suggest inclusion of "curses.h". - * We believe the following to be acceptable and portable. - */ - -#if defined(HAVE_LIBNCURSES) || defined(HAVE_LIBCURSES) -#if defined(HAVE_NCURSES_H) && !defined(HAVE_INCOMPATIBLE_PRINTW) -# include -# define CURSES_ENABLED 1 -#elif defined(HAVE_NCURSES_NCURSES_H) && !defined(HAVE_INCOMPATIBLE_PRINTW) -# include -# define CURSES_ENABLED 1 -#elif defined(HAVE_CURSES_H) && !defined(HAVE_INCOMPATIBLE_PRINTW) -# include -# define CURSES_ENABLED 1 -#elif defined(HAVE_CURSES_CURSES_H) && !defined(HAVE_INCOMPATIBLE_PRINTW) -# include -# define CURSES_ENABLED 1 -#else -# define CURSES_ENABLED 0 -#endif -#else -# define CURSES_ENABLED 0 -#endif - -typedef enum no_quorum_policy_e { - no_quorum_freeze, - no_quorum_stop, - no_quorum_ignore -} no_quorum_policy_t; - -enum pe_print_options { - - pe_print_log = 0x0001, - pe_print_html = 0x0002, - pe_print_ncurses = 0x0004, - pe_print_printf = 0x0008, - pe_print_dev = 0x0010, - pe_print_details = 0x0020, - pe_print_max_details = 0x0040, - pe_print_rsconly = 0x0080, -}; - -typedef struct pe_working_set_s -{ - crm_data_t *input; - ha_time_t *now; - - /* options extracted from the input */ - char *transition_idle_timeout; - char *dc_uuid; - node_t *dc_node; - gboolean have_quorum; - gboolean stonith_enabled; - const char *stonith_action; - gboolean symmetric_cluster; - gboolean is_managed_default; - - gboolean remove_after_stop; - gboolean stop_rsc_orphans; - gboolean stop_action_orphans; - - int default_resource_stickiness; - int default_resource_fail_stickiness; - no_quorum_policy_t no_quorum_policy; - - GHashTable *config_hash; - - /* intermediate steps */ - color_t *no_color; - - GListPtr nodes; - GListPtr resources; - GListPtr placement_constraints; - GListPtr ordering_constraints; - - GListPtr colors; - GListPtr actions; - - /* stats */ - int num_synapse; - int max_valid_nodes; - int order_id; - int action_id; - int color_id; - - /* final output */ - crm_data_t *graph; - -} pe_working_set_t; - #include -enum con_type { - type_none, - rsc_colocation, - rsc_to_node, - rsc_to_attr, - base_weight -}; - -enum node_type { - node_ping, - node_member -}; - enum con_strength { pecs_ignore, pecs_must, pecs_must_not, pecs_startstop }; -enum action_tasks { - no_action, - monitor_rsc, - stop_rsc, - stopped_rsc, - start_rsc, - started_rsc, - action_notify, - action_notified, - action_promote, - action_promoted, - action_demote, - action_demoted, - shutdown_crm, - stonith_node -}; - -enum rsc_recovery_type { - recovery_stop_start, - recovery_stop_only, - recovery_block -}; - -enum rsc_start_requirement { - rsc_req_nothing, - rsc_req_quorum, - rsc_req_stonith -}; enum pe_stop_fail { pesf_block, pesf_stonith, pesf_ignore }; -enum pe_restart { - pe_restart_restart, - pe_restart_ignore -}; - enum pe_ordering { pe_ordering_manditory, pe_ordering_restart, pe_ordering_recover, pe_ordering_postnotify, pe_ordering_optional }; -enum rsc_role_e { - RSC_ROLE_UNKNOWN, - RSC_ROLE_STOPPED, - RSC_ROLE_STARTED, - RSC_ROLE_SLAVE, - RSC_ROLE_MASTER, -}; -#define RSC_ROLE_MAX RSC_ROLE_MASTER+1 - -#define RSC_ROLE_UNKNOWN_S "Unknown" -#define RSC_ROLE_STOPPED_S "Stopped" -#define RSC_ROLE_STARTED_S "Started" -#define RSC_ROLE_SLAVE_S "Slave" -#define RSC_ROLE_MASTER_S "Master" - -struct node_shared_s { - const char *id; - const char *uname; - gboolean online; - gboolean standby; - gboolean unclean; - gboolean shutdown; - gboolean expected_up; - gboolean is_dc; - int num_resources; - GListPtr running_rsc; /* resource_t* */ - - GHashTable *attrs; /* char* => char* */ - enum node_type type; -}; - -struct node_s { - int weight; - gboolean fixed; - struct node_shared_s *details; -}; struct color_shared_s { int id; int highest_priority; GListPtr candidate_nodes; /* node_t* */ GListPtr allocated_resources; /* resources_t* */ node_t *chosen_node; gboolean pending; int num_resources; }; struct color_s { int id; struct color_shared_s *details; int local_weight; }; struct rsc_colocation_s { const char *id; resource_t *rsc_lh; resource_t *rsc_rh; const char *state_lh; const char *state_rh; enum con_strength strength; }; struct rsc_to_node_s { const char *id; resource_t *rsc_lh; enum rsc_role_e role_filter; GListPtr node_list_rh; /* node_t* */ }; -struct resource_s { - char *id; - char *long_name; - crm_data_t *xml; - crm_data_t *ops_xml; - - resource_t *parent; - void *variant_opaque; - enum pe_obj_types variant; - resource_object_functions_t *fns; - - enum rsc_recovery_type recovery_type; - enum pe_restart restart_type; - - int priority; - int stickiness; - int fail_stickiness; - int effective_priority; - - gboolean notify; - gboolean is_managed; - gboolean starting; - gboolean stopping; - gboolean runnable; - gboolean provisional; - gboolean globally_unique; - - gboolean failed; - gboolean start_pending; - - gboolean orphan; - - GListPtr candidate_colors; /* color_t* */ - GListPtr rsc_cons; /* rsc_colocation_t* */ - GListPtr rsc_location; /* rsc_to_node_t* */ - GListPtr actions; /* action_t* */ - - color_t *color; - GListPtr colors; /* color_t* */ - GListPtr running_on; /* node_t* */ - GListPtr known_on; /* node_t* */ - GListPtr allowed_nodes; /* node_t* */ - - enum rsc_role_e role; - enum rsc_role_e next_role; - - GHashTable *meta; - GHashTable *parameters; -}; - struct action_wrapper_s { enum pe_ordering type; action_t *action; }; -/* order is significant here - * items listed in order of accending severeness - * more severe actions take precedent over lower ones - */ -enum action_fail_response { - action_fail_ignore, - action_fail_recover, - action_fail_migrate, - action_fail_block, -/* action_fail_stop, */ - action_fail_fence -}; - struct action_s { int id; int priority; resource_t *rsc; void *rsc_opaque; node_t *node; const char *task; char *uuid; crm_data_t *op_entry; gboolean pseudo; gboolean runnable; gboolean optional; gboolean failure_is_fatal; enum rsc_start_requirement needs; enum action_fail_response on_fail; enum rsc_role_e fail_role; gboolean dumped; gboolean processed; action_t *pre_notify; action_t *pre_notified; action_t *post_notify; action_t *post_notified; int seen_count; GHashTable *meta; GHashTable *extra; GHashTable *notify_keys; /* do NOT free */ GListPtr actions_before; /* action_warpper_t* */ GListPtr actions_after; /* action_warpper_t* */ }; struct order_constraint_s { int id; enum pe_ordering type; void *lh_opaque; resource_t *lh_rsc; action_t *lh_action; char *lh_action_task; void *rh_opaque; resource_t *rh_rsc; action_t *rh_action; char *rh_action_task; /* (soon to be) variant specific */ /* int lh_rsc_incarnation; */ /* int rh_rsc_incarnation; */ }; extern gboolean stage0(pe_working_set_t *data_set); extern gboolean stage1(pe_working_set_t *data_set); extern gboolean stage2(pe_working_set_t *data_set); extern gboolean stage3(pe_working_set_t *data_set); extern gboolean stage4(pe_working_set_t *data_set); extern gboolean stage5(pe_working_set_t *data_set); extern gboolean stage6(pe_working_set_t *data_set); extern gboolean stage7(pe_working_set_t *data_set); extern gboolean stage8(pe_working_set_t *data_set); extern gboolean summary(GListPtr resources); extern gboolean pe_msg_dispatch(IPC_Channel *sender, void *user_data); extern gboolean process_pe_message( HA_Message *msg, crm_data_t *xml_data, IPC_Channel *sender); extern gboolean unpack_constraints( crm_data_t *xml_constraints, pe_working_set_t *data_set); extern gboolean unpack_resources( crm_data_t *xml_resources, pe_working_set_t *data_set); extern gboolean unpack_config(crm_data_t *config, pe_working_set_t *data_set); extern gboolean unpack_nodes(crm_data_t *xml_nodes, pe_working_set_t *data_set); extern gboolean unpack_status(crm_data_t *status, pe_working_set_t *data_set); extern gboolean apply_placement_constraints(pe_working_set_t *data_set); extern gboolean choose_node_from_list(color_t *color); extern gboolean update_action_states(GListPtr actions); extern gboolean shutdown_constraints( node_t *node, action_t *shutdown_op, pe_working_set_t *data_set); extern gboolean stonith_constraints( node_t *node, action_t *stonith_op, pe_working_set_t *data_set); extern gboolean custom_action_order( resource_t *lh_rsc, char *lh_task, action_t *lh_action, resource_t *rh_rsc, char *rh_task, action_t *rh_action, enum pe_ordering type, pe_working_set_t *data_set); #define order_start_start(rsc1,rsc2, type) \ custom_action_order(rsc1, start_key(rsc1), NULL, \ rsc2, start_key(rsc2) ,NULL, \ type, data_set) #define order_stop_stop(rsc1, rsc2, type) \ custom_action_order(rsc1, stop_key(rsc1), NULL, \ rsc2, stop_key(rsc2) ,NULL, \ type, data_set) #define order_restart(rsc1) \ custom_action_order(rsc1, stop_key(rsc1), NULL, \ rsc1, start_key(rsc1), NULL, \ pe_ordering_restart, data_set) #define order_stop_start(rsc1, rsc2, type) \ custom_action_order(rsc1, stop_key(rsc1), NULL, \ rsc2, start_key(rsc2) ,NULL, \ type, data_set) #define order_start_stop(rsc1, rsc2, type) \ custom_action_order(rsc1, start_key(rsc1), NULL, \ rsc2, stop_key(rsc2) ,NULL, \ type, data_set) -#define pe_err(fmt...) { was_processing_error = TRUE; was_config_error = TRUE; crm_err(fmt); } -#define pe_warn(fmt...) { was_processing_warning = TRUE; was_config_warning = TRUE; crm_warn(fmt); } -#define pe_proc_err(fmt...) { was_processing_error = TRUE; crm_err(fmt); } -#define pe_proc_warn(fmt...) { was_processing_warning = TRUE; crm_warn(fmt); } -#define pe_config_err(fmt...) { was_config_error = TRUE; crm_err(fmt); } -#define pe_config_warn(fmt...) { was_config_warning = TRUE; crm_warn(fmt); } - extern gboolean process_colored_constraints(resource_t *rsc); extern void graph_element_from_action( action_t *action, pe_working_set_t *data_set); -extern void set_working_set_defaults(pe_working_set_t *data_set); -extern void cleanup_calculations(pe_working_set_t *data_set); extern void order_actions(action_t *lh_action, action_t *rh_action, enum pe_ordering order); extern const char* transition_idle_timeout; -extern gboolean was_processing_error; -extern gboolean was_processing_warning; -extern gboolean was_config_error; -extern gboolean was_config_warning; -extern unsigned int pengine_input_loglevel; #endif diff --git a/lib/crm/pengine/rules.c b/lib/crm/pengine/rules.c index 2fe699a01c..434769ef7b 100644 --- a/lib/crm/pengine/rules.c +++ b/lib/crm/pengine/rules.c @@ -1,611 +1,611 @@ -/* $Id: rules.c,v 1.1 2006/05/31 14:59:12 andrew Exp $ */ +/* $Id: rules.c,v 1.2 2006/06/07 12:46:56 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 ha_time_t *parse_xml_duration(ha_time_t *start, crm_data_t *duration_spec); gboolean test_date_expression(crm_data_t *time_expr, ha_time_t *now); gboolean cron_range_satisfied(ha_time_t *now, crm_data_t *cron_spec); gboolean test_attr_expression( crm_data_t *expr, GHashTable *hash, ha_time_t *now); gboolean test_role_expression( crm_data_t *expr, enum rsc_role_e role, ha_time_t *now); gboolean test_ruleset(crm_data_t *ruleset, GHashTable *node_hash, ha_time_t *now) { gboolean ruleset_default = TRUE; xml_child_iter_filter( ruleset, rule, XML_TAG_RULE, ruleset_default = FALSE; if(test_rule(rule, node_hash, RSC_ROLE_UNKNOWN, now)) { return TRUE; } ); return ruleset_default; } gboolean test_rule(crm_data_t *rule, GHashTable *node_hash, enum rsc_role_e role, ha_time_t *now) { gboolean test = TRUE; gboolean passed = TRUE; gboolean do_and = TRUE; const char *value = crm_element_value(rule, "boolean_op"); if(safe_str_eq(value, "or")) { do_and = FALSE; passed = FALSE; } crm_debug_2("Testing rule %s", ID(rule)); xml_child_iter( rule, expr, test = test_expression(expr, node_hash, role, now); if(test && do_and == FALSE) { crm_debug_3("Expression %s/%s passed", ID(rule), ID(expr)); return TRUE; } else if(test == FALSE && do_and) { crm_debug_3("Expression %s/%s failed", ID(rule), ID(expr)); return FALSE; } ); crm_debug_2("Rule %s %s", ID(rule), passed?"passed":"failed"); return passed; } gboolean test_expression(crm_data_t *expr, GHashTable *node_hash, enum rsc_role_e role, ha_time_t *now) { gboolean accept = FALSE; const char *uname = NULL; switch(find_expression_type(expr)) { case nested_rule: accept = test_rule(expr, node_hash, role, now); break; case attr_expr: case loc_expr: /* these expressions can never succeed if there is * no node to compare with */ if(node_hash != NULL) { accept = test_attr_expression(expr, node_hash, now); } break; case time_expr: accept = test_date_expression(expr, now); break; case role_expr: accept = test_role_expression(expr, role, now); break; default: CRM_CHECK(FALSE /* bad type */, return FALSE); accept = FALSE; } if(node_hash) { uname = g_hash_table_lookup(node_hash, "#uname"); } crm_debug_2("Expression %s %s on %s", ID(expr), accept?"passed":"failed", uname?uname:"all ndoes"); return accept; } enum expression_type find_expression_type(crm_data_t *expr) { const char *tag = NULL; const char *attr = NULL; attr = crm_element_value(expr, XML_EXPR_ATTR_ATTRIBUTE); tag = crm_element_name(expr); if(safe_str_eq(tag, "date_expression")) { return time_expr; } else if(safe_str_eq(tag, XML_TAG_RULE)) { return nested_rule; } else if(safe_str_neq(tag, "expression")) { return not_expr; } else if(safe_str_eq(attr, "#uname") || safe_str_eq(attr, "#id")) { return loc_expr; } else if(safe_str_eq(attr, "#role")) { return role_expr; } return attr_expr; } gboolean test_role_expression( crm_data_t *expr, enum rsc_role_e role, ha_time_t *now) { gboolean accept = FALSE; const char *op = NULL; const char *value = NULL; if(role == RSC_ROLE_UNKNOWN) { return accept; } value = crm_element_value(expr, XML_EXPR_ATTR_VALUE); op = crm_element_value(expr, XML_EXPR_ATTR_OPERATION); if(safe_str_eq(op, "defined")) { if(role > RSC_ROLE_STARTED) { accept = TRUE; } } else if(safe_str_eq(op, "not_defined")) { if(role < RSC_ROLE_SLAVE && role > RSC_ROLE_UNKNOWN) { accept = TRUE; } } else if(safe_str_eq(op, "eq")) { if(text2role(value) == role) { accept = TRUE; } } else if(safe_str_eq(op, "ne")) { /* we will only test "ne" wtih master/slave roles style */ if(role < RSC_ROLE_SLAVE && role > RSC_ROLE_UNKNOWN) { accept = FALSE; } else if(text2role(value) != role) { accept = TRUE; } } return accept; } gboolean test_attr_expression(crm_data_t *expr, GHashTable *hash, ha_time_t *now) { gboolean accept = FALSE; int cmp = 0; const char *h_val = NULL; const char *op = NULL; const char *type = NULL; const char *attr = NULL; const char *value = NULL; attr = crm_element_value(expr, XML_EXPR_ATTR_ATTRIBUTE); op = crm_element_value(expr, XML_EXPR_ATTR_OPERATION); value = crm_element_value(expr, XML_EXPR_ATTR_VALUE); type = crm_element_value(expr, XML_EXPR_ATTR_TYPE); if(attr == NULL || op == NULL) { pe_err("Invlaid attribute or operation in expression" " (\'%s\' \'%s\' \'%s\')", crm_str(attr), crm_str(op), crm_str(value)); return FALSE; } if(hash != NULL) { h_val = (const char*)g_hash_table_lookup(hash, attr); } if(value != NULL && h_val != NULL) { if(type == NULL || (safe_str_eq(type, "string"))) { cmp = strcmp(h_val, value); } else if(safe_str_eq(type, "number")) { int h_val_f = crm_parse_int(h_val, NULL); int value_f = crm_parse_int(value, NULL); if(h_val_f < value_f) { cmp = -1; } else if(h_val_f > value_f) { cmp = 1; } else { cmp = 0; } } else if(safe_str_eq(type, "version")) { cmp = compare_version(h_val, value); } } else if(value == NULL && h_val == NULL) { cmp = 0; } else if(value == NULL) { cmp = 1; } else { cmp = -1; } if(safe_str_eq(op, "defined")) { if(h_val != NULL) { accept = TRUE; } } else if(safe_str_eq(op, "not_defined")) { if(h_val == NULL) { accept = TRUE; } } else if(safe_str_eq(op, "eq")) { if((h_val == value) || cmp == 0) { accept = TRUE; } } else if(safe_str_eq(op, "ne")) { if((h_val == NULL && value != NULL) || (h_val != NULL && value == NULL) || cmp != 0) { accept = TRUE; } } else if(value == NULL || h_val == NULL) { /* the comparision is meaningless from this point on */ accept = FALSE; } else if(safe_str_eq(op, "lt")) { if(cmp < 0) { accept = TRUE; } } else if(safe_str_eq(op, "lte")) { if(cmp <= 0) { accept = TRUE; } } else if(safe_str_eq(op, "gt")) { if(cmp > 0) { accept = TRUE; } } else if(safe_str_eq(op, "gte")) { if(cmp >= 0) { accept = TRUE; } } return accept; } /* As per the nethack rules: * * moon period = 29.53058 days ~= 30, year = 365.2422 days * days moon phase advances on first day of year compared to preceding year * = 365.2422 - 12*29.53058 ~= 11 * years in Metonic cycle (time until same phases fall on the same days of * the month) = 18.6 ~= 19 * moon phase on first day of year (epact) ~= (11*(year%19) + 29) % 30 * (29 as initial condition) * current phase in days = first day phase + days elapsed in year * 6 moons ~= 177 days * 177 ~= 8 reported phases * 22 * + 11/22 for rounding * * 0-7, with 0: new, 4: full */ static int phase_of_the_moon(ha_time_t *now) { int epact, diy, goldn; diy = now->yeardays; goldn = (now->years % 19) + 1; epact = (11 * goldn + 18) % 30; if ((epact == 25 && goldn > 11) || epact == 24) epact++; return( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 ); } #define cron_check(xml_field, time_field) \ value = crm_element_value(cron_spec, xml_field); \ if(value != NULL) { \ gboolean pass = TRUE; \ decodeNVpair(value, '-', &value_low, &value_high); \ if(value_low == NULL) { \ value_low = crm_strdup(value); \ } \ value_low_i = crm_parse_int(value_low, "0"); \ value_high_i = crm_parse_int(value_high, "-1"); \ if(value_low_i > time_field) { \ pass = FALSE; \ } else if(value_high_i < 0) { \ } else if(value_high_i < time_field) { \ pass = FALSE; \ } \ crm_free(value_low); \ crm_free(value_high); \ if(pass == FALSE) { \ crm_debug("Condition '%s' in %s: failed", value, xml_field); \ return pass; \ } \ crm_debug("Condition '%s' in %s: passed", value, xml_field); \ } gboolean cron_range_satisfied(ha_time_t *now, crm_data_t *cron_spec) { const char *value = NULL; char *value_low = NULL; char *value_high = NULL; int value_low_i = 0; int value_high_i = 0; cron_check("seconds", now->seconds); cron_check("minutes", now->minutes); cron_check("hours", now->hours); cron_check("monthdays", now->days); cron_check("weekdays", now->weekdays); cron_check("yeardays", now->yeardays); cron_check("weeks", now->weeks); cron_check("months", now->months); cron_check("years", now->years); cron_check("weekyears", now->weekyears); cron_check("moon", phase_of_the_moon(now)); return TRUE; } #define update_field(xml_field, time_fn) \ value = crm_element_value(duration_spec, xml_field); \ if(value != NULL) { \ int value_i = crm_parse_int(value, "0"); \ time_fn(end, value_i); \ } ha_time_t * parse_xml_duration(ha_time_t *start, crm_data_t *duration_spec) { ha_time_t *end = NULL; const char *value = NULL; end = new_ha_date(FALSE); ha_set_time(end, start, TRUE); update_field("years", add_years); update_field("months", add_months); update_field("weeks", add_weeks); update_field("days", add_days); update_field("hours", add_hours); update_field("minutes", add_minutes); update_field("seconds", add_seconds); return end; } gboolean test_date_expression(crm_data_t *time_expr, ha_time_t *now) { ha_time_t *start = NULL; ha_time_t *end = NULL; const char *value = NULL; char *value_copy = NULL; char *value_copy_start = NULL; const char *op = crm_element_value(time_expr, "operation"); crm_data_t *duration_spec = NULL; crm_data_t *date_spec = NULL; gboolean passed = FALSE; crm_debug_2("Testing expression: %s", ID(time_expr)); duration_spec = cl_get_struct(time_expr, "duration"); date_spec = cl_get_struct(time_expr, "date_spec"); value = crm_element_value(time_expr, "start"); if(value != NULL) { value_copy = crm_strdup(value); value_copy_start = value_copy; start = parse_date(&value_copy); crm_free(value_copy_start); } value = crm_element_value(time_expr, "end"); if(value != NULL) { value_copy = crm_strdup(value); value_copy_start = value_copy; end = parse_date(&value_copy); crm_free(value_copy_start); } if(start != NULL && end == NULL) { end = parse_xml_duration(start, duration_spec); } if(op == NULL) { op = "in_range"; } if(safe_str_eq(op, "date_spec") || safe_str_eq(op, "in_range")) { if(start != NULL && compare_date(start, now) > 0) { passed = FALSE; } else if(end != NULL && compare_date(end, now) < 0) { passed = FALSE; } else if(safe_str_eq(op, "in_range")) { passed = TRUE; } else { passed = cron_range_satisfied(now, date_spec); } } else if(safe_str_eq(op, "gt") && compare_date(start, now) < 0) { passed = TRUE; } else if(safe_str_eq(op, "lt") && compare_date(end, now) > 0) { passed = TRUE; } else if(safe_str_eq(op, "eq") && compare_date(start, now) == 0) { passed = TRUE; } else if(safe_str_eq(op, "neq") && compare_date(start, now) != 0) { passed = TRUE; } free_ha_date(start); free_ha_date(end); return passed; } typedef struct sorted_set_s { const char *name; const char *special_name; int score; crm_data_t *attr_set; GHashTable *node_hash; GHashTable *hash; ha_time_t *now; } sorted_set_t; static gint sort_pairs(gconstpointer a, gconstpointer b) { const sorted_set_t *pair_a = a; const sorted_set_t *pair_b = b; if(a == NULL && b == NULL) { return 0; } else if(a == NULL) { return 1; } else if(b == NULL) { return -1; } if(safe_str_eq(pair_a->name, pair_a->special_name)) { return -1; } else if(safe_str_eq(pair_b->name, pair_a->special_name)) { return 1; } if(pair_a->score < pair_b->score) { return 1; } else if(pair_a->score > pair_b->score) { return -1; } return 0; } static void populate_hash(crm_data_t *nvpair_list, GHashTable *hash) { const char *name = NULL; const char *value = NULL; xml_child_iter_filter( nvpair_list, an_attr, XML_CIB_TAG_NVPAIR, name = crm_element_value(an_attr, XML_NVPAIR_ATTR_NAME); crm_debug_4("Setting attribute: %s", name); value = crm_element_value( an_attr, XML_NVPAIR_ATTR_VALUE); if(name == NULL || value == NULL) { return; } else if(safe_str_eq(value, "#default")) { return; } else if(g_hash_table_lookup(hash, name) == NULL) { g_hash_table_insert( hash, crm_strdup(name), crm_strdup(value)); } ); } static void unpack_attr_set(gpointer data, gpointer user_data) { sorted_set_t *pair = data; sorted_set_t *unpack_data = user_data; crm_data_t *attributes = NULL; if(test_ruleset(pair->attr_set, unpack_data->node_hash, unpack_data->now) == FALSE) { return; } crm_debug_3("Adding attributes from %s", pair->name); attributes = cl_get_struct(pair->attr_set, XML_TAG_ATTRS); populate_hash(attributes, unpack_data->hash); } static void free_pair(gpointer data, gpointer user_data) { sorted_set_t *pair = data; crm_free(pair); } void unpack_instance_attributes( crm_data_t *xml_obj, const char *set_name, GHashTable *node_hash, GHashTable *hash, const char *always_first, ha_time_t *now) { GListPtr sorted = NULL; const char *score = NULL; sorted_set_t *pair = NULL; if(xml_obj == NULL) { crm_debug_4("No instance attributes"); return; } crm_debug_4("Checking for attributes"); xml_child_iter_filter( xml_obj, attr_set, set_name, pair = NULL; crm_malloc0(pair, sizeof(sorted_set_t)); pair->name = ID(attr_set); pair->special_name = always_first; pair->attr_set = attr_set; score = crm_element_value(attr_set, XML_RULE_ATTR_SCORE); pair->score = char2score(score); sorted = g_list_prepend(sorted, pair); ); if(pair != NULL) { pair->hash = hash; pair->node_hash = node_hash; pair->now = now; } sorted = g_list_sort(sorted, sort_pairs); g_list_foreach(sorted, unpack_attr_set, pair); g_list_foreach(sorted, free_pair, NULL); g_list_free(sorted); } diff --git a/lib/crm/pengine/status.c b/lib/crm/pengine/status.c index f6a4585bf5..b6e0080288 100644 --- a/lib/crm/pengine/status.c +++ b/lib/crm/pengine/status.c @@ -1,239 +1,239 @@ -/* $Id: status.c,v 1.1 2006/05/31 14:59:12 andrew Exp $ */ +/* $Id: status.c,v 1.2 2006/06/07 12:46:56 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 crm_data_t * do_calculations( pe_working_set_t *data_set, crm_data_t *xml_input, ha_time_t *now); unsigned int pengine_input_loglevel = LOG_INFO; #define PE_WORKING_DIR HA_VARLIBDIR"/heartbeat/pengine" #define MEMCHECK_STAGE_0 0 #define check_and_exit(stage) cleanup_calculations(data_set); \ crm_mem_stats(NULL); \ crm_err("Exiting: stage %d", stage); \ exit(1); /* * Unpack everything * At the end you'll have: * - A list of nodes * - A list of resources (each with any dependencies on other resources) * - A list of constraints between resources and nodes * - A list of constraints between start/stop actions * - A list of nodes that need to be stonith'd * - A list of nodes that need to be shutdown * - A list of the possible stop/start actions (without dependencies) */ gboolean cluster_status(pe_working_set_t *data_set) { /* int lpc; */ crm_data_t * config = get_object_root( XML_CIB_TAG_CRMCONFIG, data_set->input); crm_data_t * cib_nodes = get_object_root( XML_CIB_TAG_NODES, data_set->input); crm_data_t * cib_resources = get_object_root( XML_CIB_TAG_RESOURCES, data_set->input); crm_data_t * cib_status = get_object_root( XML_CIB_TAG_STATUS, data_set->input); const char *value = crm_element_value( data_set->input, XML_ATTR_HAVE_QUORUM); crm_debug_3("Beginning unpack"); /* reset remaining global variables */ if(data_set->input == NULL) { return FALSE; } if(data_set->input != NULL && crm_element_value(data_set->input, XML_ATTR_DC_UUID) != NULL) { /* this should always be present */ data_set->dc_uuid = crm_element_value_copy( data_set->input, XML_ATTR_DC_UUID); } data_set->no_color = create_color(data_set, NULL, NULL); unpack_config(config, data_set); if(value != NULL) { cl_str_to_boolean(value, &data_set->have_quorum); } if(data_set->have_quorum == FALSE && data_set->no_quorum_policy != no_quorum_ignore) { crm_warn("We do not have quorum" " - fencing and resource management disabled"); } unpack_nodes(cib_nodes, data_set); unpack_resources(cib_resources, data_set); unpack_status(cib_status, data_set); return TRUE; } void cleanup_calculations(pe_working_set_t *data_set) { GListPtr iterator = NULL; if(data_set == NULL) { return; } if(data_set->config_hash != NULL) { g_hash_table_destroy(data_set->config_hash); } crm_free(data_set->dc_uuid); crm_free(data_set->transition_idle_timeout); crm_debug_3("deleting order cons"); pe_free_ordering(data_set->ordering_constraints); crm_debug_3("deleting actions"); pe_free_actions(data_set->actions); crm_debug_3("deleting resources"); pe_free_resources(data_set->resources); crm_debug_3("deleting nodes"); pe_free_nodes(data_set->nodes); crm_debug_3("deleting colors"); pe_free_colors(data_set->colors); crm_debug_3("deleting node cons"); iterator = data_set->placement_constraints; while(iterator) { pe_free_rsc_to_node(iterator->data); iterator = iterator->next; } if(data_set->placement_constraints != NULL) { g_list_free(data_set->placement_constraints); } free_xml(data_set->graph); free_ha_date(data_set->now); free_xml(data_set->input); data_set->stonith_action = NULL; } void set_working_set_defaults(pe_working_set_t *data_set) { data_set->input = NULL; data_set->now = NULL; data_set->graph = NULL; data_set->transition_idle_timeout = crm_strdup("60s"); data_set->dc_uuid = NULL; data_set->dc_node = NULL; data_set->have_quorum = FALSE; data_set->stonith_enabled = FALSE; data_set->stonith_action = NULL; data_set->symmetric_cluster = TRUE; data_set->is_managed_default = TRUE; data_set->no_quorum_policy = no_quorum_freeze; data_set->remove_after_stop = FALSE; data_set->stop_action_orphans = TRUE; data_set->stop_rsc_orphans = TRUE; data_set->config_hash = NULL; data_set->nodes = NULL; data_set->resources = NULL; data_set->ordering_constraints = NULL; data_set->placement_constraints = NULL; data_set->no_color = NULL; data_set->colors = NULL; data_set->actions = NULL; data_set->num_synapse = 0; data_set->max_valid_nodes = 0; data_set->order_id = 1; data_set->action_id = 1; data_set->color_id = 0; data_set->default_resource_stickiness = 0; data_set->default_resource_fail_stickiness = 0; } resource_t * pe_find_resource(GListPtr rsc_list, const char *id) { unsigned lpc = 0; resource_t *rsc = NULL; resource_t *child_rsc = NULL; if(id == NULL) { return NULL; } crm_debug_4("Looking for %s in %d objects", id, g_list_length(rsc_list)); for(lpc = 0; lpc < g_list_length(rsc_list); lpc++) { rsc = g_list_nth_data(rsc_list, lpc); if(rsc == NULL) { } else if(safe_str_eq(rsc->id, id)){ crm_debug_4("Found a match for %s", id); return rsc; } else if(safe_str_eq(rsc->long_name, id)) { crm_debug_4("Found a match for %s", id); return rsc; } } for(lpc = 0; lpc < g_list_length(rsc_list); lpc++) { rsc = g_list_nth_data(rsc_list, lpc); child_rsc = rsc->fns->find_child(rsc, id); if(child_rsc != NULL) { crm_debug_4("Found a match for %s in %s", id, rsc->id); return child_rsc; } } crm_debug_2("No match for %s", id); return NULL; } diff --git a/lib/crm/pengine/unpack.c b/lib/crm/pengine/unpack.c index 9772318e13..854c2cdd64 100644 --- a/lib/crm/pengine/unpack.c +++ b/lib/crm/pengine/unpack.c @@ -1,2090 +1,2091 @@ -/* $Id: unpack.c,v 1.2 2006/06/02 15:34:18 andrew Exp $ */ +/* $Id: unpack.c,v 1.3 2006/06/07 12:46:56 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 /* for ONLINESTATUS */ -#include +#include #include -#include +#include gint sort_op_by_callid(gconstpointer a, gconstpointer b); gboolean unpack_rsc_to_attr(crm_data_t *xml_obj, pe_working_set_t *data_set); gboolean unpack_rsc_to_node(crm_data_t *xml_obj, pe_working_set_t *data_set); gboolean unpack_rsc_order(crm_data_t *xml_obj, pe_working_set_t *data_set); gboolean unpack_rsc_colocation(crm_data_t *xml_obj, pe_working_set_t *data_set); gboolean unpack_rsc_location(crm_data_t *xml_obj, pe_working_set_t *data_set); gboolean unpack_lrm_resources( node_t *node, crm_data_t * lrm_state, pe_working_set_t *data_set); gboolean add_node_attrs( crm_data_t * attrs, node_t *node, pe_working_set_t *data_set); gboolean unpack_rsc_op( resource_t *rsc, node_t *node, crm_data_t *xml_op, int *max_call_id, enum action_fail_response *failed, pe_working_set_t *data_set); gboolean determine_online_status( crm_data_t * node_state, node_t *this_node, pe_working_set_t *data_set); gboolean rsc_colocation_new( const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh, const char *state_lh, const char *state_rh); gboolean create_ordering( const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh, pe_working_set_t *data_set); const char *param_value( GHashTable *hash, crm_data_t * parent, const char *name); rsc_to_node_t *generate_location_rule( resource_t *rsc, crm_data_t *location_rule, pe_working_set_t *data_set); #define get_cluster_pref(pref) value = g_hash_table_lookup(config_hash, pref); \ if(value == NULL) { \ pe_config_warn("No value specified for cluster preference: %s", pref); \ } gboolean unpack_config(crm_data_t * config, pe_working_set_t *data_set) { const char *name = NULL; const char *value = NULL; GHashTable *config_hash = g_hash_table_new_full( g_str_hash,g_str_equal, g_hash_destroy_str,g_hash_destroy_str); data_set->config_hash = config_hash; unpack_instance_attributes( config, XML_CIB_TAG_PROPSET, NULL, config_hash, CIB_OPTIONS_FIRST, data_set->now); #if CRM_DEPRECATED_SINCE_2_0_1 xml_child_iter_filter( config, a_child, XML_CIB_TAG_NVPAIR, name = crm_element_value(a_child, XML_NVPAIR_ATTR_NAME); value = crm_element_value(a_child, XML_NVPAIR_ATTR_VALUE); if(g_hash_table_lookup(config_hash, name) == NULL) { g_hash_table_insert( config_hash,crm_strdup(name),crm_strdup(value)); } pe_config_err("Creating directly" "beneath has been depreciated since" " 2.0.1", ID(a_child), name); ); #else xml_child_iter_filter( config, a_child, XML_CIB_TAG_NVPAIR, name = crm_element_value(a_child, XML_NVPAIR_ATTR_NAME); pe_config_err("Creating directly" "beneath has been depreciated since" " 2.0.1 and is now disabled", ID(a_child), name); ); #endif get_cluster_pref("default_action_timeout"); if(value == NULL) { get_cluster_pref("transition_idle_timeout"); } if(value != NULL) { long tmp = crm_get_msec(value); if(tmp > 0) { crm_free(data_set->transition_idle_timeout); data_set->transition_idle_timeout = crm_strdup(value); } else { crm_err("Invalid value for default_action_timeout: %s", value); } } crm_debug("default_action_timeout set to: %s", data_set->transition_idle_timeout); get_cluster_pref("default_"XML_RSC_ATTR_STICKINESS); data_set->default_resource_stickiness = char2score(value); crm_info("Default stickiness: %d", data_set->default_resource_stickiness); get_cluster_pref("default_"XML_RSC_ATTR_FAIL_STICKINESS); data_set->default_resource_fail_stickiness = char2score(value); crm_info("Default failure stickiness: %d", data_set->default_resource_fail_stickiness); get_cluster_pref("stonith_enabled"); if(value != NULL) { cl_str_to_boolean(value, &data_set->stonith_enabled); } crm_info("STONITH of failed nodes is %s", data_set->stonith_enabled?"enabled":"disabled"); get_cluster_pref("stonith_action"); if(value == NULL || safe_str_neq(value, "poweroff")) { value = "reboot"; } data_set->stonith_action = value; crm_info("STONITH will %s nodes", data_set->stonith_action); get_cluster_pref("symmetric_cluster"); if(value != NULL) { cl_str_to_boolean(value, &data_set->symmetric_cluster); } if(data_set->symmetric_cluster) { crm_info("Cluster is symmetric" " - resources can run anywhere by default"); } get_cluster_pref("no_quorum_policy"); if(safe_str_eq(value, "ignore")) { data_set->no_quorum_policy = no_quorum_ignore; } else if(safe_str_eq(value, "freeze")) { data_set->no_quorum_policy = no_quorum_freeze; } else { data_set->no_quorum_policy = no_quorum_stop; } switch (data_set->no_quorum_policy) { case no_quorum_freeze: crm_info("On loss of CCM Quorum: Freeze resources"); break; case no_quorum_stop: crm_info("On loss of CCM Quorum: Stop ALL resources"); break; case no_quorum_ignore: crm_notice("On loss of CCM Quorum: Ignore"); break; } get_cluster_pref("stop_orphan_resources"); if(value != NULL) { cl_str_to_boolean(value, &data_set->stop_rsc_orphans); } crm_info("Orphan resources are %s", data_set->stop_rsc_orphans?"stopped":"ignored"); get_cluster_pref("stop_orphan_actions"); if(value != NULL) { cl_str_to_boolean(value, &data_set->stop_action_orphans); } crm_info("Orphan resource actions are %s", data_set->stop_action_orphans?"stopped":"ignored"); get_cluster_pref("remove_after_stop"); if(value != NULL) { cl_str_to_boolean(value, &data_set->remove_after_stop); } crm_info("Stopped resources are removed from the status section: %s", data_set->remove_after_stop?"true":"false"); get_cluster_pref("is_managed_default"); if(value != NULL) { cl_str_to_boolean(value, &data_set->is_managed_default); } crm_info("By default resources are %smanaged", data_set->is_managed_default?"":"not "); return TRUE; } gboolean unpack_nodes(crm_data_t * xml_nodes, pe_working_set_t *data_set) { node_t *new_node = NULL; const char *id = NULL; const char *uname = NULL; const char *type = NULL; crm_debug_2("Begining unpack... %s", xml_nodes?crm_element_name(xml_nodes):""); xml_child_iter_filter( xml_nodes, xml_obj, XML_CIB_TAG_NODE, new_node = NULL; id = crm_element_value(xml_obj, XML_ATTR_ID); uname = crm_element_value(xml_obj, XML_ATTR_UNAME); type = crm_element_value(xml_obj, XML_ATTR_TYPE); crm_debug_3("Processing node %s/%s", uname, id); if(id == NULL) { pe_config_err("Must specify id tag in "); continue; } if(type == NULL) { pe_config_err("Must specify type tag in "); continue; } crm_malloc0(new_node, sizeof(node_t)); if(new_node == NULL) { return FALSE; } new_node->weight = 0; new_node->fixed = FALSE; crm_malloc0(new_node->details, sizeof(struct node_shared_s)); if(new_node->details == NULL) { crm_free(new_node); return FALSE; } crm_debug_3("Creaing node for entry %s/%s", uname, id); new_node->details->id = id; new_node->details->uname = uname; new_node->details->type = node_ping; new_node->details->online = FALSE; new_node->details->shutdown = FALSE; new_node->details->running_rsc = NULL; new_node->details->attrs = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); /* if(data_set->have_quorum == FALSE */ /* && data_set->no_quorum_policy == no_quorum_stop) { */ /* /\* start shutting resources down *\/ */ /* new_node->weight = -INFINITY; */ /* } */ if(data_set->stonith_enabled) { /* all nodes are unclean until we've seen their * status entry */ new_node->details->unclean = TRUE; } else { /* blind faith... */ new_node->details->unclean = FALSE; } if(type == NULL || safe_str_eq(type, "member") || safe_str_eq(type, NORMALNODE)) { new_node->details->type = node_member; } add_node_attrs(xml_obj, new_node, data_set); if(crm_is_true(g_hash_table_lookup( new_node->details->attrs, "standby"))) { crm_info("Node %s is in standby-mode", new_node->details->uname); new_node->weight = -INFINITY; new_node->details->standby = TRUE; } data_set->nodes = g_list_append(data_set->nodes, new_node); crm_debug_3("Done with node %s", crm_element_value(xml_obj, XML_ATTR_UNAME)); crm_action_debug_3(print_node("Added", new_node, FALSE)); ); /* data_set->nodes = g_list_sort(data_set->nodes, sort_node_weight); */ return TRUE; } gboolean unpack_resources(crm_data_t * xml_resources, pe_working_set_t *data_set) { crm_debug_2("Begining unpack... %s", xml_resources?crm_element_name(xml_resources):""); xml_child_iter( xml_resources, xml_obj, resource_t *new_rsc = NULL; crm_debug_2("Begining unpack... %s", xml_obj?crm_element_name(xml_obj):""); if(common_unpack(xml_obj, &new_rsc, NULL, data_set)) { data_set->resources = g_list_append( data_set->resources, new_rsc); print_resource(LOG_DEBUG_3, "Added", new_rsc, FALSE); } else { pe_config_err("Failed unpacking %s %s", crm_element_name(xml_obj), crm_element_value(xml_obj, XML_ATTR_ID)); if(new_rsc != NULL && new_rsc->fns != NULL) { new_rsc->fns->free(new_rsc); } } ); data_set->resources = g_list_sort( data_set->resources, sort_rsc_priority); return TRUE; } gboolean unpack_constraints(crm_data_t * xml_constraints, pe_working_set_t *data_set) { crm_data_t *lifetime = NULL; crm_debug_2("Begining unpack... %s", xml_constraints?crm_element_name(xml_constraints):""); xml_child_iter( xml_constraints, xml_obj, const char *id = crm_element_value(xml_obj, XML_ATTR_ID); if(id == NULL) { pe_config_err("Constraint <%s...> must have an id", crm_element_name(xml_obj)); continue; } crm_debug_3("Processing constraint %s %s", crm_element_name(xml_obj),id); lifetime = cl_get_struct(xml_obj, "lifetime"); if(test_ruleset(lifetime, NULL, data_set->now) == FALSE) { crm_info("Constraint %s %s is not active", crm_element_name(xml_obj), id); } else if(safe_str_eq(XML_CONS_TAG_RSC_ORDER, crm_element_name(xml_obj))) { unpack_rsc_order(xml_obj, data_set); } else if(safe_str_eq(XML_CONS_TAG_RSC_DEPEND, crm_element_name(xml_obj))) { unpack_rsc_colocation(xml_obj, data_set); } else if(safe_str_eq(XML_CONS_TAG_RSC_LOCATION, crm_element_name(xml_obj))) { unpack_rsc_location(xml_obj, data_set); } else { pe_err("Unsupported constraint type: %s", crm_element_name(xml_obj)); } ); return TRUE; } /* remove nodes that are down, stopping */ /* create +ve rsc_to_node constraints between resources and the nodes they are running on */ /* anything else? */ gboolean unpack_status(crm_data_t * status, pe_working_set_t *data_set) { const char *id = NULL; const char *uname = NULL; crm_data_t * lrm_rsc = NULL; crm_data_t * attrs = NULL; node_t *this_node = NULL; crm_debug_3("Begining unpack"); xml_child_iter_filter( status, node_state, XML_CIB_TAG_STATE, id = crm_element_value(node_state, XML_ATTR_ID); uname = crm_element_value(node_state, XML_ATTR_UNAME); attrs = find_xml_node( node_state, XML_TAG_TRANSIENT_NODEATTRS, FALSE); lrm_rsc = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE); lrm_rsc = find_xml_node(lrm_rsc, XML_LRM_TAG_RESOURCES, FALSE); crm_debug_3("Processing node %s", uname); this_node = pe_find_node_id(data_set->nodes, id); if(uname == NULL) { /* error */ continue; } else if(this_node == NULL) { pe_config_warn("Node %s in status section no longer exists", uname); continue; } /* Mark the node as provisionally clean * - at least we have seen it in the current cluster's lifetime */ this_node->details->unclean = FALSE; crm_debug_3("Adding runtime node attrs"); add_node_attrs(attrs, this_node, data_set); crm_debug_3("determining node state"); determine_online_status(node_state, this_node, data_set); if(this_node->details->online || data_set->stonith_enabled) { /* offline nodes run no resources... * unless stonith is enabled in which case we need to * make sure rsc start events happen after the stonith */ crm_debug_3("Processing lrm resource entries"); unpack_lrm_resources(this_node, lrm_rsc, data_set); } ); return TRUE; } static gboolean determine_online_status_no_fencing(crm_data_t * node_state, node_t *this_node) { gboolean online = FALSE; const char *join_state = crm_element_value(node_state, XML_CIB_ATTR_JOINSTATE); const char *crm_state = crm_element_value(node_state, XML_CIB_ATTR_CRMDSTATE); const char *ccm_state = crm_element_value(node_state, XML_CIB_ATTR_INCCM); const char *ha_state = crm_element_value(node_state, XML_CIB_ATTR_HASTATE); const char *exp_state = crm_element_value(node_state, XML_CIB_ATTR_EXPSTATE); if(!crm_is_true(ccm_state) || safe_str_eq(ha_state,DEADSTATUS)){ crm_debug_2("Node is down: ha_state=%s, ccm_state=%s", crm_str(ha_state), crm_str(ccm_state)); } else if(!crm_is_true(ccm_state) || safe_str_eq(ha_state, DEADSTATUS)) { } else if(safe_str_neq(join_state, CRMD_JOINSTATE_DOWN) && safe_str_eq(crm_state, ONLINESTATUS)) { online = TRUE; } else if(this_node->details->expected_up == FALSE) { crm_debug_2("CRMd is down: ha_state=%s, ccm_state=%s", crm_str(ha_state), crm_str(ccm_state)); crm_debug_2("\tcrm_state=%s, join_state=%s, expected=%s", crm_str(crm_state), crm_str(join_state), crm_str(exp_state)); } else { /* mark it unclean */ this_node->details->unclean = TRUE; crm_warn("Node %s is partially & un-expectedly down", this_node->details->uname); crm_info("\tha_state=%s, ccm_state=%s," " crm_state=%s, join_state=%s, expected=%s", crm_str(ha_state), crm_str(ccm_state), crm_str(crm_state), crm_str(join_state), crm_str(exp_state)); } return online; } static gboolean determine_online_status_fencing(crm_data_t * node_state, node_t *this_node) { gboolean online = FALSE; const char *join_state = crm_element_value(node_state, XML_CIB_ATTR_JOINSTATE); const char *crm_state = crm_element_value(node_state, XML_CIB_ATTR_CRMDSTATE); const char *ccm_state = crm_element_value(node_state, XML_CIB_ATTR_INCCM); const char *ha_state = crm_element_value(node_state, XML_CIB_ATTR_HASTATE); const char *exp_state = crm_element_value(node_state, XML_CIB_ATTR_EXPSTATE); if(crm_is_true(ccm_state) && (ha_state == NULL || safe_str_eq(ha_state, ACTIVESTATUS)) && safe_str_eq(crm_state, ONLINESTATUS) && safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER)) { online = TRUE; } else if(crm_is_true(ccm_state) == FALSE /* && safe_str_eq(ha_state, DEADSTATUS) */ && safe_str_eq(crm_state, OFFLINESTATUS) && this_node->details->expected_up == FALSE) { crm_debug("Node %s is down: join_state=%s, expected=%s", this_node->details->uname, crm_str(join_state), crm_str(exp_state)); } else if(this_node->details->expected_up == FALSE) { crm_info("Node %s is comming up", this_node->details->uname); crm_debug("\tha_state=%s, ccm_state=%s," " crm_state=%s, join_state=%s, expected=%s", crm_str(ha_state), crm_str(ccm_state), crm_str(crm_state), crm_str(join_state), crm_str(exp_state)); } else { /* mark it unclean */ this_node->details->unclean = TRUE; crm_warn("Node %s (%s) is un-expectedly down", this_node->details->uname, this_node->details->id); crm_info("\tha_state=%s, ccm_state=%s," " crm_state=%s, join_state=%s, expected=%s", crm_str(ha_state), crm_str(ccm_state), crm_str(crm_state), crm_str(join_state), crm_str(exp_state)); } return online; } gboolean determine_online_status( crm_data_t * node_state, node_t *this_node, pe_working_set_t *data_set) { int shutdown = 0; gboolean online = FALSE; const char *exp_state = crm_element_value(node_state, XML_CIB_ATTR_EXPSTATE); if(this_node == NULL) { pe_config_err("No node to check"); return online; } ha_msg_value_int(node_state, XML_CIB_ATTR_SHUTDOWN, &shutdown); this_node->details->expected_up = FALSE; if(safe_str_eq(exp_state, CRMD_JOINSTATE_MEMBER)) { this_node->details->expected_up = TRUE; } this_node->details->shutdown = FALSE; if(shutdown != 0) { this_node->details->shutdown = TRUE; this_node->details->expected_up = FALSE; } if(data_set->stonith_enabled == FALSE) { online = determine_online_status_no_fencing( node_state, this_node); } else { online = determine_online_status_fencing( node_state, this_node); } if(online) { this_node->details->online = TRUE; } else { /* remove node from contention */ this_node->fixed = TRUE; this_node->weight = -INFINITY; } if(online && this_node->details->shutdown) { /* dont run resources here */ this_node->fixed = TRUE; this_node->weight = -INFINITY; } if(this_node->details->unclean) { pe_proc_warn("Node %s is unclean", this_node->details->uname); } else if(this_node->details->online) { crm_info("Node %s is %s", this_node->details->uname, this_node->details->shutdown?"shutting down":"online"); } else { crm_debug_2("Node %s is offline", this_node->details->uname); } return online; } #define set_char(x) last_rsc_id[len] = x; complete = TRUE; static void increment_clone(char *last_rsc_id) { gboolean complete = FALSE; int len = 0; CRM_CHECK(last_rsc_id != NULL, return); if(last_rsc_id != NULL) { len = strlen(last_rsc_id); } len--; while(complete == FALSE && len > 0) { switch (last_rsc_id[len]) { case 0: len--; break; case '0': set_char('1'); break; case '1': set_char('2'); break; case '2': set_char('3'); break; case '3': set_char('4'); break; case '4': set_char('5'); break; case '5': set_char('6'); break; case '6': set_char('7'); break; case '7': set_char('8'); break; case '8': set_char('9'); break; case '9': last_rsc_id[len] = '0'; len--; break; default: crm_err("Unexpected char: %c (%d)", last_rsc_id[len], len); break; } } } extern gboolean DeleteRsc(resource_t *rsc, node_t *node, pe_working_set_t *data_set); static resource_t * unpack_find_resource( pe_working_set_t *data_set, node_t *node, const char *rsc_id) { resource_t *rsc = NULL; gboolean is_duped_clone = FALSE; char *alt_rsc_id = crm_strdup(rsc_id); while(rsc == NULL) { crm_debug_3("looking for: %s", alt_rsc_id); rsc = pe_find_resource(data_set->resources, alt_rsc_id); /* no match */ if(rsc == NULL) { crm_debug_3("not found"); break; /* not running anywhere else */ } else if(rsc->running_on == NULL) { crm_debug_3("not active yet"); break; /* always unique */ } else if(rsc->globally_unique) { crm_debug_3("unique"); break; /* running somewhere already but we dont care * find another clone instead */ } else { crm_debug_2("find another one"); rsc = NULL; is_duped_clone = TRUE; increment_clone(alt_rsc_id); } } crm_free(alt_rsc_id); if(is_duped_clone && rsc != NULL) { crm_info("Internally renamed %s on %s to %s", rsc_id, node->details->uname, rsc->id); /* rsc->name = rsc_id; */ } return rsc; } static resource_t * process_orphan_resource(crm_data_t *rsc_entry, node_t *node, pe_working_set_t *data_set) { resource_t *rsc = NULL; gboolean is_duped_clone = FALSE; const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID); crm_data_t *xml_rsc = create_xml_node(NULL, XML_CIB_TAG_RESOURCE); crm_log_xml_info(rsc_entry, "Orphan resource"); pe_config_warn("Nothing known about resource %s running on %s", rsc_id, node->details->uname); if(pe_find_resource(data_set->resources, rsc_id) != NULL) { is_duped_clone = TRUE; } copy_in_properties(xml_rsc, rsc_entry); common_unpack(xml_rsc, &rsc, NULL, data_set); rsc->orphan = TRUE; data_set->resources = g_list_append(data_set->resources, rsc); if(data_set->stop_rsc_orphans == FALSE && is_duped_clone == FALSE) { rsc->is_managed = FALSE; } else { crm_info("Making sure orphan %s is stopped", rsc_id); print_resource(LOG_DEBUG_3, "Added orphan", rsc, FALSE); CRM_CHECK(rsc != NULL, return NULL); slist_iter( any_node, node_t, data_set->nodes, lpc, rsc2node_new( "__orphan_dont_run__", rsc, -INFINITY, any_node, data_set); ); } return rsc; } static gboolean check_rsc_parameters(resource_t *rsc, node_t *node, crm_data_t *rsc_entry, pe_working_set_t *data_set) { int attr_lpc = 0; gboolean force_restart = FALSE; gboolean delete_resource = FALSE; const char *value = NULL; const char *old_value = NULL; const char *attr_list[] = { XML_ATTR_TYPE, XML_AGENT_ATTR_CLASS, XML_AGENT_ATTR_PROVIDER }; for(; attr_lpc < DIMOF(attr_list); attr_lpc++) { value = crm_element_value(rsc->xml, attr_list[attr_lpc]); old_value = crm_element_value(rsc_entry, attr_list[attr_lpc]); if(safe_str_eq(value, old_value)) { continue; } force_restart = TRUE; crm_notice("Forcing restart of %s on %s, %s changed: %s -> %s", rsc->id, node->details->uname, attr_list[attr_lpc], crm_str(old_value), crm_str(value)); } if(force_restart) { /* make sure the restart happens */ stop_action(rsc, node, FALSE); rsc->start_pending = TRUE; delete_resource = TRUE; } return delete_resource; } static void process_rsc_state(resource_t *rsc, node_t *node, enum action_fail_response on_fail, pe_working_set_t *data_set) { crm_debug_2("Resource %s is %s on %s", rsc->id, role2text(rsc->role), node->details->uname); rsc->known_on = g_list_append(rsc->known_on, node); if(rsc->role != RSC_ROLE_STOPPED) { if(on_fail != action_fail_ignore) { rsc->failed = TRUE; crm_debug_2("Force stop"); } crm_debug_2("Adding %s to %s", rsc->id, node->details->uname); native_add_running(rsc, node, data_set); if(on_fail == action_fail_ignore) { /* nothing to do */ } else if(node->details->unclean) { stop_action(rsc, node, FALSE); } else if(on_fail == action_fail_fence) { /* treat it as if it is still running * but also mark the node as unclean */ node->details->unclean = TRUE; stop_action(rsc, node, FALSE); } else if(on_fail == action_fail_block) { /* is_managed == FALSE will prevent any * actions being sent for the resource */ rsc->is_managed = FALSE; } else if(on_fail == action_fail_migrate) { stop_action(rsc, node, FALSE); /* make sure it comes up somewhere else * or not at all */ rsc2node_new("__action_migration_auto__", rsc, -INFINITY, node, data_set); } else { stop_action(rsc, node, FALSE); } } else { char *key = stop_key(rsc); GListPtr possible_matches = find_actions(rsc->actions, key, node); slist_iter(stop, action_t, possible_matches, lpc, stop->optional = TRUE; ); crm_free(key); /* if(rsc->failed == FALSE && node->details->online) { */ /* delete_resource = TRUE; */ /* } */ } } static const char * get_interval(crm_data_t *xml_op) { const char *interval_s = NULL; interval_s = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL); #if CRM_DEPRECATED_SINCE_2_0_4 if(interval_s == NULL) { crm_data_t *params = NULL; params = find_xml_node(xml_op, XML_TAG_PARAMS, FALSE); if(params != NULL) { interval_s = crm_element_value( params, XML_LRM_ATTR_INTERVAL); } } #endif CRM_CHECK(interval_s != NULL, crm_err("Invalid rsc op: %s", ID(xml_op)); return "0"); return interval_s; } static void unpack_lrm_rsc_state( node_t *node, crm_data_t * rsc_entry, pe_working_set_t *data_set) { int fail_count = 0; char *fail_attr = NULL; const char *value = NULL; const char *fail_val = NULL; gboolean delete_resource = FALSE; const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID); int max_call_id = -1; GListPtr op_list = NULL; GListPtr sorted_op_list = NULL; enum action_fail_response on_fail = FALSE; enum rsc_role_e saved_role = RSC_ROLE_UNKNOWN; resource_t *rsc = unpack_find_resource(data_set, node, rsc_id); crm_debug_3("[%s] Processing %s on %s", crm_element_name(rsc_entry), rsc_id, node->details->uname); if(rsc == NULL) { rsc = process_orphan_resource(rsc_entry, node, data_set); } CRM_ASSERT(rsc != NULL); delete_resource = check_rsc_parameters(rsc, node, rsc_entry, data_set); /* process failure stickiness */ fail_count = 0; fail_attr = crm_concat("fail-count", rsc->id, '-'); fail_val = g_hash_table_lookup(node->details->attrs, fail_attr); if(fail_val != NULL) { crm_debug("%s: %s", fail_attr, fail_val); fail_count = crm_parse_int(fail_val, "0"); } crm_free(fail_attr); if(fail_count > 0 && rsc->fail_stickiness != 0) { rsc2node_new("fail_stickiness", rsc, fail_count * rsc->fail_stickiness, node, data_set); crm_debug("Setting failure stickiness for %s on %s: %d", rsc->id, node->details->uname, fail_count * rsc->fail_stickiness); } /* process operations */ max_call_id = -1; op_list = NULL; sorted_op_list = NULL; xml_child_iter_filter( rsc_entry, rsc_op, XML_LRM_TAG_RSC_OP, op_list = g_list_append(op_list, rsc_op); ); if(op_list != NULL) { int stop_index = -1; int start_index = -1; const char *task = NULL; const char *status = NULL; saved_role = rsc->role; on_fail = action_fail_ignore; rsc->role = RSC_ROLE_STOPPED; sorted_op_list = g_list_sort(op_list, sort_op_by_callid); slist_iter( rsc_op, crm_data_t, sorted_op_list, lpc, task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); status = crm_element_value(rsc_op, XML_LRM_ATTR_OPSTATUS); if(safe_str_eq(task, CRMD_ACTION_STOP) && safe_str_eq(status, "0")) { stop_index = lpc; } else if(safe_str_eq(task, CRMD_ACTION_START)) { start_index = lpc; } else if(start_index <= stop_index && safe_str_eq(task, CRMD_ACTION_STATUS)) { const char *rc = crm_element_value(rsc_op, XML_LRM_ATTR_RC); if(safe_str_eq(rc, "0") || safe_str_eq(rc, "8")) { start_index = lpc; } } unpack_rsc_op(rsc, node, rsc_op, &max_call_id, &on_fail, data_set); ); crm_debug_2("%s: Start index %d, stop index = %d", rsc->id, start_index, stop_index); slist_iter(rsc_op, crm_data_t, sorted_op_list, lpc, int interval = 0; char *key = NULL; const char *id = ID(rsc_op); const char *interval_s = NULL; if(node->details->online == FALSE) { crm_debug_4("Skipping %s/%s: node is offline", rsc->id, node->details->uname); break; } else if(start_index < stop_index) { crm_debug_4("Skipping %s/%s: not active", rsc->id, node->details->uname); break; } else if(lpc <= start_index) { crm_debug_4("Skipping %s/%s: old", id, node->details->uname); continue; } interval_s = get_interval(rsc_op); interval = crm_parse_int(interval_s, "0"); if(interval == 0) { crm_debug_4("Skipping %s/%s: non-recurring", id, node->details->uname); continue; } status = crm_element_value(rsc_op, XML_LRM_ATTR_OPSTATUS); if(safe_str_eq(status, "-1")) { crm_debug_4("Skipping %s/%s: status", id, node->details->uname); continue; } task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); /* create the action */ key = generate_op_key(rsc->id, task, interval); crm_debug_3("Creating %s/%s", key, node->details->uname); custom_action(rsc, key, task, node, TRUE, TRUE, data_set); ); /* no need to free the contents */ g_list_free(sorted_op_list); process_rsc_state(rsc, node, on_fail, data_set); } value = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE); if(value != NULL && safe_str_neq("default", value)) { enum rsc_role_e req_role = text2role(value); if(req_role != RSC_ROLE_UNKNOWN && req_role != rsc->next_role){ if(rsc->next_role != RSC_ROLE_UNKNOWN) { crm_debug("%s: Overwriting calculated next role %s" " with requested next role %s", rsc->id, role2text(rsc->next_role), role2text(req_role)); } rsc->next_role = req_role; } } if(delete_resource) { DeleteRsc(rsc, node, data_set); } if(saved_role > rsc->role) { rsc->role = saved_role; } } gboolean unpack_lrm_resources(node_t *node, crm_data_t * lrm_rsc_list, pe_working_set_t *data_set) { CRM_CHECK(node != NULL, return FALSE); crm_debug_3("Unpacking resources on %s", node->details->uname); xml_child_iter_filter( lrm_rsc_list, rsc_entry, XML_LRM_TAG_RESOURCE, unpack_lrm_rsc_state(node, rsc_entry, data_set); ); return TRUE; } #define sort_return(an_int) crm_free(a_uuid); crm_free(b_uuid); return an_int gint sort_op_by_callid(gconstpointer a, gconstpointer b) { char *a_uuid = NULL; char *b_uuid = NULL; const char *a_task_id = cl_get_string(a, XML_LRM_ATTR_CALLID); const char *b_task_id = cl_get_string(b, XML_LRM_ATTR_CALLID); const char *a_key = cl_get_string(a, XML_ATTR_TRANSITION_MAGIC); const char *b_key = cl_get_string(b, XML_ATTR_TRANSITION_MAGIC); const char *a_xml_id = ID(a); const char *b_xml_id = ID(b); int a_id = -1; int b_id = -1; int a_rc = -1; int b_rc = -1; int a_status = -1; int b_status = -1; int a_call_id = -1; int b_call_id = -1; if(safe_str_eq(a_xml_id, b_xml_id)) { /* We have duplicate lrm_rsc_op entries in the status * section which is unliklely to be a good thing * - we can handle it easily enough, but we need to get * to the bottom of why its happening. */ pe_err("Duplicate lrm_rsc_op entries named %s", a_xml_id); sort_return(0); } CRM_CHECK(a_task_id != NULL && b_task_id != NULL, sort_return(0)); a_call_id = crm_parse_int(a_task_id, NULL); b_call_id = crm_parse_int(b_task_id, NULL); if(a_call_id == -1 && b_call_id == -1) { /* both are pending ops so it doesnt matter since * stops are never pending */ sort_return(0); } else if(a_call_id >= 0 && a_call_id < b_call_id) { crm_debug_4("%s (%d) < %s (%d) : call id", ID(a), a_call_id, ID(b), b_call_id); sort_return(-1); } else if(b_call_id >= 0 && a_call_id > b_call_id) { crm_debug_4("%s (%d) > %s (%d) : call id", ID(a), a_call_id, ID(b), b_call_id); sort_return(1); } crm_debug_5("%s (%d) == %s (%d) : continuing", ID(a), a_call_id, ID(b), b_call_id); /* now process pending ops */ CRM_CHECK(a_key != NULL && b_key != NULL, sort_return(0)); CRM_CHECK(decode_transition_magic( a_key,&a_uuid,&a_id,&a_status, &a_rc), sort_return(0)); CRM_CHECK(decode_transition_magic( b_key,&b_uuid,&b_id,&b_status, &b_rc), sort_return(0)); /* try and determin the relative age of the operation... * some pending operations (ie. a start) may have been supuerceeded * by a subsequent stop * * [a|b]_id == -1 means its a shutdown operation and _always_ comes last */ if(safe_str_neq(a_uuid, b_uuid) || a_id == b_id) { /* * some of the logic in here may be redundant... * * if the UUID from the TE doesnt match then one better * be a pending operation. * pending operations dont survive between elections and joins * because we query the LRM directly */ CRM_CHECK(a_call_id == -1 || b_call_id == -1, sort_return(0)); CRM_CHECK(a_call_id >= 0 || b_call_id >= 0, sort_return(0)); if(b_call_id == -1) { crm_debug_2("%s (%d) < %s (%d) : transition + call id", ID(a), a_call_id, ID(b), b_call_id); sort_return(-1); } if(a_call_id == -1) { crm_debug_2("%s (%d) > %s (%d) : transition + call id", ID(a), a_call_id, ID(b), b_call_id); sort_return(1); } } else if((a_id >= 0 && a_id < b_id) || b_id == -1) { crm_debug_3("%s (%d) < %s (%d) : transition", ID(a), a_id, ID(b), b_id); sort_return(-1); } else if((b_id >= 0 && a_id > b_id) || a_id == -1) { crm_debug_3("%s (%d) > %s (%d) : transition", ID(a), a_id, ID(b), b_id); sort_return(1); } /* we should never end up here */ crm_err("%s (%d:%d:%s) ?? %s (%d:%d:%s) : default", ID(a), a_call_id, a_id, a_uuid, ID(b), b_call_id, b_id, b_uuid); CRM_CHECK(FALSE, sort_return(0)); } static gboolean check_action_definition(resource_t *rsc, node_t *active_node, crm_data_t *xml_op, pe_working_set_t *data_set) { char *key = NULL; int interval = 0; const char *interval_s = NULL; gboolean did_change = FALSE; crm_data_t *pnow = NULL; GHashTable *local_rsc_params = NULL; char *pnow_digest = NULL; const char *param_digest = NULL; char *local_param_digest = NULL; #if CRM_DEPRECATED_SINCE_2_0_4 crm_data_t *params = NULL; #endif action_t *action = NULL; const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK); const char *op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION); CRM_CHECK(active_node != NULL, return FALSE); interval_s = get_interval(xml_op); interval = crm_parse_int(interval_s, "0"); key = generate_op_key(rsc->id, task, interval); if(interval > 0) { crm_data_t *op_match = NULL; crm_debug_2("Checking parameters for %s %s", key, task); op_match = find_rsc_op_entry(rsc, key); if(op_match == NULL && data_set->stop_action_orphans) { /* create a cancel action */ action_t *cancel = NULL; crm_info("Orphan action will be stopped: %s on %s", key, active_node->details->uname); crm_free(key); key = generate_op_key(rsc->id, CRMD_ACTION_CANCEL, interval); cancel = custom_action( rsc, key, CRMD_ACTION_CANCEL, active_node, FALSE, TRUE, data_set); add_hash_param(cancel->meta, XML_LRM_ATTR_TASK, task); add_hash_param(cancel->meta, XML_LRM_ATTR_INTERVAL, interval_s); custom_action_order( rsc, NULL, cancel, rsc, stop_key(rsc), NULL, pe_ordering_optional, data_set); } if(op_match == NULL) { crm_debug("Orphan action detected: %s on %s", key, active_node->details->uname); return TRUE; } } action = custom_action(rsc, key, task, active_node, TRUE, FALSE, data_set); local_rsc_params = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); unpack_instance_attributes( rsc->xml, XML_TAG_ATTR_SETS, active_node->details->attrs, local_rsc_params, NULL, data_set->now); pnow = create_xml_node(NULL, XML_TAG_PARAMS); g_hash_table_foreach(action->extra, hash2field, pnow); g_hash_table_foreach(rsc->parameters, hash2field, pnow); g_hash_table_foreach(local_rsc_params, hash2field, pnow); filter_action_parameters(pnow, op_version); pnow_digest = calculate_xml_digest(pnow, TRUE); param_digest = crm_element_value(xml_op, XML_LRM_ATTR_OP_DIGEST); #if CRM_DEPRECATED_SINCE_2_0_4 if(param_digest == NULL) { params = find_xml_node(xml_op, XML_TAG_PARAMS, TRUE); } if(params != NULL) { crm_data_t *local_params = copy_xml(params); crm_warn("Faking parameter digest creation for %s", ID(xml_op)); filter_action_parameters(local_params, op_version); xml_remove_prop(local_params, "interval"); xml_remove_prop(local_params, "timeout"); crm_log_xml_warn(local_params, "params:used"); local_param_digest = calculate_xml_digest(local_params, TRUE); param_digest = local_param_digest; free_xml(local_params); } #endif if(safe_str_neq(pnow_digest, param_digest)) { #if CRM_DEPRECATED_SINCE_2_0_4 if(params) { crm_data_t *local_params = copy_xml(params); filter_action_parameters(local_params, op_version); xml_remove_prop(local_params, "interval"); xml_remove_prop(local_params, "timeout"); free_xml(local_params); } #endif did_change = TRUE; crm_log_xml_info(pnow, "params:calc"); crm_warn("Parameters to %s on %s changed: recorded %s vs. calculated %s", ID(xml_op), active_node->details->uname, crm_str(param_digest), pnow_digest); key = generate_op_key(rsc->id, task, interval); custom_action(rsc, key, task, NULL, FALSE, TRUE, data_set); } free_xml(pnow); crm_free(pnow_digest); crm_free(local_param_digest); g_hash_table_destroy(local_rsc_params); pe_free_action(action); return did_change; } gboolean unpack_rsc_op(resource_t *rsc, node_t *node, crm_data_t *xml_op, int *max_call_id, enum action_fail_response *on_fail, pe_working_set_t *data_set) { const char *id = NULL; const char *task = NULL; const char *task_id = NULL; const char *actual_rc = NULL; /* const char *target_rc = NULL; */ const char *task_status = NULL; const char *interval_s = NULL; const char *op_digest = NULL; int interval = 0; int task_id_i = -1; int task_status_i = -2; int actual_rc_i = 0; action_t *action = NULL; gboolean is_probe = FALSE; gboolean is_stop_action = FALSE; CRM_CHECK(rsc != NULL, return FALSE); CRM_CHECK(node != NULL, return FALSE); CRM_CHECK(xml_op != NULL, return FALSE); id = ID(xml_op); task = crm_element_value(xml_op, XML_LRM_ATTR_TASK); task_id = crm_element_value(xml_op, XML_LRM_ATTR_CALLID); task_status = crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS); op_digest = crm_element_value(xml_op, XML_LRM_ATTR_OP_DIGEST); CRM_CHECK(id != NULL, return FALSE); CRM_CHECK(task != NULL, return FALSE); CRM_CHECK(task_status != NULL, return FALSE); task_status_i = crm_parse_int(task_status, NULL); CRM_CHECK(task_status_i <= LRM_OP_ERROR, return FALSE); CRM_CHECK(task_status_i >= LRM_OP_PENDING, return FALSE); if(safe_str_eq(task, CRMD_ACTION_NOTIFY)) { /* safe to ignore these */ return TRUE; } crm_debug_2("Unpacking task %s/%s (call_id=%s, status=%s) on %s (role=%s)", id, task, task_id, task_status, node->details->uname, role2text(rsc->role)); interval_s = get_interval(xml_op); interval = crm_parse_int(interval_s, "0"); if(interval == 0 && safe_str_eq(task, CRMD_ACTION_STATUS)) { is_probe = TRUE; } else if(interval > 0 && rsc->role < RSC_ROLE_STARTED) { crm_debug_2("Skipping recurring action %s for stopped resource", id); return FALSE; } if(rsc->orphan) { crm_debug_2("Skipping param check for orphan: %s %s", rsc->id, task); } else if(safe_str_eq(task, CRMD_ACTION_STOP)) { crm_debug_2("Ignoring stop params: %s", id); } else if(is_probe || safe_str_eq(task, CRMD_ACTION_START) || interval > 0) { crm_debug_3("Checking resource definition: %s", rsc->id); check_action_definition(rsc, node, xml_op, data_set); } if(safe_str_eq(task, CRMD_ACTION_STOP)) { is_stop_action = TRUE; } if(task_status_i != LRM_OP_PENDING) { task_id_i = crm_parse_int(task_id, "-1"); CRM_CHECK(task_id != NULL, return FALSE); CRM_CHECK(task_id_i >= 0, return FALSE); CRM_CHECK(task_id_i > *max_call_id, return FALSE); } if(*max_call_id < task_id_i) { *max_call_id = task_id_i; } if(node->details->unclean) { crm_debug_2("Node %s (where %s is running) is unclean." " Further action depends on the value of %s", node->details->uname, rsc->id, XML_RSC_ATTR_STOPFAIL); } actual_rc = crm_element_value(xml_op, XML_LRM_ATTR_RC); CRM_CHECK(actual_rc != NULL, return FALSE); actual_rc_i = crm_parse_int(actual_rc, NULL); if(EXECRA_NOT_RUNNING == actual_rc_i) { if(is_probe) { /* treat these like stops */ is_stop_action = TRUE; } if(is_stop_action) { task_status_i = LRM_OP_DONE; } else { CRM_CHECK(task_status_i == LRM_OP_ERROR, task_status_i = LRM_OP_ERROR); } } else if(EXECRA_RUNNING_MASTER == actual_rc_i) { if(is_probe || (rsc->role == RSC_ROLE_MASTER && safe_str_eq(task, CRMD_ACTION_STATUS))) { task_status_i = LRM_OP_DONE; } else { if(rsc->role != RSC_ROLE_MASTER) { crm_err("%s reported %s in master mode on %s", id, rsc->id, node->details->uname); } CRM_CHECK(task_status_i == LRM_OP_ERROR, task_status_i = LRM_OP_ERROR); } rsc->role = RSC_ROLE_MASTER; } else if(EXECRA_FAILED_MASTER == actual_rc_i) { rsc->role = RSC_ROLE_MASTER; task_status_i = LRM_OP_ERROR; } else if(EXECRA_OK == actual_rc_i && interval > 0 && rsc->role == RSC_ROLE_MASTER) { /* catch status ops that return 0 instead of 8 while they * are supposed to be in master mode */ task_status_i = LRM_OP_ERROR; } if(task_status_i == LRM_OP_ERROR || task_status_i == LRM_OP_TIMEOUT || task_status_i == LRM_OP_NOTSUPPORTED) { action = custom_action(rsc, crm_strdup(id), task, NULL, TRUE, FALSE, data_set); if(action->on_fail == action_fail_ignore) { task_status_i = LRM_OP_DONE; } } switch(task_status_i) { case LRM_OP_PENDING: if(safe_str_eq(task, CRMD_ACTION_START)) { rsc->start_pending = TRUE; rsc->role = RSC_ROLE_STARTED; } else if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) { rsc->role = RSC_ROLE_MASTER; } break; case LRM_OP_DONE: crm_debug_3("%s/%s completed on %s", rsc->id, task, node->details->uname); if(is_stop_action) { rsc->role = RSC_ROLE_STOPPED; /* clear any previous failure actions */ *on_fail = action_fail_ignore; rsc->next_role = RSC_ROLE_UNKNOWN; } else if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) { rsc->role = RSC_ROLE_MASTER; } else if(safe_str_eq(task, CRMD_ACTION_DEMOTE)) { rsc->role = RSC_ROLE_SLAVE; } else if(rsc->role < RSC_ROLE_STARTED) { crm_debug_3("%s active on %s", rsc->id, node->details->uname); rsc->role = RSC_ROLE_STARTED; } break; case LRM_OP_ERROR: case LRM_OP_TIMEOUT: case LRM_OP_NOTSUPPORTED: crm_warn("Processing failed op (%s) for %s on %s", id, rsc->id, node->details->uname); if(*on_fail < action->on_fail) { *on_fail = action->on_fail; } if(task_status_i == LRM_OP_NOTSUPPORTED || is_stop_action || safe_str_eq(task, CRMD_ACTION_START) ) { crm_warn("Handling failed %s for %s on %s", task, rsc->id, node->details->uname); rsc2node_new("dont_run__failed_stopstart", rsc, -INFINITY, node, data_set); } if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) { rsc->role = RSC_ROLE_MASTER; } else if(safe_str_eq(task, CRMD_ACTION_DEMOTE)) { rsc->role = RSC_ROLE_MASTER; } else if(rsc->role < RSC_ROLE_STARTED) { rsc->role = RSC_ROLE_STARTED; } crm_debug_2("Resource %s: role=%s, unclean=%s, on_fail=%s, fail_role=%s", rsc->id, role2text(rsc->role), node->details->unclean?"true":"false", fail2text(action->on_fail), role2text(action->fail_role)); if(action->fail_role != RSC_ROLE_STARTED && rsc->next_role < action->fail_role) { rsc->next_role = action->fail_role; } if(action->fail_role == RSC_ROLE_STOPPED) { + crm_err("Making sure %s doesn't come up again", rsc->id); /* make sure it doesnt come up again */ pe_free_shallow_adv(rsc->allowed_nodes, TRUE); rsc->allowed_nodes = node_list_dup( data_set->nodes, FALSE, FALSE); slist_iter( node, node_t, rsc->allowed_nodes, lpc, node->weight = -INFINITY; ); } pe_free_action(action); action = NULL; break; case LRM_OP_CANCELLED: /* do nothing?? */ pe_err("Dont know what to do for cancelled ops yet"); break; } crm_debug_3("Resource %s after %s: role=%s", rsc->id, task, role2text(rsc->role)); pe_free_action(action); return TRUE; } gboolean rsc_colocation_new(const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh, const char *state_lh, const char *state_rh) { rsc_colocation_t *new_con = NULL; rsc_colocation_t *inverted_con = NULL; if(rsc_lh == NULL){ pe_config_err("No resource found for LHS %s", id); return FALSE; } else if(rsc_rh == NULL){ pe_config_err("No resource found for RHS of %s", id); return FALSE; } crm_malloc0(new_con, sizeof(rsc_colocation_t)); if(new_con == NULL) { return FALSE; } if(safe_str_eq(state_lh, CRMD_ACTION_STARTED)) { state_lh = NULL; } if(safe_str_eq(state_rh, CRMD_ACTION_STARTED)) { state_rh = NULL; } new_con->id = id; new_con->rsc_lh = rsc_lh; new_con->rsc_rh = rsc_rh; new_con->strength = strength; new_con->state_lh = state_lh; new_con->state_rh = state_rh; inverted_con = invert_constraint(new_con); crm_debug_4("Adding constraint %s (%p) to %s", new_con->id, new_con, rsc_lh->id); rsc_lh->rsc_cons = g_list_insert_sorted( rsc_lh->rsc_cons, new_con, sort_cons_strength); crm_debug_4("Adding constraint %s (%p) to %s", inverted_con->id, inverted_con, rsc_rh->id); rsc_rh->rsc_cons = g_list_insert_sorted( rsc_rh->rsc_cons, inverted_con, sort_cons_strength); return TRUE; } /* LHS before RHS */ gboolean custom_action_order( resource_t *lh_rsc, char *lh_action_task, action_t *lh_action, resource_t *rh_rsc, char *rh_action_task, action_t *rh_action, enum pe_ordering type, pe_working_set_t *data_set) { order_constraint_t *order = NULL; if((lh_action == NULL && lh_rsc == NULL) || (rh_action == NULL && rh_rsc == NULL)){ pe_config_err("Invalid inputs lh_rsc=%p, lh_a=%p," " rh_rsc=%p, rh_a=%p", lh_rsc, lh_action, rh_rsc, rh_action); crm_free(lh_action_task); crm_free(rh_action_task); return FALSE; } crm_malloc0(order, sizeof(order_constraint_t)); if(order == NULL) { return FALSE; } order->id = data_set->order_id++; order->type = type; order->lh_rsc = lh_rsc; order->rh_rsc = rh_rsc; order->lh_action = lh_action; order->rh_action = rh_action; order->lh_action_task = lh_action_task; order->rh_action_task = rh_action_task; data_set->ordering_constraints = g_list_append( data_set->ordering_constraints, order); if(lh_rsc != NULL && rh_rsc != NULL) { crm_debug_4("Created ordering constraint %d (%s):" " %s/%s before %s/%s", order->id, ordering_type2text(order->type), lh_rsc->id, lh_action_task, rh_rsc->id, rh_action_task); } else if(lh_rsc != NULL) { crm_debug_4("Created ordering constraint %d (%s):" " %s/%s before action %d (%s)", order->id, ordering_type2text(order->type), lh_rsc->id, lh_action_task, rh_action->id, rh_action_task); } else if(rh_rsc != NULL) { crm_debug_4("Created ordering constraint %d (%s):" " action %d (%s) before %s/%s", order->id, ordering_type2text(order->type), lh_action->id, lh_action_task, rh_rsc->id, rh_action_task); } else { crm_debug_4("Created ordering constraint %d (%s):" " action %d (%s) before action %d (%s)", order->id, ordering_type2text(order->type), lh_action->id, lh_action_task, rh_action->id, rh_action_task); } return TRUE; } gboolean unpack_rsc_colocation(crm_data_t * xml_obj, pe_working_set_t *data_set) { enum con_strength strength_e = pecs_ignore; const char *id = crm_element_value(xml_obj, XML_ATTR_ID); const char *id_rh = crm_element_value(xml_obj, XML_CONS_ATTR_TO); const char *id_lh = crm_element_value(xml_obj, XML_CONS_ATTR_FROM); const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE); const char *state_lh = crm_element_value(xml_obj, XML_RULE_ATTR_FROMSTATE); const char *state_rh = crm_element_value(xml_obj, XML_RULE_ATTR_TOSTATE); resource_t *rsc_lh = pe_find_resource(data_set->resources, id_lh); resource_t *rsc_rh = pe_find_resource(data_set->resources, id_rh); if(rsc_lh == NULL) { pe_config_err("No resource (con=%s, rsc=%s)", id, id_lh); return FALSE; } else if(rsc_rh == NULL) { pe_config_err("No resource (con=%s, rsc=%s)", id, id_rh); return FALSE; } /* the docs indicate that only +/- INFINITY are allowed, * but no-one ever reads the docs so all positive values will * count as "must" and negative values as "must not" */ if(score == NULL || score[0] != '-') { strength_e = pecs_must; } else { strength_e = pecs_must_not; } return rsc_colocation_new(id, strength_e, rsc_lh, rsc_rh, state_lh, state_rh); } static const char * invert_action(const char *action) { if(safe_str_eq(action, CRMD_ACTION_START)) { return CRMD_ACTION_STOP; } else if(safe_str_eq(action, CRMD_ACTION_STOP)) { return CRMD_ACTION_START; } else if(safe_str_eq(action, CRMD_ACTION_PROMOTE)) { return CRMD_ACTION_DEMOTE; } else if(safe_str_eq(action, CRMD_ACTION_DEMOTE)) { return CRMD_ACTION_PROMOTE; } else if(safe_str_eq(action, CRMD_ACTION_STARTED)) { return CRMD_ACTION_STOPPED; } else if(safe_str_eq(action, CRMD_ACTION_STOPPED)) { return CRMD_ACTION_STARTED; } pe_err("Unknown action: %s", action); return NULL; } gboolean unpack_rsc_order(crm_data_t * xml_obj, pe_working_set_t *data_set) { gboolean symmetrical_bool = TRUE; const char *id = crm_element_value(xml_obj, XML_ATTR_ID); const char *type = crm_element_value(xml_obj, XML_ATTR_TYPE); const char *id_rh = crm_element_value(xml_obj, XML_CONS_ATTR_TO); const char *id_lh = crm_element_value(xml_obj, XML_CONS_ATTR_FROM); const char *action = crm_element_value(xml_obj, XML_CONS_ATTR_ACTION); const char *action_rh = crm_element_value(xml_obj, XML_CONS_ATTR_TOACTION); const char *symmetrical = crm_element_value( xml_obj, XML_CONS_ATTR_SYMMETRICAL); resource_t *rsc_lh = NULL; resource_t *rsc_rh = NULL; if(xml_obj == NULL) { pe_config_err("No constraint object to process."); return FALSE; } else if(id == NULL) { pe_config_err("%s constraint must have an id", crm_element_name(xml_obj)); return FALSE; } else if(id_lh == NULL || id_rh == NULL) { pe_config_err("Constraint %s needs two sides lh: %s rh: %s", id, crm_str(id_lh), crm_str(id_rh)); return FALSE; } if(action == NULL) { action = CRMD_ACTION_START; } if(action_rh == NULL) { action_rh = action; } CRM_CHECK(action != NULL, return FALSE); CRM_CHECK(action_rh != NULL, return FALSE); if(safe_str_eq(type, "before")) { id_lh = crm_element_value(xml_obj, XML_CONS_ATTR_TO); id_rh = crm_element_value(xml_obj, XML_CONS_ATTR_FROM); action = crm_element_value(xml_obj, XML_CONS_ATTR_TOACTION); action_rh = crm_element_value(xml_obj, XML_CONS_ATTR_ACTION); if(action_rh == NULL) { action_rh = CRMD_ACTION_START; } if(action == NULL) { action = action_rh; } } CRM_CHECK(action != NULL, return FALSE); CRM_CHECK(action_rh != NULL, return FALSE); rsc_lh = pe_find_resource(data_set->resources, id_rh); rsc_rh = pe_find_resource(data_set->resources, id_lh); if(rsc_lh == NULL) { pe_config_err("Constraint %s: no resource found for LHS of %s", id, id_lh); return FALSE; } else if(rsc_rh == NULL) { pe_config_err("Constraint %s: no resource found for RHS of %s", id, id_rh); return FALSE; } custom_action_order( rsc_lh, generate_op_key(rsc_lh->id, action, 0), NULL, rsc_rh, generate_op_key(rsc_rh->id, action_rh, 0), NULL, pe_ordering_optional, data_set); if(rsc_rh->restart_type == pe_restart_restart && safe_str_eq(action, action_rh)) { if(safe_str_eq(action, CRMD_ACTION_START)) { crm_debug_2("Recover start-start: %s-%s", rsc_lh->id, rsc_rh->id); order_start_start(rsc_lh, rsc_rh, pe_ordering_recover); } else if(safe_str_eq(action, CRMD_ACTION_STOP)) { crm_debug_2("Recover stop-stop: %s-%s", rsc_rh->id, rsc_lh->id); order_stop_stop(rsc_rh, rsc_lh, pe_ordering_recover); } } cl_str_to_boolean(symmetrical, &symmetrical_bool); if(symmetrical_bool == FALSE) { return TRUE; } action = invert_action(action); action_rh = invert_action(action_rh); custom_action_order( rsc_rh, generate_op_key(rsc_rh->id, action_rh, 0), NULL, rsc_lh, generate_op_key(rsc_lh->id, action, 0), NULL, pe_ordering_optional, data_set); if(rsc_lh->restart_type == pe_restart_restart && safe_str_eq(action, action_rh)) { if(safe_str_eq(action, CRMD_ACTION_START)) { crm_debug_2("Recover start-start (2): %s-%s", rsc_lh->id, rsc_rh->id); order_start_start(rsc_lh, rsc_rh, pe_ordering_recover); } else if(safe_str_eq(action, CRMD_ACTION_STOP)) { crm_debug_2("Recover stop-stop (2): %s-%s", rsc_rh->id, rsc_lh->id); order_stop_stop(rsc_rh, rsc_lh, pe_ordering_recover); } } return TRUE; } gboolean add_node_attrs(crm_data_t *xml_obj, node_t *node, pe_working_set_t *data_set) { g_hash_table_insert(node->details->attrs, crm_strdup("#"XML_ATTR_UNAME), crm_strdup(node->details->uname)); g_hash_table_insert(node->details->attrs, crm_strdup("#"XML_ATTR_ID), crm_strdup(node->details->id)); if(safe_str_eq(node->details->id, data_set->dc_uuid)) { data_set->dc_node = node; node->details->is_dc = TRUE; g_hash_table_insert(node->details->attrs, crm_strdup("#"XML_ATTR_DC), crm_strdup(XML_BOOLEAN_TRUE)); } else { g_hash_table_insert(node->details->attrs, crm_strdup("#"XML_ATTR_DC), crm_strdup(XML_BOOLEAN_FALSE)); } unpack_instance_attributes( xml_obj, XML_TAG_ATTR_SETS, NULL, node->details->attrs, NULL, data_set->now); return TRUE; } gboolean unpack_rsc_location(crm_data_t * xml_obj, pe_working_set_t *data_set) { const char *id_lh = crm_element_value(xml_obj, "rsc"); const char *id = crm_element_value(xml_obj, XML_ATTR_ID); resource_t *rsc_lh = pe_find_resource(data_set->resources, id_lh); if(rsc_lh == NULL) { /* only a warn as BSC adds the constraint then the resource */ pe_config_warn("No resource (con=%s, rsc=%s)", id, id_lh); return FALSE; } else if(rsc_lh->is_managed == FALSE) { crm_debug_2("Ignoring constraint %s: resource %s not managed", id, id_lh); return FALSE; } xml_child_iter_filter( xml_obj, rule_xml, XML_TAG_RULE, crm_debug_2("Unpacking %s/%s", id, ID(rule_xml)); generate_location_rule(rsc_lh, rule_xml, data_set); ); return TRUE; } rsc_to_node_t * generate_location_rule( resource_t *rsc, crm_data_t *rule_xml, pe_working_set_t *data_set) { const char *rule_id = NULL; const char *score = NULL; const char *boolean = NULL; const char *role = NULL; const char *attr_score = NULL; GListPtr match_L = NULL; int score_f = 0; gboolean do_and = TRUE; gboolean accept = TRUE; gboolean raw_score = TRUE; rsc_to_node_t *location_rule = NULL; rule_id = crm_element_value(rule_xml, XML_ATTR_ID); boolean = crm_element_value(rule_xml, XML_RULE_ATTR_BOOLEAN_OP); role = crm_element_value(rule_xml, XML_RULE_ATTR_ROLE); crm_debug_2("Processing rule: %s", rule_id); if(role != NULL && text2role(role) == RSC_ROLE_UNKNOWN) { pe_err("Bad role specified for %s: %s", rule_id, role); return NULL; } score = crm_element_value(rule_xml, XML_RULE_ATTR_SCORE); if(score != NULL) { score_f = char2score(score); } else { score = crm_element_value( rule_xml, XML_RULE_ATTR_SCORE_ATTRIBUTE); if(score == NULL) { score = crm_element_value( rule_xml, XML_RULE_ATTR_SCORE_MANGLED); } if(score != NULL) { raw_score = FALSE; } } if(safe_str_eq(boolean, "or")) { do_and = FALSE; } location_rule = rsc2node_new(rule_id, rsc, 0, NULL, data_set); if(location_rule == NULL) { return NULL; } if(role != NULL) { crm_debug_2("Setting role filter: %s", role); location_rule->role_filter = text2role(role); } if(do_and) { match_L = node_list_dup(data_set->nodes, TRUE, FALSE); slist_iter( node, node_t, match_L, lpc, node->weight = score_f; ); } xml_child_iter( rule_xml, expr, enum expression_type type = find_expression_type(expr); if(type == not_expr) { pe_err("Expression <%s id=%s...> is not valid", crm_element_name(expr), crm_str(ID(expr))); continue; } slist_iter( node, node_t, data_set->nodes, lpc, if(type == nested_rule) { accept = test_rule( expr, node->details->attrs, RSC_ROLE_UNKNOWN, data_set->now); } else { accept = test_expression( expr, node->details->attrs, RSC_ROLE_UNKNOWN, data_set->now); } if(raw_score == FALSE) { attr_score = g_hash_table_lookup( node->details->attrs, score); if(attr_score == NULL) { accept = FALSE; pe_warn("node %s did not have a value" " for %s", node->details->uname, score); } else { score_f = char2score(score); } } if(!do_and && accept) { node_t *local = pe_find_node_id( match_L, node->details->id); if(local == NULL) { local = node_copy(node); match_L = g_list_append(match_L, local); } local->weight = merge_weights( local->weight, score_f); crm_debug_5("node %s already matched", node->details->uname); } else if(do_and && !accept) { /* remove it */ node_t *delete = pe_find_node_id( match_L, node->details->id); if(delete != NULL) { match_L = g_list_remove(match_L,delete); crm_debug_5("node %s did not match", node->details->uname); } crm_free(delete); } ); ); location_rule->node_list_rh = match_L; if(location_rule->node_list_rh == NULL) { crm_debug_2("No matching nodes for rule %s", rule_id); return NULL; } crm_debug_3("%s: %d nodes matched", rule_id, g_list_length(location_rule->node_list_rh)); crm_action_debug_3(print_rsc_to_node("Added", location_rule, FALSE)); return location_rule; } diff --git a/lib/crm/pengine/utils.c b/lib/crm/pengine/utils.c index 3d2de26e14..1d1392b009 100644 --- a/lib/crm/pengine/utils.c +++ b/lib/crm/pengine/utils.c @@ -1,1660 +1,1660 @@ -/* $Id: utils.c,v 1.2 2006/06/02 15:34:18 andrew Exp $ */ +/* $Id: utils.c,v 1.3 2006/06/07 12:46:56 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 void print_str_str(gpointer key, gpointer value, gpointer user_data); gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data); void unpack_operation( action_t *action, crm_data_t *xml_obj, pe_working_set_t* data_set); void pe_free_shallow(GListPtr alist) { pe_free_shallow_adv(alist, TRUE); } void pe_free_shallow_adv(GListPtr alist, gboolean with_data) { GListPtr item; GListPtr item_next = alist; while(item_next != NULL) { item = item_next; item_next = item_next->next; if(with_data) { /* crm_debug_5("freeing %p", item->data); */ crm_free(item->data); } item->data = NULL; item->next = NULL; g_list_free(item); } } node_t * pe_find_node_id(GListPtr nodes, const char *id) { unsigned lpc = 0; node_t *node = NULL; for(lpc = 0; lpc < g_list_length(nodes); lpc++) { node = g_list_nth_data(nodes, lpc); if(safe_str_eq(node->details->id, id)) { return node; } } /* error */ return NULL; } node_t * node_copy(node_t *this_node) { node_t *new_node = NULL; CRM_CHECK(this_node != NULL, return NULL); crm_malloc0(new_node, sizeof(node_t)); CRM_CHECK(new_node != NULL, return NULL); crm_debug_5("Copying %p (%s) to %p", this_node, this_node->details->uname, new_node); new_node->weight = this_node->weight; new_node->fixed = this_node->fixed; new_node->details = this_node->details; return new_node; } /* are the contents of list1 and list2 equal * nodes with weight < 0 are ignored if filter == TRUE * * slow but linear * */ gboolean node_list_eq(GListPtr list1, GListPtr list2, gboolean filter) { node_t *other_node; GListPtr lhs = list1; GListPtr rhs = list2; slist_iter( node, node_t, lhs, lpc, if(node == NULL || (filter && node->weight < 0)) { continue; } other_node = (node_t*) pe_find_node_id(rhs, node->details->id); if(other_node == NULL || other_node->weight < 0) { return FALSE; } ); lhs = list2; rhs = list1; slist_iter( node, node_t, lhs, lpc, if(node == NULL || (filter && node->weight < 0)) { continue; } other_node = (node_t*) pe_find_node_id(rhs, node->details->id); if(other_node == NULL || other_node->weight < 0) { return FALSE; } ); return TRUE; } /* the intersection of list1 and list2 */ GListPtr node_list_and(GListPtr list1, GListPtr list2, gboolean filter) { GListPtr result = NULL; unsigned lpc = 0; for(lpc = 0; lpc < g_list_length(list1); lpc++) { node_t *node = (node_t*)g_list_nth_data(list1, lpc); node_t *other_node = pe_find_node_id(list2, node->details->id); node_t *new_node = NULL; if(other_node != NULL) { new_node = node_copy(node); } if(new_node != NULL) { crm_debug_4("%s: %d + %d", node->details->uname, other_node->weight, new_node->weight); new_node->weight = merge_weights( new_node->weight, other_node->weight); crm_debug_3("New node weight for %s: %d", new_node->details->uname, new_node->weight); if(filter && new_node->weight < 0) { crm_free(new_node); new_node = NULL; } } if(new_node != NULL) { result = g_list_append(result, new_node); } } return result; } /* list1 - list2 */ GListPtr node_list_minus(GListPtr list1, GListPtr list2, gboolean filter) { GListPtr result = NULL; slist_iter( node, node_t, list1, lpc, node_t *other_node = pe_find_node_id(list2, node->details->id); node_t *new_node = NULL; if(node == NULL || other_node != NULL || (filter && node->weight < 0)) { continue; } new_node = node_copy(node); result = g_list_append(result, new_node); ); crm_debug_3("Minus result len: %d", g_list_length(result)); return result; } /* list1 + list2 - (intersection of list1 and list2) */ GListPtr node_list_xor(GListPtr list1, GListPtr list2, gboolean filter) { GListPtr result = NULL; slist_iter( node, node_t, list1, lpc, node_t *new_node = NULL; node_t *other_node = (node_t*) pe_find_node_id(list2, node->details->id); if(node == NULL || other_node != NULL || (filter && node->weight < 0)) { continue; } new_node = node_copy(node); result = g_list_append(result, new_node); ); slist_iter( node, node_t, list2, lpc, node_t *new_node = NULL; node_t *other_node = (node_t*) pe_find_node_id(list1, node->details->id); if(node == NULL || other_node != NULL || (filter && node->weight < 0)) { continue; } new_node = node_copy(node); result = g_list_append(result, new_node); ); crm_debug_3("Xor result len: %d", g_list_length(result)); return result; } GListPtr node_list_or(GListPtr list1, GListPtr list2, gboolean filter) { node_t *other_node = NULL; GListPtr result = NULL; gboolean needs_filter = FALSE; result = node_list_dup(list1, FALSE, filter); slist_iter( node, node_t, list2, lpc, if(node == NULL) { continue; } other_node = (node_t*)pe_find_node_id( result, node->details->id); if(other_node != NULL) { crm_debug_4("%s + %s: %d + %d", node->details->uname, other_node->details->uname, node->weight, other_node->weight); other_node->weight = merge_weights( other_node->weight, node->weight); if(filter && node->weight < 0) { needs_filter = TRUE; } } else if(filter == FALSE || node->weight >= 0) { node_t *new_node = node_copy(node); result = g_list_append(result, new_node); } ); /* not the neatest way, but the most expedient for now */ if(filter && needs_filter) { GListPtr old_result = result; result = node_list_dup(old_result, FALSE, filter); pe_free_shallow_adv(old_result, TRUE); } return result; } GListPtr node_list_dup(GListPtr list1, gboolean reset, gboolean filter) { GListPtr result = NULL; slist_iter( this_node, node_t, list1, lpc, node_t *new_node = NULL; if(filter && this_node->weight < 0) { continue; } new_node = node_copy(this_node); if(reset) { new_node->weight = 0; } if(new_node != NULL) { result = g_list_append(result, new_node); } ); return result; } /* only for rsc_colocation constraints */ rsc_colocation_t * invert_constraint(rsc_colocation_t *constraint) { rsc_colocation_t *inverted_con = NULL; crm_debug_3("Inverting constraint"); if(constraint == NULL) { pe_err("Cannot invert NULL constraint"); return NULL; } crm_malloc0(inverted_con, sizeof(rsc_colocation_t)); if(inverted_con == NULL) { return NULL; } inverted_con->id = constraint->id; inverted_con->strength = constraint->strength; /* swap the direction */ inverted_con->rsc_lh = constraint->rsc_rh; inverted_con->rsc_rh = constraint->rsc_lh; inverted_con->state_lh = constraint->state_rh; inverted_con->state_rh = constraint->state_lh; crm_action_debug_3( print_rsc_colocation("Inverted constraint", inverted_con, FALSE)); return inverted_con; } /* * Create a new color with the contents of "nodes" as the list of * possible nodes that resources with this color can be run on. * * Typically, when creating a color you will provide the node list from * the resource you will first assign the color to. * * If "colors" != NULL, it will be added to that list * If "resources" != NULL, it will be added to every provisional resource * in that list */ color_t * create_color( pe_working_set_t *data_set, resource_t *resource, GListPtr node_list) { color_t *new_color = NULL; crm_debug_5("Creating color"); crm_malloc0(new_color, sizeof(color_t)); if(new_color == NULL) { return NULL; } new_color->id = data_set->color_id++; new_color->local_weight = 1.0; crm_debug_5("Creating color details"); crm_malloc0(new_color->details, sizeof(struct color_shared_s)); if(new_color->details == NULL) { crm_free(new_color); return NULL; } new_color->details->id = new_color->id; new_color->details->highest_priority = -1; new_color->details->chosen_node = NULL; new_color->details->candidate_nodes = NULL; new_color->details->allocated_resources = NULL; new_color->details->pending = TRUE; if(resource != NULL) { crm_debug_5("populating node list"); new_color->details->highest_priority = resource->priority; new_color->details->candidate_nodes = node_list_dup(node_list, TRUE, TRUE); } crm_action_debug_3(print_color("Created color", new_color, TRUE)); CRM_CHECK(data_set != NULL, return NULL); data_set->colors = g_list_append(data_set->colors, new_color); return new_color; } color_t * copy_color(color_t *a_color) { color_t *color_copy = NULL; if(a_color == NULL) { pe_err("Cannot copy NULL"); return NULL; } crm_malloc0(color_copy, sizeof(color_t)); if(color_copy != NULL) { color_copy->id = a_color->id; color_copy->details = a_color->details; color_copy->local_weight = 1.0; } return color_copy; } gint gslist_color_compare(gconstpointer a, gconstpointer b); color_t * find_color(GListPtr candidate_colors, color_t *other_color) { GListPtr tmp = g_list_find_custom(candidate_colors, other_color, gslist_color_compare); if(tmp != NULL) { return (color_t *)tmp->data; } return NULL; } gint gslist_color_compare(gconstpointer a, gconstpointer b) { const color_t *color_a = (const color_t*)a; const color_t *color_b = (const color_t*)b; /* crm_debug_5("%d vs. %d", a?color_a->id:-2, b?color_b->id:-2); */ if(a == b) { return 0; } else if(a == NULL || b == NULL) { return 1; } else if(color_a->id == color_b->id) { return 0; } return 1; } gint sort_rsc_priority(gconstpointer a, gconstpointer b) { const resource_t *resource1 = (const resource_t*)a; const resource_t *resource2 = (const resource_t*)b; if(a == NULL && b == NULL) { return 0; } if(a == NULL) { return 1; } if(b == NULL) { return -1; } if(resource1->priority > resource2->priority) { return -1; } if(resource1->priority < resource2->priority) { return 1; } return 0; } gint sort_rsc_node_weight(gconstpointer a, gconstpointer b) { const resource_t *resource1 = (const resource_t*)a; const resource_t *resource2 = (const resource_t*)b; const color_t *color1 = NULL; const color_t *color2 = NULL; const node_t *node1 = NULL; const node_t *node2 = NULL; CRM_ASSERT(resource1 != NULL); CRM_ASSERT(resource2 != NULL); color1 = resource1->color; color2 = resource2->color; CRM_CHECK(color1 != NULL, return 0); CRM_CHECK(color2 != NULL, return 0); node1 = color1->details->chosen_node; node2 = color2->details->chosen_node; if(node1 == NULL && node2 == NULL) { return 0; } if(node1 == NULL) { return 1; } if(node2 == NULL) { return -1; } CRM_ASSERT(node1 != NULL); CRM_ASSERT(node2 != NULL); if(node1->weight > node2->weight) { crm_debug("%s (%d) > %s (%d) : %s vs. %s", node1->details->id, node1->weight, node2->details->id, node2->weight, resource1->id, resource2->id); return -1; } if(node1->weight < node2->weight) { crm_debug("%s (%d) < %s (%d) : %s vs. %s", node1->details->id, node1->weight, node2->details->id, node2->weight, resource1->id, resource2->id); return 1; } crm_debug("%s (%d) == %s (%d) : %s vs. %s", node1->details->id, node1->weight, node2->details->id, node2->weight, resource1->id, resource2->id); return 0; } /* lowest to highest */ gint sort_action_id(gconstpointer a, gconstpointer b) { const action_wrapper_t *action_wrapper2 = (const action_wrapper_t*)a; const action_wrapper_t *action_wrapper1 = (const action_wrapper_t*)b; if(a == NULL) { return 1; } if(b == NULL) { return -1; } if(action_wrapper1->action->id > action_wrapper2->action->id) { return -1; } if(action_wrapper1->action->id < action_wrapper2->action->id) { return 1; } return 0; } gint sort_cons_strength(gconstpointer a, gconstpointer b) { const rsc_colocation_t *rsc_constraint1 = (const rsc_colocation_t*)a; const rsc_colocation_t *rsc_constraint2 = (const rsc_colocation_t*)b; if(a == NULL) { return 1; } if(b == NULL) { return -1; } if(rsc_constraint1->strength > rsc_constraint2->strength) { return 1; } if(rsc_constraint1->strength < rsc_constraint2->strength) { return -1; } return 0; } gint sort_color_weight(gconstpointer a, gconstpointer b) { const color_t *color1 = (const color_t*)a; const color_t *color2 = (const color_t*)b; if(a == NULL) { return 1; } if(b == NULL) { return -1; } if(color1->local_weight > color2->local_weight) { return -1; } if(color1->local_weight < color2->local_weight) { return 1; } return 0; } /* return -1 if 'a' is more preferred * return 1 if 'b' is more preferred */ gint sort_node_weight(gconstpointer a, gconstpointer b) { const node_t *node1 = (const node_t*)a; const node_t *node2 = (const node_t*)b; int node1_weight = 0; int node2_weight = 0; if(a == NULL) { return 1; } if(b == NULL) { return -1; } node1_weight = node1->weight; node2_weight = node2->weight; if(node1->details->unclean || node1->details->standby || node1->details->shutdown) { node1_weight = -INFINITY; } if(node2->details->unclean || node2->details->standby || node2->details->shutdown) { node2_weight = -INFINITY; } if(node1_weight > node2_weight) { crm_debug_3("%s (%d) > %s (%d) : weight", node1->details->uname, node1_weight, node2->details->uname, node2_weight); return -1; } if(node1_weight < node2_weight) { crm_debug_3("%s (%d) < %s (%d) : weight", node1->details->uname, node1_weight, node2->details->uname, node2_weight); return 1; } crm_debug_3("%s (%d) == %s (%d) : weight", node1->details->uname, node1_weight, node2->details->uname, node2_weight); /* now try to balance resources across the cluster */ if(node1->details->num_resources < node2->details->num_resources) { crm_debug_3("%s (%d) < %s (%d) : resources", node1->details->uname, node1->details->num_resources, node2->details->uname, node2->details->num_resources); return -1; } else if(node1->details->num_resources > node2->details->num_resources) { crm_debug_3("%s (%d) > %s (%d) : resources", node1->details->uname, node1->details->num_resources, node2->details->uname, node2->details->num_resources); return 1; } crm_debug_4("%s = %s", node1->details->uname, node2->details->uname); return 0; } action_t * custom_action(resource_t *rsc, char *key, const char *task, node_t *on_node, gboolean optional, gboolean save_action, pe_working_set_t *data_set) { action_t *action = NULL; GListPtr possible_matches = NULL; CRM_CHECK(key != NULL, return NULL); CRM_CHECK(task != NULL, return NULL); if(save_action && rsc != NULL) { possible_matches = find_actions(rsc->actions, key, on_node); } if(possible_matches != NULL) { crm_free(key); if(g_list_length(possible_matches) > 1) { pe_warn("Action %s for %s on %s exists %d times", task, rsc?rsc->id:"", on_node?on_node->details->uname:"", g_list_length(possible_matches)); } action = g_list_nth_data(possible_matches, 0); crm_debug_4("Found existing action (%d) %s for %s on %s", action->id, task, rsc?rsc->id:"", on_node?on_node->details->uname:""); } if(action == NULL) { if(save_action) { crm_debug_2("Creating%s action %d: %s for %s on %s", optional?"":" manditory", data_set->action_id, key, rsc?rsc->id:"", on_node?on_node->details->uname:""); } crm_malloc0(action, sizeof(action_t)); if(action != NULL) { if(save_action) { action->id = data_set->action_id++; } else { action->id = 0; } action->rsc = rsc; action->task = task; action->node = on_node; action->actions_before = NULL; action->actions_after = NULL; action->failure_is_fatal = TRUE; action->pseudo = FALSE; action->dumped = FALSE; action->runnable = TRUE; action->processed = FALSE; action->optional = optional; action->seen_count = 0; action->extra = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); action->meta = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); if(save_action) { data_set->actions = g_list_append( data_set->actions, action); } action->uuid = key; if(rsc != NULL) { action->op_entry = find_rsc_op_entry(rsc, key); unpack_operation( action, action->op_entry, data_set); if(save_action) { rsc->actions = g_list_append( rsc->actions, action); } } if(save_action) { crm_debug_4("Action %d created", action->id); } } } if(optional == FALSE && action->optional) { crm_debug_2("Action %d (%s) marked manditory", action->id, action->uuid); action->optional = FALSE; } if(rsc != NULL) { enum action_tasks a_task = text2task(action->task); int warn_level = LOG_DEBUG_3; if(save_action) { warn_level = LOG_WARNING; } if(action->node != NULL && action->op_entry != NULL) { unpack_instance_attributes( action->op_entry, XML_TAG_ATTR_SETS, action->node->details->attrs, action->extra, NULL, data_set->now); } if(action->node == NULL) { action->runnable = FALSE; } else if(rsc->is_managed == FALSE) { crm_log_maybe(warn_level, "Action %s %s is for %s (unmanaged)", action->uuid, task, rsc->id); action->optional = TRUE; /* action->runnable = FALSE; */ #if 0 } else if(action->node->details->unclean) { crm_log_maybe(warn_level, "Action %s on %s is unrunnable (unclean)", action->uuid, action->node?action->node->details->uname:""); action->runnable = FALSE; #endif } else if(action->node->details->online == FALSE) { action->runnable = FALSE; crm_log_maybe(warn_level, "Action %s on %s is unrunnable (offline)", action->uuid, action->node->details->uname); if(action->rsc->is_managed && save_action && a_task == stop_rsc) { crm_log_maybe(warn_level, "Marking node %s unclean", action->node->details->uname); action->node->details->unclean = TRUE; } } else if(action->needs == rsc_req_nothing) { crm_debug_3("Action %s doesnt require anything", action->uuid); action->runnable = TRUE; #if 0 /* * No point checking this * - if we dont have quorum we cant stonith anyway */ } else if(action->needs == rsc_req_stonith) { crm_debug_3("Action %s requires only stonith", action->uuid); action->runnable = TRUE; #endif } else if(data_set->have_quorum == FALSE && data_set->no_quorum_policy == no_quorum_stop) { action->runnable = FALSE; crm_debug("%s\t%s %s (cancelled : quorum)", action->node->details->uname, action->task, rsc->id); } else if(data_set->have_quorum == FALSE && data_set->no_quorum_policy == no_quorum_freeze) { crm_debug_3("Check resource is already active"); if(rsc->fns->active(rsc, TRUE) == FALSE) { action->runnable = FALSE; crm_debug("%s\t%s %s (cancelled : quorum freeze)", action->node->details->uname, action->task, rsc->id); } } else { crm_debug_3("Action %s is runnable", action->uuid); action->runnable = TRUE; } if(save_action) { switch(a_task) { case stop_rsc: rsc->stopping = TRUE; break; case start_rsc: rsc->starting = FALSE; if(action->runnable) { rsc->starting = TRUE; } break; default: break; } } } return action; } void unpack_operation( action_t *action, crm_data_t *xml_obj, pe_working_set_t* data_set) { int lpc = 0; const char *value = NULL; const char *fields[] = { XML_LRM_ATTR_INTERVAL, "timeout", "start_delay", }; CRM_CHECK(action->rsc != NULL, return); if(xml_obj != NULL) { value = crm_element_value(xml_obj, "prereq"); } if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_START)) { value = g_hash_table_lookup( action->rsc->meta, "start_prereq"); } if(value == NULL && safe_str_neq(action->task, CRMD_ACTION_START)) { /* todo: integrate stop as an option? */ action->needs = rsc_req_nothing; value = "nothing (default)"; } else if(safe_str_eq(value, "nothing")) { action->needs = rsc_req_nothing; } else if(safe_str_eq(value, "quorum")) { action->needs = rsc_req_quorum; } else if(safe_str_eq(value, "fencing")) { action->needs = rsc_req_stonith; } else if(data_set->no_quorum_policy == no_quorum_ignore) { action->needs = rsc_req_nothing; value = "nothing (default)"; } else if(data_set->no_quorum_policy == no_quorum_freeze && data_set->stonith_enabled) { action->needs = rsc_req_stonith; value = "fencing (default)"; } else { action->needs = rsc_req_quorum; value = "quorum (default)"; } crm_debug_3("\tAction %s requires: %s", action->task, value); value = NULL; if(xml_obj != NULL) { value = crm_element_value(xml_obj, "on_fail"); } if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_STOP)) { value = g_hash_table_lookup( action->rsc->meta, "on_stopfail"); if(value != NULL) { #if CRM_DEPRECATED_SINCE_2_0_2 pe_config_err("The \"on_stopfail\" attribute used in" " %s has been deprecated since 2.0.2", action->rsc->id); #else pe_config_err("The \"on_stopfail\" attribute used in" " %s has been deprecated since 2.0.2" " and is now disabled", action->rsc->id); value = NULL; #endif pe_config_err("Please use specify the \"on_fail\"" " attribute on the \"stop\" operation" " instead"); } } if(value == NULL) { } else if(safe_str_eq(value, "block")) { action->on_fail = action_fail_block; } else if(safe_str_eq(value, "fence")) { action->on_fail = action_fail_fence; value = "node fencing"; } else if(safe_str_eq(value, "ignore")) { action->on_fail = action_fail_ignore; value = "ignore"; } else if(safe_str_eq(value, "migrate")) { action->on_fail = action_fail_migrate; value = "force migration"; } else if(safe_str_eq(value, "stop")) { action->fail_role = RSC_ROLE_STOPPED; value = "stop resource"; } else if(safe_str_eq(value, "restart") || safe_str_eq(value, "nothing")) { action->on_fail = action_fail_recover; value = "restart (and possibly migrate)"; } else { pe_err("Resource %s: Unknown failure type (%s)", action->rsc->id, value); value = NULL; } /* defaults */ if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_STOP)) { if(data_set->stonith_enabled) { action->on_fail = action_fail_fence; value = "resource fence (default)"; } else { action->on_fail = action_fail_block; value = "resource block (default)"; } } else if(value == NULL) { action->on_fail = action_fail_recover; value = "restart (and possibly migrate) (default)"; } crm_debug_3("\t%s failure handling: %s", action->task, value); value = NULL; if(xml_obj != NULL) { value = crm_element_value(xml_obj, "role_after_failure"); } if(value != NULL && action->fail_role == RSC_ROLE_UNKNOWN) { action->fail_role = text2role(value); } /* defaults */ if(action->fail_role == RSC_ROLE_UNKNOWN) { if(safe_str_eq(action->task, CRMD_ACTION_PROMOTE)) { action->fail_role = RSC_ROLE_SLAVE; } else { action->fail_role = RSC_ROLE_STARTED; } } crm_debug_3("\t%s failure results in: %s", action->task, role2text(action->fail_role)); if(xml_obj == NULL) { return; } xml_prop_iter(xml_obj, p_name, p_value, if(p_value != NULL) { g_hash_table_insert(action->meta, crm_strdup(p_name), crm_strdup(p_value)); } ); unpack_instance_attributes(xml_obj, XML_TAG_META_SETS, NULL, action->meta, NULL, data_set->now); unpack_instance_attributes(xml_obj, XML_TAG_ATTR_SETS, NULL, action->meta, NULL, data_set->now); if(g_hash_table_lookup(action->meta, "timeout") == NULL) { g_hash_table_insert(action->meta, crm_strdup("timeout"), crm_strdup(data_set->transition_idle_timeout)); } for(;lpc < DIMOF(fields); lpc++) { value = g_hash_table_lookup(action->meta, fields[lpc]); if(value != NULL) { char *tmp_ms = NULL; int tmp_i = crm_get_msec(value); if(tmp_i < 0) { tmp_i = 0; } tmp_ms = crm_itoa(tmp_i); g_hash_table_replace( action->meta, crm_strdup(fields[lpc]), tmp_ms); } } /* if(safe_str_eq(native_data->agent->class, "stonith")) { */ /* if(rsc->start_needs == rsc_req_stonith) { */ /* pe_err("Stonith resources (eg. %s) cannot require" */ /* " fencing to start", rsc->id); */ /* } */ /* rsc->start_needs = rsc_req_quorum; */ /* } */ } crm_data_t * find_rsc_op_entry(resource_t *rsc, const char *key) { const char *name = NULL; const char *value = NULL; const char *interval = NULL; char *match_key = NULL; crm_data_t *op = NULL; xml_child_iter_filter( rsc->ops_xml, operation, "op", name = crm_element_value(operation, "name"); interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL); value = crm_element_value(operation, "disabled"); if(crm_is_true(value)) { crm_debug_2("%s disabled", ID(operation)); continue; } match_key = generate_op_key( rsc->id, name, crm_get_msec(interval)); if(safe_str_eq(key, match_key)) { op = operation; } crm_free(match_key); if(op != NULL) { return op; } ); crm_debug_3("No match for %s", key); return op; } void print_node(const char *pre_text, node_t *node, gboolean details) { if(node == NULL) { crm_debug_4("%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } crm_debug_4("%s%s%sNode %s: (weight=%d, fixed=%s)", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", node->details==NULL?"error ":node->details->online?"":"Unavailable/Unclean ", node->details->uname, node->weight, node->fixed?"True":"False"); if(details && node != NULL && node->details != NULL) { char *pe_mutable = crm_strdup("\t\t"); crm_debug_4("\t\t===Node Attributes"); g_hash_table_foreach(node->details->attrs, print_str_str, pe_mutable); crm_free(pe_mutable); crm_debug_4("\t\t=== Resources"); slist_iter( rsc, resource_t, node->details->running_rsc, lpc, print_resource(LOG_DEBUG_4, "\t\t", rsc, FALSE); ); } } /* * Used by the HashTable for-loop */ void print_str_str(gpointer key, gpointer value, gpointer user_data) { crm_debug_4("%s%s %s ==> %s", user_data==NULL?"":(char*)user_data, user_data==NULL?"":": ", (char*)key, (char*)value); } void print_color_details(const char *pre_text, struct color_shared_s *color, gboolean details) { if(color == NULL) { crm_debug_4("%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } crm_debug_4("%s%sColor %d: node=%s (from %d candidates)", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", color->id, color->chosen_node==NULL?"":color->chosen_node->details->uname, g_list_length(color->candidate_nodes)); if(details) { slist_iter(node, node_t, color->candidate_nodes, lpc, print_node("\t", node, FALSE)); } } void print_color(const char *pre_text, color_t *color, gboolean details) { if(color == NULL) { crm_debug_4("%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } crm_debug_4("%s%sColor %d: (weight=%d, node=%s, possible=%d)", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", color->id, color->local_weight, safe_val5("",color,details,chosen_node,details,uname), g_list_length(color->details->candidate_nodes)); if(details) { print_color_details("\t", color->details, details); } } void print_rsc_to_node(const char *pre_text, rsc_to_node_t *cons, gboolean details) { if(cons == NULL) { crm_debug_4("%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } crm_debug_4("%s%s%s Constraint %s (%p) - %d nodes:", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", "rsc_to_node", cons->id, cons, g_list_length(cons->node_list_rh)); if(details == FALSE) { crm_debug_4("\t%s (node placement rule)", safe_val3(NULL, cons, rsc_lh, id)); slist_iter( node, node_t, cons->node_list_rh, lpc, print_node("\t\t-->", node, FALSE) ); } } void print_rsc_colocation(const char *pre_text, rsc_colocation_t *cons, gboolean details) { if(cons == NULL) { crm_debug_4("%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } crm_debug_4("%s%s%s Constraint %s (%p):", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", XML_CONS_TAG_RSC_DEPEND, cons->id, cons); if(details == FALSE) { crm_debug_4("\t%s --> %s, %s", safe_val3(NULL, cons, rsc_lh, id), safe_val3(NULL, cons, rsc_rh, id), strength2text(cons->strength)); } } void print_resource( int log_level, const char *pre_text, resource_t *rsc, gboolean details) { long options = pe_print_log; if(rsc == NULL) { crm_log_maybe(log_level-1, "%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } if(details) { options |= pe_print_details; } rsc->fns->print(rsc, pre_text, options, &log_level); } void log_action(unsigned int log_level, const char *pre_text, action_t *action, gboolean details) { const char *node_uname = NULL; const char *node_uuid = NULL; if(action == NULL) { crm_log_maybe(log_level, "%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } if(action->pseudo) { node_uname = NULL; node_uuid = NULL; } else if(action->node != NULL) { node_uname = action->node->details->uname; node_uuid = action->node->details->id; } else { node_uname = ""; node_uuid = NULL; } switch(text2task(action->task)) { case stonith_node: case shutdown_crm: crm_log_maybe(log_level, "%s%s%sAction %d: %s%s%s%s%s%s", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", action->pseudo?"Pseduo ":action->optional?"Optional ":action->runnable?action->processed?"":"(Provisional) ":"!!Non-Startable!! ", action->id, action->uuid, node_uname?"\ton ":"", node_uname?node_uname:"", node_uuid?"\t\t(":"", node_uuid?node_uuid:"", node_uuid?")":""); break; default: crm_log_maybe(log_level, "%s%s%sAction %d: %s %s%s%s%s%s%s", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", action->optional?"Optional ":action->pseudo?"Pseduo ":action->runnable?action->processed?"":"(Provisional) ":"!!Non-Startable!! ", action->id, action->uuid, safe_val3("", action, rsc, id), node_uname?"\ton ":"", node_uname?node_uname:"", node_uuid?"\t\t(":"", node_uuid?node_uuid:"", node_uuid?")":""); break; } if(details) { crm_log_maybe(log_level+1, "\t\t====== Preceeding Actions"); slist_iter( other, action_wrapper_t, action->actions_before, lpc, log_action(log_level+1, "\t\t", other->action, FALSE); ); #if 1 crm_log_maybe(log_level+1, "\t\t====== Subsequent Actions"); slist_iter( other, action_wrapper_t, action->actions_after, lpc, log_action(log_level+1, "\t\t", other->action, FALSE); ); #endif crm_log_maybe(log_level+1, "\t\t====== End"); } else { crm_log_maybe(log_level, "\t\t(seen=%d, before=%d, after=%d)", action->seen_count, g_list_length(action->actions_before), g_list_length(action->actions_after)); } } void pe_free_nodes(GListPtr nodes) { GListPtr iterator = nodes; while(iterator != NULL) { node_t *node = (node_t*)iterator->data; struct node_shared_s *details = node->details; iterator = iterator->next; crm_debug_5("deleting node"); crm_debug_5("%s is being deleted", details->uname); print_node("delete", node, FALSE); if(details != NULL) { if(details->attrs != NULL) { g_hash_table_destroy(details->attrs); } pe_free_shallow_adv(details->running_rsc, FALSE); crm_free(details); } crm_free(node); } if(nodes != NULL) { g_list_free(nodes); } } void pe_free_colors(GListPtr colors) { GListPtr iterator = colors; while(iterator != NULL) { color_t *color = (color_t *)iterator->data; struct color_shared_s *details = color->details; iterator = iterator->next; if(details != NULL) { pe_free_shallow(details->candidate_nodes); pe_free_shallow_adv(details->allocated_resources, FALSE); crm_free(details->chosen_node); crm_free(details); } crm_free(color); } if(colors != NULL) { g_list_free(colors); } } void pe_free_resources(GListPtr resources) { resource_t *rsc = NULL; GListPtr iterator = resources; while(iterator != NULL) { iterator = iterator; rsc = (resource_t *)iterator->data; iterator = iterator->next; rsc->fns->free(rsc); } if(resources != NULL) { g_list_free(resources); } } void pe_free_action(action_t *action) { if(action == NULL) { return; } pe_free_shallow(action->actions_before);/* action_warpper_t* */ pe_free_shallow(action->actions_after); /* action_warpper_t* */ g_hash_table_destroy(action->extra); g_hash_table_destroy(action->meta); crm_free(action->uuid); crm_free(action); } void pe_free_actions(GListPtr actions) { GListPtr iterator = actions; while(iterator != NULL) { pe_free_action(iterator->data); iterator = iterator->next; } if(actions != NULL) { g_list_free(actions); } } void pe_free_ordering(GListPtr constraints) { GListPtr iterator = constraints; while(iterator != NULL) { order_constraint_t *order = iterator->data; iterator = iterator->next; crm_free(order->lh_action_task); crm_free(order->rh_action_task); crm_free(order); } if(constraints != NULL) { g_list_free(constraints); } } void pe_free_rsc_colocation(rsc_colocation_t *cons) { if(cons != NULL) { crm_debug_4("Freeing constraint %s (%p)", cons->id, cons); crm_free(cons); } } void pe_free_rsc_to_node(rsc_to_node_t *cons) { if(cons != NULL) { pe_free_shallow(cons->node_list_rh); crm_free(cons); } } GListPtr find_recurring_actions(GListPtr input, node_t *not_on_node) { const char *value = NULL; GListPtr result = NULL; CRM_CHECK(input != NULL, return NULL); slist_iter( action, action_t, input, lpc, value = g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL); if(value == NULL) { /* skip */ } else if(safe_str_eq(CRMD_ACTION_CANCEL, action->task)) { /* skip */ } else if(not_on_node == NULL) { crm_debug_5("(null) Found: %s", action->uuid); result = g_list_append(result, action); } else if(action->node == NULL) { /* skip */ } else if(action->node->details != not_on_node->details) { crm_debug_5("Found: %s", action->uuid); result = g_list_append(result, action); } ); return result; } GListPtr find_actions(GListPtr input, const char *key, node_t *on_node) { GListPtr result = NULL; CRM_CHECK(key != NULL, return NULL); slist_iter( action, action_t, input, lpc, crm_debug_5("Matching %s against %s", key, action->uuid); if(safe_str_neq(key, action->uuid)) { continue; } else if(on_node == NULL) { result = g_list_append(result, action); } else if(action->node == NULL) { /* skip */ crm_debug_2("While looking for %s action on %s, " "found an unallocated one. Assigning" " it to the requested node...", key, on_node->details->uname); action->node = on_node; result = g_list_append(result, action); } else if(safe_str_eq(on_node->details->id, action->node->details->id)) { result = g_list_append(result, action); } ); return result; } GListPtr find_actions_exact(GListPtr input, const char *key, node_t *on_node) { GListPtr result = NULL; CRM_CHECK(key != NULL, return NULL); slist_iter( action, action_t, input, lpc, crm_debug_5("Matching %s against %s", key, action->uuid); if(safe_str_neq(key, action->uuid)) { crm_debug_3("Key mismatch: %s vs. %s", key, action->uuid); continue; } else if(on_node == NULL || action->node == NULL) { crm_debug_3("on_node=%p, action->node=%p", on_node, action->node); continue; } else if(safe_str_eq(on_node->details->id, action->node->details->id)) { result = g_list_append(result, action); } crm_debug_2("Node mismatch: %s vs. %s", on_node->details->id, action->node->details->id); ); return result; } void set_id(crm_data_t * xml_obj, const char *prefix, int child) { int id_len = 0; gboolean use_prefix = TRUE; gboolean use_child = TRUE; char *new_id = NULL; const char *id = crm_element_value(xml_obj, XML_ATTR_ID); id_len = 1 + strlen(id); if(child > 999) { pe_err("Are you insane?!?" " The CRM does not support > 1000 children per resource"); return; } else if(child < 0) { use_child = FALSE; } else { id_len += 4; /* child */ } if(prefix == NULL || safe_str_eq(id, prefix)) { use_prefix = FALSE; } else { id_len += (1 + strlen(prefix)); } crm_malloc0(new_id, id_len); if(use_child) { snprintf(new_id, id_len, "%s%s%s:%d", use_prefix?prefix:"", use_prefix?":":"", id, child); } else { snprintf(new_id, id_len, "%s%s%s", use_prefix?prefix:"", use_prefix?":":"", id); } crm_xml_add(xml_obj, XML_ATTR_ID, new_id); crm_free(new_id); } rsc_to_node_t * rsc2node_new(const char *id, resource_t *rsc, int node_weight, node_t *foo_node, pe_working_set_t *data_set) { rsc_to_node_t *new_con = NULL; if(rsc == NULL || id == NULL) { pe_err("Invalid constraint %s for rsc=%p", crm_str(id), rsc); return NULL; } crm_malloc0(new_con, sizeof(rsc_to_node_t)); if(new_con != NULL) { new_con->id = id; new_con->rsc_lh = rsc; new_con->node_list_rh = NULL; new_con->role_filter = RSC_ROLE_UNKNOWN; if(foo_node != NULL) { node_t *copy = node_copy(foo_node); copy->weight = node_weight; new_con->node_list_rh = g_list_append(NULL, copy); } else { CRM_CHECK(node_weight == 0, return NULL); } data_set->placement_constraints = g_list_append( data_set->placement_constraints, new_con); rsc->rsc_location = g_list_append( rsc->rsc_location, new_con); } return new_con; } const char * strength2text(enum con_strength strength) { const char *result = ""; switch(strength) { case pecs_ignore: result = "ignore"; break; case pecs_must: result = XML_STRENGTH_VAL_MUST; break; case pecs_must_not: result = XML_STRENGTH_VAL_MUSTNOT; break; case pecs_startstop: result = "start/stop"; break; } return result; } const char * ordering_type2text(enum pe_ordering type) { const char *result = ""; switch(type) { case pe_ordering_manditory: result = "manditory"; break; case pe_ordering_restart: result = "restart"; break; case pe_ordering_recover: result = "recover"; break; case pe_ordering_optional: result = "optional"; break; case pe_ordering_postnotify: result = "post_notify"; break; } return result; } diff --git a/lib/crm/pengine/utils.h b/lib/crm/pengine/utils.h index b0a0f99092..b5365750e9 100644 --- a/lib/crm/pengine/utils.h +++ b/lib/crm/pengine/utils.h @@ -1,171 +1,171 @@ -/* $Id: utils.h,v 1.1 2006/05/31 14:59:12 andrew Exp $ */ +/* $Id: utils.h,v 1.2 2006/06/07 12:46:56 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 */ #ifndef PE_UTILS__H #define PE_UTILS__H #include -#include +#include /* Node helper functions */ extern node_t *pe_find_node_id(GListPtr node_list, const char *id); extern node_t *node_copy(node_t *this_node) ; /* Binary like operators for lists of nodes */ extern GListPtr node_list_dup(GListPtr list1, gboolean reset, gboolean filter); extern GListPtr node_list_and(GListPtr list1, GListPtr list2, gboolean filter); extern GListPtr node_list_xor(GListPtr list1, GListPtr list2, gboolean filter); extern GListPtr node_list_minus(GListPtr list1,GListPtr list2,gboolean filter); extern gboolean node_list_eq(GListPtr list1, GListPtr list2, gboolean filter); extern GListPtr node_list_or(GListPtr list1, GListPtr list2, gboolean filter); extern void pe_free_shallow(GListPtr alist); extern void pe_free_shallow_adv(GListPtr alist, gboolean with_data); /* Constraint helper functions */ extern rsc_colocation_t *invert_constraint(rsc_colocation_t *constraint); extern rsc_to_node_t *copy_constraint(rsc_to_node_t *constraint); /* Color helper functions */ extern void add_color_to_rsc(resource_t *rsc, color_t *color); extern color_t *find_color(GListPtr candidate_colors, color_t *other_color); extern color_t *create_color( pe_working_set_t *data_set, resource_t *resource, GListPtr resources); extern color_t *copy_color(color_t *a_color); /* For creating the transition graph */ extern crm_data_t *action2xml(action_t *action, gboolean as_input); /* Printing functions for debug */ extern void print_node( const char *pre_text, node_t *node, gboolean details); extern void print_resource( int log_level, const char *pre_text, resource_t *rsc, gboolean details); extern void print_rsc_to_node( const char *pre_text, rsc_to_node_t *cons, gboolean details); extern void print_rsc_colocation( const char *pre_text, rsc_colocation_t *cons, gboolean details); extern void print_color( const char *pre_text, color_t *color, gboolean details); extern void print_color_details( const char *pre_text, struct color_shared_s *color, gboolean details); extern void log_action( unsigned int log_level, const char *pre_text, action_t *action, gboolean details); /* Sorting functions */ extern gint sort_rsc_priority(gconstpointer a, gconstpointer b); extern gint sort_rsc_node_weight(gconstpointer a, gconstpointer b); extern gint sort_cons_strength(gconstpointer a, gconstpointer b); extern gint sort_color_weight(gconstpointer a, gconstpointer b); extern gint sort_node_weight(gconstpointer a, gconstpointer b); extern gint sort_action_id(gconstpointer a, gconstpointer b); extern crm_data_t *find_rsc_op_entry(resource_t *rsc, const char *key); extern action_t *custom_action( resource_t *rsc, char *key, const char *task, node_t *on_node, gboolean optional, gboolean foo, pe_working_set_t *data_set); extern rsc_to_node_t *rsc2node_new( const char *id, resource_t *rsc, int weight, node_t *node, pe_working_set_t *data_set); #define delete_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_DELETE, 0) #define delete_action(rsc, node) custom_action( \ rsc, delete_key(rsc), CRMD_ACTION_DELETE, node, \ FALSE, TRUE, data_set); #define stopped_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_STOPPED, 0) #define stopped_action(rsc, node, optional) custom_action( \ rsc, stopped_key(rsc), CRMD_ACTION_STOPPED, node, \ optional, TRUE, data_set); #define stop_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_STOP, 0) #define stop_action(rsc, node, optional) custom_action( \ rsc, stop_key(rsc), CRMD_ACTION_STOP, node, \ optional, TRUE, data_set); #define start_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_START, 0) #define start_action(rsc, node, optional) custom_action( \ rsc, start_key(rsc), CRMD_ACTION_START, node, \ optional, TRUE, data_set) #define started_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_STARTED, 0) #define started_action(rsc, node, optional) custom_action( \ rsc, started_key(rsc), CRMD_ACTION_STARTED, node, \ optional, TRUE, data_set) #define promote_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_PROMOTE, 0) #define promote_action(rsc, node, optional) custom_action( \ rsc, promote_key(rsc), CRMD_ACTION_PROMOTE, node, \ optional, TRUE, data_set) #define promoted_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_PROMOTED, 0) #define promoted_action(rsc, node, optional) custom_action( \ rsc, promoted_key(rsc), CRMD_ACTION_PROMOTED, node, \ optional, TRUE, data_set) #define demote_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_DEMOTE, 0) #define demote_action(rsc, node, optional) custom_action( \ rsc, demote_key(rsc), CRMD_ACTION_DEMOTE, node, \ optional, TRUE, data_set) #define demoted_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_DEMOTED, 0) #define demoted_action(rsc, node, optional) custom_action( \ rsc, demoted_key(rsc), CRMD_ACTION_DEMOTED, node, \ optional, TRUE, data_set) extern GListPtr find_actions(GListPtr input, const char *key, node_t *on_node); extern GListPtr find_actions_exact( GListPtr input, const char *key, node_t *on_node); extern GListPtr find_recurring_actions(GListPtr input, node_t *not_on_node); extern void set_id(crm_data_t *xml_obj, const char *prefix, int child); /* free the various structures */ extern void pe_free_nodes(GListPtr nodes); extern void pe_free_colors(GListPtr colors); extern void pe_free_rsc_colocation(rsc_colocation_t *cons); extern void pe_free_rsc_to_node(rsc_to_node_t *cons); extern void pe_free_resources(GListPtr resources); extern void pe_free_action(action_t *action); extern void pe_free_actions(GListPtr actions); extern void pe_free_ordering(GListPtr constraints); extern const char *strength2text(enum con_strength strength); extern const char *ordering_type2text(enum pe_ordering type); #endif