Add migration_type to Migration object

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
This commit is contained in:
Dan Smith 2015-05-06 12:44:49 -07:00
parent 5c151d0807
commit 13fb2d26d4
7 changed files with 90 additions and 5 deletions

View File

@ -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

View File

@ -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

View File

@ -17,6 +17,14 @@ from nova import exception
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
@ -24,7 +32,8 @@ 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(),
@ -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)
@ -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'),
@ -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

View File

@ -53,6 +53,8 @@ class MigrationsSamplesJsonTest(api_sample_base.ApiSampleTestBaseV3):
'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,
@ -69,6 +71,8 @@ class MigrationsSamplesJsonTest(api_sample_base.ApiSampleTestBaseV3):
'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,

View File

@ -38,6 +38,8 @@ fake_migrations = [
'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,
@ -54,6 +56,8 @@ fake_migrations = [
'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,

View File

@ -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
@ -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:
@ -173,6 +177,36 @@ class _TestMigrationObject(object):
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):

View File

@ -1151,8 +1151,8 @@ object_data = {
'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',