summaryrefslogtreecommitdiffstats
path: root/nova/compute
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2013-01-09 02:30:25 +0000
committerGerrit Code Review <review@openstack.org>2013-01-09 02:30:25 +0000
commit9026553e2f6af93fa8a15dbb9dd452f73d09ac1d (patch)
treeb1918359cfab380c382f36e4ad970cedcb0f3cac /nova/compute
parentdb3da2d95626ed25ed8fc925662a5a17dc7d32a2 (diff)
parent6fc00d34651858308c5b08fdabe8a0b9ce663e26 (diff)
Merge "Adds to manager init_host validation for instances location"
Diffstat (limited to 'nova/compute')
-rw-r--r--nova/compute/manager.py67
-rw-r--r--nova/compute/utils.py60
2 files changed, 127 insertions, 0 deletions
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index f1a68345c..e9a2fa743 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -386,6 +386,71 @@ class ComputeManager(manager.SchedulerDependentManager):
return self.conductor_api.instance_get_all_by_host(context, self.host)
+ def _destroy_evacuated_instances(self, context):
+ """Destroys evacuated instances.
+
+ While the compute was down the instances running on it could be
+ evacuated to another host. Checking that instance host identical to
+ current host. Otherwise destroying it
+ """
+
+ # getting all vms on this host
+ local_instances = []
+ try:
+ # try to find all local instances by uuid
+ for uuid in self.driver.list_instance_uuids():
+ try:
+ local_instances.append(self.conductor_api.
+ instance_get_by_uuid(context, uuid))
+ except exception.InstanceNotFound as e:
+ LOG.error(_('Instance %(uuid)s found in the '
+ 'hypervisor, but not in the database'),
+ locals())
+ continue
+ except NotImplementedError:
+ # the driver doesn't support uuids listing, will do it in ugly way
+ for instance_name in self.driver.list_instances():
+ try:
+ # couldn't find better way to find instance in db by it's
+ # name if i will run on the list of this host instances it
+ # will be hard to ignore instances that were created
+ # outside openstack. returns -1 if instance name doesn't
+ # match template
+ instance_id = compute_utils.parse_decimal_id(CONF
+ .instance_name_template, instance_name)
+
+ if instance_id == -1:
+ continue
+
+ local_instances.append(self.conductor_api.
+ instance_get(context, instance_id))
+ except exception.InstanceNotFound as e:
+ LOG.error(_('Instance %(instance_name)s found in the '
+ 'hypervisor, but not in the database'),
+ locals())
+ continue
+
+ for instance in local_instances:
+ instance_host = instance['host']
+ host = self.host
+ instance_name = instance['name']
+ if instance['host'] != host:
+ LOG.info(_('instance host %(instance_host)s is not equal to '
+ 'current host %(host)s. '
+ 'Deleting zombie instance %(instance_name)s'),
+ locals())
+
+ network_info = self._get_instance_nw_info(context, instance)
+ bdi = self._get_instance_volume_block_device_info(context,
+ instance['uuid'])
+
+ self.driver.destroy(instance,
+ self._legacy_nw_info(network_info),
+ bdi,
+ False)
+
+ LOG.info(_('zombie vm destroyed'))
+
def _init_instance(self, context, instance):
'''Initialize this instance during service init.'''
db_state = instance['power_state']
@@ -450,6 +515,8 @@ class ComputeManager(manager.SchedulerDependentManager):
self.driver.filter_defer_apply_on()
try:
+ # checking that instance was not already evacuated to other host
+ self._destroy_evacuated_instances(context)
for instance in instances:
self._init_instance(context, instance)
finally:
diff --git a/nova/compute/utils.py b/nova/compute/utils.py
index 8852cb820..6d6b7cac9 100644
--- a/nova/compute/utils.py
+++ b/nova/compute/utils.py
@@ -253,3 +253,63 @@ def usage_volume_info(vol_usage):
vol_usage['curr_write_bytes'])
return usage_info
+
+
+def parse_decimal_id(template, instance_name):
+ """Finds instance decimal id from instance name
+
+ :param template: template e.g. instance-%03x-james
+ :param instance_name: instance name like instance-007-james
+
+ :returns: parsed decimal id, e.g. 7 from the input above
+ """
+
+ # find pattern like %05x, %d..etc.
+ reg = re.search('(%\d*)([ioxds])', template)
+ format = reg.group(0)
+
+ # split template to get prefix and suffix
+ tokens = template.split(format)
+
+ if tokens[0]:
+ if not instance_name.startswith(tokens[0]):
+ # template prefix not match
+ return -1
+ instance_name = instance_name[len(tokens[0]):]
+
+ if tokens[1]:
+ if not instance_name.endswith(tokens[1]):
+ # template suffix not match
+ return -1
+ instance_name = instance_name[:-len(tokens[1])]
+
+ # validate that instance_id length matches
+ expected_length = format[1:-1]
+
+ # if expected length is empty it means instance_id can be of any length
+ if expected_length:
+ if len(instance_name) < int(expected_length):
+ return -1
+ # if instance_id has preciding zeroes it must be of expected length
+ if (instance_name[:1] == '0' and
+ len(instance_name) != int(expected_length)):
+ return -1
+
+ # if the minimal expected length empty, there should be no preceding zeros
+ elif instance_name[0] == '0':
+ return -1
+
+ # finding base of the template to convert to decimal
+ base_fmt = format[-1:]
+ base = 10
+ if base_fmt == 'x':
+ base = 16
+ elif base_fmt == 'o':
+ base = 8
+
+ try:
+ res = int(instance_name, base)
+ except ValueError:
+ res = -1
+
+ return res