diff options
| author | Jenkins <jenkins@review.openstack.org> | 2013-01-09 02:30:25 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2013-01-09 02:30:25 +0000 |
| commit | 9026553e2f6af93fa8a15dbb9dd452f73d09ac1d (patch) | |
| tree | b1918359cfab380c382f36e4ad970cedcb0f3cac /nova/compute | |
| parent | db3da2d95626ed25ed8fc925662a5a17dc7d32a2 (diff) | |
| parent | 6fc00d34651858308c5b08fdabe8a0b9ce663e26 (diff) | |
Merge "Adds to manager init_host validation for instances location"
Diffstat (limited to 'nova/compute')
| -rw-r--r-- | nova/compute/manager.py | 67 | ||||
| -rw-r--r-- | nova/compute/utils.py | 60 |
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 |
