diff options
Diffstat (limited to 'nova')
-rw-r--r-- | nova/objects/base.py | 25 | ||||
-rw-r--r-- | nova/openstack/common/jsonutils.py | 3 | ||||
-rw-r--r-- | nova/tests/objects/test_objects.py | 25 | ||||
-rw-r--r-- | nova/tests/virt/libvirt/test_libvirt.py | 123 | ||||
-rw-r--r-- | nova/tests/virt/test_virt_drivers.py | 2 | ||||
-rw-r--r-- | nova/tests/virt/xenapi/test_vm_utils.py | 4 | ||||
-rwxr-xr-x | nova/virt/libvirt/driver.py | 29 | ||||
-rw-r--r-- | nova/virt/xenapi/vm_utils.py | 28 |
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): |