diff --git a/lib/plugins/lrm/Makefile.am b/lib/plugins/lrm/Makefile.am index f25f0cc218..45c9765926 100644 --- a/lib/plugins/lrm/Makefile.am +++ b/lib/plugins/lrm/Makefile.am @@ -1,44 +1,43 @@ # # Author: Sun Jiang Dong # Copyright (c) 2004 International Business Machines # # 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 LRM_DIR = lrm INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ -I$(top_builddir)/linux-ha -I$(top_srcdir)/linux-ha \ -I$(top_builddir)/libltdl -I$(top_srcdir)/libltdl halibdir = $(libdir)/@HB_PKG@ havarlibdir = $(localstatedir)/lib/@HB_PKG@ COMMONLIBS = -lplumb \ $(GLIBLIB) lrmdir = $(HA_VARLIBDIR)/$(HB_PKG)/$(LRM_DIR) plugindir = $(halibdir)/plugins/RAExec apigid = @HA_APIGID@ plugin_LTLIBRARIES = stonith.la stonith_la_SOURCES = raexecstonith.c -stonith_la_LDFLAGS = -L$(top_builddir)/lib/pils -lpils -export-dynamic -module -avoid-version \ - -L$(top_builddir)/lib/fencing -lstonithd \ - -L$(top_builddir)/lib/stonith -lstonith -llrm +stonith_la_LDFLAGS = -lpils -export-dynamic -module -avoid-version \ + -L$(top_builddir)/lib/fencing -lstonithd -lstonith -llrm install-exec-local: $(mkinstalldirs) $(DESTDIR)$(lrmdir) -chgrp $(apigid) $(DESTDIR)/$(lrmdir) chmod 770 $(DESTDIR)/$(lrmdir) diff --git a/lib/plugins/lrm/raexecstonith.c b/lib/plugins/lrm/raexecstonith.c index b1de9bfc9e..ef4f88dfeb 100644 --- a/lib/plugins/lrm/raexecstonith.c +++ b/lib/plugins/lrm/raexecstonith.c @@ -1,390 +1,390 @@ /* * 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 * * File: raexecocf.c * Author: Sun Jiang Dong * Copyright (c) 2004 International Business Machines * * This code implements the Resource Agent Plugin Module for LSB style. * It's a part of Local Resource Manager. Currently it's used by lrmd only. */ -#include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Add it for compiling on OSX */ #include #include #include #include # define PIL_PLUGINTYPE RA_EXEC_TYPE # define PIL_PLUGINTYPE_S "RAExec" # define PIL_PLUGINLICENSE LICENSE_PUBDOM # define PIL_PLUGINLICENSEURL URL_PUBDOM # define PIL_PLUGIN stonith # define PIL_PLUGIN_S "stonith" static PIL_rc close_stonithRA(PILInterface*, void* ud_interface); /* static const char * RA_PATH = STONITH_RA_DIR; */ /* Temporarily use it */ static const char * RA_PATH = HA_LIBHBDIR "/stonith/plugins/stonith/"; /* The begin of exported function list */ static int execra(const char * rsc_id, const char * rsc_type, const char * provider, const char * op_type, const int timeout, GHashTable * params); static uniform_ret_execra_t map_ra_retvalue(int ret_execra , const char * op_type, const char * std_output); static int get_resource_list(GList ** rsc_info); static char* get_resource_meta(const char* rsc_type, const char* provider); static int get_provider_list(const char* op_type, GList ** providers); /* The end of exported function list */ /* The begin of internal used function & data list */ static int get_providers(const char* class_path, const char* op_type, GList ** providers); static void stonithRA_ops_callback(stonithRA_ops_t * op, void * private_data); static int exit_value; /* The end of internal function & data list */ /* Rource agent execution plugin operations */ static struct RAExecOps raops = { execra, map_ra_retvalue, get_resource_list, get_provider_list, get_resource_meta }; static const char META_TEMPLATE[] = "\n" "\n" "\n" "1.0\n" "\n" "%s\n" "\n" "%s\n" "%s\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "2.0\n" "\n" "\n"; static const char * no_parameter_info = ""; #define CHECKMETANULL(ret, which) \ if (ret == NULL) { \ cl_log(LOG_WARNING, "stonithRA plugin: cannot get %s " \ "segment of %s's metadata.", which, rsc_type); \ ret = no_parameter_info; \ } #define xmlize(p) \ ( p ? (char *)xmlEncodeEntitiesReentrant(NULL, \ (const unsigned char *)p) \ : NULL ) #define zapxml(p) do { \ if( p ) { \ xmlFree(p); \ } \ } while(0) PIL_PLUGIN_BOILERPLATE2("1.0", Debug); static const PILPluginImports* PluginImports; static PILPlugin* OurPlugin; static PILInterface* OurInterface; static void* OurImports; static void* interfprivate; /* * Our plugin initialization and registration function * It gets called when the plugin gets loaded. */ PIL_rc PIL_PLUGIN_INIT(PILPlugin * us, const PILPluginImports* imports); PIL_rc PIL_PLUGIN_INIT(PILPlugin * us, const PILPluginImports* imports) { /* Force the compiler to do a little type checking */ (void)(PILPluginInitFun)PIL_PLUGIN_INIT; PluginImports = imports; OurPlugin = us; /* Register ourself as a plugin */ imports->register_plugin(us, &OurPIExports); /* Register our interfaces */ return imports->register_interface(us, PIL_PLUGINTYPE_S, PIL_PLUGIN_S, &raops, close_stonithRA, &OurInterface, &OurImports, interfprivate); } static PIL_rc close_stonithRA(PILInterface* pif, void* ud_interface) { return PIL_OK; } /* * Most of the oprations will be sent to sotnithd directly, such as 'start', * 'stop', 'monitor'. And others like 'meta-data' will be handled by itself * locally. * Some of important parameters' name: * config_file * config_string */ static int execra(const char * rsc_id, const char * rsc_type, const char * provider, const char * op_type,const int timeout, GHashTable * params) { stonithRA_ops_t * op; int call_id = -1; char buffer_tmp[32]; /* Handling "meta-data" operation in a special way. * Now handle "meta-data" operation locally. * Should be changed in the future? */ if ( 0 == STRNCMP_CONST(op_type, "meta-data")) { char * tmp; tmp = get_resource_meta(rsc_type, provider); printf("%s", tmp); g_free(tmp); exit(0); } g_snprintf(buffer_tmp, sizeof(buffer_tmp), "%s_%d" , "STONITH_RA_EXEC", getpid()); if (ST_OK != stonithd_signon(buffer_tmp)) { cl_log(LOG_ERR, "%s:%d: Cannot sign on the stonithd." , __FUNCTION__, __LINE__); exit(EXECRA_UNKNOWN_ERROR); } stonithd_set_stonithRA_ops_callback(stonithRA_ops_callback, &call_id); /* Temporarily donnot use it, but how to deal with the global OCF * variables. This is a important thing to think about and do. */ /* send the RA operation to stonithd to simulate a RA's actions */ if ( 0==STRNCMP_CONST(op_type, "start") || 0==STRNCMP_CONST(op_type, "stop") ) { cl_log(LOG_INFO , "Try to %s STONITH resource : Device=%s" , op_type, rsc_id, rsc_type); } op = g_new(stonithRA_ops_t, 1); op->ra_name = g_strdup(rsc_type); op->op_type = g_strdup(op_type); op->params = params; op->rsc_id = g_strdup(rsc_id); if (ST_OK != stonithd_virtual_stonithRA_ops(op, &call_id)) { cl_log(LOG_ERR, "sending stonithRA op to stonithd failed."); /* Need to improve the granularity for error return code */ stonithd_signoff(); exit(EXECRA_EXEC_UNKNOWN_ERROR); } /* May be redundant */ /* while (stonithd_op_result_ready() != TRUE) { ; } */ /* cl_log(LOG_DEBUG, "Will call stonithd_receive_ops_result."); */ if (ST_OK != stonithd_receive_ops_result(TRUE)) { cl_log(LOG_ERR, "stonithd_receive_ops_result failed."); /* Need to improve the granularity for error return code */ stonithd_signoff(); exit(EXECRA_EXEC_UNKNOWN_ERROR); } /* exit_value will be setted by the callback function */ g_free(op->ra_name); g_free(op->op_type); g_free(op->rsc_id); g_free(op); stonithd_signoff(); /* cl_log(LOG_DEBUG, "stonithRA orignal exit code=%d", exit_value); */ exit(map_ra_retvalue(exit_value, op_type, NULL)); } static void stonithRA_ops_callback(stonithRA_ops_t * op, void * private_data) { /* cl_log(LOG_DEBUG, "setting exit code=%d", exit_value); */ exit_value = op->op_result; } static uniform_ret_execra_t map_ra_retvalue(int ret_execra, const char * op_type, const char * std_output) { /* Because the UNIFORM_RET_EXECRA is compatible with OCF standard, no * actual mapping except validating, which ensure the return code * will be in the range 0 to 7. Too strict? */ if (ret_execra < 0 || ret_execra > EXECRA_STATUS_UNKNOWN) { cl_log(LOG_WARNING, "mapped the invalid return code %d." , ret_execra); ret_execra = EXECRA_UNKNOWN_ERROR; } return ret_execra; } static int get_resource_list(GList ** rsc_info) { int rc; int needprivs = !cl_have_full_privs(); if ( rsc_info == NULL ) { cl_log(LOG_ERR, "Parameter error: get_resource_list"); return -2; } if ( *rsc_info != NULL ) { cl_log(LOG_ERR, "Parameter error: get_resource_list."\ "will cause memory leak."); *rsc_info = NULL; } if (needprivs) { return_to_orig_privs(); } if (ST_OK != stonithd_signon("STONITH_RA")) { cl_log(LOG_ERR, "%s:%d: Can not signon to the stonithd." , __FUNCTION__, __LINE__); rc = -1; } else { rc = stonithd_list_stonith_types(rsc_info); stonithd_signoff(); } if (needprivs) { return_to_dropped_privs(); } return rc; } static int get_provider_list(const char* op_type, GList ** providers) { int ret; ret = get_providers(RA_PATH, op_type, providers); if (0>ret) { cl_log(LOG_ERR, "scandir failed in stonith RA plugin"); } return ret; } static char * get_resource_meta(const char* rsc_type, const char* provider) { char * buffer; int bufferlen = 0; const char * meta_param = NULL; const char * meta_longdesc = NULL; const char * meta_shortdesc = NULL; char *xml_meta_longdesc = NULL; char *xml_meta_shortdesc = NULL; Stonith * stonith_obj = NULL; if ( provider != NULL ) { cl_log(LOG_DEBUG, "stonithRA plugin: provider attribute " "is not needed and will be ignored."); } stonith_obj = stonith_new(rsc_type); meta_longdesc = stonith_get_info(stonith_obj, ST_DEVICEDESCR); CHECKMETANULL(meta_longdesc, "longdesc") xml_meta_longdesc = xmlize(meta_longdesc); meta_shortdesc = stonith_get_info(stonith_obj, ST_DEVICENAME); CHECKMETANULL(meta_shortdesc, "shortdesc") xml_meta_shortdesc = xmlize(meta_shortdesc); meta_param = stonith_get_info(stonith_obj, ST_CONF_XML); CHECKMETANULL(meta_param, "parameters") bufferlen = STRLEN_CONST(META_TEMPLATE) + strlen(rsc_type) + strlen(xml_meta_longdesc) + strlen(xml_meta_shortdesc) + strlen(meta_param) + 1; buffer = g_new(char, bufferlen); buffer[bufferlen-1] = '\0'; snprintf(buffer, bufferlen-1, META_TEMPLATE, rsc_type , xml_meta_longdesc, xml_meta_shortdesc, meta_param); stonith_delete(stonith_obj); zapxml(xml_meta_longdesc); zapxml(xml_meta_shortdesc); return buffer; } /* * Currently should return *providers = NULL, but remain the old code for * possible unsing in the future */ static int get_providers(const char* class_path, const char* op_type, GList ** providers) { if ( providers == NULL ) { cl_log(LOG_ERR, "%s:%d: Parameter error: providers==NULL" , __FUNCTION__, __LINE__); return -2; } if ( *providers != NULL ) { cl_log(LOG_ERR, "%s:%d: Parameter error: *providers==NULL." "This will cause memory leak." , __FUNCTION__, __LINE__); } /* Now temporarily make it fixed */ *providers = g_list_append(*providers, g_strdup("heartbeat")); return g_list_length(*providers); } diff --git a/pacemaker.spec b/pacemaker.spec index f8c384f8f9..b433a35633 100644 --- a/pacemaker.spec +++ b/pacemaker.spec @@ -1,295 +1,294 @@ # # spec file for package Pacemaker (Version 0.7.0) # # Copyright (c) 2006 SUSE LINUX Products GmbH, Nuernberg, Germany. # This file and all modifications and additions to the pristine # package are under the same license as the package itself. # # Please submit bugfixes or comments via http://bugs.opensuse.org/ # # norootforbuild %define with_extra_warnings 0 %define with_debugging 0 %define without_fatal_warnings 1 %define with_ais_support 1 %define with_heartbeat_support 1 %define with_snmp_support 1 %define pkg_group Productivity/Clustering/HA %if 0%{?fedora_version} %define pkg_group System Environment/Daemons %endif %define gname haclient %define uname hacluster Name: pacemaker Summary: The Pacemaker scalable High-Availability cluster resource manager Version: 0.6.2 Release: 1 License: GPL2/LGPL2 URL: http://www.clusterlabs.org Group: %{pkg_group} Source: pacemaker.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-build Autoreqprov: on %if %with_ais_support BuildRequires: openais-devel %endif %if %with_heartbeat_support BuildRequires: heartbeat heartbeat-devel > 2.1.2 %endif %if %{with_ais_support} %if %{with_heartbeat_support} Conflicts: pacemaker-ais Conflicts: pacemaker-heartbeat %else Conflicts: pacemaker Conflicts: pacemaker-heartbeat %endif %else Conflicts: pacemaker Conflicts: pacemaker-ais %endif BuildRequires: heartbeat-common heartbeat-common-devel e2fsprogs-devel glib2-devel gnutls-devel libxml2-devel pam-devel python-devel swig %if 0%{?suse_version} %if 0%{?suse_version} > 1000 %if %with_ais_support Supplements: openais %endif %if %with_heartbeat_support Supplements: heartbeat %endif %endif %if 0%{?suse_version} == 930 BuildRequires: rpm-devel %endif %if 0%{?suse_version} == 1000 BuildRequires: lzo lzo-devel %endif %if 0%{?suse_version} < 1020 BuildRequires: tcpd-devel %endif %if 0%{?sles_version} == 9 BuildRequires: pkgconfig %endif %endif %if 0%{?fedora_version} || 0%{?centos_version} || 0%{?rhel_version} BuildRequires: which %endif %if 0%{?fedora_version} == 8 BuildRequires: openssl-devel %endif %if 0%{?mandriva_version} BuildRequires: libbzip2-devel %endif %description Pacemaker is an advanced, scalable High-Availability cluster resource manager for Linux-HA (Heartbeat) and/or OpenAIS. It supports "n-node" clusters with significant capabilities for managing resources and dependencies. It will run scripts at initialization, when machines go up or down, when related resources fail and can be configured to periodically check resource health. %if 0%{?suse_version} %debug_package %endif %package devel Summary: Pacemaker development package Group: %{pkg_group} Requires: %{name} = %{version}-%{release} %description devel Header files and shared libraries needed for developing programs based on the Pacemaker High-Availability cluster resource manager. %prep ########################################################### %setup -n pacemaker ########################################################### %build # TODO: revisit -all CFLAGS="${CFLAGS} ${RPM_OPT_FLAGS}" # Feature-dependent CFLAGS: %if %with_extra_warnings # CFLAGS="${CFLAGS} -Wshadow -Wfloat-equal -Waggregate-return -Wnested-externs -Wunreachable-code -Wendif-labels -Winline" CFLAGS="${CFLAGS} -Wfloat-equal -Wendif-labels -Winline" %endif %if %with_debugging CFLAGS="${CFLAGS} -O0" %endif # Distribution specific settings: %if 0%{?suse_version} > 1001 CFLAGS="${CFLAGS} -fstack-protector-all" %endif %if 0%{?suse_version} < 1001 export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/opt/gnome/%{_lib}/pkgconfig:/opt/gnome/share/pkgconfig" %endif %if 0%{?suse_version} > 1020 CFLAGS="$CFLAGS -fgnu89-inline" %endif %if 0%{?fedora_version} > 6 CFLAGS="$CFLAGS -fgnu89-inline" %endif export CFLAGS ./ConfigureMe configure --prefix=%{_prefix} --sysconfdir=%{_sysconfdir} \ --localstatedir=%{_var} --infodir=%{_infodir} \ --mandir=%{_mandir} --libdir=%{_libdir} \ --libexecdir=%{_libexecdir} \ --with-group-name=%{gname} --with-ccmuser-name=%{uname} \ --with-hapkgversion=%{version} \ --enable-glib-malloc \ %if %with_snmp_support == 1 --enable-snmp-subagent \ %else --disable-snmp-subagent \ %endif --with-ais-prefix=%{_prefix} \ %if %with_ais_support == 0 --without-ais-support \ %endif %if %with_heartbeat_support == 0 --without-heartbeat-support \ %endif %if %without_fatal_warnings --enable-fatal-warnings=no \ %endif --enable-pretty export MAKE="make %{?jobs:-j%jobs}" make %{?jobs:-j%jobs} ########################################################### %install ########################################################### #make DESTDIR=$RPM_BUILD_ROOT install-strip rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT make DESTDIR=$RPM_BUILD_ROOT install #%if %with_ais_support # mkdir -p $RPM_BUILD_ROOT/%{_libexecdir}/lcrso # cp $RPM_BUILD_ROOT/%{_libdir}/service_crm.so $RPM_BUILD_ROOT/%{_libexecdir}/lcrso/pacemaker.lcrso #%endif # Cleanup [ -d $RPM_BUILD_ROOT/usr/man ] && rm -rf $RPM_BUILD_ROOT/usr/man [ -d $RPM_BUILD_ROOT/usr/share/libtool ] && rm -rf $RPM_BUILD_ROOT/usr/share/libtool find $RPM_BUILD_ROOT -name '*.a' -type f -print0 | xargs -0 rm -f find $RPM_BUILD_ROOT -name '*.la' -type f -print0 | xargs -0 rm -f ########################################################### %clean ########################################################### if [ -n "${RPM_BUILD_ROOT}" -a "${RPM_BUILD_ROOT}" != "/" ] then rm -rf $RPM_BUILD_ROOT fi rm -rf $RPM_BUILD_DIR/pacemaker ########################################################### %pre %preun # Use the following if more commands need to be executed # %post # /sbin/ldconfig # [...] # http://en.opensuse.org/SUSE_Package_Conventions/RPM_Macros %post -p /sbin/ldconfig %postun -p /sbin/ldconfig %files ########################################################### %defattr(-,root,root) %dir %{_libdir}/heartbeat %{_prefix}/share/pacemaker %{_prefix}/share/heartbeat %{_libdir}/heartbeat/* -%{_libdir}/heartbeat/plugins/RAExec/* %dir %{_var}/lib/heartbeat %{_libdir}/libcib.so.* %{_libdir}/libcrmcommon.so.* %{_libdir}/libcrmcluster.so.* #%{_libdir}/heartbeat/crm_primitive.py %{_libdir}/libpe_status.so.* %{_libdir}/libpe_rules.so.* %{_libdir}/libpengine.so.* %{_libdir}/libtransitioner.so.* %{_libdir}/libstonithd.so.* %{_sbindir}/cibadmin %{_sbindir}/crm_attribute %{_sbindir}/crm_diff %{_sbindir}/crm_failcount %{_sbindir}/crm_master %{_sbindir}/crm_mon %{_sbindir}/crm_sh %{_sbindir}/crm_resource %{_sbindir}/crm_standby %{_sbindir}/crm_uuid %{_sbindir}/crm_verify %{_sbindir}/crmadmin %{_sbindir}/iso8601 %{_sbindir}/ccm_tool %{_sbindir}/attrd_updater %{_sbindir}/ptest %doc %{_mandir}/man8/cibadmin.8* %doc %{_mandir}/man8/crm_resource.8* %dir %attr (750, %{uname}, %{gname}) %{_var}/lib/heartbeat/crm %dir %attr (750, %{uname}, %{gname}) %{_var}/lib/heartbeat/pengine %dir %attr (750, %{uname}, %{gname}) %{_var}/run/heartbeat/crm %if %with_ais_support %{_libexecdir}/lcrso/pacemaker.lcrso %endif %if %with_snmp_support == 1 /usr/share/snmp/mibs/LINUX-HA-MIB.mib %endif %files devel %defattr(-,root,root) #%doc %{_datadir}/doc/%{name}-%{version} %{_includedir}/pacemaker %{_includedir}/heartbeat/fencing %{_libdir}/*.so %changelog pacemaker diff --git a/pengine/group.c b/pengine/group.c index 0a29f1d9b3..01c644e0e5 100644 --- a/pengine/group.c +++ b/pengine/group.c @@ -1,509 +1,564 @@ /* * 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 VARIANT_GROUP 1 #include node_t * group_color(resource_t *rsc, pe_working_set_t *data_set) { node_t *node = NULL; node_t *group_node = NULL; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); if(is_not_set(rsc->flags, pe_rsc_provisional)) { return rsc->allocated_to; } crm_debug_2("Processing %s", rsc->id); if(is_set(rsc->flags, pe_rsc_allocating)) { crm_debug("Dependancy loop detected involving %s", rsc->id); return NULL; } if(group_data->first_child == NULL) { /* nothign to allocate */ clear_bit(rsc->flags, pe_rsc_provisional); return NULL; } set_bit(rsc->flags, pe_rsc_allocating); rsc->role = group_data->first_child->role; group_data->first_child->rsc_cons = g_list_concat( group_data->first_child->rsc_cons, rsc->rsc_cons); rsc->rsc_cons = NULL; dump_node_scores(scores_log_level, rsc, __PRETTY_FUNCTION__, rsc->allowed_nodes); slist_iter( child_rsc, resource_t, rsc->children, lpc, node = child_rsc->cmds->color(child_rsc, data_set); if(group_node == NULL) { group_node = node; } ); rsc->next_role = group_data->first_child->next_role; clear_bit(rsc->flags, pe_rsc_allocating); clear_bit(rsc->flags, pe_rsc_provisional); if(group_data->colocated) { return group_node; } return NULL; } 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; const char *value = NULL; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_2("Creating actions for %s", rsc->id); slist_iter( child_rsc, resource_t, rsc->children, lpc, child_rsc->cmds->create_actions(child_rsc, data_set); group_update_pseudo_status(rsc, child_rsc); ); op = start_action(rsc, NULL, TRUE/* !group_data->child_starting */); op->pseudo = TRUE; op->runnable = TRUE; op = custom_action(rsc, started_key(rsc), RSC_STARTED, NULL, TRUE/* !group_data->child_starting */, TRUE, data_set); op->pseudo = TRUE; op->runnable = TRUE; op = stop_action(rsc, NULL, TRUE/* !group_data->child_stopping */); op->pseudo = TRUE; op->runnable = TRUE; op = custom_action(rsc, stopped_key(rsc), RSC_STOPPED, NULL, TRUE/* !group_data->child_stopping */, TRUE, data_set); op->pseudo = TRUE; op->runnable = TRUE; value = g_hash_table_lookup(rsc->parameters, crm_meta_name("stateful")); if(crm_is_true(value)) { op = custom_action(rsc, demote_key(rsc), RSC_DEMOTE, NULL, TRUE, TRUE, data_set); op->pseudo = TRUE; op->runnable = TRUE; op = custom_action(rsc, demoted_key(rsc), RSC_DEMOTED, NULL, TRUE, TRUE, data_set); op->pseudo = TRUE; op->runnable = TRUE; op = custom_action(rsc, promote_key(rsc), RSC_PROMOTE, NULL, TRUE, TRUE, data_set); op->pseudo = TRUE; op->runnable = TRUE; op = custom_action(rsc, promoted_key(rsc), RSC_PROMOTED, NULL, TRUE, TRUE, data_set); op->pseudo = TRUE; op->runnable = TRUE; } rsc->actions = rsc->actions; /* rsc->actions = NULL; */ } 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->ordered == FALSE) { /* If this group is not ordered, then leave the meta-actions as optional */ return; } 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(RSC_STOP, action->task) && action->runnable) { group_data->child_stopping = TRUE; crm_debug_3("Based on %s the group is stopping", action->uuid); } else if(safe_str_eq(RSC_START, action->task) && action->runnable) { group_data->child_starting = TRUE; crm_debug_3("Based on %s the group is starting", action->uuid); } ); } void group_internal_constraints(resource_t *rsc, pe_working_set_t *data_set) { const char *value = NULL; gboolean stateful = FALSE; resource_t *last_rsc = NULL; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); native_internal_constraints(rsc, data_set); value = g_hash_table_lookup(rsc->parameters, crm_meta_name("stateful")); stateful = crm_is_true(value); new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_START, pe_order_optional, data_set); new_rsc_order(rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_runnable_left|pe_order_implies_right|pe_order_implies_left, data_set); new_rsc_order(rsc, RSC_START, rsc, RSC_STARTED, pe_order_runnable_left, data_set); slist_iter( child_rsc, resource_t, rsc->children, lpc, int stop = pe_order_shutdown|pe_order_implies_right; int stopped = pe_order_implies_right_printed; int start = pe_order_implies_right|pe_order_runnable_left; int started = pe_order_runnable_left|pe_order_implies_right|pe_order_implies_right_printed; child_rsc->cmds->internal_constraints(child_rsc, data_set); if(last_rsc == NULL) { stop |= pe_order_implies_left; stopped = pe_order_implies_right; } else if(group_data->colocated) { rsc_colocation_new( "group:internal_colocation", NULL, INFINITY, child_rsc, last_rsc, NULL, NULL, data_set); } if(stateful) { new_rsc_order(rsc, RSC_DEMOTE, child_rsc, RSC_DEMOTE, stop|pe_order_implies_left_printed, data_set); new_rsc_order(child_rsc, RSC_DEMOTE, rsc, RSC_DEMOTED, stopped, data_set); new_rsc_order(child_rsc, RSC_PROMOTE, rsc, RSC_PROMOTED, started, data_set); new_rsc_order(rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE, pe_order_implies_left_printed, data_set); } order_start_start(rsc, child_rsc, pe_order_implies_left_printed); order_stop_stop(rsc, child_rsc, stop|pe_order_implies_left_printed); new_rsc_order(child_rsc, RSC_STOP, rsc, RSC_STOPPED, stopped, data_set); new_rsc_order(child_rsc, RSC_START, rsc, RSC_STARTED, started, data_set); if(group_data->ordered == FALSE) { order_start_start(rsc, child_rsc, start|pe_order_implies_left_printed); if(stateful) { new_rsc_order(rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE, start|pe_order_implies_left_printed, data_set); } } else if(last_rsc != NULL) { child_rsc->restart_type = pe_restart_restart; order_start_start(last_rsc, child_rsc, start); order_stop_stop(child_rsc, last_rsc, pe_order_implies_left); if(stateful) { new_rsc_order(last_rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE, start, data_set); new_rsc_order(child_rsc, RSC_DEMOTE, last_rsc, RSC_DEMOTE, pe_order_implies_left, data_set); } } else { /* If anyone in the group is starting, then * pe_order_implies_right will cause _everyone_ in the group * to be sent a start action * But this is safe since starting something that is already * started is required to be "safe" */ int flags = pe_order_implies_left|pe_order_implies_right|pe_order_runnable_right|pe_order_runnable_left; order_start_start(rsc, child_rsc, flags); if(stateful) { new_rsc_order(rsc, RSC_PROMOTE, child_rsc, RSC_PROMOTE, flags, data_set); } } last_rsc = child_rsc; ); if(group_data->ordered && last_rsc != NULL) { int stop_stop_flags = pe_order_implies_right; int stop_stopped_flags = pe_order_implies_left; order_stop_stop(rsc, last_rsc, stop_stop_flags); new_rsc_order(last_rsc, RSC_STOP, rsc, RSC_STOPPED, stop_stopped_flags, data_set); if(stateful) { new_rsc_order(rsc, RSC_DEMOTE, last_rsc, RSC_DEMOTE, stop_stop_flags, data_set); new_rsc_order(last_rsc, RSC_DEMOTE, rsc, RSC_DEMOTED, stop_stopped_flags, data_set); } } } 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); if(group_data->colocated) { group_data->first_child->cmds->rsc_colocation_lh( group_data->first_child, rsc_rh, constraint); return; } else if(constraint->score >= INFINITY) { crm_config_err("%s: Cannot perform manditory colocation" " between non-colocated group and %s", rsc_lh->id, rsc_rh->id); return; } slist_iter( child_rsc, resource_t, rsc_lh->children, lpc, 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(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(is_set(rsc_rh->flags, pe_rsc_provisional)) { return; } else if(group_data->colocated && group_data->first_child) { group_data->first_child->cmds->rsc_colocation_rh( rsc_lh, group_data->first_child, constraint); return; } else if(constraint->score >= INFINITY) { crm_config_err("%s: Cannot perform manditory colocation with" " non-colocated group: %s", rsc_lh->id, rsc_rh->id); return; } slist_iter( child_rsc, resource_t, rsc_rh->children, lpc, child_rsc->cmds->rsc_colocation_rh( rsc_lh, child_rsc, constraint); ); } void group_rsc_order_lh(resource_t *rsc, order_constraint_t *order, pe_working_set_t *data_set) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug_4("%s->%s", order->lh_action_task, order->rh_action_task); if(order->rh_rsc != NULL && (rsc == order->rh_rsc || rsc == order->rh_rsc->parent)) { native_rsc_order_lh(rsc, order, data_set); return; } #if 0 if(order->type != pe_order_optional) { native_rsc_order_lh(rsc, order, data_set); } if(order->type & pe_order_implies_left) { native_rsc_order_lh(group_data->first_child, order, data_set); } #endif convert_non_atomic_task(rsc, order, TRUE); native_rsc_order_lh(rsc, order, data_set); } 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_4("%s->%s", lh_action->uuid, order->rh_action_task); if(rsc == NULL) { return; } if(safe_str_eq(CRM_OP_PROBED, lh_action->uuid)) { slist_iter( child_rsc, resource_t, rsc->children, lpc, child_rsc->cmds->rsc_order_rh(lh_action, child_rsc, order); ); if(rsc->fns->state(rsc, TRUE) < RSC_ROLE_STARTED && rsc->fns->state(rsc, FALSE) > RSC_ROLE_STOPPED) { order->type |= pe_order_implies_right; } } else if(lh_action->rsc != NULL && lh_action->rsc != rsc && lh_action->rsc != rsc->parent && lh_action->rsc->parent != rsc) { char *tmp = NULL; char *task_s = NULL; int interval = 0; enum action_tasks task = 0; parse_op_key(order->lh_action_task, &tmp, &task_s, &interval); task = text2task(task_s); crm_free(task_s); crm_free(tmp); switch(task) { case no_action: case monitor_rsc: case action_notify: case action_notified: case shutdown_crm: case stonith_node: break; case stop_rsc: case stopped_rsc: case action_demote: case action_demoted: order->type |= pe_order_complex_left; break; case start_rsc: case started_rsc: case action_promote: case action_promoted: order->type |= pe_order_complex_right; break; } } native_rsc_order_rh(lh_action, rsc, order); } void group_rsc_location(resource_t *rsc, rsc_to_node_t *constraint) { GListPtr saved = constraint->node_list_rh; GListPtr zero = node_list_dup(constraint->node_list_rh, TRUE, FALSE); gboolean reset_scores = TRUE; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); crm_debug("Processing rsc_location %s for %s", constraint->id, rsc->id); slist_iter( child_rsc, resource_t, rsc->children, lpc, child_rsc->cmds->rsc_location(child_rsc, constraint); if(group_data->colocated && reset_scores) { reset_scores = FALSE; constraint->node_list_rh = zero; } ); constraint->node_list_rh = saved; pe_free_shallow_adv(zero, TRUE); } 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(rsc != NULL, return); native_expand(rsc, data_set); slist_iter( child_rsc, resource_t, rsc->children, lpc, child_rsc->cmds->expand(child_rsc, data_set); ); } +extern void node_list_update(GListPtr list1, GListPtr list2, int factor); + GListPtr group_merge_weights( resource_t *rsc, const char *rhs, GListPtr nodes, int factor, gboolean allow_rollback) { + GListPtr archive = NULL; + GListPtr child_nodes = NULL; group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); if(is_set(rsc->flags, pe_rsc_merging)) { crm_debug("Breaking dependancy loop with %s at %s", rsc->id, rhs); return nodes; - } else if(is_not_set(rsc->flags, pe_rsc_provisional) || can_run_any(nodes) == FALSE) { + } else if(is_not_set(rsc->flags, pe_rsc_provisional)) { return nodes; } set_bit(rsc->flags, pe_rsc_merging); + +#if 0 + /* turn this back on once we switch to migration-threshold */ nodes = group_data->first_child->cmds->merge_weights( group_data->first_child, rhs, nodes, factor, allow_rollback); + +#else + slist_iter(child, resource_t, rsc->children, lpc, + + if(allow_rollback) { + archive = node_list_dup(nodes, FALSE, FALSE); + } + + child_nodes = node_list_dup(child->allowed_nodes, FALSE, FALSE); + slist_iter( + constraint, rsc_colocation_t, child->rsc_cons_lhs, lpc2, + + child_nodes = constraint->rsc_lh->cmds->merge_weights( + constraint->rsc_lh, rhs, child_nodes, + constraint->score/INFINITY, allow_rollback); + ); + + slist_iter( + node, node_t, child_nodes, lpc2, + if(node->weight < 0 && node->weight > -INFINITY) { + /* Once a child's score goes below zero, force the node score to -INFINITY + * + * This prevents the group from being partially active in scenarios + * where it could be fully active elsewhere + * + * If we don't do this, then the next child(ren)'s stickiness might bring + * the combined score above 0 again - which confuses the PE into thinking + * the whole group can run there but is pointless since the later children + * are not be able to run if the ones before them can't + */ + node->weight = -INFINITY; + } + ); + + node_list_update(nodes, child_nodes, factor); + pe_free_shallow_adv(child_nodes, TRUE); + + if(archive && can_run_any(nodes) == FALSE) { + crm_err("%s: Rolling back scores from %s", rhs, rsc->id); + pe_free_shallow_adv(nodes, TRUE); + nodes = archive; + goto bail; + } + + pe_free_shallow_adv(archive, TRUE); + ); +#endif slist_iter( constraint, rsc_colocation_t, rsc->rsc_cons_lhs, lpc, nodes = native_merge_weights( constraint->rsc_lh, rsc->id, nodes, constraint->score/INFINITY, allow_rollback); ); + bail: clear_bit(rsc->flags, pe_rsc_merging); return nodes; }