diff --git a/crm/crm-1.0.dtd b/crm/crm-1.0.dtd index a4665ea30a..cd6e03bfcf 100644 --- a/crm/crm-1.0.dtd +++ b/crm/crm-1.0.dtd @@ -1,834 +1,835 @@ <?xml version="1.0" encoding="UTF-8" ?> <!-- GLOBAL TODOs: Versionize DTD so we can validate against a specific version Background The CIB is described quite well in section 5 of the crm.txt (checked into CVS in the crm directory) so it is not repeated here. Suffice to say that it stores the configuration and runtime data required for cluster-wide resource management in XML format. CIB: Information Structure The CIB is divided into two main sections: The "static" configuration part and the "dynamic" status. The configuration contains - surprisingly - the configuration of the cluster, namely node attributes, resource instance configuration, and the constraints which describe the dependencies between all these. To identify the most recent configuration available in the cluster, this section is time-stamped with the unique timestamp of the last update. The status part is dynamically generated / updated by the CRM system and represents the current status of the cluster; which nodes are up, down or crashed, which resources are running where etc. Every information carrying object has an "id" tag, which is basically the UUID of it, should we ever need to access it directly. Unless otherwise stated, the id field is a short name consisting simple ascii characters [a-zA-Z0-9_\-] The exception is for resources because the LRM can support only id's of up to 64 characters. Other Notes The description field in all elements is opaque to the CRM and is for administrative comments. TODO * Figure out a sane way to version the DTD * Do we need to know about ping nodes...? * The integer comparison type really should be number --> <!ELEMENT cib (configuration, status)> <!ATTLIST cib cib-last-written CDATA #IMPLIED admin_epoch CDATA #REQUIRED epoch CDATA #REQUIRED num_updates CDATA #REQUIRED num_peers CDATA #IMPLIED cib_feature_revision CDATA #IMPLIED crm_feature_set CDATA #IMPLIED dc_uuid CDATA #IMPLIED ccm_transition CDATA #IMPLIED have_quorum (true|1|false|0) 'false' ignore_dtd (true|1|false|0) #IMPLIED generated CDATA #IMPLIED crm-debug-origin CDATA #IMPLIED> <!-- The CIB's version is a tuple of admin_epoch, epoch and num_updates (in that order). This is used when applying updates from the master CIB instance. Additionally, num_peers and have_quorum are used during the election process to determin who has the latest configuration. * num_updates is incremented every time the CIB changes. * epoch is incremented after every DC election. * admin_epoch is exclusivly for the admin to change. * num_peers is the number of CIB instances that we can talk to * have_quorum is derived from the ConsensusClusterMembership layer * dc_uuid stored the UUID of the current DesignatedController * ccm_transition stores the membership instance from the ConsensusClusterMembership layer. * cib_feature_revision is the feature set that this configuration requires --> <!ELEMENT configuration (crm_config, nodes, resources, constraints)> <!-- crm_config Used to specify cluster-wide options. The use of multiple cluster_property_set sections and time-based rule expressions allows the the cluster to behave differently (for example) during buisness hours than it does overnight. --> <!ELEMENT crm_config (cluster_property_set)*> <!-- Current crm_config options: * transition_idle_timeout (interval, default=60s): If no activity is recorded in this time, the transition is deemed failed as are all sent actions that have not yet been confirmed complete. If any operation initiated has an explicit higher timeout, the higher value applies. * symmetric_cluster (boolean, default=TRUE): If true, resources are permitted to run anywhere by default. Otherwise, explicit constraints must be created to specify where they can run. * stonith_enabled (boolean, default=FALSE): If true, failed nodes will be fenced. * no_quorum_policy (enum, default=stop) * ignore - Pretend we have quorum * freeze - Do not start any resources not currently in our partition. Resources in our partition may be moved to another node within the partition Fencing is disabled * stop - Stop all running resources in our partition Fencing is disabled * default_resource_stickiness Do we prefer to run on the existing node or be moved to a "better" one? * 0 : resources will be placed optimally in the system. This may mean they are moved when a "better" or less loaded node becomes available. This option is almost equivalent to auto_failback on except that the resource may be moved to other nodes than the one it was previously active on. * value > 0 : resources will prefer to remain in their current location but may be moved if a more suitable node is available. Higher values indicate a stronger preference for resources to stay where they are. * value < 0 : resources prefer to move away from their current location. Higher absolute values indicate a stronger preference for resources to be moved. * INFINITY : resources will always remain in their current locations until forced off because the node is no longer eligible to run the resource (node shutdown, node standby or configuration change). This option is almost equivalent to auto_failback off except that the resource may be moved to other nodes than the one it was previously active on. * -INFINITY : resources will always move away from their current location. * is_managed_default (boolean, default=TRUE) Unless the resource's definition says otherwise, * TRUE : resources will be started, stopped, monitored and moved as necessary/required * FALSE : resources will not started if stopped, stopped if started nor have any recurring actions scheduled. * stop_orphan_resources (boolean, default=TRUE (as of release 2.0.6)) If a resource is found for which we have no definition for; * TRUE : Stop the resource * FALSE : Ignore the resource This mostly effects the CRM's behavior when a resource is deleted by an admin without it first being stopped. * stop_orphan_actions (boolean, default=TRUE) If a recurring action is found for which we have no definition for; * TRUE : Stop the action * FALSE : Ignore the action This mostly effects the CRM's behavior when the interval for a recurring action is changed. --> <!ELEMENT cluster_property_set (rule*, attributes)> <!ATTLIST cluster_property_set id CDATA #REQUIRED score CDATA #IMPLIED> <!ELEMENT nodes (node*)> <!-- * id : the node's UUID. * uname : the result of uname -n * type : should either be "normal" or "member" for nodes you with to run resources "normal" is preferred as of version 2.0.4 Each node can also have additional "instance" attributes. These attributes are completely arbitrary and can be used later in constraints. In this way it is possible to define groups of nodes to which a constraint can apply. It is also theoretically possible to have a process on each node which updates these values automatically. This would make it possible to have an attribute that represents "connected to SAN subsystem" or perhaps "system_load (low|medium|high)". Ideally it would be possible to have the CRMd on each node gather some of this information and automatically populate things like architecture and OS/kernel version. --> <!ELEMENT node (instance_attributes*)> <!ATTLIST node id CDATA #REQUIRED uname CDATA #REQUIRED description CDATA #IMPLIED type (normal|member|ping) #REQUIRED> <!ELEMENT resources (primitive|group|clone|master_slave)*> <!-- * class Specifies the location and standard the resource script conforms to * ocf Most OCF RAs started out life as v1 Heartbeat resource agents. These have all been ported to meet the OCF specifications. As an added advantage, in accordance with the OCF spec, they also describe the parameters they take and what their defaults are. It is also easier to configure them as each part of the configuration is passed as its own parameter. In accordance with the OCF spec, each parameter is passed to the RA with an OCF_RESKEY_ prefix. So ip=192.168.1.1 in the CIB would be passed as OCF_RESKEY_ip=192.168.1.1. Located under /usr/lib/ocf/resource.d/heartbeat/. * lsb Most Linux init scripts conform to the LSB specification. The class allows you to use those that do as resource agents controlled by Heartbeat. Located in /etc/init.d/. * heartbeat This class gives you access to the v1 Heartbeat resource agents and allows you to reuse any custom agents you may have written. Located at /etc/heartbeat/resource.d/ or /etc/ha.d/resource.d. * type : The name of the ResourceAgent you wish to use. * provider The OCF spec allows multiple vendors to supply the same ResourceAgent. To use the OCF resource agents supplied with Heartbeat, you should specify heartbeat here * is_managed : Is the ClusterResourceManager in control of this resource. * true : (default) the resource will be started, stopped, monitored and moved as necessary/required * false : the resource will not started if stopped, stopped if started nor have any recurring actions scheduled. The resource may still be referenced in colocation constraints and ordering constraints (though obviously if no actions are performed on it then it will prevent the action on the other resource too) * restart_type Used when the other side of an ordering dependency is restarted/moved. * ignore : the default. Don't do anything extra. * restart Use this for example to have a restart of your database also trigger a restart of your web-server. * multiple_active Used when a resource is detected as being active on more than one machine. The default value, stop_start, will stop all instances and start only 1 * block : don't do anything, wait for the administrator * stop_only : stop all the active instances * stop_start : start the resource on one node after having stopped all the active instances * resource_stickiness See the description of the default_resource_stickiness cluster attribute. resource_stickiness allows you to override the cluster's default for the individual resource. NOTE: primitive resources may contain at most one "operations" object. The CRM will complain about your configuration if this criteria is not met. Please use crm_verify to ensure your configuration is valid. The DTD is written this way to be order in-sensitive. --> <!ELEMENT primitive (operations|meta_attributes|instance_attributes)*> <!ATTLIST primitive id CDATA #REQUIRED description CDATA #IMPLIED class (ocf|lsb|heartbeat|stonith) #REQUIRED type CDATA #REQUIRED provider CDATA #IMPLIED is_managed CDATA #IMPLIED restart_type (ignore|restart) 'ignore' multiple_active (stop_start|stop_only|block) 'stop_start' resource_stickiness CDATA #IMPLIED> <!-- This allows us to specify how long an action can take * name : the name of the operation. Supported operations are start, stop, & monitor * start_delay : delay the operation after starting the resource By default this value is in milliseconds, however you can also specify a value in seconds like so timeout="5s". Used for the monitor operation. * timeout : the maximum period of time before considering the action failed. By default this value is in milliseconds, however you can also specify a value in seconds like so timeout="5s". * interval : This currently only applies to monitor operations and specifies how often the LRM should check the resource is active. The same notation for timeout applies. * prereq : What conditions need to be met before this action can be run * nothing : This action can be performed at any time * quorum : This action requires the partition to have quorum * fencing : This action requires the partition to have quorum and any fencing operations to have completed before it can be executed * on_fail : The action to take if this action ever fails. * nothing : Pretend the action didnt actually fail * block : Take no further action on the resource - wait for the administrator to resolve the issue * restart : Stop the resource and re-allocate it elsewhere * stop : Stop the resource and DO NOT re-allocate it elsewhere * fence : Currently this means fence the node on which the resource is running. Any other resources currently active on the machine will be migrated away before fencing occurs. Only one entry per supported action+interval is currently permitted. Parameters specific to each operation can be passed using the instance_attributes section. --> <!ELEMENT operations (op*)> <!ELEMENT op (meta_attributes|instance_attributes)*> <!ATTLIST op id CDATA #REQUIRED name CDATA #REQUIRED description CDATA #IMPLIED interval CDATA #IMPLIED timeout CDATA #IMPLIED start_delay CDATA '0' disabled (true|1|false|0) 'false' role (Master|Slave|Started|Stopped) 'Started' prereq (nothing|quorum|fencing) #IMPLIED on_fail (ignore|block|stop|restart|fence) #IMPLIED> <!-- Use this to emulate v1 type Heartbeat groups. Defining a resource group is a quick way to make sure that the resources: * are all started on the same node, and * are started and stopped in the correct (sequential) order though either or both of these properties can be disabled. NOTE: Do not create empty groups. They are temporarily supported because the GUI requires it but will be removed as soon as possible. The DTD is written this way to be order in-sensitive. --> <!ELEMENT group (meta_attributes|instance_attributes|primitive)*> <!ATTLIST group id CDATA #REQUIRED description CDATA #IMPLIED is_managed CDATA #IMPLIED restart_type (ignore|restart) 'ignore' multiple_active (stop_start|stop_only|block) 'stop_start' resource_stickiness CDATA #IMPLIED ordered (true|1|false|0) 'true' collocated (true|1|false|0) 'true'> <!-- Clones are intended as a mechanism for easily starting a number of resources (such as a web-server) with the same configuration. As an added benefit, the number that should be started is an instance parameter and when combined with time-based constraints, allows the administrator to run more instances during peak times and save on resources during idle periods. * ordered Start (or stop) each clone only after the operation on the previous clone completed. * interleaved If a colocation constraint is created between two clone resources and interleaved is true, then clone N from one resource will be assigned the same location as clone N from the other resource. If the number of runnable clones differs, then the leftovers can be located anywhere. Using a cloned group is a much better way of achieving the same result. * notify If true, inform peers before and after any clone is stopped or started. If an action failed, you will (currently) not recieve a post-notification. Instead you can next expect to see a pre-notification for a stop. If a stop fails, and you have fencing you will get a post-notification for the stop after the fencing operation has completed. In order to use the notification service ALL decendants of the clone MUST support the notify action. Currently this action is not permitted to fail, though depending on your configuration, can block almost indefinitly. Behaviour in response to a failed action or notificaiton is likely to be improved in future releases. See http://linux-ha.org/v2/Concepts/Clones for more information on notify actions NOTE: Clones must contain exactly one primitive or one group resource. The CRM will complain about your configuration if this criteria is not met. Please use crm_verify to ensure your configuration is valid. The DTD is written this way to be order in-sensitive. --> <!ELEMENT clone (meta_attributes|instance_attributes|primitive|group)*> <!ATTLIST clone id CDATA #REQUIRED description CDATA #IMPLIED is_managed CDATA #IMPLIED restart_type (ignore|restart) 'ignore' multiple_active (stop_start|stop_only|block) 'stop_start' resource_stickiness CDATA #IMPLIED notify (true|1|false|0) 'false' globally_unique (true|1|false|0) 'true' ordered (true|1|false|0) 'false' interleave (true|1|false|0) 'false'> <!-- Master/Slave resources are a superset of Clones in that instances can also be in one of two states. The meaning of the states is specific to the resource. NOTE: master_slave must contain exactly one primitive resource OR one group resource. It may not contain both, nor may it contain neither. The CRM will complain about your configuration if this criteria is not met. Please use crm_verify to ensure your configuration is valid. The DTD is written this way to be order in-sensitive. --> <!ELEMENT master_slave (meta_attributes|instance_attributes|primitive|group)*> <!ATTLIST master_slave id CDATA #REQUIRED description CDATA #IMPLIED is_managed CDATA #IMPLIED restart_type (ignore|restart) 'ignore' multiple_active (stop_start|stop_only|block) 'stop_start' resource_stickiness CDATA #IMPLIED notify (true|1|false|0) 'false' globally_unique (true|1|false|0) 'true' ordered (true|1|false|0) 'false' interleave (true|1|false|0) 'false'> <!-- Most resource options are configured as instance attributes. Some of the built-in options can be configured directly on the resource or as an instance attribute. The advantage of using instance attributes is the added flexibility that can be achieved through conditional ?<rule/>s (see below). You can have multiple sets of 'instance attributes', they are first sorted by score and then processed. The first to have its ?<rule/> satisfied and define an attribute wins. Subsequent values for the attribute will be ignored. Note that: * instance_attributes sets with id equal to cib-bootstrap-options are treated as if they have a score of INFINITY. * instance_attributes sets with no score implicitly have a score of zero. * instance_attributes sets with no rule implicitly have a rule that evaluates to true. The addition of conditional <rule/>s to the instance_attributes object allows for an infinite variety of configurations. Just some of the possibilities are: * Specify different resource parameters * depending on the node it is allocated to (a resource may need to use eth1 on host1 but eth0 on host2) * depending on the time of day (run 10 web-servers at night an 100 during the day) * Allow nodes to have different attributes depending on the time-of-day * Set resource_stickiness to avoid failback during business hours but allow resources to be moved to a more preferred node on the weekend * Switch a node between a "front-end" processing group during the day to a "back-end" group at night. Common instance attributes for all resource types: * priority (integer, default=0): dictates the order in which resources will be processed. If there is an insufficient number of nodes to run all resources, the lower priority resources will be stopped to make sure the higher priority resources remain active. * is_managed: See previous description. * resource_stickiness: See previous description. * target_role: (Started|Stopped|Master|Slave|default, default=#default) * #default : Let the cluster decide what to do with the resource * Started : Ignore any specified value of is_managed or is_managed_default and attempt to start the resource * Stopped : Ignore any specified value of is_managed or is_managed_default and attempt to stop the resource * Master : Ignore any specified value of is_managed, is_managed_default or promotion preferences and attempt to put all instances of a cloned resource into Master mode. * Slave : Ignore any specified value of is_managed, is_managed_default or promotion preferences and attempt to put all instances of a cloned resource into Slave mode. Common instance attributes for clones: * clone_max (integer, default=1): the number of clones to be run * clone_node_max (integer, default=1): the maximum number of clones to be run on a single node Common instance attributes for nodes: * standby (boolean, default=FALSE) if TRUE, indicates that resources can not be run on the node --> <!ELEMENT instance_attributes (rule*, attributes)> <!ATTLIST instance_attributes id CDATA #REQUIRED score CDATA #IMPLIED> <!ELEMENT meta_attributes (rule*, attributes)> <!ATTLIST meta_attributes id CDATA #REQUIRED score CDATA #IMPLIED> <!-- Every constraint entry also has a 'lifetime' attribute, which expresses when this constraint is applicable. For example, a constraint may only be valid during certain times of the day, or days of the week. Eventually, we would like to be able to support constraints that only last until events such as the next reboot or the next transition. --> <!ELEMENT constraints (rsc_order|rsc_colocation|rsc_location)*> <!-- rsc_ordering constraints express dependencies between the actions on two resources. * from : A resource id * action : What action does this constraint apply to. * type : Should the action on from occur before or after action on to * to : A resource id * symmetrical : If TRUE, create the reverse constraint for the other action also. --> <!ELEMENT rsc_order (lifetime?)> <!ATTLIST rsc_order id CDATA #REQUIRED from CDATA #REQUIRED to CDATA #REQUIRED - action (start|stop) 'start' + action CDATA #IMPLIED 'start' + to_action CDATA #IMPLIED 'start' type (before|after) 'after' score CDATA '0' symmetrical (true|1|false|0) 'true'> <!-- Specify where a resource should run relative to another resource NOTE: Currently, only values of + and - INFINITY are permitted for the score. This may change in the future. --> <!ELEMENT rsc_colocation (lifetime?)> <!ATTLIST rsc_colocation id CDATA #REQUIRED from CDATA #REQUIRED from_role CDATA #IMPLIED to CDATA #REQUIRED to_role CDATA #IMPLIED node_attribute CDATA #IMPLIED score CDATA #REQUIRED> <!-- Specify which nodes are eligible for running a given resource. During processing, all rsc_location for a given rsc are evaluated. All nodes start out with their base weight (which defaults to zero). This can then be modified (up or down) using any number of rsc_location constraints. Then the highest non-zero available node is determined to place the resource. If multiple nodes have the same weighting, the node with the fewest running resources is chosen. The rsc field is, surprisingly, a resource id. --> <!ELEMENT rsc_location (lifetime?,rule*)> <!ATTLIST rsc_location id CDATA #REQUIRED description CDATA #IMPLIED rsc CDATA #REQUIRED> <!ELEMENT lifetime (rule+)> <!ATTLIST lifetime id CDATA #REQUIRED> <!-- * boolean_op determines how the results of multiple expressions are combined. * role limits this rule to applying to Multi State resources with the named role. Roles include Started, Stopped, Slave, Master though only the last two are considered useful. NOTE: A rule with role="Master" can not determin the initial location of a clone instance. It will only affect which of the active instances will be promoted. * score adjusts the preference for running on the matched nodes. NOTE: Nodes that end up with a negative score will never run the resource. Two special values of "score" exist: INFINITY and -INFINITY. Processing of these special values is as follows: INFINITY +/- -INFINITY : -INFINITY INFINITY +/- int : INFINITY -INFINITY +/- int : -INFINITY * score_attribute an alternative to the score attribute that provides extra flexibility. Each node matched by the rule has its score adjusted differently, according to its value for the named node attribute. Thus in the example below, if score_attribute="installed_ram" and nodeA would have its preference to run "the resource" increased by 1024 whereas nodeB would have its preference increased only by half as much. <nodes> <node id="uuid1" uname="nodeA" type="normal"> <instance_attributes id="uuid1:custom_attrs"> <attributes> <nvpair id="uuid1:installed_ram" name="installed_ram" value="1024"/> <nvpair id="uuid1:my_other_attr" name="my_other_attr" value="bob"/> </attributes> </instance_attributes> </node> <node id="uuid2" uname="nodeB" type="normal"> <instance_attributes id="uuid2:custom_attrs"> <attributes> <nvpair id="uuid2:installed_ram" name="installed_ram" value="512"/> </attributes> </instance_attributes> </node> </nodes> --> <!ELEMENT rule (expression|date_expression|rule)*> <!ATTLIST rule id CDATA #REQUIRED role CDATA #IMPLIED score CDATA #IMPLIED score_attribute CDATA #IMPLIED boolean_op (or|and) 'and'> <!-- Returns TRUE or FALSE depending on the properties of the object being tested. * type determines how the values being tested. * integer Values are converted to floats before being compared. * version The "version" type is intended to solve the problem of comparing 1.2 and 1.10 * string Uses strcmp Two built-in attributes are node id #id and node uname #uname so that: attribute=#id value=8C05CA5C-C9E3-11D8-BEE6-000A95B71D78 operation=eq, and attribute=#uname value=test1 operation=eq would both be valid tests. An extra built-in attribute called #is_dc will be set to true or false depending on whether the node is operating as the DC for the cluster. Valid tests using this test would be of the form: attribute=#is_dc operation=eq value=true, and attribute=#is_dc operation=eq value=false, and attribute=#is_dc operation=ne value=false (for those liking double negatives :)) --> <!ELEMENT expression EMPTY> <!ATTLIST expression id CDATA #REQUIRED attribute CDATA #REQUIRED operation (lt|gt|lte|gte|eq|ne|defined|not_defined) #REQUIRED value CDATA #IMPLIED type (integer|string|version) 'string'> <!-- * start : A date-time conforming to the ISO8601 specification. * end : A date-time conforming to the ISO8601 specification. A value for end may, for any usage, be omitted and instead inferred using start and duration. * operation * gt : Compares the current date-time with start date. Checks now > start. * lt : Compares the current date-time with end date. Checks end > now * in_range : Compares the current date-time with start and end. Checks now > start and end > now. If either start or end is omitted, then that part of the comparision is not performed. * date_spec : Performs a cron-like comparision between the contents of date_spec and now. If values for start and/or end are included, now must also be within that range. Or in other words, the date_spec operation can also be made to perform an extra in_range check. NOTE: Because the comparisions (except for date_spec) include the time, the eq, neq, gte and lte operators have not been implemented. --> <!ELEMENT date_expression (date_spec?,duration?)> <!ATTLIST date_expression id CDATA #REQUIRED operation (in_range|date_spec|gt|lt) 'in_range' start CDATA #IMPLIED end CDATA #IMPLIED> <!-- date_spec is used for (surprisingly ) date_spec operations. Fields that are not supplied are ignored. Fields can contain a single number or a single range. Eg. monthdays="1" (Matches the first day of every month) and hours="09-17" (Matches hours between 9am and 5pm inclusive) are both valid values. weekdays="1,2" and weekdays="1-2,5-6" are NOT valid ranges. This may change in a future release. * seconds : Value range 0-59 * minutes : Value range 0-59 * hours : Value range 0-23 * monthdays : Value range 0-31 (depending on current month and year) * weekdays : Value range 1-7 (1=Monday, 7=Sunday) * yeardays : Value range 1-366 (depending on current year) * months : Value range 1-12 * weeks : Value range 1-53 (depending on weekyear) * weekyears : Value range 0... (NOTE: weekyears may differ from Gregorian years. Eg. 2005-001 Ordinal == 2005-01-01 Gregorian == 2004-W53-6 Weekly ) * years : Value range 0... * moon : Value range 0..7 - 0 is new, 4 is full moon. Because we can(tm) --> <!ELEMENT date_spec EMPTY> <!ATTLIST date_spec id CDATA #REQUIRED hours CDATA #IMPLIED monthdays CDATA #IMPLIED weekdays CDATA #IMPLIED yeardays CDATA #IMPLIED months CDATA #IMPLIED weeks CDATA #IMPLIED weekyears CDATA #IMPLIED years CDATA #IMPLIED moon CDATA #IMPLIED> <!-- duration is optionally used for calculating a value for end. Any field not supplied is assumed to be zero and ignored. Negative values might work. Eg. months=11 should be equivalent to writing years=1, months=-1 but is not encouraged. --> <!ELEMENT duration EMPTY> <!ATTLIST duration id CDATA #REQUIRED hours CDATA #IMPLIED monthdays CDATA #IMPLIED weekdays CDATA #IMPLIED yeardays CDATA #IMPLIED months CDATA #IMPLIED weeks CDATA #IMPLIED years CDATA #IMPLIED> <!-- Example 1: True if now is any time in the year 2005. <rule id="rule1"> <date_expression id="date_expr1" start="2005-001" operation="in_range"> <duration years="1"/> </date_expression> </rule> Example 2: Equivalent expression. <rule id="rule2"> <date_expression id="date_expr2" operation="date_spec"> <date_spec years="2005"/> </date_expression> </rule> Example 3: 9am-5pm, Mon-Friday <rule id="rule3"> <date_expression id="date_expr3" operation="date_spec"> <date_spec hours="9-16" days="1-5"/> </date_expression> </rule> Example 4: 9am-5pm, Mon-Friday, or all day saturday <rule id="rule4" boolean_op="or"> <date_expression id="date_expr4-1" operation="date_spec"> <date_spec hours="9-16" days="1-5"/> </date_expression> <date_expression id="date_expr4-2" operation="date_spec"> <date_spec days="6"/> </date_expression> </rule> Example 5: 9am-5pm or 9pm-12pm, Mon-Friday <rule id="rule5" boolean_op="and"> <rule id="rule5-nested1" boolean_op="or"> <date_expression id="date_expr5-1" operation="date_spec"> <date_spec hours="9-16"/> </date_expression> <date_expression id="date_expr5-2" operation="date_spec"> <date_spec hours="21-23"/> </date_expression> </rule> <date_expression id="date_expr5-3" operation="date_spec"> <date_spec days="1-5"/> </date_expression> </rule> Example 6: Mondays in March 2005 <rule id="rule6" boolean_op="and"> <date_expression id="date_expr6" operation="date_spec" start="2005-03-01" end="2005-04-01"> <date_spec weekdays="1"/> </date_expression> </rule> NOTE: Because no time is specified, 00:00:00 is implied. This means that the range includes all of 2005-03-01 but none of 2005-04-01. You may wish to write end="2005-03-31T23:59:59" to avoid confusion. Example 7: Friday the 13th if it is a full moon <rule id="rule7" boolean_op="and"> <date_expression id="date_expr7" operation="date_spec"> <date_spec weekdays="5" monthdays="13" moon="4"/> </date_expression> </rule> --> <!-- You don't have to give a value. There's a difference between a key not being present and a key not having a value. --> <!ELEMENT nvpair EMPTY> <!ATTLIST nvpair id CDATA #REQUIRED name CDATA #REQUIRED value CDATA #IMPLIED> <!ELEMENT attributes (nvpair*)> <!-- These attributes take effect only if no value has previously been applied as part of the node's definition. Additionally, when the node reboots all settings made here are erased. id must be the UUID of the node. --> <!ELEMENT transient_attributes (instance_attributes*)> <!ATTLIST transient_attributes id CDATA #IMPLIED> <!--=========== Status - Advanced Use Only ===========--> <!-- Details about the status of each node configured. HERE BE DRAGONS Never, ever edit this section directly or using cibadmin. The consequences of doing so are many and varied but rarely ever good or what you anticipated. To discourage this, the status section is no longer even written to disk, and is always discarded at startup. To avoid duplication of data, state entries only carry references to nodes and resources. --> <!ELEMENT status (node_state*)> <!-- The state of a given node. This information is updated by the DC based on inputs from sources such as the CCM, status messages from remote LRMs and requests from other nodes. * id - is the node's UUID. * uname - is the result of uname -n for the node. * crmd - records whether the crmd process is running on the node * in_ccm - records whether the node is part of our membership partition * join - is the node's membership status with the current DC. * expected - is the DC's expectation of whether the node is up or not. * shutdown - is set to the time at which the node last asked to be shut down Ideally, there should be a node_state entry for every entry in the <nodes> list. --> <!ELEMENT node_state (transient_attributes|lrm)*> <!ATTLIST node_state id CDATA #REQUIRED uname CDATA #REQUIRED ha (active|dead) #IMPLIED crmd (online|offline) 'offline' join (pending|member|down) 'down' expected (pending|member|down) 'down' in_ccm (true|1|false|0) 'false' crm-debug-origin CDATA #IMPLIED shutdown CDATA #IMPLIED clear_shutdown CDATA #IMPLIED> <!-- Information from the Local Resource Manager of the node. It contains a list of all resource's added (but not necessarily still active) on the node. --> <!ELEMENT lrm (lrm_resources)> <!ATTLIST lrm id CDATA #REQUIRED> <!ELEMENT lrm_resources (lrm_resource*)> <!ELEMENT lrm_resource (lrm_rsc_op*)> <!ATTLIST lrm_resource id CDATA #REQUIRED class (lsb|ocf|heartbeat|stonith) #REQUIRED type CDATA #REQUIRED provider CDATA #IMPLIED> <!-- lrm_rsc_op (Resource Status) id: Set to [operation] +"_"+ [operation] +"_"+ [an_interval_in_milliseconds] operation typically start, stop, or monitor call_id: Supplied by the LRM, determins the order of in which lrm_rsc_op objects should be processed in order to determin the resource's true state rc_code is the last return code from the resource rsc_state is the state of the resource after the action completed and should be used as a guide only. transition_key contains an identifier and seqence number for the transition. At startup, the TEngine registers the identifier and starts the sequence at zero. It is used to identify the source of resource actions. transition_magic contains an identifier containing call_id, rc_code, and {{transition_key}}}. As the name suggests, it is a piece of magic that allows the TE to always identify the action from the stream of xml-diffs it subscribes to from the CIB. op_status is supplied by the LRM and conforms to this enum: typedef enum { LRM_OP_PENDING = -1, LRM_OP_DONE, LRM_OP_CANCELLED, LRM_OP_TIMEOUT, LRM_OP_NOTSUPPORTED, LRM_OP_ERROR, } op_status_t; The parameters section allows us to detect when a resource's definition has changed and the needs to be restarted (so the changes take effect). --> <!ELEMENT lrm_rsc_op EMPTY> <!ATTLIST lrm_rsc_op id CDATA #REQUIRED operation CDATA #REQUIRED op_status CDATA #REQUIRED rc_code CDATA #REQUIRED call_id CDATA #REQUIRED crm_feature_set CDATA #REQUIRED crm-debug-origin CDATA #IMPLIED transition_key CDATA #IMPLIED op_digest CDATA #IMPLIED interval CDATA #REQUIRED transition_magic CDATA #REQUIRED> diff --git a/crm/pengine/allocate.c b/crm/pengine/allocate.c index 1b7c969f46..2a32d656b5 100644 --- a/crm/pengine/allocate.c +++ b/crm/pengine/allocate.c @@ -1,1325 +1,1347 @@ /* $Id: allocate.c,v 1.12 2006/08/14 09:06:31 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net> * * 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 <portability.h> #include <sys/param.h> #include <crm/crm.h> #include <crm/cib.h> #include <crm/msg_xml.h> #include <crm/common/xml.h> #include <crm/common/msg.h> #include <clplumbing/cl_misc.h> #include <glib.h> #include <crm/pengine/status.h> #include <pengine.h> #include <allocate.h> #include <utils.h> #include <lib/crm/pengine/utils.h> 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, master_color, master_create_actions, clone_create_probe, master_internal_constraints, clone_agent_constraints, clone_rsc_colocation_lh, master_rsc_colocation_rh, clone_rsc_order_lh, clone_rsc_order_rh, clone_rsc_location, clone_expand, clone_stonith_ordering, clone_create_notify_element, } }; 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 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; char *cancel_key = NULL; crm_info("Orphan action will be stopped: %s on %s", key, active_node->details->uname); cancel_key = generate_op_key(rsc->id, CRMD_ACTION_CANCEL, interval); cancel = custom_action( rsc, cancel_key, CRMD_ACTION_CANCEL, active_node, FALSE, TRUE, data_set); add_hash_param(cancel->meta, XML_LRM_ATTR_TASK, task); add_hash_param(cancel->meta, XML_LRM_ATTR_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); crm_free(key); key = NULL; return TRUE; } } action = custom_action(rsc, key, task, active_node, TRUE, FALSE, data_set); local_rsc_params = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); unpack_instance_attributes( rsc->xml, XML_TAG_ATTR_SETS, active_node->details->attrs, local_rsc_params, NULL, data_set->now); 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)) { 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; } extern gboolean DeleteRsc(resource_t *rsc, node_t *node, pe_working_set_t *data_set); static void check_actions_for(crm_data_t *rsc_entry, node_t *node, pe_working_set_t *data_set) { const char *id = NULL; const char *task = NULL; int interval = 0; const char *interval_s = NULL; GListPtr op_list = NULL; GListPtr sorted_op_list = NULL; const char *rsc_id = ID(rsc_entry); gboolean is_probe = FALSE; resource_t *rsc = pe_find_resource(data_set->resources, rsc_id); CRM_CHECK(rsc_id != NULL, return); if(rsc == NULL) { crm_warn("Skipping param check for resource with no actions"); return; } else if(rsc->orphan) { crm_debug_2("Skipping param check for orphan: %s %s", rsc->id, task); return; } crm_debug_2("Processing %s on %s", rsc->id, node->details->uname); if(check_rsc_parameters(rsc, node, rsc_entry, data_set)) { DeleteRsc(rsc, node, data_set); } xml_child_iter_filter( rsc_entry, rsc_op, XML_LRM_TAG_RSC_OP, op_list = g_list_append(op_list, rsc_op); ); sorted_op_list = g_list_sort(op_list, sort_op_by_callid); slist_iter( rsc_op, crm_data_t, sorted_op_list, lpc, id = ID(rsc_op); is_probe = FALSE; task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); interval_s = get_interval(rsc_op); interval = crm_parse_int(interval_s, "0"); if(interval == 0 && safe_str_eq(task, CRMD_ACTION_STATUS)) { is_probe = TRUE; } if(is_probe || safe_str_eq(task, CRMD_ACTION_START) || interval > 0) { crm_debug_2("Checking resource definition: %s", rsc->id); check_action_definition(rsc, node, rsc_op, data_set); } crm_debug_3("Ignoring %s params: %s", task, id); ); g_list_free(sorted_op_list); } static void check_actions(pe_working_set_t *data_set) { const char *id = NULL; node_t *node = NULL; crm_data_t *lrm_rscs = NULL; crm_data_t *status = get_object_root(XML_CIB_TAG_STATUS, data_set->input); xml_child_iter_filter( status, node_state, XML_CIB_TAG_STATE, id = crm_element_value(node_state, XML_ATTR_ID); lrm_rscs = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE); lrm_rscs = find_xml_node(lrm_rscs, XML_LRM_TAG_RESOURCES, FALSE); node = pe_find_node_id(data_set->nodes, id); if(node == NULL) { continue; } crm_debug("Processing node %s", node->details->uname); if(node->details->online || data_set->stonith_enabled) { xml_child_iter_filter( lrm_rscs, rsc_entry, XML_LRM_TAG_RESOURCE, check_actions_for(rsc_entry, node, data_set); ); } ); } static gboolean apply_placement_constraints(pe_working_set_t *data_set) { crm_debug_3("Applying constraints..."); slist_iter( cons, rsc_to_node_t, data_set->placement_constraints, lpc, cons->rsc_lh->cmds->rsc_location(cons->rsc_lh, cons); ); return TRUE; } 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); set_alloc_actions(data_set); unpack_constraints(cib_constraints, data_set); return TRUE; } /* * Check nodes for resources started outside of the LRM */ gboolean stage1(pe_working_set_t *data_set) { action_t *probe_complete = NULL; action_t *probe_node_complete = NULL; slist_iter( node, node_t, data_set->nodes, lpc, gboolean force_probe = FALSE; const char *probed = g_hash_table_lookup( node->details->attrs, CRM_OP_PROBED); crm_debug_2("%s probed: %s", node->details->uname, probed); if(node->details->online == FALSE) { continue; } else if(node->details->unclean) { continue; } else if(probe_complete == NULL) { probe_complete = custom_action( NULL, crm_strdup(CRM_OP_PROBED), CRM_OP_PROBED, NULL, FALSE, TRUE, data_set); probe_complete->pseudo = TRUE; probe_complete->optional = TRUE; } if(probed != NULL && crm_is_true(probed) == FALSE) { force_probe = TRUE; } probe_node_complete = custom_action( NULL, crm_strdup(CRM_OP_PROBED), CRM_OP_PROBED, node, FALSE, TRUE, data_set); probe_node_complete->optional = crm_is_true(probed); probe_node_complete->priority = INFINITY; add_hash_param(probe_node_complete->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); custom_action_order(NULL, NULL, probe_node_complete, NULL, NULL, probe_complete, pe_ordering_optional, data_set); slist_iter( rsc, resource_t, data_set->resources, lpc2, if(rsc->cmds->create_probe( rsc, node, probe_node_complete, force_probe, data_set)) { probe_complete->optional = FALSE; probe_node_complete->optional = FALSE; custom_action_order( NULL, NULL, probe_complete, rsc, start_key(rsc), NULL, pe_ordering_manditory, data_set); } ); ); return TRUE; } /* * Count how many valid nodes we have (so we know the maximum number of * colors we can resolve). * * Apply node constraints (ie. filter the "allowed_nodes" part of resources */ gboolean stage2(pe_working_set_t *data_set) { crm_debug_3("Applying placement constraints"); slist_iter( node, node_t, data_set->nodes, lpc, if(node == NULL) { /* error */ } else if(node->weight >= 0.0 /* global weight */ && node->details->online && node->details->type == node_member) { data_set->max_valid_nodes++; } ); apply_placement_constraints(data_set); return TRUE; } /* * Create internal resource constraints before allocation */ gboolean stage3(pe_working_set_t *data_set) { slist_iter( rsc, resource_t, data_set->resources, lpc, rsc->cmds->internal_constraints(rsc, data_set); ); return TRUE; } /* * Check for orphaned or redefined actions */ gboolean stage4(pe_working_set_t *data_set) { check_actions(data_set); return TRUE; } gboolean stage5(pe_working_set_t *data_set) { /* Take (next) highest resource, assign it and create its actions */ slist_iter( rsc, resource_t, data_set->resources, lpc, rsc->cmds->color(rsc, data_set); rsc->cmds->create_actions(rsc, data_set); ); return TRUE; } /* * Create dependacies for stonith and shutdown operations */ gboolean stage6(pe_working_set_t *data_set) { action_t *dc_down = NULL; action_t *stonith_op = NULL; action_t *last_stonith = NULL; gboolean integrity_lost = FALSE; 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(last_stonith) { order_actions(last_stonith, stonith_op, pe_ordering_manditory); } last_stonith = stonith_op; } } else if(node->details->online && node->details->shutdown) { action_t *down_op = NULL; crm_info("Scheduling Node %s for shutdown", node->details->uname); down_op = custom_action( NULL, crm_strdup(CRM_OP_SHUTDOWN), CRM_OP_SHUTDOWN, node, FALSE, TRUE, data_set); shutdown_constraints(node, down_op, data_set); if(node->details->is_dc) { dc_down = down_op; } } if(node->details->unclean && stonith_op == NULL) { integrity_lost = TRUE; pe_warn("Node %s is unclean!", node->details->uname); } ); if(integrity_lost) { if(data_set->have_quorum == FALSE) { crm_notice("Cannot fence unclean nodes until quorum is" " attained (or no_quorum_policy is set to ignore)"); } else if(data_set->stonith_enabled == FALSE) { pe_warn("YOUR RESOURCES ARE NOW LIKELY COMPROMISED"); pe_err("ENABLE STONITH TO KEEP YOUR RESOURCES SAFE"); } } if(dc_down != NULL) { GListPtr shutdown_matches = find_actions( data_set->actions, CRM_OP_SHUTDOWN, NULL); crm_debug_2("Ordering shutdowns before %s on %s (DC)", dc_down->task, dc_down->node->details->uname); add_hash_param(dc_down->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); slist_iter( node_stop, action_t, shutdown_matches, lpc, if(node_stop->node->details->is_dc) { continue; } crm_debug("Ordering shutdown on %s before %s on %s", node_stop->node->details->uname, dc_down->task, dc_down->node->details->uname); order_actions(node_stop, dc_down, pe_ordering_manditory); ); if(last_stonith && dc_down != last_stonith) { order_actions(last_stonith, 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->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->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) { const char *value = NULL; char *transition_id_s = NULL; transition_id++; transition_id_s = crm_itoa(transition_id); value = pe_pref(data_set->config_hash, "network-delay"); crm_debug("Creating transition graph %d.", transition_id); data_set->graph = create_xml_node(NULL, XML_TAG_GRAPH); crm_xml_add(data_set->graph, "network-delay", value); crm_xml_add(data_set->graph, "transition_id", transition_id_s); crm_free(transition_id_s); /* errors... slist_iter(action, action_t, action_list, lpc, if(action->optional == FALSE && action->runnable == FALSE) { print_action("Ignoring", action, TRUE); } ); */ slist_iter( rsc, resource_t, data_set->resources, lpc, crm_debug_4("processing actions for rsc=%s", rsc->id); rsc->cmds->expand(rsc, data_set); ); crm_log_xml_debug_3( data_set->graph, "created resource-driven action list"); /* catch any non-resource specific actions */ crm_debug_4("processing non-resource actions"); slist_iter( action, action_t, data_set->actions, lpc, graph_element_from_action(action, data_set); ); crm_log_xml_debug_3(data_set->graph, "created generic action list"); crm_notice("Created transition graph %d.", transition_id); return TRUE; } void cleanup_alloc_calculations(pe_working_set_t *data_set) { if(data_set == NULL) { return; } crm_debug_3("deleting order cons: %p", data_set->ordering_constraints); pe_free_ordering(data_set->ordering_constraints); data_set->ordering_constraints = NULL; crm_debug_3("deleting node cons: %p", data_set->placement_constraints); pe_free_rsc_to_node(data_set->placement_constraints); data_set->placement_constraints = NULL; cleanup_calculations(data_set); } 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):"<none>"); xml_child_iter( xml_constraints, xml_obj, const char *id = crm_element_value(xml_obj, XML_ATTR_ID); if(id == NULL) { crm_config_err("Constraint <%s...> must have an id", crm_element_name(xml_obj)); continue; } crm_debug_3("Processing constraint %s %s", crm_element_name(xml_obj),id); lifetime = cl_get_struct(xml_obj, "lifetime"); if(test_ruleset(lifetime, NULL, data_set->now) == FALSE) { crm_info("Constraint %s %s is not active", crm_element_name(xml_obj), id); } else if(safe_str_eq(XML_CONS_TAG_RSC_ORDER, crm_element_name(xml_obj))) { unpack_rsc_order(xml_obj, data_set); } else if(safe_str_eq(XML_CONS_TAG_RSC_DEPEND, crm_element_name(xml_obj))) { unpack_rsc_colocation(xml_obj, data_set); } else if(safe_str_eq(XML_CONS_TAG_RSC_LOCATION, crm_element_name(xml_obj))) { unpack_rsc_location(xml_obj, data_set); } else { pe_err("Unsupported constraint type: %s", crm_element_name(xml_obj)); } ); return TRUE; } static const char * invert_action(const char *action) { if(safe_str_eq(action, CRMD_ACTION_START)) { return CRMD_ACTION_STOP; } else if(safe_str_eq(action, CRMD_ACTION_STOP)) { return CRMD_ACTION_START; } else if(safe_str_eq(action, CRMD_ACTION_PROMOTE)) { return CRMD_ACTION_DEMOTE; } else if(safe_str_eq(action, CRMD_ACTION_DEMOTE)) { return CRMD_ACTION_PROMOTE; } else if(safe_str_eq(action, CRMD_ACTION_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; enum pe_ordering cons_weight = pe_ordering_optional; 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 *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE); 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) { crm_config_err("No constraint object to process."); return FALSE; } else if(id == NULL) { crm_config_err("%s constraint must have an id", crm_element_name(xml_obj)); return FALSE; } else if(id_lh == NULL || id_rh == NULL) { crm_config_err("Constraint %s needs two sides lh: %s rh: %s", id, crm_str(id_lh), crm_str(id_rh)); return FALSE; } 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) { crm_config_err("Constraint %s: no resource found for LHS of %s", id, id_lh); return FALSE; } else if(rsc_rh == NULL) { crm_config_err("Constraint %s: no resource found for RHS of %s", id, id_rh); return FALSE; } if(crm_atoi(score, "0") > 0) { /* the name seems weird but the effect is correct */ cons_weight = pe_ordering_restart; } custom_action_order( rsc_lh, generate_op_key(rsc_lh->id, action, 0), NULL, rsc_rh, generate_op_key(rsc_rh->id, action_rh, 0), NULL, cons_weight, data_set); 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); + crm_debug_2("Recover %s.%s-%s.%s", + rsc_lh->id, action, rsc_rh->id, action_rh); +/* order_start_start(rsc_lh, rsc_rh, pe_ordering_recover); */ + 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_recover, data_set); } 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); + crm_debug_2("Recover %s.%s-%s.%s", + rsc_rh->id, action_rh, rsc_lh->id, action); +/* order_stop_stop(rsc_rh, rsc_lh, pe_ordering_recover); */ + 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_recover, data_set); } } cl_str_to_boolean(symmetrical, &symmetrical_bool); if(symmetrical_bool == FALSE) { return TRUE; } action = invert_action(action); action_rh = invert_action(action_rh); + + if(action == NULL || action_rh == NULL) { + crm_config_err("Cannot invert rsc_order constraint %s." + " Please specify the inverse manually.", id); + return TRUE; + } custom_action_order( rsc_rh, generate_op_key(rsc_rh->id, action_rh, 0), NULL, rsc_lh, generate_op_key(rsc_lh->id, action, 0), NULL, cons_weight, data_set); 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); +/* order_start_start(rsc_lh, rsc_rh, pe_ordering_recover); */ + 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_recover, data_set); } 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); +/* order_stop_stop(rsc_rh, rsc_lh, pe_ordering_recover); */ + 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_recover, data_set); } } return TRUE; } gboolean unpack_rsc_location(crm_data_t * xml_obj, pe_working_set_t *data_set) { gboolean empty = TRUE; const char *id_lh = crm_element_value(xml_obj, "rsc"); const char *id = crm_element_value(xml_obj, XML_ATTR_ID); resource_t *rsc_lh = pe_find_resource(data_set->resources, id_lh); if(rsc_lh == NULL) { /* only a warn as BSC adds the constraint then the resource */ crm_config_warn("No resource (con=%s, rsc=%s)", id, id_lh); return FALSE; } else if(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, empty = FALSE; crm_debug_2("Unpacking %s/%s", id, ID(rule_xml)); generate_location_rule(rsc_lh, rule_xml, data_set); ); if(empty) { crm_config_err("Invalid location constraint %s:" " rsc_location must contain at least one rule", ID(xml_obj)); } return TRUE; } static int get_node_score(const char *rule, const char *score, gboolean raw, node_t *node) { int score_f = 0; if(score == NULL) { pe_err("Rule %s: no score specified. Assuming 0.", rule); } else if(raw) { score_f = char2score(score); } else { const char *attr_score = g_hash_table_lookup( node->details->attrs, score); if(attr_score == NULL) { crm_debug("Rule %s: node %s did not have a value for %s", rule, node->details->uname, score); score_f = -INFINITY; } else { crm_debug("Rule %s: node %s had value %s for %s", rule, node->details->uname, attr_score, score); score_f = char2score(attr_score); } } return score_f; } rsc_to_node_t * generate_location_rule( resource_t *rsc, crm_data_t *rule_xml, pe_working_set_t *data_set) { const char *rule_id = NULL; const char *score = NULL; const char *boolean = NULL; const char *role = NULL; GListPtr match_L = NULL; int score_f = 0; gboolean do_and = TRUE; gboolean accept = TRUE; gboolean raw_score = TRUE; rsc_to_node_t *location_rule = NULL; rule_id = crm_element_value(rule_xml, XML_ATTR_ID); boolean = crm_element_value(rule_xml, XML_RULE_ATTR_BOOLEAN_OP); role = crm_element_value(rule_xml, XML_RULE_ATTR_ROLE); crm_debug_2("Processing rule: %s", rule_id); if(role != NULL && text2role(role) == RSC_ROLE_UNKNOWN) { pe_err("Bad role specified for %s: %s", rule_id, role); return NULL; } score = crm_element_value(rule_xml, XML_RULE_ATTR_SCORE); if(score != NULL) { score_f = char2score(score); } else { score = crm_element_value( rule_xml, XML_RULE_ATTR_SCORE_ATTRIBUTE); if(score == NULL) { score = crm_element_value( rule_xml, XML_RULE_ATTR_SCORE_MANGLED); } if(score != NULL) { raw_score = FALSE; } } if(safe_str_eq(boolean, "or")) { do_and = FALSE; } location_rule = rsc2node_new(rule_id, rsc, 0, NULL, data_set); if(location_rule == NULL) { return NULL; } if(role != NULL) { crm_debug_2("Setting role filter: %s", role); location_rule->role_filter = text2role(role); } if(do_and) { match_L = node_list_dup(data_set->nodes, TRUE, FALSE); slist_iter( node, node_t, match_L, lpc, node->weight = get_node_score(rule_id, score, raw_score, node); ); } xml_child_iter( rule_xml, expr, enum expression_type type = find_expression_type(expr); crm_debug_2("Processing expression: %s", ID(expr)); if(type == not_expr) { pe_err("Expression <%s id=%s...> is not valid", crm_element_name(expr), crm_str(ID(expr))); continue; } slist_iter( node, node_t, data_set->nodes, lpc, if(type == nested_rule) { accept = test_rule( expr, node->details->attrs, RSC_ROLE_UNKNOWN, data_set->now); } else { accept = test_expression( expr, node->details->attrs, RSC_ROLE_UNKNOWN, data_set->now); } score_f = get_node_score(rule_id, score, raw_score, node); /* if(accept && score_f == -INFINITY) { */ /* accept = FALSE; */ /* } */ if(accept) { node_t *local = pe_find_node_id( match_L, node->details->id); if(local == NULL && do_and) { continue; } else if(local == NULL) { local = node_copy(node); match_L = g_list_append(match_L, local); } if(do_and == FALSE) { local->weight = merge_weights( local->weight, score_f); } crm_debug_2("node %s now has weight %d", node->details->uname, local->weight); } else if(do_and && !accept) { /* remove it */ node_t *delete = pe_find_node_id( match_L, node->details->id); if(delete != NULL) { match_L = g_list_remove(match_L,delete); crm_debug_5("node %s did not match", node->details->uname); } crm_free(delete); } ); ); location_rule->node_list_rh = match_L; if(location_rule->node_list_rh == NULL) { crm_debug_2("No matching nodes for rule %s", rule_id); return NULL; } crm_debug_3("%s: %d nodes matched", rule_id, g_list_length(location_rule->node_list_rh)); return location_rule; } gboolean rsc_colocation_new(const char *id, const char *node_attr, int score, resource_t *rsc_lh, resource_t *rsc_rh, const char *state_lh, const char *state_rh) { rsc_colocation_t *new_con = NULL; if(rsc_lh == NULL){ crm_config_err("No resource found for LHS %s", id); return FALSE; } else if(rsc_rh == NULL){ crm_config_err("No resource found for RHS of %s", id); return FALSE; } crm_malloc0(new_con, sizeof(rsc_colocation_t)); if(new_con == NULL) { return FALSE; } if(state_lh == NULL || safe_str_eq(state_lh, RSC_ROLE_STARTED_S)) { state_lh = RSC_ROLE_UNKNOWN_S; } if(state_rh == NULL || safe_str_eq(state_rh, RSC_ROLE_STARTED_S)) { state_rh = RSC_ROLE_UNKNOWN_S; } new_con->id = id; new_con->rsc_lh = rsc_lh; new_con->rsc_rh = rsc_rh; new_con->score = score; new_con->role_lh = text2role(state_lh); new_con->role_rh = text2role(state_rh); new_con->node_attribute = node_attr; crm_debug_4("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); 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)){ crm_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) { int score_i = 0; const char *id = crm_element_value(xml_obj, XML_ATTR_ID); const char *id_rh = crm_element_value(xml_obj, XML_CONS_ATTR_TO); const char *id_lh = crm_element_value(xml_obj, XML_CONS_ATTR_FROM); const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE); const char *state_lh = crm_element_value(xml_obj, XML_RULE_ATTR_FROMSTATE); const char *state_rh = crm_element_value(xml_obj, XML_RULE_ATTR_TOSTATE); const char *attr = crm_element_value(xml_obj, "node_attribute"); resource_t *rsc_lh = pe_find_resource(data_set->resources, id_lh); resource_t *rsc_rh = pe_find_resource(data_set->resources, id_rh); if(rsc_lh == NULL) { crm_config_err("No resource (con=%s, rsc=%s)", id, id_lh); return FALSE; } else if(rsc_rh == NULL) { crm_config_err("No resource (con=%s, rsc=%s)", id, id_rh); return FALSE; } if(score) { score_i = char2score(score); } return rsc_colocation_new( id, attr, score_i, rsc_lh, rsc_rh, state_lh, state_rh); } gboolean is_active(rsc_to_node_t *cons) { return TRUE; } diff --git a/crm/pengine/clone.c b/crm/pengine/clone.c index 4658ccd4ff..0bc1ebf38e 100644 --- a/crm/pengine/clone.c +++ b/crm/pengine/clone.c @@ -1,1279 +1,1286 @@ /* $Id: clone.c,v 1.6 2006/07/18 06:19:33 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net> * * 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 <portability.h> #include <crm/msg_xml.h> #include <allocate.h> #include <utils.h> #include <lib/crm/pengine/utils.h> #define VARIANT_CLONE 1 #include <lib/crm/pengine/variant.h> void clone_create_notifications( resource_t *rsc, action_t *action, action_t *action_complete, pe_working_set_t *data_set); 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); void clone_set_cmds(resource_t *rsc) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); 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->cmds->num_allowed_nodes(child_rsc); if(tmp_num_nodes > num_nodes) { num_nodes = tmp_num_nodes; } ); return num_nodes; } static node_t * parent_node_instance(const resource_t *rsc, node_t *node) { clone_variant_data_t *clone_data = NULL; if(node == NULL) { return NULL; } get_clone_variant_data(clone_data, rsc->parent); return pe_find_node_id( clone_data->self->allowed_nodes, node->details->id); } static gint sort_clone_instance(gconstpointer a, gconstpointer b) { int level = LOG_DEBUG_3; node_t *node1 = NULL; node_t *node2 = NULL; gboolean can1 = TRUE; gboolean can2 = TRUE; const resource_t *resource1 = (const resource_t*)a; const resource_t *resource2 = (const resource_t*)b; CRM_ASSERT(resource1 != NULL); CRM_ASSERT(resource2 != NULL); /* allocation order: * - active instances * - instances running on nodes with the least copies * - active instances on nodes that cant support them or are to be fenced * - failed instances * - inactive instances */ + do_crm_log(level, "%s ? %s", resource1->id, resource2->id); if(resource1->running_on && resource2->running_on) { if(g_list_length(resource1->running_on) < g_list_length(resource2->running_on)) { do_crm_log(level, "%s < %s: running_on", resource1->id, resource2->id); return -1; } else if(g_list_length(resource1->running_on) > g_list_length(resource2->running_on)) { do_crm_log(level, "%s > %s: running_on", resource1->id, resource2->id); return 1; } } if(resource1->running_on) { node1 = resource1->running_on->data; } if(resource2->running_on) { node2 = resource2->running_on->data; } if(node1 != node2) { if(node1 == NULL) { do_crm_log(level, "%s > %s: active", resource1->id, resource2->id); return 1; } else if(node2 == NULL) { do_crm_log(level, "%s < %s: active", resource1->id, resource2->id); return -1; } } can1 = can_run_resources(node1); can2 = can_run_resources(node2); if(can1 != can2) { if(can1) { do_crm_log(level, "%s < %s: can", resource1->id, resource2->id); return -1; } do_crm_log(level, "%s > %s: can", resource1->id, resource2->id); return 1; } node1 = parent_node_instance(resource1, node1); node2 = parent_node_instance(resource2, node2); if(node1 != NULL && node2 == NULL) { do_crm_log(level, "%s < %s: not allowed", resource1->id, resource2->id); return -1; } else if(node1 == NULL && node2 != NULL) { do_crm_log(level, "%s > %s: not allowed", resource1->id, resource2->id); return 1; } + if(node1 == NULL) { + do_crm_log(level, "%s == %s: not allowed", resource1->id, resource2->id); + return 0; + } + if(node1->count < node2->count) { do_crm_log(level, "%s < %s: count", resource1->id, resource2->id); return -1; } else if(node1->count > node2->count) { do_crm_log(level, "%s > %s: count", resource1->id, resource2->id); return 1; } do_crm_log(level, "%s == %s: default", resource1->id, resource2->id); return 0; } static node_t * can_run_instance(resource_t *rsc, node_t *node) { node_t *local_node = NULL; clone_variant_data_t *clone_data = NULL; if(can_run_resources(node) == FALSE) { goto bail; } local_node = parent_node_instance(rsc, node); get_clone_variant_data(clone_data, rsc->parent); if(local_node == NULL) { crm_warn("%s cannot run on %s: node not allowed", rsc->id, node->details->uname); goto bail; } else if(local_node->count < clone_data->clone_node_max) { return local_node; } else { crm_debug_2("%s cannot run on %s: node full", rsc->id, node->details->uname); } bail: if(node) { node->weight = -INFINITY; } return NULL; } static node_t * color_instance(resource_t *rsc, pe_working_set_t *data_set) { node_t *local_node = NULL; node_t *chosen = NULL; crm_debug("Processing %s", rsc->id); if(rsc->provisional == FALSE) { return rsc->allocated_to; } else if(rsc->is_allocating) { crm_err("Dependancy loop detected involving %s", rsc->id); return NULL; } if(rsc->allowed_nodes) { slist_iter(try_node, node_t, rsc->allowed_nodes, lpc, if(can_run_instance(rsc, try_node) == NULL) { try_node->weight = -INFINITY; } ); } chosen = rsc->cmds->color(rsc, data_set); if(chosen) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc->parent); local_node = pe_find_node_id( clone_data->self->allowed_nodes, chosen->details->id); CRM_ASSERT(local_node); local_node->count++; } return chosen; } node_t * clone_color(resource_t *rsc, pe_working_set_t *data_set) { int allocated = 0; resource_t *first_child = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); if(rsc->provisional == FALSE) { return NULL; } else if(rsc->is_allocating) { crm_err("Dependancy loop detected involving %s", rsc->id); return NULL; } rsc->is_allocating = TRUE; crm_debug("Processing %s", rsc->id); if(rsc->stickiness) { /* count now tracks the number of clones currently allocated */ slist_iter(node, node_t, clone_data->self->allowed_nodes, lpc, node->count = 0; ); - + slist_iter(child, resource_t, clone_data->child_list, lpc, if(child->running_on) { node_t *local_node = parent_node_instance( child, child->running_on->data); local_node->count++; } ); + clone_data->child_list = g_list_sort( clone_data->child_list, sort_clone_instance); } /* count now tracks the number of clones we have allocated */ slist_iter(node, node_t, clone_data->self->allowed_nodes, lpc, node->count = 0; ); first_child = clone_data->child_list->data; first_child->rsc_cons = g_list_concat( first_child->rsc_cons, rsc->rsc_cons); rsc->rsc_cons = NULL; clone_data->self->allowed_nodes = g_list_sort( clone_data->self->allowed_nodes, sort_node_weight); slist_iter(child, resource_t, clone_data->child_list, lpc, if(allocated >= clone_data->clone_max) { crm_debug("Child %s not allocated - limit reached", child->id); resource_location(child, NULL, -INFINITY, "clone_color:limit_reached", data_set); } if(color_instance(child, data_set)) { allocated++; } ); crm_debug("Allocated %d %s instances of a possible %d", allocated, rsc->id, clone_data->clone_max); rsc->provisional = FALSE; rsc->is_allocating = 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); crm_debug_2("Creating actions for %s", rsc->id); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, 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->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->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); } static resource_t* find_compatible_child(resource_t *local_child, resource_t *rsc) { node_t *local_node = NULL; node_t *node = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); local_node = local_child->allocated_to; if(local_node == NULL) { crm_debug("Can't colocate unrunnable child %s with %s", local_child->id, rsc->id); return NULL; } slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, node = child_rsc->allocated_to; if(node->details == local_node->details) { crm_info("Colocating %s with %s on %s", local_child->id, child_rsc->id, node->details->uname); return child_rsc; } ); crm_debug("Can't colocate child %s with %s", local_child->id, rsc->id); return NULL; } 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) { crm_config_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->score >= INFINITY) { GListPtr lhs = NULL, rhs = NULL; lhs = rsc_lh->allowed_nodes; slist_iter( child_rsc, resource_t, clone_data_rh->child_list, lpc, if(child_rsc->allocated_to != NULL) { rhs = g_list_append(rhs, child_rsc->allocated_to); } ); rsc_lh->allowed_nodes = node_list_and(lhs, rhs, FALSE); pe_free_shallow_adv(rhs, FALSE); pe_free_shallow(lhs); return; } } else if(constraint->score >= INFINITY) { crm_config_err("Manditory co-location of clones (%s) with other" " non-clone (%s) resources is not supported", rsc_lh->id, rsc_rh->id); return; } if(do_interleave) { resource_t *rh_child = NULL; slist_iter(lh_child, resource_t, clone_data->child_list, lpc, CRM_ASSERT(lh_child != NULL); rh_child = find_compatible_child(lh_child, rsc_rh); if(rh_child == NULL) { continue; } lh_child->cmds->rsc_colocation_lh( lh_child, rh_child, constraint); ); return; } slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, 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); get_clone_variant_data(clone_data, rsc_rh); crm_debug_3("Processing constraint %s: %d", constraint->id, constraint->score); if(rsc_rh == NULL) { pe_err("rsc_rh was NULL for %s", constraint->id); return; } else if(rsc_rh->provisional) { crm_debug_3("%s is still provisional", rsc_rh->id); return; } else if(constraint->score >= INFINITY) { GListPtr lhs = NULL, rhs = NULL; lhs = rsc_lh->allowed_nodes; slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, if(child_rsc->allocated_to != NULL) { rhs = g_list_append(rhs, child_rsc->allocated_to); } ); rsc_lh->allowed_nodes = node_list_and(lhs, rhs, FALSE); pe_free_shallow_adv(rhs, FALSE); pe_free_shallow(lhs); return; } slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, 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->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->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 location constraint %s for %s", constraint->id, rsc->id); clone_data->self->cmds->rsc_location(clone_data->self, constraint); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, 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) { const char *uname = NULL; const char *rsc_id = NULL; const char *last_rsc_id = NULL; CRM_CHECK(list != NULL, return); if(rsc_list) { CRM_CHECK(*rsc_list == NULL, *rsc_list = NULL); } if(node_list) { CRM_CHECK(*node_list == NULL, *node_list = NULL); } slist_iter(entry, notify_entry_t, list, lpc, CRM_CHECK(entry != NULL, continue); 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) { int existing_len = 0; int len = 2 + strlen(rsc_id); /* +1 space, +1 EOS */ if(rsc_list && *rsc_list) { existing_len = strlen(*rsc_list); } crm_debug_5("Adding %s (%dc) at offset %d", rsc_id, len-2, existing_len); crm_realloc(*rsc_list, len + existing_len); sprintf(*rsc_list + existing_len, "%s ", rsc_id); } if(node_list != NULL) { int existing_len = 0; int len = 2 + strlen(uname); if(node_list && *node_list) { existing_len = strlen(*node_list); } crm_debug_5("Adding %s (%dc) at offset %d", uname, len-2, existing_len); crm_realloc(*node_list, len + existing_len); sprintf(*node_list + existing_len, "%s ", uname); } ); } 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->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->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->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); } 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->cmds->agent_constraints(child_rsc); ); } 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->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->cmds->create_probe( child_rsc, node, complete, force, data_set); } ); } slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, 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) { 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->cmds->stonith_ordering( child_rsc, stonith_op, data_set); ); } diff --git a/crm/pengine/testcases/inc7.dot b/crm/pengine/testcases/inc7.dot index 41aa71b690..53adc3e699 100644 --- a/crm/pengine/testcases/inc7.dot +++ b/crm/pengine/testcases/inc7.dot @@ -1,116 +1,116 @@ digraph "g" { "child_rsc1:0_monitor_0 node1" -> "probe_complete node1" [ style = bold] "child_rsc1:0_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "child_rsc1:0_monitor_0 node2" -> "probe_complete node2" [ style = bold] "child_rsc1:0_monitor_0 node2" [ style=bold color="green" fontcolor="black" ] "child_rsc1:0_monitor_0 node3" -> "probe_complete node3" [ style = bold] "child_rsc1:0_monitor_0 node3" [ style=bold color="green" fontcolor="black" ] -"child_rsc1:0_start_0 node2" -> "rsc1_running_0" [ style = bold] -"child_rsc1:0_start_0 node2" [ style=bold color="green" fontcolor="black" ] +"child_rsc1:0_start_0 node1" -> "rsc1_running_0" [ style = bold] +"child_rsc1:0_start_0 node1" [ style=bold color="green" fontcolor="black" ] "child_rsc1:1_monitor_0 node1" -> "probe_complete node1" [ style = bold] "child_rsc1:1_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "child_rsc1:1_monitor_0 node2" -> "probe_complete node2" [ style = bold] "child_rsc1:1_monitor_0 node2" [ style=bold color="green" fontcolor="black" ] "child_rsc1:1_monitor_0 node3" -> "probe_complete node3" [ style = bold] "child_rsc1:1_monitor_0 node3" [ style=bold color="green" fontcolor="black" ] -"child_rsc1:1_start_0 node1" -> "rsc1_running_0" [ style = bold] -"child_rsc1:1_start_0 node1" [ style=bold color="green" fontcolor="black" ] +"child_rsc1:1_start_0 node2" -> "rsc1_running_0" [ style = bold] +"child_rsc1:1_start_0 node2" [ style=bold color="green" fontcolor="black" ] "child_rsc1:2_monitor_0 node1" -> "probe_complete node1" [ style = bold] "child_rsc1:2_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "child_rsc1:2_monitor_0 node2" -> "probe_complete node2" [ style = bold] "child_rsc1:2_monitor_0 node2" [ style=bold color="green" fontcolor="black" ] "child_rsc1:2_monitor_0 node3" -> "probe_complete node3" [ style = bold] "child_rsc1:2_monitor_0 node3" [ style=bold color="green" fontcolor="black" ] "child_rsc1:2_start_0 node3" -> "rsc1_running_0" [ style = bold] "child_rsc1:2_start_0 node3" [ style=bold color="green" fontcolor="black" ] "child_rsc1:3_monitor_0 node1" -> "probe_complete node1" [ style = bold] "child_rsc1:3_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "child_rsc1:3_monitor_0 node2" -> "probe_complete node2" [ style = bold] "child_rsc1:3_monitor_0 node2" [ style=bold color="green" fontcolor="black" ] "child_rsc1:3_monitor_0 node3" -> "probe_complete node3" [ style = bold] "child_rsc1:3_monitor_0 node3" [ style=bold color="green" fontcolor="black" ] "child_rsc1:3_start_0 node1" -> "rsc1_running_0" [ style = bold] "child_rsc1:3_start_0 node1" [ style=bold color="green" fontcolor="black" ] "child_rsc1:4_monitor_0 node1" -> "probe_complete node1" [ style = bold] "child_rsc1:4_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "child_rsc1:4_monitor_0 node2" -> "probe_complete node2" [ style = bold] "child_rsc1:4_monitor_0 node2" [ style=bold color="green" fontcolor="black" ] "child_rsc1:4_monitor_0 node3" -> "probe_complete node3" [ style = bold] "child_rsc1:4_monitor_0 node3" [ style=bold color="green" fontcolor="black" ] "child_rsc1:4_start_0 node2" -> "rsc1_running_0" [ style = bold] "child_rsc1:4_start_0 node2" [ style=bold color="green" fontcolor="black" ] "child_rsc2:0_monitor_0 node1" -> "probe_complete node1" [ style = bold] "child_rsc2:0_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "child_rsc2:0_monitor_0 node2" -> "probe_complete node2" [ style = bold] "child_rsc2:0_monitor_0 node2" [ style=bold color="green" fontcolor="black" ] "child_rsc2:0_monitor_0 node3" -> "probe_complete node3" [ style = bold] "child_rsc2:0_monitor_0 node3" [ style=bold color="green" fontcolor="black" ] "child_rsc2:0_start_0 node2" -> "rsc2_running_0" [ style = bold] "child_rsc2:0_start_0 node2" [ style=bold color="green" fontcolor="black" ] "child_rsc2:1_monitor_0 node1" -> "probe_complete node1" [ style = bold] "child_rsc2:1_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "child_rsc2:1_monitor_0 node2" -> "probe_complete node2" [ style = bold] "child_rsc2:1_monitor_0 node2" [ style=bold color="green" fontcolor="black" ] "child_rsc2:1_monitor_0 node3" -> "probe_complete node3" [ style = bold] "child_rsc2:1_monitor_0 node3" [ style=bold color="green" fontcolor="black" ] "child_rsc2:1_start_0 node3" -> "rsc2_running_0" [ style = bold] "child_rsc2:1_start_0 node3" [ style=bold color="green" fontcolor="black" ] "child_rsc2:2_monitor_0 node1" -> "probe_complete node1" [ style = bold] "child_rsc2:2_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "child_rsc2:2_monitor_0 node2" -> "probe_complete node2" [ style = bold] "child_rsc2:2_monitor_0 node2" [ style=bold color="green" fontcolor="black" ] "child_rsc2:2_monitor_0 node3" -> "probe_complete node3" [ style = bold] "child_rsc2:2_monitor_0 node3" [ style=bold color="green" fontcolor="black" ] "child_rsc2:2_start_0 node1" -> "rsc2_running_0" [ style = bold] "child_rsc2:2_start_0 node1" [ style=bold color="green" fontcolor="black" ] "child_rsc2:3_monitor_0 node1" -> "probe_complete node1" [ style = bold] "child_rsc2:3_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "child_rsc2:3_monitor_0 node2" -> "probe_complete node2" [ style = bold] "child_rsc2:3_monitor_0 node2" [ style=bold color="green" fontcolor="black" ] "child_rsc2:3_monitor_0 node3" -> "probe_complete node3" [ style = bold] "child_rsc2:3_monitor_0 node3" [ style=bold color="green" fontcolor="black" ] "child_rsc2:3_start_0 node2" -> "rsc2_running_0" [ style = bold] "child_rsc2:3_start_0 node2" [ style=bold color="green" fontcolor="black" ] "child_rsc2:4_monitor_0 node1" -> "probe_complete node1" [ style = bold] "child_rsc2:4_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "child_rsc2:4_monitor_0 node2" -> "probe_complete node2" [ style = bold] "child_rsc2:4_monitor_0 node2" [ style=bold color="green" fontcolor="black" ] "child_rsc2:4_monitor_0 node3" -> "probe_complete node3" [ style = bold] "child_rsc2:4_monitor_0 node3" [ style=bold color="green" fontcolor="black" ] "child_rsc2:4_start_0 node3" -> "rsc2_running_0" [ style = bold] "child_rsc2:4_start_0 node3" [ style=bold color="green" fontcolor="black" ] "probe_complete node1" -> "probe_complete" [ style = bold] "probe_complete node1" [ style=bold color="green" fontcolor="black" ] "probe_complete node2" -> "probe_complete" [ style = bold] "probe_complete node2" [ style=bold color="green" fontcolor="black" ] "probe_complete node3" -> "probe_complete" [ style = bold] "probe_complete node3" [ style=bold color="green" fontcolor="black" ] "probe_complete" -> "rsc0_start_0 node1" [ style = bold] "probe_complete" -> "rsc1_start_0" [ style = bold] "probe_complete" -> "rsc2_start_0" [ style = bold] "probe_complete" [ style=bold color="green" fontcolor="orange" ] "rsc0_monitor_0 node1" -> "probe_complete node1" [ style = bold] "rsc0_monitor_0 node1" [ style=bold color="green" fontcolor="black" ] "rsc0_monitor_0 node2" -> "probe_complete node2" [ style = bold] "rsc0_monitor_0 node2" [ style=bold color="green" fontcolor="black" ] "rsc0_monitor_0 node3" -> "probe_complete node3" [ style = bold] "rsc0_monitor_0 node3" [ style=bold color="green" fontcolor="black" ] "rsc0_start_0 node1" [ style=bold color="green" fontcolor="black" ] "rsc1_running_0" -> "rsc2_start_0" [ style = bold] "rsc1_running_0" [ style=bold color="green" fontcolor="orange" ] -"rsc1_start_0" -> "child_rsc1:0_start_0 node2" [ style = bold] -"rsc1_start_0" -> "child_rsc1:1_start_0 node1" [ style = bold] +"rsc1_start_0" -> "child_rsc1:0_start_0 node1" [ style = bold] +"rsc1_start_0" -> "child_rsc1:1_start_0 node2" [ style = bold] "rsc1_start_0" -> "child_rsc1:2_start_0 node3" [ style = bold] "rsc1_start_0" -> "child_rsc1:3_start_0 node1" [ style = bold] "rsc1_start_0" -> "child_rsc1:4_start_0 node2" [ style = bold] "rsc1_start_0" -> "rsc1_running_0" [ style = bold] "rsc1_start_0" [ style=bold color="green" fontcolor="orange" ] "rsc2_running_0" [ style=bold color="green" fontcolor="orange" ] "rsc2_start_0" -> "child_rsc2:0_start_0 node2" [ style = bold] "rsc2_start_0" -> "child_rsc2:1_start_0 node3" [ style = bold] "rsc2_start_0" -> "child_rsc2:2_start_0 node1" [ style = bold] "rsc2_start_0" -> "child_rsc2:3_start_0 node2" [ style = bold] "rsc2_start_0" -> "child_rsc2:4_start_0 node3" [ style = bold] "rsc2_start_0" -> "rsc2_running_0" [ style = bold] "rsc2_start_0" [ style=bold color="green" fontcolor="orange" ] } diff --git a/crm/pengine/testcases/inc7.exp b/crm/pengine/testcases/inc7.exp index d5a1e8e2ac..3d4223d3a3 100644 --- a/crm/pengine/testcases/inc7.exp +++ b/crm/pengine/testcases/inc7.exp @@ -1,668 +1,668 @@ <transition_graph network-delay="60s" transition_id="0"> <synapse id="0" priority="1000000"> <action_set> <rsc_op id="3" operation="monitor" operation_key="rsc0_monitor_0" on_node="node1" on_node_uuid="uuid1"> <primitive id="rsc0" long-id="rsc0" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="1" priority="1000000"> <action_set> <rsc_op id="15" operation="monitor" operation_key="rsc0_monitor_0" on_node="node2" on_node_uuid="uuid2"> <primitive id="rsc0" long-id="rsc0" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="2" priority="1000000"> <action_set> <rsc_op id="27" operation="monitor" operation_key="rsc0_monitor_0" on_node="node3" on_node_uuid="uuid3"> <primitive id="rsc0" long-id="rsc0" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="3"> <action_set> <rsc_op id="38" operation="start" operation_key="rsc0_start_0" on_node="node1" on_node_uuid="uuid1"> <primitive id="rsc0" long-id="rsc0" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000"/> </rsc_op> </action_set> <inputs> <trigger> <pseudo_event id="1" operation="probe_complete" operation_key="probe_complete"/> </trigger> </inputs> </synapse> <synapse id="4" priority="1000000"> <action_set> <rsc_op id="4" operation="monitor" operation_key="child_rsc1:0_monitor_0" on_node="node1" on_node_uuid="uuid1"> <primitive id="child_rsc1:0" long-id="rsc1:child_rsc1:0" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="0" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="5" priority="1000000"> <action_set> <rsc_op id="16" operation="monitor" operation_key="child_rsc1:0_monitor_0" on_node="node2" on_node_uuid="uuid2"> <primitive id="child_rsc1:0" long-id="rsc1:child_rsc1:0" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="0" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="6" priority="1000000"> <action_set> <rsc_op id="28" operation="monitor" operation_key="child_rsc1:0_monitor_0" on_node="node3" on_node_uuid="uuid3"> <primitive id="child_rsc1:0" long-id="rsc1:child_rsc1:0" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="0" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="7"> <action_set> - <rsc_op id="39" operation="start" operation_key="child_rsc1:0_start_0" on_node="node2" on_node_uuid="uuid2"> + <rsc_op id="39" operation="start" operation_key="child_rsc1:0_start_0" on_node="node1" on_node_uuid="uuid1"> <primitive id="child_rsc1:0" long-id="rsc1:child_rsc1:0" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_clone="0" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs> <trigger> <pseudo_event id="44" operation="start" operation_key="rsc1_start_0"/> </trigger> </inputs> </synapse> <synapse id="8" priority="1000000"> <action_set> <rsc_op id="5" operation="monitor" operation_key="child_rsc1:1_monitor_0" on_node="node1" on_node_uuid="uuid1"> <primitive id="child_rsc1:1" long-id="rsc1:child_rsc1:1" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="1" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="9" priority="1000000"> <action_set> <rsc_op id="17" operation="monitor" operation_key="child_rsc1:1_monitor_0" on_node="node2" on_node_uuid="uuid2"> <primitive id="child_rsc1:1" long-id="rsc1:child_rsc1:1" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="1" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="10" priority="1000000"> <action_set> <rsc_op id="29" operation="monitor" operation_key="child_rsc1:1_monitor_0" on_node="node3" on_node_uuid="uuid3"> <primitive id="child_rsc1:1" long-id="rsc1:child_rsc1:1" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="1" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="11"> <action_set> - <rsc_op id="40" operation="start" operation_key="child_rsc1:1_start_0" on_node="node1" on_node_uuid="uuid1"> + <rsc_op id="40" operation="start" operation_key="child_rsc1:1_start_0" on_node="node2" on_node_uuid="uuid2"> <primitive id="child_rsc1:1" long-id="rsc1:child_rsc1:1" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_clone="1" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs> <trigger> <pseudo_event id="44" operation="start" operation_key="rsc1_start_0"/> </trigger> </inputs> </synapse> <synapse id="12" priority="1000000"> <action_set> <rsc_op id="6" operation="monitor" operation_key="child_rsc1:2_monitor_0" on_node="node1" on_node_uuid="uuid1"> <primitive id="child_rsc1:2" long-id="rsc1:child_rsc1:2" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="2" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="13" priority="1000000"> <action_set> <rsc_op id="18" operation="monitor" operation_key="child_rsc1:2_monitor_0" on_node="node2" on_node_uuid="uuid2"> <primitive id="child_rsc1:2" long-id="rsc1:child_rsc1:2" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="2" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="14" priority="1000000"> <action_set> <rsc_op id="30" operation="monitor" operation_key="child_rsc1:2_monitor_0" on_node="node3" on_node_uuid="uuid3"> <primitive id="child_rsc1:2" long-id="rsc1:child_rsc1:2" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="2" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="15"> <action_set> <rsc_op id="41" operation="start" operation_key="child_rsc1:2_start_0" on_node="node3" on_node_uuid="uuid3"> <primitive id="child_rsc1:2" long-id="rsc1:child_rsc1:2" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_clone="2" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs> <trigger> <pseudo_event id="44" operation="start" operation_key="rsc1_start_0"/> </trigger> </inputs> </synapse> <synapse id="16" priority="1000000"> <action_set> <rsc_op id="7" operation="monitor" operation_key="child_rsc1:3_monitor_0" on_node="node1" on_node_uuid="uuid1"> <primitive id="child_rsc1:3" long-id="rsc1:child_rsc1:3" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="3" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="17" priority="1000000"> <action_set> <rsc_op id="19" operation="monitor" operation_key="child_rsc1:3_monitor_0" on_node="node2" on_node_uuid="uuid2"> <primitive id="child_rsc1:3" long-id="rsc1:child_rsc1:3" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="3" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="18" priority="1000000"> <action_set> <rsc_op id="31" operation="monitor" operation_key="child_rsc1:3_monitor_0" on_node="node3" on_node_uuid="uuid3"> <primitive id="child_rsc1:3" long-id="rsc1:child_rsc1:3" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="3" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="19"> <action_set> <rsc_op id="42" operation="start" operation_key="child_rsc1:3_start_0" on_node="node1" on_node_uuid="uuid1"> <primitive id="child_rsc1:3" long-id="rsc1:child_rsc1:3" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_clone="3" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs> <trigger> <pseudo_event id="44" operation="start" operation_key="rsc1_start_0"/> </trigger> </inputs> </synapse> <synapse id="20" priority="1000000"> <action_set> <rsc_op id="8" operation="monitor" operation_key="child_rsc1:4_monitor_0" on_node="node1" on_node_uuid="uuid1"> <primitive id="child_rsc1:4" long-id="rsc1:child_rsc1:4" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="4" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="21" priority="1000000"> <action_set> <rsc_op id="20" operation="monitor" operation_key="child_rsc1:4_monitor_0" on_node="node2" on_node_uuid="uuid2"> <primitive id="child_rsc1:4" long-id="rsc1:child_rsc1:4" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="4" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="22" priority="1000000"> <action_set> <rsc_op id="32" operation="monitor" operation_key="child_rsc1:4_monitor_0" on_node="node3" on_node_uuid="uuid3"> <primitive id="child_rsc1:4" long-id="rsc1:child_rsc1:4" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="4" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="23"> <action_set> <rsc_op id="43" operation="start" operation_key="child_rsc1:4_start_0" on_node="node2" on_node_uuid="uuid2"> <primitive id="child_rsc1:4" long-id="rsc1:child_rsc1:4" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_clone="4" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs> <trigger> <pseudo_event id="44" operation="start" operation_key="rsc1_start_0"/> </trigger> </inputs> </synapse> <synapse id="24"> <action_set> <pseudo_event id="44" operation="start" operation_key="rsc1_start_0"> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </pseudo_event> </action_set> <inputs> <trigger> <pseudo_event id="1" operation="probe_complete" operation_key="probe_complete"/> </trigger> </inputs> </synapse> <synapse id="25" priority="1000000"> <action_set> <pseudo_event id="45" operation="running" operation_key="rsc1_running_0"> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </pseudo_event> </action_set> <inputs> <trigger> - <rsc_op id="39" operation="start" operation_key="child_rsc1:0_start_0" on_node="node2" on_node_uuid="uuid2"/> + <rsc_op id="39" operation="start" operation_key="child_rsc1:0_start_0" on_node="node1" on_node_uuid="uuid1"/> </trigger> <trigger> - <rsc_op id="40" operation="start" operation_key="child_rsc1:1_start_0" on_node="node1" on_node_uuid="uuid1"/> + <rsc_op id="40" operation="start" operation_key="child_rsc1:1_start_0" on_node="node2" on_node_uuid="uuid2"/> </trigger> <trigger> <rsc_op id="41" operation="start" operation_key="child_rsc1:2_start_0" on_node="node3" on_node_uuid="uuid3"/> </trigger> <trigger> <rsc_op id="42" operation="start" operation_key="child_rsc1:3_start_0" on_node="node1" on_node_uuid="uuid1"/> </trigger> <trigger> <rsc_op id="43" operation="start" operation_key="child_rsc1:4_start_0" on_node="node2" on_node_uuid="uuid2"/> </trigger> <trigger> <pseudo_event id="44" operation="start" operation_key="rsc1_start_0"/> </trigger> </inputs> </synapse> <synapse id="26" priority="1000000"> <action_set> <rsc_op id="9" operation="monitor" operation_key="child_rsc2:0_monitor_0" on_node="node1" on_node_uuid="uuid1"> <primitive id="child_rsc2:0" long-id="rsc2:child_rsc2:0" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="0" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="27" priority="1000000"> <action_set> <rsc_op id="21" operation="monitor" operation_key="child_rsc2:0_monitor_0" on_node="node2" on_node_uuid="uuid2"> <primitive id="child_rsc2:0" long-id="rsc2:child_rsc2:0" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="0" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="28" priority="1000000"> <action_set> <rsc_op id="33" operation="monitor" operation_key="child_rsc2:0_monitor_0" on_node="node3" on_node_uuid="uuid3"> <primitive id="child_rsc2:0" long-id="rsc2:child_rsc2:0" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="0" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="29"> <action_set> <rsc_op id="48" operation="start" operation_key="child_rsc2:0_start_0" on_node="node2" on_node_uuid="uuid2"> <primitive id="child_rsc2:0" long-id="rsc2:child_rsc2:0" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_clone="0" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs> <trigger> <pseudo_event id="53" operation="start" operation_key="rsc2_start_0"/> </trigger> </inputs> </synapse> <synapse id="30" priority="1000000"> <action_set> <rsc_op id="10" operation="monitor" operation_key="child_rsc2:1_monitor_0" on_node="node1" on_node_uuid="uuid1"> <primitive id="child_rsc2:1" long-id="rsc2:child_rsc2:1" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="1" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="31" priority="1000000"> <action_set> <rsc_op id="22" operation="monitor" operation_key="child_rsc2:1_monitor_0" on_node="node2" on_node_uuid="uuid2"> <primitive id="child_rsc2:1" long-id="rsc2:child_rsc2:1" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="1" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="32" priority="1000000"> <action_set> <rsc_op id="34" operation="monitor" operation_key="child_rsc2:1_monitor_0" on_node="node3" on_node_uuid="uuid3"> <primitive id="child_rsc2:1" long-id="rsc2:child_rsc2:1" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="1" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="33"> <action_set> <rsc_op id="49" operation="start" operation_key="child_rsc2:1_start_0" on_node="node3" on_node_uuid="uuid3"> <primitive id="child_rsc2:1" long-id="rsc2:child_rsc2:1" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_clone="1" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs> <trigger> <pseudo_event id="53" operation="start" operation_key="rsc2_start_0"/> </trigger> </inputs> </synapse> <synapse id="34" priority="1000000"> <action_set> <rsc_op id="11" operation="monitor" operation_key="child_rsc2:2_monitor_0" on_node="node1" on_node_uuid="uuid1"> <primitive id="child_rsc2:2" long-id="rsc2:child_rsc2:2" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="2" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="35" priority="1000000"> <action_set> <rsc_op id="23" operation="monitor" operation_key="child_rsc2:2_monitor_0" on_node="node2" on_node_uuid="uuid2"> <primitive id="child_rsc2:2" long-id="rsc2:child_rsc2:2" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="2" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="36" priority="1000000"> <action_set> <rsc_op id="35" operation="monitor" operation_key="child_rsc2:2_monitor_0" on_node="node3" on_node_uuid="uuid3"> <primitive id="child_rsc2:2" long-id="rsc2:child_rsc2:2" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="2" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="37"> <action_set> <rsc_op id="50" operation="start" operation_key="child_rsc2:2_start_0" on_node="node1" on_node_uuid="uuid1"> <primitive id="child_rsc2:2" long-id="rsc2:child_rsc2:2" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_clone="2" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs> <trigger> <pseudo_event id="53" operation="start" operation_key="rsc2_start_0"/> </trigger> </inputs> </synapse> <synapse id="38" priority="1000000"> <action_set> <rsc_op id="12" operation="monitor" operation_key="child_rsc2:3_monitor_0" on_node="node1" on_node_uuid="uuid1"> <primitive id="child_rsc2:3" long-id="rsc2:child_rsc2:3" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="3" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="39" priority="1000000"> <action_set> <rsc_op id="24" operation="monitor" operation_key="child_rsc2:3_monitor_0" on_node="node2" on_node_uuid="uuid2"> <primitive id="child_rsc2:3" long-id="rsc2:child_rsc2:3" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="3" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="40" priority="1000000"> <action_set> <rsc_op id="36" operation="monitor" operation_key="child_rsc2:3_monitor_0" on_node="node3" on_node_uuid="uuid3"> <primitive id="child_rsc2:3" long-id="rsc2:child_rsc2:3" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="3" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="41"> <action_set> <rsc_op id="51" operation="start" operation_key="child_rsc2:3_start_0" on_node="node2" on_node_uuid="uuid2"> <primitive id="child_rsc2:3" long-id="rsc2:child_rsc2:3" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_clone="3" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs> <trigger> <pseudo_event id="53" operation="start" operation_key="rsc2_start_0"/> </trigger> </inputs> </synapse> <synapse id="42" priority="1000000"> <action_set> <rsc_op id="13" operation="monitor" operation_key="child_rsc2:4_monitor_0" on_node="node1" on_node_uuid="uuid1"> <primitive id="child_rsc2:4" long-id="rsc2:child_rsc2:4" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="4" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="43" priority="1000000"> <action_set> <rsc_op id="25" operation="monitor" operation_key="child_rsc2:4_monitor_0" on_node="node2" on_node_uuid="uuid2"> <primitive id="child_rsc2:4" long-id="rsc2:child_rsc2:4" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="4" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="44" priority="1000000"> <action_set> <rsc_op id="37" operation="monitor" operation_key="child_rsc2:4_monitor_0" on_node="node3" on_node_uuid="uuid3"> <primitive id="child_rsc2:4" long-id="rsc2:child_rsc2:4" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_op_target_rc="7" CRM_meta_clone="4" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs/> </synapse> <synapse id="45"> <action_set> <rsc_op id="52" operation="start" operation_key="child_rsc2:4_start_0" on_node="node3" on_node_uuid="uuid3"> <primitive id="child_rsc2:4" long-id="rsc2:child_rsc2:4" class="heartbeat" type="apache"/> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_clone="4" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </rsc_op> </action_set> <inputs> <trigger> <pseudo_event id="53" operation="start" operation_key="rsc2_start_0"/> </trigger> </inputs> </synapse> <synapse id="46"> <action_set> <pseudo_event id="53" operation="start" operation_key="rsc2_start_0"> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </pseudo_event> </action_set> <inputs> <trigger> <pseudo_event id="1" operation="probe_complete" operation_key="probe_complete"/> </trigger> <trigger> <pseudo_event id="45" operation="running" operation_key="rsc1_running_0"/> </trigger> </inputs> </synapse> <synapse id="47" priority="1000000"> <action_set> <pseudo_event id="54" operation="running" operation_key="rsc2_running_0"> <attributes crm_feature_set="1.0.7" CRM_meta_timeout="20000" CRM_meta_clone_max="5" CRM_meta_clone_node_max="2"/> </pseudo_event> </action_set> <inputs> <trigger> <rsc_op id="48" operation="start" operation_key="child_rsc2:0_start_0" on_node="node2" on_node_uuid="uuid2"/> </trigger> <trigger> <rsc_op id="49" operation="start" operation_key="child_rsc2:1_start_0" on_node="node3" on_node_uuid="uuid3"/> </trigger> <trigger> <rsc_op id="50" operation="start" operation_key="child_rsc2:2_start_0" on_node="node1" on_node_uuid="uuid1"/> </trigger> <trigger> <rsc_op id="51" operation="start" operation_key="child_rsc2:3_start_0" on_node="node2" on_node_uuid="uuid2"/> </trigger> <trigger> <rsc_op id="52" operation="start" operation_key="child_rsc2:4_start_0" on_node="node3" on_node_uuid="uuid3"/> </trigger> <trigger> <pseudo_event id="53" operation="start" operation_key="rsc2_start_0"/> </trigger> </inputs> </synapse> <synapse id="48"> <action_set> <pseudo_event id="1" operation="probe_complete" operation_key="probe_complete"> <attributes crm_feature_set="1.0.7"/> </pseudo_event> </action_set> <inputs> <trigger> <rsc_op id="2" operation="probe_complete" operation_key="probe_complete" on_node="node1" on_node_uuid="uuid1"/> </trigger> <trigger> <rsc_op id="14" operation="probe_complete" operation_key="probe_complete" on_node="node2" on_node_uuid="uuid2"/> </trigger> <trigger> <rsc_op id="26" operation="probe_complete" operation_key="probe_complete" on_node="node3" on_node_uuid="uuid3"/> </trigger> </inputs> </synapse> <synapse id="49" priority="1000000"> <action_set> <rsc_op id="2" operation="probe_complete" operation_key="probe_complete" on_node="node1" on_node_uuid="uuid1"> <attributes crm_feature_set="1.0.7" CRM_meta_op_no_wait="true"/> </rsc_op> </action_set> <inputs> <trigger> <rsc_op id="3" operation="monitor" operation_key="rsc0_monitor_0" on_node="node1" on_node_uuid="uuid1"/> </trigger> <trigger> <rsc_op id="4" operation="monitor" operation_key="child_rsc1:0_monitor_0" on_node="node1" on_node_uuid="uuid1"/> </trigger> <trigger> <rsc_op id="5" operation="monitor" operation_key="child_rsc1:1_monitor_0" on_node="node1" on_node_uuid="uuid1"/> </trigger> <trigger> <rsc_op id="6" operation="monitor" operation_key="child_rsc1:2_monitor_0" on_node="node1" on_node_uuid="uuid1"/> </trigger> <trigger> <rsc_op id="7" operation="monitor" operation_key="child_rsc1:3_monitor_0" on_node="node1" on_node_uuid="uuid1"/> </trigger> <trigger> <rsc_op id="8" operation="monitor" operation_key="child_rsc1:4_monitor_0" on_node="node1" on_node_uuid="uuid1"/> </trigger> <trigger> <rsc_op id="9" operation="monitor" operation_key="child_rsc2:0_monitor_0" on_node="node1" on_node_uuid="uuid1"/> </trigger> <trigger> <rsc_op id="10" operation="monitor" operation_key="child_rsc2:1_monitor_0" on_node="node1" on_node_uuid="uuid1"/> </trigger> <trigger> <rsc_op id="11" operation="monitor" operation_key="child_rsc2:2_monitor_0" on_node="node1" on_node_uuid="uuid1"/> </trigger> <trigger> <rsc_op id="12" operation="monitor" operation_key="child_rsc2:3_monitor_0" on_node="node1" on_node_uuid="uuid1"/> </trigger> <trigger> <rsc_op id="13" operation="monitor" operation_key="child_rsc2:4_monitor_0" on_node="node1" on_node_uuid="uuid1"/> </trigger> </inputs> </synapse> <synapse id="50" priority="1000000"> <action_set> <rsc_op id="14" operation="probe_complete" operation_key="probe_complete" on_node="node2" on_node_uuid="uuid2"> <attributes crm_feature_set="1.0.7" CRM_meta_op_no_wait="true"/> </rsc_op> </action_set> <inputs> <trigger> <rsc_op id="15" operation="monitor" operation_key="rsc0_monitor_0" on_node="node2" on_node_uuid="uuid2"/> </trigger> <trigger> <rsc_op id="16" operation="monitor" operation_key="child_rsc1:0_monitor_0" on_node="node2" on_node_uuid="uuid2"/> </trigger> <trigger> <rsc_op id="17" operation="monitor" operation_key="child_rsc1:1_monitor_0" on_node="node2" on_node_uuid="uuid2"/> </trigger> <trigger> <rsc_op id="18" operation="monitor" operation_key="child_rsc1:2_monitor_0" on_node="node2" on_node_uuid="uuid2"/> </trigger> <trigger> <rsc_op id="19" operation="monitor" operation_key="child_rsc1:3_monitor_0" on_node="node2" on_node_uuid="uuid2"/> </trigger> <trigger> <rsc_op id="20" operation="monitor" operation_key="child_rsc1:4_monitor_0" on_node="node2" on_node_uuid="uuid2"/> </trigger> <trigger> <rsc_op id="21" operation="monitor" operation_key="child_rsc2:0_monitor_0" on_node="node2" on_node_uuid="uuid2"/> </trigger> <trigger> <rsc_op id="22" operation="monitor" operation_key="child_rsc2:1_monitor_0" on_node="node2" on_node_uuid="uuid2"/> </trigger> <trigger> <rsc_op id="23" operation="monitor" operation_key="child_rsc2:2_monitor_0" on_node="node2" on_node_uuid="uuid2"/> </trigger> <trigger> <rsc_op id="24" operation="monitor" operation_key="child_rsc2:3_monitor_0" on_node="node2" on_node_uuid="uuid2"/> </trigger> <trigger> <rsc_op id="25" operation="monitor" operation_key="child_rsc2:4_monitor_0" on_node="node2" on_node_uuid="uuid2"/> </trigger> </inputs> </synapse> <synapse id="51" priority="1000000"> <action_set> <rsc_op id="26" operation="probe_complete" operation_key="probe_complete" on_node="node3" on_node_uuid="uuid3"> <attributes crm_feature_set="1.0.7" CRM_meta_op_no_wait="true"/> </rsc_op> </action_set> <inputs> <trigger> <rsc_op id="27" operation="monitor" operation_key="rsc0_monitor_0" on_node="node3" on_node_uuid="uuid3"/> </trigger> <trigger> <rsc_op id="28" operation="monitor" operation_key="child_rsc1:0_monitor_0" on_node="node3" on_node_uuid="uuid3"/> </trigger> <trigger> <rsc_op id="29" operation="monitor" operation_key="child_rsc1:1_monitor_0" on_node="node3" on_node_uuid="uuid3"/> </trigger> <trigger> <rsc_op id="30" operation="monitor" operation_key="child_rsc1:2_monitor_0" on_node="node3" on_node_uuid="uuid3"/> </trigger> <trigger> <rsc_op id="31" operation="monitor" operation_key="child_rsc1:3_monitor_0" on_node="node3" on_node_uuid="uuid3"/> </trigger> <trigger> <rsc_op id="32" operation="monitor" operation_key="child_rsc1:4_monitor_0" on_node="node3" on_node_uuid="uuid3"/> </trigger> <trigger> <rsc_op id="33" operation="monitor" operation_key="child_rsc2:0_monitor_0" on_node="node3" on_node_uuid="uuid3"/> </trigger> <trigger> <rsc_op id="34" operation="monitor" operation_key="child_rsc2:1_monitor_0" on_node="node3" on_node_uuid="uuid3"/> </trigger> <trigger> <rsc_op id="35" operation="monitor" operation_key="child_rsc2:2_monitor_0" on_node="node3" on_node_uuid="uuid3"/> </trigger> <trigger> <rsc_op id="36" operation="monitor" operation_key="child_rsc2:3_monitor_0" on_node="node3" on_node_uuid="uuid3"/> </trigger> <trigger> <rsc_op id="37" operation="monitor" operation_key="child_rsc2:4_monitor_0" on_node="node3" on_node_uuid="uuid3"/> </trigger> </inputs> </synapse> </transition_graph> diff --git a/crm/pengine/utils.c b/crm/pengine/utils.c index a9c7164424..12ca0bb0bf 100644 --- a/crm/pengine/utils.c +++ b/crm/pengine/utils.c @@ -1,343 +1,346 @@ /* $Id: utils.c,v 1.147 2006/07/05 14:20:02 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net> * * 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 <crm/msg_xml.h> #include <allocate.h> #include <utils.h> #include <lib/crm/pengine/utils.h> 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->score > rsc_constraint2->score) { return 1; } if(rsc_constraint1->score < rsc_constraint2->score) { return -1; } return 0; } void print_rsc_to_node(const char *pre_text, rsc_to_node_t *cons, gboolean details) { if(cons == NULL) { crm_debug_4("%s%s: <NULL>", 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: <NULL>", 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, %d", safe_val3(NULL, cons, rsc_lh, id), safe_val3(NULL, cons, rsc_rh, id), cons->score); } } 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_to_node(GListPtr constraints) { GListPtr iterator = constraints; while(iterator != NULL) { rsc_to_node_t *cons = iterator->data; iterator = iterator->next; pe_free_shallow(cons->node_list_rh); crm_free(cons); } if(constraints != NULL) { g_list_free(constraints); } } 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 * ordering_type2text(enum pe_ordering type) { const char *result = "<unknown>"; 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; } gboolean can_run_resources(const node_t *node) { - if(node == NULL - || node->details->online == FALSE + if(node == NULL) { + crm_err("No node supplied"); + return FALSE; + + } else if(node->details->online == FALSE || node->details->shutdown || node->details->unclean || node->details->standby) { crm_debug_2("%s: online=%d, unclean=%d, standby=%d", node->details->uname, node->details->online, node->details->unclean, node->details->standby); return FALSE; } return TRUE; } /* 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(can_run_resources(node1) == FALSE) { node1_weight = -INFINITY; } if(can_run_resources(node2) == FALSE) { 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; } gboolean native_assign_node(resource_t *rsc, GListPtr nodes, node_t *chosen) { int multiple = 0; CRM_ASSERT(rsc->variant == pe_native); rsc->provisional = FALSE; if(chosen == NULL) { crm_debug("Could not allocate a node for %s", rsc->id); rsc->next_role = RSC_ROLE_STOPPED; return FALSE; } else if(can_run_resources(chosen) == FALSE) { crm_debug("All nodes for color %s are unavailable" ", unclean or shutting down", rsc->id); rsc->next_role = RSC_ROLE_STOPPED; return FALSE; } else if(chosen->weight < 0) { crm_debug("Even highest ranked node for %s, had weight %d", rsc->id, chosen->weight); rsc->next_role = RSC_ROLE_STOPPED; return FALSE; } if(rsc->next_role == RSC_ROLE_UNKNOWN) { rsc->next_role = RSC_ROLE_STARTED; } slist_iter(candidate, node_t, nodes, lpc, crm_debug("Color %s, Node[%d] %s: %d", rsc->id, lpc, candidate->details->uname, candidate->weight); if(chosen->weight > 0 && candidate->details->unclean == FALSE && candidate->weight == chosen->weight) { multiple++; } ); if(multiple > 1) { int log_level = LOG_INFO; char *score = score2char(chosen->weight); if(chosen->weight >= INFINITY) { log_level = LOG_WARNING; } do_crm_log(log_level, "%d nodes with equal score (%s) for" " running the listed resources (chose %s):", multiple, score, chosen->details->uname); crm_free(score); } /* todo: update the old node for each resource to reflect its * new resource count */ if(rsc->allocated_to) { node_t *old = rsc->allocated_to; old->details->allocated_rsc = g_list_remove( old->details->allocated_rsc, rsc); old->details->num_resources--; old->count--; } crm_debug("Assigning %s to %s", chosen->details->uname, rsc->id); crm_free(rsc->allocated_to); rsc->allocated_to = node_copy(chosen); chosen->details->allocated_rsc = g_list_append(chosen->details->allocated_rsc, rsc); chosen->details->num_resources++; chosen->count++; return TRUE; }