Merge "libvirt: Moving tests under tests/virt/libvirt"
This commit is contained in:
commit
e809ba6b96
|
@ -1,60 +0,0 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2012 Grid Dynamics
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import os
|
||||
|
||||
from nova.virt.libvirt import config
|
||||
from nova.virt.libvirt import imagebackend
|
||||
|
||||
|
||||
class Backend(object):
|
||||
def __init__(self, use_cow):
|
||||
pass
|
||||
|
||||
def image(self, instance, name, image_type=''):
|
||||
class FakeImage(imagebackend.Image):
|
||||
def __init__(self, instance, name):
|
||||
self.path = os.path.join(instance['name'], name)
|
||||
|
||||
def create_image(self, prepare_template, base,
|
||||
size, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def cache(self, fetch_func, filename, size=None, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def snapshot(self, name):
|
||||
pass
|
||||
|
||||
def libvirt_info(self, disk_bus, disk_dev, device_type,
|
||||
cache_mode, extra_specs):
|
||||
info = config.LibvirtConfigGuestDisk()
|
||||
info.source_type = 'file'
|
||||
info.source_device = device_type
|
||||
info.target_bus = disk_bus
|
||||
info.target_dev = disk_dev
|
||||
info.driver_cache = cache_mode
|
||||
info.driver_format = 'raw'
|
||||
info.source_path = self.path
|
||||
return info
|
||||
|
||||
return FakeImage(instance, name)
|
||||
|
||||
def snapshot(self, path, name, image_type=''):
|
||||
#NOTE(bfilippov): this is done in favor for
|
||||
# snapshot tests in test_libvirt.LibvirtConnTestCase
|
||||
return imagebackend.Backend(True).snapshot(path, name, image_type)
|
|
@ -1,205 +0,0 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright (c) 2011 OpenStack Foundation
|
||||
#
|
||||
# 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.
|
||||
|
||||
import os
|
||||
import StringIO
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from nova.virt.libvirt import utils as libvirt_utils
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.import_opt('instances_path', 'nova.compute.manager')
|
||||
|
||||
|
||||
files = {'console.log': True}
|
||||
disk_sizes = {}
|
||||
disk_backing_files = {}
|
||||
disk_type = "qcow2"
|
||||
|
||||
|
||||
def get_iscsi_initiator():
|
||||
return "fake.initiator.iqn"
|
||||
|
||||
|
||||
def get_fc_hbas():
|
||||
return [{'ClassDevice': 'host1',
|
||||
'ClassDevicePath': '/sys/devices/pci0000:00/0000:00:03.0'
|
||||
'/0000:05:00.2/host1/fc_host/host1',
|
||||
'dev_loss_tmo': '30',
|
||||
'fabric_name': '0x1000000533f55566',
|
||||
'issue_lip': '<store method only>',
|
||||
'max_npiv_vports': '255',
|
||||
'maxframe_size': '2048 bytes',
|
||||
'node_name': '0x200010604b019419',
|
||||
'npiv_vports_inuse': '0',
|
||||
'port_id': '0x680409',
|
||||
'port_name': '0x100010604b019419',
|
||||
'port_state': 'Online',
|
||||
'port_type': 'NPort (fabric via point-to-point)',
|
||||
'speed': '10 Gbit',
|
||||
'supported_classes': 'Class 3',
|
||||
'supported_speeds': '10 Gbit',
|
||||
'symbolic_name': 'Emulex 554M FV4.0.493.0 DV8.3.27',
|
||||
'tgtid_bind_type': 'wwpn (World Wide Port Name)',
|
||||
'uevent': None,
|
||||
'vport_create': '<store method only>',
|
||||
'vport_delete': '<store method only>'}]
|
||||
|
||||
|
||||
def get_fc_hbas_info():
|
||||
hbas = get_fc_hbas()
|
||||
info = [{'port_name': hbas[0]['port_name'].replace('0x', ''),
|
||||
'node_name': hbas[0]['node_name'].replace('0x', ''),
|
||||
'host_device': hbas[0]['ClassDevice'],
|
||||
'device_path': hbas[0]['ClassDevicePath']}]
|
||||
return info
|
||||
|
||||
|
||||
def get_fc_wwpns():
|
||||
hbas = get_fc_hbas()
|
||||
wwpns = []
|
||||
for hba in hbas:
|
||||
wwpn = hba['port_name'].replace('0x', '')
|
||||
wwpns.append(wwpn)
|
||||
|
||||
return wwpns
|
||||
|
||||
|
||||
def get_fc_wwnns():
|
||||
hbas = get_fc_hbas()
|
||||
wwnns = []
|
||||
for hba in hbas:
|
||||
wwnn = hba['node_name'].replace('0x', '')
|
||||
wwnns.append(wwnn)
|
||||
|
||||
return wwnns
|
||||
|
||||
|
||||
def create_image(disk_format, path, size):
|
||||
pass
|
||||
|
||||
|
||||
def create_cow_image(backing_file, path):
|
||||
pass
|
||||
|
||||
|
||||
def get_disk_backing_file(path):
|
||||
return disk_backing_files.get(path, None)
|
||||
|
||||
|
||||
def get_disk_type(path):
|
||||
return disk_type
|
||||
|
||||
|
||||
def copy_image(src, dest):
|
||||
pass
|
||||
|
||||
|
||||
def resize2fs(path):
|
||||
pass
|
||||
|
||||
|
||||
def create_lvm_image(vg, lv, size, sparse=False):
|
||||
pass
|
||||
|
||||
|
||||
def volume_group_free_space(vg):
|
||||
pass
|
||||
|
||||
|
||||
def remove_logical_volumes(*paths):
|
||||
pass
|
||||
|
||||
|
||||
def write_to_file(path, contents, umask=None):
|
||||
pass
|
||||
|
||||
|
||||
def chown(path, owner):
|
||||
pass
|
||||
|
||||
|
||||
def create_snapshot(disk_path, snapshot_name):
|
||||
pass
|
||||
|
||||
|
||||
def delete_snapshot(disk_path, snapshot_name):
|
||||
pass
|
||||
|
||||
|
||||
def extract_snapshot(disk_path, source_fmt, snapshot_name, out_path, dest_fmt):
|
||||
files[out_path] = ''
|
||||
|
||||
|
||||
class File(object):
|
||||
def __init__(self, path, mode=None):
|
||||
if path in files:
|
||||
self.fp = StringIO.StringIO(files[path])
|
||||
else:
|
||||
self.fp = StringIO.StringIO(files[os.path.split(path)[-1]])
|
||||
|
||||
def __enter__(self):
|
||||
return self.fp
|
||||
|
||||
def __exit__(self, *args):
|
||||
return
|
||||
|
||||
def close(self, *args, **kwargs):
|
||||
self.fp.close()
|
||||
|
||||
|
||||
def file_open(path, mode=None):
|
||||
return File(path, mode)
|
||||
|
||||
|
||||
def find_disk(virt_dom):
|
||||
return "filename"
|
||||
|
||||
|
||||
def load_file(path):
|
||||
if os.path.exists(path):
|
||||
with open(path, 'r') as fp:
|
||||
return fp.read()
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
def logical_volume_info(path):
|
||||
return {}
|
||||
|
||||
|
||||
def file_delete(path):
|
||||
return True
|
||||
|
||||
|
||||
def get_fs_info(path):
|
||||
return {'total': 128 * (1024 ** 3),
|
||||
'used': 44 * (1024 ** 3),
|
||||
'free': 84 * (1024 ** 3)}
|
||||
|
||||
|
||||
def fetch_image(context, target, image_id, user_id, project_id):
|
||||
pass
|
||||
|
||||
|
||||
def get_instance_path(instance, forceold=False):
|
||||
return libvirt_utils.get_instance_path(instance, forceold=forceold)
|
||||
|
||||
|
||||
def pick_disk_driver_name(is_block_dev=False):
|
||||
return "qemu"
|
|
@ -1,920 +0,0 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2010 OpenStack Foundation
|
||||
#
|
||||
# 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.
|
||||
|
||||
from lxml import etree
|
||||
|
||||
import time
|
||||
import uuid
|
||||
|
||||
# Allow passing None to the various connect methods
|
||||
# (i.e. allow the client to rely on default URLs)
|
||||
allow_default_uri_connection = True
|
||||
|
||||
# string indicating the CPU arch
|
||||
node_arch = 'x86_64' # or 'i686' (or whatever else uname -m might return)
|
||||
|
||||
# memory size in kilobytes
|
||||
node_kB_mem = 4096
|
||||
|
||||
# the number of active CPUs
|
||||
node_cpus = 2
|
||||
|
||||
# expected CPU frequency
|
||||
node_mhz = 800
|
||||
|
||||
# the number of NUMA cell, 1 for unusual NUMA topologies or uniform
|
||||
# memory access; check capabilities XML for the actual NUMA topology
|
||||
node_nodes = 1 # NUMA nodes
|
||||
|
||||
# number of CPU sockets per node if nodes > 1, total number of CPU
|
||||
# sockets otherwise
|
||||
node_sockets = 1
|
||||
|
||||
# number of cores per socket
|
||||
node_cores = 2
|
||||
|
||||
# number of threads per core
|
||||
node_threads = 1
|
||||
|
||||
# CPU model
|
||||
node_cpu_model = "Penryn"
|
||||
|
||||
# CPU vendor
|
||||
node_cpu_vendor = "Intel"
|
||||
|
||||
|
||||
def _reset():
|
||||
global allow_default_uri_connection
|
||||
allow_default_uri_connection = True
|
||||
|
||||
# virDomainState
|
||||
VIR_DOMAIN_NOSTATE = 0
|
||||
VIR_DOMAIN_RUNNING = 1
|
||||
VIR_DOMAIN_BLOCKED = 2
|
||||
VIR_DOMAIN_PAUSED = 3
|
||||
VIR_DOMAIN_SHUTDOWN = 4
|
||||
VIR_DOMAIN_SHUTOFF = 5
|
||||
VIR_DOMAIN_CRASHED = 6
|
||||
|
||||
VIR_DOMAIN_XML_SECURE = 1
|
||||
|
||||
VIR_DOMAIN_EVENT_ID_LIFECYCLE = 0
|
||||
|
||||
VIR_DOMAIN_EVENT_DEFINED = 0
|
||||
VIR_DOMAIN_EVENT_UNDEFINED = 1
|
||||
VIR_DOMAIN_EVENT_STARTED = 2
|
||||
VIR_DOMAIN_EVENT_SUSPENDED = 3
|
||||
VIR_DOMAIN_EVENT_RESUMED = 4
|
||||
VIR_DOMAIN_EVENT_STOPPED = 5
|
||||
VIR_DOMAIN_EVENT_SHUTDOWN = 6
|
||||
VIR_DOMAIN_EVENT_PMSUSPENDED = 7
|
||||
|
||||
VIR_DOMAIN_UNDEFINE_MANAGED_SAVE = 1
|
||||
|
||||
VIR_DOMAIN_AFFECT_CURRENT = 0
|
||||
VIR_DOMAIN_AFFECT_LIVE = 1
|
||||
VIR_DOMAIN_AFFECT_CONFIG = 2
|
||||
|
||||
VIR_CPU_COMPARE_ERROR = -1
|
||||
VIR_CPU_COMPARE_INCOMPATIBLE = 0
|
||||
VIR_CPU_COMPARE_IDENTICAL = 1
|
||||
VIR_CPU_COMPARE_SUPERSET = 2
|
||||
|
||||
VIR_CRED_USERNAME = 1
|
||||
VIR_CRED_AUTHNAME = 2
|
||||
VIR_CRED_LANGUAGE = 3
|
||||
VIR_CRED_CNONCE = 4
|
||||
VIR_CRED_PASSPHRASE = 5
|
||||
VIR_CRED_ECHOPROMPT = 6
|
||||
VIR_CRED_NOECHOPROMPT = 7
|
||||
VIR_CRED_REALM = 8
|
||||
VIR_CRED_EXTERNAL = 9
|
||||
|
||||
VIR_MIGRATE_PEER2PEER = 2
|
||||
VIR_MIGRATE_UNDEFINE_SOURCE = 16
|
||||
|
||||
# libvirtError enums
|
||||
# (Intentionally different from what's in libvirt. We do this to check,
|
||||
# that consumers of the library are using the symbolic names rather than
|
||||
# hardcoding the numerical values)
|
||||
VIR_FROM_QEMU = 100
|
||||
VIR_FROM_DOMAIN = 200
|
||||
VIR_FROM_NWFILTER = 330
|
||||
VIR_FROM_REMOTE = 340
|
||||
VIR_FROM_RPC = 345
|
||||
VIR_ERR_XML_DETAIL = 350
|
||||
VIR_ERR_NO_DOMAIN = 420
|
||||
VIR_ERR_NO_NWFILTER = 620
|
||||
VIR_ERR_SYSTEM_ERROR = 900
|
||||
VIR_ERR_INTERNAL_ERROR = 950
|
||||
|
||||
|
||||
def _parse_disk_info(element):
|
||||
disk_info = {}
|
||||
disk_info['type'] = element.get('type', 'file')
|
||||
disk_info['device'] = element.get('device', 'disk')
|
||||
|
||||
driver = element.find('./driver')
|
||||
if driver is not None:
|
||||
disk_info['driver_name'] = driver.get('name')
|
||||
disk_info['driver_type'] = driver.get('type')
|
||||
|
||||
source = element.find('./source')
|
||||
if source is not None:
|
||||
disk_info['source'] = source.get('file')
|
||||
if not disk_info['source']:
|
||||
disk_info['source'] = source.get('dev')
|
||||
|
||||
if not disk_info['source']:
|
||||
disk_info['source'] = source.get('path')
|
||||
|
||||
target = element.find('./target')
|
||||
if target is not None:
|
||||
disk_info['target_dev'] = target.get('dev')
|
||||
disk_info['target_bus'] = target.get('bus')
|
||||
|
||||
return disk_info
|
||||
|
||||
|
||||
class libvirtError(Exception):
|
||||
def __init__(self, msg,
|
||||
error_code=VIR_ERR_INTERNAL_ERROR,
|
||||
error_domain=VIR_FROM_QEMU):
|
||||
self.error_code = error_code
|
||||
self.error_domain = error_domain
|
||||
Exception(self, msg)
|
||||
|
||||
def get_error_code(self):
|
||||
return self.error_code
|
||||
|
||||
def get_error_domain(self):
|
||||
return self.error_domain
|
||||
|
||||
|
||||
class NWFilter(object):
|
||||
def __init__(self, connection, xml):
|
||||
self._connection = connection
|
||||
|
||||
self._xml = xml
|
||||
self._parse_xml(xml)
|
||||
|
||||
def _parse_xml(self, xml):
|
||||
tree = etree.fromstring(xml)
|
||||
root = tree.find('.')
|
||||
self._name = root.get('name')
|
||||
|
||||
def undefine(self):
|
||||
self._connection._remove_filter(self)
|
||||
|
||||
|
||||
class Domain(object):
|
||||
def __init__(self, connection, xml, running=False, transient=False):
|
||||
self._connection = connection
|
||||
if running:
|
||||
connection._mark_running(self)
|
||||
|
||||
self._state = running and VIR_DOMAIN_RUNNING or VIR_DOMAIN_SHUTOFF
|
||||
self._transient = transient
|
||||
self._def = self._parse_definition(xml)
|
||||
self._has_saved_state = False
|
||||
self._snapshots = {}
|
||||
self._id = self._connection._id_counter
|
||||
|
||||
def _parse_definition(self, xml):
|
||||
try:
|
||||
tree = etree.fromstring(xml)
|
||||
except etree.ParseError:
|
||||
raise libvirtError("Invalid XML.",
|
||||
VIR_ERR_XML_DETAIL, VIR_FROM_DOMAIN)
|
||||
|
||||
definition = {}
|
||||
|
||||
name = tree.find('./name')
|
||||
if name is not None:
|
||||
definition['name'] = name.text
|
||||
|
||||
uuid_elem = tree.find('./uuid')
|
||||
if uuid_elem is not None:
|
||||
definition['uuid'] = uuid_elem.text
|
||||
else:
|
||||
definition['uuid'] = str(uuid.uuid4())
|
||||
|
||||
vcpu = tree.find('./vcpu')
|
||||
if vcpu is not None:
|
||||
definition['vcpu'] = int(vcpu.text)
|
||||
|
||||
memory = tree.find('./memory')
|
||||
if memory is not None:
|
||||
definition['memory'] = int(memory.text)
|
||||
|
||||
os = {}
|
||||
os_type = tree.find('./os/type')
|
||||
if os_type is not None:
|
||||
os['type'] = os_type.text
|
||||
os['arch'] = os_type.get('arch', node_arch)
|
||||
|
||||
os_kernel = tree.find('./os/kernel')
|
||||
if os_kernel is not None:
|
||||
os['kernel'] = os_kernel.text
|
||||
|
||||
os_initrd = tree.find('./os/initrd')
|
||||
if os_initrd is not None:
|
||||
os['initrd'] = os_initrd.text
|
||||
|
||||
os_cmdline = tree.find('./os/cmdline')
|
||||
if os_cmdline is not None:
|
||||
os['cmdline'] = os_cmdline.text
|
||||
|
||||
os_boot = tree.find('./os/boot')
|
||||
if os_boot is not None:
|
||||
os['boot_dev'] = os_boot.get('dev')
|
||||
|
||||
definition['os'] = os
|
||||
|
||||
features = {}
|
||||
|
||||
acpi = tree.find('./features/acpi')
|
||||
if acpi is not None:
|
||||
features['acpi'] = True
|
||||
|
||||
definition['features'] = features
|
||||
|
||||
devices = {}
|
||||
|
||||
device_nodes = tree.find('./devices')
|
||||
if device_nodes is not None:
|
||||
disks_info = []
|
||||
disks = device_nodes.findall('./disk')
|
||||
for disk in disks:
|
||||
disks_info += [_parse_disk_info(disk)]
|
||||
devices['disks'] = disks_info
|
||||
|
||||
nics_info = []
|
||||
nics = device_nodes.findall('./interface')
|
||||
for nic in nics:
|
||||
nic_info = {}
|
||||
nic_info['type'] = nic.get('type')
|
||||
|
||||
mac = nic.find('./mac')
|
||||
if mac is not None:
|
||||
nic_info['mac'] = mac.get('address')
|
||||
|
||||
source = nic.find('./source')
|
||||
if source is not None:
|
||||
if nic_info['type'] == 'network':
|
||||
nic_info['source'] = source.get('network')
|
||||
elif nic_info['type'] == 'bridge':
|
||||
nic_info['source'] = source.get('bridge')
|
||||
|
||||
nics_info += [nic_info]
|
||||
|
||||
devices['nics'] = nics_info
|
||||
|
||||
definition['devices'] = devices
|
||||
|
||||
return definition
|
||||
|
||||
def create(self):
|
||||
self.createWithFlags(0)
|
||||
|
||||
def createWithFlags(self, flags):
|
||||
# FIXME: Not handling flags at the moment
|
||||
self._state = VIR_DOMAIN_RUNNING
|
||||
self._connection._mark_running(self)
|
||||
self._has_saved_state = False
|
||||
|
||||
def isActive(self):
|
||||
return int(self._state == VIR_DOMAIN_RUNNING)
|
||||
|
||||
def undefine(self):
|
||||
self._connection._undefine(self)
|
||||
|
||||
def undefineFlags(self, flags):
|
||||
self.undefine()
|
||||
if flags & VIR_DOMAIN_UNDEFINE_MANAGED_SAVE:
|
||||
if self.hasManagedSaveImage(0):
|
||||
self.managedSaveRemove()
|
||||
|
||||
def destroy(self):
|
||||
self._state = VIR_DOMAIN_SHUTOFF
|
||||
self._connection._mark_not_running(self)
|
||||
|
||||
def ID(self):
|
||||
return self._id
|
||||
|
||||
def name(self):
|
||||
return self._def['name']
|
||||
|
||||
def UUIDString(self):
|
||||
return self._def['uuid']
|
||||
|
||||
def interfaceStats(self, device):
|
||||
return [10000242400, 1234, 0, 2, 213412343233, 34214234, 23, 3]
|
||||
|
||||
def blockStats(self, device):
|
||||
return [2, 10000242400, 234, 2343424234, 34]
|
||||
|
||||
def suspend(self):
|
||||
self._state = VIR_DOMAIN_PAUSED
|
||||
|
||||
def shutdown(self):
|
||||
self._state = VIR_DOMAIN_SHUTDOWN
|
||||
self._connection._mark_not_running(self)
|
||||
|
||||
def reset(self, flags):
|
||||
# FIXME: Not handling flags at the moment
|
||||
self._state = VIR_DOMAIN_RUNNING
|
||||
self._connection._mark_running(self)
|
||||
|
||||
def info(self):
|
||||
return [self._state,
|
||||
long(self._def['memory']),
|
||||
long(self._def['memory']),
|
||||
self._def['vcpu'],
|
||||
123456789L]
|
||||
|
||||
def migrateToURI(self, desturi, flags, dname, bandwidth):
|
||||
raise libvirtError("Migration always fails for fake libvirt!")
|
||||
|
||||
def attachDevice(self, xml):
|
||||
disk_info = _parse_disk_info(etree.fromstring(xml))
|
||||
disk_info['_attached'] = True
|
||||
self._def['devices']['disks'] += [disk_info]
|
||||
return True
|
||||
|
||||
def attachDeviceFlags(self, xml, flags):
|
||||
if (flags & VIR_DOMAIN_AFFECT_LIVE and
|
||||
self._state != VIR_DOMAIN_RUNNING):
|
||||
raise libvirtError("AFFECT_LIVE only allowed for running domains!")
|
||||
self.attachDevice(xml)
|
||||
|
||||
def detachDevice(self, xml):
|
||||
disk_info = _parse_disk_info(etree.fromstring(xml))
|
||||
disk_info['_attached'] = True
|
||||
return disk_info in self._def['devices']['disks']
|
||||
|
||||
def detachDeviceFlags(self, xml, _flags):
|
||||
self.detachDevice(xml)
|
||||
|
||||
def XMLDesc(self, flags):
|
||||
disks = ''
|
||||
for disk in self._def['devices']['disks']:
|
||||
disks += '''<disk type='%(type)s' device='%(device)s'>
|
||||
<driver name='%(driver_name)s' type='%(driver_type)s'/>
|
||||
<source file='%(source)s'/>
|
||||
<target dev='%(target_dev)s' bus='%(target_bus)s'/>
|
||||
<address type='drive' controller='0' bus='0' unit='0'/>
|
||||
</disk>''' % disk
|
||||
|
||||
nics = ''
|
||||
for nic in self._def['devices']['nics']:
|
||||
nics += '''<interface type='%(type)s'>
|
||||
<mac address='%(mac)s'/>
|
||||
<source %(type)s='%(source)s'/>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x03'
|
||||
function='0x0'/>
|
||||
</interface>''' % nic
|
||||
|
||||
return '''<domain type='kvm'>
|
||||
<name>%(name)s</name>
|
||||
<uuid>%(uuid)s</uuid>
|
||||
<memory>%(memory)s</memory>
|
||||
<currentMemory>%(memory)s</currentMemory>
|
||||
<vcpu>%(vcpu)s</vcpu>
|
||||
<os>
|
||||
<type arch='%(arch)s' machine='pc-0.12'>hvm</type>
|
||||
<boot dev='hd'/>
|
||||
</os>
|
||||
<features>
|
||||
<acpi/>
|
||||
<apic/>
|
||||
<pae/>
|
||||
</features>
|
||||
<clock offset='localtime'/>
|
||||
<on_poweroff>destroy</on_poweroff>
|
||||
<on_reboot>restart</on_reboot>
|
||||
<on_crash>restart</on_crash>
|
||||
<devices>
|
||||
<emulator>/usr/bin/kvm</emulator>
|
||||
%(disks)s
|
||||
<controller type='ide' index='0'>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x01'
|
||||
function='0x1'/>
|
||||
</controller>
|
||||
%(nics)s
|
||||
<serial type='file'>
|
||||
<source path='dummy.log'/>
|
||||
<target port='0'/>
|
||||
</serial>
|
||||
<serial type='pty'>
|
||||
<source pty='/dev/pts/27'/>
|
||||
<target port='1'/>
|
||||
</serial>
|
||||
<console type='file'>
|
||||
<source path='dummy.log'/>
|
||||
<target port='0'/>
|
||||
</console>
|
||||
<input type='tablet' bus='usb'/>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<graphics type='vnc' port='-1' autoport='yes'/>
|
||||
<graphics type='spice' port='-1' autoport='yes'/>
|
||||
<video>
|
||||
<model type='cirrus' vram='9216' heads='1'/>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x02'
|
||||
function='0x0'/>
|
||||
</video>
|
||||
<memballoon model='virtio'>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x04'
|
||||
function='0x0'/>
|
||||
</memballoon>
|
||||
</devices>
|
||||
</domain>''' % {'name': self._def['name'],
|
||||
'uuid': self._def['uuid'],
|
||||
'memory': self._def['memory'],
|
||||
'vcpu': self._def['vcpu'],
|
||||
'arch': self._def['os']['arch'],
|
||||
'disks': disks,
|
||||
'nics': nics}
|
||||
|
||||
def managedSave(self, flags):
|
||||
self._connection._mark_not_running(self)
|
||||
self._has_saved_state = True
|
||||
|
||||
def managedSaveRemove(self, flags):
|
||||
self._has_saved_state = False
|
||||
|
||||
def hasManagedSaveImage(self, flags):
|
||||
return int(self._has_saved_state)
|
||||
|
||||
def resume(self):
|
||||
self._state = VIR_DOMAIN_RUNNING
|
||||
|
||||
def snapshotCreateXML(self, xml, flags):
|
||||
tree = etree.fromstring(xml)
|
||||
name = tree.find('./name').text
|
||||
snapshot = DomainSnapshot(name, self)
|
||||
self._snapshots[name] = snapshot
|
||||
return snapshot
|
||||
|
||||
def vcpus(self):
|
||||
vcpus = ([], [])
|
||||
for i in range(0, self._def['vcpu']):
|
||||
vcpus[0].append((i, 1, 120405L, i))
|
||||
vcpus[1].append((True, True, True, True))
|
||||
return vcpus
|
||||
|
||||
def memoryStats(self):
|
||||
return {}
|
||||
|
||||
def maxMemory(self):
|
||||
return self._def['memory']
|
||||
|
||||
|
||||
class DomainSnapshot(object):
|
||||
def __init__(self, name, domain):
|
||||
self._name = name
|
||||
self._domain = domain
|
||||
|
||||
def delete(self, flags):
|
||||
del self._domain._snapshots[self._name]
|
||||
|
||||
|
||||
class Connection(object):
|
||||
def __init__(self, uri, readonly, version=9007):
|
||||
if not uri or uri == '':
|
||||
if allow_default_uri_connection:
|
||||
uri = 'qemu:///session'
|
||||
else:
|
||||
raise ValueError("URI was None, but fake libvirt is "
|
||||
"configured to not accept this.")
|
||||
|
||||
uri_whitelist = ['qemu:///system',
|
||||
'qemu:///session',
|
||||
'xen:///system',
|
||||
'uml:///system',
|
||||
'test:///default']
|
||||
|
||||
if uri not in uri_whitelist:
|
||||
raise libvirtError("libvirt error: no connection driver "
|
||||
"available for No connection for URI %s" % uri,
|
||||
5, 0)
|
||||
|
||||
self.readonly = readonly
|
||||
self._uri = uri
|
||||
self._vms = {}
|
||||
self._running_vms = {}
|
||||
self._id_counter = 1 # libvirt reserves 0 for the hypervisor.
|
||||
self._nwfilters = {}
|
||||
self._event_callbacks = {}
|
||||
self.fakeLibVersion = version
|
||||
self.fakeVersion = version
|
||||
|
||||
def _add_filter(self, nwfilter):
|
||||
self._nwfilters[nwfilter._name] = nwfilter
|
||||
|
||||
def _remove_filter(self, nwfilter):
|
||||
del self._nwfilters[nwfilter._name]
|
||||
|
||||
def _mark_running(self, dom):
|
||||
self._running_vms[self._id_counter] = dom
|
||||
self._emit_lifecycle(dom, VIR_DOMAIN_EVENT_STARTED, 0)
|
||||
self._id_counter += 1
|
||||
|
||||
def _mark_not_running(self, dom):
|
||||
if dom._transient:
|
||||
self._undefine(dom)
|
||||
|
||||
dom._id = -1
|
||||
|
||||
for (k, v) in self._running_vms.iteritems():
|
||||
if v == dom:
|
||||
del self._running_vms[k]
|
||||
self._emit_lifecycle(dom, VIR_DOMAIN_EVENT_STOPPED, 0)
|
||||
return
|
||||
|
||||
def _undefine(self, dom):
|
||||
del self._vms[dom.name()]
|
||||
if not dom._transient:
|
||||
self._emit_lifecycle(dom, VIR_DOMAIN_EVENT_UNDEFINED, 0)
|
||||
|
||||
def getInfo(self):
|
||||
return [node_arch,
|
||||
node_kB_mem,
|
||||
node_cpus,
|
||||
node_mhz,
|
||||
node_nodes,
|
||||
node_sockets,
|
||||
node_cores,
|
||||
node_threads]
|
||||
|
||||
def numOfDomains(self):
|
||||
return len(self._running_vms)
|
||||
|
||||
def listDomainsID(self):
|
||||
return self._running_vms.keys()
|
||||
|
||||
def lookupByID(self, id):
|
||||
if id in self._running_vms:
|
||||
return self._running_vms[id]
|
||||
raise libvirtError('Domain not found: no domain with matching '
|
||||
'id %d' % id,
|
||||
VIR_ERR_NO_DOMAIN, VIR_FROM_QEMU)
|
||||
|
||||
def lookupByName(self, name):
|
||||
if name in self._vms:
|
||||
return self._vms[name]
|
||||
raise libvirtError('Domain not found: no domain with matching '
|
||||
'name "%s"' % name,
|
||||
VIR_ERR_NO_DOMAIN, VIR_FROM_QEMU)
|
||||
|
||||
def _emit_lifecycle(self, dom, event, detail):
|
||||
if VIR_DOMAIN_EVENT_ID_LIFECYCLE not in self._event_callbacks:
|
||||
return
|
||||
|
||||
cbinfo = self._event_callbacks[VIR_DOMAIN_EVENT_ID_LIFECYCLE]
|
||||
callback = cbinfo[0]
|
||||
opaque = cbinfo[1]
|
||||
callback(self, dom, event, detail, opaque)
|
||||
|
||||
def defineXML(self, xml):
|
||||
dom = Domain(connection=self, running=False, transient=False, xml=xml)
|
||||
self._vms[dom.name()] = dom
|
||||
self._emit_lifecycle(dom, VIR_DOMAIN_EVENT_DEFINED, 0)
|
||||
return dom
|
||||
|
||||
def createXML(self, xml, flags):
|
||||
dom = Domain(connection=self, running=True, transient=True, xml=xml)
|
||||
self._vms[dom.name()] = dom
|
||||
self._emit_lifecycle(dom, VIR_DOMAIN_EVENT_STARTED, 0)
|
||||
return dom
|
||||
|
||||
def getType(self):
|
||||
if self._uri == 'qemu:///system':
|
||||
return 'QEMU'
|
||||
|
||||
def getLibVersion(self):
|
||||
return self.fakeLibVersion
|
||||
|
||||
def getVersion(self):
|
||||
return self.fakeVersion
|
||||
|
||||
def getHostname(self):
|
||||
return 'compute1'
|
||||
|
||||
def domainEventRegisterAny(self, dom, eventid, callback, opaque):
|
||||
self._event_callbacks[eventid] = [callback, opaque]
|
||||
|
||||
def getCapabilities(self):
|
||||
return '''<capabilities>
|
||||
<host>
|
||||
<uuid>cef19ce0-0ca2-11df-855d-b19fbce37686</uuid>
|
||||
<cpu>
|
||||
<arch>x86_64</arch>
|
||||
<model>Penryn</model>
|
||||
<vendor>Intel</vendor>
|
||||
<topology sockets='1' cores='2' threads='1'/>
|
||||
<feature name='xtpr'/>
|
||||
<feature name='tm2'/>
|
||||
<feature name='est'/>
|
||||
<feature name='vmx'/>
|
||||
<feature name='ds_cpl'/>
|
||||
<feature name='monitor'/>
|
||||
<feature name='pbe'/>
|
||||
<feature name='tm'/>
|
||||
<feature name='ht'/>
|
||||
<feature name='ss'/>
|
||||
<feature name='acpi'/>
|
||||
<feature name='ds'/>
|
||||
<feature name='vme'/>
|
||||
</cpu>
|
||||
<migration_features>
|
||||
<live/>
|
||||
<uri_transports>
|
||||
<uri_transport>tcp</uri_transport>
|
||||
</uri_transports>
|
||||
</migration_features>
|
||||
<secmodel>
|
||||
<model>apparmor</model>
|
||||
<doi>0</doi>
|
||||
</secmodel>
|
||||
</host>
|
||||
|
||||
<guest>
|
||||
<os_type>hvm</os_type>
|
||||
<arch name='i686'>
|
||||
<wordsize>32</wordsize>
|
||||
<emulator>/usr/bin/qemu</emulator>
|
||||
<machine>pc-0.14</machine>
|
||||
<machine canonical='pc-0.14'>pc</machine>
|
||||
<machine>pc-0.13</machine>
|
||||
<machine>pc-0.12</machine>
|
||||
<machine>pc-0.11</machine>
|
||||
<machine>pc-0.10</machine>
|
||||
<machine>isapc</machine>
|
||||
<domain type='qemu'>
|
||||
</domain>
|
||||
<domain type='kvm'>
|
||||
<emulator>/usr/bin/kvm</emulator>
|
||||
<machine>pc-0.14</machine>
|
||||
<machine canonical='pc-0.14'>pc</machine>
|
||||
<machine>pc-0.13</machine>
|
||||
<machine>pc-0.12</machine>
|
||||
<machine>pc-0.11</machine>
|
||||
<machine>pc-0.10</machine>
|
||||
<machine>isapc</machine>
|
||||
</domain>
|
||||
</arch>
|
||||
<features>
|
||||
<cpuselection/>
|
||||
<deviceboot/>
|
||||
<pae/>
|
||||
<nonpae/>
|
||||
<acpi default='on' toggle='yes'/>
|
||||
<apic default='on' toggle='no'/>
|
||||
</features>
|
||||
</guest>
|
||||
|
||||
<guest>
|
||||
<os_type>hvm</os_type>
|
||||
<arch name='x86_64'>
|
||||
<wordsize>64</wordsize>
|
||||
<emulator>/usr/bin/qemu-system-x86_64</emulator>
|
||||
<machine>pc-0.14</machine>
|
||||
<machine canonical='pc-0.14'>pc</machine>
|
||||
<machine>pc-0.13</machine>
|
||||
<machine>pc-0.12</machine>
|
||||
<machine>pc-0.11</machine>
|
||||
<machine>pc-0.10</machine>
|
||||
<machine>isapc</machine>
|
||||
<domain type='qemu'>
|
||||
</domain>
|
||||
<domain type='kvm'>
|
||||
<emulator>/usr/bin/kvm</emulator>
|
||||
<machine>pc-0.14</machine>
|
||||
<machine canonical='pc-0.14'>pc</machine>
|
||||
<machine>pc-0.13</machine>
|
||||
<machine>pc-0.12</machine>
|
||||
<machine>pc-0.11</machine>
|
||||
<machine>pc-0.10</machine>
|
||||
<machine>isapc</machine>
|
||||
</domain>
|
||||
</arch>
|
||||
<features>
|
||||
<cpuselection/>
|
||||
<deviceboot/>
|
||||
<acpi default='on' toggle='yes'/>
|
||||
<apic default='on' toggle='no'/>
|
||||
</features>
|
||||
</guest>
|
||||
|
||||
<guest>
|
||||
<os_type>hvm</os_type>
|
||||
<arch name='arm'>
|
||||
<wordsize>32</wordsize>
|
||||
<emulator>/usr/bin/qemu-system-arm</emulator>
|
||||
<machine>integratorcp</machine>
|
||||
<machine>vexpress-a9</machine>
|
||||
<machine>syborg</machine>
|
||||
<machine>musicpal</machine>
|
||||
<machine>mainstone</machine>
|
||||
<machine>n800</machine>
|
||||
<machine>n810</machine>
|
||||
<machine>n900</machine>
|
||||
<machine>cheetah</machine>
|
||||
<machine>sx1</machine>
|
||||
<machine>sx1-v1</machine>
|
||||
<machine>beagle</machine>
|
||||
<machine>beaglexm</machine>
|
||||
<machine>tosa</machine>
|
||||
<machine>akita</machine>
|
||||
<machine>spitz</machine>
|
||||
<machine>borzoi</machine>
|
||||
<machine>terrier</machine>
|
||||
<machine>connex</machine>
|
||||
<machine>verdex</machine>
|
||||
<machine>lm3s811evb</machine>
|
||||
<machine>lm3s6965evb</machine>
|
||||
<machine>realview-eb</machine>
|
||||
<machine>realview-eb-mpcore</machine>
|
||||
<machine>realview-pb-a8</machine>
|
||||
<machine>realview-pbx-a9</machine>
|
||||
<machine>versatilepb</machine>
|
||||
<machine>versatileab</machine>
|
||||
<domain type='qemu'>
|
||||
</domain>
|
||||
</arch>
|
||||
<features>
|
||||
<deviceboot/>
|
||||
</features>
|
||||
</guest>
|
||||
|
||||
<guest>
|
||||
<os_type>hvm</os_type>
|
||||
<arch name='mips'>
|
||||
<wordsize>32</wordsize>
|
||||
<emulator>/usr/bin/qemu-system-mips</emulator>
|
||||
<machine>malta</machine>
|
||||
<machine>mipssim</machine>
|
||||
<machine>magnum</machine>
|
||||
<machine>pica61</machine>
|
||||
<machine>mips</machine>
|
||||
<domain type='qemu'>
|
||||
</domain>
|
||||
</arch>
|
||||
<features>
|
||||
<deviceboot/>
|
||||
</features>
|
||||
</guest>
|
||||
|
||||
<guest>
|
||||
<os_type>hvm</os_type>
|
||||
<arch name='mipsel'>
|
||||
<wordsize>32</wordsize>
|
||||
<emulator>/usr/bin/qemu-system-mipsel</emulator>
|
||||
<machine>malta</machine>
|
||||
<machine>mipssim</machine>
|
||||
<machine>magnum</machine>
|
||||
<machine>pica61</machine>
|
||||
<machine>mips</machine>
|
||||
<domain type='qemu'>
|
||||
</domain>
|
||||
</arch>
|
||||
<features>
|
||||
<deviceboot/>
|
||||
</features>
|
||||
</guest>
|
||||
|
||||
<guest>
|
||||
<os_type>hvm</os_type>
|
||||
<arch name='sparc'>
|
||||
<wordsize>32</wordsize>
|
||||
<emulator>/usr/bin/qemu-system-sparc</emulator>
|
||||
<machine>SS-5</machine>
|
||||
<machine>leon3_generic</machine>
|
||||
<machine>SS-10</machine>
|
||||
<machine>SS-600MP</machine>
|
||||
<machine>SS-20</machine>
|
||||
<machine>Voyager</machine>
|
||||
<machine>LX</machine>
|
||||
<machine>SS-4</machine>
|
||||
<machine>SPARCClassic</machine>
|
||||
<machine>SPARCbook</machine>
|
||||
<machine>SS-1000</machine>
|
||||
<machine>SS-2000</machine>
|
||||
<machine>SS-2</machine>
|
||||
<domain type='qemu'>
|
||||
</domain>
|
||||
</arch>
|
||||
</guest>
|
||||
|
||||
<guest>
|
||||
<os_type>hvm</os_type>
|
||||
<arch name='ppc'>
|
||||
<wordsize>32</wordsize>
|
||||
<emulator>/usr/bin/qemu-system-ppc</emulator>
|
||||
<machine>g3beige</machine>
|
||||
<machine>virtex-ml507</machine>
|
||||
<machine>mpc8544ds</machine>
|
||||
<machine canonical='bamboo-0.13'>bamboo</machine>
|
||||
<machine>bamboo-0.13</machine>
|
||||
<machine>bamboo-0.12</machine>
|
||||
<machine>ref405ep</machine>
|
||||
<machine>taihu</machine>
|
||||
<machine>mac99</machine>
|
||||
<machine>prep</machine>
|
||||
<domain type='qemu'>
|
||||
</domain>
|
||||
</arch>
|
||||
<features>
|
||||
<deviceboot/>
|
||||
</features>
|
||||
</guest>
|
||||
|
||||
</capabilities>'''
|
||||
|
||||
def compareCPU(self, xml, flags):
|
||||
tree = etree.fromstring(xml)
|
||||
|
||||
arch_node = tree.find('./arch')
|
||||
if arch_node is not None:
|
||||
if arch_node.text not in ['x86_64', 'i686']:
|
||||
return VIR_CPU_COMPARE_INCOMPATIBLE
|
||||
|
||||
model_node = tree.find('./model')
|
||||
if model_node is not None:
|
||||
if model_node.text != node_cpu_model:
|
||||
return VIR_CPU_COMPARE_INCOMPATIBLE
|
||||
|
||||
vendor_node = tree.find('./vendor')
|
||||
if vendor_node is not None:
|
||||
if vendor_node.text != node_cpu_vendor:
|
||||
return VIR_CPU_COMPARE_INCOMPATIBLE
|
||||
|
||||
# The rest of the stuff libvirt implements is rather complicated
|
||||
# and I don't think it adds much value to replicate it here.
|
||||
|
||||
return VIR_CPU_COMPARE_IDENTICAL
|
||||
|
||||
def nwfilterLookupByName(self, name):
|
||||
try:
|
||||
return self._nwfilters[name]
|
||||
except KeyError:
|
||||
raise libvirtError("no nwfilter with matching name %s" % name,
|
||||
VIR_ERR_NO_NWFILTER, VIR_FROM_NWFILTER)
|
||||
|
||||
def nwfilterDefineXML(self, xml):
|
||||
nwfilter = NWFilter(self, xml)
|
||||
self._add_filter(nwfilter)
|
||||
|
||||
def listDefinedDomains(self):
|
||||
return []
|
||||
|
||||
|
||||
def openReadOnly(uri):
|
||||
return Connection(uri, readonly=True)
|
||||
|
||||
|
||||
def openAuth(uri, auth, flags):
|
||||
if flags != 0:
|
||||
raise Exception(_("Please extend mock libvirt module to support "
|
||||
"flags"))
|
||||
|
||||
if type(auth) != list:
|
||||
raise Exception(_("Expected a list for 'auth' parameter"))
|
||||
|
||||
if type(auth[0]) != list:
|
||||
raise Exception(
|
||||
_("Expected a function in 'auth[0]' parameter"))
|
||||
|
||||
if not callable(auth[1]):
|
||||
raise Exception(
|
||||
_("Expected a function in 'auth[1]' parameter"))
|
||||
|
||||
return Connection(uri, readonly=False)
|
||||
|
||||
|
||||
def virEventRunDefaultImpl():
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
def virEventRegisterDefaultImpl():
|
||||
pass
|
||||
|
||||
|
||||
virDomain = Domain
|
||||
|
||||
|
||||
virConnect = Connection
|
|
@ -1,406 +0,0 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2010 OpenStack Foundation
|
||||
#
|
||||
# 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.
|
||||
|
||||
from nova import test
|
||||
|
||||
from lxml import etree
|
||||
|
||||
import nova.tests.fakelibvirt as libvirt
|
||||
|
||||
|
||||
def get_vm_xml(name="testname", uuid=None, source_type='file',
|
||||
interface_type='bridge'):
|
||||
uuid_tag = ''
|
||||
if uuid:
|
||||
uuid_tag = '<uuid>%s</uuid>' % (uuid,)
|
||||
|
||||
return '''<domain type='kvm'>
|
||||
<name>%(name)s</name>
|
||||
%(uuid_tag)s
|
||||
<memory>128000</memory>
|
||||
<vcpu>1</vcpu>
|
||||
<os>
|
||||
<type>hvm</type>
|
||||
<kernel>/somekernel</kernel>
|
||||
<cmdline>root=/dev/sda</cmdline>
|
||||
<boot dev='hd'/>
|
||||
</os>
|
||||
<features>
|
||||
<acpi/>
|
||||
</features>
|
||||
<devices>
|
||||
<disk type='file' device='disk'>
|
||||
<driver name='qemu' type='qcow2'/>
|
||||
<source %(source_type)s='/somefile'/>
|
||||
<target dev='vda' bus='virtio'/>
|
||||
</disk>
|
||||
<interface type='%(interface_type)s'>
|
||||
<mac address='05:26:3e:31:28:1f'/>
|
||||
<source %(interface_type)s='br100'/>
|
||||
</interface>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<graphics type='vnc' port='5901' autoport='yes' keymap='en-us'/>
|
||||
<graphics type='spice' port='5901' autoport='yes' keymap='en-us'/>
|
||||
</devices>
|
||||
</domain>''' % {'name': name,
|
||||
'uuid_tag': uuid_tag,
|
||||
'source_type': source_type,
|
||||
'interface_type': interface_type}
|
||||
|
||||
|
||||
class FakeLibvirtTests(test.TestCase):
|
||||
def setUp(self):
|
||||
super(FakeLibvirtTests, self).setUp()
|
||||
libvirt._reset()
|
||||
|
||||
def get_openReadOnly_curry_func(self):
|
||||
return lambda uri: libvirt.openReadOnly(uri)
|
||||
|
||||
def get_openAuth_curry_func(self):
|
||||
def fake_cb(credlist):
|
||||
return 0
|
||||
return lambda uri: libvirt.openAuth(uri,
|
||||
[[libvirt.VIR_CRED_AUTHNAME,
|
||||
libvirt.VIR_CRED_NOECHOPROMPT],
|
||||
fake_cb,
|
||||
None], 0)
|
||||
|
||||
def _test_connect_method_accepts_None_uri_by_default(self, conn_method):
|
||||
conn = conn_method(None)
|
||||
self.assertNotEqual(conn, None, "Connecting to fake libvirt failed")
|
||||
|
||||
def test_openReadOnly_accepts_None_uri_by_default(self):
|
||||
conn_method = self.get_openReadOnly_curry_func()
|
||||
self._test_connect_method_accepts_None_uri_by_default(conn_method)
|
||||
|
||||
def test_openAuth_accepts_None_uri_by_default(self):
|
||||
conn_method = self.get_openAuth_curry_func()
|
||||
self._test_connect_method_accepts_None_uri_by_default(conn_method)
|
||||
|
||||
def _test_connect_method_can_refuse_None_uri(self, conn_method):
|
||||
libvirt.allow_default_uri_connection = False
|
||||
self.assertRaises(ValueError, conn_method, None)
|
||||
|
||||
def test_openReadOnly_can_refuse_None_uri(self):
|
||||
conn_method = self.get_openReadOnly_curry_func()
|
||||
self._test_connect_method_can_refuse_None_uri(conn_method)
|
||||
|
||||
def test_openAuth_can_refuse_None_uri(self):
|
||||
conn_method = self.get_openAuth_curry_func()
|
||||
self._test_connect_method_can_refuse_None_uri(conn_method)
|
||||
|
||||
def _test_connect_method_refuses_invalid_URI(self, conn_method):
|
||||
self.assertRaises(libvirt.libvirtError, conn_method, 'blah')
|
||||
|
||||
def test_openReadOnly_refuses_invalid_URI(self):
|
||||
conn_method = self.get_openReadOnly_curry_func()
|
||||
self._test_connect_method_refuses_invalid_URI(conn_method)
|
||||
|
||||
def test_openAuth_refuses_invalid_URI(self):
|
||||
conn_method = self.get_openAuth_curry_func()
|
||||
self._test_connect_method_refuses_invalid_URI(conn_method)
|
||||
|
||||
def test_getInfo(self):
|
||||
conn = libvirt.openReadOnly(None)
|
||||
res = conn.getInfo()
|
||||
self.assertIn(res[0], ('i686', 'x86_64'))
|
||||
self.assertTrue(1024 <= res[1] <= 16384,
|
||||
"Memory unusually high or low.")
|
||||
self.assertTrue(1 <= res[2] <= 32,
|
||||
"Active CPU count unusually high or low.")
|
||||
self.assertTrue(800 <= res[3] <= 4500,
|
||||
"CPU speed unusually high or low.")
|
||||
self.assertTrue(res[2] <= (res[5] * res[6]),
|
||||
"More active CPUs than num_sockets*cores_per_socket")
|
||||
|
||||
def test_createXML_detects_invalid_xml(self):
|
||||
self._test_XML_func_detects_invalid_xml('createXML', [0])
|
||||
|
||||
def test_defineXML_detects_invalid_xml(self):
|
||||
self._test_XML_func_detects_invalid_xml('defineXML', [])
|
||||
|
||||
def _test_XML_func_detects_invalid_xml(self, xmlfunc_name, args):
|
||||
conn = self.get_openAuth_curry_func()('qemu:///system')
|
||||
try:
|
||||
getattr(conn, xmlfunc_name)("this is not valid </xml>", *args)
|
||||
except libvirt.libvirtError, e:
|
||||
self.assertEqual(e.get_error_code(), libvirt.VIR_ERR_XML_DETAIL)
|
||||
self.assertEqual(e.get_error_domain(), libvirt.VIR_FROM_DOMAIN)
|
||||
return
|
||||
raise self.failureException("Invalid XML didn't raise libvirtError")
|
||||
|
||||
def test_defineXML_defines_domain(self):
|
||||
conn = self.get_openAuth_curry_func()('qemu:///system')
|
||||
conn.defineXML(get_vm_xml())
|
||||
dom = conn.lookupByName('testname')
|
||||
self.assertEqual('testname', dom.name())
|
||||
self.assertEqual(0, dom.isActive())
|
||||
dom.undefine()
|
||||
self.assertRaises(libvirt.libvirtError,
|
||||
conn.lookupByName,
|
||||
'testname')
|
||||
|
||||
def test_blockStats(self):
|
||||
conn = self.get_openAuth_curry_func()('qemu:///system')
|
||||
conn.createXML(get_vm_xml(), 0)
|
||||
dom = conn.lookupByName('testname')
|
||||
blockstats = dom.blockStats('vda')
|
||||
self.assertEqual(len(blockstats), 5)
|
||||
for x in blockstats:
|
||||
self.assertTrue(type(x) in [int, long])
|
||||
|
||||
def test_attach_detach(self):
|
||||
conn = self.get_openAuth_curry_func()('qemu:///system')
|
||||
conn.createXML(get_vm_xml(), 0)
|
||||
dom = conn.lookupByName('testname')
|
||||
xml = '''<disk type='block'>
|
||||
<driver name='qemu' type='raw'/>
|
||||
<source dev='/dev/nbd0'/>
|
||||
<target dev='/dev/vdc' bus='virtio'/>
|
||||
</disk>'''
|
||||
self.assertTrue(dom.attachDevice(xml))
|
||||
self.assertTrue(dom.detachDevice(xml))
|
||||
|
||||
def test_info(self):
|
||||
conn = self.get_openAuth_curry_func()('qemu:///system')
|
||||
conn.createXML(get_vm_xml(), 0)
|
||||
dom = conn.lookupByName('testname')
|
||||
info = dom.info()
|
||||
self.assertEqual(info[0], libvirt.VIR_DOMAIN_RUNNING)
|
||||
self.assertEqual(info[1], 128000)
|
||||
self.assertTrue(info[2] <= 128000)
|
||||
self.assertEqual(info[3], 1)
|
||||
self.assertTrue(type(info[4]) in [int, long])
|
||||
|
||||
def test_createXML_runs_domain(self):
|
||||
conn = self.get_openAuth_curry_func()('qemu:///system')
|
||||
conn.createXML(get_vm_xml(), 0)
|
||||
dom = conn.lookupByName('testname')
|
||||
self.assertEqual('testname', dom.name())
|
||||
self.assertEqual(1, dom.isActive())
|
||||
dom.destroy()
|
||||
try:
|
||||
dom = conn.lookupByName('testname')
|
||||
except libvirt.libvirtError as e:
|
||||
self.assertEqual(e.get_error_code(), libvirt.VIR_ERR_NO_DOMAIN)
|
||||
self.assertEqual(e.get_error_domain(), libvirt.VIR_FROM_QEMU)
|
||||
return
|
||||
self.fail("lookupByName succeeded for destroyed non-defined VM")
|
||||
|
||||
def test_defineXML_remembers_uuid(self):
|
||||
conn = self.get_openAuth_curry_func()('qemu:///system')
|
||||
uuid = 'b21f957d-a72f-4b93-b5a5-45b1161abb02'
|
||||
conn.defineXML(get_vm_xml(uuid=uuid))
|
||||
dom = conn.lookupByName('testname')
|
||||
self.assertEquals(dom.UUIDString(), uuid)
|
||||
|
||||
def test_createWithFlags(self):
|
||||
conn = self.get_openAuth_curry_func()('qemu:///system')
|
||||
conn.defineXML(get_vm_xml())
|
||||
dom = conn.lookupByName('testname')
|
||||
self.assertFalse(dom.isActive(), 'Defined domain was running.')
|
||||
dom.createWithFlags(0)
|
||||
self.assertTrue(dom.isActive(),
|
||||
'Domain wasn\'t running after createWithFlags')
|
||||
|
||||
def test_managedSave(self):
|
||||
conn = self.get_openAuth_curry_func()('qemu:///system')
|
||||
conn.defineXML(get_vm_xml())
|
||||
dom = conn.lookupByName('testname')
|
||||
self.assertFalse(dom.isActive(), 'Defined domain was running.')
|
||||
dom.createWithFlags(0)
|
||||
self.assertEquals(dom.hasManagedSaveImage(0), 0)
|
||||
dom.managedSave(0)
|
||||
self.assertEquals(dom.hasManagedSaveImage(0), 1)
|
||||
dom.managedSaveRemove(0)
|
||||
self.assertEquals(dom.hasManagedSaveImage(0), 0)
|
||||
|
||||
def test_listDomainsId_and_lookupById(self):
|
||||
conn = self.get_openAuth_curry_func()('qemu:///system')
|
||||
self.assertEquals(conn.listDomainsID(), [])
|
||||
conn.defineXML(get_vm_xml())
|
||||
dom = conn.lookupByName('testname')
|
||||
dom.createWithFlags(0)
|
||||
self.assertEquals(len(conn.listDomainsID()), 1)
|
||||
|
||||
dom_id = conn.listDomainsID()[0]
|
||||
self.assertEquals(conn.lookupByID(dom_id), dom)
|
||||
|
||||
dom_id = conn.listDomainsID()[0]
|
||||
try:
|
||||
conn.lookupByID(dom_id + 1)
|
||||
except libvirt.libvirtError, e:
|
||||
self.assertEqual(e.get_error_code(), libvirt.VIR_ERR_NO_DOMAIN)
|
||||
self.assertEqual(e.get_error_domain(), libvirt.VIR_FROM_QEMU)
|
||||
return
|
||||
raise self.failureException("Looking up an invalid domain ID didn't "
|
||||
"raise libvirtError")
|
||||
|
||||
def test_define_and_retrieve(self):
|
||||
conn = self.get_openAuth_curry_func()('qemu:///system')
|
||||
self.assertEquals(conn.listDomainsID(), [])
|
||||
conn.defineXML(get_vm_xml())
|
||||
dom = conn.lookupByName('testname')
|
||||
xml = dom.XMLDesc(0)
|
||||
etree.fromstring(xml)
|
||||
|
||||
def _test_accepts_source_type(self, source_type):
|
||||
conn = self.get_openAuth_curry_func()('qemu:///system')
|
||||
self.assertEquals(conn.listDomainsID(), [])
|
||||
conn.defineXML(get_vm_xml(source_type=source_type))
|
||||
dom = conn.lookupByName('testname')
|
||||
xml = dom.XMLDesc(0)
|
||||
tree = etree.fromstring(xml)
|
||||
elem = tree.find('./devices/disk/source')
|
||||
self.assertEquals(elem.get('file'), '/somefile')
|
||||
|
||||
def test_accepts_source_dev(self):
|
||||
self._test_accepts_source_type('dev')
|
||||
|
||||
def test_accepts_source_path(self):
|
||||
self._test_accepts_source_type('path')
|
||||
|
||||
def test_network_type_bridge_sticks(self):
|
||||
self._test_network_type_sticks('bridge')
|
||||
|
||||
def test_network_type_network_sticks(self):
|
||||
self._test_network_type_sticks('network')
|
||||
|
||||
def _test_network_type_sticks(self, network_type):
|
||||
conn = self.get_openAuth_curry_func()('qemu:///system')
|
||||
self.assertEquals(conn.listDomainsID(), [])
|
||||
conn.defineXML(get_vm_xml(interface_type=network_type))
|
||||
dom = conn.lookupByName('testname')
|
||||
xml = dom.XMLDesc(0)
|
||||
tree = etree.fromstring(xml)
|
||||
elem = tree.find('./devices/interface')
|
||||
self.assertEquals(elem.get('type'), network_type)
|
||||
elem = elem.find('./source')
|
||||
self.assertEquals(elem.get(network_type), 'br100')
|
||||
|
||||
def test_getType(self):
|
||||
conn = self.get_openAuth_curry_func()('qemu:///system')
|
||||
self.assertEquals(conn.getType(), 'QEMU')
|
||||
|
||||
def test_getVersion(self):
|
||||
conn = self.get_openAuth_curry_func()('qemu:///system')
|
||||
self.assertTrue(type(conn.getVersion()) is int)
|
||||
|
||||
def test_getCapabilities(self):
|
||||
conn = self.get_openAuth_curry_func()('qemu:///system')
|
||||
etree.fromstring(conn.getCapabilities())
|
||||
|
||||
def test_nwfilter_define_undefine(self):
|
||||
conn = self.get_openAuth_curry_func()('qemu:///system')
|
||||
# Will raise an exception if it's not valid XML
|
||||
xml = '''<filter name='nova-instance-instance-789' chain='root'>
|
||||
<uuid>946878c6-3ad3-82b2-87f3-c709f3807f58</uuid>
|
||||
</filter>'''
|
||||
|
||||
conn.nwfilterDefineXML(xml)
|
||||
nwfilter = conn.nwfilterLookupByName('nova-instance-instance-789')
|
||||
nwfilter.undefine()
|
||||
try:
|
||||
conn.nwfilterLookupByName('nova-instance-instance-789320334')
|
||||
except libvirt.libvirtError, e:
|
||||
self.assertEqual(e.get_error_code(), libvirt.VIR_ERR_NO_NWFILTER)
|
||||
self.assertEqual(e.get_error_domain(), libvirt.VIR_FROM_NWFILTER)
|
||||
return
|
||||
raise self.failureException("Invalid NWFilter name didn't"
|
||||
" raise libvirtError")
|
||||
|
||||
def test_compareCPU_compatible(self):
|
||||
conn = self.get_openAuth_curry_func()('qemu:///system')
|
||||
|
||||
xml = '''<cpu>
|
||||
<arch>%s</arch>
|
||||
<model>%s</model>
|
||||
<vendor>%s</vendor>
|
||||
<topology sockets="%d" cores="%d" threads="%d"/>
|
||||
</cpu>''' % (libvirt.node_arch,
|
||||
libvirt.node_cpu_model,
|
||||
libvirt.node_cpu_vendor,
|
||||
libvirt.node_sockets,
|
||||
libvirt.node_cores,
|
||||
libvirt.node_threads)
|
||||
self.assertEqual(conn.compareCPU(xml, 0),
|
||||
libvirt.VIR_CPU_COMPARE_IDENTICAL)
|
||||
|
||||
def test_compareCPU_incompatible_vendor(self):
|
||||
conn = self.get_openAuth_curry_func()('qemu:///system')
|
||||
|
||||
xml = '''<cpu>
|
||||
<arch>%s</arch>
|
||||
<model>%s</model>
|
||||
<vendor>%s</vendor>
|
||||
<topology sockets="%d" cores="%d" threads="%d"/>
|
||||
</cpu>''' % (libvirt.node_arch,
|
||||
libvirt.node_cpu_model,
|
||||
"AnotherVendor",
|
||||
libvirt.node_sockets,
|
||||
libvirt.node_cores,
|
||||
libvirt.node_threads)
|
||||
self.assertEqual(conn.compareCPU(xml, 0),
|
||||
libvirt.VIR_CPU_COMPARE_INCOMPATIBLE)
|
||||
|
||||
def test_compareCPU_incompatible_arch(self):
|
||||
conn = self.get_openAuth_curry_func()('qemu:///system')
|
||||
|
||||
xml = '''<cpu>
|
||||
<arch>%s</arch>
|
||||
<model>%s</model>
|
||||
<vendor>%s</vendor>
|
||||
<topology sockets="%d" cores="%d" threads="%d"/>
|
||||
</cpu>''' % ('not-a-valid-arch',
|
||||
libvirt.node_cpu_model,
|
||||
libvirt.node_cpu_vendor,
|
||||
libvirt.node_sockets,
|
||||
libvirt.node_cores,
|
||||
libvirt.node_threads)
|
||||
self.assertEqual(conn.compareCPU(xml, 0),
|
||||
libvirt.VIR_CPU_COMPARE_INCOMPATIBLE)
|
||||
|
||||
def test_compareCPU_incompatible_model(self):
|
||||
conn = self.get_openAuth_curry_func()('qemu:///system')
|
||||
|
||||
xml = '''<cpu>
|
||||
<arch>%s</arch>
|
||||
<model>%s</model>
|
||||
<vendor>%s</vendor>
|
||||
<topology sockets="%d" cores="%d" threads="%d"/>
|
||||
</cpu>''' % (libvirt.node_arch,
|
||||
"AnotherModel",
|
||||
libvirt.node_cpu_vendor,
|
||||
libvirt.node_sockets,
|
||||
libvirt.node_cores,
|
||||
libvirt.node_threads)
|
||||
self.assertEqual(conn.compareCPU(xml, 0),
|
||||
libvirt.VIR_CPU_COMPARE_INCOMPATIBLE)
|
||||
|
||||
def test_compareCPU_compatible_unspecified_model(self):
|
||||
conn = self.get_openAuth_curry_func()('qemu:///system')
|
||||
|
||||
xml = '''<cpu>
|
||||
<arch>%s</arch>
|
||||
<vendor>%s</vendor>
|
||||
<topology sockets="%d" cores="%d" threads="%d"/>
|
||||
</cpu>''' % (libvirt.node_arch,
|
||||
libvirt.node_cpu_vendor,
|
||||
libvirt.node_sockets,
|
||||
libvirt.node_cores,
|
||||
libvirt.node_threads)
|
||||
self.assertEqual(conn.compareCPU(xml, 0),
|
||||
libvirt.VIR_CPU_COMPARE_IDENTICAL)
|
|
@ -1,478 +0,0 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2012 Grid Dynamics
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import os
|
||||
|
||||
import fixtures
|
||||
from oslo.config import cfg
|
||||
|
||||
from nova import exception
|
||||
from nova.openstack.common import uuidutils
|
||||
from nova import test
|
||||
from nova.tests import fake_libvirt_utils
|
||||
from nova.tests import fake_processutils
|
||||
from nova.virt.libvirt import imagebackend
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class _ImageTestCase(object):
|
||||
INSTANCES_PATH = '/instances_path'
|
||||
|
||||
def mock_create_image(self, image):
|
||||
def create_image(fn, base, size, *args, **kwargs):
|
||||
fn(target=base, *args, **kwargs)
|
||||
image.create_image = create_image
|
||||
|
||||
def setUp(self):
|
||||
super(_ImageTestCase, self).setUp()
|
||||
self.flags(disable_process_locking=True,
|
||||
instances_path=self.INSTANCES_PATH)
|
||||
self.INSTANCE = {'name': 'instance',
|
||||
'uuid': uuidutils.generate_uuid()}
|
||||
self.NAME = 'fake.vm'
|
||||
self.TEMPLATE = 'template'
|
||||
|
||||
self.OLD_STYLE_INSTANCE_PATH = \
|
||||
fake_libvirt_utils.get_instance_path(self.INSTANCE, forceold=True)
|
||||
self.PATH = os.path.join(
|
||||
fake_libvirt_utils.get_instance_path(self.INSTANCE), self.NAME)
|
||||
|
||||
# TODO(mikal): rename template_dir to base_dir and template_path
|
||||
# to cached_image_path. This will be less confusing.
|
||||
self.TEMPLATE_DIR = os.path.join(CONF.instances_path, '_base')
|
||||
self.TEMPLATE_PATH = os.path.join(self.TEMPLATE_DIR, 'template')
|
||||
|
||||
self.useFixture(fixtures.MonkeyPatch(
|
||||
'nova.virt.libvirt.imagebackend.libvirt_utils',
|
||||
fake_libvirt_utils))
|
||||
|
||||
def test_cache(self):
|
||||
self.mox.StubOutWithMock(os.path, 'exists')
|
||||
if self.OLD_STYLE_INSTANCE_PATH:
|
||||
os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False)
|
||||
os.path.exists(self.TEMPLATE_DIR).AndReturn(False)
|
||||
os.path.exists(self.PATH).AndReturn(False)
|
||||
os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
|
||||
fn = self.mox.CreateMockAnything()
|
||||
fn(target=self.TEMPLATE_PATH)
|
||||
self.mox.StubOutWithMock(imagebackend.fileutils, 'ensure_tree')
|
||||
imagebackend.fileutils.ensure_tree(self.TEMPLATE_DIR)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
self.mock_create_image(image)
|
||||
image.cache(fn, self.TEMPLATE)
|
||||
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_cache_image_exists(self):
|
||||
self.mox.StubOutWithMock(os.path, 'exists')
|
||||
if self.OLD_STYLE_INSTANCE_PATH:
|
||||
os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False)
|
||||
os.path.exists(self.TEMPLATE_DIR).AndReturn(True)
|
||||
os.path.exists(self.PATH).AndReturn(True)
|
||||
os.path.exists(self.TEMPLATE_PATH).AndReturn(True)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
image.cache(None, self.TEMPLATE)
|
||||
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_cache_base_dir_exists(self):
|
||||
self.mox.StubOutWithMock(os.path, 'exists')
|
||||
if self.OLD_STYLE_INSTANCE_PATH:
|
||||
os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False)
|
||||
os.path.exists(self.TEMPLATE_DIR).AndReturn(True)
|
||||
os.path.exists(self.PATH).AndReturn(False)
|
||||
os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
|
||||
fn = self.mox.CreateMockAnything()
|
||||
fn(target=self.TEMPLATE_PATH)
|
||||
self.mox.StubOutWithMock(imagebackend.fileutils, 'ensure_tree')
|
||||
self.mox.ReplayAll()
|
||||
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
self.mock_create_image(image)
|
||||
image.cache(fn, self.TEMPLATE)
|
||||
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_cache_template_exists(self):
|
||||
self.mox.StubOutWithMock(os.path, 'exists')
|
||||
if self.OLD_STYLE_INSTANCE_PATH:
|
||||
os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False)
|
||||
os.path.exists(self.TEMPLATE_DIR).AndReturn(True)
|
||||
os.path.exists(self.PATH).AndReturn(False)
|
||||
os.path.exists(self.TEMPLATE_PATH).AndReturn(True)
|
||||
fn = self.mox.CreateMockAnything()
|
||||
self.mox.ReplayAll()
|
||||
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
self.mock_create_image(image)
|
||||
image.cache(fn, self.TEMPLATE)
|
||||
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_prealloc_image(self):
|
||||
CONF.set_override('preallocate_images', 'space')
|
||||
|
||||
fake_processutils.fake_execute_clear_log()
|
||||
fake_processutils.stub_out_processutils_execute(self.stubs)
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
|
||||
def fake_fetch(target, *args, **kwargs):
|
||||
return
|
||||
|
||||
self.stubs.Set(os.path, 'exists', lambda _: True)
|
||||
|
||||
# Call twice to verify testing fallocate is only called once.
|
||||
image.cache(fake_fetch, self.TEMPLATE_PATH, self.SIZE)
|
||||
image.cache(fake_fetch, self.TEMPLATE_PATH, self.SIZE)
|
||||
|
||||
self.assertEqual(fake_processutils.fake_execute_get_log(),
|
||||
['fallocate -n -l 1 %s.fallocate_test' % self.PATH,
|
||||
'fallocate -n -l %s %s' % (self.SIZE, self.PATH),
|
||||
'fallocate -n -l %s %s' % (self.SIZE, self.PATH)])
|
||||
|
||||
|
||||
class RawTestCase(_ImageTestCase, test.TestCase):
|
||||
|
||||
SIZE = 1024
|
||||
|
||||
def setUp(self):
|
||||
self.image_class = imagebackend.Raw
|
||||
super(RawTestCase, self).setUp()
|
||||
self.stubs.Set(imagebackend.Raw, 'correct_format', lambda _: None)
|
||||
|
||||
def prepare_mocks(self):
|
||||
fn = self.mox.CreateMockAnything()
|
||||
self.mox.StubOutWithMock(imagebackend.utils.synchronized,
|
||||
'__call__')
|
||||
self.mox.StubOutWithMock(imagebackend.libvirt_utils, 'copy_image')
|
||||
self.mox.StubOutWithMock(imagebackend.disk, 'extend')
|
||||
return fn
|
||||
|
||||
def test_create_image(self):
|
||||
fn = self.prepare_mocks()
|
||||
fn(target=self.TEMPLATE_PATH, image_id=None)
|
||||
imagebackend.libvirt_utils.copy_image(self.TEMPLATE_PATH, self.PATH)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
image.create_image(fn, self.TEMPLATE_PATH, None, image_id=None)
|
||||
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_create_image_generated(self):
|
||||
fn = self.prepare_mocks()
|
||||
fn(target=self.PATH)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
image.create_image(fn, self.TEMPLATE_PATH, None)
|
||||
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_create_image_extend(self):
|
||||
fn = self.prepare_mocks()
|
||||
fn(target=self.TEMPLATE_PATH, image_id=None)
|
||||
imagebackend.libvirt_utils.copy_image(self.TEMPLATE_PATH, self.PATH)
|
||||
imagebackend.disk.extend(self.PATH, self.SIZE)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
image.create_image(fn, self.TEMPLATE_PATH, self.SIZE, image_id=None)
|
||||
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_correct_format(self):
|
||||
info = self.mox.CreateMockAnything()
|
||||
self.stubs.UnsetAll()
|
||||
|
||||
self.mox.StubOutWithMock(os.path, 'exists')
|
||||
self.mox.StubOutWithMock(imagebackend.images, 'qemu_img_info')
|
||||
|
||||
os.path.exists(self.PATH).AndReturn(True)
|
||||
info = self.mox.CreateMockAnything()
|
||||
info.file_format = 'foo'
|
||||
imagebackend.images.qemu_img_info(self.PATH).AndReturn(info)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
image = self.image_class(self.INSTANCE, self.NAME, path=self.PATH)
|
||||
self.assertEqual(image.driver_format, 'foo')
|
||||
|
||||
self.mox.VerifyAll()
|
||||
|
||||
|
||||
class Qcow2TestCase(_ImageTestCase, test.TestCase):
|
||||
SIZE = 1024 * 1024 * 1024
|
||||
|
||||
def setUp(self):
|
||||
self.image_class = imagebackend.Qcow2
|
||||
super(Qcow2TestCase, self).setUp()
|
||||
self.QCOW2_BASE = (self.TEMPLATE_PATH +
|
||||
'_%d' % (self.SIZE / (1024 * 1024 * 1024)))
|
||||
|
||||
def prepare_mocks(self):
|
||||
fn = self.mox.CreateMockAnything()
|
||||
self.mox.StubOutWithMock(imagebackend.utils.synchronized,
|
||||
'__call__')
|
||||
self.mox.StubOutWithMock(imagebackend.libvirt_utils,
|
||||
'create_cow_image')
|
||||
self.mox.StubOutWithMock(imagebackend.libvirt_utils, 'copy_image')
|
||||
self.mox.StubOutWithMock(imagebackend.disk, 'extend')
|
||||
return fn
|
||||
|
||||
def test_create_image(self):
|
||||
fn = self.prepare_mocks()
|
||||
fn(target=self.TEMPLATE_PATH)
|
||||
imagebackend.libvirt_utils.create_cow_image(self.TEMPLATE_PATH,
|
||||
self.PATH)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
image.create_image(fn, self.TEMPLATE_PATH, None)
|
||||
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_create_image_with_size(self):
|
||||
fn = self.prepare_mocks()
|
||||
fn(target=self.TEMPLATE_PATH)
|
||||
self.mox.StubOutWithMock(os.path, 'exists')
|
||||
self.mox.StubOutWithMock(imagebackend.disk, 'get_disk_size')
|
||||
if self.OLD_STYLE_INSTANCE_PATH:
|
||||
os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False)
|
||||
os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
|
||||
imagebackend.disk.get_disk_size(self.TEMPLATE_PATH
|
||||
).AndReturn(self.SIZE)
|
||||
os.path.exists(self.PATH).AndReturn(False)
|
||||
imagebackend.libvirt_utils.create_cow_image(self.TEMPLATE_PATH,
|
||||
self.PATH)
|
||||
imagebackend.disk.extend(self.PATH, self.SIZE)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
image.create_image(fn, self.TEMPLATE_PATH, self.SIZE)
|
||||
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_create_image_too_small(self):
|
||||
fn = self.prepare_mocks()
|
||||
fn(target=self.TEMPLATE_PATH)
|
||||
self.mox.StubOutWithMock(os.path, 'exists')
|
||||
self.mox.StubOutWithMock(imagebackend.disk, 'get_disk_size')
|
||||
if self.OLD_STYLE_INSTANCE_PATH:
|
||||
os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False)
|
||||
os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
|
||||
imagebackend.disk.get_disk_size(self.TEMPLATE_PATH
|
||||
).AndReturn(self.SIZE)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
self.assertRaises(exception.ImageTooLarge, image.create_image, fn,
|
||||
self.TEMPLATE_PATH, 1)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
|
||||
class LvmTestCase(_ImageTestCase, test.TestCase):
|
||||
VG = 'FakeVG'
|
||||
TEMPLATE_SIZE = 512
|
||||
SIZE = 1024
|
||||
|
||||
def setUp(self):
|
||||
self.image_class = imagebackend.Lvm
|
||||
super(LvmTestCase, self).setUp()
|
||||
self.flags(libvirt_images_volume_group=self.VG)
|
||||
self.LV = '%s_%s' % (self.INSTANCE['name'], self.NAME)
|
||||
self.OLD_STYLE_INSTANCE_PATH = None
|
||||
self.PATH = os.path.join('/dev', self.VG, self.LV)
|
||||
|
||||
self.disk = imagebackend.disk
|
||||
self.utils = imagebackend.utils
|
||||
self.libvirt_utils = imagebackend.libvirt_utils
|
||||
|
||||
def prepare_mocks(self):
|
||||
fn = self.mox.CreateMockAnything()
|
||||
self.mox.StubOutWithMock(self.disk, 'resize2fs')
|
||||
self.mox.StubOutWithMock(self.libvirt_utils, 'create_lvm_image')
|
||||
self.mox.StubOutWithMock(self.disk, 'get_disk_size')
|
||||
self.mox.StubOutWithMock(self.utils, 'execute')
|
||||
return fn
|
||||
|
||||
def _create_image(self, sparse):
|
||||
fn = self.prepare_mocks()
|
||||
fn(target=self.TEMPLATE_PATH)
|
||||
self.libvirt_utils.create_lvm_image(self.VG,
|
||||
self.LV,
|
||||
self.TEMPLATE_SIZE,
|
||||
sparse=sparse)
|
||||
self.disk.get_disk_size(self.TEMPLATE_PATH
|
||||
).AndReturn(self.TEMPLATE_SIZE)
|
||||
cmd = ('qemu-img', 'convert', '-O', 'raw', self.TEMPLATE_PATH,
|
||||
self.PATH)
|
||||
self.utils.execute(*cmd, run_as_root=True)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
image.create_image(fn, self.TEMPLATE_PATH, None)
|
||||
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def _create_image_generated(self, sparse):
|
||||
fn = self.prepare_mocks()
|
||||
self.libvirt_utils.create_lvm_image(self.VG, self.LV,
|
||||
self.SIZE, sparse=sparse)
|
||||
fn(target=self.PATH, ephemeral_size=None)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
image.create_image(fn, self.TEMPLATE_PATH,
|
||||
self.SIZE, ephemeral_size=None)
|
||||
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def _create_image_resize(self, sparse):
|
||||
fn = self.prepare_mocks()
|
||||
fn(target=self.TEMPLATE_PATH)
|
||||
self.libvirt_utils.create_lvm_image(self.VG, self.LV,
|
||||
self.SIZE, sparse=sparse)
|
||||
self.disk.get_disk_size(self.TEMPLATE_PATH
|
||||
).AndReturn(self.TEMPLATE_SIZE)
|
||||
cmd = ('qemu-img', 'convert', '-O', 'raw', self.TEMPLATE_PATH,
|
||||
self.PATH)
|
||||
self.utils.execute(*cmd, run_as_root=True)
|
||||
self.disk.resize2fs(self.PATH, run_as_root=True)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
image.create_image(fn, self.TEMPLATE_PATH, self.SIZE)
|
||||
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_create_image(self):
|
||||
self._create_image(False)
|
||||
|
||||
def test_create_image_sparsed(self):
|
||||
self.flags(libvirt_sparse_logical_volumes=True)
|
||||
self._create_image(True)
|
||||
|
||||
def test_create_image_generated(self):
|
||||
self._create_image_generated(False)
|
||||
|
||||
def test_create_image_generated_sparsed(self):
|
||||
self.flags(libvirt_sparse_logical_volumes=True)
|
||||
self._create_image_generated(True)
|
||||
|
||||
def test_create_image_resize(self):
|
||||
self._create_image_resize(False)
|
||||
|
||||
def test_create_image_resize_sparsed(self):
|
||||
self.flags(libvirt_sparse_logical_volumes=True)
|
||||
self._create_image_resize(True)
|
||||
|
||||
def test_create_image_negative(self):
|
||||
fn = self.prepare_mocks()
|
||||
fn(target=self.TEMPLATE_PATH)
|
||||
self.libvirt_utils.create_lvm_image(self.VG,
|
||||
self.LV,
|
||||
self.SIZE,
|
||||
sparse=False
|
||||
).AndRaise(RuntimeError())
|
||||
self.disk.get_disk_size(self.TEMPLATE_PATH
|
||||
).AndReturn(self.TEMPLATE_SIZE)
|
||||
self.mox.StubOutWithMock(self.libvirt_utils, 'remove_logical_volumes')
|
||||
self.libvirt_utils.remove_logical_volumes(self.PATH)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
|
||||
self.assertRaises(RuntimeError, image.create_image, fn,
|
||||
self.TEMPLATE_PATH, self.SIZE)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_create_image_generated_negative(self):
|
||||
fn = self.prepare_mocks()
|
||||
fn(target=self.PATH,
|
||||
ephemeral_size=None).AndRaise(RuntimeError())
|
||||
self.libvirt_utils.create_lvm_image(self.VG,
|
||||
self.LV,
|
||||
self.SIZE,
|
||||
sparse=False)
|
||||
self.mox.StubOutWithMock(self.libvirt_utils, 'remove_logical_volumes')
|
||||
self.libvirt_utils.remove_logical_volumes(self.PATH)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
|
||||
self.assertRaises(RuntimeError, image.create_image, fn,
|
||||
self.TEMPLATE_PATH, self.SIZE,
|
||||
ephemeral_size=None)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_prealloc_image(self):
|
||||
CONF.set_override('preallocate_images', 'space')
|
||||
|
||||
fake_processutils.fake_execute_clear_log()
|
||||
fake_processutils.stub_out_processutils_execute(self.stubs)
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
|
||||
def fake_fetch(target, *args, **kwargs):
|
||||
return
|
||||
|
||||
self.stubs.Set(os.path, 'exists', lambda _: True)
|
||||
|
||||
image.cache(fake_fetch, self.TEMPLATE_PATH, self.SIZE)
|
||||
|
||||
self.assertEqual(fake_processutils.fake_execute_get_log(), [])
|
||||
|
||||
|
||||
class BackendTestCase(test.TestCase):
|
||||
INSTANCE = {'name': 'fake-instance',
|
||||
'uuid': uuidutils.generate_uuid()}
|
||||
NAME = 'fake-name.suffix'
|
||||
|
||||
def get_image(self, use_cow, image_type):
|
||||
return imagebackend.Backend(use_cow).image(self.INSTANCE,
|
||||
self.NAME,
|
||||
image_type)
|
||||
|
||||
def _test_image(self, image_type, image_not_cow, image_cow):
|
||||
image1 = self.get_image(False, image_type)
|
||||
image2 = self.get_image(True, image_type)
|
||||
|
||||
def assertIsInstance(instance, class_object):
|
||||
failure = ('Expected %s,' +
|
||||
' but got %s.') % (class_object.__name__,
|
||||
instance.__class__.__name__)
|
||||
self.assertTrue(isinstance(instance, class_object), failure)
|
||||
|
||||
assertIsInstance(image1, image_not_cow)
|
||||
assertIsInstance(image2, image_cow)
|
||||
|
||||
def test_image_raw(self):
|
||||
self._test_image('raw', imagebackend.Raw, imagebackend.Raw)
|
||||
|
||||
def test_image_qcow2(self):
|
||||
self._test_image('qcow2', imagebackend.Qcow2, imagebackend.Qcow2)
|
||||
|
||||
def test_image_lvm(self):
|
||||
self.flags(libvirt_images_volume_group='FakeVG')
|
||||
self._test_image('lvm', imagebackend.Lvm, imagebackend.Lvm)
|
||||
|
||||
def test_image_default(self):
|
||||
self._test_image('default', imagebackend.Raw, imagebackend.Qcow2)
|
|
@ -1,972 +0,0 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2012 Michael Still and Canonical Inc
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
import contextlib
|
||||
import cStringIO
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from nova.compute import vm_states
|
||||
from nova import conductor
|
||||
from nova import db
|
||||
from nova.openstack.common import importutils
|
||||
from nova.openstack.common import log as logging
|
||||
from nova import test
|
||||
from nova import utils
|
||||
from nova.virt.libvirt import imagecache
|
||||
from nova.virt.libvirt import utils as virtutils
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.import_opt('compute_manager', 'nova.service')
|
||||
CONF.import_opt('host', 'nova.netconf')
|
||||
|
||||
|
||||
class ImageCacheManagerTestCase(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ImageCacheManagerTestCase, self).setUp()
|
||||
self.stock_instance_names = set(['instance-00000001',
|
||||
'instance-00000002',
|
||||
'instance-00000003',
|
||||
'banana-42-hamster'])
|
||||
|
||||
def test_read_stored_checksum_missing(self):
|
||||
self.stubs.Set(os.path, 'exists', lambda x: False)
|
||||
csum = imagecache.read_stored_checksum('/tmp/foo', timestamped=False)
|
||||
self.assertEquals(csum, None)
|
||||
|
||||
def test_read_stored_checksum(self):
|
||||
with utils.tempdir() as tmpdir:
|
||||
self.flags(instances_path=tmpdir)
|
||||
self.flags(image_info_filename_pattern=('$instances_path/'
|
||||
'%(image)s.info'))
|
||||
|
||||
csum_input = '{"sha1": "fdghkfhkgjjksfdgjksjkghsdf"}\n'
|
||||
fname = os.path.join(tmpdir, 'aaa')
|
||||
info_fname = imagecache.get_info_filename(fname)
|
||||
f = open(info_fname, 'w')
|
||||
f.write(csum_input)
|
||||
f.close()
|
||||
|
||||
csum_output = imagecache.read_stored_checksum(fname,
|
||||
timestamped=False)
|
||||
self.assertEquals(csum_input.rstrip(),
|
||||
'{"sha1": "%s"}' % csum_output)
|
||||
|
||||
def test_read_stored_checksum_legacy_essex(self):
|
||||
with utils.tempdir() as tmpdir:
|
||||
self.flags(instances_path=tmpdir)
|
||||
self.flags(image_info_filename_pattern=('$instances_path/'
|
||||
'%(image)s.info'))
|
||||
|
||||
fname = os.path.join(tmpdir, 'aaa')
|
||||
old_fname = fname + '.sha1'
|
||||
f = open(old_fname, 'w')
|
||||
f.write('fdghkfhkgjjksfdgjksjkghsdf')
|
||||
f.close()
|
||||
|
||||
csum_output = imagecache.read_stored_checksum(fname,
|
||||
timestamped=False)
|
||||
self.assertEquals(csum_output, 'fdghkfhkgjjksfdgjksjkghsdf')
|
||||
self.assertFalse(os.path.exists(old_fname))
|
||||
info_fname = imagecache.get_info_filename(fname)
|
||||
self.assertTrue(os.path.exists(info_fname))
|
||||
|
||||
def test_list_base_images(self):
|
||||
listing = ['00000001',
|
||||
'ephemeral_0_20_None',
|
||||
'17d1b00b81642842e514494a78e804e9a511637c_5368709120.info',
|
||||
'00000004']
|
||||
images = ['e97222e91fc4241f49a7f520d1dcf446751129b3_sm',
|
||||
'e09c675c2d1cfac32dae3c2d83689c8c94bc693b_sm',
|
||||
'e97222e91fc4241f49a7f520d1dcf446751129b3',
|
||||
'17d1b00b81642842e514494a78e804e9a511637c',
|
||||
'17d1b00b81642842e514494a78e804e9a511637c_5368709120',
|
||||
'17d1b00b81642842e514494a78e804e9a511637c_10737418240']
|
||||
listing.extend(images)
|
||||
|
||||
self.stubs.Set(os, 'listdir', lambda x: listing)
|
||||
self.stubs.Set(os.path, 'isfile', lambda x: True)
|
||||
|
||||
base_dir = '/var/lib/nova/instances/_base'
|
||||
self.flags(instances_path='/var/lib/nova/instances')
|
||||
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
image_cache_manager._list_base_images(base_dir)
|
||||
|
||||
sanitized = []
|
||||
for ent in image_cache_manager.unexplained_images:
|
||||
sanitized.append(ent.replace(base_dir + '/', ''))
|
||||
|
||||
sanitized = sanitized.sort()
|
||||
images = images.sort()
|
||||
self.assertEquals(sanitized, images)
|
||||
|
||||
expected = os.path.join(base_dir,
|
||||
'e97222e91fc4241f49a7f520d1dcf446751129b3')
|
||||
self.assertTrue(expected in image_cache_manager.unexplained_images)
|
||||
|
||||
expected = os.path.join(base_dir,
|
||||
'17d1b00b81642842e514494a78e804e9a511637c_'
|
||||
'10737418240')
|
||||
self.assertTrue(expected in image_cache_manager.unexplained_images)
|
||||
|
||||
unexpected = os.path.join(base_dir, '00000004')
|
||||
self.assertFalse(unexpected in image_cache_manager.unexplained_images)
|
||||
|
||||
for ent in image_cache_manager.unexplained_images:
|
||||
self.assertTrue(ent.startswith(base_dir))
|
||||
|
||||
self.assertEquals(len(image_cache_manager.originals), 2)
|
||||
|
||||
expected = os.path.join(base_dir,
|
||||
'17d1b00b81642842e514494a78e804e9a511637c')
|
||||
self.assertTrue(expected in image_cache_manager.originals)
|
||||
|
||||
unexpected = os.path.join(base_dir,
|
||||
'17d1b00b81642842e514494a78e804e9a511637c_'
|
||||
'10737418240')
|
||||
self.assertFalse(unexpected in image_cache_manager.originals)
|
||||
|
||||
def test_list_running_instances(self):
|
||||
all_instances = [{'image_ref': '1',
|
||||
'host': CONF.host,
|
||||
'name': 'inst-1',
|
||||
'uuid': '123',
|
||||
'vm_state': '',
|
||||
'task_state': ''},
|
||||
{'image_ref': '2',
|
||||
'host': CONF.host,
|
||||
'name': 'inst-2',
|
||||
'uuid': '456',
|
||||
'vm_state': '',
|
||||
'task_state': ''},
|
||||
{'image_ref': '2',
|
||||
'kernel_id': '21',
|
||||
'ramdisk_id': '22',
|
||||
'host': 'remotehost',
|
||||
'name': 'inst-3',
|
||||
'uuid': '789',
|
||||
'vm_state': '',
|
||||
'task_state': ''}]
|
||||
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
|
||||
# The argument here should be a context, but it's mocked out
|
||||
image_cache_manager._list_running_instances(None, all_instances)
|
||||
|
||||
self.assertEqual(len(image_cache_manager.used_images), 4)
|
||||
self.assertTrue(image_cache_manager.used_images['1'] ==
|
||||
(1, 0, ['inst-1']))
|
||||
self.assertTrue(image_cache_manager.used_images['2'] ==
|
||||
(1, 1, ['inst-2', 'inst-3']))
|
||||
self.assertTrue(image_cache_manager.used_images['21'] ==
|
||||
(0, 1, ['inst-3']))
|
||||
self.assertTrue(image_cache_manager.used_images['22'] ==
|
||||
(0, 1, ['inst-3']))
|
||||
|
||||
self.assertTrue('inst-1' in image_cache_manager.instance_names)
|
||||
self.assertTrue('123' in image_cache_manager.instance_names)
|
||||
|
||||
self.assertEqual(len(image_cache_manager.image_popularity), 4)
|
||||
self.assertEqual(image_cache_manager.image_popularity['1'], 1)
|
||||
self.assertEqual(image_cache_manager.image_popularity['2'], 2)
|
||||
self.assertEqual(image_cache_manager.image_popularity['21'], 1)
|
||||
self.assertEqual(image_cache_manager.image_popularity['22'], 1)
|
||||
|
||||
def test_list_resizing_instances(self):
|
||||
all_instances = [{'image_ref': '1',
|
||||
'host': CONF.host,
|
||||
'name': 'inst-1',
|
||||
'uuid': '123',
|
||||
'vm_state': vm_states.RESIZED,
|
||||
'task_state': None}]
|
||||
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
image_cache_manager._list_running_instances(None, all_instances)
|
||||
|
||||
self.assertEqual(len(image_cache_manager.used_images), 1)
|
||||
self.assertTrue(image_cache_manager.used_images['1'] ==
|
||||
(1, 0, ['inst-1']))
|
||||
self.assertTrue(image_cache_manager.instance_names ==
|
||||
set(['inst-1', '123', 'inst-1_resize', '123_resize']))
|
||||
|
||||
self.assertEqual(len(image_cache_manager.image_popularity), 1)
|
||||
self.assertEqual(image_cache_manager.image_popularity['1'], 1)
|
||||
|
||||
def test_list_backing_images_small(self):
|
||||
self.stubs.Set(os, 'listdir',
|
||||
lambda x: ['_base', 'instance-00000001',
|
||||
'instance-00000002', 'instance-00000003'])
|
||||
self.stubs.Set(os.path, 'exists',
|
||||
lambda x: x.find('instance-') != -1)
|
||||
self.stubs.Set(virtutils, 'get_disk_backing_file',
|
||||
lambda x: 'e97222e91fc4241f49a7f520d1dcf446751129b3_sm')
|
||||
|
||||
found = os.path.join(CONF.instances_path, CONF.base_dir_name,
|
||||
'e97222e91fc4241f49a7f520d1dcf446751129b3_sm')
|
||||
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
image_cache_manager.unexplained_images = [found]
|
||||
image_cache_manager.instance_names = self.stock_instance_names
|
||||
|
||||
inuse_images = image_cache_manager._list_backing_images()
|
||||
|
||||
self.assertEquals(inuse_images, [found])
|
||||
self.assertEquals(len(image_cache_manager.unexplained_images), 0)
|
||||
|
||||
def test_list_backing_images_resized(self):
|
||||
self.stubs.Set(os, 'listdir',
|
||||
lambda x: ['_base', 'instance-00000001',
|
||||
'instance-00000002', 'instance-00000003'])
|
||||
self.stubs.Set(os.path, 'exists',
|
||||
lambda x: x.find('instance-') != -1)
|
||||
self.stubs.Set(virtutils, 'get_disk_backing_file',
|
||||
lambda x: ('e97222e91fc4241f49a7f520d1dcf446751129b3_'
|
||||
'10737418240'))
|
||||
|
||||
found = os.path.join(CONF.instances_path, CONF.base_dir_name,
|
||||
'e97222e91fc4241f49a7f520d1dcf446751129b3_'
|
||||
'10737418240')
|
||||
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
image_cache_manager.unexplained_images = [found]
|
||||
image_cache_manager.instance_names = self.stock_instance_names
|
||||
|
||||
inuse_images = image_cache_manager._list_backing_images()
|
||||
|
||||
self.assertEquals(inuse_images, [found])
|
||||
self.assertEquals(len(image_cache_manager.unexplained_images), 0)
|
||||
|
||||
def test_list_backing_images_instancename(self):
|
||||
self.stubs.Set(os, 'listdir',
|
||||
lambda x: ['_base', 'banana-42-hamster'])
|
||||
self.stubs.Set(os.path, 'exists',
|
||||
lambda x: x.find('banana-42-hamster') != -1)
|
||||
self.stubs.Set(virtutils, 'get_disk_backing_file',
|
||||
lambda x: 'e97222e91fc4241f49a7f520d1dcf446751129b3_sm')
|
||||
|
||||
found = os.path.join(CONF.instances_path, CONF.base_dir_name,
|
||||
'e97222e91fc4241f49a7f520d1dcf446751129b3_sm')
|
||||
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
image_cache_manager.unexplained_images = [found]
|
||||
image_cache_manager.instance_names = self.stock_instance_names
|
||||
|
||||
inuse_images = image_cache_manager._list_backing_images()
|
||||
|
||||
self.assertEquals(inuse_images, [found])
|
||||
self.assertEquals(len(image_cache_manager.unexplained_images), 0)
|
||||
|
||||
def test_find_base_file_nothing(self):
|
||||
self.stubs.Set(os.path, 'exists', lambda x: False)
|
||||
|
||||
base_dir = '/var/lib/nova/instances/_base'
|
||||
fingerprint = '549867354867'
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
res = list(image_cache_manager._find_base_file(base_dir, fingerprint))
|
||||
|
||||
self.assertEqual(0, len(res))
|
||||
|
||||
def test_find_base_file_small(self):
|
||||
fingerprint = '968dd6cc49e01aaa044ed11c0cce733e0fa44a6a'
|
||||
self.stubs.Set(os.path, 'exists',
|
||||
lambda x: x.endswith('%s_sm' % fingerprint))
|
||||
|
||||
base_dir = '/var/lib/nova/instances/_base'
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
res = list(image_cache_manager._find_base_file(base_dir, fingerprint))
|
||||
|
||||
base_file = os.path.join(base_dir, fingerprint + '_sm')
|
||||
self.assertTrue(res == [(base_file, True, False)])
|
||||
|
||||
def test_find_base_file_resized(self):
|
||||
fingerprint = '968dd6cc49e01aaa044ed11c0cce733e0fa44a6a'
|
||||
listing = ['00000001',
|
||||
'ephemeral_0_20_None',
|
||||
'968dd6cc49e01aaa044ed11c0cce733e0fa44a6a_10737418240',
|
||||
'00000004']
|
||||
|
||||
self.stubs.Set(os, 'listdir', lambda x: listing)
|
||||
self.stubs.Set(os.path, 'exists',
|
||||
lambda x: x.endswith('%s_10737418240' % fingerprint))
|
||||
self.stubs.Set(os.path, 'isfile', lambda x: True)
|
||||
|
||||
base_dir = '/var/lib/nova/instances/_base'
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
image_cache_manager._list_base_images(base_dir)
|
||||
res = list(image_cache_manager._find_base_file(base_dir, fingerprint))
|
||||
|
||||
base_file = os.path.join(base_dir, fingerprint + '_10737418240')
|
||||
self.assertTrue(res == [(base_file, False, True)])
|
||||
|
||||
def test_find_base_file_all(self):
|
||||
fingerprint = '968dd6cc49e01aaa044ed11c0cce733e0fa44a6a'
|
||||
listing = ['00000001',
|
||||
'ephemeral_0_20_None',
|
||||
'968dd6cc49e01aaa044ed11c0cce733e0fa44a6a_sm',
|
||||
'968dd6cc49e01aaa044ed11c0cce733e0fa44a6a_10737418240',
|
||||
'00000004']
|
||||
|
||||
self.stubs.Set(os, 'listdir', lambda x: listing)
|
||||
self.stubs.Set(os.path, 'exists', lambda x: True)
|
||||
self.stubs.Set(os.path, 'isfile', lambda x: True)
|
||||
|
||||
base_dir = '/var/lib/nova/instances/_base'
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
image_cache_manager._list_base_images(base_dir)
|
||||
res = list(image_cache_manager._find_base_file(base_dir, fingerprint))
|
||||
|
||||
base_file1 = os.path.join(base_dir, fingerprint)
|
||||
base_file2 = os.path.join(base_dir, fingerprint + '_sm')
|
||||
base_file3 = os.path.join(base_dir, fingerprint + '_10737418240')
|
||||
self.assertTrue(res == [(base_file1, False, False),
|
||||
(base_file2, True, False),
|
||||
(base_file3, False, True)])
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _intercept_log_messages(self):
|
||||
try:
|
||||
mylog = logging.getLogger('nova')
|
||||
stream = cStringIO.StringIO()
|
||||
handler = logging.logging.StreamHandler(stream)
|
||||
handler.setFormatter(logging.ContextFormatter())
|
||||
mylog.logger.addHandler(handler)
|
||||
yield stream
|
||||
finally:
|
||||
mylog.logger.removeHandler(handler)
|
||||
|
||||
def _make_checksum(self, tmpdir):
|
||||
testdata = ('OpenStack Software delivers a massively scalable cloud '
|
||||
'operating system.')
|
||||
|
||||
fname = os.path.join(tmpdir, 'aaa')
|
||||
info_fname = imagecache.get_info_filename(fname)
|
||||
|
||||
with open(fname, 'w') as f:
|
||||
f.write(testdata)
|
||||
|
||||
return fname, info_fname, testdata
|
||||
|
||||
def test_verify_checksum(self):
|
||||
img = {'container_format': 'ami', 'id': '42'}
|
||||
|
||||
self.flags(checksum_base_images=True)
|
||||
|
||||
with self._intercept_log_messages() as stream:
|
||||
with utils.tempdir() as tmpdir:
|
||||
self.flags(instances_path=tmpdir)
|
||||
self.flags(image_info_filename_pattern=('$instances_path/'
|
||||
'%(image)s.info'))
|
||||
fname, info_fname, testdata = self._make_checksum(tmpdir)
|
||||
|
||||
# Checksum is valid
|
||||
f = open(info_fname, 'w')
|
||||
csum = hashlib.sha1()
|
||||
csum.update(testdata)
|
||||
f.write('{"sha1": "%s"}\n' % csum.hexdigest())
|
||||
f.close()
|
||||
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
res = image_cache_manager._verify_checksum(img, fname)
|
||||
self.assertTrue(res)
|
||||
|
||||
def test_verify_checksum_disabled(self):
|
||||
img = {'container_format': 'ami', 'id': '42'}
|
||||
|
||||
self.flags(checksum_base_images=False)
|
||||
|
||||
with self._intercept_log_messages() as stream:
|
||||
with utils.tempdir() as tmpdir:
|
||||
self.flags(instances_path=tmpdir)
|
||||
self.flags(image_info_filename_pattern=('$instances_path/'
|
||||
'%(image)s.info'))
|
||||
fname, info_fname, testdata = self._make_checksum(tmpdir)
|
||||
|
||||
# Checksum is valid
|
||||
f = open(info_fname, 'w')
|
||||
csum = hashlib.sha1()
|
||||
csum.update(testdata)
|
||||
f.write('{"sha1": "%s"}\n' % csum.hexdigest())
|
||||
f.close()
|
||||
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
res = image_cache_manager._verify_checksum(img, fname)
|
||||
self.assertTrue(res is None)
|
||||
|
||||
def test_verify_checksum_invalid_json(self):
|
||||
img = {'container_format': 'ami', 'id': '42'}
|
||||
|
||||
self.flags(checksum_base_images=True)
|
||||
|
||||
with self._intercept_log_messages() as stream:
|
||||
with utils.tempdir() as tmpdir:
|
||||
self.flags(instances_path=tmpdir)
|
||||
self.flags(image_info_filename_pattern=('$instances_path/'
|
||||
'%(image)s.info'))
|
||||
|
||||
fname, info_fname, testdata = self._make_checksum(tmpdir)
|
||||
|
||||
# Checksum is invalid, and not json
|
||||
f = open(info_fname, 'w')
|
||||
f.write('banana')
|
||||
f.close()
|
||||
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
res = image_cache_manager._verify_checksum(
|
||||
img, fname, create_if_missing=False)
|
||||
self.assertFalse(res)
|
||||
log = stream.getvalue()
|
||||
|
||||
# NOTE(mikal): this is a skip not a fail because the file is
|
||||
# present, but is not in valid json format and therefore is
|
||||
# skipped.
|
||||
self.assertNotEqual(log.find('image verification skipped'), -1)
|
||||
|
||||
def test_verify_checksum_invalid_repaired(self):
|
||||
img = {'container_format': 'ami', 'id': '42'}
|
||||
|
||||
self.flags(checksum_base_images=True)
|
||||
|
||||
with utils.tempdir() as tmpdir:
|
||||
self.flags(instances_path=tmpdir)
|
||||
self.flags(image_info_filename_pattern=('$instances_path/'
|
||||
'%(image)s.info'))
|
||||
|
||||
fname, info_fname, testdata = self._make_checksum(tmpdir)
|
||||
|
||||
# Checksum is invalid, and not json
|
||||
f = open(info_fname, 'w')
|
||||
f.write('banana')
|
||||
f.close()
|
||||
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
res = image_cache_manager._verify_checksum(
|
||||
img, fname, create_if_missing=True)
|
||||
self.assertTrue(res is None)
|
||||
|
||||
def test_verify_checksum_invalid(self):
|
||||
img = {'container_format': 'ami', 'id': '42'}
|
||||
|
||||
self.flags(checksum_base_images=True)
|
||||
|
||||
with self._intercept_log_messages() as stream:
|
||||
with utils.tempdir() as tmpdir:
|
||||
self.flags(instances_path=tmpdir)
|
||||
self.flags(image_info_filename_pattern=('$instances_path/'
|
||||
'%(image)s.info'))
|
||||
|
||||
fname, info_fname, testdata = self._make_checksum(tmpdir)
|
||||
|
||||
# Checksum is invalid, but is in valid json
|
||||
f = open(info_fname, 'w')
|
||||
f.write('{"sha1": "banana"}')
|
||||
f.close()
|
||||
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
res = image_cache_manager._verify_checksum(img, fname)
|
||||
self.assertFalse(res)
|
||||
log = stream.getvalue()
|
||||
|
||||
self.assertNotEqual(log.find('image verification failed'), -1)
|
||||
|
||||
def test_verify_checksum_file_missing(self):
|
||||
self.flags(checksum_base_images=True)
|
||||
|
||||
with utils.tempdir() as tmpdir:
|
||||
self.flags(instances_path=tmpdir)
|
||||
self.flags(image_info_filename_pattern=('$instances_path/'
|
||||
'%(image)s.info'))
|
||||
|
||||
fname, info_fname, testdata = self._make_checksum(tmpdir)
|
||||
|
||||
# Checksum file missing
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
res = image_cache_manager._verify_checksum('aaa', fname)
|
||||
self.assertEquals(res, None)
|
||||
|
||||
# Checksum requests for a file with no checksum now have the
|
||||
# side effect of creating the checksum
|
||||
self.assertTrue(os.path.exists(info_fname))
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _make_base_file(self, checksum=True):
|
||||
"""Make a base file for testing."""
|
||||
|
||||
with utils.tempdir() as tmpdir:
|
||||
self.flags(instances_path=tmpdir)
|
||||
self.flags(image_info_filename_pattern=('$instances_path/'
|
||||
'%(image)s.info'))
|
||||
fname = os.path.join(tmpdir, 'aaa')
|
||||
|
||||
base_file = open(fname, 'w')
|
||||
base_file.write('data')
|
||||
base_file.close()
|
||||
base_file = open(fname, 'r')
|
||||
|
||||
if checksum:
|
||||
imagecache.write_stored_checksum(fname)
|
||||
|
||||
base_file.close()
|
||||
yield fname
|
||||
|
||||
def test_remove_base_file(self):
|
||||
with self._make_base_file() as fname:
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
image_cache_manager._remove_base_file(fname)
|
||||
info_fname = imagecache.get_info_filename(fname)
|
||||
|
||||
# Files are initially too new to delete
|
||||
self.assertTrue(os.path.exists(fname))
|
||||
self.assertTrue(os.path.exists(info_fname))
|
||||
|
||||
# Old files get cleaned up though
|
||||
os.utime(fname, (-1, time.time() - 3601))
|
||||
image_cache_manager._remove_base_file(fname)
|
||||
|
||||
self.assertFalse(os.path.exists(fname))
|
||||
self.assertFalse(os.path.exists(info_fname))
|
||||
|
||||
def test_remove_base_file_original(self):
|
||||
with self._make_base_file() as fname:
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
image_cache_manager.originals = [fname]
|
||||
image_cache_manager._remove_base_file(fname)
|
||||
info_fname = imagecache.get_info_filename(fname)
|
||||
|
||||
# Files are initially too new to delete
|
||||
self.assertTrue(os.path.exists(fname))
|
||||
self.assertTrue(os.path.exists(info_fname))
|
||||
|
||||
# This file should stay longer than a resized image
|
||||
os.utime(fname, (-1, time.time() - 3601))
|
||||
image_cache_manager._remove_base_file(fname)
|
||||
|
||||
self.assertTrue(os.path.exists(fname))
|
||||
self.assertTrue(os.path.exists(info_fname))
|
||||
|
||||
# Originals don't stay forever though
|
||||
os.utime(fname, (-1, time.time() - 3600 * 25))
|
||||
image_cache_manager._remove_base_file(fname)
|
||||
|
||||
self.assertFalse(os.path.exists(fname))
|
||||
self.assertFalse(os.path.exists(info_fname))
|
||||
|
||||
def test_remove_base_file_dne(self):
|
||||
# This test is solely to execute the "does not exist" code path. We
|
||||
# don't expect the method being tested to do anything in this case.
|
||||
with utils.tempdir() as tmpdir:
|
||||
self.flags(instances_path=tmpdir)
|
||||
self.flags(image_info_filename_pattern=('$instances_path/'
|
||||
'%(image)s.info'))
|
||||
|
||||
fname = os.path.join(tmpdir, 'aaa')
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
image_cache_manager._remove_base_file(fname)
|
||||
|
||||
def test_remove_base_file_oserror(self):
|
||||
with self._intercept_log_messages() as stream:
|
||||
with utils.tempdir() as tmpdir:
|
||||
self.flags(instances_path=tmpdir)
|
||||
self.flags(image_info_filename_pattern=('$instances_path/'
|
||||
'%(image)s.info'))
|
||||
|
||||
fname = os.path.join(tmpdir, 'aaa')
|
||||
|
||||
os.mkdir(fname)
|
||||
os.utime(fname, (-1, time.time() - 3601))
|
||||
|
||||
# This will raise an OSError because of file permissions
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
image_cache_manager._remove_base_file(fname)
|
||||
|
||||
self.assertTrue(os.path.exists(fname))
|
||||
self.assertNotEqual(stream.getvalue().find('Failed to remove'),
|
||||
-1)
|
||||
|
||||
def test_handle_base_image_unused(self):
|
||||
img = '123'
|
||||
|
||||
with self._make_base_file() as fname:
|
||||
os.utime(fname, (-1, time.time() - 3601))
|
||||
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
image_cache_manager.unexplained_images = [fname]
|
||||
image_cache_manager._handle_base_image(img, fname)
|
||||
|
||||
self.assertEquals(image_cache_manager.unexplained_images, [])
|
||||
self.assertEquals(image_cache_manager.removable_base_files,
|
||||
[fname])
|
||||
self.assertEquals(image_cache_manager.corrupt_base_files, [])
|
||||
|
||||
def test_handle_base_image_used(self):
|
||||
self.stubs.Set(virtutils, 'chown', lambda x, y: None)
|
||||
img = '123'
|
||||
|
||||
with self._make_base_file() as fname:
|
||||
os.utime(fname, (-1, time.time() - 3601))
|
||||
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
image_cache_manager.unexplained_images = [fname]
|
||||
image_cache_manager.used_images = {'123': (1, 0, ['banana-42'])}
|
||||
image_cache_manager._handle_base_image(img, fname)
|
||||
|
||||
self.assertEquals(image_cache_manager.unexplained_images, [])
|
||||
self.assertEquals(image_cache_manager.removable_base_files, [])
|
||||
self.assertEquals(image_cache_manager.corrupt_base_files, [])
|
||||
|
||||
def test_handle_base_image_used_remotely(self):
|
||||
self.stubs.Set(virtutils, 'chown', lambda x, y: None)
|
||||
img = '123'
|
||||
|
||||
with self._make_base_file() as fname:
|
||||
os.utime(fname, (-1, time.time() - 3601))
|
||||
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
image_cache_manager.unexplained_images = [fname]
|
||||
image_cache_manager.used_images = {'123': (0, 1, ['banana-42'])}
|
||||
image_cache_manager._handle_base_image(img, fname)
|
||||
|
||||
self.assertEquals(image_cache_manager.unexplained_images, [])
|
||||
self.assertEquals(image_cache_manager.removable_base_files, [])
|
||||
self.assertEquals(image_cache_manager.corrupt_base_files, [])
|
||||
|
||||
def test_handle_base_image_absent(self):
|
||||
img = '123'
|
||||
|
||||
with self._intercept_log_messages() as stream:
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
image_cache_manager.used_images = {'123': (1, 0, ['banana-42'])}
|
||||
image_cache_manager._handle_base_image(img, None)
|
||||
|
||||
self.assertEquals(image_cache_manager.unexplained_images, [])
|
||||
self.assertEquals(image_cache_manager.removable_base_files, [])
|
||||
self.assertEquals(image_cache_manager.corrupt_base_files, [])
|
||||
self.assertNotEqual(stream.getvalue().find('an absent base file'),
|
||||
-1)
|
||||
|
||||
def test_handle_base_image_used_missing(self):
|
||||
img = '123'
|
||||
|
||||
with utils.tempdir() as tmpdir:
|
||||
self.flags(instances_path=tmpdir)
|
||||
self.flags(image_info_filename_pattern=('$instances_path/'
|
||||
'%(image)s.info'))
|
||||
|
||||
fname = os.path.join(tmpdir, 'aaa')
|
||||
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
image_cache_manager.unexplained_images = [fname]
|
||||
image_cache_manager.used_images = {'123': (1, 0, ['banana-42'])}
|
||||
image_cache_manager._handle_base_image(img, fname)
|
||||
|
||||
self.assertEquals(image_cache_manager.unexplained_images, [])
|
||||
self.assertEquals(image_cache_manager.removable_base_files, [])
|
||||
self.assertEquals(image_cache_manager.corrupt_base_files, [])
|
||||
|
||||
def test_handle_base_image_checksum_fails(self):
|
||||
self.flags(checksum_base_images=True)
|
||||
self.stubs.Set(virtutils, 'chown', lambda x, y: None)
|
||||
|
||||
img = '123'
|
||||
|
||||
with self._make_base_file() as fname:
|
||||
with open(fname, 'w') as f:
|
||||
f.write('banana')
|
||||
|
||||
d = {'sha1': '21323454'}
|
||||
with open('%s.info' % fname, 'w') as f:
|
||||
f.write(json.dumps(d))
|
||||
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
image_cache_manager.unexplained_images = [fname]
|
||||
image_cache_manager.used_images = {'123': (1, 0, ['banana-42'])}
|
||||
image_cache_manager._handle_base_image(img, fname)
|
||||
|
||||
self.assertEquals(image_cache_manager.unexplained_images, [])
|
||||
self.assertEquals(image_cache_manager.removable_base_files, [])
|
||||
self.assertEquals(image_cache_manager.corrupt_base_files,
|
||||
[fname])
|
||||
|
||||
def test_verify_base_images(self):
|
||||
hashed_1 = '356a192b7913b04c54574d18c28d46e6395428ab'
|
||||
hashed_21 = '472b07b9fcf2c2451e8781e944bf5f77cd8457c8'
|
||||
hashed_22 = '12c6fc06c99a462375eeb3f43dfd832b08ca9e17'
|
||||
hashed_42 = '92cfceb39d57d914ed8b14d0e37643de0797ae56'
|
||||
|
||||
self.flags(instances_path='/instance_path')
|
||||
self.flags(base_dir_name='_base')
|
||||
self.flags(remove_unused_base_images=True)
|
||||
|
||||
base_file_list = ['00000001',
|
||||
'ephemeral_0_20_None',
|
||||
'e97222e91fc4241f49a7f520d1dcf446751129b3_sm',
|
||||
'e09c675c2d1cfac32dae3c2d83689c8c94bc693b_sm',
|
||||
hashed_42,
|
||||
hashed_1,
|
||||
hashed_21,
|
||||
hashed_22,
|
||||
'%s_5368709120' % hashed_1,
|
||||
'%s_10737418240' % hashed_1,
|
||||
'00000004']
|
||||
|
||||
def fq_path(path):
|
||||
return os.path.join('/instance_path/_base/', path)
|
||||
|
||||
# Fake base directory existence
|
||||
orig_exists = os.path.exists
|
||||
|
||||
def exists(path):
|
||||
# The python coverage tool got angry with my overly broad mocks
|
||||
if not path.startswith('/instance_path'):
|
||||
return orig_exists(path)
|
||||
|
||||
if path in ['/instance_path',
|
||||
'/instance_path/_base',
|
||||
'/instance_path/instance-1/disk',
|
||||
'/instance_path/instance-2/disk',
|
||||
'/instance_path/instance-3/disk',
|
||||
'/instance_path/_base/%s.info' % hashed_42]:
|
||||
return True
|
||||
|
||||
for p in base_file_list:
|
||||
if path == fq_path(p):
|
||||
return True
|
||||
if path == fq_path(p) + '.info':
|
||||
return False
|
||||
|
||||
if path in ['/instance_path/_base/%s_sm' % i for i in [hashed_1,
|
||||
hashed_21,
|
||||
hashed_22,
|
||||
hashed_42]]:
|
||||
return False
|
||||
|
||||
self.fail('Unexpected path existence check: %s' % path)
|
||||
|
||||
self.stubs.Set(os.path, 'exists', lambda x: exists(x))
|
||||
|
||||
self.stubs.Set(virtutils, 'chown', lambda x, y: None)
|
||||
|
||||
# We need to stub utime as well
|
||||
orig_utime = os.utime
|
||||
self.stubs.Set(os, 'utime', lambda x, y: None)
|
||||
|
||||
# Fake up some instances in the instances directory
|
||||
orig_listdir = os.listdir
|
||||
|
||||
def listdir(path):
|
||||
# The python coverage tool got angry with my overly broad mocks
|
||||
if not path.startswith('/instance_path'):
|
||||
return orig_listdir(path)
|
||||
|
||||
if path == '/instance_path':
|
||||
return ['instance-1', 'instance-2', 'instance-3', '_base']
|
||||
|
||||
if path == '/instance_path/_base':
|
||||
return base_file_list
|
||||
|
||||
self.fail('Unexpected directory listed: %s' % path)
|
||||
|
||||
self.stubs.Set(os, 'listdir', lambda x: listdir(x))
|
||||
|
||||
# Fake isfile for these faked images in _base
|
||||
orig_isfile = os.path.isfile
|
||||
|
||||
def isfile(path):
|
||||
# The python coverage tool got angry with my overly broad mocks
|
||||
if not path.startswith('/instance_path'):
|
||||
return orig_isfile(path)
|
||||
|
||||
for p in base_file_list:
|
||||
if path == fq_path(p):
|
||||
return True
|
||||
|
||||
self.fail('Unexpected isfile call: %s' % path)
|
||||
|
||||
self.stubs.Set(os.path, 'isfile', lambda x: isfile(x))
|
||||
|
||||
# Fake the database call which lists running instances
|
||||
all_instances = [{'image_ref': '1',
|
||||
'host': CONF.host,
|
||||
'name': 'instance-1',
|
||||
'uuid': '123',
|
||||
'vm_state': '',
|
||||
'task_state': ''},
|
||||
{'image_ref': '1',
|
||||
'kernel_id': '21',
|
||||
'ramdisk_id': '22',
|
||||
'host': CONF.host,
|
||||
'name': 'instance-2',
|
||||
'uuid': '456',
|
||||
'vm_state': '',
|
||||
'task_state': ''}]
|
||||
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
|
||||
# Fake the utils call which finds the backing image
|
||||
def get_disk_backing_file(path):
|
||||
if path in ['/instance_path/instance-1/disk',
|
||||
'/instance_path/instance-2/disk']:
|
||||
return fq_path('%s_5368709120' % hashed_1)
|
||||
self.fail('Unexpected backing file lookup: %s' % path)
|
||||
|
||||
self.stubs.Set(virtutils, 'get_disk_backing_file',
|
||||
lambda x: get_disk_backing_file(x))
|
||||
|
||||
# Fake out verifying checksums, as that is tested elsewhere
|
||||
self.stubs.Set(image_cache_manager, '_verify_checksum',
|
||||
lambda x, y: y == hashed_42)
|
||||
|
||||
# Fake getmtime as well
|
||||
orig_getmtime = os.path.getmtime
|
||||
|
||||
def getmtime(path):
|
||||
if not path.startswith('/instance_path'):
|
||||
return orig_getmtime(path)
|
||||
|
||||
return 1000000
|
||||
|
||||
self.stubs.Set(os.path, 'getmtime', lambda x: getmtime(x))
|
||||
|
||||
# Make sure we don't accidentally remove a real file
|
||||
orig_remove = os.remove
|
||||
|
||||
def remove(path):
|
||||
if not path.startswith('/instance_path'):
|
||||
return orig_remove(path)
|
||||
|
||||
# Don't try to remove fake files
|
||||
return
|
||||
|
||||
self.stubs.Set(os, 'remove', lambda x: remove(x))
|
||||
|
||||
# And finally we can make the call we're actually testing...
|
||||
# The argument here should be a context, but it is mocked out
|
||||
image_cache_manager.verify_base_images(None, all_instances)
|
||||
|
||||
# Verify
|
||||
active = [fq_path(hashed_1), fq_path('%s_5368709120' % hashed_1),
|
||||
fq_path(hashed_21), fq_path(hashed_22)]
|
||||
self.assertEquals(image_cache_manager.active_base_files, active)
|
||||
|
||||
for rem in [fq_path('e97222e91fc4241f49a7f520d1dcf446751129b3_sm'),
|
||||
fq_path('e09c675c2d1cfac32dae3c2d83689c8c94bc693b_sm'),
|
||||
fq_path(hashed_42),
|
||||
fq_path('%s_10737418240' % hashed_1)]:
|
||||
self.assertTrue(rem in image_cache_manager.removable_base_files)
|
||||
|
||||
# Ensure there are no "corrupt" images as well
|
||||
self.assertTrue(len(image_cache_manager.corrupt_base_files), 0)
|
||||
|
||||
def test_verify_base_images_no_base(self):
|
||||
self.flags(instances_path='/tmp/no/such/dir/name/please')
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
image_cache_manager.verify_base_images(None, [])
|
||||
|
||||
def test_is_valid_info_file(self):
|
||||
hashed = 'e97222e91fc4241f49a7f520d1dcf446751129b3'
|
||||
|
||||
self.flags(instances_path='/tmp/no/such/dir/name/please')
|
||||
self.flags(image_info_filename_pattern=('$instances_path/_base/'
|
||||
'%(image)s.info'))
|
||||
base_filename = os.path.join(CONF.instances_path, '_base', hashed)
|
||||
|
||||
is_valid_info_file = imagecache.is_valid_info_file
|
||||
self.assertFalse(is_valid_info_file('banana'))
|
||||
self.assertFalse(is_valid_info_file(
|
||||
os.path.join(CONF.instances_path, '_base', '00000001')))
|
||||
self.assertFalse(is_valid_info_file(base_filename))
|
||||
self.assertFalse(is_valid_info_file(base_filename + '.sha1'))
|
||||
self.assertTrue(is_valid_info_file(base_filename + '.info'))
|
||||
|
||||
def test_configured_checksum_path(self):
|
||||
with utils.tempdir() as tmpdir:
|
||||
self.flags(instances_path=tmpdir)
|
||||
self.flags(image_info_filename_pattern=('$instances_path/'
|
||||
'%(image)s.info'))
|
||||
self.flags(remove_unused_base_images=True)
|
||||
|
||||
# Ensure there is a base directory
|
||||
os.mkdir(os.path.join(tmpdir, '_base'))
|
||||
|
||||
# Fake the database call which lists running instances
|
||||
all_instances = [{'image_ref': '1',
|
||||
'host': CONF.host,
|
||||
'name': 'instance-1',
|
||||
'uuid': '123',
|
||||
'vm_state': '',
|
||||
'task_state': ''},
|
||||
{'image_ref': '1',
|
||||
'host': CONF.host,
|
||||
'name': 'instance-2',
|
||||
'uuid': '456',
|
||||
'vm_state': '',
|
||||
'task_state': ''}]
|
||||
|
||||
def touch(filename):
|
||||
f = open(filename, 'w')
|
||||
f.write('Touched')
|
||||
f.close()
|
||||
|
||||
old = time.time() - (25 * 3600)
|
||||
hashed = 'e97222e91fc4241f49a7f520d1dcf446751129b3'
|
||||
base_filename = os.path.join(tmpdir, hashed)
|
||||
touch(base_filename)
|
||||
touch(base_filename + '.info')
|
||||
os.utime(base_filename + '.info', (old, old))
|
||||
touch(base_filename + '.info')
|
||||
os.utime(base_filename + '.info', (old, old))
|
||||
|
||||
image_cache_manager = imagecache.ImageCacheManager()
|
||||
image_cache_manager.verify_base_images(None, all_instances)
|
||||
|
||||
self.assertTrue(os.path.exists(base_filename))
|
||||
self.assertTrue(os.path.exists(base_filename + '.info'))
|
||||
|
||||
def test_compute_manager(self):
|
||||
was = {'called': False}
|
||||
|
||||
def fake_get_all_by_filters(context, *args, **kwargs):
|
||||
was['called'] = True
|
||||
return [{'image_ref': '1',
|
||||
'host': CONF.host,
|
||||
'name': 'instance-1',
|
||||
'uuid': '123',
|
||||
'vm_state': '',
|
||||
'task_state': ''},
|
||||
{'image_ref': '1',
|
||||
'host': CONF.host,
|
||||
'name': 'instance-2',
|
||||
'uuid': '456',
|
||||
'vm_state': '',
|
||||
'task_state': ''}]
|
||||
|
||||
with utils.tempdir() as tmpdir:
|
||||
self.flags(instances_path=tmpdir)
|
||||
|
||||
self.stubs.Set(db, 'instance_get_all_by_filters',
|
||||
fake_get_all_by_filters)
|
||||
compute = importutils.import_object(CONF.compute_manager)
|
||||
self.flags(use_local=True, group='conductor')
|
||||
compute.conductor_api = conductor.API()
|
||||
compute._run_image_cache_manager_pass(None)
|
||||
self.assertTrue(was['called'])
|
File diff suppressed because it is too large
Load Diff
|
@ -1,446 +0,0 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2010 OpenStack Foundation
|
||||
# Copyright 2012 University Of Minho
|
||||
#
|
||||
# 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.
|
||||
|
||||
from nova import block_device
|
||||
from nova.compute import flavors
|
||||
from nova import context
|
||||
from nova import db
|
||||
from nova import exception
|
||||
from nova import test
|
||||
import nova.tests.image.fake
|
||||
from nova.virt.libvirt import blockinfo
|
||||
|
||||
|
||||
class LibvirtBlockInfoTest(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(LibvirtBlockInfoTest, self).setUp()
|
||||
|
||||
self.user_id = 'fake'
|
||||
self.project_id = 'fake'
|
||||
self.context = context.get_admin_context()
|
||||
instance_type = db.instance_type_get(self.context, 2)
|
||||
sys_meta = flavors.save_instance_type_info({}, instance_type)
|
||||
nova.tests.image.fake.stub_out_image_service(self.stubs)
|
||||
self.test_instance = {
|
||||
'uuid': '32dfcb37-5af1-552b-357c-be8c3aa38310',
|
||||
'memory_kb': '1024000',
|
||||
'basepath': '/some/path',
|
||||
'bridge_name': 'br100',
|
||||
'vcpus': 2,
|
||||
'project_id': 'fake',
|
||||
'bridge': 'br101',
|
||||
'image_ref': '155d900f-4e14-4e4c-a73d-069cbf4541e6',
|
||||
'root_gb': 10,
|
||||
'ephemeral_gb': 20,
|
||||
'instance_type_id': 2, # m1.tiny
|
||||
'system_metadata': sys_meta}
|
||||
|
||||
def test_volume_in_mapping(self):
|
||||
swap = {'device_name': '/dev/sdb',
|
||||
'swap_size': 1}
|
||||
ephemerals = [{'num': 0,
|
||||
'virtual_name': 'ephemeral0',
|
||||
'device_name': '/dev/sdc1',
|
||||
'size': 1},
|
||||
{'num': 2,
|
||||
'virtual_name': 'ephemeral2',
|
||||
'device_name': '/dev/sdd',
|
||||
'size': 1}]
|
||||
block_device_mapping = [{'mount_device': '/dev/sde',
|
||||
'device_path': 'fake_device'},
|
||||
{'mount_device': '/dev/sdf',
|
||||
'device_path': 'fake_device'}]
|
||||
block_device_info = {
|
||||
'root_device_name': '/dev/sda',
|
||||
'swap': swap,
|
||||
'ephemerals': ephemerals,
|
||||
'block_device_mapping': block_device_mapping}
|
||||
|
||||
def _assert_volume_in_mapping(device_name, true_or_false):
|
||||
self.assertEquals(
|
||||
block_device.volume_in_mapping(device_name,
|
||||
block_device_info),
|
||||
true_or_false)
|
||||
|
||||
_assert_volume_in_mapping('sda', False)
|
||||
_assert_volume_in_mapping('sdb', True)
|
||||
_assert_volume_in_mapping('sdc1', True)
|
||||
_assert_volume_in_mapping('sdd', True)
|
||||
_assert_volume_in_mapping('sde', True)
|
||||
_assert_volume_in_mapping('sdf', True)
|
||||
_assert_volume_in_mapping('sdg', False)
|
||||
_assert_volume_in_mapping('sdh1', False)
|
||||
|
||||
def test_find_disk_dev(self):
|
||||
mapping = {
|
||||
"disk.local": {
|
||||
'dev': 'sda',
|
||||
'bus': 'scsi',
|
||||
'type': 'disk',
|
||||
},
|
||||
"disk.swap": {
|
||||
'dev': 'sdc',
|
||||
'bus': 'scsi',
|
||||
'type': 'disk',
|
||||
},
|
||||
}
|
||||
|
||||
dev = blockinfo.find_disk_dev_for_disk_bus(mapping, 'scsi')
|
||||
self.assertEqual(dev, 'sdb')
|
||||
|
||||
dev = blockinfo.find_disk_dev_for_disk_bus(mapping, 'scsi',
|
||||
last_device=True)
|
||||
self.assertEqual(dev, 'sdz')
|
||||
|
||||
dev = blockinfo.find_disk_dev_for_disk_bus(mapping, 'virtio')
|
||||
self.assertEqual(dev, 'vda')
|
||||
|
||||
def test_get_next_disk_dev(self):
|
||||
mapping = {}
|
||||
mapping['disk.local'] = blockinfo.get_next_disk_info(mapping,
|
||||
'virtio')
|
||||
self.assertEqual(mapping['disk.local'],
|
||||
{'dev': 'vda', 'bus': 'virtio', 'type': 'disk'})
|
||||
|
||||
mapping['disk.swap'] = blockinfo.get_next_disk_info(mapping,
|
||||
'virtio')
|
||||
self.assertEqual(mapping['disk.swap'],
|
||||
{'dev': 'vdb', 'bus': 'virtio', 'type': 'disk'})
|
||||
|
||||
mapping['disk.config'] = blockinfo.get_next_disk_info(mapping,
|
||||
'ide',
|
||||
'cdrom',
|
||||
True)
|
||||
self.assertEqual(mapping['disk.config'],
|
||||
{'dev': 'hdd', 'bus': 'ide', 'type': 'cdrom'})
|
||||
|
||||
def test_get_disk_mapping_simple(self):
|
||||
# The simplest possible disk mapping setup, all defaults
|
||||
|
||||
user_context = context.RequestContext(self.user_id, self.project_id)
|
||||
instance_ref = db.instance_create(user_context, self.test_instance)
|
||||
|
||||
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
|
||||
"virtio", "ide")
|
||||
|
||||
expect = {
|
||||
'disk': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'},
|
||||
'disk.local': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
|
||||
'root': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'}
|
||||
}
|
||||
self.assertEqual(mapping, expect)
|
||||
|
||||
def test_get_disk_mapping_simple_rootdev(self):
|
||||
# A simple disk mapping setup, but with custom root device name
|
||||
|
||||
user_context = context.RequestContext(self.user_id, self.project_id)
|
||||
instance_ref = db.instance_create(user_context, self.test_instance)
|
||||
block_device_info = {
|
||||
'root_device_name': '/dev/sda'
|
||||
}
|
||||
|
||||
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
|
||||
"virtio", "ide",
|
||||
block_device_info)
|
||||
|
||||
expect = {
|
||||
'disk': {'bus': 'scsi', 'dev': 'sda', 'type': 'disk'},
|
||||
'disk.local': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'},
|
||||
'root': {'bus': 'scsi', 'dev': 'sda', 'type': 'disk'}
|
||||
}
|
||||
self.assertEqual(mapping, expect)
|
||||
|
||||
def test_get_disk_mapping_rescue(self):
|
||||
# A simple disk mapping setup, but in rescue mode
|
||||
|
||||
user_context = context.RequestContext(self.user_id, self.project_id)
|
||||
instance_ref = db.instance_create(user_context, self.test_instance)
|
||||
|
||||
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
|
||||
"virtio", "ide",
|
||||
rescue=True)
|
||||
|
||||
expect = {
|
||||
'disk.rescue': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'},
|
||||
'disk': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
|
||||
'root': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'}
|
||||
}
|
||||
self.assertEqual(mapping, expect)
|
||||
|
||||
def test_get_disk_mapping_lxc(self):
|
||||
# A simple disk mapping setup, but for lxc
|
||||
|
||||
user_context = context.RequestContext(self.user_id, self.project_id)
|
||||
instance_ref = db.instance_create(user_context, self.test_instance)
|
||||
|
||||
mapping = blockinfo.get_disk_mapping("lxc", instance_ref,
|
||||
"lxc", "lxc",
|
||||
None)
|
||||
expect = {
|
||||
'disk': {'bus': 'lxc', 'dev': None, 'type': 'disk'},
|
||||
'root': {'bus': 'lxc', 'dev': None, 'type': 'disk'}
|
||||
}
|
||||
self.assertEqual(mapping, expect)
|
||||
|
||||
def test_get_disk_mapping_simple_iso(self):
|
||||
# A simple disk mapping setup, but with a ISO for root device
|
||||
|
||||
user_context = context.RequestContext(self.user_id, self.project_id)
|
||||
instance_ref = db.instance_create(user_context, self.test_instance)
|
||||
image_meta = {'disk_format': 'iso'}
|
||||
|
||||
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
|
||||
"virtio", "ide",
|
||||
None,
|
||||
image_meta)
|
||||
|
||||
expect = {
|
||||
'disk': {'bus': 'ide', 'dev': 'hda', 'type': 'cdrom'},
|
||||
'disk.local': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'},
|
||||
'root': {'bus': 'ide', 'dev': 'hda', 'type': 'cdrom'}
|
||||
}
|
||||
self.assertEqual(mapping, expect)
|
||||
|
||||
def test_get_disk_mapping_simple_swap(self):
|
||||
# A simple disk mapping setup, but with a swap device added
|
||||
|
||||
user_context = context.RequestContext(self.user_id, self.project_id)
|
||||
self.test_instance['system_metadata']['instance_type_swap'] = 5
|
||||
instance_ref = db.instance_create(user_context, self.test_instance)
|
||||
|
||||
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
|
||||
"virtio", "ide")
|
||||
|
||||
expect = {
|
||||
'disk': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'},
|
||||
'disk.local': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
|
||||
'disk.swap': {'bus': 'virtio', 'dev': 'vdc', 'type': 'disk'},
|
||||
'root': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'}
|
||||
}
|
||||
self.assertEqual(mapping, expect)
|
||||
|
||||
def test_get_disk_mapping_simple_configdrive(self):
|
||||
# A simple disk mapping setup, but with configdrive added
|
||||
|
||||
self.flags(force_config_drive=True)
|
||||
|
||||
user_context = context.RequestContext(self.user_id, self.project_id)
|
||||
instance_ref = db.instance_create(user_context, self.test_instance)
|
||||
|
||||
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
|
||||
"virtio", "ide")
|
||||
|
||||
expect = {
|
||||
'disk': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'},
|
||||
'disk.local': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
|
||||
'disk.config': {'bus': 'virtio', 'dev': 'vdz', 'type': 'disk'},
|
||||
'root': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'}
|
||||
}
|
||||
self.assertEqual(mapping, expect)
|
||||
|
||||
def test_get_disk_mapping_ephemeral(self):
|
||||
# A disk mapping with ephemeral devices
|
||||
user_context = context.RequestContext(self.user_id, self.project_id)
|
||||
self.test_instance['system_metadata']['instance_type_swap'] = 5
|
||||
instance_ref = db.instance_create(user_context, self.test_instance)
|
||||
|
||||
block_device_info = {
|
||||
'ephemerals': [
|
||||
{'num': 0, 'virtual_name': 'ephemeral0',
|
||||
'device_name': '/dev/vdb', 'size': 10},
|
||||
{'num': 1, 'virtual_name': 'ephemeral1',
|
||||
'device_name': '/dev/vdc', 'size': 10},
|
||||
{'num': 2, 'virtual_name': 'ephemeral2',
|
||||
'device_name': '/dev/vdd', 'size': 10},
|
||||
]
|
||||
}
|
||||
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
|
||||
"virtio", "ide",
|
||||
block_device_info)
|
||||
|
||||
expect = {
|
||||
'disk': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'},
|
||||
'disk.eph0': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
|
||||
'disk.eph1': {'bus': 'virtio', 'dev': 'vdc', 'type': 'disk'},
|
||||
'disk.eph2': {'bus': 'virtio', 'dev': 'vdd', 'type': 'disk'},
|
||||
'disk.swap': {'bus': 'virtio', 'dev': 'vde', 'type': 'disk'},
|
||||
'root': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'}
|
||||
}
|
||||
self.assertEqual(mapping, expect)
|
||||
|
||||
def test_get_disk_mapping_custom_swap(self):
|
||||
# A disk mapping with a swap device at position vdb. This
|
||||
# should cause disk.local to be removed
|
||||
user_context = context.RequestContext(self.user_id, self.project_id)
|
||||
instance_ref = db.instance_create(user_context, self.test_instance)
|
||||
|
||||
block_device_info = {
|
||||
'swap': {'device_name': '/dev/vdb',
|
||||
'swap_size': 10},
|
||||
}
|
||||
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
|
||||
"virtio", "ide",
|
||||
block_device_info)
|
||||
|
||||
expect = {
|
||||
'disk': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'},
|
||||
'disk.swap': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
|
||||
'root': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'}
|
||||
}
|
||||
self.assertEqual(mapping, expect)
|
||||
|
||||
def test_get_disk_mapping_blockdev_root(self):
|
||||
# A disk mapping with a blockdev replacing the default root
|
||||
user_context = context.RequestContext(self.user_id, self.project_id)
|
||||
instance_ref = db.instance_create(user_context, self.test_instance)
|
||||
|
||||
block_device_info = {
|
||||
'block_device_mapping': [
|
||||
{'connection_info': "fake",
|
||||
'mount_device': "/dev/vda",
|
||||
'delete_on_termination': True},
|
||||
]
|
||||
}
|
||||
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
|
||||
"virtio", "ide",
|
||||
block_device_info)
|
||||
|
||||
expect = {
|
||||
'/dev/vda': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'},
|
||||
'disk.local': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
|
||||
'root': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'}
|
||||
}
|
||||
self.assertEqual(mapping, expect)
|
||||
|
||||
def test_get_disk_mapping_blockdev_eph(self):
|
||||
# A disk mapping with a blockdev replacing the ephemeral device
|
||||
user_context = context.RequestContext(self.user_id, self.project_id)
|
||||
instance_ref = db.instance_create(user_context, self.test_instance)
|
||||
|
||||
block_device_info = {
|
||||
'block_device_mapping': [
|
||||
{'connection_info': "fake",
|
||||
'mount_device': "/dev/vdb",
|
||||
'delete_on_termination': True},
|
||||
]
|
||||
}
|
||||
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
|
||||
"virtio", "ide",
|
||||
block_device_info)
|
||||
|
||||
expect = {
|
||||
'disk': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'},
|
||||
'/dev/vdb': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
|
||||
'root': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'}
|
||||
}
|
||||
self.assertEqual(mapping, expect)
|
||||
|
||||
def test_get_disk_mapping_blockdev_many(self):
|
||||
# A disk mapping with a blockdev replacing all devices
|
||||
user_context = context.RequestContext(self.user_id, self.project_id)
|
||||
instance_ref = db.instance_create(user_context, self.test_instance)
|
||||
|
||||
block_device_info = {
|
||||
'block_device_mapping': [
|
||||
{'connection_info': "fake",
|
||||
'mount_device': "/dev/vda",
|
||||
'delete_on_termination': True},
|
||||
{'connection_info': "fake",
|
||||
'mount_device': "/dev/vdb",
|
||||
'delete_on_termination': True},
|
||||
{'connection_info': "fake",
|
||||
'mount_device': "/dev/vdc",
|
||||
'delete_on_termination': True},
|
||||
]
|
||||
}
|
||||
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
|
||||
"virtio", "ide",
|
||||
block_device_info)
|
||||
|
||||
expect = {
|
||||
'/dev/vda': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'},
|
||||
'/dev/vdb': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
|
||||
'/dev/vdc': {'bus': 'virtio', 'dev': 'vdc', 'type': 'disk'},
|
||||
'root': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'}
|
||||
}
|
||||
self.assertEqual(mapping, expect)
|
||||
|
||||
def test_get_disk_mapping_complex(self):
|
||||
# The strangest possible disk mapping setup
|
||||
user_context = context.RequestContext(self.user_id, self.project_id)
|
||||
instance_ref = db.instance_create(user_context, self.test_instance)
|
||||
|
||||
block_device_info = {
|
||||
'root_device_name': '/dev/vdf',
|
||||
'swap': {'device_name': '/dev/vdy',
|
||||
'swap_size': 10},
|
||||
'ephemerals': [
|
||||
{'num': 0, 'virtual_name': 'ephemeral0',
|
||||
'device_name': '/dev/vdb', 'size': 10},
|
||||
{'num': 1, 'virtual_name': 'ephemeral1',
|
||||
'device_name': '/dev/vdc', 'size': 10},
|
||||
],
|
||||
'block_device_mapping': [
|
||||
{'connection_info': "fake",
|
||||
'mount_device': "/dev/vda",
|
||||
'delete_on_termination': True},
|
||||
]
|
||||
}
|
||||
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
|
||||
"virtio", "ide",
|
||||
block_device_info)
|
||||
|
||||
expect = {
|
||||
'disk': {'bus': 'virtio', 'dev': 'vdf', 'type': 'disk'},
|
||||
'/dev/vda': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'},
|
||||
'disk.eph0': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
|
||||
'disk.eph1': {'bus': 'virtio', 'dev': 'vdc', 'type': 'disk'},
|
||||
'disk.swap': {'bus': 'virtio', 'dev': 'vdy', 'type': 'disk'},
|
||||
'root': {'bus': 'virtio', 'dev': 'vdf', 'type': 'disk'}
|
||||
}
|
||||
self.assertEqual(mapping, expect)
|
||||
|
||||
def test_get_disk_bus(self):
|
||||
bus = blockinfo.get_disk_bus_for_device_type('kvm')
|
||||
self.assertEqual(bus, 'virtio')
|
||||
|
||||
bus = blockinfo.get_disk_bus_for_device_type('kvm',
|
||||
device_type='cdrom')
|
||||
self.assertEqual(bus, 'ide')
|
||||
|
||||
image_meta = {'properties': {'hw_disk_bus': 'scsi'}}
|
||||
bus = blockinfo.get_disk_bus_for_device_type('kvm',
|
||||
image_meta)
|
||||
self.assertEqual(bus, 'scsi')
|
||||
|
||||
image_meta = {'properties': {'hw_disk_bus': 'usb',
|
||||
'hw_cdrom_bus': 'scsi'}}
|
||||
bus = blockinfo.get_disk_bus_for_device_type('kvm',
|
||||
image_meta,
|
||||
device_type='cdrom')
|
||||
self.assertEqual(bus, 'scsi')
|
||||
|
||||
bus = blockinfo.get_disk_bus_for_device_type('kvm',
|
||||
image_meta)
|
||||
self.assertEqual(bus, 'usb')
|
||||
|
||||
image_meta = {'properties': {'hw_disk_bus': 'xen'}}
|
||||
self.assertRaises(exception.UnsupportedHardware,
|
||||
blockinfo.get_disk_bus_for_device_type,
|
||||
'kvm',
|
||||
image_meta)
|
|
@ -1,902 +0,0 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright (C) 2012 Red Hat, 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.
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from nova import test
|
||||
from nova.tests import matchers
|
||||
from nova.virt.libvirt import config
|
||||
|
||||
|
||||
class LibvirtConfigBaseTest(test.TestCase):
|
||||
def assertXmlEqual(self, expectedXmlstr, actualXmlstr):
|
||||
self.assertThat(actualXmlstr, matchers.XMLMatches(expectedXmlstr))
|
||||
|
||||
|
||||
class LibvirtConfigTest(LibvirtConfigBaseTest):
|
||||
|
||||
def test_config_plain(self):
|
||||
obj = config.LibvirtConfigObject(root_name="demo")
|
||||
xml = obj.to_xml()
|
||||
|
||||
self.assertXmlEqual(xml, "<demo/>")
|
||||
|
||||
def test_config_ns(self):
|
||||
obj = config.LibvirtConfigObject(root_name="demo", ns_prefix="foo",
|
||||
ns_uri="http://example.com/foo")
|
||||
xml = obj.to_xml()
|
||||
|
||||
self.assertXmlEqual(xml, """
|
||||
<foo:demo xmlns:foo="http://example.com/foo"/>""")
|
||||
|
||||
def test_config_text(self):
|
||||
obj = config.LibvirtConfigObject(root_name="demo")
|
||||
root = obj.format_dom()
|
||||
root.append(obj._text_node("foo", "bar"))
|
||||
|
||||
xml = etree.tostring(root)
|
||||
self.assertXmlEqual(xml, "<demo><foo>bar</foo></demo>")
|
||||
|
||||
def test_config_parse(self):
|
||||
inxml = "<demo><foo/></demo>"
|
||||
obj = config.LibvirtConfigObject(root_name="demo")
|
||||
obj.parse_str(inxml)
|
||||
|
||||
|
||||
class LibvirtConfigCapsTest(LibvirtConfigBaseTest):
|
||||
|
||||
def test_config_host(self):
|
||||
xmlin = """
|
||||
<capabilities>
|
||||
<host>
|
||||
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
|
||||
<cpu>
|
||||
<arch>x86_64</arch>
|
||||
<model>Opteron_G3</model>
|
||||
<vendor>AMD</vendor>
|
||||
<topology sockets='1' cores='4' threads='1'/>
|
||||
<feature name='ibs'/>
|
||||
<feature name='osvw'/>
|
||||
</cpu>
|
||||
</host>
|
||||
<guest>
|
||||
<os_type>hvm</os_type>
|
||||
<arch name='x86_64'/>
|
||||
</guest>
|
||||
<guest>
|
||||
<os_type>hvm</os_type>
|
||||
<arch name='i686'/>
|
||||
</guest>
|
||||
</capabilities>"""
|
||||
|
||||
obj = config.LibvirtConfigCaps()
|
||||
obj.parse_str(xmlin)
|
||||
|
||||
self.assertEqual(type(obj.host), config.LibvirtConfigCapsHost)
|
||||
self.assertEqual(obj.host.uuid, "c7a5fdbd-edaf-9455-926a-d65c16db1809")
|
||||
|
||||
xmlout = obj.to_xml()
|
||||
|
||||
self.assertXmlEqual(xmlin, xmlout)
|
||||
|
||||
|
||||
class LibvirtConfigGuestTimerTest(LibvirtConfigBaseTest):
|
||||
def test_config_platform(self):
|
||||
obj = config.LibvirtConfigGuestTimer()
|
||||
obj.track = "host"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<timer name="platform" track="host"/>
|
||||
""")
|
||||
|
||||
def test_config_pit(self):
|
||||
obj = config.LibvirtConfigGuestTimer()
|
||||
obj.name = "pit"
|
||||
obj.tickpolicy = "discard"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<timer name="pit" tickpolicy="discard"/>
|
||||
""")
|
||||
|
||||
def test_config_hpet(self):
|
||||
obj = config.LibvirtConfigGuestTimer()
|
||||
obj.name = "hpet"
|
||||
obj.present = False
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<timer name="hpet" present="no"/>
|
||||
""")
|
||||
|
||||
|
||||
class LibvirtConfigGuestClockTest(LibvirtConfigBaseTest):
|
||||
def test_config_utc(self):
|
||||
obj = config.LibvirtConfigGuestClock()
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<clock offset="utc"/>
|
||||
""")
|
||||
|
||||
def test_config_localtime(self):
|
||||
obj = config.LibvirtConfigGuestClock()
|
||||
obj.offset = "localtime"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<clock offset="localtime"/>
|
||||
""")
|
||||
|
||||
def test_config_timezone(self):
|
||||
obj = config.LibvirtConfigGuestClock()
|
||||
obj.offset = "timezone"
|
||||
obj.timezone = "EDT"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<clock offset="timezone" timezone="EDT"/>
|
||||
""")
|
||||
|
||||
def test_config_variable(self):
|
||||
obj = config.LibvirtConfigGuestClock()
|
||||
obj.offset = "variable"
|
||||
obj.adjustment = "123456"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<clock offset="variable" adjustment="123456"/>
|
||||
""")
|
||||
|
||||
def test_config_timers(self):
|
||||
obj = config.LibvirtConfigGuestClock()
|
||||
|
||||
tmpit = config.LibvirtConfigGuestTimer()
|
||||
tmpit.name = "pit"
|
||||
tmpit.tickpolicy = "discard"
|
||||
|
||||
tmrtc = config.LibvirtConfigGuestTimer()
|
||||
tmrtc.name = "rtc"
|
||||
tmrtc.tickpolicy = "merge"
|
||||
|
||||
obj.add_timer(tmpit)
|
||||
obj.add_timer(tmrtc)
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<clock offset="utc">
|
||||
<timer name="pit" tickpolicy="discard"/>
|
||||
<timer name="rtc" tickpolicy="merge"/>
|
||||
</clock>
|
||||
""")
|
||||
|
||||
|
||||
class LibvirtConfigCPUFeatureTest(LibvirtConfigBaseTest):
|
||||
|
||||
def test_config_simple(self):
|
||||
obj = config.LibvirtConfigCPUFeature("mtrr")
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<feature name="mtrr"/>
|
||||
""")
|
||||
|
||||
|
||||
class LibvirtConfigGuestCPUFeatureTest(LibvirtConfigBaseTest):
|
||||
|
||||
def test_config_simple(self):
|
||||
obj = config.LibvirtConfigGuestCPUFeature("mtrr")
|
||||
obj.policy = "force"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<feature name="mtrr" policy="force"/>
|
||||
""")
|
||||
|
||||
|
||||
class LibvirtConfigCPUTest(LibvirtConfigBaseTest):
|
||||
|
||||
def test_config_simple(self):
|
||||
obj = config.LibvirtConfigCPU()
|
||||
obj.model = "Penryn"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<cpu>
|
||||
<model>Penryn</model>
|
||||
</cpu>
|
||||
""")
|
||||
|
||||
def test_config_complex(self):
|
||||
obj = config.LibvirtConfigCPU()
|
||||
obj.model = "Penryn"
|
||||
obj.vendor = "Intel"
|
||||
obj.arch = "x86_64"
|
||||
|
||||
obj.add_feature(config.LibvirtConfigCPUFeature("mtrr"))
|
||||
obj.add_feature(config.LibvirtConfigCPUFeature("apic"))
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<cpu>
|
||||
<arch>x86_64</arch>
|
||||
<model>Penryn</model>
|
||||
<vendor>Intel</vendor>
|
||||
<feature name="mtrr"/>
|
||||
<feature name="apic"/>
|
||||
</cpu>
|
||||
""")
|
||||
|
||||
def test_config_topology(self):
|
||||
obj = config.LibvirtConfigCPU()
|
||||
obj.model = "Penryn"
|
||||
obj.sockets = 4
|
||||
obj.cores = 4
|
||||
obj.threads = 2
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<cpu>
|
||||
<model>Penryn</model>
|
||||
<topology sockets="4" cores="4" threads="2"/>
|
||||
</cpu>
|
||||
""")
|
||||
|
||||
|
||||
class LibvirtConfigGuestCPUTest(LibvirtConfigBaseTest):
|
||||
|
||||
def test_config_simple(self):
|
||||
obj = config.LibvirtConfigGuestCPU()
|
||||
obj.model = "Penryn"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<cpu match="exact">
|
||||
<model>Penryn</model>
|
||||
</cpu>
|
||||
""")
|
||||
|
||||
def test_config_complex(self):
|
||||
obj = config.LibvirtConfigGuestCPU()
|
||||
obj.model = "Penryn"
|
||||
obj.vendor = "Intel"
|
||||
obj.arch = "x86_64"
|
||||
obj.mode = "custom"
|
||||
|
||||
obj.add_feature(config.LibvirtConfigGuestCPUFeature("mtrr"))
|
||||
obj.add_feature(config.LibvirtConfigGuestCPUFeature("apic"))
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<cpu mode="custom" match="exact">
|
||||
<arch>x86_64</arch>
|
||||
<model>Penryn</model>
|
||||
<vendor>Intel</vendor>
|
||||
<feature name="mtrr" policy="require"/>
|
||||
<feature name="apic" policy="require"/>
|
||||
</cpu>
|
||||
""")
|
||||
|
||||
def test_config_host(self):
|
||||
obj = config.LibvirtConfigGuestCPU()
|
||||
obj.mode = "host-model"
|
||||
obj.match = "exact"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<cpu mode="host-model" match="exact"/>
|
||||
""")
|
||||
|
||||
|
||||
class LibvirtConfigGuestSMBIOSTest(LibvirtConfigBaseTest):
|
||||
|
||||
def test_config_simple(self):
|
||||
obj = config.LibvirtConfigGuestSMBIOS()
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<smbios mode="sysinfo"/>
|
||||
""")
|
||||
|
||||
|
||||
class LibvirtConfigGuestSysinfoTest(LibvirtConfigBaseTest):
|
||||
|
||||
def test_config_simple(self):
|
||||
obj = config.LibvirtConfigGuestSysinfo()
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<sysinfo type="smbios"/>
|
||||
""")
|
||||
|
||||
def test_config_bios(self):
|
||||
obj = config.LibvirtConfigGuestSysinfo()
|
||||
obj.bios_vendor = "Acme"
|
||||
obj.bios_version = "6.6.6"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<sysinfo type="smbios">
|
||||
<bios>
|
||||
<entry name="vendor">Acme</entry>
|
||||
<entry name="version">6.6.6</entry>
|
||||
</bios>
|
||||
</sysinfo>
|
||||
""")
|
||||
|
||||
def test_config_system(self):
|
||||
obj = config.LibvirtConfigGuestSysinfo()
|
||||
obj.system_manufacturer = "Acme"
|
||||
obj.system_product = "Wile Coyote"
|
||||
obj.system_version = "6.6.6"
|
||||
obj.system_serial = "123456"
|
||||
obj.system_uuid = "c7a5fdbd-edaf-9455-926a-d65c16db1809"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<sysinfo type="smbios">
|
||||
<system>
|
||||
<entry name="manufacturer">Acme</entry>
|
||||
<entry name="product">Wile Coyote</entry>
|
||||
<entry name="version">6.6.6</entry>
|
||||
<entry name="serial">123456</entry>
|
||||
<entry name="uuid">c7a5fdbd-edaf-9455-926a-d65c16db1809</entry>
|
||||
</system>
|
||||
</sysinfo>
|
||||
""")
|
||||
|
||||
def test_config_mixed(self):
|
||||
obj = config.LibvirtConfigGuestSysinfo()
|
||||
obj.bios_vendor = "Acme"
|
||||
obj.system_manufacturer = "Acme"
|
||||
obj.system_product = "Wile Coyote"
|
||||
obj.system_uuid = "c7a5fdbd-edaf-9455-926a-d65c16db1809"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<sysinfo type="smbios">
|
||||
<bios>
|
||||
<entry name="vendor">Acme</entry>
|
||||
</bios>
|
||||
<system>
|
||||
<entry name="manufacturer">Acme</entry>
|
||||
<entry name="product">Wile Coyote</entry>
|
||||
<entry name="uuid">c7a5fdbd-edaf-9455-926a-d65c16db1809</entry>
|
||||
</system>
|
||||
</sysinfo>
|
||||
""")
|
||||
|
||||
|
||||
class LibvirtConfigGuestDiskTest(LibvirtConfigBaseTest):
|
||||
|
||||
def test_config_file(self):
|
||||
obj = config.LibvirtConfigGuestDisk()
|
||||
obj.source_type = "file"
|
||||
obj.source_path = "/tmp/hello"
|
||||
obj.target_dev = "/dev/hda"
|
||||
obj.target_bus = "ide"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<disk type="file" device="disk">
|
||||
<source file="/tmp/hello"/>
|
||||
<target bus="ide" dev="/dev/hda"/>
|
||||
</disk>""")
|
||||
|
||||
def test_config_file_serial(self):
|
||||
obj = config.LibvirtConfigGuestDisk()
|
||||
obj.source_type = "file"
|
||||
obj.source_path = "/tmp/hello"
|
||||
obj.target_dev = "/dev/hda"
|
||||
obj.target_bus = "ide"
|
||||
obj.serial = "7a97c4a3-6f59-41d4-bf47-191d7f97f8e9"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<disk type="file" device="disk">
|
||||
<source file="/tmp/hello"/>
|
||||
<target bus="ide" dev="/dev/hda"/>
|
||||
<serial>7a97c4a3-6f59-41d4-bf47-191d7f97f8e9</serial>
|
||||
</disk>""")
|
||||
|
||||
def test_config_block(self):
|
||||
obj = config.LibvirtConfigGuestDisk()
|
||||
obj.source_type = "block"
|
||||
obj.source_path = "/tmp/hello"
|
||||
obj.source_device = "cdrom"
|
||||
obj.driver_name = "qemu"
|
||||
obj.target_dev = "/dev/hdc"
|
||||
obj.target_bus = "ide"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<disk type="block" device="cdrom">
|
||||
<driver name="qemu"/>
|
||||
<source dev="/tmp/hello"/>
|
||||
<target bus="ide" dev="/dev/hdc"/>
|
||||
</disk>""")
|
||||
|
||||
def test_config_network(self):
|
||||
obj = config.LibvirtConfigGuestDisk()
|
||||
obj.source_type = "network"
|
||||
obj.source_protocol = "iscsi"
|
||||
obj.source_host = "foo.bar.com"
|
||||
obj.driver_name = "qemu"
|
||||
obj.driver_format = "qcow2"
|
||||
obj.target_dev = "/dev/hda"
|
||||
obj.target_bus = "ide"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<disk type="network" device="disk">
|
||||
<driver name="qemu" type="qcow2"/>
|
||||
<source name="foo.bar.com" protocol="iscsi"/>
|
||||
<target bus="ide" dev="/dev/hda"/>
|
||||
</disk>""")
|
||||
|
||||
def test_config_network_auth(self):
|
||||
obj = config.LibvirtConfigGuestDisk()
|
||||
obj.source_type = "network"
|
||||
obj.source_protocol = "rbd"
|
||||
obj.source_host = "pool/image"
|
||||
obj.driver_name = "qemu"
|
||||
obj.driver_format = "raw"
|
||||
obj.target_dev = "/dev/vda"
|
||||
obj.target_bus = "virtio"
|
||||
obj.auth_username = "foo"
|
||||
obj.auth_secret_type = "ceph"
|
||||
obj.auth_secret_uuid = "b38a3f43-4be2-4046-897f-b67c2f5e0147"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<disk type="network" device="disk">
|
||||
<driver name="qemu" type="raw"/>
|
||||
<source name="pool/image" protocol="rbd"/>
|
||||
<auth username="foo">
|
||||
<secret type="ceph"
|
||||
uuid="b38a3f43-4be2-4046-897f-b67c2f5e0147"/>
|
||||
</auth>
|
||||
<target bus="virtio" dev="/dev/vda"/>
|
||||
</disk>""")
|
||||
|
||||
def test_config_iotune(self):
|
||||
obj = config.LibvirtConfigGuestDisk()
|
||||
obj.source_type = "file"
|
||||
obj.source_path = "/tmp/hello"
|
||||
obj.target_dev = "/dev/hda"
|
||||
obj.target_bus = "ide"
|
||||
obj.disk_read_bytes_sec = 1024000
|
||||
obj.disk_read_iops_sec = 1000
|
||||
obj.disk_total_bytes_sec = 2048000
|
||||
obj.disk_write_bytes_sec = 1024000
|
||||
obj.disk_write_iops_sec = 1000
|
||||
obj.disk_total_iops_sec = 2000
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<disk type="file" device="disk">
|
||||
<source file="/tmp/hello"/>
|
||||
<target bus="ide" dev="/dev/hda"/>
|
||||
<iotune>
|
||||
<read_bytes_sec>1024000</read_bytes_sec>
|
||||
<read_iops_sec>1000</read_iops_sec>
|
||||
<write_bytes_sec>1024000</write_bytes_sec>
|
||||
<write_iops_sec>1000</write_iops_sec>
|
||||
<total_bytes_sec>2048000</total_bytes_sec>
|
||||
<total_iops_sec>2000</total_iops_sec>
|
||||
</iotune>
|
||||
</disk>""")
|
||||
|
||||
|
||||
class LibvirtConfigGuestFilesysTest(LibvirtConfigBaseTest):
|
||||
|
||||
def test_config_mount(self):
|
||||
obj = config.LibvirtConfigGuestFilesys()
|
||||
obj.source_type = "mount"
|
||||
obj.source_dir = "/tmp/hello"
|
||||
obj.target_dir = "/mnt"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<filesystem type="mount">
|
||||
<source dir="/tmp/hello"/>
|
||||
<target dir="/mnt"/>
|
||||
</filesystem>""")
|
||||
|
||||
|
||||
class LibvirtConfigGuestInputTest(LibvirtConfigBaseTest):
|
||||
|
||||
def test_config_tablet(self):
|
||||
obj = config.LibvirtConfigGuestInput()
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<input type="tablet" bus="usb"/>""")
|
||||
|
||||
|
||||
class LibvirtConfigGuestGraphicsTest(LibvirtConfigBaseTest):
|
||||
|
||||
def test_config_graphics(self):
|
||||
obj = config.LibvirtConfigGuestGraphics()
|
||||
obj.type = "vnc"
|
||||
obj.autoport = True
|
||||
obj.keymap = "en_US"
|
||||
obj.listen = "127.0.0.1"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<graphics type="vnc" autoport="yes" keymap="en_US" listen="127.0.0.1"/>
|
||||
""")
|
||||
|
||||
|
||||
class LibvirtConfigGuestSerialTest(LibvirtConfigBaseTest):
|
||||
|
||||
def test_config_file(self):
|
||||
obj = config.LibvirtConfigGuestSerial()
|
||||
obj.type = "file"
|
||||
obj.source_path = "/tmp/vm.log"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<serial type="file">
|
||||
<source path="/tmp/vm.log"/>
|
||||
</serial>""")
|
||||
|
||||
|
||||
class LibvirtConfigGuestConsoleTest(LibvirtConfigBaseTest):
|
||||
def test_config_pty(self):
|
||||
obj = config.LibvirtConfigGuestConsole()
|
||||
obj.type = "pty"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<console type="pty"/>""")
|
||||
|
||||
|
||||
class LibvirtConfigGuestChannelTest(LibvirtConfigBaseTest):
|
||||
def test_config_spice_minimal(self):
|
||||
obj = config.LibvirtConfigGuestChannel()
|
||||
obj.type = "spicevmc"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<channel type="spicevmc">
|
||||
<target type='virtio'/>
|
||||
</channel>""")
|
||||
|
||||
def test_config_spice_full(self):
|
||||
obj = config.LibvirtConfigGuestChannel()
|
||||
obj.type = "spicevmc"
|
||||
obj.target_name = "com.redhat.spice.0"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<channel type="spicevmc">
|
||||
<target type='virtio' name='com.redhat.spice.0'/>
|
||||
</channel>""")
|
||||
|
||||
|
||||
class LibvirtConfigGuestInterfaceTest(LibvirtConfigBaseTest):
|
||||
def test_config_ethernet(self):
|
||||
obj = config.LibvirtConfigGuestInterface()
|
||||
obj.net_type = "ethernet"
|
||||
obj.mac_addr = "DE:AD:BE:EF:CA:FE"
|
||||
obj.model = "virtio"
|
||||
obj.target_dev = "vnet0"
|
||||
obj.driver_name = "vhost"
|
||||
obj.vif_inbound_average = 1024000
|
||||
obj.vif_inbound_peak = 10240000
|
||||
obj.vif_inbound_burst = 1024000
|
||||
obj.vif_outbound_average = 1024000
|
||||
obj.vif_outbound_peak = 10240000
|
||||
obj.vif_outbound_burst = 1024000
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<interface type="ethernet">
|
||||
<mac address="DE:AD:BE:EF:CA:FE"/>
|
||||
<model type="virtio"/>
|
||||
<driver name="vhost"/>
|
||||
<target dev="vnet0"/>
|
||||
<bandwidth>
|
||||
<inbound average="1024000" peak="10240000" burst="1024000"/>
|
||||
<outbound average="1024000" peak="10240000" burst="1024000"/>
|
||||
</bandwidth>
|
||||
</interface>""")
|
||||
|
||||
def test_config_bridge(self):
|
||||
obj = config.LibvirtConfigGuestInterface()
|
||||
obj.net_type = "bridge"
|
||||
obj.source_dev = "br0"
|
||||
obj.mac_addr = "DE:AD:BE:EF:CA:FE"
|
||||
obj.model = "virtio"
|
||||
obj.target_dev = "tap12345678"
|
||||
obj.filtername = "clean-traffic"
|
||||
obj.filterparams.append({"key": "IP", "value": "192.168.122.1"})
|
||||
obj.vif_inbound_average = 1024000
|
||||
obj.vif_inbound_peak = 10240000
|
||||
obj.vif_inbound_burst = 1024000
|
||||
obj.vif_outbound_average = 1024000
|
||||
obj.vif_outbound_peak = 10240000
|
||||
obj.vif_outbound_burst = 1024000
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<interface type="bridge">
|
||||
<mac address="DE:AD:BE:EF:CA:FE"/>
|
||||
<model type="virtio"/>
|
||||
<source bridge="br0"/>
|
||||
<target dev="tap12345678"/>
|
||||
<filterref filter="clean-traffic">
|
||||
<parameter name="IP" value="192.168.122.1"/>
|
||||
</filterref>
|
||||
<bandwidth>
|
||||
<inbound average="1024000" peak="10240000" burst="1024000"/>
|
||||
<outbound average="1024000" peak="10240000" burst="1024000"/>
|
||||
</bandwidth>
|
||||
</interface>""")
|
||||
|
||||
def test_config_bridge_ovs(self):
|
||||
obj = config.LibvirtConfigGuestInterface()
|
||||
obj.net_type = "bridge"
|
||||
obj.source_dev = "br0"
|
||||
obj.mac_addr = "DE:AD:BE:EF:CA:FE"
|
||||
obj.model = "virtio"
|
||||
obj.target_dev = "tap12345678"
|
||||
obj.vporttype = "openvswitch"
|
||||
obj.vportparams.append({"key": "instanceid", "value": "foobar"})
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<interface type="bridge">
|
||||
<mac address="DE:AD:BE:EF:CA:FE"/>
|
||||
<model type="virtio"/>
|
||||
<source bridge="br0"/>
|
||||
<target dev="tap12345678"/>
|
||||
<virtualport type="openvswitch">
|
||||
<parameters instanceid="foobar"/>
|
||||
</virtualport>
|
||||
</interface>""")
|
||||
|
||||
def test_config_8021Qbh(self):
|
||||
obj = config.LibvirtConfigGuestInterface()
|
||||
obj.net_type = "direct"
|
||||
obj.mac_addr = "DE:AD:BE:EF:CA:FE"
|
||||
obj.model = "virtio"
|
||||
obj.target_dev = "tap12345678"
|
||||
obj.source_dev = "eth0"
|
||||
obj.vporttype = "802.1Qbh"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<interface type="direct">
|
||||
<mac address="DE:AD:BE:EF:CA:FE"/>
|
||||
<model type="virtio"/>
|
||||
<source dev="eth0" mode="private"/>
|
||||
<target dev="tap12345678"/>
|
||||
<virtualport type="802.1Qbh"/>
|
||||
</interface>""")
|
||||
|
||||
|
||||
class LibvirtConfigGuestTest(LibvirtConfigBaseTest):
|
||||
|
||||
def test_config_lxc(self):
|
||||
obj = config.LibvirtConfigGuest()
|
||||
obj.virt_type = "lxc"
|
||||
obj.memory = 1024 * 1024 * 100
|
||||
obj.vcpus = 2
|
||||
obj.cpuset = "0-3,^2,4-5"
|
||||
obj.name = "demo"
|
||||
obj.uuid = "b38a3f43-4be2-4046-897f-b67c2f5e0147"
|
||||
obj.os_type = "exe"
|
||||
obj.os_init_path = "/sbin/init"
|
||||
|
||||
fs = config.LibvirtConfigGuestFilesys()
|
||||
fs.source_dir = "/root/lxc"
|
||||
fs.target_dir = "/"
|
||||
|
||||
obj.add_device(fs)
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<domain type="lxc">
|
||||
<uuid>b38a3f43-4be2-4046-897f-b67c2f5e0147</uuid>
|
||||
<name>demo</name>
|
||||
<memory>104857600</memory>
|
||||
<vcpu cpuset="0-3,^2,4-5">2</vcpu>
|
||||
<os>
|
||||
<type>exe</type>
|
||||
<init>/sbin/init</init>
|
||||
</os>
|
||||
<devices>
|
||||
<filesystem type="mount">
|
||||
<source dir="/root/lxc"/>
|
||||
<target dir="/"/>
|
||||
</filesystem>
|
||||
</devices>
|
||||
</domain>""")
|
||||
|
||||
def test_config_xen_pv(self):
|
||||
obj = config.LibvirtConfigGuest()
|
||||
obj.virt_type = "xen"
|
||||
obj.memory = 1024 * 1024 * 100
|
||||
obj.vcpus = 2
|
||||
obj.cpuset = "0-3,^2,4-5"
|
||||
obj.name = "demo"
|
||||
obj.uuid = "b38a3f43-4be2-4046-897f-b67c2f5e0147"
|
||||
obj.os_type = "linux"
|
||||
obj.os_kernel = "/tmp/vmlinuz"
|
||||
obj.os_initrd = "/tmp/ramdisk"
|
||||
obj.os_root = "root=xvda"
|
||||
obj.os_cmdline = "console=xvc0"
|
||||
|
||||
disk = config.LibvirtConfigGuestDisk()
|
||||
disk.source_type = "file"
|
||||
disk.source_path = "/tmp/img"
|
||||
disk.target_dev = "/dev/xvda"
|
||||
disk.target_bus = "xen"
|
||||
|
||||
obj.add_device(disk)
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<domain type="xen">
|
||||
<uuid>b38a3f43-4be2-4046-897f-b67c2f5e0147</uuid>
|
||||
<name>demo</name>
|
||||
<memory>104857600</memory>
|
||||
<vcpu cpuset="0-3,^2,4-5">2</vcpu>
|
||||
<os>
|
||||
<type>linux</type>
|
||||
<kernel>/tmp/vmlinuz</kernel>
|
||||
<initrd>/tmp/ramdisk</initrd>
|
||||
<cmdline>console=xvc0</cmdline>
|
||||
<root>root=xvda</root>
|
||||
</os>
|
||||
<devices>
|
||||
<disk type="file" device="disk">
|
||||
<source file="/tmp/img"/>
|
||||
<target bus="xen" dev="/dev/xvda"/>
|
||||
</disk>
|
||||
</devices>
|
||||
</domain>""")
|
||||
|
||||
def test_config_xen_hvm(self):
|
||||
obj = config.LibvirtConfigGuest()
|
||||
obj.virt_type = "xen"
|
||||
obj.memory = 1024 * 1024 * 100
|
||||
obj.vcpus = 2
|
||||
obj.cpuset = "0-3,^2,4-5"
|
||||
obj.name = "demo"
|
||||
obj.uuid = "b38a3f43-4be2-4046-897f-b67c2f5e0147"
|
||||
obj.os_type = "hvm"
|
||||
obj.os_loader = '/usr/lib/xen/boot/hvmloader'
|
||||
obj.os_root = "root=xvda"
|
||||
obj.os_cmdline = "console=xvc0"
|
||||
obj.acpi = True
|
||||
obj.apic = True
|
||||
|
||||
disk = config.LibvirtConfigGuestDisk()
|
||||
disk.source_type = "file"
|
||||
disk.source_path = "/tmp/img"
|
||||
disk.target_dev = "/dev/xvda"
|
||||
disk.target_bus = "xen"
|
||||
|
||||
obj.add_device(disk)
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<domain type="xen">
|
||||
<uuid>b38a3f43-4be2-4046-897f-b67c2f5e0147</uuid>
|
||||
<name>demo</name>
|
||||
<memory>104857600</memory>
|
||||
<vcpu cpuset="0-3,^2,4-5">2</vcpu>
|
||||
<os>
|
||||
<type>hvm</type>
|
||||
<loader>/usr/lib/xen/boot/hvmloader</loader>
|
||||
<cmdline>console=xvc0</cmdline>
|
||||
<root>root=xvda</root>
|
||||
</os>
|
||||
<features>
|
||||
<acpi/>
|
||||
<apic/>
|
||||
</features>
|
||||
<devices>
|
||||
<disk type="file" device="disk">
|
||||
<source file="/tmp/img"/>
|
||||
<target bus="xen" dev="/dev/xvda"/>
|
||||
</disk>
|
||||
</devices>
|
||||
</domain>""")
|
||||
|
||||
def test_config_kvm(self):
|
||||
obj = config.LibvirtConfigGuest()
|
||||
obj.virt_type = "kvm"
|
||||
obj.memory = 1024 * 1024 * 100
|
||||
obj.vcpus = 2
|
||||
obj.cpuset = "0-3,^2,4-5"
|
||||
obj.cpu_shares = 100
|
||||
obj.cpu_quota = 50000
|
||||
obj.cpu_period = 25000
|
||||
obj.name = "demo"
|
||||
obj.uuid = "b38a3f43-4be2-4046-897f-b67c2f5e0147"
|
||||
obj.os_type = "linux"
|
||||
obj.os_boot_dev = "hd"
|
||||
obj.os_smbios = config.LibvirtConfigGuestSMBIOS()
|
||||
obj.acpi = True
|
||||
obj.apic = True
|
||||
|
||||
obj.sysinfo = config.LibvirtConfigGuestSysinfo()
|
||||
obj.sysinfo.bios_vendor = "Acme"
|
||||
obj.sysinfo.system_version = "1.0.0"
|
||||
|
||||
disk = config.LibvirtConfigGuestDisk()
|
||||
disk.source_type = "file"
|
||||
disk.source_path = "/tmp/img"
|
||||
disk.target_dev = "/dev/vda"
|
||||
disk.target_bus = "virtio"
|
||||
|
||||
obj.add_device(disk)
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<domain type="kvm">
|
||||
<uuid>b38a3f43-4be2-4046-897f-b67c2f5e0147</uuid>
|
||||
<name>demo</name>
|
||||
<memory>104857600</memory>
|
||||
<vcpu cpuset="0-3,^2,4-5">2</vcpu>
|
||||
<sysinfo type='smbios'>
|
||||
<bios>
|
||||
<entry name="vendor">Acme</entry>
|
||||
</bios>
|
||||
<system>
|
||||
<entry name="version">1.0.0</entry>
|
||||
</system>
|
||||
</sysinfo>
|
||||
<os>
|
||||
<type>linux</type>
|
||||
<boot dev="hd"/>
|
||||
<smbios mode="sysinfo"/>
|
||||
</os>
|
||||
<features>
|
||||
<acpi/>
|
||||
<apic/>
|
||||
</features>
|
||||
<cputune>
|
||||
<shares>100</shares>
|
||||
<quota>50000</quota>
|
||||
<period>25000</period>
|
||||
</cputune>
|
||||
<devices>
|
||||
<disk type="file" device="disk">
|
||||
<source file="/tmp/img"/>
|
||||
<target bus="virtio" dev="/dev/vda"/>
|
||||
</disk>
|
||||
</devices>
|
||||
</domain>""")
|
||||
|
||||
|
||||
class LibvirtConfigGuestSnapshotTest(LibvirtConfigBaseTest):
|
||||
|
||||
def test_config_snapshot(self):
|
||||
obj = config.LibvirtConfigGuestSnapshot()
|
||||
obj.name = "Demo"
|
||||
|
||||
xml = obj.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<domainsnapshot>
|
||||
<name>Demo</name>
|
||||
</domainsnapshot>""")
|
|
@ -1,42 +0,0 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2012 NTT Data
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import os
|
||||
|
||||
from nova import test
|
||||
from nova import utils
|
||||
from nova.virt.libvirt import utils as libvirt_utils
|
||||
|
||||
|
||||
class LibvirtUtilsTestCase(test.TestCase):
|
||||
def test_get_disk_type(self):
|
||||
path = "disk.config"
|
||||
example_output = """image: disk.config
|
||||
file format: raw
|
||||
virtual size: 64M (67108864 bytes)
|
||||
cluster_size: 65536
|
||||
disk size: 96K
|
||||
blah BLAH: bb
|
||||
"""
|
||||
self.mox.StubOutWithMock(os.path, 'exists')
|
||||
self.mox.StubOutWithMock(utils, 'execute')
|
||||
os.path.exists(path).AndReturn(True)
|
||||
utils.execute('env', 'LC_ALL=C', 'LANG=C',
|
||||
'qemu-img', 'info', path).AndReturn((example_output, ''))
|
||||
self.mox.ReplayAll()
|
||||
disk_type = libvirt_utils.get_disk_type(path)
|
||||
self.assertEqual(disk_type, 'raw')
|
|
@ -1,628 +0,0 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2012 Nicira, 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.
|
||||
|
||||
from lxml import etree
|
||||
from oslo.config import cfg
|
||||
|
||||
from nova import exception
|
||||
from nova.network import model as network_model
|
||||
from nova import test
|
||||
from nova.tests import fakelibvirt
|
||||
from nova import utils
|
||||
from nova.virt.libvirt import config as vconfig
|
||||
from nova.virt.libvirt import vif
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class LibvirtVifTestCase(test.TestCase):
|
||||
|
||||
net_bridge = {
|
||||
'cidr': '101.168.1.0/24',
|
||||
'cidr_v6': '101:1db9::/64',
|
||||
'gateway_v6': '101:1db9::1',
|
||||
'netmask_v6': '64',
|
||||
'netmask': '255.255.255.0',
|
||||
'bridge': 'br0',
|
||||
'bridge_interface': 'eth0',
|
||||
'vlan': 99,
|
||||
'gateway': '101.168.1.1',
|
||||
'broadcast': '101.168.1.255',
|
||||
'dns1': '8.8.8.8',
|
||||
'id': 'network-id-xxx-yyy-zzz'
|
||||
}
|
||||
|
||||
net_bridge_quantum = {
|
||||
'cidr': '101.168.1.0/24',
|
||||
'cidr_v6': '101:1db9::/64',
|
||||
'gateway_v6': '101:1db9::1',
|
||||
'netmask_v6': '64',
|
||||
'netmask': '255.255.255.0',
|
||||
'bridge_interface': 'eth0',
|
||||
'vlan': 99,
|
||||
'gateway': '101.168.1.1',
|
||||
'broadcast': '101.168.1.255',
|
||||
'dns1': '8.8.8.8',
|
||||
'id': 'network-id-xxx-yyy-zzz'
|
||||
}
|
||||
|
||||
mapping_bridge = {
|
||||
'mac': 'ca:fe:de:ad:be:ef',
|
||||
'gateway_v6': net_bridge['gateway_v6'],
|
||||
'ips': [{'ip': '101.168.1.9'}],
|
||||
'dhcp_server': '191.168.1.1',
|
||||
'vif_uuid': 'vif-xxx-yyy-zzz',
|
||||
'vif_devname': 'tap-xxx-yyy-zzz',
|
||||
'vif_type': network_model.VIF_TYPE_BRIDGE,
|
||||
}
|
||||
|
||||
mapping_bridge_quantum = {
|
||||
'mac': 'ca:fe:de:ad:be:ef',
|
||||
'gateway_v6': net_bridge['gateway_v6'],
|
||||
'ips': [{'ip': '101.168.1.9'}],
|
||||
'dhcp_server': '191.168.1.1',
|
||||
'vif_uuid': 'vif-xxx-yyy-zzz',
|
||||
'vif_devname': 'tap-xxx-yyy-zzz',
|
||||
}
|
||||
|
||||
net_ovs = {
|
||||
'cidr': '101.168.1.0/24',
|
||||
'cidr_v6': '101:1db9::/64',
|
||||
'gateway_v6': '101:1db9::1',
|
||||
'netmask_v6': '64',
|
||||
'netmask': '255.255.255.0',
|
||||
'bridge': 'br0',
|
||||
'vlan': 99,
|
||||
'gateway': '101.168.1.1',
|
||||
'broadcast': '101.168.1.255',
|
||||
'dns1': '8.8.8.8',
|
||||
'id': 'network-id-xxx-yyy-zzz'
|
||||
}
|
||||
|
||||
mapping_ovs = {
|
||||
'mac': 'ca:fe:de:ad:be:ef',
|
||||
'gateway_v6': net_ovs['gateway_v6'],
|
||||
'ips': [{'ip': '101.168.1.9'}],
|
||||
'dhcp_server': '191.168.1.1',
|
||||
'vif_uuid': 'vif-xxx-yyy-zzz',
|
||||
'vif_devname': 'tap-xxx-yyy-zzz',
|
||||
'vif_type': network_model.VIF_TYPE_OVS,
|
||||
'ovs_interfaceid': 'aaa-bbb-ccc',
|
||||
}
|
||||
|
||||
mapping_ovs_legacy = {
|
||||
'mac': 'ca:fe:de:ad:be:ef',
|
||||
'gateway_v6': net_ovs['gateway_v6'],
|
||||
'ips': [{'ip': '101.168.1.9'}],
|
||||
'dhcp_server': '191.168.1.1',
|
||||
'vif_uuid': 'vif-xxx-yyy-zzz',
|
||||
}
|
||||
|
||||
net_8021 = {
|
||||
'cidr': '101.168.1.0/24',
|
||||
'cidr_v6': '101:1db9::/64',
|
||||
'gateway_v6': '101:1db9::1',
|
||||
'netmask_v6': '64',
|
||||
'netmask': '255.255.255.0',
|
||||
'interface': 'eth0',
|
||||
'vlan': 99,
|
||||
'gateway': '101.168.1.1',
|
||||
'broadcast': '101.168.1.255',
|
||||
'dns1': '8.8.8.8',
|
||||
'id': 'network-id-xxx-yyy-zzz'
|
||||
}
|
||||
|
||||
mapping_8021qbh = {
|
||||
'mac': 'ca:fe:de:ad:be:ef',
|
||||
'vif_uuid': 'vif-xxx-yyy-zzz',
|
||||
'vif_devname': 'tap-xxx-yyy-zzz',
|
||||
'vif_type': network_model.VIF_TYPE_802_QBH,
|
||||
'qbh_params': network_model.VIF8021QbhParams(
|
||||
profileid="xxx-yyy-zzz"),
|
||||
}
|
||||
|
||||
mapping_8021qbg = {
|
||||
'mac': 'ca:fe:de:ad:be:ef',
|
||||
'vif_uuid': 'vif-xxx-yyy-zzz',
|
||||
'vif_devname': 'tap-xxx-yyy-zzz',
|
||||
'vif_type': network_model.VIF_TYPE_802_QBG,
|
||||
'qbg_params': network_model.VIF8021QbgParams(
|
||||
managerid="xxx-yyy-zzz",
|
||||
typeid="aaa-bbb-ccc",
|
||||
typeidversion="1",
|
||||
instanceid="ddd-eee-fff")
|
||||
}
|
||||
|
||||
mapping_none = {
|
||||
'mac': 'ca:fe:de:ad:be:ef',
|
||||
'gateway_v6': net_bridge['gateway_v6'],
|
||||
'ips': [{'ip': '101.168.1.9'}],
|
||||
'dhcp_server': '191.168.1.1',
|
||||
'vif_uuid': 'vif-xxx-yyy-zzz',
|
||||
'vif_devname': 'tap-xxx-yyy-zzz',
|
||||
}
|
||||
|
||||
instance = {
|
||||
'name': 'instance-name',
|
||||
'uuid': 'instance-uuid'
|
||||
}
|
||||
|
||||
def setUp(self):
|
||||
super(LibvirtVifTestCase, self).setUp()
|
||||
self.flags(allow_same_net_traffic=True)
|
||||
self.executes = []
|
||||
|
||||
def fake_execute(*cmd, **kwargs):
|
||||
self.executes.append(cmd)
|
||||
return None, None
|
||||
|
||||
self.stubs.Set(utils, 'execute', fake_execute)
|
||||
|
||||
def _get_instance_xml(self, driver, net, mapping, image_meta=None):
|
||||
conf = vconfig.LibvirtConfigGuest()
|
||||
conf.virt_type = "qemu"
|
||||
conf.name = "fake-name"
|
||||
conf.uuid = "fake-uuid"
|
||||
conf.memory = 100 * 1024
|
||||
conf.vcpus = 4
|
||||
|
||||
nic = driver.get_config(self.instance, net, mapping, image_meta)
|
||||
conf.add_device(nic)
|
||||
return conf.to_xml()
|
||||
|
||||
def test_multiple_nics(self):
|
||||
conf = vconfig.LibvirtConfigGuest()
|
||||
conf.virt_type = "qemu"
|
||||
conf.name = "fake-name"
|
||||
conf.uuid = "fake-uuid"
|
||||
conf.memory = 100 * 1024
|
||||
conf.vcpus = 4
|
||||
|
||||
# Tests multiple nic configuration and that target_dev is
|
||||
# set for each
|
||||
nics = [{'net_type': 'bridge',
|
||||
'mac_addr': '00:00:00:00:00:0b',
|
||||
'source_dev': 'b_source_dev',
|
||||
'target_dev': 'b_target_dev'},
|
||||
{'net_type': 'ethernet',
|
||||
'mac_addr': '00:00:00:00:00:0e',
|
||||
'source_dev': 'e_source_dev',
|
||||
'target_dev': 'e_target_dev'},
|
||||
{'net_type': 'direct',
|
||||
'mac_addr': '00:00:00:00:00:0d',
|
||||
'source_dev': 'd_source_dev',
|
||||
'target_dev': 'd_target_dev'}]
|
||||
|
||||
for nic in nics:
|
||||
nic_conf = vconfig.LibvirtConfigGuestInterface()
|
||||
nic_conf.net_type = nic['net_type']
|
||||
nic_conf.target_dev = nic['target_dev']
|
||||
nic_conf.mac_addr = nic['mac_addr']
|
||||
nic_conf.source_dev = nic['source_dev']
|
||||
conf.add_device(nic_conf)
|
||||
|
||||
xml = conf.to_xml()
|
||||
doc = etree.fromstring(xml)
|
||||
for nic in nics:
|
||||
path = "./devices/interface/[@type='%s']" % nic['net_type']
|
||||
node = doc.find(path)
|
||||
self.assertEqual(nic['net_type'], node.get("type"))
|
||||
self.assertEqual(nic['mac_addr'],
|
||||
node.find("mac").get("address"))
|
||||
self.assertEqual(nic['target_dev'],
|
||||
node.find("target").get("dev"))
|
||||
|
||||
def test_model_novirtio(self):
|
||||
self.flags(libvirt_use_virtio_for_bridges=False,
|
||||
libvirt_type='kvm')
|
||||
|
||||
def get_connection():
|
||||
return fakelibvirt.Connection("qemu:///session",
|
||||
False)
|
||||
d = vif.LibvirtGenericVIFDriver(get_connection)
|
||||
xml = self._get_instance_xml(d,
|
||||
self.net_bridge,
|
||||
self.mapping_bridge)
|
||||
|
||||
doc = etree.fromstring(xml)
|
||||
ret = doc.findall('./devices/interface')
|
||||
self.assertEqual(len(ret), 1)
|
||||
node = ret[0]
|
||||
|
||||
ret = node.findall("model")
|
||||
self.assertEqual(len(ret), 0)
|
||||
ret = node.findall("driver")
|
||||
self.assertEqual(len(ret), 0)
|
||||
|
||||
def test_model_kvm(self):
|
||||
self.flags(libvirt_use_virtio_for_bridges=True,
|
||||
libvirt_type='kvm')
|
||||
|
||||
def get_connection():
|
||||
return fakelibvirt.Connection("qemu:///session",
|
||||
False)
|
||||
d = vif.LibvirtGenericVIFDriver(get_connection)
|
||||
xml = self._get_instance_xml(d,
|
||||
self.net_bridge,
|
||||
self.mapping_bridge)
|
||||
|
||||
doc = etree.fromstring(xml)
|
||||
ret = doc.findall('./devices/interface')
|
||||
self.assertEqual(len(ret), 1)
|
||||
node = ret[0]
|
||||
|
||||
model = node.find("model").get("type")
|
||||
self.assertEqual(model, "virtio")
|
||||
ret = node.findall("driver")
|
||||
self.assertEqual(len(ret), 0)
|
||||
|
||||
def test_model_kvm_custom(self):
|
||||
self.flags(libvirt_use_virtio_for_bridges=True,
|
||||
libvirt_type='kvm')
|
||||
|
||||
def get_connection():
|
||||
return fakelibvirt.Connection("qemu:///session",
|
||||
False)
|
||||
d = vif.LibvirtGenericVIFDriver(get_connection)
|
||||
image_meta = {'properties': {'hw_vif_model': 'e1000'}}
|
||||
xml = self._get_instance_xml(d,
|
||||
self.net_bridge,
|
||||
self.mapping_bridge,
|
||||
image_meta)
|
||||
|
||||
doc = etree.fromstring(xml)
|
||||
ret = doc.findall('./devices/interface')
|
||||
self.assertEqual(len(ret), 1)
|
||||
node = ret[0]
|
||||
|
||||
model = node.find("model").get("type")
|
||||
self.assertEqual(model, "e1000")
|
||||
ret = node.findall("driver")
|
||||
self.assertEqual(len(ret), 0)
|
||||
|
||||
def test_model_kvm_bogus(self):
|
||||
self.flags(libvirt_use_virtio_for_bridges=True,
|
||||
libvirt_type='kvm')
|
||||
|
||||
def get_connection():
|
||||
return fakelibvirt.Connection("qemu:///session",
|
||||
False)
|
||||
d = vif.LibvirtGenericVIFDriver(get_connection)
|
||||
image_meta = {'properties': {'hw_vif_model': 'acme'}}
|
||||
self.assertRaises(exception.UnsupportedHardware,
|
||||
self._get_instance_xml,
|
||||
d,
|
||||
self.net_bridge,
|
||||
self.mapping_bridge,
|
||||
image_meta)
|
||||
|
||||
def test_model_qemu(self):
|
||||
self.flags(libvirt_use_virtio_for_bridges=True,
|
||||
libvirt_type='qemu')
|
||||
|
||||
def get_connection():
|
||||
return fakelibvirt.Connection("qemu:///session",
|
||||
False)
|
||||
d = vif.LibvirtGenericVIFDriver(get_connection)
|
||||
xml = self._get_instance_xml(d,
|
||||
self.net_bridge,
|
||||
self.mapping_bridge)
|
||||
|
||||
doc = etree.fromstring(xml)
|
||||
ret = doc.findall('./devices/interface')
|
||||
self.assertEqual(len(ret), 1)
|
||||
node = ret[0]
|
||||
|
||||
model = node.find("model").get("type")
|
||||
self.assertEqual(model, "virtio")
|
||||
driver = node.find("driver").get("name")
|
||||
self.assertEqual(driver, "qemu")
|
||||
|
||||
def test_model_xen(self):
|
||||
self.flags(libvirt_use_virtio_for_bridges=True,
|
||||
libvirt_type='xen')
|
||||
|
||||
def get_connection():
|
||||
return fakelibvirt.Connection("xen:///system",
|
||||
False)
|
||||
d = vif.LibvirtGenericVIFDriver(get_connection)
|
||||
xml = self._get_instance_xml(d,
|
||||
self.net_bridge,
|
||||
self.mapping_bridge)
|
||||
|
||||
doc = etree.fromstring(xml)
|
||||
ret = doc.findall('./devices/interface')
|
||||
self.assertEqual(len(ret), 1)
|
||||
node = ret[0]
|
||||
|
||||
ret = node.findall("model")
|
||||
self.assertEqual(len(ret), 0)
|
||||
ret = node.findall("driver")
|
||||
self.assertEqual(len(ret), 0)
|
||||
|
||||
def test_generic_driver_none(self):
|
||||
def get_connection():
|
||||
return fakelibvirt.Connection("qemu:///session",
|
||||
False)
|
||||
d = vif.LibvirtGenericVIFDriver(get_connection)
|
||||
self.assertRaises(exception.NovaException,
|
||||
self._get_instance_xml,
|
||||
d,
|
||||
self.net_bridge,
|
||||
self.mapping_none)
|
||||
|
||||
def _check_bridge_driver(self, d, net, mapping, br_want):
|
||||
xml = self._get_instance_xml(d, net, mapping)
|
||||
|
||||
doc = etree.fromstring(xml)
|
||||
ret = doc.findall('./devices/interface')
|
||||
self.assertEqual(len(ret), 1)
|
||||
node = ret[0]
|
||||
ret = node.findall("filterref")
|
||||
self.assertEqual(len(ret), 1)
|
||||
self.assertEqual(node.get("type"), "bridge")
|
||||
br_name = node.find("source").get("bridge")
|
||||
self.assertEqual(br_name, br_want)
|
||||
mac = node.find("mac").get("address")
|
||||
self.assertEqual(mac, self.mapping_bridge['mac'])
|
||||
|
||||
def test_bridge_driver(self):
|
||||
def get_connection():
|
||||
return fakelibvirt.Connection("qemu:///session",
|
||||
False)
|
||||
d = vif.LibvirtBridgeDriver(get_connection)
|
||||
self._check_bridge_driver(d,
|
||||
self.net_bridge,
|
||||
self.mapping_bridge,
|
||||
self.net_bridge['bridge'])
|
||||
|
||||
def test_generic_driver_bridge(self):
|
||||
def get_connection():
|
||||
return fakelibvirt.Connection("qemu:///session",
|
||||
False)
|
||||
d = vif.LibvirtGenericVIFDriver(get_connection)
|
||||
self._check_bridge_driver(d,
|
||||
self.net_bridge,
|
||||
self.mapping_bridge,
|
||||
self.net_bridge['bridge'])
|
||||
|
||||
def test_quantum_bridge_driver(self):
|
||||
def get_connection():
|
||||
return fakelibvirt.Connection("qemu:///session",
|
||||
False)
|
||||
d = vif.QuantumLinuxBridgeVIFDriver(get_connection)
|
||||
br_want = 'brq' + self.net_bridge_quantum['id']
|
||||
br_want = br_want[:network_model.NIC_NAME_LEN]
|
||||
self._check_bridge_driver(d,
|
||||
self.net_bridge_quantum,
|
||||
self.mapping_bridge_quantum,
|
||||
br_want)
|
||||
|
||||
def _check_ovs_ethernet_driver(self, d, net, mapping, dev_prefix):
|
||||
self.flags(firewall_driver="nova.virt.firewall.NoopFirewallDriver")
|
||||
xml = self._get_instance_xml(d, net, mapping)
|
||||
|
||||
doc = etree.fromstring(xml)
|
||||
ret = doc.findall('./devices/interface')
|
||||
self.assertEqual(len(ret), 1)
|
||||
node = ret[0]
|
||||
ret = node.findall("filterref")
|
||||
self.assertEqual(len(ret), 0)
|
||||
self.assertEqual(node.get("type"), "ethernet")
|
||||
dev_name = node.find("target").get("dev")
|
||||
self.assertTrue(dev_name.startswith(dev_prefix))
|
||||
mac = node.find("mac").get("address")
|
||||
self.assertEqual(mac, self.mapping_ovs['mac'])
|
||||
script = node.find("script").get("path")
|
||||
self.assertEquals(script, "")
|
||||
|
||||
def test_ovs_ethernet_driver_legacy(self):
|
||||
def get_connection():
|
||||
return fakelibvirt.Connection("qemu:///session",
|
||||
False,
|
||||
9010)
|
||||
d = vif.LibvirtOpenVswitchDriver(get_connection)
|
||||
self._check_ovs_ethernet_driver(d,
|
||||
self.net_ovs,
|
||||
self.mapping_ovs_legacy,
|
||||
"nic")
|
||||
|
||||
def test_ovs_ethernet_driver(self):
|
||||
def get_connection():
|
||||
return fakelibvirt.Connection("qemu:///session",
|
||||
False,
|
||||
9010)
|
||||
d = vif.LibvirtGenericVIFDriver(get_connection)
|
||||
self._check_ovs_ethernet_driver(d,
|
||||
self.net_ovs,
|
||||
self.mapping_ovs,
|
||||
"tap")
|
||||
|
||||
def _check_ovs_virtualport_driver(self, d, net, mapping, want_iface_id):
|
||||
self.flags(firewall_driver="nova.virt.firewall.NoopFirewallDriver")
|
||||
xml = self._get_instance_xml(d, net, mapping)
|
||||
|
||||
doc = etree.fromstring(xml)
|
||||
ret = doc.findall('./devices/interface')
|
||||
self.assertEqual(len(ret), 1)
|
||||
node = ret[0]
|
||||
ret = node.findall("filterref")
|
||||
self.assertEqual(len(ret), 0)
|
||||
self.assertEqual(node.get("type"), "bridge")
|
||||
|
||||
br_name = node.find("source").get("bridge")
|
||||
self.assertEqual(br_name, "br0")
|
||||
mac = node.find("mac").get("address")
|
||||
self.assertEqual(mac, mapping['mac'])
|
||||
vp = node.find("virtualport")
|
||||
self.assertEqual(vp.get("type"), "openvswitch")
|
||||
iface_id_found = False
|
||||
for p_elem in vp.findall("parameters"):
|
||||
iface_id = p_elem.get("interfaceid", None)
|
||||
if iface_id:
|
||||
self.assertEqual(iface_id, want_iface_id)
|
||||
iface_id_found = True
|
||||
|
||||
self.assertTrue(iface_id_found)
|
||||
|
||||
def test_ovs_virtualport_driver(self):
|
||||
def get_connection():
|
||||
return fakelibvirt.Connection("qemu:///session",
|
||||
False,
|
||||
9011)
|
||||
d = vif.LibvirtOpenVswitchVirtualPortDriver(get_connection)
|
||||
want_iface_id = 'vif-xxx-yyy-zzz'
|
||||
self._check_ovs_virtualport_driver(d,
|
||||
self.net_ovs,
|
||||
self.mapping_ovs_legacy,
|
||||
want_iface_id)
|
||||
|
||||
def test_generic_ovs_virtualport_driver(self):
|
||||
def get_connection():
|
||||
return fakelibvirt.Connection("qemu:///session",
|
||||
False,
|
||||
9011)
|
||||
d = vif.LibvirtGenericVIFDriver(get_connection)
|
||||
want_iface_id = self.mapping_ovs['ovs_interfaceid']
|
||||
self._check_ovs_virtualport_driver(d,
|
||||
self.net_ovs,
|
||||
self.mapping_ovs,
|
||||
want_iface_id)
|
||||
|
||||
def _check_quantum_hybrid_driver(self, d, net, mapping, br_want):
|
||||
self.flags(firewall_driver="nova.virt.firewall.IptablesFirewallDriver")
|
||||
xml = self._get_instance_xml(d, net, mapping)
|
||||
|
||||
doc = etree.fromstring(xml)
|
||||
ret = doc.findall('./devices/interface')
|
||||
self.assertEqual(len(ret), 1)
|
||||
node = ret[0]
|
||||
ret = node.findall("filterref")
|
||||
self.assertEqual(len(ret), 1)
|
||||
self.assertEqual(node.get("type"), "bridge")
|
||||
br_name = node.find("source").get("bridge")
|
||||
self.assertEqual(br_name, br_want)
|
||||
mac = node.find("mac").get("address")
|
||||
self.assertEqual(mac, mapping['mac'])
|
||||
|
||||
def test_quantum_hybrid_driver(self):
|
||||
def get_connection():
|
||||
return fakelibvirt.Connection("qemu:///session",
|
||||
False)
|
||||
br_want = "qbr" + self.mapping_ovs['vif_uuid']
|
||||
br_want = br_want[:network_model.NIC_NAME_LEN]
|
||||
d = vif.LibvirtHybridOVSBridgeDriver(get_connection)
|
||||
self._check_quantum_hybrid_driver(d,
|
||||
self.net_ovs,
|
||||
self.mapping_ovs_legacy,
|
||||
br_want)
|
||||
|
||||
def test_generic_hybrid_driver(self):
|
||||
def get_connection():
|
||||
return fakelibvirt.Connection("qemu:///session",
|
||||
False)
|
||||
d = vif.LibvirtGenericVIFDriver(get_connection)
|
||||
br_want = "qbr" + self.mapping_ovs['vif_uuid']
|
||||
br_want = br_want[:network_model.NIC_NAME_LEN]
|
||||
self._check_quantum_hybrid_driver(d,
|
||||
self.net_ovs,
|
||||
self.mapping_ovs,
|
||||
br_want)
|
||||
|
||||
def test_generic_8021qbh_driver(self):
|
||||
def get_connection():
|
||||
return fakelibvirt.Connection("qemu:///session",
|
||||
False)
|
||||
d = vif.LibvirtGenericVIFDriver(get_connection)
|
||||
xml = self._get_instance_xml(d,
|
||||
self.net_8021,
|
||||
self.mapping_8021qbh)
|
||||
|
||||
doc = etree.fromstring(xml)
|
||||
ret = doc.findall('./devices/interface')
|
||||
self.assertEqual(len(ret), 1)
|
||||
node = ret[0]
|
||||
self.assertEqual(node.get("type"), "direct")
|
||||
|
||||
br_name = node.find("source").get("dev")
|
||||
self.assertEqual(br_name, "eth0")
|
||||
mac = node.find("mac").get("address")
|
||||
self.assertEqual(mac, self.mapping_8021qbh['mac'])
|
||||
vp = node.find("virtualport")
|
||||
self.assertEqual(vp.get("type"), "802.1Qbh")
|
||||
profile_id_found = False
|
||||
for p_elem in vp.findall("parameters"):
|
||||
wantparams = self.mapping_8021qbh['qbh_params']
|
||||
profile_id = p_elem.get("profileid", None)
|
||||
if profile_id:
|
||||
self.assertEqual(profile_id,
|
||||
wantparams['profileid'])
|
||||
profile_id_found = True
|
||||
|
||||
self.assertTrue(profile_id_found)
|
||||
|
||||
def test_generic_8021qbg_driver(self):
|
||||
def get_connection():
|
||||
return fakelibvirt.Connection("qemu:///session",
|
||||
False)
|
||||
d = vif.LibvirtGenericVIFDriver(get_connection)
|
||||
xml = self._get_instance_xml(d,
|
||||
self.net_8021,
|
||||
self.mapping_8021qbg)
|
||||
|
||||
doc = etree.fromstring(xml)
|
||||
ret = doc.findall('./devices/interface')
|
||||
self.assertEqual(len(ret), 1)
|
||||
node = ret[0]
|
||||
self.assertEqual(node.get("type"), "direct")
|
||||
|
||||
br_name = node.find("source").get("dev")
|
||||
self.assertEqual(br_name, "eth0")
|
||||
mac = node.find("mac").get("address")
|
||||
self.assertEqual(mac, self.mapping_8021qbg['mac'])
|
||||
vp = node.find("virtualport")
|
||||
self.assertEqual(vp.get("type"), "802.1Qbg")
|
||||
manager_id_found = False
|
||||
type_id_found = False
|
||||
typeversion_id_found = False
|
||||
instance_id_found = False
|
||||
for p_elem in vp.findall("parameters"):
|
||||
wantparams = self.mapping_8021qbg['qbg_params']
|
||||
manager_id = p_elem.get("managerid", None)
|
||||
type_id = p_elem.get("typeid", None)
|
||||
typeversion_id = p_elem.get("typeidversion", None)
|
||||
instance_id = p_elem.get("instanceid", None)
|
||||
if manager_id:
|
||||
self.assertEqual(manager_id,
|
||||
wantparams['managerid'])
|
||||
manager_id_found = True
|
||||
if type_id:
|
||||
self.assertEqual(type_id,
|
||||
wantparams['typeid'])
|
||||
type_id_found = True
|
||||
if typeversion_id:
|
||||
self.assertEqual(typeversion_id,
|
||||
wantparams['typeidversion'])
|
||||
typeversion_id_found = True
|
||||
if instance_id:
|
||||
self.assertEqual(instance_id,
|
||||
wantparams['instanceid'])
|
||||
instance_id_found = True
|
||||
|
||||
self.assertTrue(manager_id_found)
|
||||
self.assertTrue(type_id_found)
|
||||
self.assertTrue(typeversion_id_found)
|
||||
self.assertTrue(instance_id_found)
|
|
@ -1,620 +0,0 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2010 OpenStack Foundation
|
||||
# Copyright 2012 University Of Minho
|
||||
#
|
||||
# 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.
|
||||
|
||||
import fixtures
|
||||
import os
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from nova import exception
|
||||
from nova.storage import linuxscsi
|
||||
from nova import test
|
||||
from nova.tests import fake_libvirt_utils
|
||||
from nova import utils
|
||||
from nova.virt import fake
|
||||
from nova.virt.libvirt import utils as libvirt_utils
|
||||
from nova.virt.libvirt import volume
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class LibvirtVolumeTestCase(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(LibvirtVolumeTestCase, self).setUp()
|
||||
self.executes = []
|
||||
|
||||
def fake_execute(*cmd, **kwargs):
|
||||
self.executes.append(cmd)
|
||||
return None, None
|
||||
|
||||
self.stubs.Set(utils, 'execute', fake_execute)
|
||||
|
||||
class FakeLibvirtDriver(object):
|
||||
def __init__(self, hyperv="QEMU"):
|
||||
self.hyperv = hyperv
|
||||
|
||||
def get_hypervisor_type(self):
|
||||
return self.hyperv
|
||||
|
||||
def get_all_block_devices(self):
|
||||
return []
|
||||
|
||||
self.fake_conn = FakeLibvirtDriver(fake.FakeVirtAPI())
|
||||
self.connr = {
|
||||
'ip': '127.0.0.1',
|
||||
'initiator': 'fake_initiator',
|
||||
'host': 'fake_host'
|
||||
}
|
||||
|
||||
def test_libvirt_volume_driver_serial(self):
|
||||
libvirt_driver = volume.LibvirtVolumeDriver(self.fake_conn)
|
||||
name = 'volume-00000001'
|
||||
vol = {'id': 1, 'name': name}
|
||||
connection_info = {
|
||||
'driver_volume_type': 'fake',
|
||||
'data': {
|
||||
'device_path': '/foo',
|
||||
},
|
||||
'serial': 'fake_serial',
|
||||
}
|
||||
disk_info = {
|
||||
"bus": "virtio",
|
||||
"dev": "vde",
|
||||
"type": "disk",
|
||||
}
|
||||
conf = libvirt_driver.connect_volume(connection_info, disk_info)
|
||||
tree = conf.format_dom()
|
||||
self.assertEqual(tree.get('type'), 'block')
|
||||
self.assertEqual(tree.find('./serial').text, 'fake_serial')
|
||||
|
||||
def iscsi_connection(self, volume, location, iqn):
|
||||
return {
|
||||
'driver_volume_type': 'iscsi',
|
||||
'data': {
|
||||
'volume_id': volume['id'],
|
||||
'target_portal': location,
|
||||
'target_iqn': iqn,
|
||||
'target_lun': 1,
|
||||
}
|
||||
}
|
||||
|
||||
def test_libvirt_iscsi_driver(self):
|
||||
# NOTE(vish) exists is to make driver assume connecting worked
|
||||
self.stubs.Set(os.path, 'exists', lambda x: True)
|
||||
libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)
|
||||
location = '10.0.2.15:3260'
|
||||
name = 'volume-00000001'
|
||||
iqn = 'iqn.2010-10.org.openstack:%s' % name
|
||||
vol = {'id': 1, 'name': name}
|
||||
connection_info = self.iscsi_connection(vol, location, iqn)
|
||||
disk_info = {
|
||||
"bus": "virtio",
|
||||
"dev": "vde",
|
||||
"type": "disk",
|
||||
}
|
||||
conf = libvirt_driver.connect_volume(connection_info, disk_info)
|
||||
tree = conf.format_dom()
|
||||
dev_str = '/dev/disk/by-path/ip-%s-iscsi-%s-lun-1' % (location, iqn)
|
||||
self.assertEqual(tree.get('type'), 'block')
|
||||
self.assertEqual(tree.find('./source').get('dev'), dev_str)
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
expected_commands = [('iscsiadm', '-m', 'node', '-T', iqn,
|
||||
'-p', location),
|
||||
('iscsiadm', '-m', 'session'),
|
||||
('iscsiadm', '-m', 'node', '-T', iqn,
|
||||
'-p', location, '--login'),
|
||||
('iscsiadm', '-m', 'node', '-T', iqn,
|
||||
'-p', location, '--op', 'update',
|
||||
'-n', 'node.startup', '-v', 'automatic'),
|
||||
('iscsiadm', '-m', 'node', '-T', iqn,
|
||||
'-p', location, '--op', 'update',
|
||||
'-n', 'node.startup', '-v', 'manual'),
|
||||
('iscsiadm', '-m', 'node', '-T', iqn,
|
||||
'-p', location, '--logout'),
|
||||
('iscsiadm', '-m', 'node', '-T', iqn,
|
||||
'-p', location, '--op', 'delete')]
|
||||
self.assertEqual(self.executes, expected_commands)
|
||||
|
||||
def test_libvirt_iscsi_driver_still_in_use(self):
|
||||
# NOTE(vish) exists is to make driver assume connecting worked
|
||||
self.stubs.Set(os.path, 'exists', lambda x: True)
|
||||
libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)
|
||||
location = '10.0.2.15:3260'
|
||||
name = 'volume-00000001'
|
||||
iqn = 'iqn.2010-10.org.openstack:%s' % name
|
||||
devs = ['/dev/disk/by-path/ip-%s-iscsi-%s-lun-1' % (location, iqn)]
|
||||
self.stubs.Set(self.fake_conn, 'get_all_block_devices', lambda: devs)
|
||||
vol = {'id': 1, 'name': name}
|
||||
connection_info = self.iscsi_connection(vol, location, iqn)
|
||||
disk_info = {
|
||||
"bus": "virtio",
|
||||
"dev": "vde",
|
||||
"type": "disk",
|
||||
}
|
||||
conf = libvirt_driver.connect_volume(connection_info, disk_info)
|
||||
tree = conf.format_dom()
|
||||
dev_str = '/dev/disk/by-path/ip-%s-iscsi-%s-lun-1' % (location, iqn)
|
||||
self.assertEqual(tree.get('type'), 'block')
|
||||
self.assertEqual(tree.find('./source').get('dev'), dev_str)
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
expected_commands = [('iscsiadm', '-m', 'node', '-T', iqn,
|
||||
'-p', location),
|
||||
('iscsiadm', '-m', 'session'),
|
||||
('iscsiadm', '-m', 'node', '-T', iqn,
|
||||
'-p', location, '--login'),
|
||||
('iscsiadm', '-m', 'node', '-T', iqn,
|
||||
'-p', location, '--op', 'update',
|
||||
'-n', 'node.startup', '-v', 'automatic')]
|
||||
self.assertEqual(self.executes, expected_commands)
|
||||
|
||||
def sheepdog_connection(self, volume):
|
||||
return {
|
||||
'driver_volume_type': 'sheepdog',
|
||||
'data': {
|
||||
'name': volume['name']
|
||||
}
|
||||
}
|
||||
|
||||
def test_libvirt_sheepdog_driver(self):
|
||||
libvirt_driver = volume.LibvirtNetVolumeDriver(self.fake_conn)
|
||||
name = 'volume-00000001'
|
||||
vol = {'id': 1, 'name': name}
|
||||
connection_info = self.sheepdog_connection(vol)
|
||||
disk_info = {
|
||||
"bus": "virtio",
|
||||
"dev": "vde",
|
||||
"type": "disk",
|
||||
}
|
||||
conf = libvirt_driver.connect_volume(connection_info, disk_info)
|
||||
tree = conf.format_dom()
|
||||
self.assertEqual(tree.get('type'), 'network')
|
||||
self.assertEqual(tree.find('./source').get('protocol'), 'sheepdog')
|
||||
self.assertEqual(tree.find('./source').get('name'), name)
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
|
||||
def rbd_connection(self, volume):
|
||||
return {
|
||||
'driver_volume_type': 'rbd',
|
||||
'data': {
|
||||
'name': '%s/%s' % ('rbd', volume['name']),
|
||||
'auth_enabled': CONF.rbd_secret_uuid is not None,
|
||||
'auth_username': CONF.rbd_user,
|
||||
'secret_type': 'ceph',
|
||||
'secret_uuid': CONF.rbd_secret_uuid,
|
||||
}
|
||||
}
|
||||
|
||||
def test_libvirt_rbd_driver(self):
|
||||
libvirt_driver = volume.LibvirtNetVolumeDriver(self.fake_conn)
|
||||
name = 'volume-00000001'
|
||||
vol = {'id': 1, 'name': name}
|
||||
connection_info = self.rbd_connection(vol)
|
||||
disk_info = {
|
||||
"bus": "virtio",
|
||||
"dev": "vde",
|
||||
"type": "disk",
|
||||
}
|
||||
conf = libvirt_driver.connect_volume(connection_info, disk_info)
|
||||
tree = conf.format_dom()
|
||||
self.assertEqual(tree.get('type'), 'network')
|
||||
self.assertEqual(tree.find('./source').get('protocol'), 'rbd')
|
||||
rbd_name = '%s/%s' % ('rbd', name)
|
||||
self.assertEqual(tree.find('./source').get('name'), rbd_name)
|
||||
self.assertEqual(tree.find('./source/auth'), None)
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
|
||||
def test_libvirt_rbd_driver_auth_enabled(self):
|
||||
libvirt_driver = volume.LibvirtNetVolumeDriver(self.fake_conn)
|
||||
name = 'volume-00000001'
|
||||
vol = {'id': 1, 'name': name}
|
||||
connection_info = self.rbd_connection(vol)
|
||||
uuid = '875a8070-d0b9-4949-8b31-104d125c9a64'
|
||||
user = 'foo'
|
||||
secret_type = 'ceph'
|
||||
connection_info['data']['auth_enabled'] = True
|
||||
connection_info['data']['auth_username'] = user
|
||||
connection_info['data']['secret_type'] = secret_type
|
||||
connection_info['data']['secret_uuid'] = uuid
|
||||
disk_info = {
|
||||
"bus": "virtio",
|
||||
"dev": "vde",
|
||||
"type": "disk",
|
||||
}
|
||||
|
||||
conf = libvirt_driver.connect_volume(connection_info, disk_info)
|
||||
tree = conf.format_dom()
|
||||
self.assertEqual(tree.get('type'), 'network')
|
||||
self.assertEqual(tree.find('./source').get('protocol'), 'rbd')
|
||||
rbd_name = '%s/%s' % ('rbd', name)
|
||||
self.assertEqual(tree.find('./source').get('name'), rbd_name)
|
||||
self.assertEqual(tree.find('./auth').get('username'), user)
|
||||
self.assertEqual(tree.find('./auth/secret').get('type'), secret_type)
|
||||
self.assertEqual(tree.find('./auth/secret').get('uuid'), uuid)
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
|
||||
def test_libvirt_rbd_driver_auth_enabled_flags_override(self):
|
||||
libvirt_driver = volume.LibvirtNetVolumeDriver(self.fake_conn)
|
||||
name = 'volume-00000001'
|
||||
vol = {'id': 1, 'name': name}
|
||||
connection_info = self.rbd_connection(vol)
|
||||
uuid = '875a8070-d0b9-4949-8b31-104d125c9a64'
|
||||
user = 'foo'
|
||||
secret_type = 'ceph'
|
||||
connection_info['data']['auth_enabled'] = True
|
||||
connection_info['data']['auth_username'] = user
|
||||
connection_info['data']['secret_type'] = secret_type
|
||||
connection_info['data']['secret_uuid'] = uuid
|
||||
|
||||
flags_uuid = '37152720-1785-11e2-a740-af0c1d8b8e4b'
|
||||
flags_user = 'bar'
|
||||
self.flags(rbd_user=flags_user,
|
||||
rbd_secret_uuid=flags_uuid)
|
||||
disk_info = {
|
||||
"bus": "virtio",
|
||||
"dev": "vde",
|
||||
"type": "disk",
|
||||
}
|
||||
|
||||
conf = libvirt_driver.connect_volume(connection_info, disk_info)
|
||||
tree = conf.format_dom()
|
||||
self.assertEqual(tree.get('type'), 'network')
|
||||
self.assertEqual(tree.find('./source').get('protocol'), 'rbd')
|
||||
rbd_name = '%s/%s' % ('rbd', name)
|
||||
self.assertEqual(tree.find('./source').get('name'), rbd_name)
|
||||
self.assertEqual(tree.find('./auth').get('username'), flags_user)
|
||||
self.assertEqual(tree.find('./auth/secret').get('type'), secret_type)
|
||||
self.assertEqual(tree.find('./auth/secret').get('uuid'), flags_uuid)
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
|
||||
def test_libvirt_rbd_driver_auth_disabled(self):
|
||||
libvirt_driver = volume.LibvirtNetVolumeDriver(self.fake_conn)
|
||||
name = 'volume-00000001'
|
||||
vol = {'id': 1, 'name': name}
|
||||
connection_info = self.rbd_connection(vol)
|
||||
uuid = '875a8070-d0b9-4949-8b31-104d125c9a64'
|
||||
user = 'foo'
|
||||
secret_type = 'ceph'
|
||||
connection_info['data']['auth_enabled'] = False
|
||||
connection_info['data']['auth_username'] = user
|
||||
connection_info['data']['secret_type'] = secret_type
|
||||
connection_info['data']['secret_uuid'] = uuid
|
||||
disk_info = {
|
||||
"bus": "virtio",
|
||||
"dev": "vde",
|
||||
"type": "disk",
|
||||
}
|
||||
|
||||
conf = libvirt_driver.connect_volume(connection_info, disk_info)
|
||||
tree = conf.format_dom()
|
||||
self.assertEqual(tree.get('type'), 'network')
|
||||
self.assertEqual(tree.find('./source').get('protocol'), 'rbd')
|
||||
rbd_name = '%s/%s' % ('rbd', name)
|
||||
self.assertEqual(tree.find('./source').get('name'), rbd_name)
|
||||
self.assertEqual(tree.find('./auth'), None)
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
|
||||
def test_libvirt_rbd_driver_auth_disabled_flags_override(self):
|
||||
libvirt_driver = volume.LibvirtNetVolumeDriver(self.fake_conn)
|
||||
name = 'volume-00000001'
|
||||
vol = {'id': 1, 'name': name}
|
||||
connection_info = self.rbd_connection(vol)
|
||||
uuid = '875a8070-d0b9-4949-8b31-104d125c9a64'
|
||||
user = 'foo'
|
||||
secret_type = 'ceph'
|
||||
connection_info['data']['auth_enabled'] = False
|
||||
connection_info['data']['auth_username'] = user
|
||||
connection_info['data']['secret_type'] = secret_type
|
||||
connection_info['data']['secret_uuid'] = uuid
|
||||
|
||||
# NOTE: Supplying the rbd_secret_uuid will enable authentication
|
||||
# locally in nova-compute even if not enabled in nova-volume/cinder
|
||||
flags_uuid = '37152720-1785-11e2-a740-af0c1d8b8e4b'
|
||||
flags_user = 'bar'
|
||||
self.flags(rbd_user=flags_user,
|
||||
rbd_secret_uuid=flags_uuid)
|
||||
disk_info = {
|
||||
"bus": "virtio",
|
||||
"dev": "vde",
|
||||
"type": "disk",
|
||||
}
|
||||
|
||||
conf = libvirt_driver.connect_volume(connection_info, disk_info)
|
||||
tree = conf.format_dom()
|
||||
self.assertEqual(tree.get('type'), 'network')
|
||||
self.assertEqual(tree.find('./source').get('protocol'), 'rbd')
|
||||
rbd_name = '%s/%s' % ('rbd', name)
|
||||
self.assertEqual(tree.find('./source').get('name'), rbd_name)
|
||||
self.assertEqual(tree.find('./auth').get('username'), flags_user)
|
||||
self.assertEqual(tree.find('./auth/secret').get('type'), secret_type)
|
||||
self.assertEqual(tree.find('./auth/secret').get('uuid'), flags_uuid)
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
|
||||
def test_libvirt_kvm_volume(self):
|
||||
self.stubs.Set(os.path, 'exists', lambda x: True)
|
||||
libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)
|
||||
name = 'volume-00000001'
|
||||
location = '10.0.2.15:3260'
|
||||
iqn = 'iqn.2010-10.org.openstack:%s' % name
|
||||
vol = {'id': 1, 'name': name}
|
||||
connection_info = self.iscsi_connection(vol, location, iqn)
|
||||
disk_info = {
|
||||
"bus": "virtio",
|
||||
"dev": "vde",
|
||||
"type": "disk",
|
||||
}
|
||||
conf = libvirt_driver.connect_volume(connection_info, disk_info)
|
||||
tree = conf.format_dom()
|
||||
dev_str = '/dev/disk/by-path/ip-%s-iscsi-%s-lun-1' % (location, iqn)
|
||||
self.assertEqual(tree.get('type'), 'block')
|
||||
self.assertEqual(tree.find('./source').get('dev'), dev_str)
|
||||
libvirt_driver.disconnect_volume(connection_info, 'vde')
|
||||
|
||||
def test_libvirt_kvm_volume_with_multipath(self):
|
||||
self.flags(libvirt_iscsi_use_multipath=True)
|
||||
self.stubs.Set(os.path, 'exists', lambda x: True)
|
||||
devs = ['/dev/mapper/sda', '/dev/mapper/sdb']
|
||||
self.stubs.Set(self.fake_conn, 'get_all_block_devices', lambda: devs)
|
||||
libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)
|
||||
name = 'volume-00000001'
|
||||
location = '10.0.2.15:3260'
|
||||
iqn = 'iqn.2010-10.org.openstack:%s' % name
|
||||
vol = {'id': 1, 'name': name}
|
||||
connection_info = self.iscsi_connection(vol, location, iqn)
|
||||
mpdev_filepath = '/dev/mapper/foo'
|
||||
connection_info['data']['device_path'] = mpdev_filepath
|
||||
disk_info = {
|
||||
"bus": "virtio",
|
||||
"dev": "vde",
|
||||
"type": "disk",
|
||||
}
|
||||
target_portals = ['fake_portal1', 'fake_portal2']
|
||||
libvirt_driver._get_multipath_device_name = lambda x: mpdev_filepath
|
||||
conf = libvirt_driver.connect_volume(connection_info, disk_info)
|
||||
tree = conf.format_dom()
|
||||
self.assertEqual(tree.find('./source').get('dev'), mpdev_filepath)
|
||||
libvirt_driver.disconnect_volume(connection_info, 'vde')
|
||||
|
||||
def test_libvirt_kvm_volume_with_multipath_getmpdev(self):
|
||||
self.flags(libvirt_iscsi_use_multipath=True)
|
||||
self.stubs.Set(os.path, 'exists', lambda x: True)
|
||||
libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)
|
||||
name0 = 'volume-00000000'
|
||||
location0 = '10.0.2.15:3260'
|
||||
iqn0 = 'iqn.2010-10.org.openstack:%s' % name0
|
||||
vol0 = {'id': 0, 'name': name0}
|
||||
dev0 = '/dev/disk/by-path/ip-%s-iscsi-%s-lun-0' % (location0, iqn0)
|
||||
name = 'volume-00000001'
|
||||
location = '10.0.2.15:3260'
|
||||
iqn = 'iqn.2010-10.org.openstack:%s' % name
|
||||
vol = {'id': 1, 'name': name}
|
||||
dev = '/dev/disk/by-path/ip-%s-iscsi-%s-lun-1' % (location, iqn)
|
||||
devs = [dev0, dev]
|
||||
self.stubs.Set(self.fake_conn, 'get_all_block_devices', lambda: devs)
|
||||
connection_info = self.iscsi_connection(vol, location, iqn)
|
||||
mpdev_filepath = '/dev/mapper/foo'
|
||||
disk_info = {
|
||||
"bus": "virtio",
|
||||
"dev": "vde",
|
||||
"type": "disk",
|
||||
}
|
||||
target_portals = ['fake_portal1', 'fake_portal2']
|
||||
libvirt_driver._get_multipath_device_name = lambda x: mpdev_filepath
|
||||
conf = libvirt_driver.connect_volume(connection_info, disk_info)
|
||||
tree = conf.format_dom()
|
||||
self.assertEqual(tree.find('./source').get('dev'), mpdev_filepath)
|
||||
libvirt_driver.disconnect_volume(connection_info, 'vde')
|
||||
|
||||
def test_libvirt_nfs_driver(self):
|
||||
# NOTE(vish) exists is to make driver assume connecting worked
|
||||
mnt_base = '/mnt'
|
||||
self.flags(nfs_mount_point_base=mnt_base)
|
||||
|
||||
libvirt_driver = volume.LibvirtNFSVolumeDriver(self.fake_conn)
|
||||
export_string = '192.168.1.1:/nfs/share1'
|
||||
name = 'volume-00001'
|
||||
export_mnt_base = os.path.join(mnt_base,
|
||||
libvirt_driver.get_hash_str(export_string))
|
||||
file_path = os.path.join(export_mnt_base, name)
|
||||
|
||||
connection_info = {'data': {'export': export_string, 'name': name}}
|
||||
disk_info = {
|
||||
"bus": "virtio",
|
||||
"dev": "vde",
|
||||
"type": "disk",
|
||||
}
|
||||
conf = libvirt_driver.connect_volume(connection_info, disk_info)
|
||||
tree = conf.format_dom()
|
||||
self.assertEqual(tree.get('type'), 'file')
|
||||
self.assertEqual(tree.find('./source').get('file'), file_path)
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
|
||||
expected_commands = [
|
||||
('stat', export_mnt_base),
|
||||
('mount', '-t', 'nfs', export_string, export_mnt_base)]
|
||||
self.assertEqual(self.executes, expected_commands)
|
||||
|
||||
def aoe_connection(self, shelf, lun):
|
||||
return {
|
||||
'driver_volume_type': 'aoe',
|
||||
'data': {
|
||||
'target_shelf': shelf,
|
||||
'target_lun': lun,
|
||||
}
|
||||
}
|
||||
|
||||
def test_libvirt_aoe_driver(self):
|
||||
# NOTE(jbr_) exists is to make driver assume connecting worked
|
||||
self.stubs.Set(os.path, 'exists', lambda x: True)
|
||||
libvirt_driver = volume.LibvirtAOEVolumeDriver(self.fake_conn)
|
||||
shelf = '100'
|
||||
lun = '1'
|
||||
connection_info = self.aoe_connection(shelf, lun)
|
||||
disk_info = {
|
||||
"bus": "virtio",
|
||||
"dev": "vde",
|
||||
"type": "disk",
|
||||
}
|
||||
conf = libvirt_driver.connect_volume(connection_info, disk_info)
|
||||
tree = conf.format_dom()
|
||||
aoedevpath = '/dev/etherd/e%s.%s' % (shelf, lun)
|
||||
self.assertEqual(tree.get('type'), 'block')
|
||||
self.assertEqual(tree.find('./source').get('dev'), aoedevpath)
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
|
||||
def test_libvirt_glusterfs_driver(self):
|
||||
mnt_base = '/mnt'
|
||||
self.flags(glusterfs_mount_point_base=mnt_base)
|
||||
|
||||
libvirt_driver = volume.LibvirtGlusterfsVolumeDriver(self.fake_conn)
|
||||
export_string = '192.168.1.1:/volume-00001'
|
||||
name = 'volume-00001'
|
||||
export_mnt_base = os.path.join(mnt_base,
|
||||
libvirt_driver.get_hash_str(export_string))
|
||||
file_path = os.path.join(export_mnt_base, name)
|
||||
|
||||
connection_info = {'data': {'export': export_string, 'name': name}}
|
||||
disk_info = {
|
||||
"bus": "virtio",
|
||||
"dev": "vde",
|
||||
"type": "disk",
|
||||
}
|
||||
conf = libvirt_driver.connect_volume(connection_info, disk_info)
|
||||
tree = conf.format_dom()
|
||||
self.assertEqual(tree.get('type'), 'file')
|
||||
self.assertEqual(tree.find('./source').get('file'), file_path)
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
|
||||
expected_commands = [
|
||||
('stat', export_mnt_base),
|
||||
('mount', '-t', 'glusterfs', export_string, export_mnt_base)]
|
||||
self.assertEqual(self.executes, expected_commands)
|
||||
|
||||
def fibrechan_connection(self, volume, location, wwn):
|
||||
return {
|
||||
'driver_volume_type': 'fibrechan',
|
||||
'data': {
|
||||
'volume_id': volume['id'],
|
||||
'target_portal': location,
|
||||
'target_wwn': wwn,
|
||||
'target_lun': 1,
|
||||
}
|
||||
}
|
||||
|
||||
def test_libvirt_fibrechan_driver(self):
|
||||
self.stubs.Set(libvirt_utils, 'get_fc_hbas',
|
||||
fake_libvirt_utils.get_fc_hbas)
|
||||
self.stubs.Set(libvirt_utils, 'get_fc_hbas_info',
|
||||
fake_libvirt_utils.get_fc_hbas_info)
|
||||
# NOTE(vish) exists is to make driver assume connecting worked
|
||||
self.stubs.Set(os.path, 'exists', lambda x: True)
|
||||
self.stubs.Set(os.path, 'realpath', lambda x: '/dev/sdb')
|
||||
libvirt_driver = volume.LibvirtFibreChannelVolumeDriver(self.fake_conn)
|
||||
multipath_devname = '/dev/md-1'
|
||||
devices = {"device": multipath_devname,
|
||||
"devices": [{'device': '/dev/sdb',
|
||||
'address': '1:0:0:1',
|
||||
'host': 1, 'channel': 0,
|
||||
'id': 0, 'lun': 1}]}
|
||||
self.stubs.Set(linuxscsi, 'find_multipath_device', lambda x: devices)
|
||||
self.stubs.Set(linuxscsi, 'remove_device', lambda x: None)
|
||||
location = '10.0.2.15:3260'
|
||||
name = 'volume-00000001'
|
||||
wwn = '1234567890123456'
|
||||
vol = {'id': 1, 'name': name}
|
||||
connection_info = self.fibrechan_connection(vol, location, wwn)
|
||||
mount_device = "vde"
|
||||
disk_info = {
|
||||
"bus": "virtio",
|
||||
"dev": mount_device,
|
||||
"type": "disk"
|
||||
}
|
||||
conf = libvirt_driver.connect_volume(connection_info, disk_info)
|
||||
tree = conf.format_dom()
|
||||
dev_str = '/dev/disk/by-path/pci-0000:05:00.2-fc-0x%s-lun-1' % wwn
|
||||
self.assertEqual(tree.get('type'), 'block')
|
||||
self.assertEqual(tree.find('./source').get('dev'), multipath_devname)
|
||||
connection_info["data"]["devices"] = devices["devices"]
|
||||
libvirt_driver.disconnect_volume(connection_info, mount_device)
|
||||
expected_commands = []
|
||||
self.assertEqual(self.executes, expected_commands)
|
||||
|
||||
self.stubs.Set(libvirt_utils, 'get_fc_hbas',
|
||||
lambda: [])
|
||||
self.stubs.Set(libvirt_utils, 'get_fc_hbas_info',
|
||||
lambda: [])
|
||||
self.assertRaises(exception.NovaException,
|
||||
libvirt_driver.connect_volume,
|
||||
connection_info, disk_info)
|
||||
|
||||
self.stubs.Set(libvirt_utils, 'get_fc_hbas', lambda: [])
|
||||
self.stubs.Set(libvirt_utils, 'get_fc_hbas_info', lambda: [])
|
||||
self.assertRaises(exception.NovaException,
|
||||
libvirt_driver.connect_volume,
|
||||
connection_info, disk_info)
|
||||
|
||||
def test_libvirt_fibrechan_getpci_num(self):
|
||||
libvirt_driver = volume.LibvirtFibreChannelVolumeDriver(self.fake_conn)
|
||||
hba = {'device_path': "/sys/devices/pci0000:00/0000:00:03.0"
|
||||
"/0000:05:00.3/host2/fc_host/host2"}
|
||||
pci_num = libvirt_driver._get_pci_num(hba)
|
||||
self.assertEqual("0000:05:00.3", pci_num)
|
||||
|
||||
hba = {'device_path': "/sys/devices/pci0000:00/0000:00:03.0"
|
||||
"/0000:05:00.3/0000:06:00.6/host2/fc_host/host2"}
|
||||
pci_num = libvirt_driver._get_pci_num(hba)
|
||||
self.assertEqual("0000:06:00.6", pci_num)
|
||||
|
||||
def test_libvirt_scality_driver(self):
|
||||
tempdir = self.useFixture(fixtures.TempDir()).path
|
||||
TEST_MOUNT = os.path.join(tempdir, 'fake_mount')
|
||||
TEST_CONFIG = os.path.join(tempdir, 'fake_config')
|
||||
TEST_VOLDIR = 'volumes'
|
||||
TEST_VOLNAME = 'volume_name'
|
||||
TEST_CONN_INFO = {
|
||||
'data': {
|
||||
'sofs_path': os.path.join(TEST_VOLDIR, TEST_VOLNAME)
|
||||
}
|
||||
}
|
||||
TEST_VOLPATH = os.path.join(TEST_MOUNT,
|
||||
TEST_VOLDIR,
|
||||
TEST_VOLNAME)
|
||||
TEST_DISK_INFO = {
|
||||
"bus": "virtio",
|
||||
"dev": "vde",
|
||||
"type": "disk",
|
||||
}
|
||||
|
||||
open(TEST_CONFIG, "w+").close()
|
||||
os.makedirs(os.path.join(TEST_MOUNT, 'sys'))
|
||||
|
||||
def _access_wrapper(path, flags):
|
||||
if path == '/sbin/mount.sofs':
|
||||
return True
|
||||
else:
|
||||
return os.access(path, flags)
|
||||
|
||||
self.stubs.Set(os, 'access', _access_wrapper)
|
||||
|
||||
self.flags(scality_sofs_config=TEST_CONFIG,
|
||||
scality_sofs_mount_point=TEST_MOUNT)
|
||||
driver = volume.LibvirtScalityVolumeDriver(self.fake_conn)
|
||||
conf = driver.connect_volume(TEST_CONN_INFO, TEST_DISK_INFO)
|
||||
|
||||
tree = conf.format_dom()
|
||||
self.assertEqual(tree.get('type'), 'file')
|
||||
self.assertEqual(tree.find('./source').get('file'), TEST_VOLPATH)
|
|
@ -25,9 +25,9 @@ from nova import exception
|
|||
from nova.openstack.common import importutils
|
||||
from nova.openstack.common import log as logging
|
||||
from nova import test
|
||||
from nova.tests import fake_libvirt_utils
|
||||
from nova.tests.image import fake as fake_image
|
||||
from nova.tests import utils as test_utils
|
||||
from nova.tests.virt.libvirt import fake_libvirt_utils
|
||||
from nova.virt import event as virtevent
|
||||
from nova.virt import fake
|
||||
|
||||
|
@ -67,9 +67,9 @@ class _FakeDriverBackendTestCase(object):
|
|||
else:
|
||||
self.saved_libvirt = None
|
||||
|
||||
import nova.tests.fake_imagebackend as fake_imagebackend
|
||||
import nova.tests.fake_libvirt_utils as fake_libvirt_utils
|
||||
import nova.tests.fakelibvirt as fakelibvirt
|
||||
import nova.tests.virt.libvirt.fake_imagebackend as fake_imagebackend
|
||||
import nova.tests.virt.libvirt.fake_libvirt_utils as fake_libvirt_utils
|
||||
import nova.tests.virt.libvirt.fakelibvirt as fakelibvirt
|
||||
|
||||
sys.modules['libvirt'] = fakelibvirt
|
||||
import nova.virt.libvirt.driver
|
||||
|
|
|
@ -2117,8 +2117,9 @@ class XenAPIBWCountersTestCase(stubs.XenAPITestBase):
|
|||
|
||||
|
||||
# TODO(salvatore-orlando): this class and
|
||||
# nova.tests.test_libvirt.IPTablesFirewallDriverTestCase share a lot of code.
|
||||
# Consider abstracting common code in a base class for firewall driver testing.
|
||||
# nova.tests.virt.test_libvirt.IPTablesFirewallDriverTestCase share a lot of
|
||||
# code. Consider abstracting common code in a base class for firewall driver
|
||||
# testing.
|
||||
class XenAPIDom0IptablesFirewallTestCase(stubs.XenAPITestBase):
|
||||
|
||||
_in_rules = [
|
||||
|
|
Loading…
Reference in New Issue