#!/bin/bash
#
#	ManageVE OCF RA. Manages OpenVZ Virtual Environments (VEs)
#
#   (c) 2006-2010 Matthias Dahl, Florian Haas,
#                 and Linux-HA contributors
#
# 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.
#
#
# This OCF compliant resource agent manages OpenVZ VEs and thus requires
# a proper OpenVZ installation including a recent vzctl util.
#
# rev. 1.00.4
#
# Changelog
#
# 21/Oct/10 1.00.4 implement migrate_from/migrate_to
# 12/Sep/06 1.00.3 more cleanup
# 12/Sep/06 1.00.2 fixed some logic in start_ve
#                  general cleanup all over the place
# 11/Sep/06 1.00.1 fixed some typos
# 07/Sep/06 1.00.0 it's alive... muahaha... ALIVE... :-)
# 

###
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
###

# required utilities
VZCTL=/usr/sbin/vzctl

#
# usage()
#
usage()
{
	cat <<-EOF
	usage: $0 {start|stop|status|monitor|migrate_from|migrate_to|validate-all|usage|meta-data}
	EOF
}

#
# meta_data()
#
meta_data()
{
	cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="ManageVE">
  <version>1.00.4</version>

  <longdesc lang="en">
    This OCF compliant resource agent manages OpenVZ VEs and thus requires
    a proper OpenVZ installation including a recent vzctl util.
  </longdesc>

  <shortdesc lang="en">Manages an OpenVZ Virtual Environment (VE)</shortdesc>

  <parameters>
    <parameter name="veid" unique="0" required="1">
      <longdesc lang="en">
        OpenVZ ID of virtual environment (see output of vzlist -a for all assigned IDs)
      </longdesc>
      <shortdesc lang="en">OpenVZ ID of VE</shortdesc>
      <content type="integer" default="" />
    </parameter>
  </parameters>

  <actions>
    <action name="start" timeout="75" />
    <action name="stop" timeout="75" />
    <action name="status" depth="0" timeout="10" interval="10" />
    <action name="monitor" depth="0" timeout="10" interval="10" />
    <action name="migrate_to" timeout="75" />
    <action name="migrate_from" timeout="75" />
    <action name="validate-all" timeout="5" />
    <action name="meta-data" timeout="5" />
  </actions>
</resource-agent>
END
}

#
# start_ve()
#
# Starts a VE, or simply logs a message if the VE is already running.
#
start_ve()
{
  if status_ve; then
	ocf_log info "VE $VEID already running."
	return $OCF_SUCCESS
  fi

  ocf_run $VZCTL start $VEID || exit $OCF_ERR_GENERIC

  return $OCF_SUCCESS
}

#
# stop_ve()
#
# ATTENTION: The following code relies on vzctl's exit codes, especially:
#
#   0 : success
#
# In case any of those exit codes change, this function will need fixing.
#
stop_ve()
{
  status_ve
  if [ $? -eq $OCF_NOT_RUNNING ]; then
	ocf_log info "VE $VEID already stopped."
	return $OCF_SUCCESS
  fi

  ocf_run $VZCTL stop $VEID || exit $OCF_ERR_GENERIC

  return $OCF_SUCCESS
}

#
# migrate_to_ve()
#
# In the process of a resource migration, checkpoints the VE. For this
# to work, vzctl must obviously create the dump file in a place which
# the migration target has access to (an NFS mount, a DRBD device,
# etc.).
#
migrate_to_ve()
{
  if ! status_ve; then
    ocf_log err "VE $VEID is not running, aborting"
    exit $OCF_ERR_GENERIC
  fi
  ocf_run $VZCTL chkpnt $VEID || exit $OCF_ERR_GENERIC
  return $OCF_SUCCESS
}

#
# migrate_to_ve()
#
# In the process of a resource migration, restores the VE. For this to
# work, vzctl must obviously have access to the dump file which was
# created on the migration source (on an NFS mount, a DRBD device,
# etc.).
#
migrate_from_ve()
{
  ocf_run $VZCTL restore $VEID || exit $OCF_ERR_GENERIC
  return $OCF_SUCCESS
}

#
# status_ve()
#
# ATTENTION: The following code relies on vzctl's status output. The fifth
# column is interpreted as the VE status (either up or down).
#
# In case the output format should change, this function will need fixing.
#
status_ve()
{ 
  declare -i retcode

  veexists=`$VZCTL status $VEID 2>/dev/null | $AWK '{print $3}'`
  vestatus=`$VZCTL status $VEID 2>/dev/null | $AWK '{print $5}'`
  retcode=$?

  if [[ $retcode != 0 ]]; then
    # log error only if expected to find running
    if [ "$__OCF_ACTION" = "monitor" ] && ! ocf_is_probe; then
      ocf_log err "vzctl status $VEID returned: $retcode"
    fi
    exit $OCF_ERR_GENERIC
  fi

  if [[ $veexists != "exist" ]]; then
    ocf_log err "vzctl status $VEID returned: $VEID does not exist."
    return $OCF_NOT_RUNNING
  fi

  case "$vestatus" in
    running)
        return $OCF_SUCCESS
        ;;
    down)
	return $OCF_NOT_RUNNING
        ;;
    *)
	ocf_log err "vzctl status $VEID, wrong output format. (5th column: $vestatus)"
	exit $OCF_ERR_GENERIC
        ;;
  esac
}    

#
# validate_all_ve()
#
# ATTENTION: The following code relies on vzctl's status output. The fifth
# column is interpreted as the VE status (either up or down).
#
# In case the output format should change, this function will need fixing.
#
validate_all_ve()
{
  declare -i retcode

  # VEID should be a valid VE
  `status_ve`
  retcode=$?

  if [[ $retcode != $OCF_SUCCESS && $retcode != $OCF_NOT_RUNNING ]]; then
    return $retcode
  fi

  return $OCF_SUCCESS
}
	

if [[ $# != 1 ]]; then
  usage
  exit $OCF_ERR_ARGS
fi

case "$1" in
  meta-data)
	meta_data
	exit $OCF_SUCCESS
	;;
  usage) 
	usage
	exit $OCF_SUCCESS
	;;
  *)
	;;
esac

#
# check relevant environment variables for sanity and security
#

# empty string?
`test -z "$OCF_RESKEY_veid"`

declare -i veidtest1=$?

# really a number?
`echo "$OCF_RESKEY_veid" | egrep -q '^[[:digit:]]+$'`

if [[ $veidtest1 != 1 || $? != 0 ]]; then
  ocf_log err "OCF_RESKEY_veid not set or not a number."
  exit $OCF_ERR_ARGS
fi

declare -i VEID=$OCF_RESKEY_veid

#
# check that all relevant utilities are available
# 
check_binary $VZCTL
check_binary $AWK

#
# finally... let's see what we are ordered to do :-)
#
case "$1" in
  start)
	start_ve
	;;
  stop)
	stop_ve
	;;
  status|monitor) 
	status_ve
	;;
  migrate_to)
    migrate_to_ve
    ;;
  migrate_from)
    migrate_from_ve
    ;;
  validate-all)
	validate_all_ve
	;;
  *)
	usage
	exit $OCF_ERR_UNIMPLEMENTED 
	;;
esac

exit $?

