Add user_id and project_id column to Migration
This adds two String columns, 'user_id' and 'project_id', to the ``migrations`` table in the DB and corresponding fields in the Migration versioned object. Add optional 'user_id' and/or 'project_id' query parameters for filtering migrations by user or project in the DB. Co-Authored-By: Qiu Fossen <qiujunting> Part of blueprint add-user-id-field-to-the-migrations-table Change-Id: I4700cb00da66eaa84621e91649eaf93c4a6e6f01
This commit is contained in:
parent
7a18209a81
commit
c65aabded2
|
@ -62,6 +62,10 @@ class MigrationsController(wsgi.Controller):
|
|||
if 'memory_total' in obj:
|
||||
for key in detail_keys:
|
||||
del obj[key]
|
||||
if 'user_id' in obj:
|
||||
del obj['user_id']
|
||||
if 'project_id' in obj:
|
||||
del obj['project_id']
|
||||
# NOTE(Shaohe Feng) above version 2.23, add migration_type for all
|
||||
# kinds of migration, but we only add links just for in-progress
|
||||
# live-migration.
|
||||
|
|
|
@ -4484,6 +4484,13 @@ def migration_get_all_by_filters(context, filters,
|
|||
if "instance_uuid" in filters:
|
||||
instance_uuid = filters["instance_uuid"]
|
||||
query = query.filter(models.Migration.instance_uuid == instance_uuid)
|
||||
if 'user_id' in filters:
|
||||
user_id = filters['user_id']
|
||||
query = query.filter(models.Migration.user_id == user_id)
|
||||
if 'project_id' in filters:
|
||||
project_id = filters['project_id']
|
||||
query = query.filter(models.Migration.project_id == project_id)
|
||||
|
||||
if marker:
|
||||
try:
|
||||
marker = migration_get_by_uuid(context, marker)
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from sqlalchemy import MetaData, Column, Table, String
|
||||
|
||||
NEW_COLUMNS_NAME = ['user_id', 'project_id']
|
||||
BASE_TABLE_NAME = 'migrations'
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
meta = MetaData(bind=migrate_engine)
|
||||
|
||||
for prefix in ('', 'shadow_'):
|
||||
table = Table(prefix + BASE_TABLE_NAME, meta, autoload=True)
|
||||
for new_column_name in NEW_COLUMNS_NAME:
|
||||
new_column = Column(new_column_name, String(255), nullable=True)
|
||||
if not hasattr(table.c, new_column_name):
|
||||
table.create_column(new_column)
|
|
@ -797,6 +797,9 @@ class Migration(BASE, NovaBase, models.SoftDeleteMixin):
|
|||
disk_remaining = Column(BigInteger, nullable=True)
|
||||
cross_cell_move = Column(Boolean, default=False)
|
||||
|
||||
user_id = Column(String(255), nullable=True)
|
||||
project_id = Column(String(255), nullable=True)
|
||||
|
||||
instance = orm.relationship("Instance", foreign_keys=instance_uuid,
|
||||
primaryjoin='and_(Migration.instance_uuid == '
|
||||
'Instance.uuid, Instance.deleted == '
|
||||
|
|
|
@ -42,7 +42,8 @@ class Migration(base.NovaPersistentObject, base.NovaObject,
|
|||
# Version 1.4: Added migration progress detail
|
||||
# Version 1.5: Added uuid
|
||||
# Version 1.6: Added cross_cell_move and get_by_uuid().
|
||||
VERSION = '1.6'
|
||||
# Version 1.7: Added user_id and project_id
|
||||
VERSION = '1.7'
|
||||
|
||||
fields = {
|
||||
'id': fields.IntegerField(),
|
||||
|
@ -67,6 +68,10 @@ class Migration(base.NovaPersistentObject, base.NovaObject,
|
|||
'disk_processed': fields.IntegerField(nullable=True),
|
||||
'disk_remaining': fields.IntegerField(nullable=True),
|
||||
'cross_cell_move': fields.BooleanField(default=False),
|
||||
# request context user id
|
||||
'user_id': fields.StringField(nullable=True),
|
||||
# request context project id
|
||||
'project_id': fields.StringField(nullable=True),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
|
@ -104,6 +109,11 @@ class Migration(base.NovaPersistentObject, base.NovaObject,
|
|||
del primitive['uuid']
|
||||
if target_version < (1, 6) and 'cross_cell_move' in primitive:
|
||||
del primitive['cross_cell_move']
|
||||
if target_version < (1, 7):
|
||||
if 'user_id' in primitive:
|
||||
del primitive['user_id']
|
||||
if 'project_id' in primitive:
|
||||
del primitive['project_id']
|
||||
|
||||
def obj_load_attr(self, attrname):
|
||||
if attrname == 'migration_type':
|
||||
|
|
|
@ -56,6 +56,8 @@ fake_migrations = [
|
|||
'deleted': False,
|
||||
'uuid': uuids.migration1,
|
||||
'cross_cell_move': False,
|
||||
'user_id': None,
|
||||
'project_id': None
|
||||
},
|
||||
# non in-progress live migration
|
||||
{
|
||||
|
@ -83,6 +85,8 @@ fake_migrations = [
|
|||
'deleted': False,
|
||||
'uuid': uuids.migration2,
|
||||
'cross_cell_move': False,
|
||||
'user_id': None,
|
||||
'project_id': None
|
||||
},
|
||||
# in-progress resize
|
||||
{
|
||||
|
@ -110,6 +114,8 @@ fake_migrations = [
|
|||
'deleted': False,
|
||||
'uuid': uuids.migration3,
|
||||
'cross_cell_move': False,
|
||||
'user_id': None,
|
||||
'project_id': None
|
||||
},
|
||||
# non in-progress resize
|
||||
{
|
||||
|
@ -137,6 +143,8 @@ fake_migrations = [
|
|||
'deleted': False,
|
||||
'uuid': uuids.migration4,
|
||||
'cross_cell_move': False,
|
||||
'user_id': None,
|
||||
'project_id': None
|
||||
}
|
||||
]
|
||||
|
||||
|
|
|
@ -57,6 +57,8 @@ fake_migrations = [
|
|||
'deleted': False,
|
||||
'uuid': uuids.migration1,
|
||||
'cross_cell_move': False,
|
||||
'user_id': None,
|
||||
'project_id': None
|
||||
},
|
||||
{
|
||||
'id': 5678,
|
||||
|
@ -83,6 +85,8 @@ fake_migrations = [
|
|||
'deleted': False,
|
||||
'uuid': uuids.migration2,
|
||||
'cross_cell_move': False,
|
||||
'user_id': None,
|
||||
'project_id': None
|
||||
}
|
||||
]
|
||||
|
||||
|
|
|
@ -4106,7 +4106,8 @@ class _ComputeAPIUnitTestMixIn(object):
|
|||
'disk_remaining': None, 'deleted': False,
|
||||
'hidden': False, 'created_at': None,
|
||||
'updated_at': None, 'deleted_at': None,
|
||||
'cross_cell_move': False}
|
||||
'cross_cell_move': False, 'user_id': None,
|
||||
'project_id': None}
|
||||
|
||||
def migration_get(context, id):
|
||||
return migrations[id]
|
||||
|
|
|
@ -1123,7 +1123,8 @@ class MigrationTestCase(test.TestCase):
|
|||
def _create(self, status='migrating', source_compute='host1',
|
||||
source_node='a', dest_compute='host2', dest_node='b',
|
||||
system_metadata=None, migration_type=None, uuid=None,
|
||||
created_at=None, updated_at=None):
|
||||
created_at=None, updated_at=None, user_id=None,
|
||||
project_id=None):
|
||||
|
||||
values = {'host': source_compute}
|
||||
instance = db.instance_create(self.ctxt, values)
|
||||
|
@ -1139,6 +1140,10 @@ class MigrationTestCase(test.TestCase):
|
|||
values['created_at'] = created_at
|
||||
if updated_at:
|
||||
values['updated_at'] = updated_at
|
||||
if user_id:
|
||||
values['user_id'] = user_id
|
||||
if project_id:
|
||||
values['project_id'] = project_id
|
||||
db.migration_create(self.ctxt, values)
|
||||
return values
|
||||
|
||||
|
@ -1292,6 +1297,54 @@ class MigrationTestCase(test.TestCase):
|
|||
self.assertEqual(migration['instance_uuid'],
|
||||
instance_migrations[0]['instance_uuid'])
|
||||
|
||||
def test_get_migrations_by_filters_user_id(self):
|
||||
# Create two migrations with different user_id
|
||||
user_id1 = "fake_user_id"
|
||||
self._create(user_id=user_id1)
|
||||
user_id2 = "other_fake_user_id"
|
||||
self._create(user_id=user_id2)
|
||||
# Filter on only the first user_id
|
||||
filters = {"user_id": user_id1}
|
||||
migrations = db.migration_get_all_by_filters(self.ctxt, filters)
|
||||
# We should only get one migration back because we filtered on only
|
||||
# one of the two different user_id
|
||||
self.assertEqual(1, len(migrations))
|
||||
for migration in migrations:
|
||||
self.assertEqual(filters['user_id'], migration['user_id'])
|
||||
|
||||
def test_get_migrations_by_filters_project_id(self):
|
||||
# Create two migrations with different project_id
|
||||
project_id1 = "fake_project_id"
|
||||
self._create(project_id=project_id1)
|
||||
project_id2 = "other_fake_project_id"
|
||||
self._create(project_id=project_id2)
|
||||
# Filter on only the first project_id
|
||||
filters = {"project_id": project_id1}
|
||||
migrations = db.migration_get_all_by_filters(self.ctxt, filters)
|
||||
# We should only get one migration back because we filtered on only
|
||||
# one of the two different project_id
|
||||
self.assertEqual(1, len(migrations))
|
||||
for migration in migrations:
|
||||
self.assertEqual(filters['project_id'], migration['project_id'])
|
||||
|
||||
def test_get_migrations_by_filters_user_id_and_project_id(self):
|
||||
# Create two migrations with different user_id and project_id
|
||||
user_id1 = "fake_user_id"
|
||||
project_id1 = "fake_project_id"
|
||||
self._create(user_id=user_id1, project_id=project_id1)
|
||||
user_id2 = "other_fake_user_id"
|
||||
project_id2 = "other_fake_project_id"
|
||||
self._create(user_id=user_id2, project_id=project_id2)
|
||||
# Filter on only the first user_id and project_id
|
||||
filters = {"user_id": user_id1, "project_id": project_id1}
|
||||
migrations = db.migration_get_all_by_filters(self.ctxt, filters)
|
||||
# We should only get one migration back because we filtered on only
|
||||
# one of the two different user_id and project_id
|
||||
self.assertEqual(1, len(migrations))
|
||||
for migration in migrations:
|
||||
self.assertEqual(filters['user_id'], migration['user_id'])
|
||||
self.assertEqual(filters['project_id'], migration['project_id'])
|
||||
|
||||
def test_migration_get_unconfirmed_by_dest_compute(self):
|
||||
# Ensure no migrations are returned.
|
||||
results = db.migration_get_unconfirmed_by_dest_compute(self.ctxt, 10,
|
||||
|
|
|
@ -1041,6 +1041,13 @@ class NovaMigrationsCheckers(test_migrations.ModelsMigrationsSync,
|
|||
# check. The actual test for 400 is in TestServicesUUIDCheck.
|
||||
pass
|
||||
|
||||
def _check_401(self, engine, data):
|
||||
for prefix in ('', 'shadow_'):
|
||||
self.assertColumnExists(
|
||||
engine, '%smigrations' % prefix, 'user_id')
|
||||
self.assertColumnExists(
|
||||
engine, '%smigrations' % prefix, 'project_id')
|
||||
|
||||
|
||||
class TestNovaMigrationsSQLite(NovaMigrationsCheckers,
|
||||
test_fixtures.OpportunisticDBTestMixin,
|
||||
|
|
|
@ -54,6 +54,8 @@ def fake_db_migration(**updates):
|
|||
'disk_processed': 23456,
|
||||
'disk_remaining': 211111,
|
||||
'cross_cell_move': False,
|
||||
'user_id': None,
|
||||
'project_id': None,
|
||||
}
|
||||
|
||||
if updates:
|
||||
|
@ -110,6 +112,8 @@ class _TestMigrationObject(object):
|
|||
self.assertEqual(fake_migration['dest_compute'], mig.dest_compute)
|
||||
self.assertIn('uuid', mig)
|
||||
self.assertFalse(mig.cross_cell_move)
|
||||
self.assertIn('user_id', mig)
|
||||
self.assertIn('project_id', mig)
|
||||
mock_create.assert_called_once_with(ctxt,
|
||||
{'source_compute': 'foo',
|
||||
'migration_type': 'resize',
|
||||
|
@ -298,6 +302,10 @@ class _TestMigrationObject(object):
|
|||
source_compute='fake-host' # added in 1.0
|
||||
)
|
||||
data = lambda x: x['nova_object.data']
|
||||
primitive = data(mig.obj_to_primitive(target_version='1.6'))
|
||||
self.assertIn('cross_cell_move', primitive)
|
||||
self.assertNotIn('user_id', primitive)
|
||||
self.assertNotIn('project_id', primitive)
|
||||
primitive = data(mig.obj_to_primitive(target_version='1.5'))
|
||||
self.assertIn('uuid', primitive)
|
||||
self.assertNotIn('cross_cell_move', primitive)
|
||||
|
|
|
@ -1094,7 +1094,7 @@ object_data = {
|
|||
'LibvirtLiveMigrateBDMInfo': '1.1-5f4a68873560b6f834b74e7861d71aaf',
|
||||
'LibvirtLiveMigrateData': '1.9-7082cc7dd48ca49df71fe3846521b2f3',
|
||||
'MemoryDiagnostics': '1.0-2c995ae0f2223bb0f8e523c5cc0b83da',
|
||||
'Migration': '1.6-fd6b1abfd8e3ce945348e7b5f04baa28',
|
||||
'Migration': '1.7-b77066a88d08bdb0b05d7bc18780c55a',
|
||||
'MigrationContext': '1.1-9fb17b0b521370957a884636499df52d',
|
||||
'MigrationList': '1.4-983a9c29d4f1e747ce719dc9063b729b',
|
||||
'MonitorMetric': '1.1-53b1db7c4ae2c531db79761e7acc52ba',
|
||||
|
|
Loading…
Reference in New Issue