====== ProxMox Stonith driver ====== Here is a stonith driver for ProxMox 2, 3 and 4 that works great for Containers and VM's in Corosync/Pacemaker. #!/bin/sh # # External STONITH module for a ProxMox managed hypervisors and Containers. # Uses vzctl, pct and qm in ProxMox versions 2, 3 and 4 as a STONITH device to control guest. # # Copyright (c) 2012 Charles Williams # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # # # primitive p_fence_ct1 stonith:external/proxmox \ # params hostlist="101" \ # hosttype="vz" \ # nodelist="host1 host2 host3" \ # op monitor interval="60" # primitive p_fence_vm1 stonith:external/proxmox \ # params hostlist="102" \ # hosttype="kvm" \ # nodelist="host1 host2 host3 host4 host5" \ # op monitor interval="60" #location l_fence_ct1 p_fence_ct1 -inf: ct1 #location l_fence_vm1 p_fence_vm1 -inf: vm1 #property stonith-enabled=true proxmox_get_node() { for node in $nodelist do STATUSRESPONCE=$($SSH $STONITH_USER@$node "sudo ${CTCTL} status ${hostid}" 2>&1) if [ $? -eq 0 ] && [ "$STATUSRESPONCE" != "CTID $hostid deleted unmounted down" ] then HOSTNODE=$node break fi done } # start a Container or VM proxmox_start() { if [ "$hosttype" = "kvm" ] then sshout=$($SSH $STONITH_USER@$HOSTNODE "sudo /usr/sbin/qm start ${hostid} 2>&1") 2>&1 rtc=$? if [ $rtc -eq 0 ] then ha_log.sh notice "VM $hostid was started" return 0 else ha_log.sh err "Failed to start VM $hostid (error code: $rtc)" ha_log.sh err "$sshout" return 1 fi elif [ "$hosttype" = "vz" ] || [ "$hosttype" = "lxc" ] then sshout=$($SSH $STONITH_USER@$HOSTNODE "sudo ${CTCTL} start ${hostid} 2>&1") 2>&1 rtc=$? if [ "$sshout" = "Container is already running" ] || [ $rtc -eq 0 ] then ha_log.sh notice "Container $hostid is running" return 0 fi fi ha_log.sh err "Failed to start Container $hostid (erro code: $rtc)" ha_log.sh err "$sshout" return 1 } # reboot a Container or VM proxmox_restart() { if [ "$hosttype" = "kvm" ] then sshout=$($SSH $STONITH_USER@$HOSTNODE "sudo /usr/sbin/qm shutdown ${hostid} 2>&1") 2>&1 rtc=$? if [ $rtc -eq 0 ] then sshout=$($SSH $STONITH_USER@$HOSTNODE "sudo /usr/sbin/qm start ${hostid} 2>&1") 2>&1 rtc=$? if [ $rtc -eq 0 ] then ha_log.sh notice "VM $hostid was restarted" return 0 else ha_log.sh err "Failed to restart VM $hostid (error code: $rtc)" ha_log.sh err "$sshout" return 1 fi else sshout=$($SSH $STONITH_USER@$HOSTNODE "sudo /usr/sbin/qm stop ${hostid} 2>&1") 2>&1 rtc=$? if [ $rtc -eq 0 ] then sshout=$($SSH $STONITH_USER@$HOSTNODE "sudo /usr/sbin/qm start ${hostid} 2>&1") 2>&1 rtc=$? if [ $rtc -eq 0 ] then ha_log.sh notice "VM $hostid was restarted" return 0 else ha_log.sh err "Failed to restart VM $hostid (error code: $rtc)" ha_log.sh err "$sshout" return 1 fi else ha_log.sh err "Failed to restart VM $hostid (error code: $rtc)" ha_log.sh err "$sshout" return 1 fi ha_log.sh err "Failed to restart VM $hostid (error code: $rtc)" ha_log.sh err "$sshout" return 1 fi elif [ "$hosttype" = "vz" ] || [ "$hosttype" = "lxc" ] then sshout=$($SSH $STONITH_USER@$HOSTNODE "sudo ${CTCTL} restart ${hostid} 2>&1") 2>&1 rtc=$? if [ $rtc -eq 0 ] then ha_log.sh notice "Container $hostid was restarted" return 0 fi fi ha_log.sh err "Failed to restart Container $hostid (error code: $rtc)" ha_log.sh err "$sshout" return 1 } # stop a host proxmox_stop() { if [ "$hosttype" = "kvm" ] then sshout=$($SSH $STONITH_USER@$HOSTNODE "sudo /usr/sbin/qm shutdown ${hostid} 2>&1") 2>&1 rtc=$? if [ $rtc -eq 0 ] then ha_log.sh notice "VM $hostid was shutdown" return 0 else sshout=$($SSH $STONITH_USER@$HOSTNODE "sudo /usr/sbin/qm stop ${hostid} 2>&1") 2>&1 rtc=$? if [ $rtc -eq 0 ] then ha_log.sh notice "VM $hostid was killed" return 0 else ha_log.sh err "Failed to shutdown VM $hostid (error code: $rtc)" ha_log.sh err "$sshout" return 1 fi fi elif [ "$hosttype" = "vz" ] || [ "$hosttype" = "lxc" ] then sshout=$($SSH $STONITH_USER@$HOSTNODE "sudo ${CTCTL} stop ${hostid} 2>&1") 2>&1 rtc=$? if [ $rtc -eq 0 ] then ha_log.sh notice "Container $hostid was stopped" return 0 fi sshout=$($SSH $STONITH_USER@$HOSTNODE "sudo ${CTCTL} status ${hostid} 2>&1") 2>&1 rtc=$? if [ $? -eq 0 ] then ha_log.sh notice "Container $hostid is already stopped" return 2 fi fi ha_log.sh err "Failed to stop Container $hostid (error code: $rtc)" ha_log.sh err "$sshout" return 1 } # get status of stonith device. # If we can retrieve some info from the container or hypervisor # the stonith device is OK. proxmox_status() { if [ "$hosttype" = "kvm" ] then sshout=$($SSH $STONITH_USER@$HOSTNODE "sudo /usr/sbin/qm status ${hostid} 2>&1") 2>&1 rtc=$? if [ $rtc -eq 0 ] then ha_log.sh notice "$sshout" return 0 else ha_log.sh err "Failed to get status for VM $hostid (error code: $rtc)" ha_log.sh err "$sshout" return 1 fi elif [ "$hosttype" = "vz" ] || [ "$hosttype" = "lxc" ] then sshout=$($SSH $STONITH_USER@$HOSTNODE "sudo ${CTCTL} status ${hostid} 2>&1") 2>&1 rtc=$? if [ $rtc -eq 0 ] then ha_log.sh notice "$sshout" return 0 fi fi ha_log.sh err "Failed to get status for container $hostid (error code: $rtc)" ha_log.sh err "$sshout" return 1 } # check config and set variables # does not return on error proxmox_check_config() { if [ -z "$hostlist" -o -z "$nodelist" ] then ha_log.sh err "hostid or nodelist missing; check configuration" exit 1 fi if [ "$hosttype" != "vz" ] && [ "$hosttype" != "lxc" ] && [ "$hosttype" != "kvm" ] then ha_log.sh err "hosttype missing or incorrect; check configuration" exit 1 fi } proxmox_info() { cat << PROXMOXXML List of hosts to control List of Host container/VM IDs to control Host Type [vz, lxc, kvm] Type of Host: vz = OpenVZ lxc = LXC kvm = Qemu/KVM Host nodes list List of Host nodes that can be used to control the configured hosts SSH user SSH user that can log into the nodes. Defaults to user "stonith" PROXMOXXML exit 0 } ############# # Main code # ############# # don't fool yourself when testing with stonith(8) # and transport ssh unset SSH_AUTH_SOCK # support , as a separator as well hostlist=`echo $hostlist| sed -e 's/,/ /g'` nodelist=`echo $nodelist| sed -e 's/,/ /g'` SSH="/usr/bin/ssh -q -x -n" STONITH_USER=${stonithuser:-"stonith"} if [ "$hosttype" = "vz" ]; then CTCTL="/usr/sbin/vzctl" elif [ "$hosttype" = "lxc" ]; then CTCTL="/usr/sbin/pct" fi case $1 in gethosts) hostlist=`echo $hostlist|sed -e 's/:[^ ]*//g'` for hostid in $hostlist do echo $hostid done exit 0 ;; on) proxmox_check_config for hostid in $hostlist do proxmox_get_node proxmox_start done exit $? ;; off) proxmox_check_config for hostid in $hostlist do proxmox_get_node proxmox_stop done [ $? = 1 ] && exit 1 exit 0 ;; reset) proxmox_check_config for hostid in $hostlist do proxmox_get_node proxmox_restart done exit $? ;; status) proxmox_check_config for hostid in $hostlist do proxmox_get_node proxmox_status done exit $? ;; getconfignames) echo "hostname hostlist hosttype nodelist stonithuser" exit 0 ;; getinfo-devid) echo "ProxMox STONITH device" exit 0 ;; getinfo-devname) echo "ProxMox STONITH external device" exit 0 ;; getinfo-devdescr) echo "ProxMox OpenVZ/LXC Container and QEMU/KVM VM control" exit 0 ;; getinfo-devurl) echo "http://proxmox.org/ http://linux-ha.org/wiki" exit 0 ;; getinfo-xml) proxmox_info echo 0; ;; *) exit 1 ;; esac