016e39734e
Due to some issues in the gate, several flake8 errors got merged recently. This patch fixes the most recent issues found. For the H304 relative import errors, we have to skip those because they are put into /etc/xensource/scripts which is the current working directory when running the plugin. For the H231 incompatible python 3 'except x,y' construct, we have to skip those because this code is written to run on python 2.4 and 'except x as y' does not work with python 2.4. Note that in cleaning up some of the H304 failures for relative imports, I also re-arranged the imports to follow the hacking guide of doing standard library packages first, then third party packages, and finally nova-specific packages. Closes-Bug: #1229753 Change-Id: I1c2211fd6a10d43d7e65cdb4e18530397788cf2c
144 lines
4.7 KiB
Python
144 lines
4.7 KiB
Python
# Copyright (c) 2010 Citrix Systems, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
#
|
|
# Helper functions for the Nova xapi plugins. In time, this will merge
|
|
# with the pluginlib.py shipped with xapi, but for now, that file is not
|
|
# very stable, so it's easiest just to have a copy of all the functions
|
|
# that we need.
|
|
#
|
|
|
|
import gettext
|
|
import logging
|
|
import logging.handlers
|
|
import time
|
|
import XenAPI
|
|
|
|
|
|
translations = gettext.translation('nova', fallback=True)
|
|
_ = translations.ugettext
|
|
|
|
|
|
##### Logging setup
|
|
|
|
def configure_logging(name):
|
|
log = logging.getLogger()
|
|
log.setLevel(logging.DEBUG)
|
|
sysh = logging.handlers.SysLogHandler('/dev/log')
|
|
sysh.setLevel(logging.DEBUG)
|
|
formatter = logging.Formatter('%s: %%(levelname)-8s %%(message)s' % name)
|
|
sysh.setFormatter(formatter)
|
|
log.addHandler(sysh)
|
|
|
|
|
|
##### Exceptions
|
|
|
|
class PluginError(Exception):
|
|
"""Base Exception class for all plugin errors."""
|
|
def __init__(self, *args):
|
|
Exception.__init__(self, *args)
|
|
|
|
|
|
class ArgumentError(PluginError):
|
|
"""Raised when required arguments are missing, argument values are invalid,
|
|
or incompatible arguments are given.
|
|
"""
|
|
def __init__(self, *args):
|
|
PluginError.__init__(self, *args)
|
|
|
|
|
|
##### Argument validation
|
|
|
|
def exists(args, key):
|
|
"""Validates that a freeform string argument to a RPC method call is given.
|
|
Returns the string.
|
|
"""
|
|
if key in args:
|
|
return args[key]
|
|
else:
|
|
raise ArgumentError(_('Argument %s is required.') % key)
|
|
|
|
|
|
def optional(args, key):
|
|
"""If the given key is in args, return the corresponding value, otherwise
|
|
return None
|
|
"""
|
|
return key in args and args[key] or None
|
|
|
|
|
|
def _get_domain_0(session):
|
|
this_host_ref = session.xenapi.session.get_this_host(session.handle)
|
|
expr = 'field "is_control_domain" = "true" and field "resident_on" = "%s"'
|
|
expr = expr % this_host_ref
|
|
return session.xenapi.VM.get_all_records_where(expr).keys()[0]
|
|
|
|
|
|
def with_vdi_in_dom0(session, vdi, read_only, f):
|
|
dom0 = _get_domain_0(session)
|
|
vbd_rec = {}
|
|
vbd_rec['VM'] = dom0
|
|
vbd_rec['VDI'] = vdi
|
|
vbd_rec['userdevice'] = 'autodetect'
|
|
vbd_rec['bootable'] = False
|
|
vbd_rec['mode'] = read_only and 'RO' or 'RW'
|
|
vbd_rec['type'] = 'disk'
|
|
vbd_rec['unpluggable'] = True
|
|
vbd_rec['empty'] = False
|
|
vbd_rec['other_config'] = {}
|
|
vbd_rec['qos_algorithm_type'] = ''
|
|
vbd_rec['qos_algorithm_params'] = {}
|
|
vbd_rec['qos_supported_algorithms'] = []
|
|
logging.debug(_('Creating VBD for VDI %s ... '), vdi)
|
|
vbd = session.xenapi.VBD.create(vbd_rec)
|
|
logging.debug(_('Creating VBD for VDI %s done.'), vdi)
|
|
try:
|
|
logging.debug(_('Plugging VBD %s ... '), vbd)
|
|
session.xenapi.VBD.plug(vbd)
|
|
logging.debug(_('Plugging VBD %s done.'), vbd)
|
|
return f(session.xenapi.VBD.get_device(vbd))
|
|
finally:
|
|
logging.debug(_('Destroying VBD for VDI %s ... '), vdi)
|
|
_vbd_unplug_with_retry(session, vbd)
|
|
try:
|
|
session.xenapi.VBD.destroy(vbd)
|
|
except XenAPI.Failure, e: # noqa
|
|
logging.error(_('Ignoring XenAPI.Failure %s'), e)
|
|
logging.debug(_('Destroying VBD for VDI %s done.'), vdi)
|
|
|
|
|
|
def _vbd_unplug_with_retry(session, vbd):
|
|
"""Call VBD.unplug on the given VBD, with a retry if we get
|
|
DEVICE_DETACH_REJECTED. For reasons which I don't understand, we're
|
|
seeing the device still in use, even when all processes using the device
|
|
should be dead.
|
|
"""
|
|
while True:
|
|
try:
|
|
session.xenapi.VBD.unplug(vbd)
|
|
logging.debug(_('VBD.unplug successful first time.'))
|
|
return
|
|
except XenAPI.Failure, e: # noqa
|
|
if (len(e.details) > 0 and
|
|
e.details[0] == 'DEVICE_DETACH_REJECTED'):
|
|
logging.debug(_('VBD.unplug rejected: retrying...'))
|
|
time.sleep(1)
|
|
elif (len(e.details) > 0 and
|
|
e.details[0] == 'DEVICE_ALREADY_DETACHED'):
|
|
logging.debug(_('VBD.unplug successful eventually.'))
|
|
return
|
|
else:
|
|
logging.error(_('Ignoring XenAPI.Failure in VBD.unplug: %s'),
|
|
e)
|
|
return
|