* [Cluster-devel] [PATCH 1/5] New fencing script for Citrix XenServer and XCP. @ 2011-04-20 11:51 Matt Clark 2011-04-20 11:51 ` [Cluster-devel] [PATCH 2/5] Updated to include xenapi script Matt Clark ` (3 more replies) 0 siblings, 4 replies; 10+ messages in thread From: Matt Clark @ 2011-04-20 11:51 UTC (permalink / raw) To: cluster-devel.redhat.com Fencing script that uses the XenAPI to allow remote switch, status and list of virtual machines running on Citrix XenServer and Xen Cloud Platform hosts. --- fence/agents/xenapi/Makefile.am | 17 +++ fence/agents/xenapi/XenAPI.py | 209 ++++++++++++++++++++++++++++++++ fence/agents/xenapi/fence_xenapi.py | 227 +++++++++++++++++++++++++++++++++++ 3 files changed, 453 insertions(+), 0 deletions(-) create mode 100644 fence/agents/xenapi/Makefile.am create mode 100755 fence/agents/xenapi/XenAPI.py create mode 100644 fence/agents/xenapi/fence_xenapi.py diff --git a/fence/agents/xenapi/Makefile.am b/fence/agents/xenapi/Makefile.am new file mode 100644 index 0000000..781975e --- /dev/null +++ b/fence/agents/xenapi/Makefile.am @@ -0,0 +1,17 @@ +MAINTAINERCLEANFILES = Makefile.in + +TARGET = fence_xenapi + +SRC = $(TARGET).py + +EXTRA_DIST = $(SRC) + +sbin_SCRIPTS = $(TARGET) + +man_MANS = $(TARGET).8 + +include $(top_srcdir)/make/fencebuild.mk +include $(top_srcdir)/make/fenceman.mk + +clean-local: clean-man + rm -f $(TARGET) diff --git a/fence/agents/xenapi/XenAPI.py b/fence/agents/xenapi/XenAPI.py new file mode 100755 index 0000000..4f27ef5 --- /dev/null +++ b/fence/agents/xenapi/XenAPI.py @@ -0,0 +1,209 @@ +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (C) 2006 XenSource Inc. +#============================================================================ +# +# Parts of this file are based upon xmlrpclib.py, the XML-RPC client +# interface included in the Python distribution. +# +# Copyright (c) 1999-2002 by Secret Labs AB +# Copyright (c) 1999-2002 by Fredrik Lundh +# +# By obtaining, using, and/or copying this software and/or its +# associated documentation, you agree that you have read, understood, +# and will comply with the following terms and conditions: +# +# Permission to use, copy, modify, and distribute this software and +# its associated documentation for any purpose and without fee is +# hereby granted, provided that the above copyright notice appears in +# all copies, and that both that copyright notice and this permission +# notice appear in supporting documentation, and that the name of +# Secret Labs AB or the author not be used in advertising or publicity +# pertaining to distribution of the software without specific, written +# prior permission. +# +# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD +# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- +# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR +# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# -------------------------------------------------------------------- + +import gettext +import xmlrpclib +import httplib +import socket + +translation = gettext.translation('xen-xm', fallback = True) + +class Failure(Exception): + def __init__(self, details): + try: + # If this failure is MESSAGE_PARAMETER_COUNT_MISMATCH, then we + # correct the return values here, to account for the fact that we + # transparently add the session handle as the first argument. + if details[0] == 'MESSAGE_PARAMETER_COUNT_MISMATCH': + details[2] = str(int(details[2]) - 1) + details[3] = str(int(details[3]) - 1) + + self.details = details + except Exception, exn: + self.details = ['INTERNAL_ERROR', 'Client-side: ' + str(exn)] + + def __str__(self): + try: + return translation.ugettext(self.details[0]) % self._details_map() + except TypeError, exn: + return "Message database broken: %s.\nXen-API failure: %s" % \ + (exn, str(self.details)) + except Exception, exn: + import sys + print >>sys.stderr, exn + return "Xen-API failure: %s" % str(self.details) + + def _details_map(self): + return dict([(str(i), self.details[i]) + for i in range(len(self.details))]) + + +_RECONNECT_AND_RETRY = (lambda _ : ()) + +class UDSHTTPConnection(httplib.HTTPConnection): + """ Stupid hacked up HTTPConnection subclass to allow HTTP over Unix domain + sockets. """ + def connect(self): + path = self.host.replace("_", "/") + self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self.sock.connect(path) + +class UDSHTTP(httplib.HTTP): + _connection_class = UDSHTTPConnection + +class UDSTransport(xmlrpclib.Transport): + def make_connection(self, host): + return UDSHTTP(host) + +class Session(xmlrpclib.ServerProxy): + """A server proxy and session manager for communicating with Xend using + the Xen-API. + + Example: + + session = Session('http://localhost:9363/') + session.login_with_password('me', 'mypassword') + session.xenapi.VM.start(vm_uuid) + session.xenapi.session.logout() + + For now, this class also supports the legacy XML-RPC API, using + session.xend.domain('Domain-0') and similar. This support will disappear + once there is a working Xen-API replacement for every call in the legacy + API. + """ + + def __init__(self, uri, transport=None, encoding=None, verbose=0, + allow_none=1): + xmlrpclib.ServerProxy.__init__(self, uri, transport, encoding, + verbose, allow_none) + self._session = None + self.last_login_method = None + self.last_login_params = None + + + def xenapi_request(self, methodname, params): + if methodname.startswith('login'): + self._login(methodname, params) + return None + else: + retry_count = 0 + while retry_count < 3: + full_params = (self._session,) + params + result = _parse_result(getattr(self, methodname)(*full_params)) + if result == _RECONNECT_AND_RETRY: + retry_count += 1 + if self.last_login_method: + self._login(self.last_login_method, + self.last_login_params) + else: + raise xmlrpclib.Fault(401, 'You must log in') + else: + return result + raise xmlrpclib.Fault( + 500, 'Tried 3 times to get a valid session, but failed') + + + def _login(self, method, params): + result = _parse_result(getattr(self, 'session.%s' % method)(*params)) + if result == _RECONNECT_AND_RETRY: + raise xmlrpclib.Fault( + 500, 'Received SESSION_INVALID when logging in') + self._session = result + self.last_login_method = method + self.last_login_params = params + + + def __getattr__(self, name): + if name == 'xenapi': + return _Dispatcher(self.xenapi_request, None) + elif name.startswith('login'): + return lambda *params: self._login(name, params) + else: + return xmlrpclib.ServerProxy.__getattr__(self, name) + +def xapi_local(): + return Session("http://_var_xapi_xapi/", transport=UDSTransport()) + +def _parse_result(result): + if type(result) != dict or 'Status' not in result: + raise xmlrpclib.Fault(500, 'Missing Status in response from server' + result) + if result['Status'] == 'Success': + if 'Value' in result: + return result['Value'] + else: + raise xmlrpclib.Fault(500, + 'Missing Value in response from server') + else: + if 'ErrorDescription' in result: + if result['ErrorDescription'][0] == 'SESSION_INVALID': + return _RECONNECT_AND_RETRY + else: + raise Failure(result['ErrorDescription']) + else: + raise xmlrpclib.Fault( + 500, 'Missing ErrorDescription in response from server') + + +# Based upon _Method from xmlrpclib. +class _Dispatcher: + def __init__(self, send, name): + self.__send = send + self.__name = name + + def __repr__(self): + if self.__name: + return '<XenAPI._Dispatcher for %s>' % self.__name + else: + return '<XenAPI._Dispatcher>' + + def __getattr__(self, name): + if self.__name is None: + return _Dispatcher(self.__send, name) + else: + return _Dispatcher(self.__send, "%s.%s" % (self.__name, name)) + + def __call__(self, *args): + return self.__send(self.__name, args) diff --git a/fence/agents/xenapi/fence_xenapi.py b/fence/agents/xenapi/fence_xenapi.py new file mode 100644 index 0000000..0657f4e --- /dev/null +++ b/fence/agents/xenapi/fence_xenapi.py @@ -0,0 +1,227 @@ +#!/usr/bin/python +# +############################################################################# +# Copyright 2011 Matt 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 +sys.path.append("/usr/lib/fence") +from fencing import * +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 options.has_key("-v"): + 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, 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): + action = options["-o"].lower() + if options.has_key("-v"): + 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"]): + if( action == "on" ): + # Start the VM + session.xenapi.VM.start(vm, False, True) + elif( action == "off" ): + # Force shutdown the VM + session.xenapi.VM.hard_shutdown(vm) + elif( action == "reboot" ): + # Force reboot the VM + session.xenapi.VM.hard_reboot(vm) + except Exception, exn: + print str(exn); + +# Function to populate an array of virtual machines and their status +def get_outlet_list(session, options): + result = {} + if options.has_key("-v"): + 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, exn: + print str(exn); + + return result + +# Function to initiate the XenServer session via the XenAPI library. +def connect_and_login(options): + url = options["-s"] + username = options["-l"] + password = options["-p"] + + 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, 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 options.has_key("-v"): + verbose = True + else: + verbose = False + + # Case where the UUID has been specified + if options.has_key("-U"): + uuid = options["-U"].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,exn: + if verbose: print "No VM's found with a UUID of \"%s\"" %uuid + raise + + + # Case where the vm_name/port has been specified + if options.has_key("-n"): + vm_name = options["-n"] + 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 = [ "help", "version", "agent", "quiet", "verbose", "debug", "action", + "login", "passwd", "passwd_script", "port", "test", "separator", + "no_login", "no_password", "power_timeout", "shell_timeout", + "login_timeout", "power_wait", "session_url", "uuid" ] + + atexit.register(atexit_handler) + + options=process_input(device_opt) + + options = check_input(device_opt, options) + + docs = { } + docs["shortdesc"] = "XenAPI based fencing for the Citrix XenServer virtual machines." + 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." + show_docs(options, docs) + + xenSession = connect_and_login(options) + + # Operate the fencing device + result = fence_action(xenSession, options, set_power_fn, get_power_fn, get_outlet_list) + + sys.exit(result) + +if __name__ == "__main__": + main() +RELEASE_VERSION="3.1.2.11-2b5b-dirty" +BUILD_DATE="(built Fri Mar 25 22:57:28 EST 2011)" -- 1.7.0.4 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Cluster-devel] [PATCH 2/5] Updated to include xenapi script. 2011-04-20 11:51 [Cluster-devel] [PATCH 1/5] New fencing script for Citrix XenServer and XCP Matt Clark @ 2011-04-20 11:51 ` Matt Clark 2011-04-20 11:51 ` [Cluster-devel] [PATCH 3/5] Updated to include xenapi script in Makefile.am Matt Clark ` (2 subsequent siblings) 3 siblings, 0 replies; 10+ messages in thread From: Matt Clark @ 2011-04-20 11:51 UTC (permalink / raw) To: cluster-devel.redhat.com --- configure.ac | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/configure.ac b/configure.ac index d8994d2..d71f6e4 100644 --- a/configure.ac +++ b/configure.ac @@ -256,6 +256,7 @@ AC_CONFIG_FILES([Makefile fence/agents/vmware_soap/Makefile fence/agents/wti/Makefile fence/agents/xcat/Makefile + fence/agents/xenapi/Makefile fence/agents/zvm/Makefile doc/Makefile]) -- 1.7.0.4 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Cluster-devel] [PATCH 3/5] Updated to include xenapi script in Makefile.am. 2011-04-20 11:51 [Cluster-devel] [PATCH 1/5] New fencing script for Citrix XenServer and XCP Matt Clark 2011-04-20 11:51 ` [Cluster-devel] [PATCH 2/5] Updated to include xenapi script Matt Clark @ 2011-04-20 11:51 ` Matt Clark 2011-04-20 11:51 ` [Cluster-devel] [PATCH 4/5] Clean up of fence_xenapi patches. Moved XenAPI.py to lib directory and added to Makefile.am Matt Clark 2011-04-20 11:51 ` [Cluster-devel] [PATCH 5/5] Cleanup of fence_xenapi patches. Added copyright information to doc/COPYRIGHT. Fixed static reference to lib directory in fence_xenapi.py. Fixed static reference to RELEASE_VERSION and BUILD_DATE in fence_xenapi.py Matt Clark 3 siblings, 0 replies; 10+ messages in thread From: Matt Clark @ 2011-04-20 11:51 UTC (permalink / raw) To: cluster-devel.redhat.com --- fence/agents/Makefile.am | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) mode change 100644 => 100755 fence/agents/xenapi/fence_xenapi.py diff --git a/fence/agents/Makefile.am b/fence/agents/Makefile.am index e2f445f..ff3dbf7 100644 --- a/fence/agents/Makefile.am +++ b/fence/agents/Makefile.am @@ -40,4 +40,5 @@ SUBDIRS = lib \ vmware_soap \ wti \ xcat \ + xenapi \ zvm diff --git a/fence/agents/xenapi/fence_xenapi.py b/fence/agents/xenapi/fence_xenapi.py old mode 100644 new mode 100755 -- 1.7.0.4 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Cluster-devel] [PATCH 4/5] Clean up of fence_xenapi patches. Moved XenAPI.py to lib directory and added to Makefile.am. 2011-04-20 11:51 [Cluster-devel] [PATCH 1/5] New fencing script for Citrix XenServer and XCP Matt Clark 2011-04-20 11:51 ` [Cluster-devel] [PATCH 2/5] Updated to include xenapi script Matt Clark 2011-04-20 11:51 ` [Cluster-devel] [PATCH 3/5] Updated to include xenapi script in Makefile.am Matt Clark @ 2011-04-20 11:51 ` Matt Clark 2011-04-20 11:51 ` [Cluster-devel] [PATCH 5/5] Cleanup of fence_xenapi patches. Added copyright information to doc/COPYRIGHT. Fixed static reference to lib directory in fence_xenapi.py. Fixed static reference to RELEASE_VERSION and BUILD_DATE in fence_xenapi.py Matt Clark 3 siblings, 0 replies; 10+ messages in thread From: Matt Clark @ 2011-04-20 11:51 UTC (permalink / raw) To: cluster-devel.redhat.com --- fence/agents/lib/XenAPI.py.py | 209 +++++++++++++++++++++++++++++++++++++++++ fence/agents/xenapi/XenAPI.py | 209 ----------------------------------------- 2 files changed, 209 insertions(+), 209 deletions(-) create mode 100755 fence/agents/lib/XenAPI.py.py delete mode 100755 fence/agents/xenapi/XenAPI.py diff --git a/fence/agents/lib/XenAPI.py.py b/fence/agents/lib/XenAPI.py.py new file mode 100755 index 0000000..4f27ef5 --- /dev/null +++ b/fence/agents/lib/XenAPI.py.py @@ -0,0 +1,209 @@ +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (C) 2006 XenSource Inc. +#============================================================================ +# +# Parts of this file are based upon xmlrpclib.py, the XML-RPC client +# interface included in the Python distribution. +# +# Copyright (c) 1999-2002 by Secret Labs AB +# Copyright (c) 1999-2002 by Fredrik Lundh +# +# By obtaining, using, and/or copying this software and/or its +# associated documentation, you agree that you have read, understood, +# and will comply with the following terms and conditions: +# +# Permission to use, copy, modify, and distribute this software and +# its associated documentation for any purpose and without fee is +# hereby granted, provided that the above copyright notice appears in +# all copies, and that both that copyright notice and this permission +# notice appear in supporting documentation, and that the name of +# Secret Labs AB or the author not be used in advertising or publicity +# pertaining to distribution of the software without specific, written +# prior permission. +# +# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD +# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- +# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR +# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# -------------------------------------------------------------------- + +import gettext +import xmlrpclib +import httplib +import socket + +translation = gettext.translation('xen-xm', fallback = True) + +class Failure(Exception): + def __init__(self, details): + try: + # If this failure is MESSAGE_PARAMETER_COUNT_MISMATCH, then we + # correct the return values here, to account for the fact that we + # transparently add the session handle as the first argument. + if details[0] == 'MESSAGE_PARAMETER_COUNT_MISMATCH': + details[2] = str(int(details[2]) - 1) + details[3] = str(int(details[3]) - 1) + + self.details = details + except Exception, exn: + self.details = ['INTERNAL_ERROR', 'Client-side: ' + str(exn)] + + def __str__(self): + try: + return translation.ugettext(self.details[0]) % self._details_map() + except TypeError, exn: + return "Message database broken: %s.\nXen-API failure: %s" % \ + (exn, str(self.details)) + except Exception, exn: + import sys + print >>sys.stderr, exn + return "Xen-API failure: %s" % str(self.details) + + def _details_map(self): + return dict([(str(i), self.details[i]) + for i in range(len(self.details))]) + + +_RECONNECT_AND_RETRY = (lambda _ : ()) + +class UDSHTTPConnection(httplib.HTTPConnection): + """ Stupid hacked up HTTPConnection subclass to allow HTTP over Unix domain + sockets. """ + def connect(self): + path = self.host.replace("_", "/") + self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self.sock.connect(path) + +class UDSHTTP(httplib.HTTP): + _connection_class = UDSHTTPConnection + +class UDSTransport(xmlrpclib.Transport): + def make_connection(self, host): + return UDSHTTP(host) + +class Session(xmlrpclib.ServerProxy): + """A server proxy and session manager for communicating with Xend using + the Xen-API. + + Example: + + session = Session('http://localhost:9363/') + session.login_with_password('me', 'mypassword') + session.xenapi.VM.start(vm_uuid) + session.xenapi.session.logout() + + For now, this class also supports the legacy XML-RPC API, using + session.xend.domain('Domain-0') and similar. This support will disappear + once there is a working Xen-API replacement for every call in the legacy + API. + """ + + def __init__(self, uri, transport=None, encoding=None, verbose=0, + allow_none=1): + xmlrpclib.ServerProxy.__init__(self, uri, transport, encoding, + verbose, allow_none) + self._session = None + self.last_login_method = None + self.last_login_params = None + + + def xenapi_request(self, methodname, params): + if methodname.startswith('login'): + self._login(methodname, params) + return None + else: + retry_count = 0 + while retry_count < 3: + full_params = (self._session,) + params + result = _parse_result(getattr(self, methodname)(*full_params)) + if result == _RECONNECT_AND_RETRY: + retry_count += 1 + if self.last_login_method: + self._login(self.last_login_method, + self.last_login_params) + else: + raise xmlrpclib.Fault(401, 'You must log in') + else: + return result + raise xmlrpclib.Fault( + 500, 'Tried 3 times to get a valid session, but failed') + + + def _login(self, method, params): + result = _parse_result(getattr(self, 'session.%s' % method)(*params)) + if result == _RECONNECT_AND_RETRY: + raise xmlrpclib.Fault( + 500, 'Received SESSION_INVALID when logging in') + self._session = result + self.last_login_method = method + self.last_login_params = params + + + def __getattr__(self, name): + if name == 'xenapi': + return _Dispatcher(self.xenapi_request, None) + elif name.startswith('login'): + return lambda *params: self._login(name, params) + else: + return xmlrpclib.ServerProxy.__getattr__(self, name) + +def xapi_local(): + return Session("http://_var_xapi_xapi/", transport=UDSTransport()) + +def _parse_result(result): + if type(result) != dict or 'Status' not in result: + raise xmlrpclib.Fault(500, 'Missing Status in response from server' + result) + if result['Status'] == 'Success': + if 'Value' in result: + return result['Value'] + else: + raise xmlrpclib.Fault(500, + 'Missing Value in response from server') + else: + if 'ErrorDescription' in result: + if result['ErrorDescription'][0] == 'SESSION_INVALID': + return _RECONNECT_AND_RETRY + else: + raise Failure(result['ErrorDescription']) + else: + raise xmlrpclib.Fault( + 500, 'Missing ErrorDescription in response from server') + + +# Based upon _Method from xmlrpclib. +class _Dispatcher: + def __init__(self, send, name): + self.__send = send + self.__name = name + + def __repr__(self): + if self.__name: + return '<XenAPI._Dispatcher for %s>' % self.__name + else: + return '<XenAPI._Dispatcher>' + + def __getattr__(self, name): + if self.__name is None: + return _Dispatcher(self.__send, name) + else: + return _Dispatcher(self.__send, "%s.%s" % (self.__name, name)) + + def __call__(self, *args): + return self.__send(self.__name, args) diff --git a/fence/agents/xenapi/XenAPI.py b/fence/agents/xenapi/XenAPI.py deleted file mode 100755 index 4f27ef5..0000000 --- a/fence/agents/xenapi/XenAPI.py +++ /dev/null @@ -1,209 +0,0 @@ -#============================================================================ -# This library is free software; you can redistribute it and/or -# modify it under the terms of version 2.1 of the GNU Lesser General Public -# License as published by the Free Software Foundation. -# -# This library 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 -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -#============================================================================ -# Copyright (C) 2006 XenSource Inc. -#============================================================================ -# -# Parts of this file are based upon xmlrpclib.py, the XML-RPC client -# interface included in the Python distribution. -# -# Copyright (c) 1999-2002 by Secret Labs AB -# Copyright (c) 1999-2002 by Fredrik Lundh -# -# By obtaining, using, and/or copying this software and/or its -# associated documentation, you agree that you have read, understood, -# and will comply with the following terms and conditions: -# -# Permission to use, copy, modify, and distribute this software and -# its associated documentation for any purpose and without fee is -# hereby granted, provided that the above copyright notice appears in -# all copies, and that both that copyright notice and this permission -# notice appear in supporting documentation, and that the name of -# Secret Labs AB or the author not be used in advertising or publicity -# pertaining to distribution of the software without specific, written -# prior permission. -# -# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD -# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- -# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR -# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY -# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE -# OF THIS SOFTWARE. -# -------------------------------------------------------------------- - -import gettext -import xmlrpclib -import httplib -import socket - -translation = gettext.translation('xen-xm', fallback = True) - -class Failure(Exception): - def __init__(self, details): - try: - # If this failure is MESSAGE_PARAMETER_COUNT_MISMATCH, then we - # correct the return values here, to account for the fact that we - # transparently add the session handle as the first argument. - if details[0] == 'MESSAGE_PARAMETER_COUNT_MISMATCH': - details[2] = str(int(details[2]) - 1) - details[3] = str(int(details[3]) - 1) - - self.details = details - except Exception, exn: - self.details = ['INTERNAL_ERROR', 'Client-side: ' + str(exn)] - - def __str__(self): - try: - return translation.ugettext(self.details[0]) % self._details_map() - except TypeError, exn: - return "Message database broken: %s.\nXen-API failure: %s" % \ - (exn, str(self.details)) - except Exception, exn: - import sys - print >>sys.stderr, exn - return "Xen-API failure: %s" % str(self.details) - - def _details_map(self): - return dict([(str(i), self.details[i]) - for i in range(len(self.details))]) - - -_RECONNECT_AND_RETRY = (lambda _ : ()) - -class UDSHTTPConnection(httplib.HTTPConnection): - """ Stupid hacked up HTTPConnection subclass to allow HTTP over Unix domain - sockets. """ - def connect(self): - path = self.host.replace("_", "/") - self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - self.sock.connect(path) - -class UDSHTTP(httplib.HTTP): - _connection_class = UDSHTTPConnection - -class UDSTransport(xmlrpclib.Transport): - def make_connection(self, host): - return UDSHTTP(host) - -class Session(xmlrpclib.ServerProxy): - """A server proxy and session manager for communicating with Xend using - the Xen-API. - - Example: - - session = Session('http://localhost:9363/') - session.login_with_password('me', 'mypassword') - session.xenapi.VM.start(vm_uuid) - session.xenapi.session.logout() - - For now, this class also supports the legacy XML-RPC API, using - session.xend.domain('Domain-0') and similar. This support will disappear - once there is a working Xen-API replacement for every call in the legacy - API. - """ - - def __init__(self, uri, transport=None, encoding=None, verbose=0, - allow_none=1): - xmlrpclib.ServerProxy.__init__(self, uri, transport, encoding, - verbose, allow_none) - self._session = None - self.last_login_method = None - self.last_login_params = None - - - def xenapi_request(self, methodname, params): - if methodname.startswith('login'): - self._login(methodname, params) - return None - else: - retry_count = 0 - while retry_count < 3: - full_params = (self._session,) + params - result = _parse_result(getattr(self, methodname)(*full_params)) - if result == _RECONNECT_AND_RETRY: - retry_count += 1 - if self.last_login_method: - self._login(self.last_login_method, - self.last_login_params) - else: - raise xmlrpclib.Fault(401, 'You must log in') - else: - return result - raise xmlrpclib.Fault( - 500, 'Tried 3 times to get a valid session, but failed') - - - def _login(self, method, params): - result = _parse_result(getattr(self, 'session.%s' % method)(*params)) - if result == _RECONNECT_AND_RETRY: - raise xmlrpclib.Fault( - 500, 'Received SESSION_INVALID when logging in') - self._session = result - self.last_login_method = method - self.last_login_params = params - - - def __getattr__(self, name): - if name == 'xenapi': - return _Dispatcher(self.xenapi_request, None) - elif name.startswith('login'): - return lambda *params: self._login(name, params) - else: - return xmlrpclib.ServerProxy.__getattr__(self, name) - -def xapi_local(): - return Session("http://_var_xapi_xapi/", transport=UDSTransport()) - -def _parse_result(result): - if type(result) != dict or 'Status' not in result: - raise xmlrpclib.Fault(500, 'Missing Status in response from server' + result) - if result['Status'] == 'Success': - if 'Value' in result: - return result['Value'] - else: - raise xmlrpclib.Fault(500, - 'Missing Value in response from server') - else: - if 'ErrorDescription' in result: - if result['ErrorDescription'][0] == 'SESSION_INVALID': - return _RECONNECT_AND_RETRY - else: - raise Failure(result['ErrorDescription']) - else: - raise xmlrpclib.Fault( - 500, 'Missing ErrorDescription in response from server') - - -# Based upon _Method from xmlrpclib. -class _Dispatcher: - def __init__(self, send, name): - self.__send = send - self.__name = name - - def __repr__(self): - if self.__name: - return '<XenAPI._Dispatcher for %s>' % self.__name - else: - return '<XenAPI._Dispatcher>' - - def __getattr__(self, name): - if self.__name is None: - return _Dispatcher(self.__send, name) - else: - return _Dispatcher(self.__send, "%s.%s" % (self.__name, name)) - - def __call__(self, *args): - return self.__send(self.__name, args) -- 1.7.0.4 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Cluster-devel] [PATCH 5/5] Cleanup of fence_xenapi patches. Added copyright information to doc/COPYRIGHT. Fixed static reference to lib directory in fence_xenapi.py. Fixed static reference to RELEASE_VERSION and BUILD_DATE in fence_xenapi.py. 2011-04-20 11:51 [Cluster-devel] [PATCH 1/5] New fencing script for Citrix XenServer and XCP Matt Clark ` (2 preceding siblings ...) 2011-04-20 11:51 ` [Cluster-devel] [PATCH 4/5] Clean up of fence_xenapi patches. Moved XenAPI.py to lib directory and added to Makefile.am Matt Clark @ 2011-04-20 11:51 ` Matt Clark 2011-04-20 14:04 ` Fabio M. Di Nitto 3 siblings, 1 reply; 10+ messages in thread From: Matt Clark @ 2011-04-20 11:51 UTC (permalink / raw) To: cluster-devel.redhat.com --- doc/COPYRIGHT | 4 ++++ fence/agents/lib/Makefile.am | 4 ++-- fence/agents/xenapi/fence_xenapi.py | 12 ++++++++---- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/doc/COPYRIGHT b/doc/COPYRIGHT index b10071c..5afc642 100644 --- a/doc/COPYRIGHT +++ b/doc/COPYRIGHT @@ -5,6 +5,10 @@ Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved. Exceptions: +fence/agents/xenapi/*: + Copyright (C) 2011 Matthew Clark. + Author: Matthew Clark <mattjclark0407@hotmail.com> + fence/agents/apc_snmp/powernet369.mib: Copyright (c) 2005 American Power Conversion, Inc. PowerNet is a Trademark of American Power Conversion Corp. diff --git a/fence/agents/lib/Makefile.am b/fence/agents/lib/Makefile.am index b42fc12..aa6d072 100644 --- a/fence/agents/lib/Makefile.am +++ b/fence/agents/lib/Makefile.am @@ -1,8 +1,8 @@ MAINTAINERCLEANFILES = Makefile.in -TARGET = fencing.py fencing_snmp.py +TARGET = fencing.py fencing_snmp.py XenAPI.py -SRC = fencing.py.py fencing_snmp.py.py +SRC = fencing.py.py fencing_snmp.py.py XenAPI.py.py EXTRA_DIST = $(SRC) fence2man.xsl diff --git a/fence/agents/xenapi/fence_xenapi.py b/fence/agents/xenapi/fence_xenapi.py index 0657f4e..cae53e6 100755 --- a/fence/agents/xenapi/fence_xenapi.py +++ b/fence/agents/xenapi/fence_xenapi.py @@ -1,7 +1,7 @@ #!/usr/bin/python # ############################################################################# -# Copyright 2011 Matt Clark +# Copyright 2011 Matthew Clark # This file is part of fence-xenserver # # fence-xenserver is free software: you can redistribute it and/or modify @@ -32,10 +32,16 @@ # whether I should continue support for it. mattjclark0407 at hotmail dot com import sys -sys.path.append("/usr/lib/fence") +sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * import XenAPI +#BEGIN_VERSION_GENERATION +RELEASE_VERSION="" +REDHAT_COPYRIGHT="" +BUILD_DATE="" +#END_VERSION_GENERATION + EC_BAD_SESSION = 1 # Find the status of the port given in the -U flag of options. def get_power_fn(session, options): @@ -223,5 +229,3 @@ the status of virtual machines running on the host." if __name__ == "__main__": main() -RELEASE_VERSION="3.1.2.11-2b5b-dirty" -BUILD_DATE="(built Fri Mar 25 22:57:28 EST 2011)" -- 1.7.0.4 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Cluster-devel] [PATCH 5/5] Cleanup of fence_xenapi patches. Added copyright information to doc/COPYRIGHT. Fixed static reference to lib directory in fence_xenapi.py. Fixed static reference to RELEASE_VERSION and BUILD_DATE in fence_xenapi.py. 2011-04-20 11:51 ` [Cluster-devel] [PATCH 5/5] Cleanup of fence_xenapi patches. Added copyright information to doc/COPYRIGHT. Fixed static reference to lib directory in fence_xenapi.py. Fixed static reference to RELEASE_VERSION and BUILD_DATE in fence_xenapi.py Matt Clark @ 2011-04-20 14:04 ` Fabio M. Di Nitto 2011-04-20 15:12 ` Matt Clark 0 siblings, 1 reply; 10+ messages in thread From: Fabio M. Di Nitto @ 2011-04-20 14:04 UTC (permalink / raw) To: cluster-devel.redhat.com On 04/20/2011 01:51 PM, Matt Clark wrote: > --- > doc/COPYRIGHT | 4 ++++ > fence/agents/lib/Makefile.am | 4 ++-- > fence/agents/xenapi/fence_xenapi.py | 12 ++++++++---- > 3 files changed, 14 insertions(+), 6 deletions(-) You forgot to move the xenapi file in lib/ ? Fabio ^ permalink raw reply [flat|nested] 10+ messages in thread
* [Cluster-devel] [PATCH 5/5] Cleanup of fence_xenapi patches. Added copyright information to doc/COPYRIGHT. Fixed static reference to lib directory in fence_xenapi.py. Fixed static reference to RELEASE_VERSION and BUILD_DATE in fence_xenapi.py. 2011-04-20 14:04 ` Fabio M. Di Nitto @ 2011-04-20 15:12 ` Matt Clark 2011-04-20 15:32 ` Fabio M. Di Nitto 0 siblings, 1 reply; 10+ messages in thread From: Matt Clark @ 2011-04-20 15:12 UTC (permalink / raw) To: cluster-devel.redhat.com Patch 4/5 takes care of that. At least it should have... > Date: Wed, 20 Apr 2011 16:04:46 +0200 > From: fdinitto at redhat.com > To: cluster-devel at redhat.com > Subject: Re: [Cluster-devel] [PATCH 5/5] Cleanup of fence_xenapi patches. Added copyright information to doc/COPYRIGHT. Fixed static reference to lib directory in fence_xenapi.py. Fixed static reference to RELEASE_VERSION and BUILD_DATE in fence_xenapi.py. > > On 04/20/2011 01:51 PM, Matt Clark wrote: > > --- > > doc/COPYRIGHT | 4 ++++ > > fence/agents/lib/Makefile.am | 4 ++-- > > fence/agents/xenapi/fence_xenapi.py | 12 ++++++++---- > > 3 files changed, 14 insertions(+), 6 deletions(-) > > You forgot to move the xenapi file in lib/ ? > > Fabio > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://listman.redhat.com/archives/cluster-devel/attachments/20110421/221e4271/attachment.htm> ^ permalink raw reply [flat|nested] 10+ messages in thread
* [Cluster-devel] [PATCH 5/5] Cleanup of fence_xenapi patches. Added copyright information to doc/COPYRIGHT. Fixed static reference to lib directory in fence_xenapi.py. Fixed static reference to RELEASE_VERSION and BUILD_DATE in fence_xenapi.py. 2011-04-20 15:12 ` Matt Clark @ 2011-04-20 15:32 ` Fabio M. Di Nitto 2011-04-20 15:42 ` Matt Clark 0 siblings, 1 reply; 10+ messages in thread From: Fabio M. Di Nitto @ 2011-04-20 15:32 UTC (permalink / raw) To: cluster-devel.redhat.com On 04/20/2011 05:12 PM, Matt Clark wrote: > Patch 4/5 takes care of that. At least it should have... > Then something is wrong with the patch ordering because 4/4 renames but 5 changes the old path? Fabio >> Date: Wed, 20 Apr 2011 16:04:46 +0200 >> From: fdinitto at redhat.com >> To: cluster-devel at redhat.com >> Subject: Re: [Cluster-devel] [PATCH 5/5] Cleanup of fence_xenapi > patches. Added copyright information to doc/COPYRIGHT. Fixed static > reference to lib directory in fence_xenapi.py. Fixed static reference to > RELEASE_VERSION and BUILD_DATE in fence_xenapi.py. >> >> On 04/20/2011 01:51 PM, Matt Clark wrote: >> > --- >> > doc/COPYRIGHT | 4 ++++ >> > fence/agents/lib/Makefile.am | 4 ++-- >> > fence/agents/xenapi/fence_xenapi.py | 12 ++++++++---- >> > 3 files changed, 14 insertions(+), 6 deletions(-) >> >> You forgot to move the xenapi file in lib/ ? >> >> Fabio >> ^ permalink raw reply [flat|nested] 10+ messages in thread
* [Cluster-devel] [PATCH 5/5] Cleanup of fence_xenapi patches. Added copyright information to doc/COPYRIGHT. Fixed static reference to lib directory in fence_xenapi.py. Fixed static reference to RELEASE_VERSION and BUILD_DATE in fence_xenapi.py. 2011-04-20 15:32 ` Fabio M. Di Nitto @ 2011-04-20 15:42 ` Matt Clark 2011-04-20 15:57 ` Fabio M. Di Nitto 0 siblings, 1 reply; 10+ messages in thread From: Matt Clark @ 2011-04-20 15:42 UTC (permalink / raw) To: cluster-devel.redhat.com Patch 5/5 only touches the 3 files listed in your original email. The script fence_xenapi.py is the script that does the fencing, not the library. XenAPI.py is the underlying library which is now located in lib/ as of patch 4/50004-Clean-up-of-fence_xenapi-patches.patch: fence/agents/lib/XenAPI.py.py | 209 +++++++++++++++++++++++++++++++++++++++++0004-Clean-up-of-fence_xenapi-patches.patch: fence/agents/xenapi/XenAPI.py | 209 ----------------------------------------- Unless I am missing something... Which is quite possible. > Date: Wed, 20 Apr 2011 17:32:23 +0200 > From: fdinitto at redhat.com > To: cluster-devel at redhat.com > Subject: Re: [Cluster-devel] [PATCH 5/5] Cleanup of fence_xenapi patches. Added copyright information to doc/COPYRIGHT. Fixed static reference to lib directory in fence_xenapi.py. Fixed static reference to RELEASE_VERSION and BUILD_DATE in fence_xenapi.py. > > On 04/20/2011 05:12 PM, Matt Clark wrote: > > Patch 4/5 takes care of that. At least it should have... > > > > Then something is wrong with the patch ordering because 4/4 renames but > 5 changes the old path? > > Fabio > > >> Date: Wed, 20 Apr 2011 16:04:46 +0200 > >> From: fdinitto at redhat.com > >> To: cluster-devel at redhat.com > >> Subject: Re: [Cluster-devel] [PATCH 5/5] Cleanup of fence_xenapi > > patches. Added copyright information to doc/COPYRIGHT. Fixed static > > reference to lib directory in fence_xenapi.py. Fixed static reference to > > RELEASE_VERSION and BUILD_DATE in fence_xenapi.py. > >> > >> On 04/20/2011 01:51 PM, Matt Clark wrote: > >> > --- > >> > doc/COPYRIGHT | 4 ++++ > >> > fence/agents/lib/Makefile.am | 4 ++-- > >> > fence/agents/xenapi/fence_xenapi.py | 12 ++++++++---- > >> > 3 files changed, 14 insertions(+), 6 deletions(-) > >> > >> You forgot to move the xenapi file in lib/ ? > >> > >> Fabio > >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://listman.redhat.com/archives/cluster-devel/attachments/20110421/223cfd1a/attachment.htm> ^ permalink raw reply [flat|nested] 10+ messages in thread
* [Cluster-devel] [PATCH 5/5] Cleanup of fence_xenapi patches. Added copyright information to doc/COPYRIGHT. Fixed static reference to lib directory in fence_xenapi.py. Fixed static reference to RELEASE_VERSION and BUILD_DATE in fence_xenapi.py. 2011-04-20 15:42 ` Matt Clark @ 2011-04-20 15:57 ` Fabio M. Di Nitto 0 siblings, 0 replies; 10+ messages in thread From: Fabio M. Di Nitto @ 2011-04-20 15:57 UTC (permalink / raw) To: cluster-devel.redhat.com On 04/20/2011 05:42 PM, Matt Clark wrote: > Patch 5/5 only touches the 3 files listed in your original email. > > The script fence_xenapi.py is the script that does the fencing, not the > library. > > XenAPI.py is the underlying library which is now located in lib/ as of > patch 4/5 > 0004-Clean-up-of-fence_xenapi-patches.patch: > fence/agents/lib/XenAPI.py.py | 209 > +++++++++++++++++++++++++++++++++++++++++ > 0004-Clean-up-of-fence_xenapi-patches.patch: > fence/agents/xenapi/XenAPI.py | 209 > ----------------------------------------- > > Unless I am missing something... Which is quite possible. Whooops... I got confused by the two names... Ok time for me to go on vacation and relax. Marek, can you please merge the patchset when you are around (git am ..) ? Thanks Fabio ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2011-04-20 15:57 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2011-04-20 11:51 [Cluster-devel] [PATCH 1/5] New fencing script for Citrix XenServer and XCP Matt Clark 2011-04-20 11:51 ` [Cluster-devel] [PATCH 2/5] Updated to include xenapi script Matt Clark 2011-04-20 11:51 ` [Cluster-devel] [PATCH 3/5] Updated to include xenapi script in Makefile.am Matt Clark 2011-04-20 11:51 ` [Cluster-devel] [PATCH 4/5] Clean up of fence_xenapi patches. Moved XenAPI.py to lib directory and added to Makefile.am Matt Clark 2011-04-20 11:51 ` [Cluster-devel] [PATCH 5/5] Cleanup of fence_xenapi patches. Added copyright information to doc/COPYRIGHT. Fixed static reference to lib directory in fence_xenapi.py. Fixed static reference to RELEASE_VERSION and BUILD_DATE in fence_xenapi.py Matt Clark 2011-04-20 14:04 ` Fabio M. Di Nitto 2011-04-20 15:12 ` Matt Clark 2011-04-20 15:32 ` Fabio M. Di Nitto 2011-04-20 15:42 ` Matt Clark 2011-04-20 15:57 ` Fabio M. Di Nitto
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).