用于openstack环境中的fence.
RHCS Fencing Agent for use on OpenStack guests
#!/bin/bash
#
# Copyright (c) 2012 Andrew Beekhof
# 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.
#
#######################################################################
description="
fence_openstack is an I/O Fencing agent which can be used with
OpenStack instances. In order to function, the agent needs the Python
nova client and the following data:
- region name
- tenant name
- authentication url (eg. http://open.stack:5000/v2.0/)
- user name
- password
The value for 'port' can either be the.
- Instance name (must not contain spaces),
- Instance ID (eg. 0365bd97-3c2d-416f-ae07-b9772aff5938)
If the name used by the cluster node is one of these values, then,
when used with Pacemaker, the agent should be able to automatically
discover the instances it can control.
The name and id values can be obtained using 'nova list', eg.
+--------------------------------------+----------------+--------+---------------------------------------+
| ID | Name | Status | Networks |
+--------------------------------------+----------------+--------+---------------------------------------+
| 0365bd97-3c2d-416f-ae07-b9772aff5938 | CTS-Master | ACTIVE | novanetwork=192.168.0.40, 10.16.16.55 |
| 7320e184-afbd-46a8-aec7-94c38ec67e21 | Fedora-18-base | ACTIVE | novanetwork=192.168.0.9 |
+--------------------------------------+----------------+--------+---------------------------------------+
"
port=""
quiet=0
unknown_are_stopped=0
action="list" # Default fence action
# Inherit from the environment if present
os_region="$OS_REGION_NAME"
os_tenant="$OS_TENANT_NAME"
os_auth="$OS_AUTH_URL"
os_user="$OS_USERNAME"
os_pass="$OS_PASSWORD"
function usage()
{
cat <<EOF
`basename $0` - A fencing agent for OpenStack instances
$description
Usage: `basename $0` -o|--action [-n|--port] [options]
Options:
-h, --help This text
-V, --version Version information
-q, --quiet Reduced output mode
Commands:
-o, --action Action to perform: on|off|reboot|status|monitor
-n, --port The name of a machine/instance to control/check
Additional Options:
-a, --auth The OpenStack authentication URL (eg. http://open.stack:5000/v2.0/)
-r, --region The OpenStack region for which the device should control instances (defaults to us-east-1)
-t, --tenant The OpenStack tenant name. Might match the username.
-u, --user The OpenStack username to connect as
-p, --pass The OpenStack password
Dangerous options:
-U, --unknown-are-stopped Assume any unknown instance is safely stopped
EOF
exit 0;
}
function metadata()
{
cat <<EOF
<?xml version="1.0" ?>
<resource-agent name="fence_openstack" shortdesc="Fencing agent for OpenStack instances" >
<longdesc>
$description
</longdesc>
<parameters>
<parameter name="action" unique="1" required="0">
<getopt mixed="-o, --action=[action]" />
<content type="string" default="reboot" />
<shortdesc lang="en">Fencing Action</shortdesc>
</parameter>
<parameter name="port" unique="1" required="0">
<getopt mixed="-n, --port=[port]" />
<content type="string" />
<shortdesc lang="en">The name/id of a instance to control/check</shortdesc>
</parameter>
<parameter name="auth" unique="0" required="0">
<getopt mixed="-a, --auth=[url]" />
<content type="string" />
<shortdesc lang="en">The OpenStack authentication URL (eg. http://open.stack:5000/v2.0/)</shortdesc>
</parameter>
<parameter name="region" unique="0" required="0">
<getopt mixed="-r, --region" />
<content type="string" />
<shortdesc lang="en">The OpenStack region for which the device should control instances (defaults to us-east-1)</shortdesc>
</parameter>
<parameter name="tenant" unique="0" required="0">
<getopt mixed="-t, --tenant" />
<content type="string" />
<shortdesc lang="en">The OpenStack tenant name. Might match the username.</shortdesc>
</parameter>
<parameter name="user" unique="0" required="0">
<getopt mixed="-u, --user" />
<content type="string" />
<shortdesc lang="en">The OpenStack username to connect as</shortdesc>
</parameter>
<parameter name="password" unique="0" required="0">
<getopt mixed="-p, --password" />
<content type="string" />
<shortdesc lang="en">The OpenStack password</shortdesc>
</parameter>
<parameter name="unknown-are-stopped" unique="1" required="0">
<getopt mixed="-U, --unknown-are-stopped" />
<content type="string" default="false" />
<shortdesc lang="en">DANGER: Assume any unknown instance is safely stopped</shortdesc>
</parameter>
</parameters>
<actions>
<action name="on" />
<action name="off" />
<action name="reboot" />
<action name="status" />
<action name="list" />
<action name="monitor" />
<action name="metadata" />
</actions>
</resource-agent>
EOF
exit 0;
}
function debug() {
if [ $quiet -eq 1 ]; then
: nothing
else
printf "$*\n"
fi
}
function error() {
printf "$*\n" 1>&2
}
function fence_done()
{
if [ $quiet -eq 1 ]; then
: nothing
elif [ $1 -eq 0 ]; then
debug "Operation $action (port=$port) passed"
else
error "Operation $action (port=$port) failed: $1"
fi
exit $1
}
function instance_for_port()
{
# Do any funky mapping (like partial ID matches) here
echo $1
}
function status_for_port() {
status=`$nova show $1 | grep status | awk '{ print $4 }'`
if [ -z $status ]; then
if [ $unknown_are_stopped = 1 ]; then
echo "STOPPED"
else
echo "UNKNOWN"
fi
else
echo $status
fi
}
TEMP=`getopt -o qVo:e:k:c:r:n:t:U -l version,help,region:,action:,port:,option:,home:,region:,cert:,tenant:,user:,password:,unknown-are-stopped \
-n 'fence_ec2' -- "$@"`
if [ $? != 0 ];then
usage
exit 1
fi
# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"
# stdin option processing
if [ -z $2 ]; then
# If there are no command line args, look for options from stdin
while read line; do
case $line in
option=*|action=*) action=`echo $line | sed s/.*=//`;;
port=*) port=`echo $line | sed s/.*=//`;;
region=*) os_region=`echo $line | sed s/.*=//`;;
tenant=*) os_tenant=`echo $line | sed s/.*=//`;;
auth=*) os_auth=`echo $line | sed s/.*=//`;;
user=*) os_user=`echo $line | sed s/.*=//`;;
password=*) os_pass=`echo $line | sed s/.*=//`;;
quiet*) quiet=1;;
unknown-are-stopped*) unknown_are_stopped=1;;
--);;
*) error "Invalid command: $line";;
esac
done
fi
# Command line option processing
while true ; do
case "$1" in
-o|--action|--option) action=$2; shift; shift;;
-n|--port) port=$2; shift; shift;;
-r|--region) os_region=$2; shift; shift;;
-t|--tenant) os_tenant=$2; shift; shift;;
-a|--auth) os_auth=$2; shift; shift;;
-u|--user) os_user=$2; shift; shift;;
-p|--password) os_pass=$2; shift; shift;;
-U|--unknown-are-stopped) unknown_are_stopped=1; shift;;
-q|--quiet) quiet=1; shift;;
-V|--version) echo "1.0.0"; exit 0;;
--help|-h)
usage;
exit 0;;
--) shift ; break ;;
*) error "Unknown option: $1. See --help for details."; exit 1;;
esac
done
# Normalize the action
action=`echo $action | tr 'A-Z' 'a-z'`
case $action in
hostlist|list) action=list;;
stat|status) action=status;;
reboot|reset) action=reboot;;
poweron|on) action=start;;
poweroff|off) action=stop;;
esac
nova="nova --os-username $os_user --os-password $os_pass --os-tenant-name $os_tenant --os-auth-url $os_auth"
instance=""
if [ ! -z "$port" ]; then
instance=`instance_for_port $port`
fi
case $action in
metadata) metadata;;
list)
# List of names we know about
$nova list | grep -v -e Status -e --- | awk '{print $4 " " $2}'
;;
monitor)
# Is the device ok?
$nova list &> /dev/null
if [ $? != 0 ]; then
# If there is a problem, we're probably interested in the output
$nova list 1>&2
fi
;;
status)
state=`status_for_port $instance`
case $state in
ACTIVE) fence_done 0;;
STOPPED) fence_done 1;;
PAUSED) fence_done 2;;
SUSPENDED) fence_done 3;;
UNKNOWN) fence_done 99;;
*) error "Unexpected state: $state"; fence_done 100;;
esac
;;
reboot)
state=`status_for_port $instance`
case $state in
UNKNOWN)
error "Cannot $action unknown instance: $port"
fence_done 1
;;
SUSPENDED)
$nova resume $instance
while [ $state != ACTIVE ]; do
state=`status_for_port $instance`
done
$nova $action $instance
;;
PAUSED)
$nova unpause $instance
while [ $state != ACTIVE ]; do
state=`status_for_port $instance`
done
$nova $action $instance;;
ACTIVE) $nova $action $instance;;
STOPPED) $nova start $instance;;
*) error "Cannot $action instance $port in unexpected state: $status"; fence_done 1;;
esac
;;
start)
state=`status_for_port $instance`
case $state in
UNKNOWN)
error "Cannot perform $action action on unknown instance: $port"
fence_done 1
;;
SUSPENDED) $nova resume $instance;;
PAUSED) $nova unpause $instance;;
ACTIVE) debug "Already active";;
STOPPED) $nova $action $instance;;
*) error "Cannot $action instance $port in unexpected state: $status"; fence_done 1;;
esac
;;
stop)
state=`status_for_port $instance`
case $state in
UNKNOWN)
error "Cannot perform $action action on unknown instance: $port"
fence_done 1
;;
STOPPED|PAUSED|SUSPENDED)
# Stop, start, and reboot do not function on a suspended or paused instances
# But for all intensive purposes they are already in a safe state
debug "$instance is $state"
;;
ACTIVE) $nova $action $instance;;
*) error "Cannot perform $action action on instance $port in unexpected state: $status"; fence_done 1;;
esac
;;
*) error "Unknown action: $action"; fence_done 1;;
esac
fence_done $?
[参考]