summaryrefslogtreecommitdiffstats
path: root/nova/virt
diff options
context:
space:
mode:
authorIlya Alekseyev <ialekseev@griddynamics.com>2011-04-18 15:25:44 +0400
committerIlya Alekseyev <ialekseev@griddynamics.com>2011-04-18 15:25:44 +0400
commit1e02e152aea76d5af30c42708caaee2fb1f05ede (patch)
tree57d6498fe5122f291f3e4899b1816487fc5bbff3 /nova/virt
parent519c885a4e3622417cd78655a211a2f23033d610 (diff)
parent9761e7690ab8f13a76c761ba6055372a0d29eaff (diff)
trunk merged. conflict resolved.
Diffstat (limited to 'nova/virt')
-rw-r--r--nova/virt/libvirt_conn.py227
-rw-r--r--nova/virt/vmwareapi_conn.py4
-rw-r--r--nova/virt/xenapi/vm_utils.py27
-rw-r--r--nova/virt/xenapi/vmops.py43
-rw-r--r--nova/virt/xenapi_conn.py9
5 files changed, 230 insertions, 80 deletions
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index 1eec55e5f..bc54835ff 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -117,6 +117,8 @@ flags.DEFINE_integer('live_migration_bandwidth', 0,
'Define live migration behavior')
flags.DEFINE_string('qemu_img', 'qemu-img',
'binary to use for qemu-img commands')
+flags.DEFINE_bool('start_guests_on_host_boot', False,
+ 'Whether to restart guests when the host reboots')
def get_connection(read_only):
@@ -172,36 +174,36 @@ def _get_network_info(instance):
instance['instance_type'])
network_info = []
- def ip_dict(ip):
- return {
- "ip": ip.address,
- "netmask": network["netmask"],
- "enabled": "1"}
-
- def ip6_dict(ip6):
- prefix = ip6.network.cidr_v6
- mac = instance.mac_address
- return {
- "ip": utils.to_global_ipv6(prefix, mac),
- "netmask": ip6.network.netmask_v6,
- "gateway": ip6.network.gateway_v6,
- "enabled": "1"}
-
for network in networks:
network_ips = [ip for ip in ip_addresses
- if ip.network_id == network.id]
+ if ip['network_id'] == network['id']]
+
+ def ip_dict(ip):
+ return {
+ 'ip': ip['address'],
+ 'netmask': network['netmask'],
+ 'enabled': '1'}
+
+ def ip6_dict():
+ prefix = network['cidr_v6']
+ mac = instance['mac_address']
+ return {
+ 'ip': utils.to_global_ipv6(prefix, mac),
+ 'netmask': network['netmask_v6'],
+ 'enabled': '1'}
mapping = {
'label': network['label'],
'gateway': network['gateway'],
'broadcast': network['broadcast'],
- 'mac': instance.mac_address,
+ 'mac': instance['mac_address'],
'rxtx_cap': flavor['rxtx_cap'],
'dns': [network['dns']],
'ips': [ip_dict(ip) for ip in network_ips]}
if FLAGS.use_ipv6:
- mapping['ip6s'] = [ip6_dict(ip) for ip in network_ips]
+ mapping['ip6s'] = [ip6_dict()]
+ mapping['gateway6'] = network['gateway_v6']
network_info.append((network, mapping))
return network_info
@@ -236,12 +238,8 @@ class LibvirtConnection(driver.ComputeDriver):
{'name': instance['name'], 'state': state})
db.instance_set_state(ctxt, instance['id'], state)
- if state == power_state.SHUTOFF:
- # TODO(soren): This is what the compute manager does when you
- # terminate # an instance. At some point I figure we'll have a
- # "terminated" state and some sort of cleanup job that runs
- # occasionally, cleaning them out.
- db.instance_destroy(ctxt, instance['id'])
+ # NOTE(justinsb): We no longer delete SHUTOFF instances,
+ # the user may want to power them back on
if state != power_state.RUNNING:
continue
@@ -316,12 +314,57 @@ class LibvirtConnection(driver.ComputeDriver):
return infos
def destroy(self, instance, cleanup=True):
+ instance_name = instance['name']
+
+ # TODO(justinsb): Refactor all lookupByName calls for error-handling
try:
- virt_dom = self._conn.lookupByName(instance['name'])
- virt_dom.destroy()
- except Exception as _err:
- pass
- # If the instance is already terminated, we're still happy
+ virt_dom = self._conn.lookupByName(instance_name)
+ except libvirt.libvirtError as e:
+ errcode = e.get_error_code()
+ if errcode == libvirt.VIR_ERR_NO_DOMAIN:
+ virt_dom = None
+ else:
+ LOG.warning(_("Error from libvirt during lookup of "
+ "%(instance_name)s. Code=%(errcode)s "
+ "Error=%(e)s") %
+ locals())
+ raise
+
+ # If the instance is already terminated, we're still happy
+ # Otherwise, destroy it
+ if virt_dom is not None:
+ try:
+ virt_dom.destroy()
+ except libvirt.libvirtError as e:
+ is_okay = False
+ errcode = e.get_error_code()
+ if errcode == libvirt.VIR_ERR_OPERATION_INVALID:
+ # If the instance if already shut off, we get this:
+ # Code=55 Error=Requested operation is not valid:
+ # domain is not running
+ (state, _max_mem, _mem, _cpus, _t) = virt_dom.info()
+ if state == power_state.SHUTOFF:
+ is_okay = True
+
+ if not is_okay:
+ LOG.warning(_("Error from libvirt during destroy of "
+ "%(instance_name)s. Code=%(errcode)s "
+ "Error=%(e)s") %
+ locals())
+ raise
+
+ try:
+ # NOTE(justinsb): We remove the domain definition. We probably
+ # would do better to keep it if cleanup=False (e.g. volumes?)
+ # (e.g. #2 - not losing machines on failure)
+ virt_dom.undefine()
+ except libvirt.libvirtError as e:
+ errcode = e.get_error_code()
+ LOG.warning(_("Error from libvirt during undefine of "
+ "%(instance_name)s. Code=%(errcode)s "
+ "Error=%(e)s") %
+ locals())
+ raise
# We'll save this for when we do shutdown,
# instead of destroy - but destroy returns immediately
@@ -332,12 +375,18 @@ class LibvirtConnection(driver.ComputeDriver):
state = self.get_info(instance['name'])['state']
db.instance_set_state(context.get_admin_context(),
instance['id'], state)
- if state == power_state.SHUTDOWN:
+ if state == power_state.SHUTOFF:
break
- except Exception:
+
+ # Let's not hammer on the DB
+ time.sleep(1)
+ except Exception as ex:
+ msg = _("Error encountered when destroying instance '%(id)s': "
+ "%(ex)s") % {"id": instance["id"], "ex": ex}
+ LOG.debug(msg)
db.instance_set_state(context.get_admin_context(),
instance['id'],
- power_state.SHUTDOWN)
+ power_state.SHUTOFF)
break
self.firewall_driver.unfilter_instance(instance)
@@ -429,7 +478,6 @@ class LibvirtConnection(driver.ComputeDriver):
'container_format': base['container_format'],
'is_public': False,
'properties': {'architecture': base['architecture'],
- 'type': base['type'],
'name': '%s.%s' % (base['name'], image_id),
'kernel_id': instance['kernel_id'],
'image_location': 'snapshot',
@@ -480,7 +528,7 @@ class LibvirtConnection(driver.ComputeDriver):
xml = self.to_xml(instance)
self.firewall_driver.setup_basic_filtering(instance)
self.firewall_driver.prepare_instance_filter(instance)
- self._conn.createXML(xml, 0)
+ self._create_new_domain(xml)
self.firewall_driver.apply_instance_filter(instance)
timer = utils.LoopingCall(f=None)
@@ -528,7 +576,7 @@ class LibvirtConnection(driver.ComputeDriver):
'kernel_id': FLAGS.rescue_kernel_id,
'ramdisk_id': FLAGS.rescue_ramdisk_id}
self._create_image(instance, xml, '.rescue', rescue_images)
- self._conn.createXML(xml, 0)
+ self._create_new_domain(xml)
timer = utils.LoopingCall(f=None)
@@ -571,10 +619,15 @@ class LibvirtConnection(driver.ComputeDriver):
self.firewall_driver.setup_basic_filtering(instance, network_info)
self.firewall_driver.prepare_instance_filter(instance, network_info)
self._create_image(instance, xml, network_info)
- self._conn.createXML(xml, 0)
+ domain = self._create_new_domain(xml)
LOG.debug(_("instance %s: is running"), instance['name'])
self.firewall_driver.apply_instance_filter(instance)
+ if FLAGS.start_guests_on_host_boot:
+ LOG.debug(_("instance %s: setting autostart ON") %
+ instance['name'])
+ domain.setAutostart(1)
+
timer = utils.LoopingCall(f=None)
def _wait_for_boot():
@@ -802,7 +855,10 @@ class LibvirtConnection(driver.ComputeDriver):
root_fname = '%08x' % int(disk_images['image_id'])
size = FLAGS.minimum_root_size
- if inst['instance_type'] == 'm1.tiny' or suffix == '.rescue':
+
+ inst_type_id = inst['instance_type_id']
+ inst_type = instance_types.get_instance_type(inst_type_id)
+ if inst_type['name'] == 'm1.tiny' or suffix == '.rescue':
size = None
root_fname += "_sm"
@@ -814,14 +870,13 @@ class LibvirtConnection(driver.ComputeDriver):
user=user,
project=project,
size=size)
- type_data = instance_types.get_instance_type(inst['instance_type'])
- if type_data['local_gb']:
+ if inst_type['local_gb']:
self._cache_image(fn=self._create_local,
target=basepath('disk.local'),
- fname="local_%s" % type_data['local_gb'],
+ fname="local_%s" % inst_type['local_gb'],
cow=FLAGS.use_cow_images,
- local_gb=type_data['local_gb'])
+ local_gb=inst_type['local_gb'])
# For now, we assume that if we're not using a kernel, we're using a
# partitioned disk image where the target partition is the first
@@ -847,7 +902,7 @@ class LibvirtConnection(driver.ComputeDriver):
for (network_ref, mapping) in network_info:
ifc_num += 1
- if not 'injected' in network_ref:
+ if not network_ref['injected']:
continue
have_injected_networks = True
@@ -955,8 +1010,8 @@ class LibvirtConnection(driver.ComputeDriver):
nics.append(self._get_nic_for_xml(network,
mapping))
# FIXME(vish): stick this in db
- instance_type_name = instance['instance_type']
- instance_type = instance_types.get_instance_type(instance_type_name)
+ inst_type_id = instance['instance_type_id']
+ inst_type = instance_types.get_instance_type(inst_type_id)
if FLAGS.use_cow_images:
driver_type = 'qcow2'
@@ -967,15 +1022,16 @@ class LibvirtConnection(driver.ComputeDriver):
'name': instance['name'],
'basepath': os.path.join(FLAGS.instances_path,
instance['name']),
- 'memory_kb': instance_type['memory_mb'] * 1024,
- 'vcpus': instance_type['vcpus'],
+ 'memory_kb': inst_type['memory_mb'] * 1024,
+ 'vcpus': inst_type['vcpus'],
'rescue': rescue,
- 'local': instance_type['local_gb'],
+ 'local': inst_type['local_gb'],
'driver_type': driver_type,
'nics': nics}
if FLAGS.vnc_enabled:
- xml_info['vncserver_host'] = FLAGS.vncserver_host
+ if FLAGS.libvirt_type != 'lxc':
+ xml_info['vncserver_host'] = FLAGS.vncserver_host
if not rescue:
if instance['kernel_id']:
xml_info['kernel'] = xml_info['basepath'] + "/kernel"
@@ -991,11 +1047,22 @@ class LibvirtConnection(driver.ComputeDriver):
return xml
def get_info(self, instance_name):
+ # NOTE(justinsb): When libvirt isn't running / can't connect, we get:
+ # libvir: Remote error : unable to connect to
+ # '/var/run/libvirt/libvirt-sock', libvirtd may need to be started:
+ # No such file or directory
try:
virt_dom = self._conn.lookupByName(instance_name)
- except:
- raise exception.NotFound(_("Instance %s not found")
- % instance_name)
+ except libvirt.libvirtError as e:
+ errcode = e.get_error_code()
+ if errcode == libvirt.VIR_ERR_NO_DOMAIN:
+ raise exception.NotFound(_("Instance %s not found")
+ % instance_name)
+ LOG.warning(_("Error from libvirt during lookup. "
+ "Code=%(errcode)s Error=%(e)s") %
+ locals())
+ raise
+
(state, max_mem, mem, num_cpu, cpu_time) = virt_dom.info()
return {'state': state,
'max_mem': max_mem,
@@ -1003,6 +1070,24 @@ class LibvirtConnection(driver.ComputeDriver):
'num_cpu': num_cpu,
'cpu_time': cpu_time}
+ def _create_new_domain(self, xml, persistent=True, launch_flags=0):
+ # NOTE(justinsb): libvirt has two types of domain:
+ # * a transient domain disappears when the guest is shutdown
+ # or the host is rebooted.
+ # * a permanent domain is not automatically deleted
+ # NOTE(justinsb): Even for ephemeral instances, transient seems risky
+
+ if persistent:
+ # To create a persistent domain, first define it, then launch it.
+ domain = self._conn.defineXML(xml)
+
+ domain.createWithFlags(launch_flags)
+ else:
+ # createXML call creates a transient domain
+ domain = self._conn.createXML(xml, launch_flags)
+
+ return domain
+
def get_diagnostics(self, instance_name):
raise exception.ApiError(_("diagnostics are not supported "
"for libvirt"))
@@ -1406,18 +1491,13 @@ class LibvirtConnection(driver.ComputeDriver):
# wait for completion
timeout_count = range(FLAGS.live_migration_retry_count)
while timeout_count:
- try:
- filter_name = 'nova-instance-%s' % instance_ref.name
- self._conn.nwfilterLookupByName(filter_name)
+ if self.firewall_driver.instance_filter_exists(instance_ref):
break
- except libvirt.libvirtError:
- timeout_count.pop()
- if len(timeout_count) == 0:
- ec2_id = instance_ref['hostname']
- iname = instance_ref.name
- msg = _('Timeout migrating for %(ec2_id)s(%(iname)s)')
- raise exception.Error(msg % locals())
- time.sleep(1)
+ timeout_count.pop()
+ if len(timeout_count) == 0:
+ msg = _('Timeout migrating for %s. nwfilter not found.')
+ raise exception.Error(msg % instance_ref.name)
+ time.sleep(1)
def live_migration(self, ctxt, instance_ref, dest,
post_method, recover_method):
@@ -1546,6 +1626,10 @@ class FirewallDriver(object):
"""
raise NotImplementedError()
+ def instance_filter_exists(self, instance):
+ """Check nova-instance-instance-xxx exists"""
+ raise NotImplementedError()
+
class NWFilterFirewall(FirewallDriver):
"""
@@ -1853,6 +1937,21 @@ class NWFilterFirewall(FirewallDriver):
return 'nova-instance-%s' % (instance['name'])
return 'nova-instance-%s-%s' % (instance['name'], nic_id)
+ def instance_filter_exists(self, instance):
+ """Check nova-instance-instance-xxx exists"""
+ network_info = _get_network_info(instance)
+ for (network, mapping) in network_info:
+ nic_id = mapping['mac'].replace(':', '')
+ instance_filter_name = self._instance_filter_name(instance, nic_id)
+ try:
+ self._conn.nwfilterLookupByName(instance_filter_name)
+ except libvirt.libvirtError:
+ name = instance.name
+ LOG.debug(_('The nwfilter(%(instance_filter_name)s) for'
+ '%(name)s is not found.') % locals())
+ return False
+ return True
+
class IptablesFirewallDriver(FirewallDriver):
def __init__(self, execute=None, **kwargs):
@@ -2042,6 +2141,10 @@ class IptablesFirewallDriver(FirewallDriver):
return ipv4_rules, ipv6_rules
+ def instance_filter_exists(self, instance):
+ """Check nova-instance-instance-xxx exists"""
+ return self.nwfilter.instance_filter_exists(instance)
+
def refresh_security_group_members(self, security_group):
pass
diff --git a/nova/virt/vmwareapi_conn.py b/nova/virt/vmwareapi_conn.py
index 20c1b2b45..1c6d2572d 100644
--- a/nova/virt/vmwareapi_conn.py
+++ b/nova/virt/vmwareapi_conn.py
@@ -42,6 +42,7 @@ from nova import exception
from nova import flags
from nova import log as logging
from nova import utils
+from nova.virt import driver
from nova.virt.vmwareapi import error_util
from nova.virt.vmwareapi import vim
from nova.virt.vmwareapi import vim_util
@@ -104,11 +105,12 @@ def get_connection(_):
api_retry_count)
-class VMWareESXConnection(object):
+class VMWareESXConnection(driver.ComputeDriver):
"""The ESX host connection object."""
def __init__(self, host_ip, host_username, host_password,
api_retry_count, scheme="https"):
+ super(VMWareESXConnection, self).__init__()
session = VMWareAPISession(host_ip, host_username, host_password,
api_retry_count, scheme=scheme)
self._vmops = VMWareVMOps(session)
diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py
index d07d60800..d2045a557 100644
--- a/nova/virt/xenapi/vm_utils.py
+++ b/nova/virt/xenapi/vm_utils.py
@@ -49,6 +49,8 @@ LOG = logging.getLogger("nova.virt.xenapi.vm_utils")
FLAGS = flags.FLAGS
flags.DEFINE_string('default_os_type', 'linux', 'Default OS type')
+flags.DEFINE_integer('block_device_creation_timeout', 10,
+ 'time to wait for a block device to be created')
XENAPI_POWER_STATE = {
'Halted': power_state.SHUTDOWN,
@@ -101,8 +103,8 @@ class VMHelper(HelperBase):
3. Using hardware virtualization
"""
- instance_type = instance_types.\
- get_instance_type(instance.instance_type)
+ inst_type_id = instance.instance_type_id
+ instance_type = instance_types.get_instance_type(inst_type_id)
mem = str(long(instance_type['memory_mb']) * 1024 * 1024)
vcpus = str(instance_type['vcpus'])
rec = {
@@ -169,8 +171,8 @@ class VMHelper(HelperBase):
@classmethod
def ensure_free_mem(cls, session, instance):
- instance_type = instance_types.get_instance_type(
- instance.instance_type)
+ inst_type_id = instance.instance_type_id
+ instance_type = instance_types.get_instance_type(inst_type_id)
mem = long(instance_type['memory_mb']) * 1024 * 1024
#get free memory from host
host = session.get_xenapi_host()
@@ -896,6 +898,16 @@ def remap_vbd_dev(dev):
return remapped_dev
+def _wait_for_device(dev):
+ """Wait for device node to appear"""
+ for i in xrange(0, FLAGS.block_device_creation_timeout):
+ if os.path.exists('/dev/%s' % dev):
+ return
+ time.sleep(1)
+
+ raise StorageError(_('Timeout waiting for device %s to be created') % dev)
+
+
def with_vdi_attached_here(session, vdi_ref, read_only, f):
this_vm_ref = get_this_vm_ref(session)
vbd_rec = {}
@@ -924,6 +936,11 @@ def with_vdi_attached_here(session, vdi_ref, read_only, f):
if dev != orig_dev:
LOG.debug(_('VBD %(vbd_ref)s plugged into wrong dev, '
'remapping to %(dev)s') % locals())
+ if dev != 'autodetect':
+ # NOTE(johannes): Unit tests will end up with a device called
+ # 'autodetect' which obviously won't exist. It's not ideal,
+ # but the alternatives were much messier
+ _wait_for_device(dev)
return f(dev)
finally:
LOG.debug(_('Destroying VBD for VDI %s ... '), vdi_ref)
@@ -1130,7 +1147,7 @@ def _prepare_injectables(inst, networks_info):
'dns': dns,
'address_v6': ip_v6 and ip_v6['ip'] or '',
'netmask_v6': ip_v6 and ip_v6['netmask'] or '',
- 'gateway_v6': ip_v6 and ip_v6['gateway'] or '',
+ 'gateway_v6': ip_v6 and info['gateway6'] or '',
'use_ipv6': FLAGS.use_ipv6}
interfaces_info.append(interface_info)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index c96c35a6e..7c7aa8e98 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -176,7 +176,7 @@ class VMOps(object):
vdi_ref, network_info)
self.create_vifs(vm_ref, network_info)
- self.inject_network_info(instance, vm_ref, network_info)
+ self.inject_network_info(instance, network_info, vm_ref)
return vm_ref
def _spawn(self, instance, vm_ref):
@@ -802,8 +802,10 @@ class VMOps(object):
instance['id'])
networks = db.network_get_all_by_instance(admin_context,
instance['id'])
- flavor = db.instance_type_get_by_name(admin_context,
- instance['instance_type'])
+
+ inst_type = db.instance_type_get_by_id(admin_context,
+ instance['instance_type_id'])
+
network_info = []
for network in networks:
network_IPs = [ip for ip in IPs if ip.network_id == network.id]
@@ -814,12 +816,11 @@ class VMOps(object):
"netmask": network["netmask"],
"enabled": "1"}
- def ip6_dict(ip6):
+ def ip6_dict():
return {
"ip": utils.to_global_ipv6(network['cidr_v6'],
instance['mac_address']),
"netmask": network['netmask_v6'],
- "gateway": network['gateway_v6'],
"enabled": "1"}
info = {
@@ -827,23 +828,41 @@ class VMOps(object):
'gateway': network['gateway'],
'broadcast': network['broadcast'],
'mac': instance.mac_address,
- 'rxtx_cap': flavor['rxtx_cap'],
+ 'rxtx_cap': inst_type['rxtx_cap'],
'dns': [network['dns']],
'ips': [ip_dict(ip) for ip in network_IPs]}
if network['cidr_v6']:
- info['ip6s'] = [ip6_dict(ip) for ip in network_IPs]
+ info['ip6s'] = [ip6_dict()]
+ if network['gateway_v6']:
+ info['gateway6'] = network['gateway_v6']
network_info.append((network, info))
return network_info
- def inject_network_info(self, instance, vm_ref, network_info):
+ #TODO{tr3buchet) remove this shim with nova-multi-nic
+ def inject_network_info(self, instance, network_info=None, vm_ref=None):
+ """
+ shim in place which makes inject_network_info work without being
+ passed network_info.
+ shim goes away after nova-multi-nic
+ """
+ if not network_info:
+ network_info = self._get_network_info(instance)
+ self._inject_network_info(instance, network_info, vm_ref)
+
+ def _inject_network_info(self, instance, network_info, vm_ref=None):
"""
Generate the network info and make calls to place it into the
xenstore and the xenstore param list.
+ vm_ref can be passed in because it will sometimes be different than
+ what VMHelper.lookup(session, instance.name) will find (ex: rescue)
"""
logging.debug(_("injecting network info to xs for vm: |%s|"), vm_ref)
- # this function raises if vm_ref is not a vm_opaque_ref
- self._session.get_xenapi().VM.get_record(vm_ref)
+ if vm_ref:
+ # this function raises if vm_ref is not a vm_opaque_ref
+ self._session.get_xenapi().VM.get_record(vm_ref)
+ else:
+ vm_ref = VMHelper.lookup(self._session, instance.name)
for (network, info) in network_info:
location = 'vm-data/networking/%s' % info['mac'].replace(':', '')
@@ -875,8 +894,10 @@ class VMOps(object):
VMHelper.create_vif(self._session, vm_ref, network_ref,
mac_address, device, rxtx_cap)
- def reset_network(self, instance, vm_ref):
+ def reset_network(self, instance, vm_ref=None):
"""Creates uuid arg to pass to make_agent_call and calls it."""
+ if not vm_ref:
+ vm_ref = VMHelper.lookup(self._session, instance.name)
args = {'id': str(uuid.uuid4())}
# TODO(tr3buchet): fix function call after refactor
#resp = self._make_agent_call('resetnetwork', instance, '', args)
diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py
index 99fd35c61..0cabccf08 100644
--- a/nova/virt/xenapi_conn.py
+++ b/nova/virt/xenapi_conn.py
@@ -63,6 +63,7 @@ import xmlrpclib
from eventlet import event
from eventlet import tpool
+from eventlet import timeout
from nova import context
from nova import db
@@ -140,6 +141,9 @@ flags.DEFINE_bool('xenapi_remap_vbd_dev', False,
flags.DEFINE_string('xenapi_remap_vbd_dev_prefix', 'sd',
'Specify prefix to remap VBD dev to '
'(ex. /dev/xvdb -> /dev/sdb)')
+flags.DEFINE_integer('xenapi_login_timeout',
+ 10,
+ 'Timeout in seconds for XenAPI login.')
def get_connection(_):
@@ -318,7 +322,10 @@ class XenAPISession(object):
def __init__(self, url, user, pw):
self.XenAPI = self.get_imported_xenapi()
self._session = self._create_session(url)
- self._session.login_with_password(user, pw)
+ exception = self.XenAPI.Failure(_("Unable to log in to XenAPI "
+ "(is the Dom0 disk full?)"))
+ with timeout.Timeout(FLAGS.xenapi_login_timeout, exception):
+ self._session.login_with_password(user, pw)
self.loop = None
def get_imported_xenapi(self):