Skip to content

Commit

Permalink
Fallback to conductor if types are not stashed.
Browse files Browse the repository at this point in the history
If the instance types are not stashed, fallback to
the conductor API to retrieve them.

bug 1164110

Change-Id: I1f0ef48e072f8580980de5bd8d43cf2206cd7d27
(cherry picked from commit e9c88b7)
  • Loading branch information
Brian Elliott authored and vishvananda committed Apr 12, 2013
1 parent fd66545 commit 05e1c47
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 14 deletions.
41 changes: 31 additions & 10 deletions nova/compute/resource_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ def resize_claim(self, context, instance_ref, instance_type, limits=None):

# Mark the resources in-use for the resize landing on this
# compute host:
self._update_usage_from_migration(instance_ref, self.compute_node,
migration_ref)
self._update_usage_from_migration(context, instance_ref,
self.compute_node, migration_ref)
elevated = context.elevated()
self._update(elevated, self.compute_node)

Expand Down Expand Up @@ -263,7 +263,7 @@ def update_available_resource(self, context, delete=False):
migrations = capi.migration_get_in_progress_by_host_and_node(context,
self.host, self.nodename)

self._update_usage_from_migrations(resources, migrations)
self._update_usage_from_migrations(context, resources, migrations)

# Detect and account for orphaned instances that may exist on the
# hypervisor, but are not in the DB:
Expand Down Expand Up @@ -387,7 +387,8 @@ def _update_usage(self, resources, usage, sign=1):
resources['running_vms'] = self.stats.num_instances
resources['vcpus_used'] = self.stats.num_vcpus_used

def _update_usage_from_migration(self, instance, resources, migration):
def _update_usage_from_migration(self, context, instance, resources,
migration):
"""Update usage for a single migration. The record may
represent an incoming or outbound migration.
"""
Expand All @@ -408,27 +409,31 @@ def _update_usage_from_migration(self, instance, resources, migration):
# instance is *not* in:
if (instance['instance_type_id'] ==
migration['old_instance_type_id']):
itype = instance_types.extract_instance_type(instance)
itype = self._get_instance_type(context, instance, 'new_',
migration['new_instance_type_id'])
else:
# instance record already has new flavor, hold space for a
# possible revert to the old instance type:
itype = instance_types.extract_instance_type(instance, 'old_')
itype = self._get_instance_type(context, instance, 'old_',
migration['old_instance_type_id'])

elif incoming and not record:
# instance has not yet migrated here:
itype = instance_types.extract_instance_type(instance, 'new_')
itype = self._get_instance_type(context, instance, 'new_',
migration['new_instance_type_id'])

elif outbound and not record:
# instance migrated, but record usage for a possible revert:
itype = instance_types.extract_instance_type(instance, 'old_')
itype = self._get_instance_type(context, instance, 'old_',
migration['old_instance_type_id'])

if itype:
self.stats.update_stats_for_migration(itype)
self._update_usage(resources, itype)
resources['stats'] = self.stats
self.tracked_migrations[uuid] = (migration, itype)

def _update_usage_from_migrations(self, resources, migrations):
def _update_usage_from_migrations(self, context, resources, migrations):

self.tracked_migrations.clear()

Expand Down Expand Up @@ -459,7 +464,7 @@ def _update_usage_from_migrations(self, resources, migrations):

for migration in filtered.values():
try:
self._update_usage_from_migration(instance, resources,
self._update_usage_from_migration(context, instance, resources,
migration)
except exception.InstanceTypeNotFound:
LOG.warn(_("InstanceType could not be found, skipping "
Expand Down Expand Up @@ -575,3 +580,19 @@ def _instance_in_resize_state(self, instance):
return True

return False

def _get_instance_type(self, context, instance, prefix,
instance_type_id=None):
"""Get the instance type from sys metadata if it's stashed. If not,
fall back to fetching it via the conductor API.
See bug 1164110
"""
if not instance_type_id:
instance_type_id = instance['instance_type_id']

try:
return instance_types.extract_instance_type(instance, prefix)
except KeyError:
return self.conductor_api.instance_type_get(context,
instance_type_id)
26 changes: 22 additions & 4 deletions nova/tests/compute/test_resource_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,14 +161,18 @@ def _fake_instance_system_metadata(self, instance_type, prefix=''):
'value': instance_type[key]})
return sys_meta

def _fake_instance(self, *args, **kwargs):
def _fake_instance(self, stash=True, **kwargs):

# Default to an instance ready to resize to or from the same
# instance_type
itype = self._fake_instance_type_create()
sys_meta = (self._fake_instance_system_metadata(itype) +
self._fake_instance_system_metadata(itype, 'new_') +
self._fake_instance_system_metadata(itype, 'old_'))
sys_meta = self._fake_instance_system_metadata(itype)

if stash:
# stash instance types in system metadata.
sys_meta = (sys_meta +
self._fake_instance_system_metadata(itype, 'new_') +
self._fake_instance_system_metadata(itype, 'old_'))

instance_uuid = str(uuid.uuid1())
instance = {
Expand Down Expand Up @@ -876,6 +880,20 @@ def test_set_instance_host_and_node(self):
self.assertEqual('fakenode', instance['node'])


class NoInstanceTypesInSysMetadata(ResizeClaimTestCase):
"""Make sure we handle the case where the following are true:
1) Compute node C gets upgraded to code that looks for instance types in
system metadata. AND
2) C already has instances in the process of migrating that do not have
stashed instance types.
bug 1164110
"""
def setUp(self):
super(NoInstanceTypesInSysMetadata, self).setUp()
self.instance = self._fake_instance(stash=False)


class OrphanTestCase(BaseTrackerTestCase):
def _driver(self):
class OrphanVirtDriver(FakeVirtDriver):
Expand Down

0 comments on commit 05e1c47

Please sign in to comment.