From c173b6bef17d8efe64b43664cc39d81a1c31f3b8 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 24 Aug 2011 15:53:23 +0100 Subject: Do not require --bridge_interface for FlatDHCPManager Unlike VlanManager, FlatDHCPManager actually works fine without a bridge interface on single host deployments. --- bin/nova-manage | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/nova-manage b/bin/nova-manage index 2e0bd0ecb..bd42c24df 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -714,8 +714,7 @@ class NetworkCommands(object): bridge_interface = bridge_interface or FLAGS.flat_interface or \ FLAGS.vlan_interface if not bridge_interface: - interface_required = ['nova.network.manager.FlatDHCPManager', - 'nova.network.manager.VlanManager'] + interface_required = ['nova.network.manager.VlanManager'] if FLAGS.network_manager in interface_required: raise exception.NetworkNotCreated(req='--bridge_interface') -- cgit From edc43980ff56777e8200022f888c7170ca9baaea Mon Sep 17 00:00:00 2001 From: Chuck Short Date: Tue, 30 Aug 2011 11:26:59 -0400 Subject: Use getCapabilities rather than getInfo() since some versions of libvirt dont provide dmi information --- nova/virt/libvirt/connection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 363a20ed0..6ae458537 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -196,7 +196,7 @@ class LibvirtConnection(driver.ComputeDriver): def _test_connection(self): try: - self._wrapped_conn.getInfo() + self._wrapped_conn.geCapabilities() return True except libvirt.libvirtError as e: if e.get_error_code() == libvirt.VIR_ERR_SYSTEM_ERROR and \ -- cgit From 9773d900d35316edbad4468a869ca62a353d3114 Mon Sep 17 00:00:00 2001 From: Tushar Patil Date: Fri, 2 Sep 2011 12:34:14 -0700 Subject: Fix for LP Bug #839269 --- nova/db/api.py | 6 ++++-- nova/db/sqlalchemy/api.py | 5 +++-- nova/network/manager.py | 3 ++- nova/tests/test_network.py | 3 ++- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/nova/db/api.py b/nova/db/api.py index 148887635..efc088e35 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -324,13 +324,15 @@ def migration_get_by_instance_and_status(context, instance_uuid, status): #################### -def fixed_ip_associate(context, address, instance_id, network_id=None): +def fixed_ip_associate(context, address, instance_id, network_id=None, + reserved=False): """Associate fixed ip to instance. Raises if fixed ip is not available. """ - return IMPL.fixed_ip_associate(context, address, instance_id, network_id) + return IMPL.fixed_ip_associate(context, address, instance_id, network_id, + reserved) def fixed_ip_associate_pool(context, network_id, instance_id=None, host=None): diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index b99667afc..e0be8454e 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -669,14 +669,15 @@ def floating_ip_update(context, address, values): @require_admin_context -def fixed_ip_associate(context, address, instance_id, network_id=None): +def fixed_ip_associate(context, address, instance_id, network_id=None, + reserved=False): session = get_session() with session.begin(): network_or_none = or_(models.FixedIp.network_id == network_id, models.FixedIp.network_id == None) fixed_ip_ref = session.query(models.FixedIp).\ filter(network_or_none).\ - filter_by(reserved=False).\ + filter_by(reserved=reserved).\ filter_by(deleted=False).\ filter_by(address=address).\ with_lockmode('update').\ diff --git a/nova/network/manager.py b/nova/network/manager.py index e6b30d1a0..90f414ee2 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -991,7 +991,8 @@ class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager): address = network['vpn_private_address'] self.db.fixed_ip_associate(context, address, - instance_id) + instance_id, + reserved=True) else: address = kwargs.get('address', None) if address: diff --git a/nova/tests/test_network.py b/nova/tests/test_network.py index 25ff940f0..2347544de 100644 --- a/nova/tests/test_network.py +++ b/nova/tests/test_network.py @@ -264,7 +264,8 @@ class VlanNetworkTestCase(test.TestCase): db.fixed_ip_associate(mox.IgnoreArg(), mox.IgnoreArg(), - mox.IgnoreArg()).AndReturn('192.168.0.1') + mox.IgnoreArg(), + reserved=True).AndReturn('192.168.0.1') db.fixed_ip_update(mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg()) -- cgit From dd7aa0234080d5c3512d0e9bab831a621aac10aa Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 2 Sep 2011 16:30:52 -0400 Subject: use 'qemu-image resize' rather than 'truncate' to grow image files qcow-image is capable of growing qcow formated disks in addition to being able to grow a qcow formated one. (LP: #836759) --- nova/virt/disk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/virt/disk.py b/nova/virt/disk.py index 52b2881e8..50c7c40e9 100644 --- a/nova/virt/disk.py +++ b/nova/virt/disk.py @@ -58,7 +58,7 @@ def extend(image, size): file_size = os.path.getsize(image) if file_size >= size: return - utils.execute('truncate', '-s', size, image) + utils.execute('qemu-img', 'resize', image, size) # NOTE(vish): attempts to resize filesystem utils.execute('e2fsck', '-fp', image, check_exit_code=False) utils.execute('resize2fs', image, check_exit_code=False) -- cgit From d2b9299408f07f995fffc8b8559f52ee6adeeaad Mon Sep 17 00:00:00 2001 From: "Kevin L. Mitchell" Date: Wed, 7 Sep 2011 18:01:52 -0500 Subject: spread-first strategy --- nova/scheduler/abstract_scheduler.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nova/scheduler/abstract_scheduler.py b/nova/scheduler/abstract_scheduler.py index 7f17b642f..a81fa53cd 100644 --- a/nova/scheduler/abstract_scheduler.py +++ b/nova/scheduler/abstract_scheduler.py @@ -20,8 +20,9 @@ customize the behavior: filter_hosts() and weigh_hosts(). The default behavior is to simply select all hosts and weight them the same. """ -import operator import json +import operator +import random import M2Crypto @@ -40,6 +41,8 @@ from nova.scheduler import api from nova.scheduler import driver FLAGS = flags.FLAGS +flags.DEFINE_boolean('spread_first', False, + 'Use a spread-first zone scheduler strategy') LOG = logging.getLogger('nova.scheduler.abstract_scheduler') -- cgit From ad25b7aa2ad744607b20432d635f70cc645cc6f6 Mon Sep 17 00:00:00 2001 From: "Kevin L. Mitchell" Date: Wed, 7 Sep 2011 18:08:39 -0500 Subject: actually shuffle the weighted_hosts list... --- nova/scheduler/abstract_scheduler.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nova/scheduler/abstract_scheduler.py b/nova/scheduler/abstract_scheduler.py index a81fa53cd..b4c2bf4f1 100644 --- a/nova/scheduler/abstract_scheduler.py +++ b/nova/scheduler/abstract_scheduler.py @@ -295,6 +295,8 @@ class AbstractScheduler(driver.Scheduler): "child_zone": child_zone, "child_blob": weighting["blob"]} weighted_hosts.append(host_dict) + if FLAGS.spread_first: + random.shuffle(weighted_hosts) weighted_hosts.sort(key=operator.itemgetter('weight')) return weighted_hosts -- cgit From 98a5e149395ee58d1830d4671e2c70aaf0008585 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 8 Sep 2011 04:45:04 -0700 Subject: fixes vncproxy service listening on rabbit --- bin/nova-vncproxy | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/bin/nova-vncproxy b/bin/nova-vncproxy index dc08e2433..8e75451cb 100755 --- a/bin/nova-vncproxy +++ b/bin/nova-vncproxy @@ -107,10 +107,13 @@ if __name__ == "__main__": else: with_auth = auth.VNCNovaAuthMiddleware(with_logging) - server = wsgi.Server("VNC Proxy", - with_auth, - host=FLAGS.vncproxy_host, - port=FLAGS.vncproxy_port) - server.start_tcp(handle_flash_socket_policy, 843, host=FLAGS.vncproxy_host) - service.serve(server) + wsgi_server = wsgi.Server("VNC Proxy", + with_auth, + host=FLAGS.vncproxy_host, + port=FLAGS.vncproxy_port) + wsgi_server.start_tcp(handle_flash_socket_policy, + 843, + host=FLAGS.vncproxy_host) + server = service.Service.create(binary='nova-vncproxy') + service.serve(wsgi_server, server) service.wait() -- cgit From 212ec3af4b11a770d7e4cf7869b1865b0f067e5c Mon Sep 17 00:00:00 2001 From: Chuck Short Date: Thu, 8 Sep 2011 10:52:29 -0400 Subject: Clean up shutdown of lxc containers --- nova/virt/disk.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/nova/virt/disk.py b/nova/virt/disk.py index 52b2881e8..12a3a64ca 100644 --- a/nova/virt/disk.py +++ b/nova/virt/disk.py @@ -148,16 +148,17 @@ def destroy_container(target, instance, nbd=False): LXC does not support qcow2 images yet. """ + out, err = utils.execute('mount', run_as_root=True) + for loop in out.splitlines(): + if instance['name'] in loop: + device = loop.split()[0] + try: container_dir = '%s/rootfs' % target utils.execute('umount', container_dir, run_as_root=True) - finally: - out, err = utils.execute('losetup', '-a', run_as_root=True) - for loop in out.splitlines(): - if instance['name'] in loop: - device = loop.split(loop, ':') - _unlink_device(device, nbd) - + _unlink_device(device, nbd) + except Exception, exn: + LOG.exception(_('Failed to remove container: %s'), exn) def _link_device(image, nbd): """Link image to device using loopback or nbd""" -- cgit From aec647b3b42c4cd56a9509c2d1ac25ff12b0664e Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Thu, 8 Sep 2011 16:10:03 -0500 Subject: First pass at adding reboot_type to reboot codepath. --- nova/api/openstack/servers.py | 5 ++--- nova/compute/api.py | 5 +++-- nova/compute/manager.py | 4 ++-- nova/tests/api/openstack/test_servers.py | 2 +- nova/tests/test_compute.py | 15 ++++++++++++--- nova/tests/test_virt_drivers.py | 3 ++- nova/tests/test_vmwareapi.py | 3 ++- nova/virt/driver.py | 3 ++- nova/virt/fake.py | 2 +- nova/virt/hyperv.py | 2 +- nova/virt/vmwareapi_conn.py | 2 +- nova/virt/xenapi/vmops.py | 9 +++++++-- nova/virt/xenapi_conn.py | 4 ++-- 13 files changed, 38 insertions(+), 21 deletions(-) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index d084ac360..f5447edc5 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -334,9 +334,8 @@ class Controller(object): LOG.exception(msg) raise exc.HTTPBadRequest(explanation=msg) try: - # TODO(gundlach): pass reboot_type, support soft reboot in - # virt driver - self.compute_api.reboot(req.environ['nova.context'], id) + self.compute_api.reboot(req.environ['nova.context'], id, + reboot_type) except Exception, e: LOG.exception(_("Error in reboot %s"), e) raise exc.HTTPUnprocessableEntity() diff --git a/nova/compute/api.py b/nova/compute/api.py index 4e2944bb7..b0ea044c5 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -1042,13 +1042,14 @@ class API(base.Base): return recv_meta @scheduler_api.reroute_compute("reboot") - def reboot(self, context, instance_id): + def reboot(self, context, instance_id, reboot_type): """Reboot the given instance.""" self.update(context, instance_id, vm_state=vm_states.ACTIVE, task_state=task_states.REBOOTING) - self._cast_compute_message('reboot_instance', context, instance_id) + self._cast_compute_message('reboot_instance', context, instance_id, + reboot_type) @scheduler_api.reroute_compute("rebuild") def rebuild(self, context, instance_id, image_href, admin_password, diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 0477db745..0be12297f 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -579,7 +579,7 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) @checks_instance_lock - def reboot_instance(self, context, instance_id): + def reboot_instance(self, context, instance_id, reboot_type="SOFT"): """Reboot an instance on this host.""" LOG.audit(_("Rebooting instance %s"), instance_id, context=context) context = context.elevated() @@ -601,7 +601,7 @@ class ComputeManager(manager.SchedulerDependentManager): context=context) network_info = self._get_instance_nw_info(context, instance_ref) - self.driver.reboot(instance_ref, network_info) + self.driver.reboot(instance_ref, network_info, reboot_type) current_power_state = self._get_power_state(context, instance_ref) self._instance_update(context, diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 2ef687709..d063a60c2 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -3615,7 +3615,7 @@ class TestGetKernelRamdiskFromImage(test.TestCase): self.assertRaises(exception.NotFound, self._get_k_r, image_meta) def test_ami_no_ramdisk(self): - """If an ami is missing a ramdisk, return kernel ID and None for + """If an ami is missing a ramdisk, return kernel ID and None for ramdisk ID """ image_meta = {'id': 1, 'status': 'active', 'container_format': 'ami', diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index 65fdffbd6..4d463572b 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -300,11 +300,20 @@ class ComputeTestCase(test.TestCase): self.compute.resume_instance(self.context, instance_id) self.compute.terminate_instance(self.context, instance_id) - def test_reboot(self): - """Ensure instance can be rebooted""" + def test_soft_reboot(self): + """Ensure instance can be soft rebooted""" instance_id = self._create_instance() + reboot_type = "SOFT" self.compute.run_instance(self.context, instance_id) - self.compute.reboot_instance(self.context, instance_id) + self.compute.reboot_instance(self.context, instance_id, reboot_type) + self.compute.terminate_instance(self.context, instance_id) + + def test_hard_reboot(self): + """Ensure instance can be hard rebooted""" + instance_id = self._create_instance() + reboot_type = "HARD" + self.compute.run_instance(self.context, instance_id) + self.compute.reboot_instance(self.context, instance_id, reboot_type) self.compute.terminate_instance(self.context, instance_id) def test_set_admin_password(self): diff --git a/nova/tests/test_virt_drivers.py b/nova/tests/test_virt_drivers.py index 480247c91..440d3401b 100644 --- a/nova/tests/test_virt_drivers.py +++ b/nova/tests/test_virt_drivers.py @@ -103,8 +103,9 @@ class _VirtDriverTestCase(test.TestCase): def test_reboot(self): instance_ref = test_utils.get_test_instance() network_info = test_utils.get_test_network_info() + reboot_type = "SOFT" self.connection.spawn(self.ctxt, instance_ref, network_info) - self.connection.reboot(instance_ref, network_info) + self.connection.reboot(instance_ref, network_info, reboot_type) @catch_notimplementederror def test_get_host_ip_addr(self): diff --git a/nova/tests/test_vmwareapi.py b/nova/tests/test_vmwareapi.py index 06daf46e8..e6da1690f 100644 --- a/nova/tests/test_vmwareapi.py +++ b/nova/tests/test_vmwareapi.py @@ -170,7 +170,8 @@ class VMWareAPIVMTestCase(test.TestCase): self._create_vm() info = self.conn.get_info(1) self._check_vm_info(info, power_state.RUNNING) - self.conn.reboot(self.instance, self.network_info) + reboot_type = "SOFT" + self.conn.reboot(self.instance, self.network_info, reboot_type) info = self.conn.get_info(1) self._check_vm_info(info, power_state.RUNNING) diff --git a/nova/virt/driver.py b/nova/virt/driver.py index d05b51bd9..301346c6b 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -165,12 +165,13 @@ class ComputeDriver(object): # TODO(Vek): Need to pass context in for access to auth_token raise NotImplementedError() - def reboot(self, instance, network_info): + def reboot(self, instance, network_info, reboot_type): """Reboot the specified instance. :param instance: Instance object as returned by DB layer. :param network_info: :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info` + :param reboot_type: Either a HARD or SOFT reboot """ # TODO(Vek): Need to pass context in for access to auth_token raise NotImplementedError() diff --git a/nova/virt/fake.py b/nova/virt/fake.py index d5e2bf31b..3596d8353 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -103,7 +103,7 @@ class FakeConnection(driver.ComputeDriver): if not instance['name'] in self.instances: raise exception.InstanceNotRunning() - def reboot(self, instance, network_info): + def reboot(self, instance, network_info, reboot_type): pass def get_host_ip_addr(self): diff --git a/nova/virt/hyperv.py b/nova/virt/hyperv.py index 03a78db1f..76925b405 100644 --- a/nova/virt/hyperv.py +++ b/nova/virt/hyperv.py @@ -367,7 +367,7 @@ class HyperVConnection(driver.ComputeDriver): wmi_obj.Properties_.Item(prop).Value return newinst - def reboot(self, instance, network_info): + def reboot(self, instance, network_info, reboot_type): """Reboot the specified instance.""" vm = self._lookup(instance.name) if vm is None: diff --git a/nova/virt/vmwareapi_conn.py b/nova/virt/vmwareapi_conn.py index 243ee64f5..fa89a8f45 100644 --- a/nova/virt/vmwareapi_conn.py +++ b/nova/virt/vmwareapi_conn.py @@ -133,7 +133,7 @@ class VMWareESXConnection(driver.ComputeDriver): """Create snapshot from a running VM instance.""" self._vmops.snapshot(context, instance, name) - def reboot(self, instance, network_info): + def reboot(self, instance, network_info, reboot_type): """Reboot VM instance.""" self._vmops.reboot(instance, network_info) diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index c5f105f40..b7d6a40b4 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -617,10 +617,15 @@ class VMOps(object): str(new_disk_size)) LOG.debug(_("Resize instance %s complete") % (instance.name)) - def reboot(self, instance): + def reboot(self, instance, reboot_type): """Reboot VM instance.""" vm_ref = self._get_vm_opaque_ref(instance) - task = self._session.call_xenapi('Async.VM.clean_reboot', vm_ref) + + if reboot_type == "HARD": + task = self._session.call_xenapi('Async.VM.hard_reboot', vm_ref) + else: + task = self._session.call_xenapi('Async.VM.clean_reboot', vm_ref) + self._session.wait_for_task(task, instance.id) def get_agent_version(self, instance, timeout=None): diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index 0d23e7689..f6dbc19f8 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -203,9 +203,9 @@ class XenAPIConnection(driver.ComputeDriver): """ Create snapshot from a running VM instance """ self._vmops.snapshot(context, instance, image_id) - def reboot(self, instance, network_info): + def reboot(self, instance, network_info, reboot_type): """Reboot VM instance""" - self._vmops.reboot(instance) + self._vmops.reboot(instance, reboot_type) def set_admin_password(self, instance, new_pass): """Set the root/admin password on the VM instance""" -- cgit From d05d4e77df0bdfd2b802186762391d7f91361701 Mon Sep 17 00:00:00 2001 From: "Kevin L. Mitchell" Date: Fri, 9 Sep 2011 14:35:38 -0500 Subject: Add comment to document why random.shuffle() works --- nova/scheduler/abstract_scheduler.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/nova/scheduler/abstract_scheduler.py b/nova/scheduler/abstract_scheduler.py index b4c2bf4f1..e4f615b94 100644 --- a/nova/scheduler/abstract_scheduler.py +++ b/nova/scheduler/abstract_scheduler.py @@ -296,6 +296,13 @@ class AbstractScheduler(driver.Scheduler): "child_blob": weighting["blob"]} weighted_hosts.append(host_dict) if FLAGS.spread_first: + # NOTE(Vek): If all the weights are unique, then the sort + # below undoes this shuffle; however, if + # several responses from several zones have the + # same weight, then this shuffle serves to + # break up the monolithic blocks and cause the + # instances to be uniformly spread across the + # zones. random.shuffle(weighted_hosts) weighted_hosts.sort(key=operator.itemgetter('weight')) return weighted_hosts -- cgit From c0700ea7bbb4d860610b71e635b8dbde19157e85 Mon Sep 17 00:00:00 2001 From: "Kevin L. Mitchell" Date: Fri, 9 Sep 2011 20:27:22 +0000 Subject: don't need random in abstract_scheduler.py anymore... --- nova/scheduler/abstract_scheduler.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nova/scheduler/abstract_scheduler.py b/nova/scheduler/abstract_scheduler.py index 76329bbc6..6e8c7d715 100644 --- a/nova/scheduler/abstract_scheduler.py +++ b/nova/scheduler/abstract_scheduler.py @@ -22,7 +22,6 @@ behavior is to simply select all hosts and weight them the same. import json import operator -import random import M2Crypto -- cgit From c3cb1d38ca4a6f3308503c79e13e3e8688143163 Mon Sep 17 00:00:00 2001 From: Chuck Short Date: Fri, 9 Sep 2011 20:47:37 -0400 Subject: Fix spelling mistake --- nova/virt/libvirt/connection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 6ae458537..7c1edc373 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -196,7 +196,7 @@ class LibvirtConnection(driver.ComputeDriver): def _test_connection(self): try: - self._wrapped_conn.geCapabilities() + self._wrapped_conn.getCapabilities() return True except libvirt.libvirtError as e: if e.get_error_code() == libvirt.VIR_ERR_SYSTEM_ERROR and \ -- cgit From 9482275a60ab8caa546ec402f61c60b9f5e7e33f Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Sat, 10 Sep 2011 13:56:54 -0400 Subject: Update GlanceClient, GlanceImageService, and Glance Xen plugin to work with Glance keystone. --- nova/api/auth.py | 1 + nova/api/openstack/create_instance_helper.py | 3 +- nova/compute/api.py | 3 +- nova/compute/manager.py | 3 +- nova/context.py | 9 ++- nova/image/__init__.py | 56 +------------ nova/image/glance.py | 91 ++++++++++++++++------ nova/tests/api/openstack/fakes.py | 2 +- nova/tests/glance/stubs.py | 6 +- nova/tests/integrated/integrated_helpers.py | 2 +- nova/tests/test_xenapi.py | 3 +- nova/virt/images.py | 3 +- nova/virt/libvirt/connection.py | 4 +- nova/virt/vmwareapi/fake.py | 6 +- nova/virt/vmwareapi/vmops.py | 4 +- nova/virt/vmwareapi/vmware_images.py | 69 +++------------- nova/virt/xenapi/vm_utils.py | 17 ++-- nova/virt/xenapi/vmops.py | 4 +- plugins/xenserver/xenapi/etc/xapi.d/plugins/glance | 6 +- 19 files changed, 124 insertions(+), 168 deletions(-) diff --git a/nova/api/auth.py b/nova/api/auth.py index cd0d38b3f..f73cae01e 100644 --- a/nova/api/auth.py +++ b/nova/api/auth.py @@ -70,6 +70,7 @@ class KeystoneContext(wsgi.Middleware): project_id, roles=roles, auth_token=auth_token, + strategy='keystone', remote_address=remote_address) req.environ['nova.context'] = ctx diff --git a/nova/api/openstack/create_instance_helper.py b/nova/api/openstack/create_instance_helper.py index 67e669c17..e27ddf78b 100644 --- a/nova/api/openstack/create_instance_helper.py +++ b/nova/api/openstack/create_instance_helper.py @@ -92,7 +92,8 @@ class CreateInstanceHelper(object): if str(image_href).startswith(req.application_url): image_href = image_href.split('/').pop() try: - image_service, image_id = nova.image.get_image_service(image_href) + image_service, image_id = nova.image.get_image_service(context, + image_href) kernel_id, ramdisk_id = self._get_kernel_ramdisk_from_image( req, image_service, image_id) images = set([str(x['id']) for x in image_service.index(context)]) diff --git a/nova/compute/api.py b/nova/compute/api.py index 4e2944bb7..95b4f5dea 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -202,7 +202,8 @@ class API(base.Base): self._check_injected_file_quota(context, injected_files) self._check_requested_networks(context, requested_networks) - (image_service, image_id) = nova.image.get_image_service(image_href) + (image_service, image_id) = nova.image.get_image_service(context, + image_href) image = image_service.show(context, image_id) config_drive_id = None diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 0477db745..25d44e502 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -322,7 +322,8 @@ class ComputeManager(manager.SchedulerDependentManager): # used by the image service. This should be refactored to be # consistent. image_href = instance['image_ref'] - image_service, image_id = nova.image.get_image_service(image_href) + image_service, image_id = nova.image.get_image_service(context, + image_href) image_meta = image_service.show(context, image_id) try: diff --git a/nova/context.py b/nova/context.py index 5c22641a0..de5b791c4 100644 --- a/nova/context.py +++ b/nova/context.py @@ -32,7 +32,7 @@ class RequestContext(object): def __init__(self, user_id, project_id, is_admin=None, read_deleted=False, roles=None, remote_address=None, timestamp=None, - request_id=None, auth_token=None): + request_id=None, auth_token=None, strategy='noauth'): self.user_id = user_id self.project_id = project_id self.roles = roles or [] @@ -50,6 +50,7 @@ class RequestContext(object): request_id = unicode(uuid.uuid4()) self.request_id = request_id self.auth_token = auth_token + self.strategy = strategy def to_dict(self): return {'user_id': self.user_id, @@ -60,7 +61,8 @@ class RequestContext(object): 'remote_address': self.remote_address, 'timestamp': utils.strtime(self.timestamp), 'request_id': self.request_id, - 'auth_token': self.auth_token} + 'auth_token': self.auth_token, + 'strategy': self.strategy} @classmethod def from_dict(cls, values): @@ -77,7 +79,8 @@ class RequestContext(object): remote_address=self.remote_address, timestamp=self.timestamp, request_id=self.request_id, - auth_token=self.auth_token) + auth_token=self.auth_token, + strategy=self.strategy) def get_admin_context(read_deleted=False): diff --git a/nova/image/__init__.py b/nova/image/__init__.py index 5447c8a3a..307b73f01 100644 --- a/nova/image/__init__.py +++ b/nova/image/__init__.py @@ -16,70 +16,20 @@ # under the License. -from urlparse import urlparse - import nova -from nova import exception from nova import utils from nova import flags -from nova.image import glance as glance_image_service +from nova.image import glance FLAGS = flags.FLAGS -GlanceClient = utils.import_class('glance.client.Client') - - -def _parse_image_ref(image_href): - """Parse an image href into composite parts. - - :param image_href: href of an image - :returns: a tuple of the form (image_id, host, port) - :raises ValueError - - """ - o = urlparse(image_href) - port = o.port or 80 - host = o.netloc.split(':', 1)[0] - image_id = int(o.path.split('/')[-1]) - return (image_id, host, port) - - def get_default_image_service(): ImageService = utils.import_class(FLAGS.image_service) return ImageService() -# FIXME(sirp): perhaps this should be moved to nova/images/glance so that we -# keep Glance specific code together for the most part -def get_glance_client(image_href): - """Get the correct glance client and id for the given image_href. - - The image_href param can be an href of the form - http://myglanceserver:9292/images/42, or just an int such as 42. If the - image_href is an int, then flags are used to create the default - glance client. - - :param image_href: image ref/id for an image - :returns: a tuple of the form (glance_client, image_id) - - """ - image_href = image_href or 0 - if str(image_href).isdigit(): - glance_host, glance_port = \ - glance_image_service.pick_glance_api_server() - glance_client = GlanceClient(glance_host, glance_port) - return (glance_client, int(image_href)) - - try: - (image_id, host, port) = _parse_image_ref(image_href) - except ValueError: - raise exception.InvalidImageRef(image_href=image_href) - glance_client = GlanceClient(host, port) - return (glance_client, image_id) - - -def get_image_service(image_href): +def get_image_service(context, image_href): """Get the proper image_service and id for the given image_href. The image_href param can be an href of the form @@ -94,6 +44,6 @@ def get_image_service(image_href): if str(image_href).isdigit(): return (get_default_image_service(), int(image_href)) - (glance_client, image_id) = get_glance_client(image_href) + (glance_client, image_id) = glance.get_glance_client(context, image_href) image_service = nova.image.glance.GlanceImageService(glance_client) return (image_service, image_id) diff --git a/nova/image/glance.py b/nova/image/glance.py index 80abc7384..e735f4082 100644 --- a/nova/image/glance.py +++ b/nova/image/glance.py @@ -23,6 +23,7 @@ import copy import datetime import json import random +from urlparse import urlparse from glance.common import exception as glance_exception @@ -42,6 +43,35 @@ FLAGS = flags.FLAGS GlanceClient = utils.import_class('glance.client.Client') +def _parse_image_ref(image_href): + """Parse an image href into composite parts. + + :param image_href: href of an image + :returns: a tuple of the form (image_id, host, port) + :raises ValueError + + """ + o = urlparse(image_href) + port = o.port or 80 + host = o.netloc.split(':', 1)[0] + image_id = int(o.path.split('/')[-1]) + return (image_id, host, port) + + +def _create_glance_client(context, host, port): + if context.strategy == 'keystone': + # NOTE(dprince): Glance client just needs auth_tok right? Should we + # add username and tenant to the creds below? + creds={'strategy': 'keystone', + 'username': context.user_id, + 'tenant': context.project_id} + glance_client = GlanceClient(host, port, auth_tok=context.auth_token, + creds=creds) + else: + glance_client = GlanceClient(host, port) + return glance_client + + def pick_glance_api_server(): """Return which Glance API server to use for the request @@ -57,6 +87,33 @@ def pick_glance_api_server(): return host, port +def get_glance_client(context, image_href): + """Get the correct glance client and id for the given image_href. + + The image_href param can be an href of the form + http://myglanceserver:9292/images/42, or just an int such as 42. If the + image_href is an int, then flags are used to create the default + glance client. + + :param image_href: image ref/id for an image + :returns: a tuple of the form (glance_client, image_id) + + """ + image_href = image_href or 0 + if str(image_href).isdigit(): + glance_host, glance_port = pick_glance_api_server() + glance_client = _create_glance_client(context, glance_host, + glance_port) + return (glance_client, int(image_href)) + + try: + (image_id, host, port) = _parse_image_ref(image_href) + except ValueError: + raise exception.InvalidImageRef(image_href=image_href) + glance_client = _create_glance_client(context, glance_host, glance_port) + return (glance_client, image_id) + + class GlanceImageService(service.BaseImageService): """Provides storage and retrieval of disk image objects within Glance.""" @@ -71,23 +128,14 @@ class GlanceImageService(service.BaseImageService): def __init__(self, client=None): self._client = client - def _get_client(self): + def _get_client(self, context): # NOTE(sirp): we want to load balance each request across glance # servers. Since GlanceImageService is a long-lived object, `client` # is made to choose a new server each time via this property. if self._client is not None: return self._client glance_host, glance_port = pick_glance_api_server() - return GlanceClient(glance_host, glance_port) - - def _set_client(self, client): - self._client = client - - client = property(_get_client, _set_client) - - def _set_client_context(self, context): - """Sets the client's auth token.""" - self.client.set_auth_token(context.auth_token) + return _create_glance_client(context, glance_host, glance_port) def index(self, context, **kwargs): """Calls out to Glance for a list of images available.""" @@ -128,14 +176,14 @@ class GlanceImageService(service.BaseImageService): def _get_images(self, context, **kwargs): """Get image entitites from images service""" - self._set_client_context(context) # ensure filters is a dict kwargs['filters'] = kwargs.get('filters') or {} # NOTE(vish): don't filter out private images kwargs['filters'].setdefault('is_public', 'none') - return self._fetch_images(self.client.get_images_detailed, **kwargs) + client = self._get_client(context) + return self._fetch_images(client.get_images_detailed, **kwargs) def _fetch_images(self, fetch_func, **kwargs): """Paginate through results from glance server""" @@ -168,9 +216,8 @@ class GlanceImageService(service.BaseImageService): def show(self, context, image_id): """Returns a dict with image data for the given opaque image id.""" - self._set_client_context(context) try: - image_meta = self.client.get_image_meta(image_id) + image_meta = self._get_client(context).get_image_meta(image_id) except glance_exception.NotFound: raise exception.ImageNotFound(image_id=image_id) @@ -192,9 +239,9 @@ class GlanceImageService(service.BaseImageService): def get(self, context, image_id, data): """Calls out to Glance for metadata and data and writes data.""" - self._set_client_context(context) try: - image_meta, image_chunks = self.client.get_image(image_id) + client = self._get_client(context) + image_meta, image_chunks = client.get_image(image_id) except glance_exception.NotFound: raise exception.ImageNotFound(image_id=image_id) @@ -210,7 +257,6 @@ class GlanceImageService(service.BaseImageService): :raises: AlreadyExists if the image already exist. """ - self._set_client_context(context) # Translate Base -> Service LOG.debug(_('Creating image in Glance. Metadata passed in %s'), image_meta) @@ -218,7 +264,7 @@ class GlanceImageService(service.BaseImageService): LOG.debug(_('Metadata after formatting for Glance %s'), sent_service_image_meta) - recv_service_image_meta = self.client.add_image( + recv_service_image_meta = self._get_client(context).add_image( sent_service_image_meta, data) # Translate Service -> Base @@ -233,12 +279,12 @@ class GlanceImageService(service.BaseImageService): :raises: ImageNotFound if the image does not exist. """ - self._set_client_context(context) # NOTE(vish): show is to check if image is available self.show(context, image_id) image_meta = _convert_to_string(image_meta) try: - image_meta = self.client.update_image(image_id, image_meta, data) + client = self._get_client(context) + image_meta = client.update_image(image_id, image_meta, data) except glance_exception.NotFound: raise exception.ImageNotFound(image_id=image_id) @@ -251,11 +297,10 @@ class GlanceImageService(service.BaseImageService): :raises: ImageNotFound if the image does not exist. """ - self._set_client_context(context) # NOTE(vish): show is to check if image is available self.show(context, image_id) try: - result = self.client.delete_image(image_id) + result = self._get_client(context).delete_image(image_id) except glance_exception.NotFound: raise exception.ImageNotFound(image_id=image_id) return result diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py index 44681d395..098b1e284 100644 --- a/nova/tests/api/openstack/fakes.py +++ b/nova/tests/api/openstack/fakes.py @@ -124,7 +124,7 @@ def stub_out_key_pair_funcs(stubs, have_key_pair=True): def stub_out_image_service(stubs): - def fake_get_image_service(image_href): + def fake_get_image_service(context, image_href): return (nova.image.fake.FakeImageService(), image_href) stubs.Set(nova.image, 'get_image_service', fake_get_image_service) stubs.Set(nova.image, 'get_default_image_service', diff --git a/nova/tests/glance/stubs.py b/nova/tests/glance/stubs.py index f2a19f22d..6b74e671c 100644 --- a/nova/tests/glance/stubs.py +++ b/nova/tests/glance/stubs.py @@ -16,14 +16,14 @@ import StringIO -import nova.image +from nova.image import glance def stubout_glance_client(stubs): - def fake_get_glance_client(image_href): + def fake_get_glance_client(context, image_href): image_id = int(str(image_href).split('/')[-1]) return (FakeGlance('foo'), image_id) - stubs.Set(nova.image, 'get_glance_client', fake_get_glance_client) + stubs.Set(glance, 'get_glance_client', fake_get_glance_client) class FakeGlance(object): diff --git a/nova/tests/integrated/integrated_helpers.py b/nova/tests/integrated/integrated_helpers.py index 343190427..49de9c854 100644 --- a/nova/tests/integrated/integrated_helpers.py +++ b/nova/tests/integrated/integrated_helpers.py @@ -64,7 +64,7 @@ class _IntegratedTestBase(test.TestCase): self.flags(**f) self.flags(verbose=True) - def fake_get_image_service(image_href): + def fake_get_image_service(context, image_href): image_id = int(str(image_href).split('/')[-1]) return (nova.image.fake.FakeImageService(), image_id) self.stubs.Set(nova.image, 'get_image_service', fake_get_image_service) diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index 91b4161b0..4a83d139e 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -932,8 +932,9 @@ class XenAPIDetermineDiskImageTestCase(test.TestCase): self.fake_instance.architecture = 'x86-64' def assert_disk_type(self, disk_type): + ctx = context.RequestContext('fake', 'fake') dt = vm_utils.VMHelper.determine_disk_image_type( - self.fake_instance) + self.fake_instance, ctx) self.assertEqual(disk_type, dt) def test_instance_disk(self): diff --git a/nova/virt/images.py b/nova/virt/images.py index 54c691a40..810b359d9 100644 --- a/nova/virt/images.py +++ b/nova/virt/images.py @@ -37,7 +37,8 @@ def fetch(context, image_href, path, _user_id, _project_id): # when it is added to glance. Right now there is no # auth checking in glance, so we assume that access was # checked before we got here. - (image_service, image_id) = nova.image.get_image_service(image_href) + (image_service, image_id) = nova.image.get_image_service(context, + image_href) with open(path, "wb") as image_file: metadata = image_service.get(context, image_id, image_file) return metadata diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 19cef5ad7..fd902ca4b 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -398,10 +398,10 @@ class LibvirtConnection(driver.ComputeDriver): virt_dom = self._lookup_by_name(instance['name']) (image_service, image_id) = nova.image.get_image_service( - instance['image_ref']) + context, instance['image_ref']) base = image_service.show(context, image_id) (snapshot_image_service, snapshot_image_id) = \ - nova.image.get_image_service(image_href) + nova.image.get_image_service(context, image_href) snapshot = snapshot_image_service.show(context, snapshot_image_id) metadata = {'is_public': False, diff --git a/nova/virt/vmwareapi/fake.py b/nova/virt/vmwareapi/fake.py index 4c62d18bb..0dea13aba 100644 --- a/nova/virt/vmwareapi/fake.py +++ b/nova/virt/vmwareapi/fake.py @@ -412,7 +412,7 @@ def fake_get_network(*args, **kwargs): return [{'type': 'fake'}] -def fake_fetch_image(image, instance, **kwargs): +def fake_fetch_image(context, image, instance, **kwargs): """Fakes fetch image call. Just adds a reference to the db for the file.""" ds_name = kwargs.get("datastore_name") file_path = kwargs.get("file_path") @@ -420,12 +420,12 @@ def fake_fetch_image(image, instance, **kwargs): _add_file(ds_file_path) -def fake_upload_image(image, instance, **kwargs): +def fake_upload_image(context, image, instance, **kwargs): """Fakes the upload of an image.""" pass -def fake_get_vmdk_size_and_properties(image_id, instance): +def fake_get_vmdk_size_and_properties(context, image_id, instance): """Fakes the file size and properties fetch for the image file.""" props = {"vmware_ostype": "otherGuest", "vmware_adaptertype": "lsiLogic"} diff --git a/nova/virt/vmwareapi/vmops.py b/nova/virt/vmwareapi/vmops.py index 07a6ba6ab..6bdc2f23a 100644 --- a/nova/virt/vmwareapi/vmops.py +++ b/nova/virt/vmwareapi/vmops.py @@ -157,7 +157,7 @@ class VMWareVMOps(object): repository. """ image_size, image_properties = \ - vmware_images.get_vmdk_size_and_properties( + vmware_images.get_vmdk_size_and_properties(context, instance.image_ref, instance) vmdk_file_size_in_kb = int(image_size) / 1024 os_type = image_properties.get("vmware_ostype", "otherGuest") @@ -282,6 +282,7 @@ class VMWareVMOps(object): # Upload the -flat.vmdk file whose meta-data file we just created # above vmware_images.fetch_image( + context, instance.image_ref, instance, host=self._session._host_ip, @@ -448,6 +449,7 @@ class VMWareVMOps(object): # Upload the contents of -flat.vmdk file which has the disk data. LOG.debug(_("Uploading image %s") % snapshot_name) vmware_images.upload_image( + context, snapshot_name, instance, os_type=os_type, diff --git a/nova/virt/vmwareapi/vmware_images.py b/nova/virt/vmwareapi/vmware_images.py index f5f75dae2..53f2d372e 100644 --- a/nova/virt/vmwareapi/vmware_images.py +++ b/nova/virt/vmwareapi/vmware_images.py @@ -20,15 +20,13 @@ Utility functions for Image transfer. from nova import exception from nova import flags -import nova.image +from nova.image import glance from nova import log as logging from nova.virt.vmwareapi import io_util from nova.virt.vmwareapi import read_write_util LOG = logging.getLogger("nova.virt.vmwareapi.vmware_images") -FLAGS = flags.FLAGS - QUEUE_BUFFER_SIZE = 10 @@ -87,36 +85,10 @@ def start_transfer(read_file_handle, data_size, write_file_handle=None, write_file_handle.close() -def fetch_image(image, instance, **kwargs): - """Fetch an image for attaching to the newly created VM.""" - # Depending upon the image service, make appropriate image service call - if FLAGS.image_service == "nova.image.glance.GlanceImageService": - func = _get_glance_image - elif FLAGS.image_service == "nova.image.s3.S3ImageService": - func = _get_s3_image - else: - raise NotImplementedError(_("The Image Service %s is not implemented") - % FLAGS.image_service) - return func(image, instance, **kwargs) - - -def upload_image(image, instance, **kwargs): - """Upload the newly snapshotted VM disk file.""" - # Depending upon the image service, make appropriate image service call - if FLAGS.image_service == "nova.image.glance.GlanceImageService": - func = _put_glance_image - elif FLAGS.image_service == "nova.image.s3.S3ImageService": - func = _put_s3_image - else: - raise NotImplementedError(_("The Image Service %s is not implemented") - % FLAGS.image_service) - return func(image, instance, **kwargs) - - -def _get_glance_image(image, instance, **kwargs): +def fetch_image(context, image, instance, **kwargs): """Download image from the glance image server.""" LOG.debug(_("Downloading image %s from glance image server") % image) - (glance_client, image_id) = nova.image.get_glance_client(image) + (glance_client, image_id) = glance.get_glance_client(context, image) metadata, read_iter = glance_client.get_image(image_id) read_file_handle = read_write_util.GlanceFileRead(read_iter) file_size = int(metadata['size']) @@ -132,17 +104,7 @@ def _get_glance_image(image, instance, **kwargs): LOG.debug(_("Downloaded image %s from glance image server") % image) -def _get_s3_image(image, instance, **kwargs): - """Download image from the S3 image server.""" - raise NotImplementedError - - -def _get_local_image(image, instance, **kwargs): - """Download image from the local nova compute node.""" - raise NotImplementedError - - -def _put_glance_image(image, instance, **kwargs): +def upload_image(context, image, instance, **kwargs): """Upload the snapshotted vm disk file to Glance image server.""" LOG.debug(_("Uploading image %s to the Glance image server") % image) read_file_handle = read_write_util.VmWareHTTPReadFile( @@ -152,7 +114,7 @@ def _put_glance_image(image, instance, **kwargs): kwargs.get("cookies"), kwargs.get("file_path")) file_size = read_file_handle.get_size() - (glance_client, image_id) = nova.image.get_glance_client(image) + (glance_client, image_id) = glance.get_glance_client(context, image) # The properties and other fields that we need to set for the image. image_metadata = {"is_public": True, "disk_format": "vmdk", @@ -168,17 +130,7 @@ def _put_glance_image(image, instance, **kwargs): LOG.debug(_("Uploaded image %s to the Glance image server") % image) -def _put_local_image(image, instance, **kwargs): - """Upload the snapshotted vm disk file to the local nova compute node.""" - raise NotImplementedError - - -def _put_s3_image(image, instance, **kwargs): - """Upload the snapshotted vm disk file to S3 image server.""" - raise NotImplementedError - - -def get_vmdk_size_and_properties(image, instance): +def get_vmdk_size_and_properties(context, image, instance): """ Get size of the vmdk file that is to be downloaded for attach in spawn. Need this to create the dummy virtual disk for the meta-data file. The @@ -186,12 +138,9 @@ def get_vmdk_size_and_properties(image, instance): """ LOG.debug(_("Getting image size for the image %s") % image) - if FLAGS.image_service == "nova.image.glance.GlanceImageService": - (glance_client, image_id) = nova.image.get_glance_client(image) - meta_data = glance_client.get_image_meta(image_id) - size, properties = meta_data["size"], meta_data["properties"] - elif FLAGS.image_service == "nova.image.s3.S3ImageService": - raise NotImplementedError + (glance_client, image_id) = glance.get_glance_client(context, image) + meta_data = glance_client.get_image_meta(image_id) + size, properties = meta_data["size"], meta_data["properties"] LOG.debug(_("Got image size of %(size)s for the image %(image)s") % locals()) return size, properties diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index efbea7076..302238c98 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -31,12 +31,10 @@ import urllib import uuid from xml.dom import minidom -import glance.client from nova import db from nova import exception from nova import flags -import nova.image -from nova.image import glance as glance_image_service +from nova.image import glance from nova import log as logging from nova import utils from nova.compute import instance_types @@ -383,8 +381,7 @@ class VMHelper(HelperBase): os_type = instance.os_type or FLAGS.default_os_type - glance_host, glance_port = \ - glance_image_service.pick_glance_api_server() + glance_host, glance_port = glance.pick_glance_api_server() params = {'vdi_uuids': vdi_uuids, 'image_id': image_id, 'glance_host': glance_host, @@ -447,8 +444,7 @@ class VMHelper(HelperBase): # pass them as arguments uuid_stack = [str(uuid.uuid4()) for i in xrange(2)] - glance_host, glance_port = \ - glance_image_service.pick_glance_api_server() + glance_host, glance_port = glance.pick_glance_api_server() params = {'image_id': image, 'glance_host': glance_host, 'glance_port': glance_port, @@ -546,7 +542,7 @@ class VMHelper(HelperBase): else: sr_ref = safe_find_sr(session) - glance_client, image_id = nova.image.get_glance_client(image) + glance_client, image_id = glance.get_glance_client(context, image) glance_client.set_auth_token(getattr(context, 'auth_token', None)) meta, image_file = glance_client.get_image(image_id) virtual_size = int(meta['size']) @@ -606,7 +602,7 @@ class VMHelper(HelperBase): raise e @classmethod - def determine_disk_image_type(cls, instance): + def determine_disk_image_type(cls, instance, context): """Disk Image Types are used to determine where the kernel will reside within an image. To figure out which type we're dealing with, we use the following rules: @@ -639,7 +635,8 @@ class VMHelper(HelperBase): 'vhd': ImageType.DISK_VHD, 'iso': ImageType.DISK_ISO} image_ref = instance.image_ref - glance_client, image_id = nova.image.get_glance_client(image_ref) + glance_client, image_id = glance.get_glance_client(context, + image_ref) meta = glance_client.get_image_meta(image_id) disk_format = meta['disk_format'] try: diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 9c138ee41..038c041c7 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -135,7 +135,7 @@ class VMOps(object): self._session.call_xenapi('VM.start', vm_ref, False, False) def _create_disks(self, context, instance): - disk_image_type = VMHelper.determine_disk_image_type(instance) + disk_image_type = VMHelper.determine_disk_image_type(instance, context) vdis = VMHelper.fetch_image(context, self._session, instance, instance.image_ref, instance.user_id, instance.project_id, @@ -176,7 +176,7 @@ class VMOps(object): power_state.SHUTDOWN) return - disk_image_type = VMHelper.determine_disk_image_type(instance) + disk_image_type = VMHelper.determine_disk_image_type(instance, context) kernel = None ramdisk = None try: diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance index a06312890..1a9ac37e9 100755 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance @@ -252,7 +252,11 @@ def _upload_tarball(staging_path, image_id, glance_host, glance_port, os_type, # NOTE(dprince): We need to resend any existing Glance meta/property # headers so they are preserved in Glance. We obtain them here with a # HEAD request. - conn.request('HEAD', '/v1/images/%s' % image_id) + conn.putrequest('HEAD', '/v1/images/%s' % image_id) + if auth_token: + conn.putheader('x-auth-token', auth_token) + conn.endheaders() + resp = conn.getresponse() if resp.status != httplib.OK: raise Exception("Unexpected response from Glance %i" % resp.status) -- cgit From cd5084f8a69b0e2a14f01aa9a4f3d8588a83c923 Mon Sep 17 00:00:00 2001 From: Thierry Carrez Date: Mon, 12 Sep 2011 14:30:56 +0200 Subject: Fix rogue usage of 'sudo' bypassing the run_as_root=True method --- nova/tests/test_libvirt.py | 4 ++-- nova/virt/disk.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index 8c6775b29..fea2b7cd3 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -743,7 +743,7 @@ class LibvirtConnTestCase(test.TestCase): # qemu-img should be mockd since test environment might not have # large disk space. self.mox.StubOutWithMock(utils, "execute") - utils.execute('sudo', 'qemu-img', 'create', '-f', 'raw', + utils.execute('qemu-img', 'create', '-f', 'raw', '%s/%s/disk' % (tmpdir, instance_ref.name), '10G') self.mox.ReplayAll() @@ -795,7 +795,7 @@ class LibvirtConnTestCase(test.TestCase): os.path.getsize("/test/disk").AndReturn(10 * 1024 * 1024 * 1024) # another is qcow image, so qemu-img should be mocked. self.mox.StubOutWithMock(utils, "execute") - utils.execute('sudo', 'qemu-img', 'info', '/test/disk.local').\ + utils.execute('qemu-img', 'info', '/test/disk.local').\ AndReturn((ret, '')) self.mox.ReplayAll() diff --git a/nova/virt/disk.py b/nova/virt/disk.py index 52b2881e8..e6cf5f5c4 100644 --- a/nova/virt/disk.py +++ b/nova/virt/disk.py @@ -228,8 +228,8 @@ def _inject_metadata_into_fs(metadata, fs, execute=None): metadata_path = os.path.join(fs, "meta.js") metadata = dict([(m.key, m.value) for m in metadata]) - utils.execute('sudo', 'tee', metadata_path, - process_input=json.dumps(metadata)) + utils.execute('tee', metadata_path, + process_input=json.dumps(metadata), run_as_root=True) def _inject_key_into_fs(key, fs, execute=None): -- cgit From 40df48ff0047caeca0472ee652a250c5d5a3e74f Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 12 Sep 2011 15:17:57 -0400 Subject: pep8 fix. --- nova/image/glance.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nova/image/glance.py b/nova/image/glance.py index e735f4082..13c8ff843 100644 --- a/nova/image/glance.py +++ b/nova/image/glance.py @@ -62,9 +62,9 @@ def _create_glance_client(context, host, port): if context.strategy == 'keystone': # NOTE(dprince): Glance client just needs auth_tok right? Should we # add username and tenant to the creds below? - creds={'strategy': 'keystone', - 'username': context.user_id, - 'tenant': context.project_id} + creds = {'strategy': 'keystone', + 'username': context.user_id, + 'tenant': context.project_id} glance_client = GlanceClient(host, port, auth_tok=context.auth_token, creds=creds) else: -- cgit From 81fe8c89061fa15ebcea9d20f39cf79b63cf8522 Mon Sep 17 00:00:00 2001 From: Antony Messerli Date: Mon, 12 Sep 2011 14:43:15 -0500 Subject: pep8 fixes --- nova/db/sqlalchemy/api.py | 2 +- nova/virt/disk.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 40e2ca167..e5a661c7f 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -672,7 +672,7 @@ def floating_ip_update(context, address, values): def fixed_ip_associate(context, address, instance_id, network_id=None, reserved=False): """Keyword arguments: - reserved -- should be a boolean value(True or False), exact value will be + reserved -- should be a boolean value(True or False), exact value will be used to filter on the fixed ip address """ session = get_session() diff --git a/nova/virt/disk.py b/nova/virt/disk.py index d0745c82d..cd3422829 100644 --- a/nova/virt/disk.py +++ b/nova/virt/disk.py @@ -160,6 +160,7 @@ def destroy_container(target, instance, nbd=False): except Exception, exn: LOG.exception(_('Failed to remove container: %s'), exn) + def _link_device(image, nbd): """Link image to device using loopback or nbd""" -- cgit