Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F3686988
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
76 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/crm/cib/cibio.h b/crm/cib/cibio.h
index 1171824857..74bc6152e5 100644
--- a/crm/cib/cibio.h
+++ b/crm/cib/cibio.h
@@ -1,60 +1,60 @@
-/* $Id: cibio.h,v 1.7 2004/03/22 14:20:49 andrew Exp $ */
+/* $Id: cibio.h,v 1.8 2004/06/02 16:03:34 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
*/
-#ifndef CRMIO_H
-#define CRMIO_H
+#ifndef CIB_IO__H
+#define CIB_IO__H
#include <portability.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <clplumbing/ipc.h>
#include <clplumbing/cl_log.h>
#include <libxml/tree.h>
extern gboolean initialized;
extern xmlNodePtr the_cib;
extern xmlNodePtr node_search;
extern xmlNodePtr resource_search;
extern xmlNodePtr constraint_search;
extern xmlNodePtr status_search;
extern xmlNodePtr get_the_CIB(void);
extern int initializeCib(xmlNodePtr cib);
extern gboolean uninitializeCib(void);
extern xmlNodePtr createEmptyCib(void);
extern gboolean verifyCibXml(xmlNodePtr cib);
extern xmlNodePtr readCibXml(char *buffer);
extern xmlNodePtr readCibXmlFile(const char *filename);
extern int activateCibBuffer(char *buffer, const char *filename);
extern int activateCibXml(xmlNodePtr doc, const char *filename);
extern int moveFile(const char *oldname,
const char *newname,
gboolean backup,
char *ext);
#endif
diff --git a/crm/cib/cibprimatives.h b/crm/cib/cibprimatives.h
index 0cf58fe191..4afcb00f75 100644
--- a/crm/cib/cibprimatives.h
+++ b/crm/cib/cibprimatives.h
@@ -1,81 +1,81 @@
-/* $Id: cibprimatives.h,v 1.8 2004/03/25 17:11:23 andrew Exp $ */
+/* $Id: cibprimatives.h,v 1.9 2004/06/02 16:03:34 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
*/
-#ifndef CRMINTERNAL_H
-#define CRMINTERNAL_H
+#ifndef CIB_PRIMATIVES__H
+#define CIB_PRIMATIVES__H
#include <portability.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <clplumbing/ipc.h>
#include <clplumbing/cl_log.h>
#include <libxml/tree.h>
#define IS_DAEMON
#define IPC_COMMS
typedef xmlNode cibStatus;
typedef xmlNode cibResource;
typedef xmlNode cibConstraint;
typedef xmlNode cibHaNode;
/* extern gboolean initialized; */
/* extern xmlNodePtr the_cib; */
/* extern xmlNodePtr node_search; */
/* extern xmlNodePtr resource_search; */
/* extern xmlNodePtr constraint_search; */
/* extern xmlNodePtr status_search; */
/* extern const char* crm_system_name; */
extern xmlNodePtr get_the_CIB(void);
extern int addResource (xmlNodePtr cib, xmlNodePtr anXmlNode);
extern int addConstraint(xmlNodePtr cib, xmlNodePtr anXmlNode);
extern int addHaNode (xmlNodePtr cib, xmlNodePtr anXmlNode);
extern int addStatus (xmlNodePtr cib, xmlNodePtr anXmlNode);
extern xmlNodePtr findResource (xmlNodePtr cib, const char *id);
extern xmlNodePtr findConstraint(xmlNodePtr cib, const char *id);
extern xmlNodePtr findHaNode (xmlNodePtr cib, const char *id);
extern xmlNodePtr findStatus (xmlNodePtr cib, const char *id);
extern int updateResource (xmlNodePtr cib, xmlNodePtr anXmlNode);
extern int updateConstraint(xmlNodePtr cib, xmlNodePtr anXmlNode);
extern int updateHaNode (xmlNodePtr cib, xmlNodePtr anXmlNode);
extern int updateStatus (xmlNodePtr cib, xmlNodePtr anXmlNode);
extern int delResource (xmlNodePtr cib, xmlNodePtr delete_spec);
extern int delConstraint(xmlNodePtr cib, xmlNodePtr delete_spec);
extern int delHaNode (xmlNodePtr cib, xmlNodePtr delete_spec);
extern int delStatus (xmlNodePtr cib, xmlNodePtr delete_spec);
extern int add_cib_object (xmlNodePtr parent, xmlNodePtr new_obj);
extern int delete_cib_object(xmlNodePtr parent, xmlNodePtr delete_spec);
extern int update_cib_object(xmlNodePtr parent, xmlNodePtr new_obj,
gboolean force);
#endif
diff --git a/crm/crmd/crmd_fsa.h b/crm/crmd/crmd_fsa.h
index 02b7b3a38b..b8236d2e75 100644
--- a/crm/crmd/crmd_fsa.h
+++ b/crm/crmd/crmd_fsa.h
@@ -1,125 +1,125 @@
-/* $Id: crmd_fsa.h,v 1.20 2004/06/01 12:25:15 andrew Exp $ */
+/* $Id: crmd_fsa.h,v 1.21 2004/06/02 16:03:34 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
*/
-#ifndef XML_CRM_FSA__H
-#define XML_CRM_FSA__H
+#ifndef CRMD_FSA__H
+#define CRMD_FSA__H
#include <fsa_defines.h>
#include <ocf/oc_event.h>
#include <clplumbing/ipc.h>
#include <hb_api.h>
#include <libxml/tree.h>
#include <lrm/lrm_api.h>
#include <crm/crm.h>
struct ccm_data
{
const oc_ev_membership_t *oc;
oc_ed_t *event;
};
struct oc_node_list_s
{
int members_size;
GHashTable *members; // contents: oc_node_t *
int new_members_size;
GHashTable *new_members; // contents: oc_node_t *
int dead_members_size;
GHashTable *dead_members; // contents: oc_node_t *
};
/* copy from struct client_child in heartbeat.h
*
* Plus a couple of other things
*/
typedef struct oc_node_list_s oc_node_list_t;
struct crm_subsystem_s {
pid_t pid; /* Process id of child process */
int respawn; /* Respawn it if it dies? */
int respawncount; /* Last time we respawned this command */
int shortrcount; /* How many times has it respawned too fast? */
const char* command; /* What command to run? */
const char* path; /* Path (argv[0])? */
/* extras */
const char* name;
IPC_Channel *ipc; /* How can we communicate with it */
long long flag; /* */
};
typedef struct fsa_timer_s fsa_timer_t;
struct fsa_timer_s
{
guint source_id; /* timer source id */
uint period_ms; /* timer period */
enum crmd_fsa_input fsa_input;
gboolean (*callback)(gpointer data);
};
extern enum crmd_fsa_state s_crmd_fsa(enum crmd_fsa_cause cause,
enum crmd_fsa_input initial_input,
void *data);
extern long long clear_flags(long long actions,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input cur_input);
extern gboolean do_dc_heartbeat(gpointer data);
/* Global FSA stuff */
extern enum crmd_fsa_state fsa_state;
extern oc_node_list_t *fsa_membership_copy;
extern ll_cluster_t *fsa_cluster_conn;
extern ll_lrm_t *fsa_lrm_conn;
extern long long fsa_input_register;
extern const char *fsa_our_uname;
extern char *fsa_pe_ref; // the last invocation of the PE
extern const char *fsa_our_dc;
extern fsa_timer_t *election_trigger; /* */
extern fsa_timer_t *election_timeout; /* */
extern fsa_timer_t *shutdown_escalation_timmer; /* */
extern fsa_timer_t *dc_heartbeat;
extern fsa_timer_t *integration_timer;
extern struct crm_subsystem_s *cib_subsystem;
extern struct crm_subsystem_s *te_subsystem;
extern struct crm_subsystem_s *pe_subsystem;
extern enum crmd_fsa_input send_cib_status_update(xmlNodePtr update);
extern xmlNodePtr do_update_cib_nodes(xmlNodePtr updates, gboolean overwrite);
extern enum crmd_fsa_input invoke_local_cib(xmlNodePtr msg_options,
xmlNodePtr msg_data,
const char *operation);
extern void CrmdClientStatus(const char * node, const char * client,
const char * status, void * private);
#define AM_I_DC is_set(fsa_input_register, R_THE_DC)
#define AM_I_OPERATIONAL (is_set(fsa_input_register, R_STARTING)==FALSE)
#include <fsa_proto.h>
#include <crmd_utils.h>
#endif
diff --git a/crm/crmd/fsa_defines.h b/crm/crmd/fsa_defines.h
index ab86071ed3..2ee79746be 100644
--- a/crm/crmd/fsa_defines.h
+++ b/crm/crmd/fsa_defines.h
@@ -1,495 +1,495 @@
-/* $Id: fsa_defines.h,v 1.15 2004/06/01 12:25:16 andrew Exp $ */
+/* $Id: fsa_defines.h,v 1.16 2004/06/02 16:03:34 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
*/
-#ifndef XML_FSA_DEFINES__H
-#define XML_FSA_DEFINES__H
+#ifndef FSA_DEFINES__H
+#define FSA_DEFINES__H
/*======================================
* States the DC/CRMd can be in
*======================================*/
enum crmd_fsa_state {
S_IDLE = 0, /* Nothing happening */
S_ELECTION, /* Take part in the election algorithm as
* described below
*/
S_INTEGRATION, /* integrate that status of new nodes (which is
* all of them if we have just been elected DC)
* to form a complete and up-to-date picture of
* the CIB
*/
S_NOT_DC, /* we are in crmd/slave mode */
S_POLICY_ENGINE,/* Determin the next stable state of the cluster
*/
S_RECOVERY, /* Something bad happened, check everything is ok
* before continuing and attempt to recover if
* required
*/
S_RECOVERY_DC, /* Something bad happened to the DC, check
* everything is ok before continuing and attempt
* to recover if required
*/
S_RELEASE_DC, /* we were the DC, but now we arent anymore,
* possibly by our own request, and we should
* release all unnecessary sub-systems, finish
* any pending actions, do general cleanup and
* unset anything that makes us think we are
* special :)
*/
S_PENDING, /* we are just starting out */
S_STOPPING, /* We are in the final stages of shutting down */
S_TERMINATE, /* We are going to shutdown, this is the equiv of
* "Sending TERM signal to all processes" in Linux
* and in worst case scenarios could be considered
* a self STONITH
*/
S_TRANSITION_ENGINE,/* Attempt to make the calculated next stable
* state of the cluster a reality
*/
/* ----------- Last input found in table is above ---------- */
S_ILLEGAL, /* This is an illegal FSA state */
/* (must be last) */
};
#define MAXSTATE S_ILLEGAL
/*
A state diagram can be constructed from the dc_fsa.dot with the
following command:
dot -Tpng crmd_fsa.dot > crmd_fsa.png
Description:
Once we start and do some basic sanity checks, we go into the
S_NOT_DC state and await instructions from the DC or input from
the CCM which indicates the election algorithm needs to run.
If the election algorithm is triggered we enter the S_ELECTION state
from where we can either go back to the S_NOT_DC state or progress
to the S_INTEGRATION state (or S_RELEASE_DC if we used to be the DC
but arent anymore).
The election algorithm has been adapted from
http://www.cs.indiana.edu/cgi-bin/techreports/TRNNN.cgi?trnum=TR521
Loosly known as the Bully Algorithm, its major points are:
- Election is initiated by any node (N) notices that the coordinator
is no longer responding
- Concurrent multiple elections are possible
- Algorithm
+ N sends ELECTION messages to all nodes that occur earlier in
the CCM's membership list.
+ If no one responds, N wins and becomes coordinator
+ N sends out COORDINATOR messages to all other nodes in the
partition
+ If one of higher-ups answers, it takes over. N is done.
Once the election is complete, if we are the DC, we enter the
S_INTEGRATION state which is a DC-in-waiting style state. We are
the DC, but we shouldnt do anything yet because we may not have an
up-to-date picture of the cluster. There may of course be times
when this fails, so we should go back to the S_RECOVERY stage and
check everything is ok. We may also end up here if a new node came
online, since each node is authorative on itself and we would want
to incorporate its information into the CIB.
Once we have the latest CIB, we then enter the S_POLICY_ENGINE state
where invoke the Policy Engine. It is possible that between
invoking the Policy Engine and recieving an answer, that we recieve
more input. In this case we would discard the orginal result and
invoke it again.
Once we are satisfied with the output from the Policy Engine we
enter S_TRANSITION_ENGINE and feed the Policy Engine's output to the
Transition Engine who attempts to make the Policy Engine's
calculation a reality. If the transition completes successfully,
we enter S_IDLE, otherwise we go back to S_POLICY_ENGINE with the
current unstable state and try again.
Of course we may be asked to shutdown at any time, however we must
progress to S_NOT_DC before doing so. Once we have handed over DC
duties to another node, we can then shut down like everyone else,
that is by asking the DC for permission and waiting it to take all
our resources away.
The case where we are the DC and the only node in the cluster is a
special case and handled as an escalation which takes us to
S_SHUTDOWN. Similarly if any other point in the shutdown
fails or stalls, this is escalated and we end up in S_TERMINATE.
At any point, the CRMd/DC can relay messages for its sub-systems,
but outbound messages (from sub-systems) should probably be blocked
until S_INTEGRATION (for the DC case) or the join protocol has
completed (for the CRMd case)
*/
/*======================================
*
* Inputs/Events/Stimuli to be given to the finite state machine
*
* Some of these a true events, and others a synthesised based on
* the "register" (see below) and the contents or source of messages.
*
* At this point, my plan is to have a loop of some sort that keeps
* going until recieving I_NULL
*
*======================================*/
enum crmd_fsa_input {
// 0
I_NULL, /* Nothing happened */
// 1
I_CCM_EVENT,
I_CIB_OP, /* An update to the CIB occurred */
I_CIB_UPDATE, /* An update to the CIB occurred */
I_DC_TIMEOUT, /* We have lost communication with the DC */
I_ELECTION, /* Someone started an election */
I_PE_CALC, /* The Policy Engine needs to be invoked */
I_RELEASE_DC, /* The election completed and we were not
* elected, but we were the DC beforehand
*/
I_ELECTION_DC, /* The election completed and we were (re-)elected
* DC
*/
I_ERROR, /* Something bad happened (more serious than
* I_FAIL) and may not have been due to the action
* being performed. For example, we may have lost
* our connection to the CIB.
*/
// 10
I_FAIL, /* The action failed to complete successfully */
I_INTEGRATION_TIMEOUT,
I_NODE_JOIN, /* A node has entered the CCM membership list*/
I_NODE_LEFT, /* A node shutdown (possibly unexpectedly) */
I_NOT_DC, /* We are not and were not the DC before or after
* the current operation or state
*/
I_RECOVERED, /* The recovery process completed successfully */
I_RELEASE_FAIL, /* We could not give up DC status for some reason
*/
I_RELEASE_SUCCESS, /* We are no longer the DC */
I_RESTART, /* The current set of actions needs to be
* restarted
*/
I_REQUEST, /* Some non-resource, non-ccm action is required
* of us, eg. ping
*/
// 20
I_ROUTER, /* Do our job as router and forward this to the
* right place
*/
I_SHUTDOWN, /* We are asking to shutdown */
I_TERMINATE, /* We have been told to shutdown */
I_STARTUP,
I_SUCCESS, /* The action completed successfully */
I_WELCOME, /* Welcome a newly joined node */
I_WELCOME_ACK, /* The newly joined node has acknowledged us as
overlord
*/
I_WAIT_FOR_EVENT, /* we may be waiting for an async task to "happen"
* and until it does, we cant do anything else
*/
I_DC_HEARTBEAT, /* The DC is telling us that it is alive and well */
I_LRM_EVENT,
/* ------------ Last input found in table is above ----------- */
I_ILLEGAL, /* This is an illegal value for an FSA input */
/* (must be last) */
};
#define MAXINPUT I_ILLEGAL
#define I_MESSAGE I_ROUTER
/*======================================
*
* actions
*
* Some of the actions below will always occur together for now, but I can
* forsee that this may not always be the case. So I've spilt them up so
* that if they ever do need to be called independantly in the future, it
* wont be a problem.
*
* For example, separating A_LRM_CONNECT from A_STARTUP might be useful
* if we ever try to recover from a faulty or disconnected LRM.
*
*======================================*/
/* Complete list of actions
A_CCM_CONNECT
A_CCM_EVENT
A_CCM_UPDATE_CACHE
A_CIB_INVOKE
A_CIB_RESTART
A_CIB_START
A_CIB_STOP
A_CIB_UPDATE
A_DC_RELEASE
A_DC_TAKEOVER
A_DISCONNECT
A_ELECTION_COUNT
A_ELECTION_TIMEOUT
A_ELECTION_VOTE
A_ERROR
A_EXIT_0
A_EXIT_1
A_HA_CONNECT
A_JOIN_ACK
A_JOIN_WELCOME
A_JOIN_WELCOME_ALL
A_LOG
A_LRM_CONNECT
A_MSG_PROCESS
A_MSG_ROUTE
A_MSG_STORE
A_NODE_BLOCK
A_NOTHING
A_PE_INVOKE
A_PE_RESTART
A_PE_START
A_PE_STOP
A_RECOVER
A_SHUTDOWN
A_STARTED
A_STARTUP
A_STOP
A_TERMINATE
A_TE_INVOKE
A_TE_RESTART
A_TE_START
A_TE_STOP
A_DC_TIMER_STOP
A_DC_TIMER_START
A_WARN
*/
/* Dont do anything */
#define A_NOTHING 0x0000000000000000ULL
/* -- Startup actions -- */
/* Hook to perform any actions (other than starting the CIB,
* connecting to HA or the CCM) that might be needed as part
* of the startup.
*/
#define A_STARTUP 0x0000000000000001ULL
/* Hook to perform any actions that might be needed as part
* after startup is successful.
*/
#define A_STARTED 0x0000000000000002ULL
/* Connect to Heartbeat */
#define A_HA_CONNECT 0x0000000000000004ULL
#define A_HA_DISCONNECT 0x0000000000000008ULL
/* -- Election actions -- */
#define A_DC_TIMER_START 0x0000000000000010ULL
#define A_DC_TIMER_STOP 0x0000000000000020ULL
#define A_ELECT_TIMER_START 0x0000000000000040ULL
#define A_ELECT_TIMER_STOP 0x0000000000000080ULL
#define A_ELECTION_COUNT 0x0000000000000100ULL
#define A_ELECTION_TIMEOUT 0x0000000000000200ULL
#define A_ELECTION_VOTE 0x0000000000000400ULL
/* -- Join protocol actions -- */
#define A_ANNOUNCE 0x0000000000000800ULL
/* Acknowledge the DC as our overlord*/
#define A_JOIN_ACK 0x0000000000001000ULL
/* Send a welcome message to new node(s) */
#define A_JOIN_WELCOME 0x0000000000002000ULL
/* Send a welcome message to all nodes */
#define A_JOIN_WELCOME_ALL 0x0000000000004000ULL
/* Process the remote node's ack of our join message */
#define A_JOIN_PROCESS_ACK 0x0000000000008000ULL
/* -- Message processing -- */
/* Process the queue of requests */
#define A_MSG_PROCESS 0x0000000000010000ULL
/* Send the message to the correct recipient */
#define A_MSG_ROUTE 0x0000000000020000ULL
/* Put the request into a queue for processing. We do this every
* time so that the processing is consistent. The intent is to
* allow the DC to keep doing important work while still not
* loosing requests.
* Messages are not considered recieved until processed.
*/
#define A_MSG_STORE 0x0000000000040000ULL
/* -- Recovery, DC start/stop -- */
/* Something bad happened, try to recover */
#define A_RECOVER 0x0000000001000000ULL
/* Hook to perform any actions (apart from starting, the TE, PE
* and gathering the latest CIB) that might be necessary before
* giving up the responsibilities of being the DC.
*/
#define A_DC_RELEASE 0x0000000002000000ULL
/* */
#define A_DC_RELEASED 0x0000000004000000ULL
/* Hook to perform any actions (apart from starting, the TE, PE
* and gathering the latest CIB) that might be necessary before
* taking over the responsibilities of being the DC.
*/
#define A_DC_TAKEOVER 0x0000000008000000ULL
/* -- Shutdown actions -- */
#define A_SHUTDOWN 0x0000000010000000ULL
#define A_STOP 0x0000000020000000ULL
#define A_EXIT_0 0x0000000040000000ULL
#define A_EXIT_1 0x0000000080000000ULL
#define A_SHUTDOWN_REQ 0x0000000100000000ULL
/* -- CCM actions -- */
#define A_CCM_CONNECT 0x0000001000000000ULL
#define A_CCM_DISCONNECT 0x0000002000000000ULL
/* Process whatever it is the CCM is trying to tell us.
* This will generate inputs such as I_NODE_JOIN,
* I_NODE_LEAVE, I_SHUTDOWN, I_DC_RELEASE, I_DC_TAKEOVER
*/
#define A_CCM_EVENT 0x0000004000000000ULL
#define A_CCM_UPDATE_CACHE 0x0000008000000000ULL
/* -- CBI actions -- */
#define A_CIB_INVOKE 0x0000010000000000ULL
#define A_CIB_START 0x0000020000000000ULL
#define A_CIB_STOP 0x0000040000000000ULL
#define A_CIB_INVOKE_LOCAL 0x0000080000000000ULL
/* -- Transition Engine actions -- */
/* Attempt to reach the newly calculated cluster state. This is
* only called once per transition (except if it is asked to
* stop the transition or start a new one).
* Once given a cluster state to reach, the TE will determin
* tasks that can be performed in parallel, execute them, wait
* for replies and then determin the next set until the new
* state is reached or no further tasks can be taken.
*/
#define A_TE_INVOKE 0x0000100000000000ULL
#define A_TE_START 0x0000200000000000ULL
#define A_TE_STOP 0x0000400000000000ULL
#define A_TE_CANCEL 0x0000800000000000ULL
#define A_TE_COPYTO 0x0001000000000000ULL
/* -- Policy Engine actions -- */
/* Calculate the next state for the cluster. This is only
* invoked once per needed calculation.
*/
#define A_PE_INVOKE 0x0002000000000000ULL
#define A_PE_START 0x0004000000000000ULL
#define A_PE_STOP 0x0008000000000000ULL
/* -- Misc actions -- */
/* Add a system generate "block" so that resources arent moved
* to or are activly moved away from the affected node. This
* way we can return quickly even if busy with other things.
*/
#define A_NODE_BLOCK 0x0010000000000000ULL
/* Update our information in the local CIB */
#define A_UPDATE_NODESTATUS 0x0020000000000000ULL
#define A_CIB_BUMPGEN 0x0040000000000000ULL
/* -- LRM Actions -- */
/* Connect to the Local Resource Manager */
#define A_LRM_CONNECT 0x0100000000000000ULL
/* Disconnect from the Local Resource Manager */
#define A_LRM_DISCONNECT 0x0200000000000000ULL
#define A_LRM_INVOKE 0x0400000000000000ULL
#define A_LRM_EVENT 0x0800000000000000ULL
/* -- Logging actions -- */
#define A_LOG 0x1000000000000000ULL
#define A_ERROR 0x2000000000000000ULL
#define A_WARN 0x4000000000000000ULL
#define O_SHUTDOWN (A_CCM_DISCONNECT|A_LRM_DISCONNECT|A_HA_DISCONNECT|A_SHUTDOWN|A_STOP|A_EXIT_0|A_CIB_STOP)
#define O_RELEASE (A_DC_TIMER_STOP|A_DC_RELEASE|A_PE_STOP|A_TE_STOP|A_DC_RELEASED)
#define O_DC_TIMER_RESTART (A_DC_TIMER_STOP|A_DC_TIMER_START)
#define O_PE_RESTART (A_PE_START|A_PE_STOP)
#define O_TE_RESTART (A_TE_START|A_TE_STOP)
#define O_CIB_RESTART (A_CIB_START|A_CIB_STOP)
#define O_DC_TICKLE O_DC_TIMER_RESTART
/*======================================
*
* "register" contents
*
* Things we may want to remember regardless of which state we are in.
*
* These also count as inputs for synthesizing I_*
*
*======================================*/
#define R_THE_DC 0x00000001 /* Are we the DC? */
#define R_STARTING 0x00000002 /* Are we starting up? */
#define R_SHUTDOWN 0x00000004 /* Are we trying to shut down? */
#define R_CIB_DONE 0x00000008 /* Have we calculated the CIB? */
#define R_JOIN_OK 0x00000010 /* Have we completed the join process */
#define R_HAVE_CIB 0x00000020 /* Do we have an up-to-date CIB */
#define R_HAVE_RES 0x00000040 /* Do we have any resources running
locally */
#define R_INVOKE_PE 0x00000080 /* Does the PE needed to be invoked at
the next appropriate point? */
#define R_CIB_CONNECTED 0x00000100 /* Is the CIB connected? */
#define R_PE_CONNECTED 0x00000200 /* Is the Policy Engine connected? */
#define R_TE_CONNECTED 0x00000400 /* Is the Transition Engine connected? */
#define R_LRM_CONNECTED 0x00000800 /* Is the Local Resource Manager
connected? */
#define R_REQ_PEND 0x00001000 /* Are there Requests waiting for
processing? */
#define R_PE_PEND 0x00002000 /* Has the PE been invoked and we're
awaiting a reply? */
#define R_TE_PEND 0x00004000 /* Has the TE been invoked and we're
awaiting completion? */
#define R_RESP_PEND 0x00008000 /* Do we have clients waiting on a
response? if so perhaps we shouldnt
stop yet */
enum crmd_fsa_cause
{
C_UNKNOWN = 0,
C_STARTUP,
C_IPC_MESSAGE,
C_HA_MESSAGE,
C_CCM_CALLBACK,
C_CRMD_STATUS_CALLBACK,
C_LRM_OP_CALLBACK,
C_LRM_MONITOR_CALLBACK,
C_TIMER_POPPED,
C_SHUTDOWN,
C_HEARTBEAT_FAILED,
C_SUBSYSTEM_CONNECT,
C_ILLEGAL
};
extern const char *fsa_input2string(enum crmd_fsa_input input);
extern const char *fsa_state2string(enum crmd_fsa_state state);
extern const char *fsa_cause2string(enum crmd_fsa_cause cause);
extern const char *fsa_action2string(long long action);
#endif
diff --git a/crm/crmd/subsystems.c b/crm/crmd/subsystems.c
index ef4af90878..1430d6dfb4 100644
--- a/crm/crmd/subsystems.c
+++ b/crm/crmd/subsystems.c
@@ -1,628 +1,628 @@
/*
* 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/crm.h>
#include <crmd_fsa.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h> // for access
#include <clplumbing/cl_signal.h>
#include <clplumbing/realtime.h>
#include <sys/types.h> // for calls to open
#include <sys/stat.h> // for calls to open
#include <fcntl.h> // for calls to open
#include <pwd.h> // for getpwuid
#include <grp.h> // for initgroups
#include <sys/time.h> // for getrlimit
#include <sys/resource.h>// for getrlimit
#include <errno.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crmd_messages.h>
#include <crm/cib.h>
#include <crmd.h>
#include <crm/dmalloc_wrapper.h>
#define CLIENT_EXIT_WAIT 10
static gboolean stop_subsystem (struct crm_subsystem_s *centry);
static gboolean start_subsystem(struct crm_subsystem_s *centry);
struct crm_subsystem_s *cib_subsystem = NULL;
struct crm_subsystem_s *te_subsystem = NULL;
struct crm_subsystem_s *pe_subsystem = NULL;
/* A_CIB_STOP, A_CIB_START, A_CIB_RESTART, */
enum crmd_fsa_input
do_cib_control(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
enum crmd_fsa_input result = I_NULL;
struct crm_subsystem_s *this_subsys = cib_subsystem;
long long stop_actions = A_CIB_STOP;
long long start_actions = A_CIB_START;
FNIN();
if(action & stop_actions) {
// dont do anything, its embedded now
}
if(action & start_actions) {
if(cur_state != S_STOPPING) {
if(startCib(CIB_FILENAME) == FALSE)
result = I_FAIL;
} else {
crm_info("Ignoring request to start %s after shutdown",
this_subsys->command);
}
}
FNRET(result);
}
/* A_CIB_INVOKE, A_CIB_BUMPGEN, A_UPDATE_NODESTATUS */
enum crmd_fsa_input
do_cib_invoke(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
xmlNodePtr cib_msg = NULL;
xmlNodePtr answer = NULL;
xmlNodePtr new_options = NULL;
const char *section = NULL;
FNIN();
if(data != NULL) {
cib_msg = (xmlNodePtr)data;
}
if(action & A_CIB_INVOKE) {
const char *op = get_xml_attr(cib_msg, XML_TAG_OPTIONS,
XML_ATTR_OP, TRUE);
xml_message_debug(cib_msg, "[CIB] Invoking with");
if(cib_msg == NULL) {
crm_err("No message for CIB command");
FNRET(I_NULL); // I_ERROR
}
set_xml_property_copy(cib_msg, XML_ATTR_SYSTO, "cib");
answer = process_cib_message(cib_msg, TRUE);
if(relay_message(answer, TRUE) == FALSE) {
crm_err("Confused what to do with cib result");
xml_message_debug(answer, "Couldnt route: ");
}
if(op != NULL && AM_I_DC
&& (strcmp(op, CRM_OP_CREATE) == 0
|| strcmp(op, CRM_OP_UPDATE) == 0
|| strcmp(op, CRM_OP_DELETE) == 0
|| strcmp(op, CRM_OP_REPLACE) == 0
|| strcmp(op, CRM_OP_WELCOME) == 0
|| strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0
|| strcmp(op, CRM_OP_ERASE) == 0)) {
FNRET(I_CIB_UPDATE);
}
if(op == NULL) {
xml_message_debug(cib_msg, "Invalid CIB Message");
}
// check the answer, see if we are interested in it also
#if 0
if(interested in reply) {
put_message(answer);
FNRET(I_REQUEST);
}
#endif
free_xml(answer);
/* experimental */
} else if(action & A_CIB_INVOKE_LOCAL) {
xml_message_debug(cib_msg, "[CIB] Invoking with");
if(cib_msg == NULL) {
crm_err("No message for CIB command");
FNRET(I_NULL); // I_ERROR
}
answer = process_cib_message(cib_msg, TRUE);
put_message(answer);
FNRET(I_REQUEST);
} else if(action & A_CIB_BUMPGEN) {
// check if the response was ok before next bit
section = get_xml_attr(cib_msg, XML_TAG_OPTIONS,
XML_ATTR_FILTER_TYPE, FALSE);
/* set the section so that we dont always send the
* whole thing
*/
if(section != NULL) {
new_options = set_xml_attr(NULL, XML_TAG_OPTIONS,
XML_ATTR_FILTER_TYPE,
section, TRUE);
}
answer = process_cib_request(CRM_OP_BUMP,
new_options, NULL);
free_xml(new_options);
if(answer == NULL) {
crm_err("Result of BUMP in %s was NULL",
__FUNCTION__);
FNRET(I_FAIL);
}
send_request(NULL, answer, CRM_OP_REPLACE,
NULL, CRM_SYSTEM_CRMD, NULL);
free_xml(answer);
} else {
crm_err("Unexpected action %s in %s",
fsa_action2string(action), __FUNCTION__);
}
FNRET(I_NULL);
}
/* A_PE_START, A_PE_STOP, A_TE_RESTART */
enum crmd_fsa_input
do_pe_control(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
enum crmd_fsa_input result = I_NULL;
struct crm_subsystem_s *this_subsys = pe_subsystem;
long long stop_actions = A_PE_STOP;
long long start_actions = A_PE_START;
FNIN();
if(action & stop_actions) {
if(stop_subsystem(this_subsys) == FALSE)
result = I_FAIL;
else if(this_subsys->pid > 0){
int lpc = CLIENT_EXIT_WAIT;
int pid_status = -1;
while(lpc-- > 0
&& this_subsys->pid > 0
&& CL_PID_EXISTS(this_subsys->pid)) {
sleep(1);
waitpid(this_subsys->pid, &pid_status, WNOHANG);
}
if(CL_PID_EXISTS(this_subsys->pid)) {
crm_err("Process %s is still active with pid=%d",
this_subsys->command, this_subsys->pid);
result = I_FAIL;
}
}
cleanup_subsystem(this_subsys);
}
if(action & start_actions) {
if(cur_state != S_STOPPING) {
if(start_subsystem(this_subsys) == FALSE) {
result = I_FAIL;
cleanup_subsystem(this_subsys);
}
} else {
crm_info("Ignoring request to start %s while shutting down",
this_subsys->command);
}
}
FNRET(result);
}
char *fsa_pe_ref = NULL;
/* A_PE_INVOKE */
enum crmd_fsa_input
do_pe_invoke(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
FNIN();
stopTimer(integration_timer);
if(is_set(fsa_input_register, R_PE_CONNECTED) == FALSE){
crm_info("Waiting for the PE to connect");
FNRET(I_WAIT_FOR_EVENT);
}
xmlNodePtr local_cib = get_cib_copy();
crm_verbose("Invoking %s with %p", CRM_SYSTEM_PENGINE, local_cib);
if(fsa_pe_ref) {
crm_free(fsa_pe_ref);
fsa_pe_ref = NULL;
}
send_request(NULL, local_cib, CRM_OP_PECALC,
NULL, CRM_SYSTEM_PENGINE, &fsa_pe_ref);
FNRET(I_NULL);
}
/* A_TE_START, A_TE_STOP, A_TE_RESTART */
enum crmd_fsa_input
do_te_control(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
enum crmd_fsa_input result = I_NULL;
struct crm_subsystem_s *this_subsys = te_subsystem;
long long stop_actions = A_TE_STOP;
long long start_actions = A_TE_START;
FNIN();
/* if(action & stop_actions && cur_state != S_STOPPING */
/* && is_set(fsa_input_register, R_TE_PEND)) { */
/* result = I_WAIT_FOR_EVENT; */
/* FNRET(result); */
/* } */
if(action & stop_actions) {
if(stop_subsystem(this_subsys) == FALSE)
result = I_FAIL;
else if(this_subsys->pid > 0){
int lpc = CLIENT_EXIT_WAIT;
int pid_status = -1;
while(lpc-- > 0
&& this_subsys->pid > 0
&& CL_PID_EXISTS(this_subsys->pid)) {
sleep(1);
waitpid(this_subsys->pid, &pid_status, WNOHANG);
}
if(CL_PID_EXISTS(this_subsys->pid)) {
crm_err("Process %s is still active with pid=%d",
this_subsys->command, this_subsys->pid);
result = I_FAIL;
}
}
cleanup_subsystem(this_subsys);
}
if(action & start_actions) {
if(cur_state != S_STOPPING) {
if(start_subsystem(this_subsys) == FALSE) {
result = I_FAIL;
cleanup_subsystem(this_subsys);
}
} else {
crm_info("Ignoring request to start %s while shutting down",
this_subsys->command);
}
}
FNRET(result);
}
static xmlNodePtr te_last_input = NULL;
static xmlNodePtr te_lastcc = NULL;
/* A_TE_COPYTO */
enum crmd_fsa_input
do_te_copyto(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
xmlNodePtr message = NULL;
xmlNodePtr opts = NULL;
const char *true_op = NULL;
FNIN();
if(data != NULL) {
message = copy_xml_node_recursive((xmlNodePtr)data);
opts = find_xml_node(message, XML_TAG_OPTIONS);
true_op = xmlGetProp(opts, XML_ATTR_OP);
set_xml_property_copy(opts, XML_ATTR_OP, CRM_OP_EVENTCC);
set_xml_property_copy(opts, XML_ATTR_TRUEOP, true_op);
set_xml_property_copy(message,
XML_ATTR_SYSTO,
CRM_SYSTEM_TENGINE);
}
if(is_set(fsa_input_register, R_TE_CONNECTED) == FALSE){
crm_info("Waiting for the TE to connect");
if(data != NULL) {
free_xml(te_lastcc);
te_lastcc = message;
}
FNRET(I_WAIT_FOR_EVENT);
}
if(message == NULL) {
message = te_lastcc;
te_lastcc = NULL;
} else {
free_xml(te_lastcc);
}
relay_message(message, FALSE);
// only free it if it was a local copy
if(data == NULL) {
free_xml(message);
}
FNRET(I_NULL);
}
/* A_TE_INVOKE, A_TE_CANCEL */
enum crmd_fsa_input
do_te_invoke(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
void *data)
{
xmlNodePtr graph = NULL;
xmlNodePtr msg = (xmlNodePtr)data;
FNIN();
if(is_set(fsa_input_register, R_TE_CONNECTED) == FALSE){
crm_info("Waiting for the TE to connect");
if(data != NULL) {
free_xml(te_last_input);
te_last_input = copy_xml_node_recursive(msg);
}
FNRET(I_WAIT_FOR_EVENT);
}
if(msg == NULL) {
msg = te_last_input;
te_last_input = NULL;
} else {
free_xml(te_last_input);
}
if(action & A_TE_INVOKE) {
graph = find_xml_node(msg, "transition_graph");
if(graph == NULL) {
FNRET(I_FAIL);
}
send_request(NULL, graph, CRM_OP_TRANSITION,
NULL, CRM_SYSTEM_TENGINE, NULL);
} else {
send_request(NULL, graph, CRM_OP_ABORT,
NULL, CRM_SYSTEM_TENGINE, NULL);
}
// only free it if it was a local copy
if(data == NULL) {
free_xml(msg);
}
FNRET(I_NULL);
}
gboolean
crmd_client_connect(IPC_Channel *client_channel, gpointer user_data)
{
FNIN();
if (client_channel == NULL) {
crm_err("Channel was NULL");
} else if (client_channel->ch_status == IPC_DISCONNECT) {
crm_err("Channel was disconnected");
} else {
crmd_client_t *blank_client =
(crmd_client_t *)crm_malloc(sizeof(crmd_client_t));
if (blank_client == NULL) {
crm_err("Could not allocate memory for a blank crmd_client_t");
FNRET(FALSE);
}
client_channel->ops->set_recv_qlen(client_channel, 100);
client_channel->ops->set_send_qlen(client_channel, 100);
blank_client->client_channel = client_channel;
blank_client->sub_sys = NULL;
- blank_client->uuid = NULL;
+ blank_client->uuid = NULL;
blank_client->table_key = NULL;
blank_client->client_source =
G_main_add_IPC_Channel(G_PRIORITY_LOW,
client_channel,
FALSE,
crmd_ipc_input_callback,
blank_client,
default_ipc_input_destroy);
}
FNRET(TRUE);
}
static gboolean
stop_subsystem(struct crm_subsystem_s* centry)
{
crm_info("Stopping sub-system \"%s\"", centry->name);
if (centry->pid <= 0) {
crm_err("OOPS! client %s not running yet",
centry->command);
} else {
crm_info("Sending quit message to %s.", centry->name);
send_request(NULL, NULL, CRM_OP_QUIT, NULL, centry->name, NULL);
}
return TRUE;
}
static gboolean
start_subsystem(struct crm_subsystem_s* centry)
{
pid_t pid;
struct stat buf;
int s_res;
crm_info("Starting sub-system \"%s\"", centry->command);
if (centry->pid != 0) {
crm_err("OOPS! client %s already running as pid %d"
, centry->command, (int) centry->pid);
}
/*
* We need to ensure that the exec will succeed before
* we bother forking. We don't want to respawn something that
* won't exec in the first place.
*/
if (access(centry->path, F_OK|X_OK) != 0) {
cl_perror("Cannot (access) exec %s", centry->path);
return FALSE;
}
s_res = stat(centry->command, &buf);
if(s_res != 0) {
cl_perror("Cannot (stat) exec %s", centry->command);
return FALSE;
}
/* We need to fork so we can make child procs not real time */
switch(pid=fork()) {
case -1:
crm_err("start_a_child_client: Cannot fork.");
return FALSE;
default: /* Parent */
centry->pid = pid;
return TRUE;
case 0: /* Child */
break;
}
/* Child process: start the managed child */
cl_make_normaltime();
setpgid(0,0);
/* Limit peak resource usage, maximize success chances */
if (centry->shortrcount > 0) {
alarm(0);
sleep(1);
}
crm_info("Executing \"%s\" (pid %d)",
centry->command, (int) getpid());
if(CL_SIGINTERRUPT(SIGALRM, 0) < 0) {
cl_perror("Cannot set interrupt for child process %s",
centry->command);
}else{
const char * devnull = "/dev/null";
unsigned int j;
struct rlimit oflimits;
CL_SIGNAL(SIGCHLD, SIG_DFL);
alarm(0);
CL_IGNORE_SIG(SIGALRM);
/* A precautionary measure */
getrlimit(RLIMIT_NOFILE, &oflimits);
for (j=0; j < oflimits.rlim_cur; ++j) {
close(j);
}
(void)devnull;
(void)open(devnull, O_RDONLY); /* Stdin: fd 0 */
(void)open(devnull, O_WRONLY); /* Stdout: fd 1 */
(void)open(devnull, O_WRONLY); /* Stderr: fd 2 */
(void)execl("/bin/sh", "sh", "-c", centry->command, (const char *)NULL);
/* Should not happen */
cl_perror("Cannot exec %s", centry->command);
}
/* Suppress respawning */
exit(100);
// never reached
return TRUE;
}
diff --git a/crm/pengine/pe_utils.h b/crm/pengine/pe_utils.h
index 3c59b1cea4..e27b0038b7 100644
--- a/crm/pengine/pe_utils.h
+++ b/crm/pengine/pe_utils.h
@@ -1,92 +1,110 @@
+/* $Id: pe_utils.h,v 1.4 2004/06/02 16:03:34 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
+ */
#ifndef PE_UTILS__H
#define PE_UTILS__H
// General utilities
extern resource_t *pe_find_resource(GSListPtr rsc_list, const char *id_rh);
extern action_t *action_new(int id, resource_t *rsc, enum action_tasks task);
// Constraint helper functions
extern rsc_to_rsc_t *invert_constraint(rsc_to_rsc_t *constraint);
extern rsc_to_node_t *copy_constraint(rsc_to_node_t *constraint);
// Color helper functions
extern void add_color_to_rsc(resource_t *rsc, color_t *color);
extern color_t *find_color(GSListPtr candidate_colors, color_t *other_color);
extern color_t *create_color(GSListPtr *colors,
GSListPtr nodes,
GSListPtr resources);
// Node helper functions
extern gboolean filter_nodes(resource_t *rsc);
extern node_t *pe_find_node(GSListPtr node_list, const char *id);
extern node_t *node_copy(node_t *this_node) ;
extern node_t *find_list_node(GSListPtr list, const char *id);
// Binary like operators for lists of nodes
extern GSListPtr node_list_dup(GSListPtr list1);
extern GSListPtr node_list_and(GSListPtr list1, GSListPtr list2);
extern GSListPtr node_list_xor(GSListPtr list1, GSListPtr list2);
extern GSListPtr node_list_minus(GSListPtr list1, GSListPtr list2);
extern gboolean node_list_eq(GSListPtr list1, GSListPtr list2);
// For creating the transition graph
extern xmlNodePtr action2xml(action_t *action);
// Printing functions for debug
extern void print_node(const char *pre_text,
node_t *node,
gboolean details);
extern void print_resource(const char *pre_text,
resource_t *rsc,
gboolean details);
extern void print_rsc_to_node(const char *pre_text,
rsc_to_node_t *cons,
gboolean details);
extern void print_rsc_to_rsc(const char *pre_text,
rsc_to_rsc_t *cons,
gboolean details);
extern void print_color(const char *pre_text,
color_t *color,
gboolean details);
extern void print_color_details(const char *pre_text,
struct color_shared_s *color,
gboolean details);
extern void print_action(const char *pre_text,
action_t *action,
gboolean details);
// Sorting functions
extern gint sort_rsc_priority(gconstpointer a, gconstpointer b);
extern gint sort_cons_strength(gconstpointer a, gconstpointer b);
extern gint sort_color_weight(gconstpointer a, gconstpointer b);
extern gint sort_node_weight(gconstpointer a, gconstpointer b);
// enum 2 text functions (mostly used by print_*)
extern const char *contype2text(enum con_type type);
extern const char *strength2text(enum con_strength strength);
extern const char *modifier2text(enum con_modifier modifier);
extern const char *task2text(enum action_tasks task);
#endif
diff --git a/crm/pengine/pengine.h b/crm/pengine/pengine.h
index 98e959f67b..7f40cecfaf 100644
--- a/crm/pengine/pengine.h
+++ b/crm/pengine/pengine.h
@@ -1,229 +1,247 @@
+/* $Id: pengine.h,v 1.19 2004/06/02 16:03:34 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
+ */
#ifndef PENGINE__H
#define PENGINE__H
#include <clplumbing/ipc.h>
typedef struct node_s node_t;
typedef struct color_s color_t;
typedef struct rsc_to_node_s rsc_to_node_t;
typedef struct rsc_to_rsc_s rsc_to_rsc_t;
typedef struct resource_s resource_t;
typedef struct order_constraint_s order_constraint_t;
typedef struct action_s action_t;
typedef struct action_wrapper_s action_wrapper_t;
enum con_type {
type_none,
rsc_to_rsc,
rsc_to_node,
rsc_to_attr,
base_weight
};
enum node_type {
node_ping,
node_member
};
enum con_strength {
ignore,
must,
should,
should_not,
must_not,
startstop
};
enum con_modifier {
modifier_none,
set,
inc,
dec
};
enum action_tasks {
no_action,
stop_rsc,
start_rsc,
shutdown_crm,
stonith_op
};
enum action_order {
dontcare,
before,
after
};
struct node_shared_s {
char *id;
gboolean online;
gboolean unclean;
gboolean shutdown;
GSListPtr running_rsc; // resource_t*
GHashTable *attrs; // char* => char*
enum node_type type;
};
struct node_s {
float weight;
gboolean fixed;
struct node_shared_s *details;
};
struct color_shared_s {
int id;
GSListPtr candidate_nodes; // node_t*
node_t *chosen_node;
};
struct color_s {
int id;
struct color_shared_s *details;
float local_weight;
};
struct rsc_to_rsc_s {
char *id;
resource_t *rsc_lh;
// gboolean is_placement;
resource_t *rsc_rh;
enum con_strength strength;
};
struct rsc_to_node_s {
char *id;
resource_t *rsc_lh;
float weight;
GSListPtr node_list_rh; // node_t*
enum con_modifier modifier;
};
struct resource_s {
char *id;
xmlNodePtr xml;
int priority;
node_t *cur_node;
gboolean runnable;
gboolean provisional;
action_t *stop;
action_t *start;
GSListPtr candidate_colors; // color_t*
GSListPtr allowed_nodes; // node_t*
GSListPtr node_cons; // rsc_to_node_t*
GSListPtr rsc_cons; // resource_t*
color_t *color;
};
struct action_wrapper_s
{
enum con_strength strength;
action_t *action;
};
struct action_s
{
int id;
resource_t *rsc;
node_t *node;
enum action_tasks task;
gboolean runnable;
gboolean processed;
gboolean optional;
gboolean discard;
gboolean failure_is_fatal;
int seen_count;
GSListPtr actions_before; // action_warpper_t*
GSListPtr actions_after; // action_warpper_t*
};
struct order_constraint_s
{
int id;
action_t *lh_action;
action_t *rh_action;
enum con_strength strength;
// enum action_order order;
};
extern gboolean stage0(xmlNodePtr cib,
GSListPtr *nodes,
GSListPtr *rscs,
GSListPtr *cons,
GSListPtr *actions, GSListPtr *action_constraints,
GSListPtr *stonith_list, GSListPtr *shutdown_list);
extern gboolean stage1(GSListPtr node_constraints,
GSListPtr nodes,
GSListPtr resources);
extern gboolean stage2(GSListPtr sorted_rscs,
GSListPtr sorted_nodes,
GSListPtr *colors);
extern gboolean stage3(GSListPtr colors);
extern gboolean stage4(GSListPtr colors);
extern gboolean stage5(GSListPtr resources);
extern gboolean stage6(GSListPtr *actions,
GSListPtr *action_constraints,
GSListPtr stonith,
GSListPtr shutdown);
extern gboolean stage7(GSListPtr resources,
GSListPtr actions,
GSListPtr action_constraints,
GSListPtr *action_sets);
extern gboolean stage8(GSListPtr action_sets, xmlNodePtr *graph);
extern gboolean summary(GSListPtr resources);
extern gboolean pe_input_dispatch(IPC_Channel *sender, void *user_data);
extern void pe_free_nodes(GSListPtr nodes);
extern void pe_free_colors(GSListPtr colors);
extern void pe_free_rsc_to_rsc(rsc_to_rsc_t *cons);
extern void pe_free_rsc_to_node(rsc_to_node_t *cons);
extern void pe_free_shallow(GSListPtr alist);
extern void pe_free_shallow_adv(GSListPtr alist, gboolean with_data);
extern void pe_free_resources(GSListPtr resources);
extern void pe_free_actions(GSListPtr actions);
extern gboolean pe_debug;
extern gboolean pe_debug_saved;
extern color_t *no_color;
#define pdebug_action(x) if(pe_debug) { \
x; \
}
#define pdebug(x...) if(pe_debug) { \
cl_log(LOG_DEBUG, x); \
}
#define pe_debug_on() pe_debug_saved = pe_debug; pe_debug = TRUE;
#define pe_debug_off() pe_debug_saved = pe_debug; pe_debug = FALSE;
#define pe_debug_restore() pe_debug = pe_debug_saved;
#define safe_val(def, x,y) (x?x->y:def)
#define safe_val3(def, t,u,v) (t?t->u?t->u->v:def:def)
#define safe_val4(def, t,u,v,w) (t?t->u?t->u->v?t->u->v->w:def:def:def)
#define safe_val5(def, t,u,v,w,x) (t?t->u?t->u->v?t->u->v->w?t->u->v->w->x:def:def:def:def)
#define safe_val6(def, t,u,v,w,x,y) (t?t->u?t->u->v?t->u->v->w?t->u->v->w->x?t->u->v->w->x->y:def:def:def:def:def)
#define safe_val7(def, t,u,v,w,x,y,z) (t?t->u?t->u->v?t->u->v->w?t->u->v->w->x?t->u->v->w->x->y?t->u->v->w->x->y->z:def:def:def:def:def:def)
#endif
diff --git a/crm/pengine/utils.c b/crm/pengine/utils.c
index a1b8732fb6..bd9d7de0e8 100644
--- a/crm/pengine/utils.c
+++ b/crm/pengine/utils.c
@@ -1,998 +1,1016 @@
+/* $Id: utils.c,v 1.22 2004/06/02 16:03:34 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/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/util.h>
#include <glib.h>
#include <pengine.h>
#include <pe_utils.h>
void print_str_str(gpointer key, gpointer value, gpointer user_data);
/* only for rsc_to_rsc constraints */
rsc_to_rsc_t *
invert_constraint(rsc_to_rsc_t *constraint)
{
crm_verbose("Inverting constraint");
rsc_to_rsc_t *inverted_con =
crm_malloc(sizeof(rsc_to_node_t));
inverted_con->id = crm_strdup(constraint->id);
inverted_con->strength = constraint->strength;
// swap the direction
inverted_con->rsc_lh = constraint->rsc_rh;
inverted_con->rsc_rh = constraint->rsc_lh;
crm_debug_action(
print_rsc_to_rsc("Inverted constraint", inverted_con, FALSE)
);
return inverted_con;
}
rsc_to_node_t *
copy_constraint(rsc_to_node_t *constraint)
{
rsc_to_node_t *copied_con = crm_malloc(sizeof(rsc_to_node_t));
copied_con->id = crm_strdup(constraint->id);
copied_con->rsc_lh = constraint->rsc_lh;
copied_con->node_list_rh = constraint->node_list_rh;
copied_con->modifier = constraint->modifier;
copied_con->weight = constraint->weight;
return copied_con;
}
/* are the contents of list1 and list2 equal */
/* nodes with weight < 0 are ignored */
gboolean
node_list_eq(GSListPtr list1, GSListPtr list2)
{
GSListPtr result = NULL;
if(g_slist_length(list1) != g_slist_length(list2)) {
return FALSE;
}
// do stuff
crm_err("Not yet implemented");
return g_slist_length(result) != 0;
}
/* the intersection of list1 and list2
* when merging weights, nodes set to < 0 in either list will always
* have their weight set to -1 in the result
*/
GSListPtr
node_list_and(GSListPtr list1, GSListPtr list2)
{
GSListPtr result = NULL;
int lpc = 0;
for(lpc = 0; lpc < g_slist_length(list1); lpc++) {
node_t *node = (node_t*)g_slist_nth_data(list1, lpc);
node_t *new_node = NULL;
node_t *other_node = find_list_node(list2, node->details->id);
if(node == NULL || other_node == NULL) {
continue;
// merge node weights
} else if(node->weight < 0 || other_node->weight < 0) {
new_node = node_copy(node);
new_node->weight = -1;
} else {
new_node = node_copy(node);
new_node->weight =
node->weight + other_node->weight;
if(new_node->weight != 0) {
new_node->weight = new_node->weight /2.0;
}
}
result = g_slist_append(result, new_node);
}
return result;
}
node_t *
find_list_node(GSListPtr list, const char *id)
{
int lpc = 0;
slist_iter(
thing, node_t, list, lpc,
if(safe_str_eq(thing->details->id, id)) {
return thing;
}
);
return NULL;
}
/* list1 - list2 */
GSListPtr
node_list_minus(GSListPtr list1, GSListPtr list2)
{
GSListPtr result = NULL;
int lpc = 0;
slist_iter(
node, node_t, list1, lpc,
node_t *other_node = find_list_node(list2, node->details->id);
if(node == NULL || other_node != NULL) {
continue;
}
node_t *new_node = node_copy(node);
result = g_slist_append(result, new_node);
);
crm_verbose("Minus result len: %d",
g_slist_length(result));
return result;
}
/* list1 + list2 - (intersection of list1 and list2) */
GSListPtr
node_list_xor(GSListPtr list1, GSListPtr list2)
{
GSListPtr result = NULL;
int lpc = 0;
slist_iter(
node, node_t, list1, lpc,
node_t *other_node = (node_t*)find_list_node(list2, node->details->id);
if(node == NULL || other_node != NULL) {
continue;
}
node_t *new_node = node_copy(node);
result = g_slist_append(result, new_node);
);
slist_iter(
node, node_t, list1, lpc,
node_t *other_node = (node_t*)find_list_node(list1, node->details->id);
if(node == NULL || other_node != NULL) {
continue;
}
node_t *new_node = node_copy(node);
result = g_slist_append(result, new_node);
);
crm_verbose("Xor result len: %d", g_slist_length(result));
return result;
}
GSListPtr
node_list_dup(GSListPtr list1)
{
GSListPtr result = NULL;
int lpc = 0;
slist_iter(
this_node, node_t, list1, lpc,
node_t *new_node = node_copy(this_node);
if(new_node != NULL) {
result = g_slist_append(result, new_node);
}
);
return result;
}
node_t *
node_copy(node_t *this_node)
{
if(this_node == NULL) {
print_node("Failed copy of", this_node, TRUE);
return NULL;
}
node_t *new_node = crm_malloc(sizeof(node_t));
new_node->weight = this_node->weight;
new_node->fixed = this_node->fixed;
new_node->details = this_node->details;
return new_node;
}
static int color_id = 0;
/*
* Create a new color with the contents of "nodes" as the list of
* possible nodes that resources with this color can be run on.
*
* Typically, when creating a color you will provide the node list from
* the resource you will first assign the color to.
*
* If "colors" != NULL, it will be added to that list
* If "resources" != NULL, it will be added to every provisional resource
* in that list
*/
color_t *
create_color(GSListPtr *colors, GSListPtr nodes, GSListPtr resources)
{
color_t *new_color = crm_malloc(sizeof(color_t));
new_color->id = color_id++;
new_color->local_weight = 1.0;
new_color->details = crm_malloc(sizeof(struct color_shared_s));
new_color->details->id = new_color->id;
new_color->details->chosen_node = NULL;
new_color->details->candidate_nodes = node_list_dup(nodes);
crm_debug_action(print_color("Created color", new_color, TRUE));
if(colors != NULL) {
*colors = g_slist_append(*colors, new_color);
}
if(resources != NULL) {
/* Add any new color to the list of candidate_colors for
* resources that havent been decided yet
*/
int lpc;
slist_iter(
rsc, resource_t, resources, lpc,
if(rsc->provisional && rsc->runnable) {
color_t *color_copy = (color_t *)
cl_malloc(sizeof(color_t));
color_copy->id = new_color->id;
color_copy->details = new_color->details;
color_copy->local_weight = 1.0;
rsc->candidate_colors =
g_slist_append(rsc->candidate_colors,
color_copy);
}
);
}
return new_color;
}
/*
* Remove any nodes with a -ve weight
*/
gboolean
filter_nodes(resource_t *rsc)
{
int lpc2 = 0;
crm_debug_action(print_resource("Filtering nodes for", rsc, FALSE));
slist_iter(
node, node_t, rsc->allowed_nodes, lpc2,
if(node == NULL) {
crm_err("Invalid NULL node");
} else if(node->weight < 0.0
|| node->details->online == FALSE
|| node->details->type == node_ping) {
crm_debug_action(print_node("Removing", node, FALSE));
rsc->allowed_nodes =
g_slist_remove(rsc->allowed_nodes,node);
crm_free(node);
lpc2--;
}
);
return TRUE;
}
resource_t *
pe_find_resource(GSListPtr rsc_list, const char *id_rh)
{
int lpc = 0;
for(lpc = 0; lpc < g_slist_length(rsc_list); lpc++) {
resource_t *rsc = g_slist_nth_data(rsc_list, lpc);
if(rsc != NULL && safe_str_eq(rsc->id, id_rh)){
return rsc;
}
}
// error
return NULL;
}
node_t *
pe_find_node(GSListPtr nodes, const char *id)
{
int lpc = 0;
for(lpc = 0; lpc < g_slist_length(nodes); lpc++) {
node_t *node = g_slist_nth_data(nodes, lpc);
if(safe_str_eq(node->details->id, id)) {
return node;
}
}
// error
return NULL;
}
gint gslist_color_compare(gconstpointer a, gconstpointer b);
color_t *
find_color(GSListPtr candidate_colors, color_t *other_color)
{
GSListPtr tmp = g_slist_find_custom(candidate_colors, other_color,
gslist_color_compare);
if(tmp != NULL) {
return (color_t *)tmp->data;
}
return NULL;
}
gint gslist_color_compare(gconstpointer a, gconstpointer b)
{
const color_t *color_a = (const color_t*)a;
const color_t *color_b = (const color_t*)b;
if(a == b) {
return 0;
} else if(a == NULL || b == NULL) {
return 1;
} else if(color_a->id == color_b->id) {
return 0;
}
return 1;
}
gint sort_rsc_priority(gconstpointer a, gconstpointer b)
{
const resource_t *resource1 = (const resource_t*)a;
const resource_t *resource2 = (const resource_t*)b;
if(a == NULL) return 1;
if(b == NULL) return -1;
if(resource1->priority > resource2->priority)
return -1;
if(resource1->priority < resource2->priority)
return 1;
return 0;
}
gint sort_cons_strength(gconstpointer a, gconstpointer b)
{
const rsc_to_rsc_t *rsc_constraint1 = (const rsc_to_rsc_t*)a;
const rsc_to_rsc_t *rsc_constraint2 = (const rsc_to_rsc_t*)b;
if(a == NULL) return 1;
if(b == NULL) return -1;
if(rsc_constraint1->strength > rsc_constraint2->strength)
return 1;
if(rsc_constraint1->strength < rsc_constraint2->strength)
return -1;
return 0;
}
gint sort_color_weight(gconstpointer a, gconstpointer b)
{
const color_t *color1 = (const color_t*)a;
const color_t *color2 = (const color_t*)b;
if(a == NULL) return 1;
if(b == NULL) return -1;
if(color1->local_weight > color2->local_weight)
return -1;
if(color1->local_weight < color2->local_weight)
return 1;
return 0;
}
gint sort_node_weight(gconstpointer a, gconstpointer b)
{
const node_t *node1 = (const node_t*)a;
const node_t *node2 = (const node_t*)b;
if(a == NULL) return 1;
if(b == NULL) return -1;
if(node1->weight > node2->weight)
return -1;
if(node1->weight < node2->weight)
return 1;
return 0;
}
action_t *
action_new(int id, resource_t *rsc, enum action_tasks task)
{
action_t *action = (action_t*)crm_malloc(sizeof(action_t));
action->id = id;
action->rsc = rsc;
action->task = task;
action->node = NULL; // fill node in later
action->actions_before = NULL;
action->actions_after = NULL;
action->failure_is_fatal = TRUE;
action->discard = FALSE;
action->runnable = FALSE;
action->processed = FALSE;
action->optional = FALSE;
action->seen_count = 0;
return action;
}
const char *
contype2text(enum con_type type)
{
const char *result = "<unknown>";
switch(type)
{
case type_none:
result = "none";
break;
case rsc_to_rsc:
result = "rsc_to_rsc";
break;
case rsc_to_node:
result = "rsc_to_node";
break;
case rsc_to_attr:
result = "rsc_to_attr";
break;
case base_weight:
result = "base_weight";
break;
}
return result;
};
const char *
strength2text(enum con_strength strength)
{
const char *result = "<unknown>";
switch(strength)
{
case ignore:
result = "ignore";
break;
case must:
result = XML_STRENGTH_VAL_MUST;
break;
case should:
result = XML_STRENGTH_VAL_SHOULD;
break;
case should_not:
result = XML_STRENGTH_VAL_SHOULDNOT;
break;
case must_not:
result = XML_STRENGTH_VAL_MUSTNOT;
break;
case startstop:
result = "start/stop";
break;
}
return result;
};
const char *
modifier2text(enum con_modifier modifier)
{
const char *result = "<unknown>";
switch(modifier)
{
case modifier_none:
result = "modifier_none";
break;
case set:
result = "set";
break;
case inc:
result = "inc";
break;
case dec:
result = "dec";
break;
}
return result;
};
const char *
task2text(enum action_tasks task)
{
const char *result = "<unknown>";
switch(task)
{
case no_action:
result = "no_action";
break;
case stop_rsc:
result = "stop";
break;
case start_rsc:
result = "start";
break;
case shutdown_crm:
result = "shutdown_crm";
break;
case stonith_op:
result = "stonith";
break;
}
return result;
};
void
print_node(const char *pre_text, node_t *node, gboolean details)
{
if(node == NULL) {
crm_debug("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
crm_debug("%s%s%sNode %s: (weight=%f, fixed=%s)",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
node->details==NULL?"error ":node->details->online?"":"Unavailable/Unclean ",
node->details->id,
node->weight,
node->fixed?"True":"False");
if(details && node->details != NULL) {
char *mutable = crm_strdup("\t\t");
crm_debug("\t\t===Node Attributes");
g_hash_table_foreach(node->details->attrs,
print_str_str, mutable);
crm_free(mutable);
}
if(details) {
int lpc = 0;
crm_debug("\t\t===Node Attributes");
slist_iter(
rsc, resource_t, node->details->running_rsc, lpc,
print_resource("\t\t", rsc, FALSE);
);
}
};
/*
* Used by the HashTable for-loop
*/
void print_str_str(gpointer key, gpointer value, gpointer user_data)
{
crm_debug("%s%s %s ==> %s",
user_data==NULL?"":(char*)user_data,
user_data==NULL?"":": ",
(char*)key,
(char*)value);
}
void
print_color_details(const char *pre_text,
struct color_shared_s *color,
gboolean details)
{
if(color == NULL) {
crm_debug("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
crm_debug("%s%sColor %d: node=%s (from %d candidates)",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
color->id,
color->chosen_node==NULL?"<unset>":color->chosen_node->details->id,
g_slist_length(color->candidate_nodes));
if(details) {
int lpc = 0;
slist_iter(node, node_t, color->candidate_nodes, lpc,
print_node("\t", node, FALSE));
}
}
void
print_color(const char *pre_text, color_t *color, gboolean details)
{
if(color == NULL) {
crm_debug("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
crm_debug("%s%sColor %d: (weight=%f, node=%s, possible=%d)",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
color->id,
color->local_weight,
color->details->chosen_node==NULL?"<unset>":color->details->chosen_node->details->id,
g_slist_length(color->details->candidate_nodes));
if(details) {
print_color_details("\t", color->details, details);
}
}
void
print_rsc_to_node(const char *pre_text, rsc_to_node_t *cons, gboolean details)
{
if(cons == NULL) {
crm_debug("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
crm_debug("%s%s%s Constraint %s (%p):",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
"rsc_to_node",
cons->id, cons);
if(details == FALSE) {
crm_debug("\t%s --> %s, %f (node placement rule)",
cons->rsc_lh->id,
modifier2text(cons->modifier),
cons->weight);
int lpc = 0;
slist_iter(
node, node_t, cons->node_list_rh, lpc,
print_node("\t\t-->", node, FALSE)
);
}
}
void
print_rsc_to_rsc(const char *pre_text, rsc_to_rsc_t *cons, gboolean details)
{
if(cons == NULL) {
crm_debug("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
crm_debug("%s%s%s Constraint %s (%p):",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
"rsc_to_rsc", cons->id, cons);
if(details == FALSE) {
crm_debug("\t%s --> %s, %s",
cons->rsc_lh==NULL?"null":cons->rsc_lh->id,
cons->rsc_rh==NULL?"null":cons->rsc_rh->id,
strength2text(cons->strength));
}
}
void
print_resource(const char *pre_text, resource_t *rsc, gboolean details)
{
if(rsc == NULL) {
crm_debug("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
crm_debug("%s%s%s%sResource %s: (priority=%f, color=%d, now=%s)",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
rsc->provisional?"Provisional ":"",
rsc->runnable?"":"(Non-Startable) ",
rsc->id,
(double)rsc->priority,
safe_val3(-1, rsc, color, id),
safe_val4(NULL, rsc, cur_node, details, id));
crm_debug("\t%d candidate colors, %d allowed nodes, %d rsc_cons and %d node_cons",
g_slist_length(rsc->candidate_colors),
g_slist_length(rsc->allowed_nodes),
g_slist_length(rsc->rsc_cons),
g_slist_length(rsc->node_cons));
if(details) {
int lpc = 0;
crm_debug("\t=== Actions");
print_action("\tStop: ", rsc->stop, FALSE);
print_action("\tStart: ", rsc->start, FALSE);
crm_debug("\t=== Colors");
slist_iter(
color, color_t, rsc->candidate_colors, lpc,
print_color("\t", color, FALSE)
);
crm_debug("\t=== Allowed Nodes");
slist_iter(
node, node_t, rsc->allowed_nodes, lpc,
print_node("\t", node, FALSE);
);
}
}
void
print_action(const char *pre_text, action_t *action, gboolean details)
{
if(action == NULL) {
crm_debug("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
switch(action->task) {
case stonith_op:
case shutdown_crm:
crm_debug("%s%s%sAction %d: %s @ %s",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
action->discard?"Discarded ":action->optional?"Optional ":action->runnable?action->processed?"":"(Provisional) ":"!!Non-Startable!! ",
action->id,
task2text(action->task),
safe_val4(NULL, action, node, details, id));
break;
default:
crm_debug("%s%s%sAction %d: %s %s @ %s",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
action->optional?"Optional ":action->runnable?action->processed?"":"(Provisional) ":"!!Non-Startable!! ",
action->id,
task2text(action->task),
safe_val3(NULL, action, rsc, id),
safe_val4(NULL, action, node, details, id));
break;
}
if(details) {
int lpc = 0;
#if 1
crm_debug("\t\t====== Preceeding Actions");
slist_iter(
other, action_wrapper_t, action->actions_before, lpc,
print_action("\t\t", other->action, FALSE);
);
crm_debug("\t\t====== Subsequent Actions");
slist_iter(
other, action_wrapper_t, action->actions_after, lpc,
print_action("\t\t", other->action, FALSE);
);
#else
crm_debug("\t\t====== Subsequent Actions");
slist_iter(
other, action_wrapper_t, action->actions_after, lpc,
print_action("\t\t", other->action, FALSE);
);
#endif
crm_debug("\t\t====== End");
} else {
crm_debug("\t\t(seen=%d, before=%d, after=%d)",
action->seen_count,
g_slist_length(action->actions_before),
g_slist_length(action->actions_after));
}
}
xmlNodePtr
action2xml(action_t *action)
{
xmlNodePtr action_xml = NULL;
if(action == NULL) {
return NULL;
}
switch(action->task) {
case stonith_op:
action_xml = create_xml_node(NULL, "pseduo_event");
break;
case shutdown_crm:
action_xml = create_xml_node(NULL, "crm_event");
break;
default:
action_xml = create_xml_node(NULL, "rsc_op");
add_node_copy(action_xml, action->rsc->xml);
break;
}
set_xml_property_copy(action_xml,
XML_LRM_ATTR_TARGET,
safe_val4(NULL, action, node, details, id));
set_xml_property_copy(action_xml,
XML_ATTR_ID,
crm_itoa(action->id));
set_xml_property_copy(action_xml,
XML_LRM_ATTR_RUNNABLE,
action->runnable?XML_BOOLEAN_TRUE:XML_BOOLEAN_FALSE);
set_xml_property_copy(action_xml,
XML_LRM_ATTR_OPTIONAL,
action->optional?XML_BOOLEAN_TRUE:XML_BOOLEAN_FALSE);
set_xml_property_copy(action_xml,
XML_LRM_ATTR_TASK,
task2text(action->task));
set_xml_property_copy(action_xml,
XML_LRM_ATTR_DISCARD,
action->discard?XML_BOOLEAN_TRUE:XML_BOOLEAN_FALSE);
set_xml_property_copy(action_xml,
"allow_fail",
action->failure_is_fatal?XML_BOOLEAN_FALSE:XML_BOOLEAN_TRUE);
return action_xml;
}
gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data);
void
pe_free_nodes(GSListPtr nodes)
{
while(nodes != NULL){
GSListPtr list_item = nodes;
node_t *node = (node_t*)list_item->data;
struct node_shared_s *details = node->details;
nodes = nodes->next;
if(details != NULL) {
crm_free(details->id);
g_hash_table_foreach_remove(details->attrs,
ghash_free_str_str, NULL);
crm_free(details);
}
crm_free(node);
}
g_slist_free(nodes);
}
gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data)
{
crm_free(key);
crm_free(value);
return TRUE;
}
void
pe_free_colors(GSListPtr colors)
{
while(colors != NULL) {
GSListPtr list_item = colors;
color_t *color = (color_t *)list_item->data;
struct color_shared_s *details = color->details;
colors = colors->next;
if(details != NULL) {
pe_free_shallow(details->candidate_nodes);
crm_free(details->chosen_node);
crm_free(details);
}
crm_free(color);
}
g_slist_free(colors);
}
void
pe_free_shallow(GSListPtr alist)
{
pe_free_shallow_adv(alist, TRUE);
}
void
pe_free_shallow_adv(GSListPtr alist, gboolean with_data)
{
GSListPtr item;
GSListPtr item_next = alist;
while(item_next != NULL) {
item = item_next;
item_next = item_next->next;
if(with_data) {
crm_free(item->data);
}
item->data = NULL;
item->next = NULL;
g_slist_free(item);
}
}
void
pe_free_resources(GSListPtr resources)
{
volatile GSListPtr list_item = NULL;
resource_t *rsc = NULL;
while(resources != NULL) {
list_item = resources;
rsc = (resource_t *)list_item->data;
resources = resources->next;
crm_free(rsc->id);
// crm_verbose("color");
// crm_free(rsc->color);
int lpc;
slist_iter(clr, color_t, rsc->candidate_colors, lpc,
print_color("deleting", clr, FALSE));
// pe_free_shallow(rsc->candidate_colors);
pe_free_shallow(rsc->allowed_nodes);
while(rsc->rsc_cons) {
pe_free_rsc_to_rsc((rsc_to_rsc_t*)rsc->rsc_cons->data);
rsc->rsc_cons = rsc->rsc_cons->next;
}
g_slist_free(rsc->rsc_cons);
crm_free(rsc);
}
g_slist_free(resources);
}
void
pe_free_actions(GSListPtr actions)
{
while(actions != NULL) {
GSListPtr list_item = actions;
action_t *action = (action_t *)list_item->data;
actions = actions->next;
pe_free_shallow(action->actions_before); // action_warpper_t*
pe_free_shallow(action->actions_after); // action_warpper_t*
action->actions_before = NULL;
action->actions_after = NULL;
crm_free(action);
}
g_slist_free(actions);
}
void
pe_free_rsc_to_rsc(rsc_to_rsc_t *cons)
{
if(cons != NULL) {
crm_free(cons->id);
crm_free(cons);
}
}
void
pe_free_rsc_to_node(rsc_to_node_t *cons)
{
if(cons != NULL) {
crm_free(cons->id);
pe_free_shallow(cons->node_list_rh); // node_t*
crm_free(cons);
}
}
diff --git a/crm/tengine/tengine.h b/crm/tengine/tengine.h
index 9775d3c12b..b24b6f82be 100644
--- a/crm/tengine/tengine.h
+++ b/crm/tengine/tengine.h
@@ -1,12 +1,30 @@
+/* $Id: tengine.h,v 1.4 2004/06/02 16:03:34 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
+ */
#ifndef TENGINE__H
#define TENGINE__H
#include <clplumbing/ipc.h>
extern gboolean process_te_message(xmlNodePtr msg, IPC_Channel *sender);
extern IPC_Channel *crm_ch;
#endif
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Apr 21, 6:18 PM (23 h, 21 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1665177
Default Alt Text
(76 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment