Skip to content

Commit

Permalink
Add migration_type to Migration object
Browse files Browse the repository at this point in the history
From the records that could be in the database prior to now, we can
determine their type by the flavor ids on the record. So, we do that
live-ly so that we don't need to (a) bother layers above with the potential
for a migration_type=None and (b) do the conversion in a db migration.

Note that this includes a change to the API to not show this field to
the user. It will be exposed in v2.1 in a later patch.

Related to blueprint robustify-evacuate

Change-Id: Id78c91357c892e684cfd8eeb1f000a57180865bb
  • Loading branch information
kk7ds committed May 15, 2015
1 parent 5c151d0 commit 13fb2d2
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 5 deletions.
3 changes: 3 additions & 0 deletions nova/api/openstack/compute/contrib/migrations.py
Expand Up @@ -32,9 +32,12 @@ def output(migrations_obj):
primitive objects with the only necessary fields.
"""
objects = obj_base.obj_to_primitive(migrations_obj)
objects = [x for x in objects if not x['hidden']]
for obj in objects:
del obj['deleted']
del obj['deleted_at']
del obj['migration_type']
del obj['hidden']
return objects


Expand Down
3 changes: 3 additions & 0 deletions nova/api/openstack/compute/plugins/v3/migrations.py
Expand Up @@ -30,9 +30,12 @@ def output(migrations_obj):
primitive objects with the only necessary fields.
"""
objects = obj_base.obj_to_primitive(migrations_obj)
objects = [x for x in objects if not x['hidden']]
for obj in objects:
del obj['deleted']
del obj['deleted_at']
del obj['migration_type']
del obj['hidden']
return objects


Expand Down
43 changes: 40 additions & 3 deletions nova/objects/migration.py
Expand Up @@ -17,14 +17,23 @@
from nova import objects
from nova.objects import base
from nova.objects import fields
from nova import utils


def _determine_migration_type(migration):
if migration['old_instance_type_id'] != migration['new_instance_type_id']:
return 'resize'
else:
return 'migration'


# TODO(berrange): Remove NovaObjectDictCompat
class Migration(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
# Version 1.1: String attributes updated to support unicode
VERSION = '1.1'
# Version 1.2: Added migration_type and hidden
VERSION = '1.2'

fields = {
'id': fields.IntegerField(),
Expand All @@ -37,16 +46,42 @@ class Migration(base.NovaPersistentObject, base.NovaObject,
'new_instance_type_id': fields.IntegerField(nullable=True),
'instance_uuid': fields.StringField(nullable=True),
'status': fields.StringField(nullable=True),
'migration_type': fields.EnumField(['migration', 'resize',
'live-migration', 'evacuate'],
nullable=False),
'hidden': fields.BooleanField(nullable=False, default=False),
}

@staticmethod
def _from_db_object(context, migration, db_migration):
for key in migration.fields:
migration[key] = db_migration[key]
value = db_migration[key]
if key == 'migration_type' and value is None:
value = _determine_migration_type(db_migration)
migration[key] = value

migration._context = context
migration.obj_reset_changes()
return migration

def obj_make_compatible(self, primitive, target_version):
super(Migration, self).obj_make_compatible(primitive, target_version)
target_version = utils.convert_version_to_tuple(target_version)
if target_version < (1, 2):
if 'migration_type' in primitive:
del primitive['migration_type']
del primitive['hidden']

def obj_load_attr(self, attrname):
if attrname == 'migration_type':
# NOTE(danms): The only reason we'd need to load this is if
# some older node sent us one. So, guess the type.
self.migration_type = _determine_migration_type(self)
elif attrname == 'hidden':
self.hidden = False
else:
super(Migration, self).obj_load_attr(attrname)

@base.remotable_classmethod
def get_by_id(cls, context, migration_id):
db_migration = db.migration_get(context, migration_id)
Expand Down Expand Up @@ -84,7 +119,8 @@ class MigrationList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version
# Migration <= 1.1
# Version 1.1: Added use_slave to get_unconfirmed_by_dest_compute
VERSION = '1.1'
# Version 1.2: Migration version 1.2
VERSION = '1.2'

fields = {
'objects': fields.ListOfObjectsField('Migration'),
Expand All @@ -93,6 +129,7 @@ class MigrationList(base.ObjectListBase, base.NovaObject):
'1.0': '1.1',
# NOTE(danms): Migration was at 1.1 before we added this
'1.1': '1.1',
'1.2': '1.2',
}

@base.remotable_classmethod
Expand Down
4 changes: 4 additions & 0 deletions nova/tests/functional/v3/test_migrations.py
Expand Up @@ -53,6 +53,8 @@ def _stub_migrations(self, context, filters):
'instance_uuid': 'instance_id_123',
'old_instance_type_id': 1,
'new_instance_type_id': 2,
'migration_type': 'resize',
'hidden': False,
'created_at': datetime.datetime(2012, 10, 29, 13, 42, 2),
'updated_at': datetime.datetime(2012, 10, 29, 13, 42, 2),
'deleted_at': None,
Expand All @@ -69,6 +71,8 @@ def _stub_migrations(self, context, filters):
'instance_uuid': 'instance_id_456',
'old_instance_type_id': 5,
'new_instance_type_id': 6,
'migration_type': 'resize',
'hidden': False,
'created_at': datetime.datetime(2013, 10, 22, 13, 42, 2),
'updated_at': datetime.datetime(2013, 10, 22, 13, 42, 2),
'deleted_at': None,
Expand Down
Expand Up @@ -38,6 +38,8 @@
'instance_uuid': 'instance_id_123',
'old_instance_type_id': 1,
'new_instance_type_id': 2,
'migration_type': 'resize',
'hidden': False,
'created_at': datetime.datetime(2012, 10, 29, 13, 42, 2),
'updated_at': datetime.datetime(2012, 10, 29, 13, 42, 2),
'deleted_at': None,
Expand All @@ -54,6 +56,8 @@
'instance_uuid': 'instance_id_456',
'old_instance_type_id': 5,
'new_instance_type_id': 6,
'migration_type': 'resize',
'hidden': False,
'created_at': datetime.datetime(2013, 10, 22, 13, 42, 2),
'updated_at': datetime.datetime(2013, 10, 22, 13, 42, 2),
'deleted_at': None,
Expand Down
34 changes: 34 additions & 0 deletions nova/tests/unit/objects/test_migration.py
Expand Up @@ -12,11 +12,13 @@
# License for the specific language governing permissions and limitations
# under the License.

import mock
from oslo_utils import timeutils

from nova import context
from nova import db
from nova import exception
from nova import objects
from nova.objects import migration
from nova.tests.unit import fake_instance
from nova.tests.unit.objects import test_objects
Expand All @@ -41,6 +43,8 @@ def fake_db_migration(**updates):
'new_instance_type_id': 84,
'instance_uuid': 'fake-uuid',
'status': 'migrating',
'migration_type': 'resize',
'hidden': False,
}

if updates:
Expand Down Expand Up @@ -173,6 +177,36 @@ def test_get_by_filters(self):
for index, db_migration in enumerate(db_migrations):
self.compare_obj(migrations[index], db_migration)

def test_migrate_old_resize_record(self):
db_migration = dict(fake_db_migration(), migration_type=None)
with mock.patch('nova.db.migration_get') as fake_get:
fake_get.return_value = db_migration
mig = objects.Migration.get_by_id(context.get_admin_context(), 1)
self.assertTrue(mig.obj_attr_is_set('migration_type'))
self.assertEqual('resize', mig.migration_type)

def test_migrate_old_migration_record(self):
db_migration = dict(
fake_db_migration(), migration_type=None,
old_instance_type_id=1, new_instance_type_id=1)
with mock.patch('nova.db.migration_get') as fake_get:
fake_get.return_value = db_migration
mig = objects.Migration.get_by_id(context.get_admin_context(), 1)
self.assertTrue(mig.obj_attr_is_set('migration_type'))
self.assertEqual('migration', mig.migration_type)

def test_migrate_unset_type_resize(self):
mig = objects.Migration(old_instance_type_id=1,
new_instance_type_id=2)
self.assertEqual('resize', mig.migration_type)
self.assertTrue(mig.obj_attr_is_set('migration_type'))

def test_migrate_unset_type_migration(self):
mig = objects.Migration(old_instance_type_id=1,
new_instance_type_id=1)
self.assertEqual('migration', mig.migration_type)
self.assertTrue(mig.obj_attr_is_set('migration_type'))


class TestMigrationObject(test_objects._LocalTest,
_TestMigrationObject):
Expand Down
4 changes: 2 additions & 2 deletions nova/tests/unit/objects/test_objects.py
Expand Up @@ -1151,8 +1151,8 @@ def test_serialize_args(self):
'InstancePCIRequests': '1.1-4825b599f000538991fdc9972a92c2c6',
'KeyPair': '1.3-2d7c9ccade5532f7cd185110a9367e6a',
'KeyPairList': '1.2-41b7c9ab5fd2a216be4bbce011a55eff',
'Migration': '1.1-dc2db9e6e625bd3444a5a114438b298d',
'MigrationList': '1.1-45a973ee70500f799da67491edabc5d4',
'Migration': '1.2-0554a9f061ec0e9fefe43773bc426fcf',
'MigrationList': '1.2-e772d7d6ae0581ec72042d50c6bdf6ec',
'MyObj': '1.6-fce707f79d6fee00f0ebbac98816a380',
'MyOwnedObject': '1.0-0f3d6c028543d7f3715d121db5b8e298',
'NUMACell': '1.2-cb9c3b08cc1c418d021492f788d04173',
Expand Down

0 comments on commit 13fb2d2

Please sign in to comment.