Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F3153181
fence_xenapi.py
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
fence_xenapi.py
View Options
#!@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
Details
Attached
Mime Type
text/x-script.python
Expires
Tue, Feb 25, 12:42 PM (1 d, 9 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1464830
Default Alt Text
fence_xenapi.py (8 KB)
Attached To
Mode
rF Fence Agents
Attached
Detach File
Event Timeline
Log In to Comment