diff -Nru nova-12.0.6/debian/changelog nova-12.0.6/debian/changelog --- nova-12.0.6/debian/changelog 2016-12-07 13:21:03.000000000 +0000 +++ nova-12.0.6/debian/changelog 2017-03-09 11:35:08.000000000 +0000 @@ -1,3 +1,10 @@ +nova (2:12.0.6-0ubuntu1~cloud1) trusty; urgency=medium + + * Backport fix for InstanceList.get_by_security_group_id can run very slow (LP: #1552971) + - d/p/list-instances-for-secgroup-without-joining-on-rules.patch + + -- Edward Hope-Morley Tue, 07 Mar 2017 15:56:28 +0000 + nova (2:12.0.6-0ubuntu1~cloud0) trusty-liberty; urgency=medium * New upstream point release for OpenStack Liberty (LP: #1648071). diff -Nru nova-12.0.6/debian/patches/list-instances-for-secgroup-without-joining-on-rules.patch nova-12.0.6/debian/patches/list-instances-for-secgroup-without-joining-on-rules.patch --- nova-12.0.6/debian/patches/list-instances-for-secgroup-without-joining-on-rules.patch 1970-01-01 01:00:00.000000000 +0100 +++ nova-12.0.6/debian/patches/list-instances-for-secgroup-without-joining-on-rules.patch 2017-03-09 11:36:02.000000000 +0000 @@ -0,0 +1,214 @@ +From 7685734664feb6b604094e3fab2403ff4b0ae970 Mon Sep 17 00:00:00 2001 +From: Paul Griffin +Date: Fri, 4 Mar 2016 15:56:48 +0000 +Subject: [PATCH] List instances for secgroup without joining on rules + +Make db.security_group_get only join rules if specified in +the columns_to_join. This works around a performance issue +with lots of instances and security groups. + +NOTE(mriedem): A legacy_v2 API test had to be updated which +didn't exist in the original fix in Newton. + +NOTE: Two extra unit test fixes were added to this patch to +get tests passing with this change. Also Nova’s EC2 API +support which was deprecated in Kilo and removed from Mitaka +(in commit 4140eb4). As a result there's some extant ec2 test +code that this patch breaks so a skipTest was added but +should be safe since it is expected that everyone be moved +off of the ec2 api in Liberty in preparation for Mitaka where +it no longer exists in Nova. + +Co-Authored-By: Dan Smith +Change-Id: Ie3daed133419c41ed22646f9a790570ff47f0eec +Closes-Bug: #1552971 +(cherry picked from commit e70468e87537965b5db61f32e72ececde84531f2) +(cherry picked from commit 5d7a23e7be1e41fdd1b13f2f05528faed41e1b98) +--- + nova/compute/api.py | 7 +++++-- + nova/db/sqlalchemy/api.py | 6 +++++- + nova/tests/unit/api/ec2/test_cloud.py | 1 + + .../unit/api/openstack/compute/legacy_v2/test_servers.py | 3 ++- + .../unit/api/openstack/compute/test_security_groups.py | 13 +++++++------ + nova/tests/unit/compute/test_compute.py | 9 +++++++-- + nova/tests/unit/db/test_db_api.py | 6 ++++-- + 7 files changed, 31 insertions(+), 14 deletions(-) + +diff --git a/nova/compute/api.py b/nova/compute/api.py +index f16f6c4..bdc94b0 100644 +--- a/nova/compute/api.py ++++ b/nova/compute/api.py +@@ -3966,13 +3966,16 @@ class SecurityGroupAPI(base.Base, security_group_base.SecurityGroupBase): + + def get(self, context, name=None, id=None, map_exception=False): + self.ensure_default(context) ++ cols = ['rules'] + try: + if name: + return self.db.security_group_get_by_name(context, + context.project_id, +- name) ++ name, ++ columns_to_join=cols) + elif id: +- return self.db.security_group_get(context, id) ++ return self.db.security_group_get(context, id, ++ columns_to_join=cols) + except exception.NotFound as exp: + if map_exception: + msg = exp.format_message() +diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py +index 443da95..8dee935 100644 +--- a/nova/db/sqlalchemy/api.py ++++ b/nova/db/sqlalchemy/api.py +@@ -4059,7 +4059,11 @@ def security_group_get_all(context): + + @require_context + def security_group_get(context, security_group_id, columns_to_join=None): +- query = _security_group_get_query(context, project_only=True).\ ++ join_rules = columns_to_join and 'rules' in columns_to_join ++ if join_rules: ++ columns_to_join.remove('rules') ++ query = _security_group_get_query(context, project_only=True, ++ join_rules=join_rules).\ + filter_by(id=security_group_id) + + if columns_to_join is None: +diff --git a/nova/tests/unit/api/ec2/test_cloud.py b/nova/tests/unit/api/ec2/test_cloud.py +index 74d5c45..b4c5fab 100644 +--- a/nova/tests/unit/api/ec2/test_cloud.py ++++ b/nova/tests/unit/api/ec2/test_cloud.py +@@ -459,6 +459,7 @@ class CloudTestCase(test.TestCase): + db.security_group_destroy(self.context, sec['id']) + + def test_describe_security_groups_by_id(self): ++ self.skipTest("Skipping EC2 unit test") + sec = db.security_group_create(self.context, + {'project_id': self.context.project_id, + 'name': 'test'}) +diff --git a/nova/tests/unit/api/openstack/compute/legacy_v2/test_servers.py b/nova/tests/unit/api/openstack/compute/legacy_v2/test_servers.py +index 0a42930..4feb1e3 100644 +--- a/nova/tests/unit/api/openstack/compute/legacy_v2/test_servers.py ++++ b/nova/tests/unit/api/openstack/compute/legacy_v2/test_servers.py +@@ -2165,7 +2165,8 @@ class ServersControllerCreateTest(test.TestCase): + group = 'foo' + old_create = compute_api.API.create + +- def sec_group_get(ctx, proj, name): ++ def sec_group_get(ctx, proj, name, columns_to_join=None): ++ self.assertEqual(['rules'], columns_to_join) + if name == group: + return True + else: +diff --git a/nova/tests/unit/api/openstack/compute/test_security_groups.py b/nova/tests/unit/api/openstack/compute/test_security_groups.py +index d3ab29a..8cdc8ba 100644 +--- a/nova/tests/unit/api/openstack/compute/test_security_groups.py ++++ b/nova/tests/unit/api/openstack/compute/test_security_groups.py +@@ -113,7 +113,8 @@ def return_non_running_server(context, server_id, columns_to_join=None): + 'uuid': FAKE_UUID1, 'host': "localhost", 'name': 'asdf'}) + + +-def return_security_group_by_name(context, project_id, group_name): ++def return_security_group_by_name(context, project_id, group_name, ++ columns_to_join=None): + return {'id': 1, 'name': group_name, + "instances": [{'id': 1, 'uuid': FAKE_UUID1}]} + +@@ -472,7 +473,7 @@ class TestSecurityGroupsV21(test.TestCase): + def test_get_security_group_by_id(self): + sg = security_group_template(id=2, rules=[]) + +- def return_security_group(context, group_id): ++ def return_security_group(context, group_id, columns_to_join=None): + self.assertEqual(sg['id'], group_id) + return security_group_db(sg) + +@@ -497,7 +498,7 @@ class TestSecurityGroupsV21(test.TestCase): + sg_update = security_group_template(id=2, rules=[], + name='update_name', description='update_desc') + +- def return_security_group(context, group_id): ++ def return_security_group(context, group_id, columns_to_join=None): + self.assertEqual(sg['id'], group_id) + return security_group_db(sg) + +@@ -522,7 +523,7 @@ class TestSecurityGroupsV21(test.TestCase): + def test_update_security_group_name_to_default(self): + sg = security_group_template(id=2, rules=[], name='default') + +- def return_security_group(context, group_id): ++ def return_security_group(context, group_id, columns_to_join=None): + self.assertEqual(sg['id'], group_id) + return security_group_db(sg) + +@@ -547,7 +548,7 @@ class TestSecurityGroupsV21(test.TestCase): + def security_group_destroy(context, id): + self.called = True + +- def return_security_group(context, group_id): ++ def return_security_group(context, group_id, columns_to_join=None): + self.assertEqual(sg['id'], group_id) + return security_group_db(sg) + +@@ -591,7 +592,7 @@ class TestSecurityGroupsV21(test.TestCase): + def security_group_in_use(context, id): + return True + +- def return_security_group(context, group_id): ++ def return_security_group(context, group_id, columns_to_join=None): + self.assertEqual(sg['id'], group_id) + return security_group_db(sg) + +diff --git a/nova/tests/unit/compute/test_compute.py b/nova/tests/unit/compute/test_compute.py +index 2639a75..0b2bcfd 100644 +--- a/nova/tests/unit/compute/test_compute.py ++++ b/nova/tests/unit/compute/test_compute.py +@@ -7663,7 +7663,10 @@ class ComputeAPITestCase(BaseTestCase): + security_group=['testgroup']) + + db.instance_destroy(self.context, ref[0]['uuid']) +- group = db.security_group_get(self.context, group['id']) ++ group = db.security_group_get(self.context, group['id'], ++ columns_to_join=['instances', ++ 'rules']) ++ + self.assertEqual(0, len(group['instances'])) + + def test_destroy_security_group_disassociates_instances(self): +@@ -7679,7 +7682,9 @@ class ComputeAPITestCase(BaseTestCase): + db.security_group_destroy(self.context, group['id']) + admin_deleted_context = context.get_admin_context( + read_deleted="only") +- group = db.security_group_get(admin_deleted_context, group['id']) ++ group = db.security_group_get(admin_deleted_context, group['id'], ++ columns_to_join=['instances', ++ 'rules']) + self.assertEqual(0, len(group['instances'])) + + def _test_rebuild(self, vm_state): +diff --git a/nova/tests/unit/db/test_db_api.py b/nova/tests/unit/db/test_db_api.py +index 2a01339..4206a6c 100644 +--- a/nova/tests/unit/db/test_db_api.py ++++ b/nova/tests/unit/db/test_db_api.py +@@ -1716,14 +1716,16 @@ class SecurityGroupTestCase(test.TestCase, ModelsObjectComparatorMixin): + self.ctxt, security_group1['id']) + self._assertEqualObjects(db.security_group_get( + self.ctxt, security_group2['id'], +- columns_to_join=['instances']), security_group2) ++ columns_to_join=['instances', ++ 'rules']), security_group2) + + def test_security_group_get(self): + security_group1 = self._create_security_group({}) + self._create_security_group({'name': 'fake_sec_group2'}) + real_security_group = db.security_group_get(self.ctxt, + security_group1['id'], +- columns_to_join=['instances']) ++ columns_to_join=['instances', ++ 'rules']) + self._assertEqualObjects(security_group1, + real_security_group) + +-- +1.9.1 + diff -Nru nova-12.0.6/debian/patches/series nova-12.0.6/debian/patches/series --- nova-12.0.6/debian/patches/series 2016-12-07 13:20:53.000000000 +0000 +++ nova-12.0.6/debian/patches/series 2017-03-09 11:36:02.000000000 +0000 @@ -8,3 +8,4 @@ disable-sphinxcontrib.seqdiag.patch libvirt-Split-out-resize_image-logic-from-create_ima.patch fix-resizing-imagebackend-cache.patch +list-instances-for-secgroup-without-joining-on-rules.patch