def test_with_failing_middle_cells(self): data = [{'id': 'foo-%i' % i} for i in range(0, 100)] cells = [objects.CellMapping(uuid=getattr(uuids, 'cell%i' % i), name='cell%i' % i) for i in range(0, 3)] lister = FailureLister(data, [], [], cells=cells) # One cell will succeed and then time out, one will fail immediately, # and the last will always work lister.set_fails(uuids.cell0, [None, context.did_not_respond_sentinel]) # Note that BuildAbortException will never appear during instance # listing, the aim is to only simulate a situation where there could # be some type of exception arising. lister.set_fails(uuids.cell1, exception.BuildAbortException( instance_uuid='fake', reason='fake')) ctx = context.RequestContext() result = lister.get_records_sorted(ctx, {}, 50, None, batch_size=5) # We should still have 50 results since there are enough from the # good cells to fill our limit. self.assertEqual(50, len(list(result))) # Make sure the counts line up self.assertEqual(1, len(lister.cells_responded)) self.assertEqual(1, len(lister.cells_failed)) self.assertEqual(1, len(lister.cells_timed_out))
def test_scatter_gather_cells(self, mock_get_inst, mock_target_cell): ctxt = context.get_context() mapping = objects.CellMapping(database_connection='fake://db', transport_url='fake://mq', uuid=uuids.cell) mappings = objects.CellMappingList(objects=[mapping]) # Use a mock manager to assert call order across mocks. manager = mock.Mock() manager.attach_mock(mock_get_inst, 'get_inst') manager.attach_mock(mock_target_cell, 'target_cell') filters = {'deleted': False} context.scatter_gather_cells( ctxt, mappings, 60, objects.InstanceList.get_by_filters, filters, sort_dir='foo') # NOTE(melwitt): This only works without the SpawnIsSynchronous fixture # because when the spawn is treated as synchronous and the thread # function is called immediately, it will occur inside the target_cell # context manager scope when it wouldn't with a real spawn. # Assert that InstanceList.get_by_filters was called before the # target_cell context manager exited. get_inst_call = mock.call.get_inst( mock_target_cell.return_value.__enter__.return_value, filters, sort_dir='foo') expected_calls = [get_inst_call, mock.call.target_cell().__exit__(None, None, None)] manager.assert_has_calls(expected_calls)
def test_create(self, create_in_db): db_mapping = get_db_mapping() uuid = db_mapping['instance_uuid'] create_in_db.return_value = db_mapping mapping_obj = objects.InstanceMapping(self.context) mapping_obj.instance_uuid = uuid mapping_obj.cell_mapping = objects.CellMapping( self.context, id=db_mapping['cell_mapping']['id']) mapping_obj.project_id = db_mapping['project_id'] mapping_obj.user_id = db_mapping['user_id'] mapping_obj.create() create_in_db.assert_called_once_with( self.context, { 'instance_uuid': uuid, 'queued_for_delete': False, 'cell_id': db_mapping['cell_mapping']['id'], 'project_id': db_mapping['project_id'], 'user_id': db_mapping['user_id'] }) self.compare_obj( mapping_obj, db_mapping, subs={'cell_mapping': 'cell_id'}, comparators={'cell_mapping': self._check_cell_map_value})
def test_upgrade_without_cell0(self): self._flavor_me() cell1 = objects.CellMapping(context=self.context, uuid=uuidsentinel.cell1, name='cell1', transport_url='fake', database_connection='fake') cell1.create() cell2 = objects.CellMapping(context=self.context, uuid=uuidsentinel.cell2, name='cell2', transport_url='fake', database_connection='fake') cell2.create() self.assertRaisesRegex(exception.ValidationError, 'Cell0', self.migration.upgrade, self.engine)
def test_scatter_gather_cells_all_timeout(self, mock_get_inst, mock_get_result, mock_timeout, mock_log_warning): """This is a regression test for bug 1847131. test_scatter_gather_cells_timeout did not catch the issue because it yields a result which sets the cell_uuid variable in scope before the CellTimeout is processed and logged. In this test we only raise the CellTimeout so cell_uuid will not be in scope for the log message. """ # This is needed because we're mocking get_by_filters. self.useFixture(nova_fixtures.SpawnIsSynchronousFixture()) ctxt = context.get_context() mapping0 = objects.CellMapping(database_connection='fake://db0', transport_url='none:///', uuid=objects.CellMapping.CELL0_UUID) mappings = objects.CellMappingList(objects=[mapping0]) # Simulate cell0 not responding. mock_get_result.side_effect = exception.CellTimeout() results = context.scatter_gather_cells( ctxt, mappings, 30, objects.InstanceList.get_by_filters, {}) self.assertEqual(1, len(results)) self.assertIn(context.did_not_respond_sentinel, results.values()) mock_timeout.assert_called_once_with(30, exception.CellTimeout) mock_log_warning.assert_called_once_with( 'Timed out waiting for response from cell', exc_info=True)
def test_map_instances_marker_deleted(self): ctxt = context.RequestContext('fake-user', 'fake_project') cell_uuid = uuidutils.generate_uuid() cell_mapping = objects.CellMapping(ctxt, uuid=cell_uuid, name='fake', transport_url='fake://', database_connection='fake://') cell_mapping.create() instance_uuids = [] for i in range(6): uuid = uuidutils.generate_uuid() instance_uuids.append(uuid) objects.Instance(ctxt, project_id=ctxt.project_id, uuid=uuid).create() ret = self.commands.map_instances(cell_uuid, max_count=3) self.assertEqual(1, ret) # Instances are mapped in the order created so we know the marker is # based off the third instance. marker = instance_uuids[2].replace('-', ' ') marker_mapping = objects.InstanceMapping.get_by_instance_uuid( ctxt, marker) marker_mapping.destroy() ret = self.commands.map_instances(cell_uuid) self.assertEqual(0, ret) for uuid in instance_uuids: inst_mapping = objects.InstanceMapping.get_by_instance_uuid( ctxt, uuid) self.assertEqual(ctxt.project_id, inst_mapping.project_id)
def test_destroy(self, destroy_in_db): uuid = uuidutils.generate_uuid() mapping_obj = objects.CellMapping(self.context) mapping_obj.uuid = uuid mapping_obj.destroy() destroy_in_db.assert_called_once_with(self.context, uuid)
def test_connection_switch(self): # Use a file-based sqlite database so data will persist across new # connections fake_conn = 'sqlite:///' + self.test_filename # The 'main' database connection will stay open, so in-memory is fine self.useFixture(fixtures.Database(database='main')) self.useFixture(fixtures.Database(connection=fake_conn)) # Make a request context with a cell mapping mapping = objects.CellMapping(database_connection=fake_conn) # In the tests, the admin context is required in order to read # an Instance back after write, for some reason ctxt = context.get_admin_context() # Create an instance in the cell database uuid = uuidutils.generate_uuid() with context.target_cell(ctxt, mapping): instance = objects.Instance(context=ctxt, uuid=uuid) instance.create() # Verify the instance is found in the cell database inst = objects.Instance.get_by_uuid(ctxt, uuid) self.assertEqual(uuid, inst.uuid) # Verify the instance isn't found in the main database self.assertRaises(exception.InstanceNotFound, objects.Instance.get_by_uuid, ctxt, uuid)
def test_map_instances_max_count(self): ctxt = context.RequestContext('fake-user', 'fake_project') cell_uuid = uuidutils.generate_uuid() cell_mapping = objects.CellMapping(ctxt, uuid=cell_uuid, name='fake', transport_url='fake://', database_connection='fake://') cell_mapping.create() instance_uuids = [] for i in range(6): uuid = uuidutils.generate_uuid() instance_uuids.append(uuid) objects.Instance(ctxt, project_id=ctxt.project_id, uuid=uuid).create() ret = self.commands.map_instances(cell_uuid, max_count=3) self.assertEqual(1, ret) for uuid in instance_uuids[:3]: # First three are mapped inst_mapping = objects.InstanceMapping.get_by_instance_uuid( ctxt, uuid) self.assertEqual(ctxt.project_id, inst_mapping.project_id) for uuid in instance_uuids[3:]: # Last three are not self.assertRaises(exception.InstanceMappingNotFound, objects.InstanceMapping.get_by_instance_uuid, ctxt, uuid)
def setUp(self): super(TestInstanceList, self).setUp() cells = [ objects.CellMapping(uuid=getattr(uuids, 'cell%i' % i), name='cell%i' % i, transport_url='fake:///', database_connection='fake://') for i in range(0, 3) ] insts = {} for cell in cells: insts[cell.uuid] = list([ dict(uuid=getattr(uuids, '%s-inst%i' % (cell.name, i)), hostname='%s-inst%i' % (cell.name, i)) for i in range(0, 3) ]) self.cells = cells self.insts = insts self.context = nova_context.RequestContext() self.useFixture(fixtures.SpawnIsSynchronousFixture()) self.flags(instance_list_cells_batch_strategy='fixed', group='api')
def test_by_host(self, mock_rpcclient, mock_create, mock_get): default_client = mock.Mock() cell_client = mock.Mock() mock_rpcclient.return_value = cell_client ctxt = mock.Mock() cm = objects.CellMapping(uuid=uuids.cell_mapping, transport_url='fake:///') mock_get.return_value = objects.HostMapping(cell_mapping=cm) host = 'fake-host' router = rpc.ClientRouter(default_client) client = router.by_host(ctxt, host) mock_get.assert_called_once_with(ctxt, host) # verify a client was created by ClientRouter mock_rpcclient.assert_called_once_with( mock_create.return_value, default_client.target, version_cap=default_client.version_cap, serializer=default_client.serializer) # verify cell client was returned self.assertEqual(cell_client, client) # reset and check that cached client is returned the second time mock_rpcclient.reset_mock() mock_create.reset_mock() mock_get.reset_mock() client = router.by_host(ctxt, host) mock_get.assert_called_once_with(ctxt, host) mock_rpcclient.assert_not_called() mock_create.assert_not_called() self.assertEqual(cell_client, client)
def test_get_by_uuid_invalid(self, uuid_from_db): db_mapping = get_db_mapping() self.assertRaises(exception.CellMappingNotFound, objects.CellMapping().get_by_uuid, self.context, db_mapping['uuid']) uuid_from_db.assert_called_once_with(self.context, db_mapping['uuid'])
def test_connection_switch(self): ctxt = context.RequestContext('fake-user', 'fake-project') # Make a request context with a cell mapping mapping = objects.CellMapping(context=ctxt, uuid=uuidutils.generate_uuid(), database_connection=self.fake_conn, transport_url='none:///') mapping.create() # Create an instance in the cell database uuid = uuidutils.generate_uuid() with context.target_cell(ctxt, mapping) as cctxt: # Must set project_id because instance get specifies # project_only=True to model_query, which means non-admin # users can only read instances for their project instance = objects.Instance(context=cctxt, uuid=uuid, project_id='fake-project') instance.create() # Verify the instance is found in the cell database inst = objects.Instance.get_by_uuid(cctxt, uuid) self.assertEqual(uuid, inst.uuid) # Verify the instance isn't found in the main database self.assertRaises(exception.InstanceNotFound, objects.Instance.get_by_uuid, ctxt, uuid)
def test_map_instances_duplicates(self): ctxt = context.RequestContext('fake-user', 'fake_project') cell_uuid = uuidutils.generate_uuid() cell_mapping = objects.CellMapping(ctxt, uuid=cell_uuid, name='fake', transport_url='fake://', database_connection='fake://') cell_mapping.create() instance_uuids = [] for i in range(3): uuid = uuidutils.generate_uuid() instance_uuids.append(uuid) objects.Instance(ctxt, project_id=ctxt.project_id, uuid=uuid).create() objects.InstanceMapping(ctxt, project_id=ctxt.project_id, instance_uuid=instance_uuids[0], cell_mapping=cell_mapping).create() self.commands.map_instances(cell_uuid) for uuid in instance_uuids: inst_mapping = objects.InstanceMapping.get_by_instance_uuid( ctxt, uuid) self.assertEqual(ctxt.project_id, inst_mapping.project_id) mappings = objects.InstanceMappingList.get_by_project_id( ctxt, ctxt.project_id) self.assertEqual(3, len(mappings))
def test_get_by_disabled(self): for ident in (4, 3): # We start with id's 4 and 3 because we already have 2 enabled cell # mappings in the base test case setup. 4 is before 3 to simply # verify the sorting mechanism. cm = objects.CellMapping(context=self.context, id=ident, uuid=getattr(uuids, 'cell%i' % ident), transport_url='fake://%i' % ident, database_connection='fake://%i' % ident, disabled=True) cm.create() obj = objects.CellMappingList.get_all(self.context) ids = [c.id for c in obj] # Returns all the cells self.assertEqual([1, 2, 3, 4], ids) obj = objects.CellMappingList.get_by_disabled(self.context, disabled=False) ids = [c.id for c in obj] # Returns only the enabled ones self.assertEqual([1, 2], ids) obj = objects.CellMappingList.get_by_disabled(self.context, disabled=True) ids = [c.id for c in obj] # Returns only the disabled ones self.assertEqual([3, 4], ids)
def test_save(self, save_in_db): db_mapping = get_db_mapping() # This isn't needed here db_mapping.pop("cell_mapping") host = db_mapping['host'] mapping_obj = objects.HostMapping(self.context) mapping_obj.host = host mapping_obj.id = db_mapping['id'] new_fake_cell = test_cell_mapping.get_db_mapping(id=10) fake_cell_obj = objects.CellMapping(self.context, **new_fake_cell) mapping_obj.cell_mapping = fake_cell_obj db_mapping.update({"cell_id": new_fake_cell["id"]}) save_in_db.return_value = db_mapping mapping_obj.save() save_in_db.assert_called_once_with( self.context, test.MatchType(host_mapping.HostMapping), { 'cell_id': new_fake_cell["id"], 'host': host, 'id': db_mapping['id'] }) self.compare_obj( mapping_obj, db_mapping, subs={'cell_mapping': 'cell_id'}, comparators={'cell_mapping': self._check_cell_map_value})
def test_map_instances_duplicates(self): ctxt = context.RequestContext('fake-user', 'fake_project') cell_uuid = uuidutils.generate_uuid() cell_mapping = objects.CellMapping( ctxt, uuid=cell_uuid, name='fake', transport_url='fake://', database_connection='fake://') cell_mapping.create() instance_uuids = [] for i in range(3): uuid = uuidutils.generate_uuid() instance_uuids.append(uuid) objects.Instance(ctxt, project_id=ctxt.project_id, uuid=uuid).create() objects.InstanceMapping(ctxt, project_id=ctxt.project_id, instance_uuid=instance_uuids[0], cell_mapping=cell_mapping).create() self.commands.map_instances(cell_uuid, verbose=True) output = sys.stdout.getvalue().strip() self.assertIn('%s already mapped to cell' % instance_uuids[0], output) for uuid in instance_uuids: inst_mapping = objects.InstanceMapping.get_by_instance_uuid(ctxt, uuid) self.assertEqual(ctxt.project_id, inst_mapping.project_id)
def test_discover_services_one_cell(self, mock_srv, mock_hm_create, mock_hm_get, mock_cm): mock_cm.return_value = objects.CellMapping(uuid=uuids.cell1) mock_srv.return_value = [ objects.Service(host='host1'), objects.Service(host='host2'), ] def fake_get_host_mapping(ctxt, host): if host == 'host2': return else: raise exception.HostMappingNotFound(name=host) mock_hm_get.side_effect = fake_get_host_mapping lines = [] def fake_status(msg): lines.append(msg) ctxt = context.get_admin_context() mappings = host_mapping.discover_hosts(ctxt, cell_uuid=uuids.cell1, status_fn=fake_status, by_service=True) self.assertEqual(1, len(mappings)) self.assertEqual(['host1'], sorted([m.host for m in mappings])) expected = """\ Getting computes from cell: %(cell)s Creating host mapping for service host1 Found 1 unmapped computes in cell: %(cell)s""" % {'cell': uuids.cell1} self.assertEqual(expected, '\n'.join(lines))
def test_discover_hosts_one(self, mock_cn_get, mock_hm_get, mock_hm_create, mock_cm): def _hm_get(context, host): if host in ['a', 'b', 'c']: return objects.HostMapping() raise exception.HostMappingNotFound(name=host) mock_hm_get.side_effect = _hm_get # NOTE(danms): Provide both side effects, but expect it to only # be called once if we provide a cell mock_cn_get.side_effect = [[objects.ComputeNode(host='d', uuid=uuids.cn1)], [objects.ComputeNode(host='e', uuid=uuids.cn2)]] mock_cm.return_value = objects.CellMapping(name='foo', uuid=uuids.cm1) ctxt = context.get_admin_context() with mock.patch('nova.objects.ComputeNode.save') as mock_save: hms = host_mapping.discover_hosts(ctxt, uuids.cm1) mock_save.assert_called_once_with() self.assertEqual(1, len(hms)) self.assertTrue(mock_hm_create.called) self.assertEqual(['d'], [hm.host for hm in hms])
def test_instances_cores_ram_count(self): ctxt = context.RequestContext('fake-user', 'fake-project') mapping1 = objects.CellMapping(context=ctxt, uuid=uuidutils.generate_uuid(), database_connection='cell1', transport_url='none:///') mapping2 = objects.CellMapping(context=ctxt, uuid=uuidutils.generate_uuid(), database_connection='cell2', transport_url='none:///') mapping1.create() mapping2.create() # Create an instance in cell1 with context.target_cell(ctxt, mapping1) as cctxt: instance = objects.Instance(context=cctxt, project_id='fake-project', user_id='fake-user', vcpus=2, memory_mb=512) instance.create() # Create an instance in cell2 with context.target_cell(ctxt, mapping2) as cctxt: instance = objects.Instance(context=cctxt, project_id='fake-project', user_id='fake-user', vcpus=4, memory_mb=1024) instance.create() # Create an instance in cell2 for a different user with context.target_cell(ctxt, mapping2) as cctxt: instance = objects.Instance(context=cctxt, project_id='fake-project', user_id='other-fake-user', vcpus=4, memory_mb=1024) instance.create() # Count instances, cores, and ram across cells count = quota._instances_cores_ram_count(ctxt, 'fake-project', user_id='fake-user') self.assertEqual(3, count['project']['instances']) self.assertEqual(10, count['project']['cores']) self.assertEqual(2560, count['project']['ram']) self.assertEqual(2, count['user']['instances']) self.assertEqual(6, count['user']['cores']) self.assertEqual(1536, count['user']['ram'])
def test_server_group_members_count_by_user(self): ctxt = context.RequestContext('fake-user', 'fake-project') mapping1 = objects.CellMapping(context=ctxt, uuid=uuidutils.generate_uuid(), database_connection='cell1', transport_url='none:///') mapping2 = objects.CellMapping(context=ctxt, uuid=uuidutils.generate_uuid(), database_connection='cell2', transport_url='none:///') mapping1.create() mapping2.create() # Create a server group the instances will use. group = objects.InstanceGroup(context=ctxt) group.project_id = ctxt.project_id group.user_id = ctxt.user_id group.create() instance_uuids = [] # Create an instance in cell1 with context.target_cell(ctxt, mapping1) as cctxt: instance = objects.Instance(context=cctxt, project_id='fake-project', user_id='fake-user') instance.create() instance_uuids.append(instance.uuid) # Create an instance in cell2 with context.target_cell(ctxt, mapping2) as cctxt: instance = objects.Instance(context=cctxt, project_id='fake-project', user_id='fake-user') instance.create() instance_uuids.append(instance.uuid) # Add the uuids to the group objects.InstanceGroup.add_members(ctxt, group.uuid, instance_uuids) # add_members() doesn't add the members to the object field group.members.extend(instance_uuids) # Count server group members across cells count = quota._server_group_count_members_by_user( ctxt, group, 'fake-user') self.assertEqual(2, count['user']['server_group_members'])
def test_service_delete(self, get_by_id, load_cells, set_target): compute_api.CELLS = [ objects.CellMapping(), objects.CellMapping(), objects.CellMapping(), ] service = mock.MagicMock() get_by_id.side_effect = [exception.ServiceNotFound(service_id=1), service, exception.ServiceNotFound(service_id=1)] self.host_api.service_delete(self.ctxt, 1) get_by_id.assert_has_calls([mock.call(self.ctxt, 1), mock.call(self.ctxt, 1), mock.call(self.ctxt, 1)]) service.destroy.assert_called_once_with() set_target.assert_called_once_with(self.ctxt, compute_api.CELLS[1])
def setUp(self): super(TestBatching, self).setUp() self._data = [{'id': 'foo-%i' % i} for i in range(0, 1000)] self._cells = [ objects.CellMapping(uuid=getattr(uuids, 'cell%i' % i), name='cell%i' % i) for i in range(0, 10) ]
def _create_cell_mapping(self, uuid): cm = objects.CellMapping(context=context.get_admin_context(), uuid=uuid, name=uuid, transport_url='fake://%s/' % uuid, database_connection=uuid) cm.create() return cm
def test_upgrade_with_no_host_mappings(self): self._flavor_me() cell0 = objects.CellMapping(context=self.context, uuid=objects.CellMapping.CELL0_UUID, name='cell0', transport_url='fake', database_connection='fake') cell0.create() cell1 = objects.CellMapping(context=self.context, uuid=uuidsentinel.cell1, name='cell1', transport_url='fake', database_connection='fake') cell1.create() self.assertRaisesRegex(exception.ValidationError, 'host mappings', self.migration.upgrade, self.engine)
def test_get_by_uuid(self, uuid_from_db): db_mapping = get_db_mapping() uuid_from_db.return_value = db_mapping mapping_obj = objects.CellMapping().get_by_uuid(self.context, db_mapping['uuid']) uuid_from_db.assert_called_once_with(self.context, db_mapping['uuid']) self.compare_obj(mapping_obj, db_mapping)
def test_service_delete_ambiguous(self, get_by_id, load_cells, set_target): compute.CELLS = [ objects.CellMapping(), objects.CellMapping(), objects.CellMapping(), ] service1 = mock.MagicMock() service2 = mock.MagicMock() get_by_id.side_effect = [ exception.ServiceNotFound(service_id=1), service1, service2 ] self.assertRaises(exception.ServiceNotUnique, self.host_api.service_delete, self.ctxt, 1) self.assertFalse(service1.destroy.called) self.assertFalse(service2.destroy.called) self.assertFalse(set_target.called)
def _create_cell_mappings(self): cell0_uuid = objects.CellMapping.CELL0_UUID self.mapping0 = objects.CellMapping(context=self.context, uuid=cell0_uuid, database_connection='cell0', transport_url='none:///') self.mapping1 = objects.CellMapping(context=self.context, uuid=uuidutils.generate_uuid(), database_connection='cell1', transport_url='none:///') self.mapping2 = objects.CellMapping(context=self.context, uuid=uuidutils.generate_uuid(), database_connection='cell2', transport_url='none:///') self.mapping0.create() self.mapping1.create() self.mapping2.create()
def test_target_cell(self, mock_create_ctxt_mgr): mock_create_ctxt_mgr.return_value = mock.sentinel.cm ctxt = context.RequestContext('111', '222', roles=['admin', 'weasel']) # Verify the existing db_connection, if any, is restored ctxt.db_connection = mock.sentinel.db_conn mapping = objects.CellMapping(database_connection='fake://') with context.target_cell(ctxt, mapping): self.assertEqual(ctxt.db_connection, mock.sentinel.cm) self.assertEqual(mock.sentinel.db_conn, ctxt.db_connection)
def test_upgrade_with_no_host_mappings(self): self._flavor_me() cell0 = objects.CellMapping(context=self.context, uuid=objects.CellMapping.CELL0_UUID, name='cell0', transport_url='fake', database_connection='fake') cell0.create() cell1 = objects.CellMapping(context=self.context, uuid=uuidsentinel.cell1, name='cell1', transport_url='fake', database_connection='fake') cell1.create() with mock.patch.object(self.migration, 'LOG') as log: self.migration.upgrade(self.engine) self.assertTrue(log.warning.called)