From aa1966a70eb38bba1c7c3f88a77a2f2ea5fcc75f Mon Sep 17 00:00:00 2001 From: melanie witt Date: Tue, 24 Jul 2018 02:28:47 +0000 Subject: [PATCH] Add functional test for affinity with multiple cells The 'az' keyword arg needed to be added to the _build_minimal_create_server_request method in the InstanceHelperMixin because we don't have 96f10711667603e7fbad57b151c6438cdd9ae270 in Queens. A fake_network.set_stub_network_methods(self) call needed to be added to the test because we don't have acd3216a8beac263aa87d785c21e816d29b1b6bb in Queens. The post_aggregate_action method from commit 8204b2492b07438d0569d3807e1c34f196756253 is also needed for this change to set the AZ for an aggregate. Related-Bug: #1746863 Change-Id: I418bbe5c38faf3e460b0d62219507ed64e156682 (cherry picked from commit 4f2c4993b1748d679bce8de6ffc672490ef3fa49) (cherry picked from commit 9dbe8cd5d31c8f63765d239392b0c0f38ee674d1) (cherry picked from commit c35f29001a2ce036b7281a125cb5077e0dddc605) --- nova/tests/functional/api/client.py | 4 + nova/tests/functional/integrated_helpers.py | 5 +- nova/tests/functional/test_server_group.py | 90 ++++++++++++++++++++- 3 files changed, 96 insertions(+), 3 deletions(-) diff --git a/nova/tests/functional/api/client.py b/nova/tests/functional/api/client.py index 3b8510574593..73fcc3ac7670 100644 --- a/nova/tests/functional/api/client.py +++ b/nova/tests/functional/api/client.py @@ -468,6 +468,10 @@ class TestOpenStackClient(object): def post_keypair(self, keypair): return self.api_post('/os-keypairs', keypair).body['keypair'] + def post_aggregate_action(self, aggregate_id, body): + return self.api_post( + '/os-aggregates/%s/action' % aggregate_id, body).body['aggregate'] + def get_active_migrations(self, server_id): return self.api_get('/servers/%s/migrations' % server_id).body['migrations'] diff --git a/nova/tests/functional/integrated_helpers.py b/nova/tests/functional/integrated_helpers.py index 41abfeaecf18..9898850e520b 100644 --- a/nova/tests/functional/integrated_helpers.py +++ b/nova/tests/functional/integrated_helpers.py @@ -243,7 +243,8 @@ class InstanceHelperMixin(object): admin_api, server, {'status': expected_status}, max_retries) def _build_minimal_create_server_request(self, api, name, image_uuid=None, - flavor_id=None, networks=None): + flavor_id=None, networks=None, + az=None): server = {} # We now have a valid imageId @@ -256,6 +257,8 @@ class InstanceHelperMixin(object): server['name'] = name if networks is not None: server['networks'] = networks + if az is not None: + server['availability_zone'] = az return server def _wait_until_deleted(self, server): diff --git a/nova/tests/functional/test_server_group.py b/nova/tests/functional/test_server_group.py index 9e8ea76e713d..ce4cea1a65eb 100644 --- a/nova/tests/functional/test_server_group.py +++ b/nova/tests/functional/test_server_group.py @@ -92,9 +92,11 @@ class ServerGroupTestBase(test.TestCase, self.addCleanup(nova.tests.unit.image.fake.FakeImageService_reset) def _boot_a_server_to_group(self, group, - expected_status='ACTIVE', flavor=None): + expected_status='ACTIVE', flavor=None, + az=None): server = self._build_minimal_create_server_request(self.api, - 'some-server') + 'some-server', + az=az) if flavor: server['flavorRef'] = ('http://fake.server/%s' % flavor['id']) @@ -845,3 +847,87 @@ class ServerGroupTestV215(ServerGroupTestV21): def test_soft_affinity_not_supported(self): pass + + +class ServerGroupTestMultiCell(ServerGroupTestBase): + + NUMBER_OF_CELLS = 2 + + def setUp(self): + super(ServerGroupTestMultiCell, self).setUp() + # Start two compute services, one per cell + fake.set_nodes(['host1']) + self.addCleanup(fake.restore_nodes) + self.compute1 = self.start_service('compute', host='host1', + cell='cell1') + fake.set_nodes(['host2']) + self.addCleanup(fake.restore_nodes) + self.compute2 = self.start_service('compute', host='host2', + cell='cell2') + # This is needed to avoid a NetworkAmbiguous error during + # _validate_requested_port_ids in allocate_for_instance. + fake_network.set_stub_network_methods(self) + # This is needed to find a server that is still booting with multiple + # cells, while waiting for the state change to ACTIVE. See the + # _get_instance method in the compute/api for details. + self.useFixture(nova_fixtures.AllServicesCurrent()) + + self.aggregates = {} + + def _create_aggregate(self, name): + agg = self.admin_api.post_aggregate({'aggregate': {'name': name}}) + self.aggregates[name] = agg + + def _add_host_to_aggregate(self, agg, host): + """Add a compute host to nova aggregates. + + :param agg: Name of the nova aggregate + :param host: Name of the compute host + """ + agg = self.aggregates[agg] + self.admin_api.add_host_to_aggregate(agg['id'], host) + + def _set_az_aggregate(self, agg, az): + """Set the availability_zone of an aggregate + + :param agg: Name of the nova aggregate + :param az: Availability zone name + """ + agg = self.aggregates[agg] + action = { + 'set_metadata': { + 'metadata': { + 'availability_zone': az, + } + }, + } + self.admin_api.post_aggregate_action(agg['id'], action) + + def test_boot_servers_with_affinity(self): + # Create a server group for affinity + # As of microversion 2.64, a single policy must be specified when + # creating a server group. + created_group = self.api.post_server_groups(self.affinity) + # Create aggregates for cell1 and cell2 + self._create_aggregate('agg1_cell1') + self._create_aggregate('agg2_cell2') + # Add each cell to a separate aggregate + self._add_host_to_aggregate('agg1_cell1', 'host1') + self._add_host_to_aggregate('agg2_cell2', 'host2') + # Set each cell to a separate availability zone + self._set_az_aggregate('agg1_cell1', 'cell1') + self._set_az_aggregate('agg2_cell2', 'cell2') + # Boot a server to cell2 with the affinity policy. Order matters here + # because the CellDatabases fixture defaults the local cell database to + # cell1. So boot the server to cell2 where the group member cannot be + # found as a result of the default setting. + self._boot_a_server_to_group(created_group, az='cell2') + # TODO(melwitt): Uncomment this when the bug is fixed. + # self._boot_a_server_to_group(created_group, az='cell1', + # expected_status='ERROR') + # TODO(melwitt): Remove this when the bug is fixed. + # Boot a server to cell1 with the affinity policy. This should fail + # because a group member has landed in cell2 already. But it passes + # because of the bug -- the query for group members doesn't find any + # members in cell2 because the query isn't multi-cell enabled. + self._boot_a_server_to_group(created_group, az='cell1')