summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2012-11-13 21:06:42 +0000
committerGerrit Code Review <review@openstack.org>2012-11-13 21:06:42 +0000
commitb45ca52108a0b64f18885abb3c42cd4a2ff89ee8 (patch)
treec67f1cb5f3889cc2083ba44fba74e96265cf17f0
parent083bccd34bc35dc043f17ff6ade66c64dd4bead2 (diff)
parent3e25d9bc235381081210ca160bb1188ed05274ea (diff)
downloadnova-b45ca52108a0b64f18885abb3c42cd4a2ff89ee8.tar.gz
nova-b45ca52108a0b64f18885abb3c42cd4a2ff89ee8.tar.xz
nova-b45ca52108a0b64f18885abb3c42cd4a2ff89ee8.zip
Merge "Add DB query to get in-progress migrations."
-rw-r--r--nova/db/api.py7
-rw-r--r--nova/db/sqlalchemy/api.py11
-rw-r--r--nova/db/sqlalchemy/migrate_repo/versions/137_add_indexes_to_migrations.py46
-rw-r--r--nova/db/sqlalchemy/models.py5
-rw-r--r--nova/tests/test_db_api.py49
5 files changed, 118 insertions, 0 deletions
diff --git a/nova/db/api.py b/nova/db/api.py
index 04786a1fb..ea47e5f43 100644
--- a/nova/db/api.py
+++ b/nova/db/api.py
@@ -406,6 +406,13 @@ def migration_get_unconfirmed_by_dest_compute(context, confirm_window,
confirm_window, dest_compute)
+def migration_get_in_progress_by_host(context, host):
+ """Finds all migrations for the given host that are not yet confirmed or
+ reverted.
+ """
+ return IMPL.migration_get_in_progress_by_host(context, host)
+
+
####################
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 72caad74d..ec78a87e6 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -3351,6 +3351,17 @@ def migration_get_unconfirmed_by_dest_compute(context, confirm_window,
all()
+@require_admin_context
+def migration_get_in_progress_by_host(context, host, session=None):
+
+ return model_query(context, models.Migration, session=session).\
+ filter(or_(models.Migration.source_compute == host,
+ models.Migration.dest_compute == host)).\
+ filter(~models.Migration.status.in_(['confirmed', 'reverted'])).\
+ options(joinedload('instance')).\
+ all()
+
+
##################
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/137_add_indexes_to_migrations.py b/nova/db/sqlalchemy/migrate_repo/versions/137_add_indexes_to_migrations.py
new file mode 100644
index 000000000..1499bd351
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/137_add_indexes_to_migrations.py
@@ -0,0 +1,46 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack LLC.
+# All Rights Reserved.
+#
+# 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 Index, MetaData, Table
+from sqlalchemy.exc import IntegrityError
+
+
+def upgrade(migrate_engine):
+ meta = MetaData()
+ meta.bind = migrate_engine
+
+ t = Table('migrations', meta, autoload=True)
+
+ # Based on migration_get_in_progress_by_host
+ # from: nova/db/sqlalchemy/api.py
+ i = Index('migrations_by_host_and_status_idx', t.c.deleted,
+ t.c.source_compute, t.c.dest_compute, t.c.status)
+ try:
+ i.create(migrate_engine)
+ except IntegrityError:
+ pass
+
+
+def downgrade(migrate_engine):
+ meta = MetaData()
+ meta.bind = migrate_engine
+
+ t = Table('migrations', meta, autoload=True)
+
+ i = Index('migrations_by_host_and_status_idx', t.c.deleted,
+ t.c.source_compute, t.c.dest_compute, t.c.status)
+ i.drop(migrate_engine)
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index 194b80f2d..d7c638ff8 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -641,6 +641,11 @@ class Migration(BASE, NovaBase):
#TODO(_cerberus_): enum
status = Column(String(255))
+ instance = relationship("Instance", foreign_keys=instance_uuid,
+ primaryjoin='and_(Migration.instance_uuid == '
+ 'Instance.uuid, Instance.deleted == '
+ 'False)')
+
class Network(BASE, NovaBase):
"""Represents a network."""
diff --git a/nova/tests/test_db_api.py b/nova/tests/test_db_api.py
index 7a71a1247..001880483 100644
--- a/nova/tests/test_db_api.py
+++ b/nova/tests/test_db_api.py
@@ -1013,6 +1013,55 @@ class CapacityTestCase(test.TestCase):
self.assertEqual(1, int(stat['value']))
+class MigrationTestCase(test.TestCase):
+
+ def setUp(self):
+ super(MigrationTestCase, self).setUp()
+ self.ctxt = context.get_admin_context()
+
+ self._create()
+ self._create()
+ self._create(status='reverted')
+ self._create(status='confirmed')
+ self._create(source_compute='host2', dest_compute='host1')
+ self._create(source_compute='host2', dest_compute='host3')
+ self._create(source_compute='host3', dest_compute='host4')
+
+ def _create(self, status='migrating', source_compute='host1',
+ dest_compute='host2'):
+
+ values = {'host': source_compute}
+ instance = db.instance_create(self.ctxt, values)
+
+ values = {'status': status, 'source_compute': source_compute,
+ 'dest_compute': dest_compute,
+ 'instance_uuid': instance['uuid']}
+ db.migration_create(self.ctxt, values)
+
+ def _assert_in_progress(self, migrations):
+ for migration in migrations:
+ self.assertNotEqual('confirmed', migration.status)
+ self.assertNotEqual('reverted', migration.status)
+
+ def test_in_progress_host1(self):
+ migrations = db.migration_get_in_progress_by_host(self.ctxt, 'host1')
+ # 2 as source + 1 as dest
+ self.assertEqual(3, len(migrations))
+ self._assert_in_progress(migrations)
+
+ def test_in_progress_host2(self):
+ migrations = db.migration_get_in_progress_by_host(self.ctxt, 'host2')
+ # 2 as dest, 2 as source
+ self.assertEqual(4, len(migrations))
+ self._assert_in_progress(migrations)
+
+ def test_instance_join(self):
+ migrations = db.migration_get_in_progress_by_host(self.ctxt, 'host2')
+ for migration in migrations:
+ instance = migration['instance']
+ self.assertEqual(migration['instance_uuid'], instance['uuid'])
+
+
class TestIpAllocation(test.TestCase):
def setUp(self):