From c94ec9a5bab6c07b402b68e2f4ff081247a27cda Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Mon, 14 Mar 2011 14:17:58 -0700 Subject: Initial implementation of refresh instance states --- nova/compute/driver.py | 38 ++++++++++++++++++++++++++++++ nova/compute/manager.py | 56 ++++++++++++++++++++++++++++++++++++++++++++- nova/compute/power_state.py | 16 +++++++++---- nova/utils.py | 9 ++++++++ nova/virt/connection.py | 4 +++- nova/virt/fake.py | 36 +++++++++++++++++++++-------- nova/virt/hyperv.py | 4 +++- nova/virt/libvirt_conn.py | 24 ++++++++++++++++++- nova/virt/xenapi/vmops.py | 19 +++++++++++++++ nova/virt/xenapi_conn.py | 7 +++++- 10 files changed, 194 insertions(+), 19 deletions(-) create mode 100644 nova/compute/driver.py diff --git a/nova/compute/driver.py b/nova/compute/driver.py new file mode 100644 index 000000000..bda82c60a --- /dev/null +++ b/nova/compute/driver.py @@ -0,0 +1,38 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 Justin Santa Barbara +# 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. + +""" +Driver base-classes: + + (Beginning of) the contract that compute drivers must follow, and shared + types that support that contract +""" + +from nova.compute import power_state + + +class InstanceInfo(object): + def __init__(self, name, state): + self.name = name + assert state in power_state.valid_states() + self.state = state + + +class ComputeDriver(object): + def list_instances_detail(self): + """Return a list of InstanceInfo for all registered VMs""" + raise NotImplementedError() diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 0cab10fc3..057371d40 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -2,6 +2,7 @@ # Copyright 2010 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. +# Copyright 2011 Justin Santa Barbara # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -51,6 +52,7 @@ from nova import manager from nova import rpc from nova import utils from nova.compute import power_state +from nova.compute import driver FLAGS = flags.FLAGS flags.DEFINE_string('instances_path', '$state_path/instances', @@ -115,7 +117,9 @@ class ComputeManager(manager.Manager): # and redocument the module docstring if not compute_driver: compute_driver = FLAGS.compute_driver - self.driver = utils.import_object(compute_driver) + self.driver = utils.check_instance(utils.import_object( + compute_driver), + driver.ComputeDriver) self.network_manager = utils.import_object(FLAGS.network_manager) self.volume_manager = utils.import_object(FLAGS.volume_manager) super(ComputeManager, self).__init__(*args, **kwargs) @@ -974,3 +978,53 @@ class ComputeManager(manager.Manager): for volume in instance_ref['volumes']: self.db.volume_update(ctxt, volume['id'], {'status': 'in-use'}) + + def periodic_tasks(self, context=None): + """Tasks to be run at a periodic interval.""" + super(ComputeManager, self).periodic_tasks(context) + try: + self._poll_instance_states(context) + except Exception as ex: + LOG.warning(_("Error during instance poll: %s"), + unicode(ex)) + + def _poll_instance_states(self, context): + vm_instances = self.driver.list_instances_detail(context) + vm_instances = dict((vm.name, vm) for vm in vm_instances) + + # Keep a list of VMs not in the DB, cross them off as we find them + vms_not_found_in_db = [vm.name for vm in vm_instances] + + db_instances = self.db.instance_get_all_by_host(context, self.host) + for db_instance in db_instances: + name = db_instance['name'] + vm_instance = vm_instances.get(name) + if vm_instance is None: + LOG.info(_("Found instance '%(name)' in DB but no VM. " + "Shutting off.") % locals()) + vm_state = power_state.SHUTOFF + else: + vm_state = vm_instance.state + vms_not_found_in_db.remove(name) + + db_state = db_instance['state'] + if vm_state != db_state: + LOG.info(_("DB/VM state mismatch. Changing state from " + "%(db_state) to %(vm_state)") % locals()) + self.db.instance_set_state(context, + db_instance['id'], + vm_state) + + if vm_state == power_state.SHUTOFF: + # TODO(soren): This is what the compute manager does when you + # terminate an instance. At some point I figure we'll have a + # "terminated" state and some sort of cleanup job that runs + # occasionally, cleaning them out. + self.db.instance_destroy(context, db_instance['id']) + + # Are there VMs not in the DB? + for vm_not_found_in_db in vms_not_found_in_db: + name = vm_not_found_in_db + #TODO(justinsb): What to do here? Adopt it? Shut it down? + LOG.warning(_("Found VM not in DB: %(name). Ignoring") + % locals()) diff --git a/nova/compute/power_state.py b/nova/compute/power_state.py index adfc2dff0..145362f97 100644 --- a/nova/compute/power_state.py +++ b/nova/compute/power_state.py @@ -2,6 +2,7 @@ # Copyright 2010 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. +# Copyright 2011 Justin Santa Barbara # All Rights Reserved. # Copyright (c) 2010 Citrix Systems, Inc. # @@ -19,6 +20,7 @@ """The various power states that a VM can be in.""" +#NOTE(justinsb): These are the virDomainState values from libvirt NOSTATE = 0x00 RUNNING = 0x01 BLOCKED = 0x02 @@ -29,9 +31,8 @@ CRASHED = 0x06 SUSPENDED = 0x07 FAILED = 0x08 - -def name(code): - d = { +#TODO(justinsb): Power state really needs to be a proper class... +_STATE_MAP = { NOSTATE: 'pending', RUNNING: 'running', BLOCKED: 'blocked', @@ -41,4 +42,11 @@ def name(code): CRASHED: 'crashed', SUSPENDED: 'suspended', FAILED: 'failed to spawn'} - return d[code] + + +def name(code): + return _STATE_MAP[code] + + +def valid_states(): + return _STATE_MAP.values() diff --git a/nova/utils.py b/nova/utils.py index 87e726394..e93f489be 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -585,3 +585,12 @@ def get_from_path(items, path): return results else: return get_from_path(results, remainder) + + +def check_instance(obj, cls): + """Checks that obj is of type cls, and lets PyLint infer types""" + if isinstance(obj, cls): + return obj + raise Exception(_("Expected object of type: %s") % (str(cls))) + #TODO(justinsb): Can we make this better?? + return cls() # Ugly PyLint hack diff --git a/nova/virt/connection.py b/nova/virt/connection.py index 13181b730..d585b6c21 100644 --- a/nova/virt/connection.py +++ b/nova/virt/connection.py @@ -23,6 +23,8 @@ import sys from nova import flags from nova import log as logging +from nova import utils +from nova.compute import driver from nova.virt import fake from nova.virt import libvirt_conn from nova.virt import xenapi_conn @@ -72,4 +74,4 @@ def get_connection(read_only=False): if conn is None: LOG.error(_('Failed to open connection to the hypervisor')) sys.exit(1) - return conn + return utils.check_instance(conn, driver.ComputeDriver) diff --git a/nova/virt/fake.py b/nova/virt/fake.py index 3a06284a1..18cca3f5e 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -26,6 +26,8 @@ semantics of real hypervisor connections. """ from nova import exception +from nova import utils +from nova.compute import driver from nova.compute import power_state @@ -34,7 +36,14 @@ def get_connection(_): return FakeConnection.instance() -class FakeConnection(object): +class FakeInstance(object): + + def __init__(self, name, state): + self.name = name + self.state = state + + +class FakeConnection(driver.ComputeDriver): """ The interface to this class talks in terms of 'instances' (Amazon EC2 and internal Nova terminology), by which we mean 'running virtual machine' @@ -90,6 +99,17 @@ class FakeConnection(object): """ return self.instances.keys() + def _map_to_instance_info(self, instance): + instance = utils.check_instance(instance, FakeInstance) + info = driver.InstanceInfo(instance.name, instance.state) + return info + + def list_instances_detail(self): + info_list = [] + for instance in self.instances: + info_list.append(self._map_to_instance_info(instance)) + return info_list + def spawn(self, instance): """ Create a new instance/VM/domain on the virtualization platform. @@ -109,9 +129,10 @@ class FakeConnection(object): that it was before this call began. """ - fake_instance = FakeInstance() - self.instances[instance.name] = fake_instance - fake_instance._state = power_state.RUNNING + name = instance.name + state = power_state.RUNNING + fake_instance = FakeInstance(name, state) + self.instances[name] = fake_instance def snapshot(self, instance, name): """ @@ -270,7 +291,7 @@ class FakeConnection(object): raise exception.NotFound(_("Instance %s Not Found") % instance_name) i = self.instances[instance_name] - return {'state': i._state, + return {'state': i.state, 'max_mem': 0, 'mem': 0, 'num_cpu': 2, @@ -428,8 +449,3 @@ class FakeConnection(object): """This method is supported only by libvirt.""" raise NotImplementedError('This method is supported only by libvirt.') - -class FakeInstance(object): - - def __init__(self): - self._state = power_state.NOSTATE diff --git a/nova/virt/hyperv.py b/nova/virt/hyperv.py index 29d18dac5..aea7413c6 100644 --- a/nova/virt/hyperv.py +++ b/nova/virt/hyperv.py @@ -67,6 +67,7 @@ from nova import exception from nova import flags from nova import log as logging from nova.auth import manager +from nova.compute import driver from nova.compute import power_state from nova.virt import images @@ -108,8 +109,9 @@ def get_connection(_): return HyperVConnection() -class HyperVConnection(object): +class HyperVConnection(driver.ComputeDriver): def __init__(self): + super(HyperVConnection, self).__init__() self._conn = wmi.WMI(moniker='//./root/virtualization') self._cim_conn = wmi.WMI(moniker='//./root/cimv2') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 0b306c950..e95bcac39 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -60,6 +60,7 @@ from nova import log as logging #from nova import test from nova import utils from nova.auth import manager +from nova.compute import driver from nova.compute import instance_types from nova.compute import power_state from nova.virt import disk @@ -154,9 +155,10 @@ def _get_ip_version(cidr): return int(net.version()) -class LibvirtConnection(object): +class LibvirtConnection(driver.ComputeDriver): def __init__(self, read_only): + super(LibvirtConnection, self).__init__() self.libvirt_uri = self.get_uri() self.libvirt_xml = open(FLAGS.libvirt_xml_template).read() @@ -235,6 +237,26 @@ class LibvirtConnection(object): return [self._conn.lookupByID(x).name() for x in self._conn.listDomainsID()] + def _map_to_instance_info(self, domain): + # .info() returns a list of: + #state: one of the state values (virDomainState) + #maxMemory: the maximum memory used by the domain + #memory: the current amount of memory used by the domain + #nbVirtCPU: the number of virtual CPU + #cpuTime: the time used by the domain in nanoseconds + (state, _max_mem, _mem, _num_cpu, _cpu_time) = domain.info() + name = domain.name() + + return driver.InstanceInfo(name, state) + + def list_instances_detail(self): + infos = [] + for domain_id in self._conn.listDomainsID(): + domain = self._conn.lookupById(domain_id) + info = self._map_to_instance_info(domain) + infos.append(info) + return infos + def destroy(self, instance, cleanup=True): try: virt_dom = self._conn.lookupByName(instance['name']) diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index fcb290d03..2fce93e38 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -34,6 +34,7 @@ from nova import exception from nova import utils from nova.auth.manager import AuthManager +from nova.compute import driver from nova.compute import power_state from nova.virt.xenapi.network_utils import NetworkHelper from nova.virt.xenapi.vm_utils import VMHelper @@ -55,6 +56,8 @@ class VMOps(object): def list_instances(self): """List VM instances""" + # TODO(justinsb): Should we just always use the details method? + # Seems to be the same number of API calls.. vm_refs = [] for vm_ref in self._session.get_xenapi().VM.get_all(): vm_rec = self._session.get_xenapi().VM.get_record(vm_ref) @@ -62,6 +65,22 @@ class VMOps(object): vm_refs.append(vm_rec["name_label"]) return vm_refs + def list_instances_detail(self): + """List VM instances, returning InstanceInfo objects""" + instance_infos = [] + for vm_ref in self._session.get_xenapi().VM.get_all(): + vm_rec = self._session.get_xenapi().VM.get_record(vm_ref) + if not vm_rec["is_a_template"] and not vm_rec["is_control_domain"]: + name = vm_rec["name_label"] + + #TODO(justinsb): Yuk... + openstack_format = VMHelper.compile_info(vm_rec) + state = openstack_format['state'] + + instance_info = driver.InstanceInfo(name, state) + instance_infos.append(instance_info) + return instance_infos + def _start(self, instance, vm_ref=None): """Power on a VM instance""" if not vm_ref: diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index da42a83b6..9390db0bb 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -69,6 +69,7 @@ from nova import db from nova import utils from nova import flags from nova import log as logging +from nova.compute import driver from nova.virt.xenapi.vmops import VMOps from nova.virt.xenapi.volumeops import VolumeOps @@ -141,10 +142,11 @@ def get_connection(_): return XenAPIConnection(url, username, password) -class XenAPIConnection(object): +class XenAPIConnection(driver.ComputeDriver): """A connection to XenServer or Xen Cloud Platform""" def __init__(self, url, user, pw): + super(XenAPIConnection, self).__init__() session = XenAPISession(url, user, pw) self._vmops = VMOps(session) self._volumeops = VolumeOps(session) @@ -160,6 +162,9 @@ class XenAPIConnection(object): """List VM instances""" return self._vmops.list_instances() + def list_instances_detail(self): + return self._vmops.list_instances_detail() + def spawn(self, instance): """Create VM instance""" self._vmops.spawn(instance) -- cgit From 54f16ee6012082c1ad9de423698573c5d9b47540 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Mon, 14 Mar 2011 14:38:39 -0700 Subject: pep8 --- nova/virt/fake.py | 1 - nova/virt/xenapi/vmops.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/nova/virt/fake.py b/nova/virt/fake.py index 18cca3f5e..ccf2a7d68 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -448,4 +448,3 @@ class FakeConnection(driver.ComputeDriver): def unfilter_instance(self, instance_ref): """This method is supported only by libvirt.""" raise NotImplementedError('This method is supported only by libvirt.') - diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 2fce93e38..3a58a887e 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -72,7 +72,7 @@ class VMOps(object): vm_rec = self._session.get_xenapi().VM.get_record(vm_ref) if not vm_rec["is_a_template"] and not vm_rec["is_control_domain"]: name = vm_rec["name_label"] - + #TODO(justinsb): Yuk... openstack_format = VMHelper.compile_info(vm_rec) state = openstack_format['state'] -- cgit From 738653b6b4ac744519a050fe50e7c795a7c63579 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Mon, 14 Mar 2011 15:11:14 -0700 Subject: Added test and fixed up code so that it works --- nova/compute/manager.py | 16 +++++++++++----- nova/tests/test_compute.py | 21 +++++++++++++++++++++ nova/virt/fake.py | 6 +++++- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 057371d40..a7727a239 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -981,26 +981,32 @@ class ComputeManager(manager.Manager): def periodic_tasks(self, context=None): """Tasks to be run at a periodic interval.""" - super(ComputeManager, self).periodic_tasks(context) + error_list = super(ComputeManager, self).periodic_tasks(context) + if error_list is None: + error_list = [] + try: self._poll_instance_states(context) except Exception as ex: LOG.warning(_("Error during instance poll: %s"), unicode(ex)) + error_list.append(ex) + return error_list def _poll_instance_states(self, context): - vm_instances = self.driver.list_instances_detail(context) + vm_instances = self.driver.list_instances_detail() vm_instances = dict((vm.name, vm) for vm in vm_instances) # Keep a list of VMs not in the DB, cross them off as we find them vms_not_found_in_db = [vm.name for vm in vm_instances] db_instances = self.db.instance_get_all_by_host(context, self.host) + for db_instance in db_instances: name = db_instance['name'] vm_instance = vm_instances.get(name) if vm_instance is None: - LOG.info(_("Found instance '%(name)' in DB but no VM. " + LOG.info(_("Found instance '%(name)s' in DB but no VM. " "Shutting off.") % locals()) vm_state = power_state.SHUTOFF else: @@ -1010,7 +1016,7 @@ class ComputeManager(manager.Manager): db_state = db_instance['state'] if vm_state != db_state: LOG.info(_("DB/VM state mismatch. Changing state from " - "%(db_state) to %(vm_state)") % locals()) + "'%(db_state)s' to '%(vm_state)s'") % locals()) self.db.instance_set_state(context, db_instance['id'], vm_state) @@ -1026,5 +1032,5 @@ class ComputeManager(manager.Manager): for vm_not_found_in_db in vms_not_found_in_db: name = vm_not_found_in_db #TODO(justinsb): What to do here? Adopt it? Shut it down? - LOG.warning(_("Found VM not in DB: %(name). Ignoring") + LOG.warning(_("Found VM not in DB: '%(name)s'. Ignoring") % locals()) diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index e486050be..b9d0aa0b6 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -595,3 +595,24 @@ class ComputeTestCase(test.TestCase): db.instance_destroy(c, instance_id) db.volume_destroy(c, v_ref['id']) db.floating_ip_destroy(c, flo_addr) + + def test_run_kill_vm(self): + """Detect when a vm is terminated behind the scenes""" + instance_id = self._create_instance() + + self.compute.run_instance(self.context, instance_id) + + instances = db.instance_get_all(context.get_admin_context()) + LOG.info(_("Running instances: %s"), instances) + self.assertEqual(len(instances), 1) + + instance_name = instances[0].name + self.compute.driver.test_remove_vm(instance_name) + + # Force the compute manager to do its periodic poll + error_list = self.compute.periodic_tasks(context.get_admin_context()) + self.assertFalse(error_list) + + instances = db.instance_get_all(context.get_admin_context()) + LOG.info(_("After force-killing instances: %s"), instances) + self.assertEqual(len(instances), 0) diff --git a/nova/virt/fake.py b/nova/virt/fake.py index ccf2a7d68..e0e2369c7 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -106,7 +106,7 @@ class FakeConnection(driver.ComputeDriver): def list_instances_detail(self): info_list = [] - for instance in self.instances: + for instance in self.instances.values(): info_list.append(self._map_to_instance_info(instance)) return info_list @@ -448,3 +448,7 @@ class FakeConnection(driver.ComputeDriver): def unfilter_instance(self, instance_ref): """This method is supported only by libvirt.""" raise NotImplementedError('This method is supported only by libvirt.') + + def test_remove_vm(self, instance_name): + """ Removes the named VM, as if it crashed. For testing""" + self.instances.pop(instance_name) -- cgit From 9f135cc4d6069a0b882c8e848d3b6cb292002d10 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Mon, 14 Mar 2011 15:37:04 -0700 Subject: Implemented Hyper-V list_instances_detail function. Needs a cleanup by someone that knows the Hyper-V code --- nova/virt/hyperv.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/nova/virt/hyperv.py b/nova/virt/hyperv.py index aea7413c6..435272109 100644 --- a/nova/virt/hyperv.py +++ b/nova/virt/hyperv.py @@ -126,6 +126,19 @@ class HyperVConnection(driver.ComputeDriver): for v in self._conn.Msvm_ComputerSystem(['ElementName'])] return vms + def list_instances_detail(self): + #TODO(justinsb): This is a terrible implementation (1+N) + instance_infos = [] + for instance_name in self.list_instances(): + info = self.get_info(instance_name) + + state = info['state'] + + instance_info = driver.InstanceInfo(instance_name, state) + instance_infos.append(instance_info) + + return instance_infos + def spawn(self, instance): """ Create a new VM and start it.""" vm = self._lookup(instance.name) @@ -347,7 +360,7 @@ class HyperVConnection(driver.ComputeDriver): newinst = cl.new() #Copy the properties from the original. for prop in wmi_obj._properties: - newinst.Properties_.Item(prop).Value =\ + newinst.Properties_.Item(prop).Value = \ wmi_obj.Properties_.Item(prop).Value return newinst -- cgit From 9dce9ee5fe5a1df018b9a606a3ea35b2dbfc987e Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Mon, 14 Mar 2011 15:37:29 -0700 Subject: Clarified message when a VM is not running but still in DB --- nova/compute/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index a7727a239..019bb3c89 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -1007,7 +1007,7 @@ class ComputeManager(manager.Manager): vm_instance = vm_instances.get(name) if vm_instance is None: LOG.info(_("Found instance '%(name)s' in DB but no VM. " - "Shutting off.") % locals()) + "Setting state to shutoff.") % locals()) vm_state = power_state.SHUTOFF else: vm_state = vm_instance.state -- cgit From 365b98f4d52740ef85f8a8f098a32e441d7ac168 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Tue, 22 Mar 2011 21:42:17 -0700 Subject: Renamed check_instance -> check_isinstance to make intent clearer --- nova/utils.py | 2 +- nova/virt/connection.py | 2 +- nova/virt/fake.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/nova/utils.py b/nova/utils.py index e93f489be..2e653bda0 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -587,7 +587,7 @@ def get_from_path(items, path): return get_from_path(results, remainder) -def check_instance(obj, cls): +def check_isinstance(obj, cls): """Checks that obj is of type cls, and lets PyLint infer types""" if isinstance(obj, cls): return obj diff --git a/nova/virt/connection.py b/nova/virt/connection.py index d585b6c21..4ba31c7a7 100644 --- a/nova/virt/connection.py +++ b/nova/virt/connection.py @@ -74,4 +74,4 @@ def get_connection(read_only=False): if conn is None: LOG.error(_('Failed to open connection to the hypervisor')) sys.exit(1) - return utils.check_instance(conn, driver.ComputeDriver) + return utils.check_isinstance(conn, driver.ComputeDriver) diff --git a/nova/virt/fake.py b/nova/virt/fake.py index e0e2369c7..57b02e00b 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -100,7 +100,7 @@ class FakeConnection(driver.ComputeDriver): return self.instances.keys() def _map_to_instance_info(self, instance): - instance = utils.check_instance(instance, FakeInstance) + instance = utils.check_isinstance(instance, FakeInstance) info = driver.InstanceInfo(instance.name, instance.state) return info -- cgit From c8e8b44ef27e49b3986659ee0cb6bd77b38430d8 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Tue, 22 Mar 2011 22:01:39 -0700 Subject: Forgot this in the rename of check_instance -> check_isinstance --- nova/compute/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 019bb3c89..b21f0b836 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -117,7 +117,7 @@ class ComputeManager(manager.Manager): # and redocument the module docstring if not compute_driver: compute_driver = FLAGS.compute_driver - self.driver = utils.check_instance(utils.import_object( + self.driver = utils.check_isinstance(utils.import_object( compute_driver), driver.ComputeDriver) self.network_manager = utils.import_object(FLAGS.network_manager) -- cgit From 19da125805eedbfcfd202abac4a90c57e6c538c4 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Tue, 22 Mar 2011 22:38:37 -0700 Subject: Filled out the base-driver contract, so it's not a false-promise --- nova/compute/driver.py | 38 -------- nova/compute/manager.py | 3 +- nova/virt/driver.py | 228 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 230 insertions(+), 39 deletions(-) delete mode 100644 nova/compute/driver.py create mode 100644 nova/virt/driver.py diff --git a/nova/compute/driver.py b/nova/compute/driver.py deleted file mode 100644 index bda82c60a..000000000 --- a/nova/compute/driver.py +++ /dev/null @@ -1,38 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011 Justin Santa Barbara -# 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. - -""" -Driver base-classes: - - (Beginning of) the contract that compute drivers must follow, and shared - types that support that contract -""" - -from nova.compute import power_state - - -class InstanceInfo(object): - def __init__(self, name, state): - self.name = name - assert state in power_state.valid_states() - self.state = state - - -class ComputeDriver(object): - def list_instances_detail(self): - """Return a list of InstanceInfo for all registered VMs""" - raise NotImplementedError() diff --git a/nova/compute/manager.py b/nova/compute/manager.py index b21f0b836..f37651ea6 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -52,7 +52,7 @@ from nova import manager from nova import rpc from nova import utils from nova.compute import power_state -from nova.compute import driver +from nova.virt import driver FLAGS = flags.FLAGS flags.DEFINE_string('instances_path', '$state_path/instances', @@ -441,6 +441,7 @@ class ComputeManager(manager.Manager): #TODO(mdietz): we may want to split these into separate methods. if migration_ref['source_compute'] == FLAGS.host: + #NOTE(justinsb): Naughty calling of internal method self.driver._start(instance_ref) self.db.migration_update(context, migration_id, {'status': 'reverted'}) diff --git a/nova/virt/driver.py b/nova/virt/driver.py new file mode 100644 index 000000000..6c1b97ce9 --- /dev/null +++ b/nova/virt/driver.py @@ -0,0 +1,228 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 Justin Santa Barbara +# 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. + +""" +Driver base-classes: + + (Beginning of) the contract that compute drivers must follow, and shared + types that support that contract +""" + +from nova.compute import power_state + + +class InstanceInfo(object): + def __init__(self, name, state): + self.name = name + assert state in power_state.valid_states() + self.state = state + + +class ComputeDriver(object): + """Base class for compute drivers.""" + + def init_host(self, host): + """Adopt existing VM's running here""" + raise NotImplementedError() + + def get_info(self, instance_name): + """Get the current status of an instance, by name (not ID!) + + Returns a dict containing: + :state: the running state, one of the power_state codes + :max_mem: (int) the maximum memory in KBytes allowed + :mem: (int) the memory in KBytes used by the domain + :num_cpu: (int) the number of virtual CPUs for the domain + :cpu_time: (int) the CPU time used in nanoseconds + """ + raise NotImplementedError() + + def list_instances(self): + raise NotImplementedError() + + def list_instances_detail(self): + """Return a list of InstanceInfo for all registered VMs""" + raise NotImplementedError() + + def spawn(self, instance): + """Launch a VM for the specified instance""" + raise NotImplementedError() + + def destroy(self, instance, cleanup=True): + """Shutdown specified VM""" + raise NotImplementedError() + + def reboot(self, instance): + """Reboot specified VM""" + raise NotImplementedError() + + def snapshot_instance(self, context, instance_id, image_id): + raise NotImplementedError() + + def get_console_pool_info(self, console_type): + """??? + + Returns a dict containing: + :address: ??? + :username: ??? + :password: ??? + """ + raise NotImplementedError() + + def get_console_output(self, instance): + raise NotImplementedError() + + def get_ajax_console(self, instance): + raise NotImplementedError() + + def get_diagnostics(self, instance): + """Return data about VM diagnostics""" + raise NotImplementedError() + + def get_host_ip_addr(self): + raise NotImplementedError() + + def attach_volume(self, context, instance_id, volume_id, mountpoint): + raise NotImplementedError() + + def detach_volume(self, context, instance_id, volume_id): + raise NotImplementedError() + + def compare_cpu(self, context, cpu_info): + raise NotImplementedError() + + def migrate_disk_and_power_off(self, instance, dest): + """Transfers the VHD of a running instance to another host, then shuts + off the instance copies over the COW disk""" + raise NotImplementedError() + + def snapshot(self, instance, image_id): + """ Create snapshot from a running VM instance """ + raise NotImplementedError() + + def finish_resize(self, instance, disk_info): + """Completes a resize, turning on the migrated instance""" + raise NotImplementedError() + + def pause(self, instance, callback): + """Pause VM instance""" + raise NotImplementedError() + + def unpause(self, instance, callback): + """Unpause paused VM instance""" + raise NotImplementedError() + + def suspend(self, instance, callback): + """suspend the specified instance""" + raise NotImplementedError() + + def resume(self, instance, callback): + """resume the specified instance""" + raise NotImplementedError() + + def rescue(self, instance, callback): + """Rescue the specified instance""" + raise NotImplementedError() + + def unrescue(self, instance, callback): + """Unrescue the specified instance""" + raise NotImplementedError() + + def update_available_resource(self, ctxt, host): + """Updates compute manager resource info on ComputeNode table. + + This method is called when nova-compute launches, and + whenever admin executes "nova-manage service update_resource". + + :param ctxt: security context + :param host: hostname that compute manager is currently running + + """ + raise NotImplementedError() + + def live_migration(self, ctxt, instance_ref, dest, + post_method, recover_method): + """Spawning live_migration operation for distributing high-load. + + :params ctxt: security context + :params instance_ref: + nova.db.sqlalchemy.models.Instance object + instance object that is migrated. + :params dest: destination host + :params post_method: + post operation method. + expected nova.compute.manager.post_live_migration. + :params recover_method: + recovery method when any exception occurs. + expected nova.compute.manager.recover_live_migration. + + """ + raise NotImplementedError() + + def refresh_security_group_rules(self, security_group_id): + raise NotImplementedError() + + def refresh_security_group_members(self, security_group_id): + raise NotImplementedError() + + def reset_network(self, instance): + """reset networking for specified instance""" + raise NotImplementedError() + + def ensure_filtering_rules_for_instance(self, instance_ref): + """Setting up filtering rules and waiting for its completion. + + To migrate an instance, filtering rules to hypervisors + and firewalls are inevitable on destination host. + ( Waiting only for filtering rules to hypervisor, + since filtering rules to firewall rules can be set faster). + + Concretely, the below method must be called. + - setup_basic_filtering (for nova-basic, etc.) + - prepare_instance_filter(for nova-instance-instance-xxx, etc.) + + to_xml may have to be called since it defines PROJNET, PROJMASK. + but libvirt migrates those value through migrateToURI(), + so , no need to be called. + + Don't use thread for this method since migration should + not be started when setting-up filtering rules operations + are not completed. + + :params instance_ref: nova.db.sqlalchemy.models.Instance object + + """ + raise NotImplementedError() + + def unfilter_instance(self, instance): + """Stop filtering instance""" + raise NotImplementedError() + + def set_admin_password(self, context, instance_id, new_pass=None): + """Set the root/admin password for an instance on this server.""" + raise NotImplementedError() + + def inject_file(self, instance, b64_path, b64_contents): + """Create a file on the VM instance. The file path and contents + should be base64-encoded. + """ + raise NotImplementedError() + + def inject_network_info(self, instance): + """inject network info for specified instance""" + raise NotImplementedError() + -- cgit From a0432e417a13fd9579c40bdd54f0201b06470f45 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Tue, 22 Mar 2011 22:42:12 -0700 Subject: Added note about the advantages of using a type vs using a set of global constants --- nova/compute/power_state.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nova/compute/power_state.py b/nova/compute/power_state.py index 145362f97..d304285b2 100644 --- a/nova/compute/power_state.py +++ b/nova/compute/power_state.py @@ -31,7 +31,9 @@ CRASHED = 0x06 SUSPENDED = 0x07 FAILED = 0x08 -#TODO(justinsb): Power state really needs to be a proper class... +#TODO(justinsb): Power state really needs to be a proper class, +# so that we're not locked into the libvirt status codes and can put mapping +# logic here rather than spread throughout the code _STATE_MAP = { NOSTATE: 'pending', RUNNING: 'running', -- cgit From a4d78e44d7ca35a6cca4454667cab743409fd95a Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Tue, 22 Mar 2011 22:45:15 -0700 Subject: Added space in between # and TODO in #TODO --- nova/compute/manager.py | 2 +- nova/compute/power_state.py | 2 +- nova/utils.py | 2 +- nova/virt/hyperv.py | 2 +- nova/virt/xenapi/vmops.py | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index f37651ea6..cfd2b0ac4 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -1032,6 +1032,6 @@ class ComputeManager(manager.Manager): # Are there VMs not in the DB? for vm_not_found_in_db in vms_not_found_in_db: name = vm_not_found_in_db - #TODO(justinsb): What to do here? Adopt it? Shut it down? + # TODO(justinsb): What to do here? Adopt it? Shut it down? LOG.warning(_("Found VM not in DB: '%(name)s'. Ignoring") % locals()) diff --git a/nova/compute/power_state.py b/nova/compute/power_state.py index d304285b2..ed50e492e 100644 --- a/nova/compute/power_state.py +++ b/nova/compute/power_state.py @@ -31,7 +31,7 @@ CRASHED = 0x06 SUSPENDED = 0x07 FAILED = 0x08 -#TODO(justinsb): Power state really needs to be a proper class, +# TODO(justinsb): Power state really needs to be a proper class, # so that we're not locked into the libvirt status codes and can put mapping # logic here rather than spread throughout the code _STATE_MAP = { diff --git a/nova/utils.py b/nova/utils.py index 2e653bda0..36b384f4f 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -592,5 +592,5 @@ def check_isinstance(obj, cls): if isinstance(obj, cls): return obj raise Exception(_("Expected object of type: %s") % (str(cls))) - #TODO(justinsb): Can we make this better?? + # TODO(justinsb): Can we make this better?? return cls() # Ugly PyLint hack diff --git a/nova/virt/hyperv.py b/nova/virt/hyperv.py index 435272109..21e21ec13 100644 --- a/nova/virt/hyperv.py +++ b/nova/virt/hyperv.py @@ -127,7 +127,7 @@ class HyperVConnection(driver.ComputeDriver): return vms def list_instances_detail(self): - #TODO(justinsb): This is a terrible implementation (1+N) + # TODO(justinsb): This is a terrible implementation (1+N) instance_infos = [] for instance_name in self.list_instances(): info = self.get_info(instance_name) diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 3a58a887e..6cd61a86f 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -73,7 +73,7 @@ class VMOps(object): if not vm_rec["is_a_template"] and not vm_rec["is_control_domain"]: name = vm_rec["name_label"] - #TODO(justinsb): Yuk... + # TODO(justinsb): Yuk... openstack_format = VMHelper.compile_info(vm_rec) state = openstack_format['state'] @@ -932,7 +932,7 @@ class VMOps(object): """ vm_ref = self._get_vm_opaque_ref(instance_or_vm) data = self._session.call_xenapi_request('VM.get_xenstore_data', - (vm_ref, )) + (vm_ref,)) ret = {} if keys is None: keys = data.keys() -- cgit From 52c2bb5e7fadf12aae96d895d374990fd4990e29 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Tue, 22 Mar 2011 22:49:22 -0700 Subject: Cleaned up comment about virsh domain.info() return format --- nova/virt/libvirt_conn.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index e95bcac39..dfe0bca49 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -60,10 +60,10 @@ from nova import log as logging #from nova import test from nova import utils from nova.auth import manager -from nova.compute import driver from nova.compute import instance_types from nova.compute import power_state from nova.virt import disk +from nova.virt import driver from nova.virt import images libvirt = None @@ -135,8 +135,8 @@ def get_connection(read_only): def _late_load_cheetah(): global Template if Template is None: - t = __import__('Cheetah.Template', globals(), locals(), ['Template'], - -1) + t = __import__('Cheetah.Template', globals(), locals(), + ['Template'], -1) Template = t.Template @@ -238,12 +238,15 @@ class LibvirtConnection(driver.ComputeDriver): for x in self._conn.listDomainsID()] def _map_to_instance_info(self, domain): - # .info() returns a list of: - #state: one of the state values (virDomainState) - #maxMemory: the maximum memory used by the domain - #memory: the current amount of memory used by the domain - #nbVirtCPU: the number of virtual CPU - #cpuTime: the time used by the domain in nanoseconds + """Gets info from a virsh domain object into an InstanceInfo""" + + # domain.info() returns a list of: + # state: one of the state values (virDomainState) + # maxMemory: the maximum memory used by the domain + # memory: the current amount of memory used by the domain + # nbVirtCPU: the number of virtual CPU + # puTime: the time used by the domain in nanoseconds + (state, _max_mem, _mem, _num_cpu, _cpu_time) = domain.info() name = domain.name() -- cgit From 95a32b4ae8d418576799fb9dd5d34e73728d7a1f Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Tue, 22 Mar 2011 22:50:45 -0700 Subject: Clarified my "Yuk" comment --- nova/virt/xenapi/vmops.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 6cd61a86f..a0c84c803 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -73,7 +73,7 @@ class VMOps(object): if not vm_rec["is_a_template"] and not vm_rec["is_control_domain"]: name = vm_rec["name_label"] - # TODO(justinsb): Yuk... + # TODO(justinsb): This a roundabout way to map the state openstack_format = VMHelper.compile_info(vm_rec) state = openstack_format['state'] -- cgit From b69a63c5d7458610b6e8931b4955c0b5b2b468f5 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Tue, 22 Mar 2011 22:58:52 -0700 Subject: Fixed up the new location of driver.py --- nova/virt/driver.py | 5 ++++- nova/virt/fake.py | 2 +- nova/virt/hyperv.py | 2 +- nova/virt/xenapi_conn.py | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/nova/virt/driver.py b/nova/virt/driver.py index 6c1b97ce9..d01a91b93 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -33,7 +33,10 @@ class InstanceInfo(object): class ComputeDriver(object): - """Base class for compute drivers.""" + """Base class for compute drivers. + + Lots of documentation is currently on fake.py. + """ def init_host(self, host): """Adopt existing VM's running here""" diff --git a/nova/virt/fake.py b/nova/virt/fake.py index 57b02e00b..5b0fe1877 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -27,8 +27,8 @@ semantics of real hypervisor connections. from nova import exception from nova import utils -from nova.compute import driver from nova.compute import power_state +from nova.virt import driver def get_connection(_): diff --git a/nova/virt/hyperv.py b/nova/virt/hyperv.py index 21e21ec13..bd45dfe0e 100644 --- a/nova/virt/hyperv.py +++ b/nova/virt/hyperv.py @@ -67,8 +67,8 @@ from nova import exception from nova import flags from nova import log as logging from nova.auth import manager -from nova.compute import driver from nova.compute import power_state +from nova.virt import driver from nova.virt import images wmi = None diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index 9390db0bb..b5bff6c26 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -69,7 +69,7 @@ from nova import db from nova import utils from nova import flags from nova import log as logging -from nova.compute import driver +from nova.virt import driver from nova.virt.xenapi.vmops import VMOps from nova.virt.xenapi.volumeops import VolumeOps -- cgit From 7a93455f41e5198fdce8aa1b3091efd956e1c186 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Wed, 23 Mar 2011 16:49:50 -0700 Subject: Doh! Missed two places which were importing the old driver location --- nova/virt/connection.py | 2 +- nova/virt/xenapi/vmops.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/virt/connection.py b/nova/virt/connection.py index 4ba31c7a7..af7001715 100644 --- a/nova/virt/connection.py +++ b/nova/virt/connection.py @@ -24,7 +24,7 @@ import sys from nova import flags from nova import log as logging from nova import utils -from nova.compute import driver +from nova.virt import driver from nova.virt import fake from nova.virt import libvirt_conn from nova.virt import xenapi_conn diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 2a9694f45..3fd98be67 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -35,8 +35,8 @@ from nova import exception from nova import utils from nova.auth.manager import AuthManager -from nova.compute import driver from nova.compute import power_state +from nova.virt import driver from nova.virt.xenapi.network_utils import NetworkHelper from nova.virt.xenapi.vm_utils import VMHelper from nova.virt.xenapi.vm_utils import ImageType -- cgit From 3c295817f91eb7c76a64d157ff4a938c85075a36 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Wed, 23 Mar 2011 18:50:30 -0700 Subject: pep8 fixes, backported some important fixes that didn't make it over from my testing system :-( --- nova/compute/manager.py | 2 +- nova/compute/power_state.py | 2 +- nova/virt/driver.py | 9 ++++----- nova/virt/libvirt_conn.py | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index d85ead88b..b67b27dd0 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -1001,7 +1001,7 @@ class ComputeManager(manager.Manager): vm_instances = dict((vm.name, vm) for vm in vm_instances) # Keep a list of VMs not in the DB, cross them off as we find them - vms_not_found_in_db = [vm.name for vm in vm_instances] + vms_not_found_in_db = list(vm_instances.keys()) db_instances = self.db.instance_get_all_by_host(context, self.host) diff --git a/nova/compute/power_state.py b/nova/compute/power_state.py index ed50e492e..ef013b2ef 100644 --- a/nova/compute/power_state.py +++ b/nova/compute/power_state.py @@ -51,4 +51,4 @@ def name(code): def valid_states(): - return _STATE_MAP.values() + return _STATE_MAP.keys() diff --git a/nova/virt/driver.py b/nova/virt/driver.py index d01a91b93..e82f49ebe 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -28,13 +28,13 @@ from nova.compute import power_state class InstanceInfo(object): def __init__(self, name, state): self.name = name - assert state in power_state.valid_states() + assert state in power_state.valid_states(), "Bad state: %s" % state self.state = state class ComputeDriver(object): """Base class for compute drivers. - + Lots of documentation is currently on fake.py. """ @@ -44,7 +44,7 @@ class ComputeDriver(object): def get_info(self, instance_name): """Get the current status of an instance, by name (not ID!) - + Returns a dict containing: :state: the running state, one of the power_state codes :max_mem: (int) the maximum memory in KBytes allowed @@ -78,7 +78,7 @@ class ComputeDriver(object): def get_console_pool_info(self, console_type): """??? - + Returns a dict containing: :address: ??? :username: ??? @@ -228,4 +228,3 @@ class ComputeDriver(object): def inject_network_info(self, instance): """inject network info for specified instance""" raise NotImplementedError() - diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index e57859f9d..ddc525e06 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -255,7 +255,7 @@ class LibvirtConnection(driver.ComputeDriver): def list_instances_detail(self): infos = [] for domain_id in self._conn.listDomainsID(): - domain = self._conn.lookupById(domain_id) + domain = self._conn.lookupByID(domain_id) info = self._map_to_instance_info(domain) infos.append(info) return infos -- cgit From 31940b550e49c23ba29c71a0e0593a6d14331516 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Wed, 23 Mar 2011 19:02:20 -0700 Subject: Added revert_resize to base class --- nova/virt/driver.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nova/virt/driver.py b/nova/virt/driver.py index e82f49ebe..4c77048be 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -120,6 +120,10 @@ class ComputeDriver(object): def finish_resize(self, instance, disk_info): """Completes a resize, turning on the migrated instance""" raise NotImplementedError() + + def revert_resize(self, instance): + """Reverts a resize, powering back on the instance""" + raise NotImplementedError() def pause(self, instance, callback): """Pause VM instance""" -- cgit From 3cde42aaac50e32f2c8fcd4493c40a2eaf1a0d4d Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Wed, 23 Mar 2011 19:15:41 -0700 Subject: pep8 fix --- nova/virt/driver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/virt/driver.py b/nova/virt/driver.py index 4c77048be..0e3a4aa3b 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -120,7 +120,7 @@ class ComputeDriver(object): def finish_resize(self, instance, disk_info): """Completes a resize, turning on the migrated instance""" raise NotImplementedError() - + def revert_resize(self, instance): """Reverts a resize, powering back on the instance""" raise NotImplementedError() -- cgit