Merge "Pull from cell0 and build_requests for instance list"
This commit is contained in:
commit
f3a1f92a1f
@ -2300,9 +2300,61 @@ class API(base.Base):
|
||||
LOG.debug('Removing limit for DB query due to IP filter')
|
||||
limit = None
|
||||
|
||||
instances = self._get_instances_by_filters(context, filters,
|
||||
limit=limit, marker=marker, expected_attrs=expected_attrs,
|
||||
sort_keys=sort_keys, sort_dirs=sort_dirs)
|
||||
# The ordering of instances will be
|
||||
# [sorted instances with no host] + [sorted instances with host].
|
||||
# This means BuildRequest and cell0 instances first, then cell
|
||||
# instances
|
||||
build_requests = objects.BuildRequestList.get_by_filters(
|
||||
context, filters, limit=limit, marker=marker, sort_keys=sort_keys,
|
||||
sort_dirs=sort_dirs)
|
||||
build_req_instances = objects.InstanceList(
|
||||
objects=[build_req.instance for build_req in build_requests])
|
||||
# Only subtract from limit if it is not None
|
||||
limit = (limit - len(build_req_instances)) if limit else limit
|
||||
|
||||
try:
|
||||
cell0_mapping = objects.CellMapping.get_by_uuid(context,
|
||||
objects.CellMapping.CELL0_UUID)
|
||||
except exception.CellMappingNotFound:
|
||||
cell0_instances = objects.InstanceList(objects=[])
|
||||
else:
|
||||
with nova_context.target_cell(context, cell0_mapping):
|
||||
cell0_instances = self._get_instances_by_filters(
|
||||
context, filters, limit=limit, marker=marker,
|
||||
expected_attrs=expected_attrs, sort_keys=sort_keys,
|
||||
sort_dirs=sort_dirs)
|
||||
# Only subtract from limit if it is not None
|
||||
limit = (limit - len(cell0_instances)) if limit else limit
|
||||
|
||||
# There is only planned support for a single cell here. Multiple cell
|
||||
# instance lists should be proxied to project Searchlight, or a similar
|
||||
# alternative.
|
||||
if limit is None or limit > 0:
|
||||
cell_instances = self._get_instances_by_filters(context, filters,
|
||||
limit=limit, marker=marker, expected_attrs=expected_attrs,
|
||||
sort_keys=sort_keys, sort_dirs=sort_dirs)
|
||||
else:
|
||||
cell_instances = objects.InstanceList(objects=[])
|
||||
|
||||
def _get_unique_filter_method():
|
||||
seen_uuids = set()
|
||||
|
||||
def _filter(instance):
|
||||
if instance.uuid in seen_uuids:
|
||||
return False
|
||||
seen_uuids.add(instance.uuid)
|
||||
return True
|
||||
|
||||
return _filter
|
||||
|
||||
filter_method = _get_unique_filter_method()
|
||||
# TODO(alaski): Clean up the objects concatenation when List objects
|
||||
# support it natively.
|
||||
instances = objects.InstanceList(
|
||||
objects=list(filter(filter_method,
|
||||
build_req_instances.objects +
|
||||
cell0_instances.objects +
|
||||
cell_instances.objects)))
|
||||
|
||||
if filter_ip:
|
||||
instances = self._ip_filter(instances, filters, orig_limit)
|
||||
|
@ -134,3 +134,42 @@ class ServersPreSchedulingTestCase(test.TestCase):
|
||||
create_resp.body['server']['id'],
|
||||
check_response_status=False)
|
||||
self.assertEqual(404, get_resp.status)
|
||||
|
||||
def _test_instance_list_from_buildrequests(self):
|
||||
image_ref = fake_image.get_valid_image_id()
|
||||
body = {
|
||||
'server': {
|
||||
'name': 'foo',
|
||||
'imageRef': image_ref,
|
||||
'flavorRef': '1',
|
||||
'networks': 'none',
|
||||
}
|
||||
}
|
||||
inst1 = self.api.api_post('servers', body)
|
||||
body['server']['name'] = 'bar'
|
||||
inst2 = self.api.api_post('servers', body)
|
||||
|
||||
list_resp = self.api.get_servers()
|
||||
# Default sort is created_at desc, so last created is first
|
||||
self.assertEqual(2, len(list_resp))
|
||||
self.assertEqual(inst2.body['server']['id'], list_resp[0]['id'])
|
||||
self.assertEqual('bar', list_resp[0]['name'])
|
||||
self.assertEqual(inst1.body['server']['id'], list_resp[1]['id'])
|
||||
self.assertEqual('foo', list_resp[1]['name'])
|
||||
|
||||
# Change the sort order
|
||||
list_resp = self.api.api_get(
|
||||
'servers/detail?sort_key=created_at&sort_dir=asc')
|
||||
list_resp = list_resp.body['servers']
|
||||
self.assertEqual(2, len(list_resp))
|
||||
self.assertEqual(inst1.body['server']['id'], list_resp[0]['id'])
|
||||
self.assertEqual('foo', list_resp[0]['name'])
|
||||
self.assertEqual(inst2.body['server']['id'], list_resp[1]['id'])
|
||||
self.assertEqual('bar', list_resp[1]['name'])
|
||||
|
||||
def test_instance_list_from_buildrequests(self):
|
||||
self.useFixture(nova_fixtures.AllServicesCurrent())
|
||||
self._test_instance_list_from_buildrequests()
|
||||
|
||||
def test_instance_list_from_buildrequests_old_service(self):
|
||||
self._test_instance_list_from_buildrequests()
|
||||
|
@ -10256,19 +10256,25 @@ class ComputeAPIIpFilterTestCase(test.NoDBTestCase):
|
||||
expected_ids = expected_ids[:expected_len]
|
||||
self.assertEqual(expected_ids, [inst.id for inst in insts])
|
||||
|
||||
def test_ip_filtering_no_limit_to_db(self):
|
||||
@mock.patch.object(objects.CellMapping, 'get_by_uuid',
|
||||
side_effect=exception.CellMappingNotFound(uuid='fake'))
|
||||
def test_ip_filtering_no_limit_to_db(self, _mock_cell_map_get):
|
||||
c = context.get_admin_context()
|
||||
# Limit is not supplied to the DB when using an IP filter
|
||||
with mock.patch('nova.objects.InstanceList.get_by_filters') as m_get:
|
||||
m_get.return_value = objects.InstanceList(objects=[])
|
||||
self.compute_api.get_all(c, search_opts={'ip': '.10'}, limit=1)
|
||||
self.assertEqual(1, m_get.call_count)
|
||||
kwargs = m_get.call_args[1]
|
||||
self.assertIsNone(kwargs['limit'])
|
||||
|
||||
def test_ip_filtering_pass_limit_to_db(self):
|
||||
@mock.patch.object(objects.CellMapping, 'get_by_uuid',
|
||||
side_effect=exception.CellMappingNotFound(uuid='fake'))
|
||||
def test_ip_filtering_pass_limit_to_db(self, _mock_cell_map_get):
|
||||
c = context.get_admin_context()
|
||||
# No IP filter, verify that the limit is passed
|
||||
with mock.patch('nova.objects.InstanceList.get_by_filters') as m_get:
|
||||
m_get.return_value = objects.InstanceList(objects=[])
|
||||
self.compute_api.get_all(c, search_opts={}, limit=1)
|
||||
self.assertEqual(1, m_get.call_count)
|
||||
kwargs = m_get.call_args[1]
|
||||
|
@ -3868,8 +3868,11 @@ class _ComputeAPIUnitTestMixIn(object):
|
||||
self.assertEqual(ephemeral_size, bdms[2].volume_size)
|
||||
|
||||
@mock.patch.object(compute_api.API, '_get_instances_by_filters')
|
||||
def test_tenant_to_project_conversion(self, mock_get):
|
||||
mock_get.return_value = []
|
||||
@mock.patch.object(objects.CellMapping, 'get_by_uuid')
|
||||
def test_tenant_to_project_conversion(self, mock_cell_map_get, mock_get):
|
||||
mock_cell_map_get.side_effect = exception.CellMappingNotFound(
|
||||
uuid='fake')
|
||||
mock_get.return_value = objects.InstanceList(objects=[])
|
||||
api = compute_api.API()
|
||||
api.get_all(self.context, search_opts={'tenant_id': 'foo'})
|
||||
filters = mock_get.call_args_list[0][0][1]
|
||||
@ -4241,6 +4244,209 @@ class _ComputeAPIUnitTestMixIn(object):
|
||||
'security_groups',
|
||||
'info_cache'])
|
||||
|
||||
def _list_of_instances(self, length=1):
|
||||
instances = []
|
||||
for i in range(length):
|
||||
instances.append(
|
||||
fake_instance.fake_instance_obj(self.context, objects.Instance,
|
||||
uuid=uuidutils.generate_uuid())
|
||||
)
|
||||
return instances
|
||||
|
||||
@mock.patch.object(objects.BuildRequestList, 'get_by_filters')
|
||||
@mock.patch.object(objects.CellMapping, 'get_by_uuid',
|
||||
side_effect=exception.CellMappingNotFound(uuid='fake'))
|
||||
def test_get_all_includes_build_requests(self, mock_cell_mapping_get,
|
||||
mock_buildreq_get):
|
||||
|
||||
build_req_instances = self._list_of_instances(2)
|
||||
build_reqs = [objects.BuildRequest(self.context, instance=instance)
|
||||
for instance in build_req_instances]
|
||||
mock_buildreq_get.return_value = objects.BuildRequestList(self.context,
|
||||
objects=build_reqs)
|
||||
|
||||
cell_instances = self._list_of_instances(2)
|
||||
|
||||
with mock.patch.object(self.compute_api,
|
||||
'_get_instances_by_filters') as mock_inst_get:
|
||||
mock_inst_get.return_value = objects.InstanceList(
|
||||
self.context, objects=cell_instances)
|
||||
|
||||
instances = self.compute_api.get_all(
|
||||
self.context, search_opts={'foo': 'bar'},
|
||||
limit=None, marker='fake-marker', sort_keys=['baz'],
|
||||
sort_dirs=['desc'])
|
||||
|
||||
mock_buildreq_get.assert_called_once_with(
|
||||
self.context, {'foo': 'bar'}, limit=None, marker='fake-marker',
|
||||
sort_keys=['baz'], sort_dirs=['desc'])
|
||||
mock_inst_get.assert_called_once_with(
|
||||
self.context, {'foo': 'bar'}, limit=None, marker='fake-marker',
|
||||
expected_attrs=None, sort_keys=['baz'], sort_dirs=['desc'])
|
||||
for i, instance in enumerate(build_req_instances + cell_instances):
|
||||
self.assertEqual(instance, instances[i])
|
||||
|
||||
@mock.patch.object(objects.BuildRequestList, 'get_by_filters')
|
||||
@mock.patch.object(objects.CellMapping, 'get_by_uuid',
|
||||
side_effect=exception.CellMappingNotFound(uuid='fake'))
|
||||
def test_get_all_includes_build_requests_filter_dupes(self,
|
||||
mock_cell_mapping_get, mock_buildreq_get):
|
||||
|
||||
build_req_instances = self._list_of_instances(2)
|
||||
build_reqs = [objects.BuildRequest(self.context, instance=instance)
|
||||
for instance in build_req_instances]
|
||||
mock_buildreq_get.return_value = objects.BuildRequestList(self.context,
|
||||
objects=build_reqs)
|
||||
|
||||
cell_instances = self._list_of_instances(2)
|
||||
|
||||
with mock.patch.object(self.compute_api,
|
||||
'_get_instances_by_filters') as mock_inst_get:
|
||||
# Insert one of the build_req_instances here so it shows up twice
|
||||
mock_inst_get.return_value = objects.InstanceList(
|
||||
self.context, objects=build_req_instances[:1] + cell_instances)
|
||||
|
||||
instances = self.compute_api.get_all(
|
||||
self.context, search_opts={'foo': 'bar'},
|
||||
limit=None, marker='fake-marker', sort_keys=['baz'],
|
||||
sort_dirs=['desc'])
|
||||
|
||||
mock_buildreq_get.assert_called_once_with(
|
||||
self.context, {'foo': 'bar'}, limit=None, marker='fake-marker',
|
||||
sort_keys=['baz'], sort_dirs=['desc'])
|
||||
mock_inst_get.assert_called_once_with(
|
||||
self.context, {'foo': 'bar'}, limit=None, marker='fake-marker',
|
||||
expected_attrs=None, sort_keys=['baz'], sort_dirs=['desc'])
|
||||
for i, instance in enumerate(build_req_instances + cell_instances):
|
||||
self.assertEqual(instance, instances[i])
|
||||
|
||||
@mock.patch.object(objects.BuildRequestList, 'get_by_filters')
|
||||
@mock.patch.object(objects.CellMapping, 'get_by_uuid',
|
||||
side_effect=exception.CellMappingNotFound(uuid='fake'))
|
||||
def test_get_all_build_requests_decrement_limit(self,
|
||||
mock_cell_mapping_get,
|
||||
mock_buildreq_get):
|
||||
|
||||
build_req_instances = self._list_of_instances(2)
|
||||
build_reqs = [objects.BuildRequest(self.context, instance=instance)
|
||||
for instance in build_req_instances]
|
||||
mock_buildreq_get.return_value = objects.BuildRequestList(self.context,
|
||||
objects=build_reqs)
|
||||
|
||||
cell_instances = self._list_of_instances(2)
|
||||
|
||||
with mock.patch.object(self.compute_api,
|
||||
'_get_instances_by_filters') as mock_inst_get:
|
||||
mock_inst_get.return_value = objects.InstanceList(
|
||||
self.context, objects=cell_instances)
|
||||
|
||||
instances = self.compute_api.get_all(
|
||||
self.context, search_opts={'foo': 'bar'},
|
||||
limit=10, marker='fake-marker', sort_keys=['baz'],
|
||||
sort_dirs=['desc'])
|
||||
|
||||
mock_buildreq_get.assert_called_once_with(
|
||||
self.context, {'foo': 'bar'}, limit=10, marker='fake-marker',
|
||||
sort_keys=['baz'], sort_dirs=['desc'])
|
||||
mock_inst_get.assert_called_once_with(
|
||||
self.context, {'foo': 'bar'}, limit=8, marker='fake-marker',
|
||||
expected_attrs=None, sort_keys=['baz'], sort_dirs=['desc'])
|
||||
for i, instance in enumerate(build_req_instances + cell_instances):
|
||||
self.assertEqual(instance, instances[i])
|
||||
|
||||
@mock.patch.object(context, 'target_cell')
|
||||
@mock.patch.object(objects.BuildRequestList, 'get_by_filters',
|
||||
return_value=objects.BuildRequestList(objects=[]))
|
||||
@mock.patch.object(objects.CellMapping, 'get_by_uuid')
|
||||
def test_get_all_includes_cell0(self, mock_cell_mapping_get,
|
||||
mock_buildreq_get, mock_target_cell):
|
||||
|
||||
cell0_instances = self._list_of_instances(2)
|
||||
cell_instances = self._list_of_instances(2)
|
||||
|
||||
cell_mapping = objects.CellMapping()
|
||||
mock_cell_mapping_get.return_value = cell_mapping
|
||||
|
||||
with mock.patch.object(self.compute_api,
|
||||
'_get_instances_by_filters') as mock_inst_get:
|
||||
mock_inst_get.side_effect = [objects.InstanceList(
|
||||
self.context,
|
||||
objects=cell0_instances),
|
||||
objects.InstanceList(
|
||||
self.context,
|
||||
objects=cell_instances)]
|
||||
|
||||
instances = self.compute_api.get_all(
|
||||
self.context, search_opts={'foo': 'bar'},
|
||||
limit=10, marker='fake-marker', sort_keys=['baz'],
|
||||
sort_dirs=['desc'])
|
||||
|
||||
mock_target_cell.assert_called_once_with(self.context,
|
||||
cell_mapping)
|
||||
inst_get_calls = [mock.call(self.context, {'foo': 'bar'},
|
||||
limit=10, marker='fake-marker',
|
||||
expected_attrs=None, sort_keys=['baz'],
|
||||
sort_dirs=['desc']),
|
||||
mock.call(self.context, {'foo': 'bar'},
|
||||
limit=8, marker='fake-marker',
|
||||
expected_attrs=None, sort_keys=['baz'],
|
||||
sort_dirs=['desc'])
|
||||
]
|
||||
self.assertEqual(2, mock_inst_get.call_count)
|
||||
mock_inst_get.assert_has_calls(inst_get_calls)
|
||||
for i, instance in enumerate(cell0_instances + cell_instances):
|
||||
self.assertEqual(instance, instances[i])
|
||||
|
||||
@mock.patch.object(context, 'target_cell')
|
||||
@mock.patch.object(objects.BuildRequestList, 'get_by_filters')
|
||||
@mock.patch.object(objects.CellMapping, 'get_by_uuid')
|
||||
def test_get_all_includes_build_request_cell0(self, mock_cell_mapping_get,
|
||||
mock_buildreq_get, mock_target_cell):
|
||||
|
||||
build_req_instances = self._list_of_instances(2)
|
||||
build_reqs = [objects.BuildRequest(self.context, instance=instance)
|
||||
for instance in build_req_instances]
|
||||
mock_buildreq_get.return_value = objects.BuildRequestList(self.context,
|
||||
objects=build_reqs)
|
||||
|
||||
cell0_instances = self._list_of_instances(2)
|
||||
cell_instances = self._list_of_instances(2)
|
||||
|
||||
cell_mapping = objects.CellMapping()
|
||||
mock_cell_mapping_get.return_value = cell_mapping
|
||||
|
||||
with mock.patch.object(self.compute_api,
|
||||
'_get_instances_by_filters') as mock_inst_get:
|
||||
mock_inst_get.side_effect = [objects.InstanceList(
|
||||
self.context,
|
||||
objects=cell0_instances),
|
||||
objects.InstanceList(
|
||||
self.context,
|
||||
objects=cell_instances)]
|
||||
|
||||
instances = self.compute_api.get_all(
|
||||
self.context, search_opts={'foo': 'bar'},
|
||||
limit=10, marker='fake-marker', sort_keys=['baz'],
|
||||
sort_dirs=['desc'])
|
||||
|
||||
mock_target_cell.assert_called_once_with(self.context,
|
||||
cell_mapping)
|
||||
inst_get_calls = [mock.call(self.context, {'foo': 'bar'},
|
||||
limit=8, marker='fake-marker',
|
||||
expected_attrs=None, sort_keys=['baz'],
|
||||
sort_dirs=['desc']),
|
||||
mock.call(self.context, {'foo': 'bar'},
|
||||
limit=6, marker='fake-marker',
|
||||
expected_attrs=None, sort_keys=['baz'],
|
||||
sort_dirs=['desc'])
|
||||
]
|
||||
self.assertEqual(2, mock_inst_get.call_count)
|
||||
mock_inst_get.assert_has_calls(inst_get_calls)
|
||||
for i, instance in enumerate(build_req_instances +
|
||||
cell0_instances +
|
||||
cell_instances):
|
||||
self.assertEqual(instance, instances[i])
|
||||
|
||||
|
||||
class ComputeAPIUnitTestCase(_ComputeAPIUnitTestMixIn, test.NoDBTestCase):
|
||||
def setUp(self):
|
||||
|
Loading…
Reference in New Issue
Block a user