summaryrefslogtreecommitdiffstats
path: root/tools/ocft
diff options
context:
space:
mode:
Diffstat (limited to 'tools/ocft')
-rw-r--r--tools/ocft/ChangeLog57
-rw-r--r--tools/ocft/Filesystem105
-rw-r--r--tools/ocft/IPaddr2137
-rw-r--r--tools/ocft/IPaddr2v4323
-rw-r--r--tools/ocft/IPaddr2v6250
-rw-r--r--tools/ocft/IPsrcaddr63
-rw-r--r--tools/ocft/IPv6addr150
-rw-r--r--tools/ocft/LVM83
-rw-r--r--tools/ocft/MailTo57
-rw-r--r--tools/ocft/Makefile.am63
-rw-r--r--tools/ocft/README.in147
-rw-r--r--tools/ocft/README.zh_CN.in124
-rw-r--r--tools/ocft/Raid1134
-rw-r--r--tools/ocft/SendArp74
-rw-r--r--tools/ocft/VirtualDomain71
-rw-r--r--tools/ocft/Xen65
-rw-r--r--tools/ocft/Xinetd64
-rw-r--r--tools/ocft/apache68
-rw-r--r--tools/ocft/caselib.in299
-rw-r--r--tools/ocft/db2164
-rw-r--r--tools/ocft/drbd.linbit183
-rw-r--r--tools/ocft/exportfs80
-rw-r--r--tools/ocft/exportfs-multidir80
-rw-r--r--tools/ocft/helpers.sh43
-rw-r--r--tools/ocft/iscsi108
-rw-r--r--tools/ocft/jboss83
-rw-r--r--tools/ocft/mysql82
-rw-r--r--tools/ocft/mysql-proxy83
-rw-r--r--tools/ocft/named69
-rw-r--r--tools/ocft/nfsserver69
-rw-r--r--tools/ocft/ocft.in893
-rw-r--r--tools/ocft/oracle81
-rw-r--r--tools/ocft/pgsql71
-rw-r--r--tools/ocft/portblock69
-rw-r--r--tools/ocft/postfix102
-rwxr-xr-xtools/ocft/runocft38
-rw-r--r--tools/ocft/runocft.prereq30
-rw-r--r--tools/ocft/sg_persist225
-rw-r--r--tools/ocft/tomcat73
39 files changed, 4960 insertions, 0 deletions
diff --git a/tools/ocft/ChangeLog b/tools/ocft/ChangeLog
new file mode 100644
index 0000000..8b00210
--- /dev/null
+++ b/tools/ocft/ChangeLog
@@ -0,0 +1,57 @@
+0.43:
+ - Add an option 'Agent' in 'CONFIG'
+ - Fix a bug about remote shell.
+ - Add top level option 'VARIABLE'.
+ - Add top level option 'CLEANUP-AGENT'.
+ - Rename Var & Unvar to Env & Unenv.
+ - Fix a bug about agent installation.
+ - Modified configs of agent according the new syntax.
+0.42:
+ - Fix a bug about agent installation.
+ - The tests stop early if the basic functionality it not there.
+ - Fix a bug about 'config parser'.
+ - Keep the resource stat between the runs to avoid there are multiple stop/start per run.
+ - Add a function with warning output.
+ - Adjust the sequence of cases running.
+ - Change the default timeout.
+ - Replace the crm_master command in Agent scripts, it is no use in testing,
+ because the agent runs in local when test.
+ - Support drbd testing if the configuration is correct.
+ - Fix a 'Include' bug.
+ - Fix a bug about configuration of 'mysql'.
+0.41:
+ - Fixed a remote shell bug.
+ - Improved 'Include' option, now it supports remote shell, invoked just like 'Include@ip_address'.
+ - Show line number, if syntax error occurs in config file.
+ - Add a 'AgentRoot' sub-option.
+ - Fix a bug with config parsing.
+ - Rename ACTION "run" to "test".
+ - Add a simple output mode for "test" ACTION.
+ - Add a verbose ouput mode for "help" ACTION.
+ - The output will be recorded to log file.
+ - Add double stop and double start to tests.
+ - Exit with 1 if test script failed.
+ - The output of agents will be exposed if the test fails.
+ - Run zypper with -q
+ - Use 127.0.0.x(and lo for interface) for agents IP*
+0.4:
+ - Add a 'CASE-BLOCK' top option, it can be included by 'CASE'
+ - Add a 'SETUP-AGENT' top option, you can initialize agents before testing.
+ - Add a 'Include' sub-option.
+ - Add a 'Unvar' sub-option.
+ - Rename 'GLOBAL' to 'CONFIG'.
+ - Modify a part of syntax.
+ - Imporve the 'InstallPackage' option, now it supports SUSE, Redhat and Debian.
+ - Add README & README.zh_CN.
+0.3:
+ - All statements in CASE can be executed by remote shell.
+0.2:
+ - Implement options: BashAtExit, GLOBAL, HangTimeout, InstallPackage.
+ - Delete option: Name.
+ - Modify a part of syntax.
+ - Fix some bugs.
+ - Print testing message in human readable format.
+ - Improve 'make' and 'run' option.
+ - Add 'clean' option.
+0.1:
+ - Implement options: CASE, Bash, Run, Var, Name.
diff --git a/tools/ocft/Filesystem b/tools/ocft/Filesystem
new file mode 100644
index 0000000..2b22d1b
--- /dev/null
+++ b/tools/ocft/Filesystem
@@ -0,0 +1,105 @@
+# Filesystem
+# by dejan@suse.de on
+# Tue Feb 15 18:50:04 CET 2011
+#
+CONFIG
+ Agent Filesystem
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ HangTimeout 20
+
+VARIABLE
+ OCFT_rundir="`get_rundir`"
+ OCFT_fs="$OCFT_rundir/resource-agents/ocft-Filesystem-fs"
+ OCFT_dir="$OCFT_rundir/resource-agents/ocft-Filesystem-mnt"
+ OCFT_loop="`loopbackeddev make $OCFT_fs 16M`"
+
+SETUP-AGENT
+ mke2fs -j -Fq -m 0 $OCFT_loop
+
+CLEANUP-AGENT
+ loopbackeddev unmake $OCFT_fs
+ rmdir $OCFT_dir
+
+CASE-BLOCK required_args
+ Env OCF_RESKEY_device=$OCFT_loop
+ Env OCF_RESKEY_fstype=ext3
+ Env OCF_RESKEY_directory=$OCFT_dir
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include required_args
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: invalid 'OCF_RESKEY_device'"
+ Include prepare
+ Env OCF_RESKEY_device=/dev/no_such_device
+ AgentRun start OCF_ERR_INSTALLED
+
+CASE "check base env: unset 'OCF_RESKEY_device'"
+ Include prepare
+ Unenv OCF_RESKEY_device
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "monitor when running"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "monitor when not running"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "monitor depth 10 when running"
+ Include prepare
+ AgentRun start
+ Env OCF_CHECK_LEVEL=10
+ AgentRun monitor OCF_SUCCESS
+
+CASE "monitor depth 20 with running"
+ Include prepare
+ AgentRun start
+ Env OCF_CHECK_LEVEL=20
+ AgentRun monitor OCF_SUCCESS
+
+CASE "start insert failure (remove device)"
+ Include prepare
+ Bash losetup -d $OCFT_loop
+ BashAtExit losetup $OCFT_loop $OCFT_fs
+ AgentRun start OCF_ERR_GENERIC
+
+CASE "monitor depth 20 insert failure (r/o fs)"
+ Include prepare
+ AgentRun start
+ Bash mount -o remount,ro $OCFT_dir
+ BashAtExit mount -o remount,rw $OCFT_dir
+ Env OCF_CHECK_LEVEL=20
+ AgentRun monitor OCF_ERR_GENERIC
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
+
diff --git a/tools/ocft/IPaddr2 b/tools/ocft/IPaddr2
new file mode 100644
index 0000000..04698a0
--- /dev/null
+++ b/tools/ocft/IPaddr2
@@ -0,0 +1,137 @@
+# IPaddr2
+
+CONFIG
+ Agent IPaddr2
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ HangTimeout 20
+
+SETUP-AGENT
+ ip addr add 192.168.144.1/24 dev eth0 brd 192.168.144.255
+
+CLEANUP-AGENT
+ ip addr del 192.168.144.1/24 dev eth0
+
+CASE-BLOCK required_args
+ Env OCF_RESKEY_ip=192.168.144.2
+
+CASE-BLOCK check_iflabel_assigned
+ Bash ip -4 -o addr show eth0 | grep -w 192.168.144.2/24 | grep -w eth0:iflabel >/dev/null # checking iflabel was assigned correctly
+
+CASE-BLOCK check_iflabel_removed
+ Bash ! ip -4 -o addr show eth0 | grep -w 192.168.144.2/24 | grep -w eth0:iflabel >/dev/null # checking iflabel was removed correctly
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include required_args
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: unset 'OCF_RESKEY_ip'"
+ Include prepare
+ Unenv OCF_RESKEY_ip
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "check base env: set invalid 'OCF_RESKEY_ip'"
+ Include prepare
+ Env OCF_RESKEY_ip=not_ip_address
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "check base env: set 'OCF_RESKEY_cidr_netmask'"
+ Include prepare
+ Env OCF_RESKEY_cidr_netmask=24
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: set invalid 'OCF_RESKEY_cidr_netmask'"
+ Include prepare
+ Env OCF_RESKEY_cidr_netmask=not_netmask
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "check base env: set 'OCF_RESKEY_broadcast'"
+ Include prepare
+ Env OCF_RESKEY_broadcast=192.168.144.255
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: set invalid 'OCF_RESKEY_broadcast'"
+ Include prepare
+ Env OCF_RESKEY_broadcast=not_broadcast
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "check base env: set 'OCF_RESKEY_nic'"
+ Include prepare
+ Env OCF_RESKEY_nic=eth0
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: set invalid 'OCF_RESKEY_nic'"
+ Include prepare
+ Env OCF_RESKEY_nic=not_nic
+ AgentRun start OCF_ERR_CONFIGURED
+ AgentRun validate-all OCF_ERR_CONFIGURED
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "monitor with running"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "monitor with not running"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
+
+CASE "Attachment to loopback interface"
+ Env OCF_RESKEY_ip=127.0.0.3
+ AgentRun start OCF_SUCCESS
+ AgentRun monitor OCF_SUCCESS
+ AgentRun stop OCF_SUCCESS
+
+CASE "check additional env: set 'OCF_RESKEY_iflabel'"
+ Include prepare
+ Env OCF_RESKEY_nic=eth0
+ Env OCF_RESKEY_iflabel=iflabel
+ AgentRun start OCF_SUCCESS
+ Include check_iflabel_assigned
+ AgentRun stop OCF_SUCCESS
+ Include check_iflabel_removed
+
+# This is deprecated but still supported for the compatibility.
+CASE "check additional env: specify iflabel in 'OCF_RESKEY_nic'"
+ Include prepare
+ Env OCF_RESKEY_nic=eth0:iflabel
+ AgentRun start OCF_SUCCESS
+ Include check_iflabel_assigned
+ AgentRun stop OCF_SUCCESS
+ Include check_iflabel_removed
+
+# monitor should return OCF_ERR_GENERIC rather than OCF_ERR_CONFIGURED
+# when the specified OCF_RESKEY_nic is vanished by a failure.
+# This has been changed as of 3.9.6.
+CASE "monitor failure when 'OCF_RESKEY_nic' is vanished"
+ Include prepare
+ Env OCF_RESKEY_nic=ethVanished
+ Env OCF_RESKEY_CRM_meta_interval=10 # not in probe
+ AgentRun monitor OCF_ERR_GENERIC
diff --git a/tools/ocft/IPaddr2v4 b/tools/ocft/IPaddr2v4
new file mode 100644
index 0000000..4d37168
--- /dev/null
+++ b/tools/ocft/IPaddr2v4
@@ -0,0 +1,323 @@
+# IPaddr2v4
+
+# Note: This test case uses two NICs(eth0, eth1) and
+# a IPv4 address prefix (192.168.144.0/24).
+# Adjust them according to your environment at VARIABLE section if needed.
+
+CONFIG
+ Agent IPaddr2
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ HangTimeout 20
+
+VARIABLE
+ OCFT_target_ip=192.168.144.2
+ OCFT_target_nic=eth0
+ OCFT_target_prefix=24
+ OCFT_target_netaddr=192.168.144.1/$OCFT_target_prefix
+ OCFT_target_brd=192.168.144.255
+ OCFT_wrong_ip=192.168.120.1
+ OCFT_force_nic=eth1
+ OCFT_force_prefix=16
+ OCFT_force_prefix2=28
+ OCFT_force_brd=192.168.255.255
+
+SETUP-AGENT
+ ip addr add $OCFT_target_netaddr dev $OCFT_target_nic brd $OCFT_target_brd
+
+CLEANUP-AGENT
+ ip addr del $OCFT_target_netaddr dev $OCFT_target_nic
+
+CASE-BLOCK required_args
+ Env OCF_RESKEY_ip=$OCFT_target_ip
+ Env OCFT_check_ip=$OCFT_target_ip
+ Env OCFT_check_prefix=$OCFT_target_prefix
+ Env OCFT_check_nic=$OCFT_target_nic
+
+CASE-BLOCK check_ip_assigned
+ Bash ip -4 -o addr show $OCFT_check_nic | grep -w $OCFT_check_ip/$OCFT_check_prefix >/dev/null # checking if the IPv4 address was assigned correctly
+
+CASE-BLOCK check_ip_removed
+ Bash ! ip -4 -o addr show $OCFT_check_nic | grep -w $OCFT_check_ip/$OCFT_check_prefix >/dev/null # checking if the IPv4 address was removed correctly
+
+CASE-BLOCK base_ip_assigned
+ Bash ip addr add $OCFT_target_netaddr dev $OCFT_target_nic brd $OCFT_target_brd
+
+CASE-BLOCK base_ip_removed
+ Bash ip addr del $OCFT_target_netaddr dev $OCFT_target_nic
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include required_args
+ Include default_status
+
+# CASE No.0
+#
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+ Include check_ip_assigned
+
+# CASE No.1
+#
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
+
+# CASE No.2
+#
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+# CASE No.3
+#
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+# CASE No.4
+#
+CASE "monitor with running"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+# CASE No.5
+#
+CASE "monitor with not running"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+# CASE No.6
+# Note: this result is different from IPaddr2 in 3.9.3.
+# IPaddr2 succeeds if the ip matched based on the netmask of the subnet
+# or fails if it did not match to any.
+# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed.
+# IPaddr2 in 3.9.3 was using a wrong subnet mask (constant of 32) in this case.
+#
+CASE "params with nic, no cidr_netmask"
+ Include prepare
+ Env OCF_RESKEY_nic=$OCFT_target_nic
+ AgentRun start OCF_SUCCESS
+ Include check_ip_assigned
+ AgentRun monitor OCF_SUCCESS
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
+
+# CASE No.7
+#
+CASE "params with nic, cidr_netmask"
+ Include prepare
+ Env OCF_RESKEY_nic=$OCFT_target_nic
+ Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix
+ AgentRun start OCF_SUCCESS
+ Include check_ip_assigned
+ AgentRun monitor OCF_SUCCESS
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
+
+# CASE No.8
+#
+CASE "error params with wrong ip"
+ Include prepare
+ Env OCF_RESKEY_ip=$OCFT_wrong_ip
+ AgentRun start OCF_ERR_GENERIC
+
+# CASE No.9
+# Note: this result is different from IPaddr2 in 3.9.3.
+# IPaddr2 fails when it could not determine the correct subnet mask.
+# When it could not get base ip, it becomes the error.
+# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed.
+# IPaddr2 in 3.9.3 was using a wrong subnet mask (constant of 32) in this case.
+#
+CASE "params with force nic"
+ Include prepare
+ Env OCF_RESKEY_nic=$OCFT_force_nic
+ Env OCFT_check_nic=$OCFT_force_nic
+ AgentRun start OCF_ERR_GENERIC
+ Include check_ip_removed
+ Unenv OCF_RESKEY_nic
+
+# CASE No.10
+# Note: this result is different from IPaddr2 in 3.9.3.
+# IPaddr2 fails when it could not determine the broadcast.
+# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed.
+# IPaddr2 in 3.9.3 succeeded but it's considered ambiguous.
+#
+CASE "params with force cidr_netmask (base netmask > assigned netmask)"
+ Include prepare
+ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix
+ Env OCFT_check_prefix=$OCFT_force_prefix
+ AgentRun start OCF_ERR_GENERIC
+ Include check_ip_removed
+
+# CASE No.11
+# Note: this result is different from IPaddr2 in 3.9.3.
+# IPaddr2 succeeds but the broadcast is not set.
+# This is because findif.sh can not calculate a broadcast from a netmask.
+# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed.
+# IPaddr2 in 3.9.3 succeeded with using a calculated broadcast.
+#
+CASE "force to use the specified nic and cidr_netmask"
+ Include prepare
+ Env OCF_RESKEY_nic=$OCFT_force_nic
+ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix
+ Env OCFT_check_nic=$OCFT_force_nic
+ Env OCFT_check_prefix=$OCFT_force_prefix
+ AgentRun start OCF_SUCCESS
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
+ Unenv OCF_RESKEY_cidr_netmask
+
+
+# CASE No.12
+# Note: this result is different from IPaddr2 in 3.9.3.
+# IPaddr2 fails when it could not determine the correct subnet mask.
+# When it could not get base ip, it becomes the error.
+# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed.
+# IPaddr2 in 3.9.3 was using a wrong subnet mask (constant of 32) in this case.
+#
+CASE "error params with wrong ip and nic (not exist base_ip)"
+ Include prepare
+ Include base_ip_removed
+ Env OCF_RESKEY_nic=$OCFT_target_nic
+ Env OCFT_check_nic=$OCFT_target_nic
+ AgentRun start OCF_ERR_GENERIC
+ Include check_ip_removed
+ Include base_ip_assigned
+
+# CASE No.13
+#
+CASE "params with cidr_netmask"
+ Include prepare
+ Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix
+ AgentRun start OCF_SUCCESS
+ Include check_ip_assigned
+ AgentRun monitor OCF_SUCCESS
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
+
+# CASE No.14
+# Note: this result is different from IPaddr2 in 3.9.3.
+# IPaddr2 does not override the broadcast by cidr_netmask.
+# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed.
+# IPaddr2 in 3.9.3 overrode the broadcast calculated by cidr_netmask.
+#
+CASE "params with force cidr_netmask (base netmask < assigned netmask)"
+ Include prepare
+ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2
+ Env OCFT_check_prefix=$OCFT_force_prefix2
+ AgentRun start OCF_SUCCESS
+ Include check_ip_assigned
+ AgentRun monitor OCF_SUCCESS
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
+
+# CASE No.15
+# Note: this result is different from IPaddr2 in 3.9.3.
+# IPaddr2 fails when it could not determine the broadcast.
+# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed.
+# IPaddr2 in 3.9.3 succeeded but it's considered ambiguous.
+#
+CASE "error params with wrong ip and cidr_netmask (not exist base_ip)"
+ Include prepare
+ Include base_ip_removed
+ Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix
+ AgentRun start OCF_ERR_GENERIC
+ Include base_ip_assigned
+
+# CASE No.16
+# Note: this result is different from IPaddr2 in 3.9.3.
+# IPaddr2 succeeds but the broadcast is not set.
+# This is because findif.sh can not calculate a broadcast from a netmask.
+# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed.
+# IPaddr2 in 3.9.3 succeeded with using a calculated broadcast.
+#
+CASE "force to use the specified nic and cidr_netmask"
+ Include prepare
+ Env OCF_RESKEY_nic=$OCFT_force_nic
+ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2
+ Env OCFT_check_prefix=$OCFT_force_prefix2
+ Env OCFT_check_nic=$OCFT_force_nic
+ AgentRun start OCF_SUCCESS
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
+
+# CASE No.17
+# Note: this result is different from IPaddr2 in 3.9.3.
+# IPaddr2 succeeds but the broadcast is not set.
+# This is because findif.sh can not calculate a broadcast from a netmask.
+# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed.
+# IPaddr2 in 3.9.3 succeeded with using a calculated broadcast.
+#
+CASE "force to use the specified nic and cidr_netmask (not exist base_ip)"
+ Include prepare
+ Include base_ip_removed
+ Env OCF_RESKEY_nic=$OCFT_force_nic
+ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2
+ Env OCFT_check_prefix=$OCFT_force_prefix2
+ Env OCFT_check_nic=$OCFT_force_nic
+ AgentRun start OCF_SUCCESS
+ AgentRun stop OCF_SUCCESS
+ Unenv OCF_RESKEY_nic
+ Unenv OCF_RESKEY_cidr_netmask
+ Include base_ip_assigned
+
+# CASE No.18
+#
+CASE "params with broadcast, no nic, no cidr_netmask"
+ Include prepare
+ Env OCF_RESKEY_broadcast=$OCFT_force_brd
+ AgentRun start OCF_SUCCESS
+ Include check_ip_assigned
+ AgentRun monitor OCF_SUCCESS
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
+
+# CASE No.19
+#
+CASE "params with broadcast, no nic, no cidr_netmask"
+ Include prepare
+ Include base_ip_removed
+ Env OCF_RESKEY_broadcast=$OCFT_force_brd
+ AgentRun start OCF_ERR_GENERIC
+ Include base_ip_assigned
+
+# CASE No.20
+#
+CASE "force to use the specified nic and cidr_netmask"
+ Include prepare
+ Env OCF_RESKEY_nic=$OCFT_force_nic
+ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix
+ Env OCF_RESKEY_broadcast=$OCFT_force_brd
+ Env OCFT_check_nic=$OCFT_force_nic
+ Env OCFT_check_prefix=$OCFT_force_prefix
+ AgentRun start OCF_SUCCESS
+ Include check_ip_assigned
+ AgentRun monitor OCF_SUCCESS
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
+ Unenv OCF_RESKEY_cidr_netmask
+
+# CASE No.21
+#
+CASE "force to use the specified nic and cidr_netmask"
+ Include prepare
+ Include base_ip_removed
+ Env OCF_RESKEY_nic=$OCFT_force_nic
+ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2
+ Env OCF_RESKEY_broadcast=$OCFT_target_brd
+ Env OCFT_check_nic=$OCFT_force_nic
+ Env OCFT_check_prefix=$OCFT_force_prefix2
+ AgentRun start OCF_SUCCESS
+ Include check_ip_assigned
+ AgentRun monitor OCF_SUCCESS
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
+ Include base_ip_assigned
+
diff --git a/tools/ocft/IPaddr2v6 b/tools/ocft/IPaddr2v6
new file mode 100644
index 0000000..d24d890
--- /dev/null
+++ b/tools/ocft/IPaddr2v6
@@ -0,0 +1,250 @@
+# IPaddr2v6
+
+# Note: This test case uses two NICs(eth0, eth1) and
+# a IPv6 address prefix (2001:db8::/32, RFC3849).
+# Adjust them according to your environment at VARIABLE section if needed.
+
+CONFIG
+ Agent IPaddr2
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ HangTimeout 20
+
+VARIABLE
+ OCFT_target_ip=2001:db8:1234::2
+ OCFT_target_nic=eth0
+ OCFT_target_prefix=64
+ OCFT_target_netaddr=2001:db8:1234::1/$OCFT_target_prefix
+ OCFT_target_linklocal=fe80::2
+ OCFT_wrong_ip=2001:db8:5678::2
+ OCFT_force_nic=eth1
+ OCFT_force_prefix=80
+ OCFT_force_prefix2=48
+
+SETUP-AGENT
+ ip addr add $OCFT_target_netaddr dev $OCFT_target_nic
+
+CLEANUP-AGENT
+ ip addr del $OCFT_target_netaddr dev $OCFT_target_nic
+
+CASE-BLOCK required_args
+ Env OCF_RESKEY_ip=$OCFT_target_ip
+ Env OCFT_check_ip=$OCFT_target_ip
+ Env OCFT_check_prefix=$OCFT_target_prefix
+ Env OCFT_check_nic=$OCFT_target_nic
+
+CASE-BLOCK check_ip_assigned
+ Bash ip -6 -o addr show $OCFT_check_nic | grep -w $OCFT_check_ip/$OCFT_check_prefix >/dev/null # checking if the IPv6 address was assigned correctly
+
+CASE-BLOCK check_ip_removed
+ Bash ! ip -6 -o addr show $OCFT_check_nic | grep -w $OCFT_check_ip/$OCFT_check_prefix >/dev/null # checking if the IPv6 address was removed correctly
+
+CASE-BLOCK base_ip_assigned
+ Bash ip addr add $OCFT_target_netaddr dev $OCFT_target_nic
+
+CASE-BLOCK base_ip_removed
+ Bash ip addr del $OCFT_target_netaddr dev $OCFT_target_nic
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include required_args
+ Include default_status
+
+# CASE No.0
+#
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+ Include check_ip_assigned
+
+# CASE No.1
+#
+CASE "normal stop"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
+
+# CASE No.2
+#
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+# CASE No.3
+#
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+# CASE No.4
+#
+CASE "monitor with running"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+# CASE No.5
+#
+CASE "monitor with not running"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+# CASE No.6
+#
+CASE "error params with wrong ip"
+ Include prepare
+ Env OCF_RESKEY_ip=$OCFT_wrong_ip
+ AgentRun start OCF_ERR_GENERIC
+
+# CASE No.7
+#
+CASE "error params with no nic for a link-local IPv6 address"
+ Include prepare
+ Env OCF_RESKEY_ip=$OCFT_target_linklocal
+ Env OCFT_check_ip=$OCFT_target_linklocal
+ # nic is mandatory for a link-local address
+ AgentRun start OCF_ERR_CONFIGURED
+
+# CASE No.8
+#
+CASE "params with nic, no cidr_netmask"
+ Include prepare
+ Env OCF_RESKEY_nic=$OCFT_target_nic
+ AgentRun start OCF_SUCCESS
+ Include check_ip_assigned
+ AgentRun monitor OCF_SUCCESS
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
+
+# CASE No.9
+#
+CASE "normal usage for a link-local IPv6 address, params with nic"
+ Include prepare
+ Env OCF_RESKEY_ip=$OCFT_target_linklocal
+ Env OCFT_check_ip=$OCFT_target_linklocal
+ # nic is mandatory for a link-local address
+ Env OCF_RESKEY_nic=$OCFT_target_nic
+ Env OCFT_check_nic=$OCFT_target_nic
+ AgentRun start OCF_SUCCESS
+ Include check_ip_assigned
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
+
+# CASE No.10
+#
+CASE "error params with wrong ip and nic (not exist base_ip)"
+ Include prepare
+ Include base_ip_removed
+ Env OCF_RESKEY_nic=$OCFT_target_nic
+ Env OCFT_check_nic=$OCFT_target_nic
+ AgentRun start OCF_ERR_GENERIC
+ Include check_ip_removed
+ Include base_ip_assigned
+
+# CASE No.11
+#
+CASE "params with force nic"
+ Include prepare
+ Env OCF_RESKEY_nic=$OCFT_force_nic
+ Env OCFT_check_nic=$OCFT_force_nic
+ AgentRun start OCF_ERR_GENERIC
+ Include check_ip_removed
+ Unenv OCF_RESKEY_nic
+
+# CASE No.12
+#
+CASE "params with force cidr_netmask"
+ Include prepare
+ Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix
+ Env OCFT_check_prefix=$OCFT_target_prefix
+ AgentRun start OCF_SUCCESS
+ Include check_ip_assigned
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
+
+# CASE No.13
+#
+CASE "params with force cidr_netmask (base netmask < assigned netmask)"
+ Include prepare
+ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix
+ Env OCFT_check_prefix=$OCFT_force_prefix
+ AgentRun start OCF_ERR_GENERIC
+ Include check_ip_removed
+
+# CASE No.14
+#
+CASE "params with force cidr_netmask (base netmask > assigned netmask)"
+ Include prepare
+ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2
+ Env OCFT_check_prefix=$OCFT_force_prefix2
+ AgentRun start OCF_ERR_GENERIC
+ Include check_ip_removed
+
+# CASE No.15
+#
+CASE "params with cidr_netmask"
+ Include prepare
+ Include base_ip_removed
+ Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix
+ Env OCFT_check_prefix=$OCFT_target_prefix
+ AgentRun start OCF_ERR_GENERIC
+ Include base_ip_assigned
+
+# CASE No.16
+#
+CASE "params with nic, cidr_netmask"
+ Include prepare
+ Env OCF_RESKEY_nic=$OCFT_target_nic
+ Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix
+ Env OCFT_check_nic=$OCFT_target_nic
+ Env OCFT_check_prefix=$OCFT_target_prefix
+ AgentRun start OCF_SUCCESS
+ Include check_ip_assigned
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
+
+# CASE No.17
+#
+CASE "force to use the specified nic and cidr_netmask (base netmask < assigned netmask)"
+ Include prepare
+ Env OCF_RESKEY_nic=$OCFT_force_nic
+ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix
+ Env OCFT_check_nic=$OCFT_force_nic
+ Env OCFT_check_prefix=$OCFT_force_prefix
+ AgentRun start OCF_SUCCESS
+ Include check_ip_assigned
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
+
+# CASE No.18
+# This use case is now valid. It was not allowed until v3.9.2.
+#
+CASE "force to use the specified nic and cidr_netmask (base netmask > assigned netmask)"
+ Include prepare
+ Env OCF_RESKEY_nic=$OCFT_force_nic
+ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2
+ Env OCFT_check_nic=$OCFT_force_nic
+ Env OCFT_check_prefix=$OCFT_force_prefix2
+ AgentRun start OCF_SUCCESS
+ Include check_ip_assigned
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
+
+# CASE No.19
+#
+CASE "force to use the specified nic and cidr_netmask (base netmask > assigned netmask)"
+ Include prepare
+ Include base_ip_removed
+ Env OCF_RESKEY_nic=$OCFT_force_nic
+ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2
+ Env OCFT_check_nic=$OCFT_force_nic
+ Env OCFT_check_prefix=$OCFT_force_prefix2
+ AgentRun start OCF_SUCCESS
+ Include check_ip_assigned
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
+ Include base_ip_assigned
+
diff --git a/tools/ocft/IPsrcaddr b/tools/ocft/IPsrcaddr
new file mode 100644
index 0000000..d95142e
--- /dev/null
+++ b/tools/ocft/IPsrcaddr
@@ -0,0 +1,63 @@
+# IPsrcaddr
+
+CONFIG
+ Agent IPsrcaddr
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ InstallPackage iproute2
+ HangTimeout 20
+
+CASE-BLOCK required_args
+ Env OCF_RESKEY_ipaddress= # put here your IP
+ Env OCF_RESKEY_cidr_netmask= # and the netmask
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include required_args
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: unset 'OCF_RESKEY_ipaddress'"
+ Include prepare
+ Unenv OCF_RESKEY_ipaddress
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "check base env: set invalid 'OCF_RESKEY_ipaddress'"
+ Include prepare
+ Env OCF_RESKEY_ipaddress=not_ip_address
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "monitor with running"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "monitor with not running"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
diff --git a/tools/ocft/IPv6addr b/tools/ocft/IPv6addr
new file mode 100644
index 0000000..36a9642
--- /dev/null
+++ b/tools/ocft/IPv6addr
@@ -0,0 +1,150 @@
+# IPv6addr
+
+# Note: This test case uses two NICs(eth0, eth1) and
+# a IPv6 address prefix (2001:db8::/32, RFC3849).
+# Adjust them according to your environment at VARIABLE section if needed.
+
+CONFIG
+ Agent IPv6addr
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ HangTimeout 20
+
+VARIABLE
+ OCFT_target_ipv6addr=2001:db8:1234::2
+ OCFT_target_nic=eth0
+ OCFT_target_prefix=64
+ OCFT_target_netaddr=2001:db8:1234::1/$OCFT_target_prefix
+ OCFT_target_linklocal=fe80::2
+ OCFT_wrong_ipv6addr=2001:db8:5678::2
+ OCFT_force_nic=eth1
+ OCFT_force_prefix=80
+
+SETUP-AGENT
+ ip addr add $OCFT_target_netaddr dev $OCFT_target_nic
+
+CLEANUP-AGENT
+ ip addr del $OCFT_target_netaddr dev $OCFT_target_nic
+
+CASE-BLOCK required_args
+ Env OCF_RESKEY_ipv6addr=$OCFT_target_ipv6addr
+ Env OCFT_check_ipv6addr=$OCFT_target_ipv6addr
+ Env OCFT_check_prefix=$OCFT_target_prefix
+ Env OCFT_check_nic=$OCFT_target_nic
+
+CASE-BLOCK check_ip_assigned
+ Bash ip -6 -o addr show $OCFT_check_nic | grep -w $OCFT_check_ipv6addr/$OCFT_check_prefix >/dev/null # checking if the IPv6 address was assigned correctly
+
+CASE-BLOCK check_ip_removed
+ Bash ! ip -6 -o addr show $OCFT_check_nic | grep -w $OCFT_check_ipv6addr/$OCFT_check_prefix >/dev/null # checking if the IPv6 address was removed correctly
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include required_args
+ Include default_status
+
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+ Include check_ip_assigned
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "monitor with running"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "monitor with not running"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "params with nic, no cidr_netmask"
+ Include prepare
+ Env OCF_RESKEY_nic=$OCFT_target_nic
+ AgentRun start OCF_SUCCESS
+ Include check_ip_assigned
+ AgentRun monitor OCF_SUCCESS
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
+
+CASE "params with nic, cidr_netmask"
+ Include prepare
+ Env OCF_RESKEY_nic=$OCFT_target_nic
+ Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix
+ AgentRun start OCF_SUCCESS
+ Include check_ip_assigned
+ AgentRun monitor OCF_SUCCESS
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
+
+CASE "normal usage for a link-local IPv6 address"
+ Include prepare
+ Env OCF_RESKEY_ipv6addr=$OCFT_target_linklocal
+ Env OCFT_check_ipv6addr=$OCFT_target_linklocal
+ # nic is mandatory for a link-local address
+ Env OCF_RESKEY_nic=$OCFT_target_nic
+ AgentRun start OCF_SUCCESS
+ Include check_ip_assigned
+ AgentRun monitor OCF_SUCCESS
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
+
+CASE "error start for a link-local IPv6 address when no nic"
+ Include prepare
+ Env OCF_RESKEY_ipv6addr=$OCFT_target_linklocal
+ # nic is mandatory for a link-local address
+ Unenv OCF_RESKEY_nic
+ AgentRun start OCF_ERR_GENERIC
+ Include check_ip_removed
+
+CASE "error params with wrong ipv6addr"
+ Include prepare
+ Env OCF_RESKEY_ipv6addr=$OCFT_wrong_ipv6addr
+ AgentRun start OCF_ERR_GENERIC
+
+# Note: this result is different from IPaddr2/findif
+# IPaddr2 succeeds if the ip matched based on the netmask of the subnet
+# or fails if it did not match to any.
+# Recommended to always specify both nic and cidr_netmask when you needed.
+CASE "error params with wrong cidr_netmask"
+ Include prepare
+ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix
+ AgentRun start OCF_ERR_GENERIC
+
+# Note: this result is different from IPaddr2/findif
+# IPaddr2 succeeds but it uses /32 as a guessed cidr_netmask which
+# does not seem to be expected.
+# Recommended to always specify both nic and cidr_netmask when you needed.
+CASE "error params with wrong nic"
+ Include prepare
+ Env OCF_RESKEY_nic=$OCFT_force_nic
+ AgentRun start OCF_ERR_GENERIC
+
+# Note: This use case is now valid. It was not allowed until v3.9.2.
+CASE "force to use the specified nic and cidr_netmask"
+ Include prepare
+ Env OCF_RESKEY_nic=$OCFT_force_nic
+ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix
+ Env OCFT_check_nic=$OCFT_force_nic
+ Env OCFT_check_prefix=$OCFT_force_prefix
+ AgentRun start OCF_SUCCESS
+ Include check_ip_assigned
+ AgentRun monitor OCF_SUCCESS
+ AgentRun stop OCF_SUCCESS
+ Include check_ip_removed
diff --git a/tools/ocft/LVM b/tools/ocft/LVM
new file mode 100644
index 0000000..00b69ee
--- /dev/null
+++ b/tools/ocft/LVM
@@ -0,0 +1,83 @@
+# LVM
+# by dejan@suse.de on
+# Wed Feb 16 13:15:01 CET 2011
+
+CONFIG
+ Agent LVM
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ HangTimeout 20
+
+VARIABLE
+ OCFT_rundir="`get_rundir`"
+ OCFT_pv=$OCFT_rundir/resource-agents/ocft-LVM-pv
+ OCFT_vg=ocft-vg
+ OCFT_lv=ocft-lv
+ OCFT_loop="`loopbackeddev make $OCFT_pv 16M`"
+
+SETUP-AGENT
+ pvcreate $OCFT_loop
+ vgcreate -s 4K $OCFT_vg $OCFT_loop
+ lvcreate -n $OCFT_lv -L 600K $OCFT_vg
+
+CLEANUP-AGENT
+ vgchange -an $OCFT_vg
+ lvremove -f /dev/$OCFT_vg/$OCFT_lv
+ vgremove -f $OCFT_vg
+ pvremove $OCFT_loop
+ loopbackeddev unmake $OCFT_pv
+
+CASE-BLOCK required_args
+ Env OCF_RESKEY_volgrpname=$OCFT_vg
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include required_args
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: invalid 'OCF_RESKEY_volgrpname'"
+ Include prepare
+ Env OCF_RESKEY_volgrpname=/dev/no_such_device
+ AgentRun start OCF_ERR_GENERIC
+
+CASE "check base env: unset 'OCF_RESKEY_volgrpname'"
+ Include prepare
+ Unenv OCF_RESKEY_volgrpname
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "monitor when running"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "monitor when not running"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
+
diff --git a/tools/ocft/MailTo b/tools/ocft/MailTo
new file mode 100644
index 0000000..8754035
--- /dev/null
+++ b/tools/ocft/MailTo
@@ -0,0 +1,57 @@
+# MailTo
+
+CONFIG
+ Agent MailTo
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ InstallPackage mailx
+ HangTimeout 20
+
+CASE-BLOCK required_args
+ Env OCF_RESKEY_email=root@localhost
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include required_args
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: unset 'OCF_RESKEY_email'"
+ Include prepare
+ Unenv OCF_RESKEY_email
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "monitor with running"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "monitor with not running"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
diff --git a/tools/ocft/Makefile.am b/tools/ocft/Makefile.am
new file mode 100644
index 0000000..69c59ee
--- /dev/null
+++ b/tools/ocft/Makefile.am
@@ -0,0 +1,63 @@
+# Author: John Shi
+# jshi@suse.de
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+MAINTAINERCLEANFILES = Makefile.in
+
+EXTRA_DIST = $(ocftcfgs_DATA) $(ocft_DATA) $(ocft_SCRIPTS)
+
+sbin_SCRIPTS = ocft
+
+ocftcfgsdir = $(datadir)/$(PACKAGE_NAME)/ocft/configs
+ocftcfgs_DATA = apache \
+ IPaddr2 \
+ IPaddr2v4 \
+ IPaddr2v6 \
+ IPv6addr \
+ Filesystem \
+ LVM \
+ Raid1 \
+ IPsrcaddr \
+ MailTo \
+ jboss \
+ mysql \
+ mysql-proxy \
+ pgsql \
+ db2 \
+ oracle \
+ drbd.linbit \
+ exportfs \
+ exportfs-multidir \
+ nfsserver \
+ portblock \
+ iscsi \
+ named \
+ postfix \
+ sg_persist \
+ tomcat \
+ Xinetd \
+ Xen \
+ VirtualDomain \
+ SendArp
+
+ocftdir = $(datadir)/$(PACKAGE_NAME)/ocft
+ocft_DATA = README \
+ README.zh_CN \
+ caselib \
+ helpers.sh \
+ runocft.prereq
+ocft_SCRIPTS = runocft
+
diff --git a/tools/ocft/README.in b/tools/ocft/README.in
new file mode 100644
index 0000000..1c4ae12
--- /dev/null
+++ b/tools/ocft/README.in
@@ -0,0 +1,147 @@
+INTRODUCTION & DESIGN
+~~~~~~~~~~~~~~~~~~~~~
+
+ - Ocft is a testing tool for resource agents. Instead of the policy of HA,
+ it mainly concerns whether resource agents run correct locally. It can
+ design types of complicated environments to test the reliability of
+ resource agents. Precisely, it is to display whether resource agents can
+ return to correct or expected value. The advantage of the tool provides
+ us with competence to design conditions which can be recorded or reproduced.
+ Hence it is useful to debuggers.
+
+* Components
+ ** Test case generator (@sbindir@/ocft)
+ - Turning configuration files of test case to executable scripts.
+
+ ** Configuration file (@datadir@/@PACKAGE_NAME@/ocft/configs/)
+ - Every configuration file directs only one resource agent and share the same
+ name with resource agent but contains more test cases.
+
+ ** The testing script (/var/lib/@PACKAGE_NAME@/ocft/cases/)
+ - After the generator reads configuration files and generates many testing
+ scripts and the script is underway, the test begins.
+
+* How to customize the environment of testing
+ - Ocft designs the running conditions through two ways, one is changing the
+ environment variables of resource agents (it is the interface left by OCF itself),
+ the other is modifying the OS environment of resource agents, such as altering
+ the permission of some key file or IP address of the machine.
+
+* How to test
+ - Firstly, you need to sketch the all complex and uncommon environments against
+ a certain resource agent and keep in mind what consequences may be caused by
+ these uncommon environments.
+ Secondly, write the designed conditions and foreknown consequences into
+ configuration files, and then run the generator to translate the test case to
+ executable scripts.
+ Finally, you need running these scripts to observe the output and learn
+ the running status of each test case, which will compares the predicated result
+ with the actual one. If they differ, you will be able to find the bugs of the
+ resource agent.
+ - All of the output with test will be recorded into the log files, you can find them
+ in /var/lib/@PACKAGE_NAME@/ocft/cases/logs.
+
+
+HOW TO WRITE CONFIGURATION FILE
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ - There are only 6 top level options that are all spelled by capital letters and "-".
+ Every top level option contains sub-options that they are initials.
+
+* 'CONFIG' (top level option)
+ - Grammar: CONFIG
+ - The design in this option is global and influences every test case.
+
+ ** 'Agent' (sub-option)
+ - Grammar: Agent AGENT_NAME
+ - The agent name you want to test.
+
+ ** 'AgentRoot' (sub-option)
+ - Grammar: AgentRoot /usr/lib/ocf/resource.d/xxx
+ - A few agents will go to "linbit" or "pacemaker" directory, if you define this option,
+ ocft will use it to replace the default directory "heartbeat".
+
+ ** 'InstallPackage' (sub-option)
+ - Grammar: InstallPackage package [package2 [...]]
+ - It will test whether the system have installed the service of the resource agent.
+ If not, it will download from Internet and have it installed automatically.
+
+ ** 'HangTimeout' (sub-option)
+ - Grammar: HangTimeout secs
+ - If you alter some key options, some resource agents will get puzzled and stop,
+ which will influence the running of the following test case. Hence timeout setting is
+ needed, if the resource agent stops timeout, the scripts will kill this resource agent.
+
+* 'VARIABLE' (top level option)
+ - Grammar:
+ VARIABLE
+ VAR1=value1
+ VAR2=value2
+ ...
+ - Define the global variable here, the variables can be visited everywhere, they can be referenced
+ using $VAR_NAME. Note, the variables in VARIABLE are different from 'Env VAR1=value1', 'Env' can
+ affect the activity of agent, but the variables in VARIABLE just be shared with top level option.
+
+* 'SETUP-AGENT' (top level option)
+ - Grammar:
+ SETUP-AGENT
+ bash scripts...
+ ...
+ - Some of Agents may need to be initialized before testing, you can do it here with bash script.
+
+* 'CLEANUP-AGENT' (top level option)
+ - Grammar:
+ CLEANUP-AGENT
+ bash scripts...
+ ...
+ - If SETUP-AGENT set, usually you might be use this option do some cleaning work after test.
+
+* 'CASE' & 'CASE-BLOCK' (top level option)
+ - Grammar: CASE "description" & CASE-BLOCK macro_name
+ - Usually, the conditions you designed are more than one and a few 'CASE "..."' will
+ appear in configuration file. It is worth noting that the following sub-options
+ have 2 spellings:
+ One is general, where shell affects the local environment; the other is special,
+ where each options added "@ipaddr". It can remotely execute shell codes. In other words,
+ it is to execute the shell codes from a remote host, which is meaningful when a resource
+ agent needs 2 hosts. This remote shell is not a remote execution only through "ssh", but
+ running a remote shell in the background while the test case is running. The remote shell
+ runs in the background till the end and saves the results during the process. That is to
+ say, you can alternatively carry out local and remote shell code segments.
+ The "CASE-BLOCK" option is a macro definer, the statements in "CASE-BLOCK" will be inserted
+ into "CASE" if you "Include" the "macro_name".
+
+ ** 'Env' (sub-option)
+ - Grammar: Env VARIABLE=value
+ - It is to set up an environment variable of the resource agent. They usually appear to
+ be OCF_RESKEY_xxx. One point is to be noted is there is no blank by both sides of "=".
+
+ ** 'Unenv' (sub-option)
+ - Grammar: Unenv VARIABLE [VARIABLE2 [...]]
+ - Remove the environment variable.
+
+ ** 'Include' (sub-option)
+ - Grammar: Include macro_name
+ - It will be replaced by statements in 'macro_name', of course, you should define the
+ content of 'macro_name' with 'CASE-BLOCK' first.
+
+ ** 'Bash' (sub-option)
+ - Grammar: Bash bash_codes
+ - This option is to set up the environment of OS, where you can insert BASH code to
+ customize the system randomly. Note, do not cause unrecoverable consequences to the
+ system.
+
+ ** 'BashAtExit' (sub-option)
+ - Grammar: BashAtExit bash_codes
+ - This option is to recover the OS environment in order to run another test case
+ correctly. Of cause you can use 'Bash' option to recover it. However, if mistakes occur
+ in the process, the script will quit directly instead of running your recovery codes.
+ If it happens, you ought to use BashAtExit which can restore the system environment
+ before you quit.
+
+ ** 'AgentRun' (sub-option)
+ - Grammar: AgentRun cmd [ret_value]
+ - This option is to run resource agent. "cmd" is the parameter of the resource agent,
+ such as "start, status, stop ...". The second parameter is optional. It will compare the
+ actual returned value with the expected value when the script has run recourse agent.
+ If differs, bugs will be found.
diff --git a/tools/ocft/README.zh_CN.in b/tools/ocft/README.zh_CN.in
new file mode 100644
index 0000000..5138cf1
--- /dev/null
+++ b/tools/ocft/README.zh_CN.in
@@ -0,0 +1,124 @@
+1 介绍和设计
+ocft是一个测试resource agents的工具。它并不关注HA的策略,而是关注resource agents
+是否正常运行在本机。他能对resource agents设计各种复杂环境,来考验resource agnets
+是否能正常应对,也就是看resouce agents是否能返回正确的或者说我们所期望的值。
+这个工具给我们带来的好处就是我们可以集中的批量的来设计环境,而且这种环境是可被我们
+记录、重现的,对Debug人员来说是很有用的。
+
+1.1 组成
+1.1.1 解释器 (@sbindir@/ocft)
+将test case配置文件转换成可执行的测试脚本。
+
+1.1.2 配置文件 (@datadir@/@PACKAGE_NAME@/ocft/configs/)
+每一个configuration file只针对一个resouce agent,配置文件名与resouce agent名相同,
+但是它可以容纳很多test case。
+
+1.1.3 测试脚本 (/var/lib/@PACKAGE_NAME@/ocft/cases/)
+由generator读取configuration file生成测试脚本,直接运行此脚本就可以开始测试了。
+
+1.2 如何定制环境
+ocft 通过两种手段来设计resouce agents的运行环境,一是更改resouce agents的环境变量,
+当然这是ocf本身就留给我们的接口。二是更改resource agents所处的系统环境,
+比如更改某个关键文件的权限,更改本机ip地址等等...
+
+1.3 如何进行测试
+首先你需要针对某个resource agent在脑中勾画各种复杂且异常的环境,并且你能清楚预知
+这些异常环境会给resource agent带来什么结果,然后将这些设计好的环境和你预知的结果
+都写入配置文件,然后运行generator,将你刚写的test case转换成可执行的脚本。最后运行
+这些脚本,观察它们的输出,你可以清楚看到每个test case运行状况,他会比较你的预知结
+果和resource agent的实际结果,如果不一样,说明你找到resource agent的bug了。
+所有的测试输出都会被记录到日志文件中,你可以在 /var/lib/@PACKAGE_NAME@/ocft/cases/logs
+中找到他们.
+
+2 配置
+只有6个top level option,它们是由大写字母和'-'构成的,每个top level option都有若干sub-option,
+它们是首字母大写。
+
+2.1 'CONFIG' 选项
+语法:CONFIG
+此option中的设计是全局的,对每个test case都有所影响。
+
+2.1.1 'Agent' 选项
+语法:Agent AGENT_NAME
+你要测试的Agent的名字。
+
+2.1.2 'AgentRoot' 选项
+语法:AgentRoot /usr/lib/ocf/resource.d/xxx
+一些agent将会被移到 "pacemaker" 或 "linbit" 目录,如果你定义了这个选项,ocft将会用它来
+替代默认的目录"heartbeat"。
+
+2.1.3 'InstallPackage' 选项
+语法:InstallPackage package [package2 [...]]
+他会检测系统是否安装了此resource agent的service,如果没有安装,会自动从网络进行安装。
+package_name是某个resouce agent在操作系统中必须安装的包。
+
+2.1.4 'HangTimeout' 选项
+语法:HangTimeout secs
+如果你更改了一些很关键的东西,有些resouce agent会不知所措,停在那里不动,那么就会影响
+到后面test case的运行,所以你需要设定超时,如果一旦resouce agent停在那超时了,脚本会
+杀死这个resouce agent。
+
+2.2 'VARIABLE' 选项
+语法:
+VARIABLE
+ VAR1=value1
+ VAR2=value2
+ ...
+在此定义全局变量,这些变量可以用于配置文件中的任何地方,引用时在变量名前加上$。请注意,这些
+变量不同于Env定义的变量,Env是定义环境变量,可以改变agent的行为,而这些变量只是用于配置文件中
+共享。
+
+2.3 'SETUP-AGENT' 选项
+语法:
+SETUP-AGENT
+ bash scripts...
+ ...
+一些Agent在测试前可能需要初始化,你可以用bash脚本在这初始化。
+
+2.4 'CLEANUP-AGENT' 选项
+语法:
+CLEANUP-AGENT
+ bash scripts...
+ ...
+如果之前定义了SETUP-AGENT, 你可能还需要此选项在测试完后来作一些清除。
+
+2.5 'CASE' & 'CASE-BLOCK' 选项
+语法:CASE "description" & CASE-BLOCK macro_name
+通常你设计的环境不止一个,那么配置文件中应该会出现许多 'CASE "..."',值得注意的是,以下子
+选项每个都有两种写法,一是普通写法,产生的shell代码对本地产生作用,二是特殊写法,就是在每
+个选项后加上 "@ipaddr",他可以远程执行shell代码,也就是控制远程机器执行你给的shell代码,
+这对需要两台机器以上的resouce agent很有用的,这个远程shell并非简单的用ssh去远程执行,而是在
+test case生存期内,后台运行一个远程shell,他始终在后台运行并且保存你的中间结果,也就是说你
+可以交替执行本地shell代码段和远程shell代码段。
+'CASE-BLOCK'选项是一个宏定义器,它定义的内容将会被插入到"CASE"内容中。
+
+2.5.1 'Env' 选项
+语法:Env VARIABLE=value
+这是设置resouce agent的环境变量,他们通常是OCF_RESKEY_xxx,注意=号两边不要有空格。
+
+2.5.2 'Unenv' 选项
+语法:Unenv VARIABLE
+此选项用于删除环境变量。
+
+2.5.3 'Include' 选项
+语法:Include macro_name
+此选项将会被宏"macro_name"的内容所替代,当然,你得预先用"CASE-BLOCK"来定义宏"macro_name"
+的内容。
+
+2.5.4 'Bash' 选项
+语法:Bash bash_codes
+此选项是用来设置os的环境,你可以嵌入bash代码来对系统作任意设置,不过要注意不要对系统造成
+不可恢复的后果就行了。
+
+2.5.5 'BashAtExit' 选项
+语法:BashAtExit bash_codes
+此选项是用来恢复os的环境,以便另一个test case能正常运行,当然你也可以直接用'Bash'选项来
+恢复,但是如果脚本在执行过程中产生某些错误,那么脚本会直接退出,而不会去执行你的恢复代码,
+那么你就要用到BashAtExit,他能在你退出前去恢复系统环境。
+
+2.5.6 'AgentRun' 选项
+语法:AgentRun cmd [ret_value]
+此option会去运行resouce agent,'cmd' 就是resouce agent的参数,如 start,status,stop ...
+第二个参数是可选的,它是你对系统环境作出特殊设定以后,你预计resouce agent会返回的值,
+如果给出此参数,那么脚本会在运行resouce agent后,会比较此时的返回值和你预期的返回值,
+如果不一致,那么说明找到bug了。
diff --git a/tools/ocft/Raid1 b/tools/ocft/Raid1
new file mode 100644
index 0000000..462b9b9
--- /dev/null
+++ b/tools/ocft/Raid1
@@ -0,0 +1,134 @@
+# Raid1
+# by dejan@suse.de on
+# Fri Aug 24 17:01:40 CEST 2012
+
+CONFIG
+ Agent Raid1
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ InstallPackage mdadm
+ HangTimeout 20
+
+VARIABLE
+ OCFT_rundir="`get_rundir`"
+ OCFT_disk0=$OCFT_rundir/resource-agents/ocft-Raid1-disk0
+ OCFT_disk1=$OCFT_rundir/resource-agents/ocft-Raid1-disk1
+ OCFT_disk2=$OCFT_rundir/resource-agents/ocft-Raid1-disk2
+ OCFT_disk3=$OCFT_rundir/resource-agents/ocft-Raid1-disk3
+ OCFT_raidconf=$OCFT_rundir/resource-agents/ocft-mdadm.conf
+ OCFT_raiddev=/dev/md8
+ OCFT_raiddev2=/dev/md9
+ OCFT_loop0="`loopbackeddev make $OCFT_disk0 16M`"
+ OCFT_loop1="`loopbackeddev make $OCFT_disk1 16M`"
+ OCFT_loop2="`loopbackeddev make $OCFT_disk2 16M`"
+ OCFT_loop3="`loopbackeddev make $OCFT_disk3 16M`"
+
+SETUP-AGENT
+ mdadm --create $OCFT_raiddev -l 0 --raid-devices=2 $OCFT_loop0 $OCFT_loop1
+ mdadm --create $OCFT_raiddev2 -l 0 --raid-devices=2 $OCFT_loop2 $OCFT_loop3
+ echo DEVICE $OCFT_loop0 $OCFT_loop1 > $OCFT_raidconf
+ echo DEVICE $OCFT_loop2 $OCFT_loop3 >> $OCFT_raidconf
+ echo ARRAY $OCFT_raiddev devices=$OCFT_loop0,$OCFT_loop1 >> $OCFT_raidconf
+ echo ARRAY $OCFT_raiddev2 devices=$OCFT_loop2,$OCFT_loop3 >> $OCFT_raidconf
+
+CLEANUP-AGENT
+ mdadm --zero-superblock $OCFT_loop0
+ mdadm --zero-superblock $OCFT_loop1
+ mdadm --zero-superblock $OCFT_loop2
+ mdadm --zero-superblock $OCFT_loop3
+ mdadm --remove $OCFT_raiddev 2>/dev/null
+ mdadm --remove $OCFT_raiddev2 2>/dev/null
+ loopbackeddev unmake $OCFT_disk0
+ loopbackeddev unmake $OCFT_disk1
+ loopbackeddev unmake $OCFT_disk2
+ loopbackeddev unmake $OCFT_disk3
+ rm -f $OCFT_raidconf
+
+CASE-BLOCK required_args
+ Env OCF_RESKEY_raidconf=$OCFT_raidconf
+ Env OCF_RESKEY_raiddev=$OCFT_raiddev
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include required_args
+ Include default_status
+
+CASE-BLOCK prepare_auto
+ Include required_args
+ Env OCF_RESKEY_raiddev="auto"
+ Include default_status
+
+CASE-BLOCK prepare_multiple
+ Include required_args
+ Env OCF_RESKEY_raiddev="$OCFT_raiddev $OCFT_raiddev2"
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: invalid 'OCF_RESKEY_raiddev'"
+ Include prepare
+ Env OCF_RESKEY_raiddev=/dev/no_such_device
+ AgentRun start OCF_ERR_GENERIC
+
+CASE "check base env: unset 'OCF_RESKEY_raiddev'"
+ Include prepare
+ Unenv OCF_RESKEY_raiddev
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "monitor when running"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "monitor when not running"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "normal start (auto)"
+ Include prepare_auto
+ AgentRun start OCF_SUCCESS
+ AgentRun monitor OCF_SUCCESS
+
+CASE "normal stop (auto)"
+ Include prepare_auto
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "normal start (multiple)"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+ AgentRun monitor OCF_SUCCESS
+
+CASE "normal stop (multiple)"
+ Include prepare
+ Env OCF_RESKEY_raiddev="$OCFT_raiddev $OCFT_raiddev2"
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
+
diff --git a/tools/ocft/SendArp b/tools/ocft/SendArp
new file mode 100644
index 0000000..7880388
--- /dev/null
+++ b/tools/ocft/SendArp
@@ -0,0 +1,74 @@
+# SendArp
+
+CONFIG
+ Agent SendArp
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ InstallPackage resource-agents
+ HangTimeout 15
+
+CASE-BLOCK required_args
+ Env OCF_RESKEY_ip=127.0.0.1
+ Env OCF_RESKEY_nic=lo
+ Env OCF_RESKEY_background=false
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include required_args
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: unset 'OCF_RESKEY_ip'"
+ Include prepare
+ Unenv OCF_RESKEY_ip
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "check base env: set invalid 'OCF_RESKEY_ip'"
+ Include prepare
+ Env OCF_RESKEY_ip=not_ip_address
+ AgentRun start OCF_ERR_GENERIC
+
+CASE "check base env: unset 'OCF_RESKEY_nic'"
+ Include prepare
+ Unenv OCF_RESKEY_nic
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "check base env: set invalid 'OCF_RESKEY_nic'"
+ Include prepare
+ Env OCF_RESKEY_nic=not_nic
+ AgentRun start OCF_ERR_GENERIC
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "monitor with running"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "monitor with not running"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
diff --git a/tools/ocft/VirtualDomain b/tools/ocft/VirtualDomain
new file mode 100644
index 0000000..3a44f20
--- /dev/null
+++ b/tools/ocft/VirtualDomain
@@ -0,0 +1,71 @@
+# VirtualDomain
+# by dejan@suse.de on
+# Tue Jul 8 12:48:03 CEST 2014
+
+CONFIG
+ Agent VirtualDomain
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ HangTimeout 20
+
+# set OCFT_config to the libvirt configuration file
+# the guest is going to be stopped and started
+VARIABLE
+ OCFT_config=/etc/libvirt/qemu/sle11-sp3.xml
+
+CASE-BLOCK required_args
+ Env OCF_RESKEY_config=$OCFT_config
+
+CASE-BLOCK unset_utilization
+ Env OCF_RESKEY_autoset_utilization_host_memory=false
+ Env OCF_RESKEY_autoset_utilization_hv_memory=false
+ Env OCF_RESKEY_autoset_utilization_cpu=false
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include required_args
+ Include unset_utilization
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: invalid 'OCF_RESKEY_config'"
+ Include prepare
+ Env OCF_RESKEY_config=/no_such_file
+ AgentRun start OCF_ERR_INSTALLED
+
+CASE "check base env: unset 'OCF_RESKEY_config'"
+ Include prepare
+ Unenv OCF_RESKEY_config
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "monitor when running"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "monitor when not running"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
+
diff --git a/tools/ocft/Xen b/tools/ocft/Xen
new file mode 100644
index 0000000..731564b
--- /dev/null
+++ b/tools/ocft/Xen
@@ -0,0 +1,65 @@
+# Xen
+# by dejan@suse.de on
+# Tue Jul 8 12:20:23 CEST 2014
+
+CONFIG
+ Agent Xen
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ HangTimeout 20
+
+# set OCFT_xmfile to the xen-xm format file
+# the guest is going to be stopped and started
+VARIABLE
+ OCFT_xmfile=/etc/xen/vm/xen-f
+
+CASE-BLOCK required_args
+ Env OCF_RESKEY_xmfile=$OCFT_xmfile
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include required_args
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: invalid 'OCF_RESKEY_xmfile'"
+ Include prepare
+ Env OCF_RESKEY_xmfile=/no_such_file
+ AgentRun start OCF_ERR_INSTALLED
+
+CASE "check base env: unset 'OCF_RESKEY_xmfile'"
+ Include prepare
+ Unenv OCF_RESKEY_xmfile
+ AgentRun start OCF_ERR_INSTALLED
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "monitor when running"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "monitor when not running"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
+
diff --git a/tools/ocft/Xinetd b/tools/ocft/Xinetd
new file mode 100644
index 0000000..53f4f65
--- /dev/null
+++ b/tools/ocft/Xinetd
@@ -0,0 +1,64 @@
+# Xinetd
+
+CONFIG
+ Agent Xinetd
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ InstallPackage xinetd
+
+SETUP-AGENT
+ sed -i /disable/s/yes/no/ /etc/xinetd.d/echo
+ if which /etc/init.d/xinetd >/dev/null 2>&1; then
+ /etc/init.d/xinetd start
+ elif systemctl list-unit-files | grep -qs xinetd; then
+ systemctl start xinetd
+ fi
+
+CASE-BLOCK required_args
+ Env OCF_RESKEY_service=discard
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include required_args
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: unset 'OCF_RESKEY_protocol'"
+ Include prepare
+ Unenv OCF_RESKEY_service
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "monitor with running"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "monitor with not running"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
diff --git a/tools/ocft/apache b/tools/ocft/apache
new file mode 100644
index 0000000..fe4f193
--- /dev/null
+++ b/tools/ocft/apache
@@ -0,0 +1,68 @@
+# apache
+# make sure that your apache configuration loads mod_status
+
+CONFIG
+ Agent apache
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ InstallPackage apache2
+ HangTimeout 20
+
+SETUP-AGENT
+ if systemctl list-unit-files 2>/dev/null | fgrep -q apache2.service; then
+ systemctl start apache2.service
+ systemctl stop apache2.service
+ else
+ /etc/init.d/apache2 start
+ /etc/init.d/apache2 stop
+ fi
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: set non-existing OCF_RESKEY_statusurl"
+ Include prepare
+ Env OCF_RESKEY_statusurl="yoyoyoyo"
+ AgentRun start OCF_ERR_GENERIC
+
+CASE "check base env: set non-existing OCF_RESKEY_configfile"
+ Include prepare
+ Env OCF_RESKEY_configfile="/yoyoyoyo/nosuchfile"
+ AgentRun start OCF_ERR_INSTALLED
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "running monitor"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "not running monitor"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
diff --git a/tools/ocft/caselib.in b/tools/ocft/caselib.in
new file mode 100644
index 0000000..44165d6
--- /dev/null
+++ b/tools/ocft/caselib.in
@@ -0,0 +1,299 @@
+#
+# Copyright (c) 2010-2011 Novell Inc, John Shi
+# All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Further, this software is distributed without any warranty that it is
+# free of the rightful claim of any third person regarding infringement
+# or the like. Any license provided herein, whether implied or
+# otherwise, applies only to this software file. Patent licenses, if
+# any, provided herein do not apply to combinations of this program with
+# other software, or any other product whatsoever.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+
+
+quit()
+{
+ local ret
+ ret="$1"
+
+ while [ $__OCFT__atexit_num -gt 0 ]; do
+ atexit$__OCFT__atexit_num
+ let __OCFT__atexit_num--
+ done
+
+ rm -rf $__OCFT__fakebin
+
+ exit $ret
+}
+
+agent_install()
+{
+ local pkg
+
+ if [ $# -eq 0 ]; then
+ return 0
+ fi
+
+ for pkg in "$@"; do
+ if [ -e /etc/SuSE-release ]; then
+ if ! zypper -q install -y "$pkg" >/dev/null 2>&1; then
+ echo
+ echo "${__OCFT__showhost}ERROR: Install '$pkg' failed."
+ quit 2
+ fi
+ elif [ -e /etc/debian_version ]; then
+ if ! apt-get -y install "$pkg" >/dev/null 2>&1; then
+ echo
+ echo "${__OCFT__showhost}ERROR: Install '$pkg' failed."
+ quit 2
+ fi
+ elif [ -e /etc/redhat-release ]; then
+ if ! yum -y install "$pkg" >/dev/null 2>&1; then
+ echo
+ echo "${__OCFT__showhost}ERROR: Install '$pkg' failed."
+ quit 2
+ fi
+ else
+ echo "${__OCFT__showhost}ERROR: Cannot detect your OS type."
+ quit 2
+ fi
+ done
+}
+
+set_ocf_env()
+{
+ export OCF_RA_VERSION_MAJOR=1
+ export OCF_RA_VERSION_MINOR=0
+ export OCF_RESOURCE_TYPE=$1
+ export OCF_RESOURCE_INSTANCE=${OCF_RESOURCE_INSTANCE:-"ocft"}
+}
+
+agent_run()
+{
+ local agent cmd timeout pid i ret aroot
+ agent="$1"
+ cmd="$2"
+ timeout="$3"
+
+ set_ocf_env $agent
+
+ export OCF_RESKEY_CRM_meta_timeout
+ : ${OCF_RESKEY_CRM_meta_timeout:=$((timeout*1000))}
+
+ aroot=${__OCFT__MYROOT:-$__OCFT__AGENT_ROOT}
+
+ setsid $aroot/$agent $cmd >${HA_RSCTMP}/.ocft_runlog 2>&1 &
+ pid=$!
+
+ i=0
+ while [ $i -lt $timeout ]; do
+ if [ ! -e /proc/$pid ]; then
+ break
+ fi
+ sleep 1
+ let i++
+ done
+
+ if [ $i -ge $timeout ]; then
+ kill -SIGTERM -$pid >/dev/null 2>&1
+ sleep 3
+ kill -SIGKILL -$pid >/dev/null 2>&1
+ echo -n "${__OCFT__showhost}ERROR: The agent was hanging, killed it, "
+ echo "maybe you damaged the agent or system's environment, see details below:"
+ cat ${HA_RSCTMP}/.ocft_runlog
+ echo
+ quit 1
+ fi
+
+ wait $pid
+}
+
+check_success()
+{
+ local ret msg
+ ret="$1"
+ msg="$2"
+
+ if [ $ret -ne 0 ]; then
+ echo "${__OCFT__showhost}ERROR: '${msg}' failed, the return code is ${ret}."
+ quit 1
+ fi
+}
+
+__maxfd()
+{
+ (echo 0; ls -1 /proc/$$/fd) | sort -rn | head -1
+}
+
+__getfd()
+{
+ local host rw fd file
+ host="$1"
+ rw="$2"
+
+ for fd in /proc/$$/fd/*; do
+ file=$(basename "$(readlink $fd)")
+ if [ "$file" = "${host}_$rw" ]; then
+ basename $fd
+ break
+ fi
+ done
+}
+
+backbash_start()
+{
+ local host fd rfd wfd
+ host="$1"
+
+ if [ ! -d "$__OCFT__CASES_DIR" ]; then
+ echo "${__OCFT__showhost}ERROR: Could not found Directory: ${__OCFT__CASES_DIR}."
+ quit 1
+ fi
+
+ if lsof $__OCFT__CASES_DIR/${host}_r $__OCFT__CASES_DIR/${host}_w >/dev/null 2>&1; then
+ echo "${__OCFT__showhost}ERROR: Connection exist with $host."
+ quit 1
+ fi
+ if [ ! -p "$__OCFT__CASES_DIR/${host}_r" ] || [ ! -p "$__OCFT__CASES_DIR/${host}_w" ]; then
+ rm -f $__OCFT__CASES_DIR/${host}_r $__OCFT__CASES_DIR/${host}_w
+ if ! mkfifo $__OCFT__CASES_DIR/${host}_r $__OCFT__CASES_DIR/${host}_w >/dev/null 2>&1; then
+ echo "${__OCFT__showhost}ERROR: Could not create pipe file: $__OCFT__CASES_DIR/${host}_*."
+ quit 1
+ fi
+ fi
+
+ ssh root@$host '@BASH_SHELL@ 2>&1
+ sed "s/00/001/g" ${HA_RSCTMP}/.backbash-log
+ echo 000
+ echo 1' >$__OCFT__CASES_DIR/${host}_r <$__OCFT__CASES_DIR/${host}_w &
+
+ fd=$(__maxfd)
+ rfd=$(expr $fd + 1)
+ wfd=$(expr $fd + 2)
+ eval "exec ${rfd}<$__OCFT__CASES_DIR/${host}_r ${wfd}>$__OCFT__CASES_DIR/${host}_w"
+}
+
+backbash()
+{
+ local host rfd wfd ret
+ host="$1"
+
+ rfd=$(__getfd $host r)
+ wfd=$(__getfd $host w)
+
+ if [ -z "$rfd" -o -z "$wfd" ]; then
+ echo "${__OCFT__showhost}ERROR: Could not found connection with $host."
+ fi
+
+ cat >&$wfd <<EOF
+{
+true
+EOF
+ cat >&$wfd
+ cat >&$wfd <<EOF
+
+} >&${HA_RSCTMP}/.backbash-log
+sed 's/00/001/g' ${HA_RSCTMP}/.backbash-log
+echo 000
+echo 0
+EOF
+ if [ $? -ne 0 ]; then
+ echo "${__OCFT__showhost}ERROR: Broken connection with $host."
+ quit 1
+ fi
+
+ awk -vlive=2 '{
+ if (sub(/000$/, "")) {
+ if ($0 != "") {
+ gsub("001", "00");
+ printf("%s", $0);
+ }
+ getline live;
+ exit;
+ }
+ gsub("001", "00");
+ print;
+ } END {
+ exit(live);
+ }' <&$rfd
+ case $? in
+ 1)
+ quit 1
+ ;;
+ 2)
+ echo "${__OCFT__showhost}ERROR: Broken connection with $host."
+ quit 1
+ ;;
+ esac
+}
+
+backbash_stop()
+{
+ local host rfd wfd
+ host="$1"
+
+ wfd=$(__getfd $host w)
+ if [ -n "$wfd" ]; then
+ cat >&$wfd <<<'quit 0'
+ fi
+ rm -f $__OCFT__CASES_DIR/${host}_r $__OCFT__CASES_DIR/${host}_w
+}
+
+
+export OCF_ROOT=@OCF_ROOT_DIR@
+export OCF_LIB=@OCF_LIB_DIR@/heartbeat
+__OCFT__AGENT_ROOT=@OCF_RA_DIR@/heartbeat
+__OCFT__CASES_DIR=/var/lib/@PACKAGE_NAME@/ocft/cases
+OCFT_DIR=@datadir@/@PACKAGE_NAME@/ocft
+
+. $OCFT_DIR/helpers.sh
+
+__OCFT__atexit_num=0
+
+if [ $EUID -ne 0 ]; then
+ echo "${__OCFT__showhost}ERROR: '$0' needs to be run by root."
+ quit 3
+fi
+
+__OCFT__fakebin=./fakebin
+
+mkdir -p $__OCFT__fakebin >/dev/null 2>&1 &&
+ln -sf /bin/true $__OCFT__fakebin/crm_master >/dev/null 2>&1 &&
+ln -sf /bin/true $__OCFT__fakebin/crm_mon >/dev/null 2>&1
+if [ $? -ne 0 ]; then
+ echo "${__OCFT__showhost}ERROR: initialize 'fakebin' failed."
+ quit 3
+fi
+export HA_SBIN_DIR=$__OCFT__fakebin
+
+. $OCF_LIB/ocf-returncodes || {
+ echo "${__OCFT__showhost}ERROR: $OCF_LIB/ocf-returncodes not found."
+ quit 3
+}
+
+. $OCF_LIB/ocf-directories || {
+ echo "${__OCFT__showhost}ERROR: $OCF_LIB/ocf-directories not found."
+ quit 3
+}
+
+while read __OCFT__line; do
+ if [ -n "$__OCFT__line" ]; then
+ __OCFT__retn=${__OCFT__line%%=*}
+ __OCFT__reti=$(eval echo \$$__OCFT__retn)
+ __OCFT__retval[__OCFT__reti]=$__OCFT__retn
+ fi
+done <<<"$(sed 's/#.*//' $OCF_LIB/ocf-returncodes)"
+
+
+# vim:ts=2:sw=2:et:
diff --git a/tools/ocft/db2 b/tools/ocft/db2
new file mode 100644
index 0000000..5c4d6ea
--- /dev/null
+++ b/tools/ocft/db2
@@ -0,0 +1,164 @@
+# db2
+#
+# This test assumes a db2 ESE instance with two partitions and a database.
+# Default is instance=db2inst1, database=ocft
+# adapt this in set_testenv below
+#
+# Simple steps to generate a test environment (if you don't have one):
+#
+# A virtual machine with 1200MB RAM is sufficient
+#
+# - download an eval version of DB2 server from IBM
+# - create an user "db2inst1" in group "db2inst1"
+#
+# As root
+# - install DB2 software in some location
+# - create instance
+# cd <this_location>/instance
+# ./db2icrt -s ese -u db2inst1 db2inst1
+# - adapt profile of db2inst1 as instructed by db2icrt
+#
+# As db2inst1
+# # allow to run with small memory footprint
+# db2set DB2_FCM_SETTINGS=FCM_MAXIMIZE_SET_SIZE:FALSE
+# db2start
+# db2start dbpartitionnum 1 add dbpartitionnum hostname $(uname -n) port 1 without tablespaces
+# db2stop
+# db2start
+# db2 create database ocft
+# Done
+# In order to install a real cluster refer to http://www.linux-ha.org/wiki/db2_(resource_agent)
+
+CONFIG
+ Agent db2
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ HangTimeout 40
+
+SETUP-AGENT
+ # nothing
+
+CASE-BLOCK set_testenv
+ Env OCFT_instance=db2inst1
+ Env OCFT_db=ocft
+
+CASE-BLOCK crm_setting
+ Env OCF_RESKEY_instance=$OCFT_instance
+ Env OCF_RESKEY_CRM_meta_timeout=30000
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include set_testenv
+ Include crm_setting
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: invalid 'OCF_RESKEY_instance'"
+ Include prepare
+ Env OCF_RESKEY_instance=no_such
+ AgentRun start OCF_ERR_INSTALLED
+
+CASE "invalid instance config"
+ Include prepare
+ Bash eval mv ~$OCFT_instance/sqllib ~$OCFT_instance/sqllib-
+ BashAtExit eval mv ~$OCFT_instance/sqllib- ~$OCFT_instance/sqllib
+ AgentRun start OCF_ERR_INSTALLED
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "started: monitor"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "not started: monitor"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "killed instance: monitor"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+ AgentRun monitor OCF_SUCCESS
+ BashAtExit rm /tmp/ocft-helper1
+ Bash echo "su $OCFT_instance -c '. ~$OCFT_instance/sqllib/db2profile; db2nkill 0 >/dev/null 2>&1'" > /tmp/ocft-helper1
+ Bash sh -x /tmp/ocft-helper1
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "overload param instance by admin"
+ Include prepare
+ Env OCF_RESKEY_instance=no_such
+ Env OCF_RESKEY_admin=$OCFT_instance
+ AgentRun start OCF_SUCCESS
+
+CASE "check start really activates db"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+ BashAtExit rm /tmp/ocft-helper2
+ Bash echo "su $OCFT_instance -c '. ~$OCFT_instance/sqllib/db2profile; db2 get snapshot for database on $OCFT_db>/dev/null'" > /tmp/ocft-helper2
+ Bash sh -x /tmp/ocft-helper2
+
+CASE "multipartion test"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+ AgentRun monitor OCF_SUCCESS
+
+ # start does not start partion 1
+ Env OCF_RESKEY_dbpartitionnum=1
+ AgentRun monitor OCF_NOT_RUNNING
+
+ # now start 1
+ AgentRun start OCF_SUCCESS
+ AgentRun monitor OCF_SUCCESS
+
+ # now stop 1
+ AgentRun stop OCF_SUCCESS
+ AgentRun monitor OCF_NOT_RUNNING
+
+ # does not affect 0
+ Env OCF_RESKEY_dbpartitionnum=0
+ AgentRun monitor OCF_SUCCESS
+
+# fault injection does not work on the 1.0.4 client due to a hardcoded path
+CASE "simulate hanging db2stop (not meaningful for 1.0.4 agent)"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+ Bash [ ! -f /usr/local/bin/db2stop ]
+ BashAtExit rm /usr/local/bin/db2stop
+ Bash echo -e "#!/bin/sh\necho fake db2stop\nsleep 10000" > /usr/local/bin/db2stop
+ Bash chmod +x /usr/local/bin/db2stop
+ AgentRun stop OCF_SUCCESS
+
+# fault injection does not work on the 1.0.4 client due to a hardcoded path
+CASE "simulate not stopping db2stop (not meaningful for 1.0.4 agent)"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+ Bash [ ! -f /usr/local/bin/db2stop ]
+ BashAtExit rm /usr/local/bin/db2stop
+ Bash echo -e "#!/bin/sh\necho fake db2stop\nexit 0" > /usr/local/bin/db2stop
+ Bash chmod +x /usr/local/bin/db2stop
+ AgentRun stop OCF_SUCCESS
diff --git a/tools/ocft/drbd.linbit b/tools/ocft/drbd.linbit
new file mode 100644
index 0000000..57fa088
--- /dev/null
+++ b/tools/ocft/drbd.linbit
@@ -0,0 +1,183 @@
+# linbit: drbd
+
+CONFIG
+ Agent drbd
+ AgentRoot /usr/lib/ocf/resource.d/linbit
+ InstallPackage drbd
+ HangTimeout 20
+
+VARIABLE
+ DRBDCONF=${HA_RSCTMP}/ocft_drbd_tmp.conf
+
+ # should be this machine's hostname/ip, please modify it by yourself.
+ NAME_1=HOSTNAME1
+ IP_1=IP_ADDRESS1
+
+ # the block device just for test, please modify it by yourself.
+ DISK_1=/dev/DEVICE1
+
+ PORT_1=5735
+ DEVICE_1=/dev/drbd0
+
+ ####################################################################
+
+ # please modify it by yourself.
+ NAME_2=HOSTNAME2
+ IP_2=IP_ADDRESS2
+
+ # the block device just for test, please modify it by yourself.
+ DISK_2=/dev/DEVICE2
+
+ PORT_2=5735
+ DEVICE_2=/dev/drbd0
+
+
+
+SETUP-AGENT
+ cat >$DRBDCONF <<EOF
+ global {
+ usage-count no;
+ }
+
+ resource ocft0 {
+ protocol C;
+ disk {
+ on-io-error detach;
+ }
+ on $NAME_1 {
+ device $DEVICE_1;
+ address $IP_1:$PORT_1;
+ meta-disk internal;
+ disk $DISK_1;
+ }
+ on $NAME_2 {
+ device $DEVICE_2;
+ address $IP_2:$PORT_2;
+ meta-disk internal;
+ disk $DISK_2;
+ }
+ }
+EOF
+ HOST=$(uname -n)
+ DRBDADM="drbdadm -c $DRBDCONF"
+
+ # prepare
+ modprobe drbd $(drbdadm sh-mod-parms)
+ $DRBDADM down ocft0
+
+ # create meta data block if necessary
+ $DRBDADM dump-md ocft0 >/dev/null 2>&1
+ if [ $? -eq 255 ]; then
+ $DRBDADM create-md ocft0
+ fi
+
+ # start drbd
+ $DRBDADM up ocft0
+
+ # UpToDate
+ if [ "$HOST" = "$NAME_1" ]; then
+ $DRBDADM wait-connect ocft0
+ echo "drbd Syncing .."
+ $DRBDADM primary --force ocft0
+ while true; do
+ CSTATE=$($DRBDADM cstate ocft0)
+ DSTATE=$($DRBDADM dstate ocft0)
+ if [ "$CSTATE" = "Connected" -a "$DSTATE" = "UpToDate/UpToDate" ]; then
+ break
+ else
+ sleep 3
+ fi
+ done
+ echo "done"
+ fi
+
+CLEANUP-AGENT
+ drbdadm -c $DRBDCONF down ocft0
+ rm -f $DRBDCONF
+
+CASE-BLOCK required_args
+ Env OCF_RESKEY_drbdconf=$DRBDCONF
+ Env OCF_RESKEY_drbd_resource=ocft0
+ Env OCF_RESKEY_CRM_meta_notify=true
+ Env OCF_RESKEY_CRM_meta_clone_max=2
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include required_args
+ Include default_status
+
+CASE "check base env"
+ Include required_args
+ AgentRun validate-all OCF_SUCCESS
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "wrong path of config file"
+ Include prepare
+ Env OCF_RESKEY_drbdconf=no_such_file
+ AgentRun start OCF_ERR_INSTALLED
+
+CASE "wrong resource name"
+ Include prepare
+ Env OCF_RESKEY_drbd_resource=no_such_src
+ # OCF_RESKEY_drbd_resource is a required parameter in agent meta-data,
+ # if wrong, I think the agent should return OCF_ERR_CONFIGURED.
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "running monitor"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "not running monitor"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "Primary/Secondary monitor"
+ Include prepare
+ AgentRun start
+ AgentRun promote
+ AgentRun monitor OCF_RUNNING_MASTER
+ AgentRun demote
+ AgentRun monitor OCF_SUCCESS
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
+
+CASE "try to 'promote' in single-primary mode"
+ Include prepare
+ Include@$IP_2 prepare
+
+ # start drbd
+ AgentRun start
+ AgentRun@$IP_2 start
+
+ # promote local drbd first
+ AgentRun promote OCF_SUCCESS
+
+ # demote local drbd prepare for remote drbd promote
+ AgentRun demote
+ # remote drbd promote
+ AgentRun@$IP_2 promote OCF_SUCCESS
+
+ # promote fails, because remote drbd promote first.
+ AgentRun promote OCF_ERR_GENERIC
diff --git a/tools/ocft/exportfs b/tools/ocft/exportfs
new file mode 100644
index 0000000..285a4b8
--- /dev/null
+++ b/tools/ocft/exportfs
@@ -0,0 +1,80 @@
+# exportfs
+#
+#
+
+CONFIG
+ Agent exportfs
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ InstallPackage nfs-kernel-server
+ HangTimeout 40
+
+SETUP-AGENT
+ # nothing
+
+CASE-BLOCK set_testenv
+ Env OCF_RESKEY_directory=/usr
+ Env OCF_RESKEY_fsid=105
+ Env OCF_RESKEY_clientspec="*"
+ Env OCF_RESKEY_CRM_meta_timeout=30000
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include set_testenv
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: no 'OCF_RESKEY_fsid'"
+ Include prepare
+ Env OCF_RESKEY_fsid=
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "check base env: invalid 'OCF_RESKEY_directory'"
+ Include prepare
+ Env OCF_RESKEY_directory=/no_such
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "check base env: non-decimal 'OCF_RESKEY_fsid'"
+ Include prepare
+ Env OCF_RESKEY_fsid="4f838db14f838db14f838db14f838db1"
+ AgentRun start OCF_SUCCESS
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "stop with no env"
+ Include prepare
+ Env OCF_RESKEY_directory=/no_such
+ AgentRun stop OCF_SUCCESS
+
+CASE "started: monitor"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "not started: monitor"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
diff --git a/tools/ocft/exportfs-multidir b/tools/ocft/exportfs-multidir
new file mode 100644
index 0000000..00e41f0
--- /dev/null
+++ b/tools/ocft/exportfs-multidir
@@ -0,0 +1,80 @@
+# exportfs
+#
+#
+
+CONFIG
+ Agent exportfs
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ InstallPackage nfs-kernel-server
+ HangTimeout 40
+
+SETUP-AGENT
+ # nothing
+
+CASE-BLOCK set_testenv
+ Env OCF_RESKEY_directory="/usr /var"
+ Env OCF_RESKEY_fsid=105
+ Env OCF_RESKEY_clientspec="*"
+ Env OCF_RESKEY_CRM_meta_timeout=30000
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include set_testenv
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: no 'OCF_RESKEY_fsid'"
+ Include prepare
+ Env OCF_RESKEY_fsid=
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "check base env: invalid 'OCF_RESKEY_directory'"
+ Include prepare
+ Env OCF_RESKEY_directory=/no_such
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "check base env: invalid 'OCF_RESKEY_fsid'"
+ Include prepare
+ Env OCF_RESKEY_fsid=root
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "stop with no env"
+ Include prepare
+ Env OCF_RESKEY_directory="/usr /no_such"
+ AgentRun stop OCF_SUCCESS
+
+CASE "started: monitor"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "not started: monitor"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
diff --git a/tools/ocft/helpers.sh b/tools/ocft/helpers.sh
new file mode 100644
index 0000000..9848934
--- /dev/null
+++ b/tools/ocft/helpers.sh
@@ -0,0 +1,43 @@
+get_rundir() {
+ local rundir
+ rundir="`mount | grep '/run ' | awk '{print $3}'`"
+ echo ${rundir:-"/var/run"}
+}
+
+loopbackeddev() {
+ local action file size ctlfile
+
+ action="$1"
+ file="$2"
+ size="$3"
+ ctlfile=$HA_RSCTMP/`echo $file | tr / _`
+
+ case "$action" in
+ start|setup|make)
+ if [ ! -f "$ctlfile" ]; then
+ if [ -z "$size" ]; then
+ echo "usage: $0 action file size" >&2
+ exit 1
+ fi
+ loopdev=`losetup -f`
+ if ! dd if=/dev/zero of=$file bs=1 count=0 seek=$size 2>/dev/null; then
+ echo "$0: dd failed" >&2
+ exit 1
+ fi
+ if ! losetup $loopdev $file; then
+ echo "$0: losetup failed" >&2
+ exit 1
+ fi
+ echo $loopdev | tee $ctlfile
+ else
+ cat $ctlfile
+ fi
+ ;;
+ stop|undo|unmake)
+ if [ -f "$ctlfile" ]; then
+ losetup -d `cat $ctlfile`
+ rm -f $file $ctlfile
+ fi
+ ;;
+ esac
+}
diff --git a/tools/ocft/iscsi b/tools/ocft/iscsi
new file mode 100644
index 0000000..3c5d524
--- /dev/null
+++ b/tools/ocft/iscsi
@@ -0,0 +1,108 @@
+# iscsi
+
+CONFIG
+ Agent iscsi
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ InstallPackage open-iscsi targetcli
+ HangTimeout 20
+
+VARIABLE
+ OCFT_rundir="`get_rundir`"
+ OCFT_disk="$OCFT_rundir/resource-agents/ocft-iscsi"
+ OCFT_target="iqn.2003-01.org.linux-iscsi:ocft"
+ OCFT_portal="127.0.0.1:3260"
+ OCFT_loop="`loopbackeddev make $OCFT_disk 16M`"
+ OCF_RESKEY_iqn=$OCFT_target
+ OCF_RESKEY_portals=$OCFT_portal
+ OCF_RESKEY_target_iqn=$OCFT_target
+ OCF_RESKEY_path=$OCFT_loop
+ OCF_RESKEY_lun=1
+
+SETUP-AGENT
+ if systemctl list-unit-files 2>/dev/null | fgrep -q iscsid.service; then
+ systemctl start iscsid.service
+ else
+ /etc/init.d/open-iscsi start
+ fi
+ if systemctl list-unit-files 2>/dev/null | fgrep -q target.service; then
+ systemctl start target.service
+ else
+ /etc/init.d/target start
+ fi
+ export OCF_RESKEY_iqn=$OCFT_target
+ export OCF_RESKEY_portals=$OCFT_portal
+ export OCF_RESKEY_target_iqn=$OCFT_target
+ export OCF_RESKEY_path=$OCFT_loop
+ export OCF_RESKEY_lun=1
+ /usr/lib/ocf/resource.d/heartbeat/iSCSITarget start
+ /usr/lib/ocf/resource.d/heartbeat/iSCSILogicalUnit start
+
+CLEANUP-AGENT
+ export OCF_RESKEY_iqn=$OCFT_target
+ export OCF_RESKEY_portals=$OCFT_portal
+ export OCF_RESKEY_target_iqn=$OCFT_target
+ export OCF_RESKEY_path=$OCFT_loop
+ export OCF_RESKEY_lun=1
+ /usr/lib/ocf/resource.d/heartbeat/iSCSILogicalUnit stop
+ /usr/lib/ocf/resource.d/heartbeat/iSCSITarget stop
+ if systemctl list-unit-files 2>/dev/null | fgrep -q target.service; then
+ systemctl stop target.service
+ fi
+ loopbackeddev unmake $OCFT_disk
+
+CASE-BLOCK required_args
+ Env OCF_RESKEY_portal=$OCFT_portal
+ Env OCF_RESKEY_target=$OCFT_target
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include required_args
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: invalid 'OCF_RESKEY_portal'"
+ Include prepare
+ Unenv OCF_RESKEY_portal
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "check base env: unset 'OCF_RESKEY_target'"
+ Include prepare
+ Unenv OCF_RESKEY_target
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "monitor when running"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "monitor when not running"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
+
diff --git a/tools/ocft/jboss b/tools/ocft/jboss
new file mode 100644
index 0000000..bc99d8f
--- /dev/null
+++ b/tools/ocft/jboss
@@ -0,0 +1,83 @@
+# jboss
+#
+# NOTE: Clean up $jboss_home/standalone/log before running this test
+# otherwise creating the pid/log files may fail
+# in the test case with a different user.
+
+CONFIG
+ Agent jboss
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ HangTimeout 120
+
+# Note : Change setting by a version of JBoss.
+#
+VARIABLE
+ # JBoss5 Environment require
+# jboss_version=5
+# jboss_home=/opt/jboss5/current
+# java_home=/usr/lib/jvm/java-1.6.0-openjdk.x86_64
+# user=jboss5
+ # JBoss6 Environment require
+ jboss_version=6
+ jboss_home=/opt/jboss6/current
+ java_home=/usr/lib/jvm/java-1.7.0-openjdk.x86_64
+ user=jboss6
+
+CASE-BLOCK required_args_jboss
+ Env OCF_RESKEY_jboss_home=${jboss_home}
+ Env OCF_RESKEY_java_home=${java_home}
+ Env OCF_RESKEY_jboss_version=${jboss_version}
+ Env OCF_RESKEY_user=${user}
+
+CASE-BLOCK args_clear
+ Unenv OCF_RESKEY_jboss_home
+ Unenv OCF_RESKEY_java_home
+ Unenv OCF_RESKEY_jboss_version
+ Unenv OCF_RESKEY_user
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare_jboss
+ Include required_args_jboss
+ Include default_status
+
+# Test CASE
+#
+CASE "normal start jboss require_args (user:user)"
+ Include prepare_jboss
+ AgentRun start OCF_SUCCESS
+ AgentRun monitor OCF_SUCCESS
+ AgentRun stop OCF_SUCCESS
+ AgentRun monitor OCF_NOT_RUNNING
+ Include args_clear
+
+CASE "normal start jboss require_args (user:root)"
+ Include prepare_jboss
+ Unenv OCF_RESKEY_user
+ AgentRun start OCF_SUCCESS
+ AgentRun monitor OCF_SUCCESS
+ AgentRun stop OCF_SUCCESS
+ AgentRun monitor OCF_NOT_RUNNING
+ Include args_clear
+
+CASE "error start jboss no jboss_home"
+ Include prepare_jboss
+ Unenv OCF_RESKEY_jboss_home
+ AgentRun start OCF_ERR_INSTALLED
+ Include args_clear
+
+CASE "error start jboss no java_home"
+ Include prepare_jboss
+ Unenv OCF_RESKEY_java_home
+ AgentRun start OCF_ERR_INSTALLED
+ Include args_clear
+
+CASE "error start jboss no java command"
+ Include prepare_jboss
+ Env OCF_RESKEY_java_home=/var
+ AgentRun start OCF_ERR_INSTALLED
+ AgentRun stop OCF_SUCCESS
+ AgentRun monitor OCF_NOT_RUNNING
+ Include args_clear
+
diff --git a/tools/ocft/mysql b/tools/ocft/mysql
new file mode 100644
index 0000000..305a900
--- /dev/null
+++ b/tools/ocft/mysql
@@ -0,0 +1,82 @@
+# mysql
+
+CONFIG
+ Agent mysql
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ InstallPackage mysql
+ HangTimeout 20
+
+SETUP-AGENT
+ if systemctl list-unit-files 2>/dev/null | fgrep -q mysql.service; then
+ systemctl start mysql.service
+ systemctl stop mysql.service
+ else
+ /etc/init.d/mysql start
+ /etc/init.d/mysql stop
+ fi
+
+CASE-BLOCK crm_setting
+ Env OCF_RESKEY_CRM_meta_timeout=15000
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include crm_setting
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: invalid 'OCF_RESKEY_binary'"
+ Include prepare
+ Env OCF_RESKEY_binary=no_such
+ AgentRun start OCF_ERR_INSTALLED
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "running monitor"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "not running monitor"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "check lib file"
+ Include prepare
+ Bash chmod u-w /var/lib/mysql
+ BashAtExit chmod u+w /var/lib/mysql
+ AgentRun start OCF_ERR_PERM
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
+
+CASE "non-existent user"
+ Include prepare
+ Env OCF_RESKEY_user=no_user
+ AgentRun start OCF_ERR_INSTALLED
+
+CASE "invalid user"
+ Include prepare
+ Env OCF_RESKEY_user=nobody
+ AgentRun start OCF_ERR_PERM
diff --git a/tools/ocft/mysql-proxy b/tools/ocft/mysql-proxy
new file mode 100644
index 0000000..e16d52b
--- /dev/null
+++ b/tools/ocft/mysql-proxy
@@ -0,0 +1,83 @@
+# mysql-proxy
+# by r.bhatia@ipax.at
+#
+# test cases (to implement):
+#
+# * /usr/sbin/ocf-tester -n mp -o binary="/usr/sbin/mysql-proxy" -o defaults_file="" -o parameters="--proxy-skip-profiling" \
+# -o admin_address="127.0.0.1:4041" -o admin_username="root" -o admin_password="la" -o admin_lua_script="/usr/lib/mysql-proxy/lua/admin.lua" \
+# -o proxy_backend_addresses="192.168.100.200:42006" -o proxy_address="/var/run/mysqld/mysqld.sock" /usr/lib/ocf/resource.d/heartbeat/mysql-proxy
+#
+# * OCF_CHECK_LEVEL 20 check
+
+CONFIG
+ Agent mysql-proxy
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat/
+ InstallPackage mysql-proxy
+ HangTimeout 20
+
+SETUP-AGENT
+ # nothing
+
+CASE-BLOCK crm_setting
+ Env OCF_RESKEY_CRM_meta_timeout=15000
+ Env OCF_RESKEY_binary=/tmp/mysql-proxy
+ Env OCF_RESKEY_admin_username=root
+ Env OCF_RESKEY_admin_password=test123
+ Env OCF_RESKEY_admin_lua_script=/usr/lib/mysql-proxy/lua/admin.lua
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Bash [ ! -x /tmp/mysql-proxy ] && ln -s `which mysql-proxy` /tmp/mysql-proxy || true
+ Include crm_setting
+
+CASE-BLOCK teardown
+ AgentRun stop
+ BashAtExit rm -f /tmp/mysql-proxy
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+ Include teardown
+
+CASE "check base env: invalid 'OCF_RESKEY_binary'"
+ Include prepare
+ Env OCF_RESKEY_binary=no_such
+ AgentRun start OCF_ERR_INSTALLED
+ BashAtExit rm -f /tmp/mysql-proxy
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+ Include teardown
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+ Include teardown
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+ Include teardown
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "running monitor"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+ Include teardown
+
+CASE "not running monitor"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
diff --git a/tools/ocft/named b/tools/ocft/named
new file mode 100644
index 0000000..90a4351
--- /dev/null
+++ b/tools/ocft/named
@@ -0,0 +1,69 @@
+#named
+
+# To work properly this test requires that standard bind and bin-utils
+# packages installed.
+
+CONFIG
+ Agent named
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ InstallPackage bind
+ InstallPackage bind-utils
+
+SETUP-AGENT
+ /etc/init.d/named start
+ /etc/init.d/named stop
+
+CASE-BLOCK crm_setting
+ Env OCF_RESKEY_CRM_meta_timeout=15000
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include crm_setting
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: invalid 'OCF_RESKEY_named'"
+ Include prepare
+ Env OCF_RESKEY_named=no_such
+ AgentRun start OCF_ERR_INSTALLED
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "running monitor"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "not running monitor"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
+
+CASE "non-existent user"
+ Include prepare
+ Env OCF_RESKEY_named_user=no_user
+ AgentRun start OCF_ERR_INSTALLED
diff --git a/tools/ocft/nfsserver b/tools/ocft/nfsserver
new file mode 100644
index 0000000..cf2ac89
--- /dev/null
+++ b/tools/ocft/nfsserver
@@ -0,0 +1,69 @@
+# nfsserver
+
+CONFIG
+ Agent nfsserver
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ InstallPackage nfs-kernel-server
+ HangTimeout 20
+
+SETUP-AGENT
+ INITSCRIPT=""
+ if test -f /etc/init.d/nfsserver; then
+ INITSCRIPT="/etc/init.d/nfsserver"
+ fi
+ true
+
+CASE-BLOCK required_args
+ Env OCF_RESKEY_nfs_init_script=$INITSCRIPT
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include required_args
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: invalid 'OCF_RESKEY_nfs_init_script'"
+ Include prepare
+ Env OCF_RESKEY_nfs_init_script=no_such_script
+ AgentRun start OCF_ERR_INSTALLED
+
+CASE "check base env: invalid 'OCF_RESKEY_nfs_notify_cmd'"
+ Include prepare
+ Env OCF_RESKEY_nfs_notify_cmd=no_such_program
+ AgentRun start OCF_ERR_INSTALLED
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "monitor with running"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "monitor with not running"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
diff --git a/tools/ocft/ocft.in b/tools/ocft/ocft.in
new file mode 100644
index 0000000..0d7f645
--- /dev/null
+++ b/tools/ocft/ocft.in
@@ -0,0 +1,893 @@
+#!@BASH_SHELL@
+
+# Copyright (c) 2010-2013 Novell Inc, John Shi
+# All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Further, this software is distributed without any warranty that it is
+# free of the rightful claim of any third person regarding infringement
+# or the like. Any license provided herein, whether implied or
+# otherwise, applies only to this software file. Patent licenses, if
+# any, provided herein do not apply to combinations of this program with
+# other software, or any other product whatsoever.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+
+die()
+{
+ local str
+ str="$1"
+
+ echo "ERROR: $str" >&2
+ exit 1
+}
+
+warn()
+{
+ local str
+ str="$1"
+
+ echo "WARNING: $str" >&2
+}
+
+parse_die()
+{
+ local str
+ str="$1"
+
+ agent_parse_finish
+ die "${agent}: line ${line_num}: ${str}"
+}
+
+# add quotes to string for Here Documents
+add_quotes()
+{
+ local typ str a b
+ typ="$1"
+ str="$2"
+
+ case "$typ" in
+ 1) a=\'; b=\";;
+ 2) a=\"; b=\';;
+ esac
+
+ echo "$str" | sed "s/$a/$a$b$a$b$a/g; 1 s/^/$a/; $ s/$/$a/"
+}
+
+# split strings
+explode()
+{
+ local str
+ str="$1"
+
+ echo "$str" | awk -F'"' '{
+ if (NF > 0 && NF%2 == 0)
+ exit(1);
+ for (i=1; i<=NF; i++) {
+ if (i%2 == 0)
+ print $i;
+ else {
+ len = split($i, str, /[ \t]+/);
+ for (j=1; j<=len; j++) {
+ sb = sub(/#.*/, "", str[j]);
+ if (str[j] != "")
+ print str[j];
+ if (sb)
+ exit(0);
+ }
+ }
+ }
+ }'
+}
+
+# phase 1: parse the string to 'command' and 'argument collection'.
+line2trunk()
+{
+ trunk[0]="${line%%[[:blank:]]*}"
+ trunk[1]="${line#*[[:blank:]]}"
+}
+
+# phase 2: split the argument collection.
+trunk2branch()
+{
+ local IFS
+
+ # Some of statements need one parameter at least.
+ if [ "$line" = "${trunk[0]}" ]; then
+ parse_die "missing parameter."
+ fi
+
+ IFS=$'\n'
+ branch=($(explode "${trunk[1]}"))
+ if [ $? -ne 0 ]; then
+ parse_die "missing '\"'."
+ fi
+}
+
+preparse_cfg()
+{
+ local agent line trunk branch macro num host
+ agent="$1"
+
+ if [ ! -r "$opt_cfgsdir/$agent" ]; then
+ die "${agent}: configuration file not found."
+ fi
+
+ line_num=0
+ while read -r line; do
+ let line_num++
+ num=" $line_num"
+
+ case "$line" in
+ ""|\#*) continue;;
+ esac
+
+ line2trunk
+ case "${trunk[0]}" in
+ CASE-BLOCK)
+ trunk2branch
+ macro="$CASES_DIR/${agent}_macro.${branch[0]}"
+ continue
+ ;;
+ Include|Include@*)
+ host=$(echo "${trunk[0]}" | awk -F@ '{print $2}')
+ trunk2branch
+ if [ ! -r "$CASES_DIR/${agent}_macro.${branch[0]}" ]; then
+ parse_die "Macro '${branch[0]}' not found."
+ fi
+ if [ -n "$host" ]; then
+ line="$(sed -e 's/^\([^[:blank:]]*\)@[^[:blank:]]*/\1/' -e "s/^[^[:blank:]]*/&@$host/" "$CASES_DIR/${agent}_macro.${branch[0]}")"
+ else
+ line="$(<"$CASES_DIR/${agent}_macro.${branch[0]}")"
+ fi
+ num=
+ ;;
+ *[!A-Z-]*)
+ :
+ ;;
+ *)
+ macro=
+ ;;
+ esac
+
+ if [ -n "$macro" ]; then
+ echo "$line$num" >>"$macro"
+ else
+ echo "$line$num" >>"$CASES_DIR/${agent}_preparse"
+ fi
+ done <"$opt_cfgsdir/$agent"
+}
+
+case_parse_finish()
+{
+ local host
+
+ if [ -n "$sh" ]; then
+ cat >>$sh <<EOF
+if [ -n "\$__OCFT__VERBOSE" ]; then
+ echo
+fi
+# Cleanup and exit
+EOF
+ for host in $hosts; do
+ echo "backbash_stop $host" >>$sh
+ done
+ echo "quit 0" >>$sh
+ fi
+
+ atexit_num=0
+ hosts=
+ sh=
+}
+
+init_cfg_vars()
+{
+ cfg_agent=
+ cfg_agent_root=
+ cfg_install_package=()
+ cfg_hang_timeout=20
+}
+
+agent_parse_finish()
+{
+ local suf
+
+ for suf in preparse setup cleanup var hosts; do
+ rm -f $CASES_DIR/${agent}_$suf
+ done
+ rm -f $CASES_DIR/${agent}_macro.*
+ init_cfg_vars
+}
+
+need_make()
+{
+ local src_time obj_time
+
+ if [ ! -f "$CASES_DIR/0_${agent}.sh" ]; then
+ return 0
+ fi
+
+ src_time=$(stat -c '%Y' "$opt_cfgsdir/$agent")
+ obj_time=$(stat -c '%Y' "$CASES_DIR/0_${agent}.sh")
+
+ test $src_time -ge $obj_time
+}
+
+parse_cfg()
+{
+ local agents i line stat sh trunk branch atexit_num host hosts
+
+ if [ $# -eq 0 ]; then
+ agents=($opt_cfgsdir/*)
+ else
+ agents=("$@")
+ fi
+
+ for agent in "${agents[@]}"; do
+ agent="$(basename "$agent")"
+
+ if ! need_make; then
+ continue
+ fi
+
+ agent_obj_clean $agent
+ agent_parse_finish
+
+ i=0
+
+ echo "Making '$agent': "
+ preparse_cfg "$agent"
+ while read -r line; do
+ line_num="${line##* }"
+ line="${line% *}"
+ line2trunk
+
+ # state switch
+ case "${trunk[0]}" in
+ CONFIG)
+ case_parse_finish
+ stat=1
+ continue
+ ;;
+ VARIABLE)
+ case_parse_finish
+ stat=2
+ continue
+ ;;
+ SETUP-AGENT)
+ case_parse_finish
+ stat=3
+ continue
+ ;;
+ CLEANUP-AGENT)
+ case_parse_finish
+ stat=4
+ continue
+ ;;
+ CASE)
+ case_parse_finish
+ trunk2branch
+ echo " - case ${i}: ${branch[0]}"
+ sh="$CASES_DIR/${i}_${agent}.sh"
+ cat >$sh <<EOF
+#!@BASH_SHELL@
+
+# Agent: $cfg_agent
+# Summary: ${branch[0]}
+
+. $OCFT_DIR/caselib || {
+ echo "ERROR: '$OCFT_DIR/caselib' not found."
+ exit 2
+}
+
+$(test -r $CASES_DIR/${agent}_var && cat $CASES_DIR/${agent}_var)
+
+__OCFT__MYROOT="$cfg_agent_root"
+
+$(test -n "$cfg_install_package" && echo "agent_install ${cfg_install_package[@]}")
+
+if [ -n "\$__OCFT__VERBOSE" ]; then
+ echo -e $(add_quotes 1 "Starting '\\033[33m${agent}\\033[0m' case $i '\\033[33m${branch[0]}\\033[0m':")
+else
+ echo -n "${agent}: ${branch[0]} - "
+fi
+EOF
+ chmod a+x $sh
+
+ let i++
+ stat=5
+ continue
+ ;;
+ esac
+
+ case "$stat" in
+ 1)
+ case "${trunk[0]}" in
+ Agent)
+ trunk2branch
+ cfg_agent="${branch[0]}"
+ ;;
+ AgentRoot)
+ trunk2branch
+ cfg_agent_root="${branch[0]}"
+ ;;
+ InstallPackage)
+ trunk2branch
+ cfg_install_package=(${cfg_install_package[@]} ${branch[@]})
+ ;;
+ HangTimeout)
+ trunk2branch
+ if ! echo "${branch[0]}" | grep -qxE '[0-9]+'; then
+ parse_die "numeric argument required."
+ fi
+ cfg_hang_timeout="${branch[0]}"
+ ;;
+ *)
+ parse_die "unimplemented statement: ${trunk[0]}"
+ ;;
+ esac
+ ;;
+ 2)
+ if echo "$line" | grep -q '^__OCFT__'; then
+ parse_die "reserved key word '__OCFT__'."
+ fi
+ echo "declare $line" >>$CASES_DIR/${agent}_var
+ ;;
+ 3)
+ echo "$line" >>$CASES_DIR/${agent}_setup
+ ;;
+ 4)
+ echo "$line" >>$CASES_DIR/${agent}_cleanup
+ ;;
+ 5)
+ host=$(echo ${trunk[0]} | awk -F@ '{print $2}')
+ if [ -n "$host" ]; then
+ if ! echo "$hosts" | grep -q "$host"; then
+ echo "$host" >>$CASES_DIR/${agent}_hosts
+ hosts=$hosts$'\n'$host
+ cat >>$sh <<EOF
+# Initialize remote shell
+backbash_start $host
+backbash $host <<CMD
+__OCFT__VERBOSE=\$__OCFT__VERBOSE
+CMD
+backbash $host <$OCFT_DIR/caselib
+backbash $host <<'CMD'
+$(test -r $CASES_DIR/${agent}_var && cat $CASES_DIR/${agent}_var)
+
+__OCFT__MYROOT="$cfg_agent_root"
+__OCFT__showhost="${host}: "
+
+$(test -n "$cfg_install_package" && echo "agent_install ${cfg_install_package[@]}")
+CMD
+EOF
+ fi
+ fi
+
+ echo "
+# CASE statement: $line" >>$sh
+
+ if [ -n "$host" ]; then
+ echo "backbash $host <<'CMD'" >>$sh
+ fi
+
+ case "${trunk[0]}" in
+ Env|Env@*)
+ cat >>$sh <<EOF
+if [ -n "\$__OCFT__VERBOSE" ]; then
+ echo $(add_quotes 2 " \${__OCFT__showhost}Setting agent environment: export ${trunk[1]}")
+fi
+export ${trunk[1]}
+check_success \$? $(add_quotes 1 "export ${trunk[1]}")
+EOF
+ ;;
+ Unenv|Unenv@*)
+ cat >>$sh <<EOF
+if [ -n "\$__OCFT__VERBOSE" ]; then
+ echo $(add_quotes 2 " \${__OCFT__showhost}Removing agent environment: unset ${trunk[1]}")
+fi
+unset ${trunk[1]}
+check_success \$? $(add_quotes 1 "unset ${trunk[1]}")
+EOF
+ ;;
+ AgentRun|AgentRun@*)
+ trunk2branch
+ if [ -z "${branch[1]}" ]; then
+ if [ "${branch[0]}" = "start" ]; then
+ cat >>$sh <<EOF
+agent_run $(add_quotes 1 "$cfg_agent") monitor $cfg_hang_timeout
+__OCFT__rc=\$?
+
+if [ \$__OCFT__rc -eq \$OCF_SUCCESS -o \$__OCFT__rc -eq \$OCF_RUNNING_MASTER ]; then
+ : #The status I want, so I can do nothing.
+elif [ \$__OCFT__rc -eq \$OCF_NOT_RUNNING ]; then
+ if [ -n "\$__OCFT__VERBOSE" ]; then
+ echo $(add_quotes 2 " \${__OCFT__showhost}Running agent: ./$cfg_agent ${branch[0]}")
+ fi
+ agent_run $(add_quotes 1 "$cfg_agent") start $cfg_hang_timeout
+ check_success \$? $(add_quotes 1 "./$cfg_agent ${branch[0]}")
+else
+ check_success \$__OCFT__rc $(add_quotes 1 "./$cfg_agent monitor")
+fi
+EOF
+ elif [ "${branch[0]}" = "stop" ]; then
+ cat >>$sh <<EOF
+agent_run $(add_quotes 1 "$cfg_agent") monitor $cfg_hang_timeout
+__OCFT__rc=\$?
+
+if [ \$__OCFT__rc -eq \$OCF_NOT_RUNNING ]; then
+ : #The status I want, so I can do nothing.
+elif [ \$__OCFT__rc -eq \$OCF_SUCCESS -o \$__OCFT__rc -eq \$OCF_RUNNING_MASTER ]; then
+ if [ -n "\$__OCFT__VERBOSE" ]; then
+ echo $(add_quotes 2 " \${__OCFT__showhost}Running agent: ./$cfg_agent ${branch[0]}")
+ fi
+ agent_run $(add_quotes 1 "$cfg_agent") stop $cfg_hang_timeout
+ check_success \$? $(add_quotes 1 "./$cfg_agent ${branch[0]}")
+else
+ check_success \$__OCFT__rc $(add_quotes 1 "./$cfg_agent monitor")
+fi
+EOF
+ elif [ "${branch[0]}" = "monitor" ]; then
+ cat >>$sh <<EOF
+if [ -n "\$__OCFT__VERBOSE" ]; then
+ echo $(add_quotes 2 " \${__OCFT__showhost}Running agent: ./$cfg_agent ${branch[0]}")
+fi
+agent_run $(add_quotes 1 "$cfg_agent") $(add_quotes 1 "${branch[0]}") $cfg_hang_timeout
+EOF
+ else
+ cat >>$sh <<EOF
+if [ -n "\$__OCFT__VERBOSE" ]; then
+ echo $(add_quotes 2 " \${__OCFT__showhost}Running agent: ./$cfg_agent ${branch[0]}")
+fi
+agent_run $(add_quotes 1 "$cfg_agent") $(add_quotes 1 "${branch[0]}") $cfg_hang_timeout
+check_success \$? $(add_quotes 1 "./$cfg_agent ${branch[0]}")
+EOF
+ fi
+ else
+ cat >>$sh <<EOF
+test -n $(add_quotes 2 "\$${branch[1]}")
+check_success \$? $(add_quotes 1 "test -n \"\$${branch[1]}\"")
+if [ -n "\$__OCFT__VERBOSE" ]; then
+ echo $(add_quotes 2 " \${__OCFT__showhost}Running agent: ./$cfg_agent ${branch[0]}")
+fi
+agent_run $(add_quotes 1 "$cfg_agent") $(add_quotes 1 "${branch[0]}") $cfg_hang_timeout
+__OCFT__ret=\$?
+if [ -n "\$__OCFT__VERBOSE" ]; then
+ echo -n " \${__OCFT__showhost}Checking return value:"
+fi
+if [ -n "\${__OCFT__retval[__OCFT__ret]}" ]; then
+ __OCFT__retstr="\${__OCFT__retval[__OCFT__ret]}"
+else
+ __OCFT__retstr=\$__OCFT__ret
+fi
+if [ \$__OCFT__ret -eq \$${branch[1]} ]; then
+ if [ -n "\$__OCFT__VERBOSE" ]; then
+ echo -e $(add_quotes 2 " \\033[32mOK\\033[0m. The return value '\\033[34m\$__OCFT__retstr\\033[0m' == '\\033[34m${branch[1]}\\033[0m'")
+ else
+ echo -e "\\033[32mOK\\033[0m."
+ fi
+else
+ if [ -n "\$__OCFT__VERBOSE" ]; then
+ echo -en $(add_quotes 2 " \\033[31mFAILED\\033[0m. The return value '\\033[34m\$__OCFT__retstr\\033[0m' != '\\033[34m${branch[1]}\\033[0m'. ")
+ else
+ echo -en "\\033[31mFAILED\\033[0m. Agent returns unexpected value: '\$__OCFT__retstr'. "
+ fi
+ echo "See details below:"
+ cat /tmp/.ocft_runlog
+ echo
+ quit 1
+fi
+EOF
+ fi
+ ;;
+ Bash|Bash@*)
+ cat >>$sh <<EOF
+if [ -n "\$__OCFT__VERBOSE" ]; then
+ echo $(add_quotes 2 " \${__OCFT__showhost}Setting system environment: ${trunk[1]}")
+fi
+${trunk[1]}
+check_success \$? $(add_quotes 1 "${trunk[1]}")
+EOF
+ ;;
+ BashAtExit|BashAtExit@*)
+ let atexit_num++
+ cat >>$sh <<EOF
+atexit${atexit_num}()
+{
+ if [ -n "\$__OCFT__VERBOSE" ]; then
+ echo $(add_quotes 2 " \${__OCFT__showhost}Setting system environment: ${trunk[1]}")
+ fi
+ ${trunk[1]}
+}
+let __OCFT__atexit_num++
+EOF
+ ;;
+ *)
+ parse_die "unimplemented statement: ${trunk[0]}"
+ ;;
+ esac
+ if [ -n "$host" ]; then
+ echo 'CMD' >>$sh
+ fi
+ ;;
+ *)
+ parse_die "unimplemented statement: ${trunk[0]}"
+ ;;
+ esac
+ done <$CASES_DIR/${agent}_preparse
+
+ if [ -r "$CASES_DIR/${agent}_setup" ]; then
+ cat >$CASES_DIR/setup_${agent}.sh <<EOF
+#!@BASH_SHELL@
+
+# Agent: $cfg_agent
+# Summary: SETUP before test
+
+echo "Initializing '$cfg_agent' ..."
+
+. $OCFT_DIR/caselib || {
+ echo "ERROR: '$OCFT_DIR/caselib' not found."
+ exit 2
+}
+
+$(test -r "$CASES_DIR/${agent}_var" && cat $CASES_DIR/${agent}_var)
+$(test -n "$cfg_install_package" && echo "agent_install ${cfg_install_package[@]}")
+
+EOF
+ for host in $(test -r $CASES_DIR/${agent}_hosts && cat $CASES_DIR/${agent}_hosts); do
+ cat >>$CASES_DIR/setup_${agent}.sh <<EOF
+# Initialize remote shell
+backbash_start $host
+backbash $host <<CMD
+__OCFT__VERBOSE=\$__OCFT__VERBOSE
+CMD
+backbash $host <$OCFT_DIR/caselib
+backbash $host <<'CMD'
+$(test -r "$CASES_DIR/${agent}_var" && cat $CASES_DIR/${agent}_var)
+
+__OCFT__MYROOT="$cfg_agent_root"
+__OCFT__showhost="${host}: "
+
+$(test -n "$cfg_install_package" && echo "agent_install ${cfg_install_package[@]}")
+
+$(cat $CASES_DIR/${agent}_setup)
+check_success \$? "SETUP-AGENT"
+CMD
+backbash_stop $host
+EOF
+ done
+ cat >>$CASES_DIR/setup_${agent}.sh <<EOF
+$(cat $CASES_DIR/${agent}_setup)
+check_success \$? "SETUP-AGENT"
+
+echo "Done."
+echo
+quit 0
+EOF
+ chmod a+x $CASES_DIR/setup_${agent}.sh
+ fi
+
+ if [ -r "$CASES_DIR/${agent}_cleanup" ]; then
+ cat >$CASES_DIR/cleanup_${agent}.sh <<EOF
+#!@BASH_SHELL@
+
+# Agent: $cfg_agent
+# Summary: CLEANUP after test
+
+echo "Cleaning '$cfg_agent' ..."
+
+. $OCFT_DIR/caselib || {
+ echo "ERROR: '$OCFT_DIR/caselib' not found."
+ exit 2
+}
+
+$(test -r "$CASES_DIR/${agent}_var" && cat $CASES_DIR/${agent}_var)
+$(test -n "$cfg_install_package" && echo "agent_install ${cfg_install_package[@]}")
+
+$(cat $CASES_DIR/${agent}_cleanup)
+check_success \$? "CLEANUP-AGENT"
+
+EOF
+ for host in $(test -r $CASES_DIR/${agent}_hosts && cat $CASES_DIR/${agent}_hosts); do
+ cat >>$CASES_DIR/cleanup_${agent}.sh <<EOF
+# Initialize remote shell
+backbash_start $host
+backbash $host <<CMD
+__OCFT__VERBOSE=\$__OCFT__VERBOSE
+CMD
+backbash $host <$OCFT_DIR/caselib
+backbash $host <<'CMD'
+$(test -r "$CASES_DIR/${agent}_var" && cat $CASES_DIR/${agent}_var)
+
+__OCFT__MYROOT="$cfg_agent_root"
+__OCFT__showhost="${host}: "
+
+$(test -n "$cfg_install_package" && echo "agent_install ${cfg_install_package[@]}")
+
+$(cat $CASES_DIR/${agent}_cleanup)
+check_success \$? "CLEANUP-AGENT"
+CMD
+backbash_stop $host
+EOF
+ done
+ cat >>$CASES_DIR/cleanup_${agent}.sh <<EOF
+echo "Done."
+echo
+quit 0
+EOF
+ chmod a+x $CASES_DIR/cleanup_${agent}.sh
+ fi
+ case_parse_finish
+ agent_parse_finish
+
+ done
+}
+
+start_test()
+{
+ local sh shs testsh agents line ret
+ local rc=0
+ local varlib
+ local rc_f
+
+ if ! cd $CASES_DIR >/dev/null 2>&1; then
+ die "cases directory not found."
+ fi
+
+ if [ ! -d logs ]; then
+ mkdir logs
+ fi
+
+ export __OCFT__VERBOSE=$opt_verbose
+
+ if [ $# -eq 0 ]; then
+ agents=($(ls -1 *.sh 2>/dev/null | sed 's/.*_\([^_]*\)\.sh$/\1/' | sort | uniq))
+ else
+ agents=("$@")
+ fi
+
+ for shs in "${agents[@]}"; do
+ if [ -z "$opt_incremental" ]; then
+ testsh="setup_${shs}.sh
+ $(ls -1 [0-9]*_${shs}.sh 2>/dev/null | sort -n)
+ cleanup_${shs}.sh"
+ else
+ testsh="setup_${shs}.sh
+ $(ls -1 [0-9]*_${shs}.retest 2>/dev/null | sed 's/retest$/sh/' | sort -n)
+ cleanup_${shs}.sh"
+ fi
+
+ if [ -n "$opt_trace_ra" ]; then
+ varlib=${HA_VARLIB:="/var/lib/heartbeat"}
+ export OCF_RESKEY_trace_ra=1
+ echo "RA trace on, output in $varlib/trace_ra"
+ fi
+
+ rc_f=`mktemp`
+ (for sh in $testsh; do
+ if [ -r "$sh" ]; then
+ if [ -n "$opt_trace_ra" ]; then
+ export OCF_RESOURCE_INSTANCE="`echo $sh | sed 's/_.*//'`"
+ fi
+ ./$sh
+ ret=$?
+
+ case "$sh" in
+ setup*)
+ rc=$((rc|ret))
+ if [ $ret -ne 0 ]; then
+ warn "SETUP failed, break all tests of '$shs'."
+ break
+ fi
+ ;;
+ cleanup*)
+ if [ $ret -ne 0 ]; then
+ warn "CLEANUP failed."
+ fi
+ ;;
+ [0-9]*)
+ case $ret in
+ 3) die "core function failed, break all tests." ;;
+ 2) warn "core function failed, break all tests of '$shs'."; break ;;
+ 1) touch ${sh%.*}.retest ;;
+ 0) rm -f ${sh%.*}.retest ;;
+ esac
+ rc=$((rc|ret))
+ ;;
+ esac
+ fi
+ done 2>&1; echo $rc > $rc_f) | while read -r line; do
+ echo "$line"
+ echo "$(date '+%F %T'): $line" | cat -A |
+ sed -r 's/\^\[\[[0-9]+m|\^I|.$//g' >>logs/$shs.log
+ done
+ done
+ rc=`cat $rc_f`
+ rm -f $rc_f
+ return $rc
+}
+
+agent_clean()
+{
+ local typ ra
+ typ=$1
+
+ shift
+
+ if [ $# -eq 0 ]; then
+ rm -f $CASES_DIR/*.$typ
+ else
+ for ra in "$@"; do
+ rm -f $CASES_DIR/*_${ra}.$typ
+ done
+ fi
+}
+
+agent_retest_clean()
+{
+ agent_clean retest "$@"
+}
+
+agent_obj_clean()
+{
+ agent_clean sh "$@"
+}
+
+usage()
+{
+ cat <<EOF
+$0 ACTION [OPTION] [agent1 [agent2] [...]]
+ACTIONs include:
+ make [-d dir] Generate the testing shell scripts.
+ -d The directory that contains
+ configuration of cases.
+ test [-v|-i|-X] Execute the testing shell scripts.
+ -v Verbose output mode.
+ -i Incremental mode, skip case
+ which succeeded. If cleaning
+ the status of incremental mode
+ is needed, try to '$0 clean RA_NAME'.
+ -X Trace the RA
+ clean Delete the testing shell scripts.
+ help [-v] Show this help and exit.
+ -v Show HOWTO and exit.
+Version 0.44
+See '$OCFT_DIR/README' for detail.
+EOF
+}
+
+howto()
+{
+ cat <<EOF
+HOW TO USE THIS TOOL
+
+ - Ocft is a testing tool for resource agents. Instead of the policy of HA,
+ it mainly concerns whether resource agents run correct locally. It can
+ design types of complicated environments to test the reliability of
+ resource agents. Precisely, it is to display whether resource agents can
+ return to correct or expected value. The advantage of the tool provides
+ us with competence to design conditions which can be recorded or reproduced.
+ Hence it is useful to debuggers.
+
+* Components
+ ** Test case generator (/usr/sbin/ocft)
+ - Turning configuration files of test case to executable scripts.
+
+ ** Configuration file ($CONFIGS_DIR/)
+ - Every configuration file directs only one resource agent and share the same
+ name with resource agent but contains more test cases.
+
+ ** The testing script ($CASES_DIR/)
+ - After the generator reads configuration files and generates many testing
+ scripts and the script is underway, the test begins.
+
+* How to customize the environment of testing
+ - Ocft designs the running conditions through two ways, one is changing the
+ environment variables of resource agents (it is the interface left by OCF itself),
+ the other is modifying the OS environment of resource agents, such as altering
+ the permission of some key file or IP address of the machine.
+
+* How to test
+ - Firstly, you need to sketch the all complex and uncommon environments against
+ a certain resource agent and keep in mind what consequences may be caused by
+ these uncommon environments.
+ Secondly, write the designed conditions and foreknown consequences into
+ configuration files, and then run the generator to translate the test case to
+ executable scripts.
+ Finally, you need running these scripts to observe the output and learn
+ the running status of each test case, which will compares the predicated result
+ with the actual one. If they differ, you will be able to find the bugs of the
+ resource agent.
+ - All of the output with test will be recorded into the log files, you can find them
+ in $CASES_DIR/logs.
+EOF
+}
+
+
+export LANG=C
+
+# system variable
+OCFT_DIR=@datadir@/@PACKAGE_NAME@/ocft
+CONFIGS_DIR=@datadir@/@PACKAGE_NAME@/ocft/configs
+CASES_DIR=/var/lib/@PACKAGE_NAME@/ocft/cases
+
+# global variable
+agent=
+line_num=
+
+# default configuration
+init_cfg_vars
+
+# default option
+opt_verbose=
+opt_incremental=
+opt_cfgsdir=$CONFIGS_DIR
+
+command="$1"
+shift
+
+case "$command" in
+ make)
+ if [ "$1" = "-d" ]; then
+ if [ ! -d "$2" ]; then
+ usage
+ exit 1
+ fi
+ opt_cfgsdir="$2"
+ shift 2
+ fi
+ if [ ! -d "$CASES_DIR" ]; then
+ mkdir -p "$CASES_DIR" || die "Can not create directory: ${CASES_DIR}."
+ fi
+ parse_cfg "$@"
+ ;;
+ test)
+ for v in 1 2 3; do
+ case "$1" in
+ -v)
+ opt_verbose=1
+ shift
+ ;;
+ -X)
+ opt_trace_ra=1
+ shift
+ ;;
+ -i)
+ opt_incremental=1
+ shift
+ ;;
+ -*)
+ die "bad option $1"
+ ;;
+ esac
+ done
+ start_test "$@"
+ ;;
+ clean)
+ agent_obj_clean "$@"
+ agent_retest_clean "$@"
+ ;;
+ help)
+ if [ "$1" = "-v" ]; then
+ howto
+ else
+ usage
+ fi
+ exit 0
+ ;;
+ *)
+ usage
+ exit 1
+ ;;
+esac
+
+# vim:ts=2:sw=2:et:
diff --git a/tools/ocft/oracle b/tools/ocft/oracle
new file mode 100644
index 0000000..6f145c7
--- /dev/null
+++ b/tools/ocft/oracle
@@ -0,0 +1,81 @@
+# oracle
+# (based on db2)
+#
+# Created on an SLE11SP2 running oracle 11g
+# database sid is orcl
+# adapt this in set_testenv below
+# TODO: need oracle expert to break it, then test it
+#
+
+CONFIG
+ Agent oracle
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ HangTimeout 40
+
+SETUP-AGENT
+ # nothing
+
+CASE-BLOCK set_testenv
+ Env OCFT_sid=orcl
+
+CASE-BLOCK crm_setting
+ Env OCF_RESKEY_sid=$OCFT_sid
+ Env OCF_RESKEY_CRM_meta_timeout=30000
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include set_testenv
+ Include crm_setting
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: no 'OCF_RESKEY_sid'"
+ Include prepare
+ Env OCF_RESKEY_sid=
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "check base env: invalid 'OCF_RESKEY_home'"
+ Include prepare
+ Env OCF_RESKEY_home=/no_such
+ AgentRun start OCF_ERR_INSTALLED
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "started: monitor"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "not started: monitor"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "try different ipcrm method"
+ Include prepare
+ Env OCF_RESKEY_ipcrm=none
+ AgentRun start OCF_SUCCESS
diff --git a/tools/ocft/pgsql b/tools/ocft/pgsql
new file mode 100644
index 0000000..9944b09
--- /dev/null
+++ b/tools/ocft/pgsql
@@ -0,0 +1,71 @@
+# pgsql
+
+CONFIG
+ Agent pgsql
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ InstallPackage postgresql-server
+ HangTimeout 20
+
+SETUP-AGENT
+ /etc/init.d/postgresql start
+ /etc/init.d/postgresql stop
+
+CASE-BLOCK crm_setting
+ Env OCF_RESKEY_CRM_meta_timeout=15000
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include crm_setting
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: invalid 'OCF_RESKEY_pgctl'"
+ Include prepare
+ Env OCF_RESKEY_pgctl=no_such
+ AgentRun start OCF_ERR_INSTALLED
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "running monitor"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "not running monitor"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
+
+CASE "non-existent user"
+ Include prepare
+ Env OCF_RESKEY_pgdba=no_user
+ AgentRun start OCF_ERR_INSTALLED
+
+CASE "invalid user"
+ Include prepare
+ Env OCF_RESKEY_pgdba=nobody
+ AgentRun start OCF_ERR_PERM
diff --git a/tools/ocft/portblock b/tools/ocft/portblock
new file mode 100644
index 0000000..3475c63
--- /dev/null
+++ b/tools/ocft/portblock
@@ -0,0 +1,69 @@
+# portblock
+
+CONFIG
+ Agent portblock
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ InstallPackage iptables
+ HangTimeout 15
+
+CASE-BLOCK required_args
+ Env OCF_RESKEY_protocol=tcp
+ Env OCF_RESKEY_portno=80
+ Env OCF_RESKEY_action=block
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include required_args
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: unset 'OCF_RESKEY_protocol'"
+ Include prepare
+ Unenv OCF_RESKEY_protocol
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "check base env: unset 'OCF_RESKEY_portno'"
+ Include prepare
+ Unenv OCF_RESKEY_portno
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "check base env: unset 'OCF_RESKEY_action'"
+ Include prepare
+ Unenv OCF_RESKEY_action
+ AgentRun start OCF_ERR_CONFIGURED
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "monitor with running"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "monitor with not running"
+ Include prepare
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
diff --git a/tools/ocft/postfix b/tools/ocft/postfix
new file mode 100644
index 0000000..f17e968
--- /dev/null
+++ b/tools/ocft/postfix
@@ -0,0 +1,102 @@
+# postfix
+# by r.bhatia@ipax.at
+#
+# test cases (to implement):
+#
+# * /usr/sbin/ocf-tester -n post1 /usr/lib/ocf/resource.d/heartbeat/postfix; echo $? -> DONE
+# * /usr/sbin/ocf-tester -n post2 -o binary="/usr/sbin/postfix" \
+# -o config_dir="" /usr/lib/ocf/resource.d/heartbeat/postfix; echo $? -> DONE
+# * /usr/sbin/ocf-tester -n post3 -o binary="/usr/sbin/postfix" \
+# -o config_dir="/etc/postfix" /usr/lib/ocf/resource.d/heartbeat/postfix; echo $? -> DONE
+# * /usr/sbin/ocf-tester -n post4 -o binary="/usr/sbin/postfix" \
+# -o config_dir="/root/postfix/" /usr/lib/ocf/resource.d/heartbeat/postfix; echo $?
+
+CONFIG
+ Agent postfix
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ InstallPackage postfix
+ HangTimeout 20
+
+SETUP-AGENT
+ # nothing
+
+CASE-BLOCK crm_setting
+ Env OCF_RESKEY_CRM_meta_timeout=15000
+ Env OCF_RESKEY_CRM_meta_interval=10000
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include crm_setting
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: invalid 'OCF_RESKEY_binary'"
+ Include prepare
+ Env OCF_RESKEY_binary=no_such
+ AgentRun start OCF_ERR_INSTALLED
+
+CASE "check base env: invalid 'OCF_RESKEY_config_dir'"
+ Include prepare
+ Env OCF_RESKEY_config_dir=no_such
+ AgentRun start OCF_ERR_INSTALLED
+
+CASE "check base env: 'OCF_RESKEY_binary'"
+ Include prepare
+ Env OCF_RESKEY_binary=/usr/sbin/postfix
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "check base env: 'OCF_RESKEY_config_dir' without trailing slash"
+ Include prepare
+ Env OCF_RESKEY_config_dir="/etc/postfix"
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "check base env: 'OCF_RESKEY_config_dir' with trailing slash"
+ Include prepare
+ Env OCF_RESKEY_config_dir="/etc/postfix/"
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop OCF_SUCCESS
+
+CASE "monitor a running resource"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "(initial) probe a stopped resource"
+ Include prepare
+ Env OCF_RESKEY_CRM_meta_interval=0
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "(re-)probe a running resource"
+ Include prepare
+ Env OCF_RESKEY_CRM_meta_interval=0
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "unimplemented command"
+ Include prepare
+ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED
diff --git a/tools/ocft/runocft b/tools/ocft/runocft
new file mode 100755
index 0000000..d269a6b
--- /dev/null
+++ b/tools/ocft/runocft
@@ -0,0 +1,38 @@
+#!/bin/sh
+OCFTDIR=/usr/share/resource-agents/ocft
+CONFDIR=$OCFTDIR/configs
+
+prereq_run() {
+ eval "$@"
+}
+prereq_prog() {
+ which $@
+}
+
+test_prereq() {
+ local tp arg
+ tp=`echo $prereq|sed 's/:.*//'`
+ arg=`echo $prereq|sed 's/[a-z]*://'`
+ prereq_$tp $arg >/dev/null 2>&1
+}
+
+rm -f ocft.FAILED
+rc=0
+while read f prereq; do
+ if [ -n "$prereq" ] && ! test_prereq; then
+ echo "$f: prerequisite not fulfilled, skipping"
+ continue
+ fi
+ ocft make $f
+ if ! ocft test $f; then
+ echo $f >> ocft.FAILED
+ rc=1
+ fi
+done < $OCFTDIR/runocft.prereq
+
+if [ -f ocft.FAILED ]; then
+ echo "The following ocft tests failed:"
+ cat ocft.FAILED
+fi
+
+exit $rc
diff --git a/tools/ocft/runocft.prereq b/tools/ocft/runocft.prereq
new file mode 100644
index 0000000..3bc222c
--- /dev/null
+++ b/tools/ocft/runocft.prereq
@@ -0,0 +1,30 @@
+apache
+db2 prog:~db2inst1/sqllib/bin/db2
+drbd.linbit run:false
+exportfs
+exportfs-multidir
+Filesystem
+IPaddr2 run:ip addr show dev eth0
+IPaddr2v4 run:ip addr show dev eth0 && ip addr show dev eth1
+IPaddr2v6 run:ip addr show dev eth0 && ip addr show dev eth1
+IPsrcaddr run:false
+IPv6addr run:ip addr show dev eth0 && ip addr show dev eth1
+iscsi
+jboss run:false
+LVM
+MailTo
+mysql
+mysql-proxy run:false
+named
+nfsserver
+oracle prog:sqlplus
+pgsql
+portblock
+postfix
+Raid1
+SendArp
+sg_persist run:false
+tomcat run:false
+VirtualDomain run:false
+Xen run:false
+Xinetd
diff --git a/tools/ocft/sg_persist b/tools/ocft/sg_persist
new file mode 100644
index 0000000..f11d36d
--- /dev/null
+++ b/tools/ocft/sg_persist
@@ -0,0 +1,225 @@
+# sg_persist
+# Before use sg_persist ocft test case you have to prepare to make pacemaker
+# can be started successfully because sg_persist RA needs to use the result of
+# `crm_node -i` as sg_persist register key.
+
+CONFIG
+ Agent sg_persist
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ InstallPackage sg3_utils
+ HangTimeout 20
+
+VARIABLE
+
+ # Please set the disk you want to test
+ #OCFT_DEVS="/dev/disk/by-id/scsi-14945540000000000844965720e6e555176b19461345d68d5"
+ OCFT_DEVS=
+
+ # please set the IP addrees of the other server.
+ IP_2=
+
+SETUP-AGENT
+ # start pacemaker to get node_id through crm_node -i
+ systemctl start pacemaker
+
+CLEANUP-AGENT
+
+CASE-BLOCK required_args
+ Env HA_SBIN_DIR=""
+ Env OCF_RESKEY_devs="$OCFT_DEVS"
+ Env OCF_RESKEY_reservation_type=1
+ Env OCF_RESKEY_CRM_meta_notify=true
+ Env OCF_RESKEY_CRM_meta_master_max=1
+
+CASE-BLOCK required_args_error
+ Env HA_SBIN_DIR=""
+ Env OCF_RESKEY_devs="$OCFT_DEVS"
+ Env OCF_RESKEY_reservation_type=1
+ Env OCF_RESKEY_CRM_meta_notify=true
+ Env OCF_RESKEY_CRM_meta_master_max=2
+
+CASE-BLOCK required_args_type_5
+ Env HA_SBIN_DIR=""
+ Env OCF_RESKEY_devs="$OCFT_DEVS"
+ Env OCF_RESKEY_reservation_type=5
+ Env OCF_RESKEY_CRM_meta_notify=true
+ Env OCF_RESKEY_CRM_meta_master_max=1
+
+CASE-BLOCK required_args_type_7
+ Env HA_SBIN_DIR=""
+ Env OCF_RESKEY_devs="$OCFT_DEVS"
+ Env OCF_RESKEY_reservation_type=7
+ Env OCF_RESKEY_CRM_meta_notify=true
+ Env OCF_RESKEY_CRM_meta_master_max=2
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare
+ Include required_args
+ Include default_status
+
+CASE-BLOCK prepare_type_5
+ Include required_args_type_5
+ Include default_status
+
+CASE-BLOCK prepare_type_7
+ Include required_args_type_7
+ Include default_status
+
+CASE "check base env"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "check base env: unset 'OCF_RESKEY_sg_persist_devs'"
+ Include prepare
+ Unenv OCF_RESKEY_devs
+ AgentRun start OCF_ERR_INSTALLED
+
+CASE "validate all"
+ Include required_args
+ AgentRun validate-all OCF_SUCCESS
+
+CASE "validate all--type:5"
+ Include required_args_type_5
+ AgentRun validate-all OCF_SUCCESS
+
+CASE "validate all--type:7"
+ Include required_args_type_7
+ AgentRun validate-all OCF_SUCCESS
+
+CASE "validate all--error configured"
+ Include required_args_error
+ AgentRun validate-all OCF_ERR_CONFIGURED
+
+CASE "normal start"
+ Include prepare
+ AgentRun start OCF_SUCCESS
+
+CASE "normal stop"
+ Include prepare
+ AgentRun start
+ AgentRun stop OCF_SUCCESS
+
+CASE "double start"
+ Include prepare
+ AgentRun start
+ AgentRun start OCF_SUCCESS
+
+CASE "double stop"
+ Include prepare
+ AgentRun stop
+ AgentRun stop OCF_SUCCESS
+
+CASE "monitor when running"
+ Include prepare
+ AgentRun start
+ AgentRun monitor OCF_SUCCESS
+
+CASE "monitor when not running"
+ Include prepare
+ AgentRun stop
+ AgentRun monitor OCF_NOT_RUNNING
+
+CASE "Primary/Secondary monitor"
+ Include prepare
+ AgentRun start
+ AgentRun promote
+ AgentRun monitor OCF_RUNNING_MASTER
+ AgentRun demote
+ AgentRun monitor OCF_SUCCESS
+ AgentRun stop
+
+CASE "promote/demote test in single-primary mode"
+ Include prepare
+ Include@$IP_2 prepare
+
+ # start
+ AgentRun start
+ AgentRun@$IP_2 start
+
+ # promote local first
+ AgentRun promote OCF_SUCCESS
+
+ # demote local prepare for remote promote
+ AgentRun demote
+
+ # remote promote
+ AgentRun@$IP_2 promote OCF_SUCCESS
+ AgentRun@$IP_2 monitor OCF_RUNNING_MASTER
+ AgentRun monitor OCF_SUCCESS
+
+ # promote local then promote(by preempt) remote, which will cause local OCF_NOT_RUNNING
+ AgentRun promote OCF_SUCCESS
+ AgentRun monitor OCF_RUNNING_MASTER
+ AgentRun@$IP_2 monitor OCF_NOT_RUNNING
+
+ # remove all reservation registration
+ AgentRun demote
+ AgentRun stop
+ AgentRun@$IP_2 stop
+
+
+CASE "normal start--type 5"
+ Include prepare_type_5
+ Include@$IP_2 prepare_type_5
+ AgentRun start OCF_SUCCESS
+ AgentRun@$IP_2 start OCF_SUCCESS
+
+CASE "promote/demote test in single-primary mode"
+ Include prepare_type_5
+ Include@$IP_2 prepare_type_5
+
+ # start
+ AgentRun start
+ AgentRun@$IP_2 start
+
+ # promote local first
+ AgentRun promote OCF_SUCCESS
+ AgentRun monitor OCF_RUNNING_MASTER
+
+ # demote local prepare for remote promote
+ AgentRun demote
+ # remote promote
+ AgentRun@$IP_2 promote OCF_SUCCESS
+ AgentRun@$IP_2 monitor OCF_RUNNING_MASTER
+ AgentRun monitor OCF_SUCCESS
+
+ # promote local then promote(by preempt) remote, which will cause local OCF_NOT_RUNNING
+ AgentRun promote OCF_SUCCESS
+ AgentRun monitor OCF_RUNNING_MASTER
+ AgentRun@$IP_2 monitor OCF_NOT_RUNNING
+
+ # remove all reservation registration
+ AgentRun demote
+ AgentRun stop
+ AgentRun@$IP_2 stop
+
+CASE "normal start--type 7: 2 masters"
+ Include prepare_type_7
+ Include@$IP_2 prepare_type_7
+ AgentRun start OCF_SUCCESS
+ AgentRun@$IP_2 start OCF_SUCCESS
+
+
+CASE "Primary/Primary monitor--type 7"
+ Include prepare_type_7
+ Include@$IP_2 prepare_type_7
+
+ AgentRun start OCF_SUCCESS
+ AgentRun@$IP_2 start OCF_SUCCESS
+
+ AgentRun promote OCF_SUCCESS
+ AgentRun monitor OCF_RUNNING_MASTER
+
+ AgentRun@$IP_2 promote OCF_SUCCESS
+ AgentRun monitor OCF_RUNNING_MASTER
+ AgentRun@$IP_2 monitor OCF_RUNNING_MASTER
+
+ AgentRun demote OCF_SUCCESS
+ AgentRun monitor OCF_NOT_RUNNING
+ AgentRun@$IP_2 demote OCF_SUCCESS
+ AgentRun@$IP_2 monitor OCF_NOT_RUNNING
+
+ AgentRun stop
+ AgentRun@$IP_2 stop
diff --git a/tools/ocft/tomcat b/tools/ocft/tomcat
new file mode 100644
index 0000000..56adf86
--- /dev/null
+++ b/tools/ocft/tomcat
@@ -0,0 +1,73 @@
+# tomcat
+#
+# NOTE: Clean up $catalina_home/logs before running this test
+# otherwise creating the pid/log files may fail
+# in the test case with a different user.
+
+CONFIG
+ Agent tomcat
+ AgentRoot /usr/lib/ocf/resource.d/heartbeat
+ HangTimeout 120
+
+VARIABLE
+ # Adjust accrding to your configuration
+ catalina_home=/opt/tomcat7
+ tomcat_user=tomcat7
+ java_home=/usr/lib/jvm/java-1.6.0-openjdk.x86_64
+
+CASE-BLOCK required_args_tomcat
+ Env OCF_RESKEY_catalina_home=${catalina_home}
+ Env OCF_RESKEY_tomcat_user=${tomcat_user}
+ Env OCF_RESKEY_java_home=${java_home}
+
+CASE-BLOCK args_clear
+ Unenv OCF_RESKEY_catalina_home
+ Unenv OCF_RESKEY_tomcat_user
+ Unenv OCF_RESKEY_java_home
+
+CASE-BLOCK default_status
+ AgentRun stop
+
+CASE-BLOCK prepare_tomcat
+ Include required_args_tomcat
+ Include default_status
+
+# Test CASE
+#
+CASE "normal start tomcat require_args (user:user)"
+ Include prepare_tomcat
+ AgentRun start OCF_SUCCESS
+ AgentRun monitor OCF_SUCCESS
+ AgentRun stop OCF_SUCCESS
+ AgentRun monitor OCF_NOT_RUNNING
+ Include args_clear
+
+CASE "normal start tomcat require_args (user:root)"
+ Include prepare_tomcat
+ Unenv OCF_RESKEY_tomcat_user
+ AgentRun start OCF_SUCCESS
+ AgentRun monitor OCF_SUCCESS
+ AgentRun stop OCF_SUCCESS
+ AgentRun monitor OCF_NOT_RUNNING
+ Include args_clear
+
+CASE "error start tomcat no catalina_home"
+ Include prepare_tomcat
+ Unenv OCF_RESKEY_catalina_home
+ AgentRun start OCF_ERR_INSTALLED
+ Include args_clear
+
+CASE "error start tomcat no java_home"
+ Include prepare_tomcat
+ Unenv OCF_RESKEY_java_home
+ AgentRun start OCF_ERR_INSTALLED
+ Include args_clear
+
+CASE "error start tomcat no java command"
+ Include prepare_tomcat
+ Env OCF_RESKEY_java_home=/var
+ AgentRun start OCF_ERR_INSTALLED
+ AgentRun stop OCF_SUCCESS
+ AgentRun monitor OCF_NOT_RUNNING
+ Include args_clear
+