-Fixed indent for _get_ip_version
-Added LoopingCall to destroy as suggested by earlier bug report -Standardized all LoopingCall uses to include useful logging and better error handling
This commit is contained in:
commit
1b56402bff
@ -154,8 +154,8 @@ def _get_net_and_prefixlen(cidr):
|
||||
|
||||
|
||||
def _get_ip_version(cidr):
|
||||
net = IPy.IP(cidr)
|
||||
return int(net.version())
|
||||
net = IPy.IP(cidr)
|
||||
return int(net.version())
|
||||
|
||||
|
||||
def _get_network_info(instance):
|
||||
@ -362,28 +362,19 @@ class LibvirtConnection(driver.ComputeDriver):
|
||||
locals())
|
||||
raise
|
||||
|
||||
# We'll save this for when we do shutdown,
|
||||
# instead of destroy - but destroy returns immediately
|
||||
timer = utils.LoopingCall(f=None)
|
||||
def _wait_for_destroy():
|
||||
"""Called at an interval until the VM is gone."""
|
||||
instance_name = instance['name']
|
||||
|
||||
while True:
|
||||
try:
|
||||
state = self.get_info(instance['name'])['state']
|
||||
db.instance_set_state(context.get_admin_context(),
|
||||
instance['id'], state)
|
||||
if state == power_state.SHUTOFF:
|
||||
break
|
||||
state = self.get_info(instance_name)['state']
|
||||
except exception.NotFound:
|
||||
msg = _("Instance %s destroyed successfully.") % instance_name
|
||||
LOG.info(msg)
|
||||
raise utils.LoopingCallDone
|
||||
|
||||
# Let's not hammer on the DB
|
||||
time.sleep(1)
|
||||
except Exception as ex:
|
||||
msg = _("Error encountered when destroying instance '%(id)s': "
|
||||
"%(ex)s") % {"id": instance["id"], "ex": ex}
|
||||
LOG.debug(msg)
|
||||
db.instance_set_state(context.get_admin_context(),
|
||||
instance['id'],
|
||||
power_state.SHUTOFF)
|
||||
break
|
||||
timer = utils.LoopingCall(_wait_for_destroy)
|
||||
timer.start(interval=0.5, now=True)
|
||||
|
||||
self.firewall_driver.unfilter_instance(instance)
|
||||
|
||||
@ -525,6 +516,12 @@ class LibvirtConnection(driver.ComputeDriver):
|
||||
|
||||
@exception.wrap_exception
|
||||
def reboot(self, instance):
|
||||
"""Reboot a virtual machine, given an instance reference.
|
||||
|
||||
This method actually destroys and re-creates the domain to ensure the
|
||||
reboot happens, as the guest OS cannot ignore this action.
|
||||
|
||||
"""
|
||||
self.destroy(instance, False)
|
||||
xml = self.to_xml(instance)
|
||||
self.firewall_driver.setup_basic_filtering(instance)
|
||||
@ -532,24 +529,23 @@ class LibvirtConnection(driver.ComputeDriver):
|
||||
self._create_new_domain(xml)
|
||||
self.firewall_driver.apply_instance_filter(instance)
|
||||
|
||||
timer = utils.LoopingCall(f=None)
|
||||
|
||||
def _wait_for_reboot():
|
||||
try:
|
||||
state = self.get_info(instance['name'])['state']
|
||||
db.instance_set_state(context.get_admin_context(),
|
||||
instance['id'], state)
|
||||
if state == power_state.RUNNING:
|
||||
LOG.debug(_('instance %s: rebooted'), instance['name'])
|
||||
timer.stop()
|
||||
except Exception, exn:
|
||||
LOG.exception(_('_wait_for_reboot failed: %s'), exn)
|
||||
db.instance_set_state(context.get_admin_context(),
|
||||
instance['id'],
|
||||
power_state.SHUTDOWN)
|
||||
timer.stop()
|
||||
"""Called at an interval until the VM is running again."""
|
||||
instance_name = instance['name']
|
||||
|
||||
timer.f = _wait_for_reboot
|
||||
try:
|
||||
state = self.get_info(instance_name)['state']
|
||||
except exception.NotFound:
|
||||
msg = _("During reboot, %s disappeared.") % instance_name
|
||||
LOG.error(msg)
|
||||
raise utils.LoopingCallDone
|
||||
|
||||
if state == power_state.RUNNING:
|
||||
msg = _("Instance %s rebooted successfully.") % instance_name
|
||||
LOG.info(msg)
|
||||
raise utils.LoopingCallDone
|
||||
|
||||
timer = utils.LoopingCall(_wait_for_reboot)
|
||||
return timer.start(interval=0.5, now=True)
|
||||
|
||||
@exception.wrap_exception
|
||||
@ -569,7 +565,15 @@ class LibvirtConnection(driver.ComputeDriver):
|
||||
raise exception.ApiError("resume not supported for libvirt")
|
||||
|
||||
@exception.wrap_exception
|
||||
def rescue(self, instance, callback=None):
|
||||
def rescue(self, instance):
|
||||
"""Loads a VM using rescue images.
|
||||
|
||||
A rescue is normally performed when something goes wrong with the
|
||||
primary images and data needs to be corrected/recovered. Rescuing
|
||||
should not edit or over-ride the original image, only allow for
|
||||
data recovery.
|
||||
|
||||
"""
|
||||
self.destroy(instance, False)
|
||||
|
||||
xml = self.to_xml(instance, rescue=True)
|
||||
@ -579,29 +583,33 @@ class LibvirtConnection(driver.ComputeDriver):
|
||||
self._create_image(instance, xml, '.rescue', rescue_images)
|
||||
self._create_new_domain(xml)
|
||||
|
||||
timer = utils.LoopingCall(f=None)
|
||||
|
||||
def _wait_for_rescue():
|
||||
try:
|
||||
state = self.get_info(instance['name'])['state']
|
||||
db.instance_set_state(None, instance['id'], state)
|
||||
if state == power_state.RUNNING:
|
||||
LOG.debug(_('instance %s: rescued'), instance['name'])
|
||||
timer.stop()
|
||||
except Exception, exn:
|
||||
LOG.exception(_('_wait_for_rescue failed: %s'), exn)
|
||||
db.instance_set_state(None,
|
||||
instance['id'],
|
||||
power_state.SHUTDOWN)
|
||||
timer.stop()
|
||||
"""Called at an interval until the VM is running again."""
|
||||
instance_name = instance['name']
|
||||
|
||||
timer.f = _wait_for_rescue
|
||||
try:
|
||||
state = self.get_info(instance_name)['state']
|
||||
except exception.NotFound:
|
||||
msg = _("During reboot, %s disappeared.") % instance_name
|
||||
LOG.error(msg)
|
||||
raise utils.LoopingCallDone
|
||||
|
||||
if state == power_state.RUNNING:
|
||||
msg = _("Instance %s rescued successfully.") % instance_name
|
||||
LOG.info(msg)
|
||||
raise utils.LoopingCallDone
|
||||
|
||||
timer = utils.LoopingCall(_wait_for_rescue)
|
||||
return timer.start(interval=0.5, now=True)
|
||||
|
||||
@exception.wrap_exception
|
||||
def unrescue(self, instance, callback=None):
|
||||
# NOTE(vish): Because reboot destroys and recreates an instance using
|
||||
# the normal xml file, we can just call reboot here
|
||||
def unrescue(self, instance):
|
||||
"""Reboot the VM which is being rescued back into primary images.
|
||||
|
||||
Because reboot destroys and re-creates instances, unresue should
|
||||
simply call reboot.
|
||||
|
||||
"""
|
||||
self.reboot(instance)
|
||||
|
||||
@exception.wrap_exception
|
||||
@ -613,10 +621,6 @@ class LibvirtConnection(driver.ComputeDriver):
|
||||
@exception.wrap_exception
|
||||
def spawn(self, instance, network_info=None):
|
||||
xml = self.to_xml(instance, False, network_info)
|
||||
db.instance_set_state(context.get_admin_context(),
|
||||
instance['id'],
|
||||
power_state.NOSTATE,
|
||||
'launching')
|
||||
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)
|
||||
@ -629,25 +633,23 @@ class LibvirtConnection(driver.ComputeDriver):
|
||||
instance['name'])
|
||||
domain.setAutostart(1)
|
||||
|
||||
timer = utils.LoopingCall(f=None)
|
||||
|
||||
def _wait_for_boot():
|
||||
try:
|
||||
state = self.get_info(instance['name'])['state']
|
||||
db.instance_set_state(context.get_admin_context(),
|
||||
instance['id'], state)
|
||||
if state == power_state.RUNNING:
|
||||
LOG.debug(_('instance %s: booted'), instance['name'])
|
||||
timer.stop()
|
||||
except:
|
||||
LOG.exception(_('instance %s: failed to boot'),
|
||||
instance['name'])
|
||||
db.instance_set_state(context.get_admin_context(),
|
||||
instance['id'],
|
||||
power_state.SHUTDOWN)
|
||||
timer.stop()
|
||||
"""Called at an interval until the VM is running."""
|
||||
instance_name = instance['name']
|
||||
|
||||
timer.f = _wait_for_boot
|
||||
try:
|
||||
state = self.get_info(instance_name)['state']
|
||||
except exception.NotFound:
|
||||
msg = _("During reboot, %s disappeared.") % instance_name
|
||||
LOG.error(msg)
|
||||
raise utils.LoopingCallDone
|
||||
|
||||
if state == power_state.RUNNING:
|
||||
msg = _("Instance %s spawned successfully.") % instance_name
|
||||
LOG.info(msg)
|
||||
raise utils.LoopingCallDone
|
||||
|
||||
timer = utils.LoopingCall(_wait_for_boot)
|
||||
return timer.start(interval=0.5, now=True)
|
||||
|
||||
def _flush_xen_console(self, virsh_output):
|
||||
@ -1048,21 +1050,24 @@ 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
|
||||
"""Retrieve information from libvirt for a specific instance name.
|
||||
|
||||
If a libvirt error is encountered during lookup, we might raise a
|
||||
NotFound exception or Error exception depending on how severe the
|
||||
libvirt error is.
|
||||
|
||||
"""
|
||||
try:
|
||||
virt_dom = self._conn.lookupByName(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
|
||||
except libvirt.libvirtError as ex:
|
||||
error_code = ex.get_error_code()
|
||||
if error_code == libvirt.VIR_ERR_NO_DOMAIN:
|
||||
msg = _("Instance %s not found") % instance_name
|
||||
raise exception.NotFound(msg)
|
||||
|
||||
msg = _("Error from libvirt while looking up %(instance_name)s: "
|
||||
"[Error Code %(error_code)s] %(ex)s") % locals()
|
||||
raise exception.Error(msg)
|
||||
|
||||
(state, max_mem, mem, num_cpu, cpu_time) = virt_dom.info()
|
||||
return {'state': state,
|
||||
|
Loading…
Reference in New Issue
Block a user