#!/bin/bash description=" fence_ec2 is an I/O Fencing agent which can be used with Amazon EC2 instances. In order to function, the agent needs the private key and cert used by the Amazon EC2 API. API functions used by this agent: - ec2-describe-tags - ec2-describe-instances - ec2-stop-instances - ec2-start-instances - ec2-reboot-instances If the uname used by the cluster node is any of: - Public DNS name (or part there of), - Private DNS name (or part there of), - Instance ID (eg. i-4f15a839) - Contents of tag associated with the instance then the agent should be able to automatically discover the instances it can control. If the tag containing the uname is not [Name], then it will need to be specified using the [tag] option. " # # Copyright (c) 2011 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. # ####################################################################### quiet=0 port="" instance_not_found=0 unknown_are_stopped=0 action="reset" # Default fence action ec2_tag="Name" # EC2 Tag containing the instance's uname ec2_key="" # EC2 Private Key ec2_cert="" # EC2 Cert ec2_region="us-east-1" # EC2 Region if [ -z "$EC2_HOME" ]; then EC2_HOME="$HOME/.ec2" fi function usage() { cat < $description Fencing Action The name/id/tag of a instance to control/check Location of Amazon EC2 command line tools The private key to use when constructing requests to Amazon EC2 The X.509 certificate to use when constructing requests to Amazon EC2 The Amazon region for which the device should control instances Name of the tag containing the instances uname DANGER: Assume any unknown instance is safely stopped EOF exit 0; } function instance_for_port() { port=$1; shift # Look for port name -n in the INSTANCE data instance=`ec2-describe-instances $* | grep INSTANCE.*$port | awk '{print $2}'` if [ -z $instance ]; then # Look for port name -n in the Name TAG instance=`ec2-describe-tags $* | grep TAG.*$ec2_tag.*$port | awk '{print $3}'` fi if [ -z $instance ]; then instance_not_found=1 instance=$port fi echo $instance } TEMP=`getopt -o qVo:e:k:c:r:n:t:U --long version,help,region:,action:,port:,option:,ec2-home:,private-key:,cert:,tag:,quiet,unknown-are-stopped \ -n 'fence_ec2' -- "$@"` if [ $? != 0 ];then usage exit 1 fi # Note the quotes around `$TEMP': they are essential! eval set -- "$TEMP" if [ -z $1 ]; 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/.*=//`;; ec2-home=*) EC2_HOME=`echo $line | sed s/.*=//`;; private-key=*) ec2_key=`echo $line | sed s/.*=//`;; cert=*) ec2_cert=`echo $line | sed s/.*=//`;; region=*) ec2_region=`echo $line | sed s/.*=//`;; tag=*) ec2_tag=`echo $line | sed s/.*=//`;; quiet*) quiet=1;; unknown-are-stopped*) unknown_are_stopped=1;; --);; *) echo "Invalid command: $line";; esac done fi while true ; do case "$1" in -o|--action|--option) action=$2; shift; shift;; -n|--port) port=$2; shift; shift;; -e|--ec2-home) EC2_HOME=$2; shift; shift;; -k|--private-key) ec2_key=$2; shift; shift;; -c|--cert) ec2_cert=$2; shift; shift;; -r|--region) ec2_region=$2; shift; shift;; -t|--tag) ec2_tag=$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 ;; *) echo "Unknown option: $1. See --help for details."; exit 1;; esac done export EC2_HOME PATH=$PATH:$EC2_HOME/bin if [ -z "$JAVA_HOME" ]; then java=`which java` while [ -L "$java" ]; do java=`/bin/ls -l $java | awk '{print $11}'` done export JAVA_HOME=`dirname $java`/.. fi if [ -z "$ec2_key" ]; then ec2_key=`ls $EC2_HOME/pk-*.pem`; fi if [ -z "$ec2_cert" ]; then ec2_cert=`ls $EC2_HOME/cert-*.pem`; fi options="--region $ec2_region --private-key $ec2_key --cert $ec2_cert" action=`echo $action | tr 'A-Z' 'a-z'` instance="" if [ ! -z "$port" ]; then instance=`instance_for_port $port $options` fi case $action in reboot|reset) if [ $unknown_are_stopped = 1 -a $instance_not_found ]; then : nothing we _can_ do echo "Assuming unknown instance $instance is already off, cannot restart" else ec2-reboot-instances $options $instance fi ;; poweron|on) ec2-start-instances $options $instance ;; poweroff|off) if [ $unknown_are_stopped = 1 -a $instance_not_found ]; then : nothing to do echo "Assuming unknown instance $instance is already off" else ec2-stop-instances $options $instance fi ;; monitor) # Is the device ok? ec2-describe-instances | grep INSTANCE &> /dev/null ;; hostlist|list) # List of names we know about ec2-describe-instances $options | awk -v tag_pat="^TAG\tinstance\t.*\t$ec2_tag" -F '\t' '{ if (/^INSTANCE.*pending/) { printf "%s\n", $2 } else if (/^INSTANCE.*stopped/) { printf "%s\n", $2 } else if (/^INSTANCE/) { printf "%s\n%s\n%s\n", $2, $4, $5 } else if ( $1"\t"$2"\t"$3"\t"$4 ~ tag_pat ) { printf "%s\n", $5 } }' | sort -u ;; stat|status) # List of instances and their current status if [ $unknown_are_stopped = 1 -a $instance_not_found ]; then echo "$instance stopped (unknown)" else ec2-describe-instances $options $instance | awk '{ if (/^INSTANCE.*pending/) { printf "%s %s\n", $2, $4 } else if (/^INSTANCE.*stopped/) { printf "%s %s\n", $2, $4 } else if (/^INSTANCE/) { printf "%s %s %s %s\n", $2, $6, $4, $5 } }' fi ;; metadata) metadata ;; *) echo "Unknown action: $action"; exit 1;; esac status=$? if [ $quiet -eq 1 ]; then : nothing elif [ $status -eq 0 ]; then echo "Operation $action passed" else echo "Operation $action failed: $status" fi exit $status