summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
Diffstat (limited to 'nova')
-rw-r--r--nova/objects/base.py25
-rw-r--r--nova/openstack/common/jsonutils.py3
-rw-r--r--nova/tests/objects/test_objects.py25
-rw-r--r--nova/tests/virt/libvirt/test_libvirt.py123
-rw-r--r--nova/tests/virt/test_virt_drivers.py2
-rw-r--r--nova/tests/virt/xenapi/test_vm_utils.py4
-rwxr-xr-xnova/virt/libvirt/driver.py29
-rw-r--r--nova/virt/xenapi/vm_utils.py28
8 files changed, 192 insertions, 47 deletions
diff --git a/nova/objects/base.py b/nova/objects/base.py
index 147d55c23..c6dc8cc1a 100644
--- a/nova/objects/base.py
+++ b/nova/objects/base.py
@@ -367,6 +367,14 @@ class NovaObject(object):
"""
return self[key]
+ def update(self, updates):
+ """For backwards-compatibility with dict-base objects.
+
+ NOTE(danms): May be removed in the future.
+ """
+ for key, value in updates.items():
+ self[key] = value
+
class ObjectListBase(object):
"""Mixin class for lists of objects.
@@ -464,3 +472,20 @@ class NovaObjectSerializer(nova.openstack.common.rpc.serializer.Serializer):
entity = self._process_iterable(context, self.deserialize_entity,
entity)
return entity
+
+
+def obj_to_primitive(obj):
+ """Recrusively turn an object into a python primitive.
+
+ A NovaObject becomes a dict, and anything that implements ObjectListBase
+ becomes a list.
+ """
+ if isinstance(obj, ObjectListBase):
+ return [obj_to_primitive(x) for x in obj]
+ elif isinstance(obj, NovaObject):
+ result = {}
+ for key, value in obj.iteritems():
+ result[key] = obj_to_primitive(value)
+ return result
+ else:
+ return obj
diff --git a/nova/openstack/common/jsonutils.py b/nova/openstack/common/jsonutils.py
index 11af66daf..a260efad7 100644
--- a/nova/openstack/common/jsonutils.py
+++ b/nova/openstack/common/jsonutils.py
@@ -41,6 +41,7 @@ import json
import types
import xmlrpclib
+import netaddr
import six
from nova.openstack.common import timeutils
@@ -137,6 +138,8 @@ def to_primitive(value, convert_instances=False, convert_datetime=True,
# Likely an instance of something. Watch for cycles.
# Ignore class member vars.
return recursive(value.__dict__, level=level + 1)
+ elif isinstance(value, netaddr.IPAddress):
+ return six.text_type(value)
else:
if any(test(value) for test in _nasty_type_tests):
return six.text_type(value)
diff --git a/nova/tests/objects/test_objects.py b/nova/tests/objects/test_objects.py
index 40ad8bb81..03a270386 100644
--- a/nova/tests/objects/test_objects.py
+++ b/nova/tests/objects/test_objects.py
@@ -178,6 +178,31 @@ class TestUtils(test.TestCase):
self.assertEqual(utils.dt_deserializer(None, None), None)
self.assertRaises(ValueError, utils.dt_deserializer, None, 'foo')
+ def test_obj_to_primitive_list(self):
+ class MyList(base.ObjectListBase, base.NovaObject):
+ pass
+ mylist = MyList()
+ mylist.objects = [1, 2, 3]
+ self.assertEqual([1, 2, 3], base.obj_to_primitive(mylist))
+
+ def test_obj_to_primitive_dict(self):
+ myobj = MyObj()
+ myobj.foo = 1
+ myobj.bar = 'foo'
+ self.assertEqual({'foo': 1, 'bar': 'foo'},
+ base.obj_to_primitive(myobj))
+
+ def test_obj_to_primitive_recursive(self):
+ class MyList(base.ObjectListBase, base.NovaObject):
+ pass
+
+ mylist = MyList()
+ mylist.objects = [MyObj(), MyObj()]
+ for i, value in enumerate(mylist):
+ value.foo = i
+ self.assertEqual([{'foo': 0}, {'foo': 1}],
+ base.obj_to_primitive(mylist))
+
class _BaseTestCase(test.TestCase):
def setUp(self):
diff --git a/nova/tests/virt/libvirt/test_libvirt.py b/nova/tests/virt/libvirt/test_libvirt.py
index 3c658a7f5..000910c4c 100644
--- a/nova/tests/virt/libvirt/test_libvirt.py
+++ b/nova/tests/virt/libvirt/test_libvirt.py
@@ -26,6 +26,7 @@ import re
import shutil
import tempfile
+from eventlet import greenthread
from lxml import etree
from oslo.config import cfg
from xml.dom import minidom
@@ -77,6 +78,7 @@ CONF.import_opt('compute_manager', 'nova.service')
CONF.import_opt('host', 'nova.netconf')
CONF.import_opt('my_ip', 'nova.netconf')
CONF.import_opt('base_dir_name', 'nova.virt.libvirt.imagecache')
+CONF.import_opt('instances_path', 'nova.compute.manager')
_fake_network_info = fake_network.fake_get_instance_nw_info
_fake_stub_out_get_nw_info = fake_network.stub_out_nw_api_get_instance_nw_info
@@ -286,8 +288,9 @@ class LibvirtConnTestCase(test.TestCase):
self.user_id = 'fake'
self.project_id = 'fake'
self.context = context.get_admin_context()
- self.flags(instances_path='')
- self.flags(libvirt_snapshots_directory='')
+ temp_dir = self.useFixture(fixtures.TempDir()).path
+ self.flags(instances_path=temp_dir)
+ self.flags(libvirt_snapshots_directory=temp_dir)
self.useFixture(fixtures.MonkeyPatch(
'nova.virt.libvirt.driver.libvirt_utils',
fake_libvirt_utils))
@@ -343,6 +346,9 @@ class LibvirtConnTestCase(test.TestCase):
'extra_specs': {},
'system_metadata': sys_meta}
+ def relpath(self, path):
+ return os.path.relpath(path, CONF.instances_path)
+
def tearDown(self):
nova.tests.image.fake.FakeImageService_reset()
super(LibvirtConnTestCase, self).tearDown()
@@ -2078,8 +2084,8 @@ class LibvirtConnTestCase(test.TestCase):
else:
suffix = ''
if expect_kernel:
- check = (lambda t: t.find('./os/kernel').text.split(
- '/')[1], 'kernel' + suffix)
+ check = (lambda t: self.relpath(t.find('./os/kernel').text).
+ split('/')[1], 'kernel' + suffix)
else:
check = (lambda t: t.find('./os/kernel'), None)
check_list.append(check)
@@ -2094,8 +2100,8 @@ class LibvirtConnTestCase(test.TestCase):
check_list.append(check)
if expect_ramdisk:
- check = (lambda t: t.find('./os/initrd').text.split(
- '/')[1], 'ramdisk' + suffix)
+ check = (lambda t: self.relpath(t.find('./os/initrd').text).
+ split('/')[1], 'ramdisk' + suffix)
else:
check = (lambda t: t.find('./os/initrd'), None)
check_list.append(check)
@@ -2146,8 +2152,9 @@ class LibvirtConnTestCase(test.TestCase):
check = (lambda t: t.findall('./devices/serial')[1].get(
'type'), 'pty')
check_list.append(check)
- check = (lambda t: t.findall('./devices/serial/source')[0].get(
- 'path').split('/')[1], 'console.log')
+ check = (lambda t: self.relpath(t.findall(
+ './devices/serial/source')[0].get('path')).
+ split('/')[1], 'console.log')
check_list.append(check)
else:
check = (lambda t: t.find('./devices/console').get(
@@ -2159,16 +2166,16 @@ class LibvirtConnTestCase(test.TestCase):
(lambda t: t.find('./memory').text, '2097152')]
if rescue:
common_checks += [
- (lambda t: t.findall('./devices/disk/source')[0].get(
- 'file').split('/')[1], 'disk.rescue'),
- (lambda t: t.findall('./devices/disk/source')[1].get(
- 'file').split('/')[1], 'disk')]
+ (lambda t: self.relpath(t.findall('./devices/disk/source')[0].
+ get('file')).split('/')[1], 'disk.rescue'),
+ (lambda t: self.relpath(t.findall('./devices/disk/source')[1].
+ get('file')).split('/')[1], 'disk')]
else:
- common_checks += [(lambda t: t.findall(
- './devices/disk/source')[0].get('file').split('/')[1],
+ common_checks += [(lambda t: self.relpath(t.findall(
+ './devices/disk/source')[0].get('file')).split('/')[1],
'disk')]
- common_checks += [(lambda t: t.findall(
- './devices/disk/source')[1].get('file').split('/')[1],
+ common_checks += [(lambda t: self.relpath(t.findall(
+ './devices/disk/source')[1].get('file')).split('/')[1],
'disk.local')]
for (libvirt_type, (expected_uri, checks)) in type_uri_map.iteritems():
@@ -3165,6 +3172,90 @@ class LibvirtConnTestCase(test.TestCase):
self.stubs.Set(os.path, 'exists', fake_os_path_exists)
conn.destroy(instance, [], None, False)
+ def test_reboot_different_ids(self):
+ class FakeLoopingCall:
+ def start(self, *a, **k):
+ return self
+
+ def wait(self):
+ return None
+
+ self.flags(libvirt_wait_soft_reboot_seconds=1)
+ info_tuple = ('fake', 'fake', 'fake', 'also_fake')
+ self.reboot_create_called = False
+
+ # Mock domain
+ mock_domain = self.mox.CreateMock(libvirt.virDomain)
+ mock_domain.info().AndReturn(
+ (libvirt_driver.VIR_DOMAIN_RUNNING,) + info_tuple)
+ mock_domain.ID().AndReturn('some_fake_id')
+ mock_domain.shutdown()
+ mock_domain.info().AndReturn(
+ (libvirt_driver.VIR_DOMAIN_CRASHED,) + info_tuple)
+ mock_domain.ID().AndReturn('some_other_fake_id')
+
+ self.mox.ReplayAll()
+
+ def fake_lookup_by_name(instance_name):
+ return mock_domain
+
+ def fake_create_domain(**kwargs):
+ self.reboot_create_called = True
+
+ conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
+ instance = {"name": "instancename", "id": "instanceid",
+ "uuid": "875a8070-d0b9-4949-8b31-104d125c9a64"}
+ self.stubs.Set(conn, '_lookup_by_name', fake_lookup_by_name)
+ self.stubs.Set(conn, '_create_domain', fake_create_domain)
+ self.stubs.Set(loopingcall, 'FixedIntervalLoopingCall',
+ lambda *a, **k: FakeLoopingCall())
+ conn.reboot(None, instance, [])
+ self.assertTrue(self.reboot_create_called)
+
+ def test_reboot_same_ids(self):
+ class FakeLoopingCall:
+ def start(self, *a, **k):
+ return self
+
+ def wait(self):
+ return None
+
+ self.flags(libvirt_wait_soft_reboot_seconds=1)
+ info_tuple = ('fake', 'fake', 'fake', 'also_fake')
+ self.reboot_hard_reboot_called = False
+
+ # Mock domain
+ mock_domain = self.mox.CreateMock(libvirt.virDomain)
+ mock_domain.info().AndReturn(
+ (libvirt_driver.VIR_DOMAIN_RUNNING,) + info_tuple)
+ mock_domain.ID().AndReturn('some_fake_id')
+ mock_domain.shutdown()
+ mock_domain.info().AndReturn(
+ (libvirt_driver.VIR_DOMAIN_CRASHED,) + info_tuple)
+ mock_domain.ID().AndReturn('some_fake_id')
+
+ self.mox.ReplayAll()
+
+ def fake_lookup_by_name(instance_name):
+ return mock_domain
+
+ def fake_hard_reboot(*args, **kwargs):
+ self.reboot_hard_reboot_called = True
+
+ def fake_sleep(interval):
+ pass
+
+ conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
+ instance = {"name": "instancename", "id": "instanceid",
+ "uuid": "875a8070-d0b9-4949-8b31-104d125c9a64"}
+ self.stubs.Set(conn, '_lookup_by_name', fake_lookup_by_name)
+ self.stubs.Set(greenthread, 'sleep', fake_sleep)
+ self.stubs.Set(conn, '_hard_reboot', fake_hard_reboot)
+ self.stubs.Set(loopingcall, 'FixedIntervalLoopingCall',
+ lambda *a, **k: FakeLoopingCall())
+ conn.reboot(None, instance, [])
+ self.assertTrue(self.reboot_hard_reboot_called)
+
def test_destroy_undefines(self):
mock = self.mox.CreateMock(libvirt.virDomain)
mock.ID()
diff --git a/nova/tests/virt/test_virt_drivers.py b/nova/tests/virt/test_virt_drivers.py
index 5c2df9854..a21993597 100644
--- a/nova/tests/virt/test_virt_drivers.py
+++ b/nova/tests/virt/test_virt_drivers.py
@@ -60,7 +60,7 @@ class _FakeDriverBackendTestCase(object):
# So that the _supports_direct_io does the test based
# on the current working directory, instead of the
# default instances_path which doesn't exist
- self.flags(instances_path='')
+ self.flags(instances_path=self.useFixture(fixtures.TempDir()).path)
# Put fakelibvirt in place
if 'libvirt' in sys.modules:
diff --git a/nova/tests/virt/xenapi/test_vm_utils.py b/nova/tests/virt/xenapi/test_vm_utils.py
index 68caab651..6884ab5a8 100644
--- a/nova/tests/virt/xenapi/test_vm_utils.py
+++ b/nova/tests/virt/xenapi/test_vm_utils.py
@@ -266,7 +266,7 @@ class FetchVhdImageTestCase(test.TestCase):
self._apply_stubouts()
self._common_params_setup(True)
- vm_utils._add_bittorrent_params(self.params)
+ vm_utils._add_bittorrent_params(self.image_id, self.params)
vm_utils._fetch_using_dom0_plugin_with_retry(self.context,
self.session, self.image_id, "bittorrent", self.params,
@@ -289,7 +289,7 @@ class FetchVhdImageTestCase(test.TestCase):
self._common_params_setup(True)
self.mox.StubOutWithMock(self.session, 'call_xenapi')
- vm_utils._add_bittorrent_params(self.params)
+ vm_utils._add_bittorrent_params(self.image_id, self.params)
vm_utils._fetch_using_dom0_plugin_with_retry(self.context,
self.session, self.image_id, "bittorrent", self.params,
diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py
index f4ba24cc4..104965d49 100755
--- a/nova/virt/libvirt/driver.py
+++ b/nova/virt/libvirt/driver.py
@@ -1386,19 +1386,22 @@ class LibvirtDriver(driver.ComputeDriver):
state = LIBVIRT_POWER_STATE[state]
new_domid = dom.ID()
- if state in [power_state.SHUTDOWN,
- power_state.CRASHED]:
- LOG.info(_("Instance shutdown successfully."),
- instance=instance)
- self._create_domain(domain=dom)
- timer = loopingcall.FixedIntervalLoopingCall(
- self._wait_for_running, instance)
- timer.start(interval=0.5).wait()
- return True
- elif old_domid != new_domid:
- LOG.info(_("Instance may have been rebooted during soft "
- "reboot, so return now."), instance=instance)
- return True
+ # NOTE(ivoks): By checking domain IDs, we make sure we are
+ # not recreating domain that's already running.
+ if old_domid != new_domid:
+ if state in [power_state.SHUTDOWN,
+ power_state.CRASHED]:
+ LOG.info(_("Instance shutdown successfully."),
+ instance=instance)
+ self._create_domain(domain=dom)
+ timer = loopingcall.FixedIntervalLoopingCall(
+ self._wait_for_running, instance)
+ timer.start(interval=0.5).wait()
+ return True
+ else:
+ LOG.info(_("Instance may have been rebooted during soft "
+ "reboot, so return now."), instance=instance)
+ return True
greenthread.sleep(1)
return False
diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py
index ac8c9c58b..6e9f09184 100644
--- a/nova/virt/xenapi/vm_utils.py
+++ b/nova/virt/xenapi/vm_utils.py
@@ -1142,7 +1142,7 @@ def _fetch_vhd_image(context, session, instance, image_id):
if _image_uses_bittorrent(context, instance):
plugin_name = 'bittorrent'
callback = None
- _add_bittorrent_params(params)
+ _add_bittorrent_params(image_id, params)
else:
plugin_name = 'glance'
callback = _generate_glance_callback(context)
@@ -1180,20 +1180,18 @@ def _generate_glance_callback(context):
return pick_glance
-def _add_bittorrent_params(params):
- params['torrent_base_url'] = CONF.xenapi_torrent_base_url
- params['torrent_seed_duration'] = CONF.xenapi_torrent_seed_duration
- params['torrent_seed_chance'] = CONF.xenapi_torrent_seed_chance
- params['torrent_max_last_accessed'] =\
- CONF.xenapi_torrent_max_last_accessed
- params['torrent_listen_port_start'] =\
- CONF.xenapi_torrent_listen_port_start
- params['torrent_listen_port_end'] =\
- CONF.xenapi_torrent_listen_port_end
- params['torrent_download_stall_cutoff'] =\
- CONF.xenapi_torrent_download_stall_cutoff
- params['torrent_max_seeder_processes_per_host'] =\
- CONF.xenapi_torrent_max_seeder_processes_per_host
+def _add_bittorrent_params(image_id, params):
+ params['torrent_url'] = urlparse.urljoin(CONF.xenapi_torrent_base_url,
+ "%s.torrent" % image_id)
+ params['torrent_seed_duration'] = CONF.xenapi_torrent_seed_duration
+ params['torrent_seed_chance'] = CONF.xenapi_torrent_seed_chance
+ params['torrent_max_last_accessed'] = CONF.xenapi_torrent_max_last_accessed
+ params['torrent_listen_port_start'] = CONF.xenapi_torrent_listen_port_start
+ params['torrent_listen_port_end'] = CONF.xenapi_torrent_listen_port_end
+ params['torrent_download_stall_cutoff'] = \
+ CONF.xenapi_torrent_download_stall_cutoff
+ params['torrent_max_seeder_processes_per_host'] = \
+ CONF.xenapi_torrent_max_seeder_processes_per_host
def _get_vdi_chain_size(session, vdi_uuid):