summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustin Santa Barbara <justin@fathomdb.com>2011-04-07 23:52:48 +0000
committerTarmac <>2011-04-07 23:52:48 +0000
commitdf0e479e204ba5e4c2b01f59a2e7249bd780572e (patch)
tree26566a1470599e6b2f2dbbc21b8c56fdd21764a0
parent25abb7036d96f41b3161fc8bd3df575c32493e67 (diff)
parent0c5f70c0bcf9395fb25a231057d997b075d04fda (diff)
downloadnova-df0e479e204ba5e4c2b01f59a2e7249bd780572e.tar.gz
nova-df0e479e204ba5e4c2b01f59a2e7249bd780572e.tar.xz
nova-df0e479e204ba5e4c2b01f59a2e7249bd780572e.zip
Keep guest instances when libvirt host restarts
-rw-r--r--nova/compute/manager.py8
-rw-r--r--nova/tests/test_compute.py3
-rw-r--r--nova/virt/libvirt_conn.py56
3 files changed, 48 insertions, 19 deletions
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 08b772517..bbc0e5f62 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -1097,12 +1097,8 @@ class ComputeManager(manager.SchedulerDependentManager):
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'])
+ # NOTE(justinsb): We no longer auto-remove SHUTOFF instances
+ # It's quite hard to get them back when we do.
# Are there VMs not in the DB?
for vm_not_found_in_db in vms_not_found_in_db:
diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py
index 1917dff3e..393110791 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -666,4 +666,5 @@ class ComputeTestCase(test.TestCase):
instances = db.instance_get_all(context.get_admin_context())
LOG.info(_("After force-killing instances: %s"), instances)
- self.assertEqual(len(instances), 0)
+ self.assertEqual(len(instances), 1)
+ self.assertEqual(power_state.SHUTOFF, instances[0]['state'])
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index d8d27a98e..75602f3d0 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -117,6 +117,8 @@ flags.DEFINE_integer('live_migration_bandwidth', 0,
'Define live migration behavior')
flags.DEFINE_string('qemu_img', 'qemu-img',
'binary to use for qemu-img commands')
+flags.DEFINE_bool('start_guests_on_host_boot', False,
+ 'Whether to restart guests when the host reboots')
def get_connection(read_only):
@@ -231,12 +233,8 @@ class LibvirtConnection(driver.ComputeDriver):
{'name': instance['name'], 'state': state})
db.instance_set_state(ctxt, instance['id'], state)
- if 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.
- db.instance_destroy(ctxt, instance['id'])
+ # NOTE(justinsb): We no longer delete SHUTOFF instances,
+ # the user may want to power them back on
if state != power_state.RUNNING:
continue
@@ -475,7 +473,7 @@ class LibvirtConnection(driver.ComputeDriver):
xml = self.to_xml(instance)
self.firewall_driver.setup_basic_filtering(instance)
self.firewall_driver.prepare_instance_filter(instance)
- self._conn.createXML(xml, 0)
+ self._create_new_domain(xml)
self.firewall_driver.apply_instance_filter(instance)
timer = utils.LoopingCall(f=None)
@@ -523,7 +521,7 @@ class LibvirtConnection(driver.ComputeDriver):
'kernel_id': FLAGS.rescue_kernel_id,
'ramdisk_id': FLAGS.rescue_ramdisk_id}
self._create_image(instance, xml, '.rescue', rescue_images)
- self._conn.createXML(xml, 0)
+ self._create_new_domain(xml)
timer = utils.LoopingCall(f=None)
@@ -566,10 +564,15 @@ class LibvirtConnection(driver.ComputeDriver):
self.firewall_driver.setup_basic_filtering(instance, network_info)
self.firewall_driver.prepare_instance_filter(instance, network_info)
self._create_image(instance, xml, network_info)
- self._conn.createXML(xml, 0)
+ domain = self._create_new_domain(xml)
LOG.debug(_("instance %s: is running"), instance['name'])
self.firewall_driver.apply_instance_filter(instance)
+ if FLAGS.start_guests_on_host_boot:
+ LOG.debug(_("instance %s: setting autostart ON") %
+ instance['name'])
+ domain.setAutostart(1)
+
timer = utils.LoopingCall(f=None)
def _wait_for_boot():
@@ -989,11 +992,22 @@ class LibvirtConnection(driver.ComputeDriver):
return xml
def get_info(self, instance_name):
+ # NOTE(justinsb): When libvirt isn't running / can't connect, we get:
+ # libvir: Remote error : unable to connect to
+ # '/var/run/libvirt/libvirt-sock', libvirtd may need to be started:
+ # No such file or directory
try:
virt_dom = self._conn.lookupByName(instance_name)
- except:
- raise exception.NotFound(_("Instance %s not found")
- % instance_name)
+ except libvirt.libvirtError as e:
+ errcode = e.get_error_code()
+ if errcode == libvirt.VIR_ERR_NO_DOMAIN:
+ raise exception.NotFound(_("Instance %s not found")
+ % instance_name)
+ LOG.warning(_("Error from libvirt during lookup. "
+ "Code=%(errcode)s Error=%(e)s") %
+ locals())
+ raise
+
(state, max_mem, mem, num_cpu, cpu_time) = virt_dom.info()
return {'state': state,
'max_mem': max_mem,
@@ -1001,6 +1015,24 @@ class LibvirtConnection(driver.ComputeDriver):
'num_cpu': num_cpu,
'cpu_time': cpu_time}
+ def _create_new_domain(self, xml, persistent=True, launch_flags=0):
+ # NOTE(justinsb): libvirt has two types of domain:
+ # * a transient domain disappears when the guest is shutdown
+ # or the host is rebooted.
+ # * a permanent domain is not automatically deleted
+ # NOTE(justinsb): Even for ephemeral instances, transient seems risky
+
+ if persistent:
+ # To create a persistent domain, first define it, then launch it.
+ domain = self._conn.defineXML(xml)
+
+ domain.createWithFlags(launch_flags)
+ else:
+ # createXML call creates a transient domain
+ domain = self._conn.createXML(xml, launch_flags)
+
+ return domain
+
def get_diagnostics(self, instance_name):
raise exception.ApiError(_("diagnostics are not supported "
"for libvirt"))