Page MenuHomeClusterLabs Projects

fence_xenapi.py
No OneTemporary

fence_xenapi.py

#!@PYTHON@ -tt
#
#############################################################################
# Copyright 2011 Matthew Clark
# This file is part of fence-xenserver
#
# fence-xenserver 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.
#
# fence-xenserver 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, see <http://www.gnu.org/licenses/>.
# Please let me know if you are using this script so that I can work out
# whether I should continue support for it. mattjclark0407 at hotmail dot com
#############################################################################
#############################################################################
# It's only just begun...
# Current status: completely usable. This script is now working well and,
# has a lot of functionality as a result of the fencing.py library and the
# XenAPI libary.
#############################################################################
# Please let me know if you are using this script so that I can work out
# whether I should continue support for it. mattjclark0407 at hotmail dot com
import sys
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import run_delay
import XenAPI
EC_BAD_SESSION = 1
# Find the status of the port given in the -U flag of options.
def get_power_fn(session, options):
if "--verbose" in options:
verbose = True
else:
verbose = False
try:
# Get a reference to the vm specified in the UUID or vm_name/port parameter
vm = return_vm_reference(session, options)
# Query the VM for its' associated parameters
record = session.xenapi.VM.get_record(vm)
# Check that we are not trying to manipulate a template or a control
# domain as they show up as VM's with specific properties.
if not record["is_a_template"] and not record["is_control_domain"]:
status = record["power_state"]
if verbose:
print("UUID:", record["uuid"], "NAME:", record["name_label"], "POWER STATUS:", record["power_state"])
# Note that the VM can be in the following states (from the XenAPI document)
# Halted: VM is offline and not using any resources.
# Paused: All resources have been allocated but the VM itself is paused and its vCPUs are not running
# Running: Running
# Paused: VM state has been saved to disk and it is nolonger running. Note that disks remain in-Use while
# We want to make sure that we only return the status "off" if the machine is actually halted as the status
# is checked before a fencing action. Only when the machine is Halted is it not consuming resources which
# may include whatever you are trying to protect with this fencing action.
return status == "Halted" and "off" or "on"
except Exception as exn:
print(str(exn))
return "Error"
# Set the state of the port given in the -U flag of options.
def set_power_fn(session, options):
try:
# Get a reference to the vm specified in the UUID or vm_name/port parameter
vm = return_vm_reference(session, options)
# Query the VM for its' associated parameters
record = session.xenapi.VM.get_record(vm)
# Check that we are not trying to manipulate a template or a control
# domain as they show up as VM's with specific properties.
if not record["is_a_template"] and not record["is_control_domain"]:
if options["--action"] == "on":
# Start the VM
session.xenapi.VM.start(vm, False, True)
elif options["--action"] == "off":
# Force shutdown the VM
session.xenapi.VM.hard_shutdown(vm)
elif options["--action"] == "reboot":
# Force reboot the VM
session.xenapi.VM.hard_reboot(vm)
except Exception as exn:
print(str(exn))
# Function to populate an array of virtual machines and their status
def get_outlet_list(session, options):
result = {}
if "--verbose" in options:
verbose = True
else:
verbose = False
try:
# Return an array of all the VM's on the host
vms = session.xenapi.VM.get_all()
for vm in vms:
# Query the VM for its' associated parameters
record = session.xenapi.VM.get_record(vm)
# Check that we are not trying to manipulate a template or a control
# domain as they show up as VM's with specific properties.
if not record["is_a_template"] and not record["is_control_domain"]:
name = record["name_label"]
uuid = record["uuid"]
status = record["power_state"]
result[uuid] = (name, status)
if verbose:
print("UUID:", record["uuid"], "NAME:", name, "POWER STATUS:", record["power_state"])
except Exception as exn:
print(str(exn))
return result
# Function to initiate the XenServer session via the XenAPI library.
def connect_and_login(options):
url = options["--session-url"]
username = options["--username"]
password = options["--password"]
try:
# Create the XML RPC session to the specified URL.
session = XenAPI.Session(url)
# Login using the supplied credentials.
session.xenapi.login_with_password(username, password)
except Exception as exn:
print(str(exn))
# http://sources.redhat.com/cluster/wiki/FenceAgentAPI says that for no connectivity
# the exit value should be 1. It doesn't say anything about failed logins, so
# until I hear otherwise it is best to keep this exit the same to make sure that
# anything calling this script (that uses the same information in the web page
# above) knows that this is an error condition, not a msg signifying a down port.
sys.exit(EC_BAD_SESSION)
return session
# return a reference to the VM by either using the UUID or the vm_name/port. If the UUID is set then
# this is tried first as this is the only properly unique identifier.
# Exceptions are not handled in this function, code that calls this must be ready to handle them.
def return_vm_reference(session, options):
if "--verbose" in options:
verbose = True
else:
verbose = False
# Case where the UUID has been specified
if "--uuid" in options:
uuid = options["--uuid"].lower()
# When using the -n parameter for name, we get an error message (in verbose
# mode) that tells us that we didn't find a VM. To immitate that here we
# need to catch and re-raise the exception produced by get_by_uuid.
try:
return session.xenapi.VM.get_by_uuid(uuid)
except Exception:
if verbose:
print("No VM's found with a UUID of \"%s\"" % uuid)
raise
# Case where the vm_name/port has been specified
if "--plug" in options:
vm_name = options["--plug"]
vm_arr = session.xenapi.VM.get_by_name_label(vm_name)
# Need to make sure that we only have one result as the vm_name may
# not be unique. Average case, so do it first.
if len(vm_arr) == 1:
return vm_arr[0]
else:
if len(vm_arr) == 0:
if verbose:
print("No VM's found with a name of \"%s\"" % vm_name)
# NAME_INVALID used as the XenAPI throws a UUID_INVALID if it can't find
# a VM with the specified UUID. This should make the output look fairly
# consistent.
raise Exception("NAME_INVALID")
else:
if verbose:
print("Multiple VM's have the name \"%s\", use UUID instead" % vm_name)
raise Exception("MULTIPLE_VMS_FOUND")
# We should never get to this case as the input processing checks that either the UUID or
# the name parameter is set. Regardless of whether or not a VM is found the above if
# statements will return to the calling function (either by exception or by a reference
# to the VM).
raise Exception("VM_LOGIC_ERROR")
def main():
device_opt = ["login", "passwd", "port", "no_login", "no_password", "session_url", "web"]
atexit.register(atexit_handler)
options = check_input(device_opt, process_input(device_opt))
docs = {}
docs["shortdesc"] = "Fence agent for Citrix XenServer over XenAPI"
docs["longdesc"] = "\
fence_cxs is an I/O Fencing agent used on Citrix XenServer hosts. \
It uses the XenAPI, supplied by Citrix, to establish an XML-RPC sesssion \
to a XenServer host. Once the session is established, further XML-RPC \
commands are issued in order to switch on, switch off, restart and query \
the status of virtual machines running on the host."
docs["vendorurl"] = "http://www.xenproject.org"
show_docs(options, docs)
run_delay(options)
xen_session = connect_and_login(options)
result = fence_action(xen_session, options, set_power_fn, get_power_fn, get_outlet_list)
sys.exit(result)
if __name__ == "__main__":
main()

File Metadata

Mime Type
text/x-script.python
Expires
Tue, Feb 25, 12:42 PM (1 d, 6 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1464830
Default Alt Text
fence_xenapi.py (8 KB)

Event Timeline