Make server groups api aware of multiple cells for membership
This teaches the server groups api to query all of the cells that have an instance claiming to be a member of the group. Instead of polling all cells, this collects the subset of cells that actually have members, according to our InstanceMapping data, and then checks for the deleted-ness in the actual cell database. This augments the tests to have one instance in each cell, plus an instance that is not yet scheduled in any cell to give us coverage of all the possibilities. This replaces the previously-flawed and now reverted change: If571f9e7c9d0ef6265a249ff808d30a24ab462af Change-Id: Idd2e35bc95ed98ebc0340ff62e109e23c8adcb21
This commit is contained in:
parent
c3597c87d8
commit
1226c57884
nova
@ -15,6 +15,8 @@
|
||||
|
||||
"""The Server Group API Extension."""
|
||||
|
||||
import collections
|
||||
|
||||
from oslo_log import log as logging
|
||||
import webob
|
||||
from webob import exc
|
||||
@ -25,6 +27,7 @@ from nova.api.openstack.compute.schemas import server_groups as schema
|
||||
from nova.api.openstack import extensions
|
||||
from nova.api.openstack import wsgi
|
||||
from nova.api import validation
|
||||
from nova import context as nova_context
|
||||
import nova.exception
|
||||
from nova.i18n import _
|
||||
from nova import objects
|
||||
@ -41,6 +44,40 @@ def _authorize_context(req, action):
|
||||
return context
|
||||
|
||||
|
||||
def _get_not_deleted(context, uuids):
|
||||
mappings = objects.InstanceMappingList.get_by_instance_uuids(
|
||||
context, uuids)
|
||||
inst_by_cell = collections.defaultdict(list)
|
||||
cell_mappings = {}
|
||||
found_inst_uuids = []
|
||||
|
||||
# Get a master list of cell mappings, and a list of instance
|
||||
# uuids organized by cell
|
||||
for im in mappings:
|
||||
if not im.cell_mapping:
|
||||
# Not scheduled yet, so just throw it in the final list
|
||||
# and move on
|
||||
found_inst_uuids.append(im.instance_uuid)
|
||||
continue
|
||||
if im.cell_mapping.uuid not in cell_mappings:
|
||||
cell_mappings[im.cell_mapping.uuid] = im.cell_mapping
|
||||
inst_by_cell[im.cell_mapping.uuid].append(im.instance_uuid)
|
||||
|
||||
# Query each cell for the instances that are inside, building
|
||||
# a list of non-deleted instance uuids.
|
||||
for cell_uuid, cell_mapping in cell_mappings.items():
|
||||
inst_uuids = inst_by_cell[cell_uuid]
|
||||
LOG.debug('Querying cell %(cell)s for %(num)i instances',
|
||||
{'cell': cell_mapping.identity, 'num': len(uuids)})
|
||||
filters = {'uuid': inst_uuids, 'deleted': False}
|
||||
with nova_context.target_cell(context, cell_mapping) as ctx:
|
||||
found_inst_uuids.extend([
|
||||
inst.uuid for inst in objects.InstanceList.get_by_filters(
|
||||
ctx, filters=filters)])
|
||||
|
||||
return found_inst_uuids
|
||||
|
||||
|
||||
class ServerGroupController(wsgi.Controller):
|
||||
"""The Server group API controller for the OpenStack API."""
|
||||
|
||||
@ -59,10 +96,7 @@ class ServerGroupController(wsgi.Controller):
|
||||
members = []
|
||||
if group.members:
|
||||
# Display the instances that are not deleted.
|
||||
filters = {'uuid': group.members, 'deleted': False}
|
||||
instances = objects.InstanceList.get_by_filters(
|
||||
context, filters=filters)
|
||||
members = [instance.uuid for instance in instances]
|
||||
members = _get_not_deleted(context, group.members)
|
||||
server_group['members'] = members
|
||||
# Add project id information to the response data for
|
||||
# API version v2.13
|
||||
|
@ -24,6 +24,7 @@ from nova import exception
|
||||
from nova import objects
|
||||
from nova.policies import server_groups as sg_policies
|
||||
from nova import test
|
||||
from nova.tests import fixtures
|
||||
from nova.tests.unit.api.openstack import fakes
|
||||
from nova.tests.unit import policy_fixture
|
||||
from nova.tests import uuidsentinel
|
||||
@ -75,7 +76,8 @@ def server_group_db(sg):
|
||||
return AttrDict(attrs)
|
||||
|
||||
|
||||
class ServerGroupTestV21(test.TestCase):
|
||||
class ServerGroupTestV21(test.NoDBTestCase):
|
||||
USES_DB_SELF = True
|
||||
validation_error = exception.ValidationError
|
||||
|
||||
def setUp(self):
|
||||
@ -86,6 +88,22 @@ class ServerGroupTestV21(test.TestCase):
|
||||
self.foo_req = fakes.HTTPRequest.blank('', project_id='foo')
|
||||
self.policy = self.useFixture(policy_fixture.RealPolicyFixture())
|
||||
|
||||
self.useFixture(fixtures.Database(database='api'))
|
||||
cells = fixtures.CellDatabases()
|
||||
cells.add_cell_database(uuidsentinel.cell1)
|
||||
cells.add_cell_database(uuidsentinel.cell2)
|
||||
self.useFixture(cells)
|
||||
|
||||
ctxt = context.get_admin_context()
|
||||
self.cells = {}
|
||||
for uuid in (uuidsentinel.cell1, uuidsentinel.cell2):
|
||||
cm = objects.CellMapping(context=ctxt,
|
||||
uuid=uuid,
|
||||
database_connection=uuid,
|
||||
transport_url=uuid)
|
||||
cm.create()
|
||||
self.cells[cm.uuid] = cm
|
||||
|
||||
def _setup_controller(self):
|
||||
self.controller = sg_v21.ServerGroupController()
|
||||
|
||||
@ -138,14 +156,21 @@ class ServerGroupTestV21(test.TestCase):
|
||||
"Policy doesn't allow %s to be performed." % rule_name,
|
||||
exc.format_message())
|
||||
|
||||
def _create_instance(self, context):
|
||||
instance = objects.Instance(context=context,
|
||||
image_ref=uuidsentinel.fake_image_ref,
|
||||
node='node1', reservation_id='a',
|
||||
host='host1', project_id='fake',
|
||||
vm_state='fake',
|
||||
system_metadata={'key': 'value'})
|
||||
instance.create()
|
||||
def _create_instance(self, ctx, cell):
|
||||
with context.target_cell(ctx, cell) as cctx:
|
||||
instance = objects.Instance(context=cctx,
|
||||
image_ref=uuidsentinel.fake_image_ref,
|
||||
node='node1', reservation_id='a',
|
||||
host='host1', project_id='fake',
|
||||
vm_state='fake',
|
||||
system_metadata={'key': 'value'})
|
||||
instance.create()
|
||||
im = objects.InstanceMapping(context=ctx,
|
||||
project_id=ctx.project_id,
|
||||
user_id=ctx.user_id,
|
||||
cell_mapping=cell,
|
||||
instance_uuid=instance.uuid)
|
||||
im.create()
|
||||
return instance
|
||||
|
||||
def _create_instance_group(self, context, members):
|
||||
@ -156,7 +181,11 @@ class ServerGroupTestV21(test.TestCase):
|
||||
return ig.uuid
|
||||
|
||||
def _create_groups_and_instances(self, ctx):
|
||||
instances = [self._create_instance(ctx), self._create_instance(ctx)]
|
||||
cell1 = self.cells[uuidsentinel.cell1]
|
||||
cell2 = self.cells[uuidsentinel.cell2]
|
||||
instances = [self._create_instance(ctx, cell=cell1),
|
||||
self._create_instance(ctx, cell=cell2),
|
||||
self._create_instance(ctx, cell=None)]
|
||||
members = [instance.uuid for instance in instances]
|
||||
ig_uuid = self._create_instance_group(ctx, members)
|
||||
return (ig_uuid, instances, members)
|
||||
@ -291,7 +320,7 @@ class ServerGroupTestV21(test.TestCase):
|
||||
(ig_uuid, instances, members) = self._create_groups_and_instances(ctx)
|
||||
res_dict = self.controller.show(self.req, ig_uuid)
|
||||
result_members = res_dict['server_group']['members']
|
||||
self.assertEqual(2, len(result_members))
|
||||
self.assertEqual(3, len(result_members))
|
||||
for member in members:
|
||||
self.assertIn(member, result_members)
|
||||
|
||||
@ -304,7 +333,11 @@ class ServerGroupTestV21(test.TestCase):
|
||||
(ig_uuid, instances, members) = self._create_groups_and_instances(ctx)
|
||||
|
||||
# delete an instance
|
||||
instances[1].destroy()
|
||||
im = objects.InstanceMapping.get_by_instance_uuid(ctx,
|
||||
instances[1].uuid)
|
||||
with context.target_cell(ctx, im.cell_mapping):
|
||||
instances[1].destroy()
|
||||
|
||||
# check that the instance does not exist
|
||||
self.assertRaises(exception.InstanceNotFound,
|
||||
objects.Instance.get_by_uuid,
|
||||
@ -312,7 +345,7 @@ class ServerGroupTestV21(test.TestCase):
|
||||
res_dict = self.controller.show(self.req, ig_uuid)
|
||||
result_members = res_dict['server_group']['members']
|
||||
# check that only the active instance is displayed
|
||||
self.assertEqual(1, len(result_members))
|
||||
self.assertEqual(2, len(result_members))
|
||||
self.assertIn(instances[0].uuid, result_members)
|
||||
|
||||
def test_display_members_rbac_default(self):
|
||||
|
Loading…
x
Reference in New Issue
Block a user