예제 #1
0
 def _get_from_db_by_instance(context, instance_uuid):
     grp_member = context.session.query(api_models.InstanceGroupMember).\
                  filter_by(instance_uuid=instance_uuid).first()
     if not grp_member:
         raise exception.InstanceGroupNotFound(group_uuid='')
     grp = InstanceGroup._get_from_db_by_id(context, grp_member.group_id)
     return grp
예제 #2
0
 def _get_from_db_by_id(context, id):
     grp = _instance_group_get_query(context,
                                     id_field=api_models.InstanceGroup.id,
                                     id=id).first()
     if not grp:
         raise exception.InstanceGroupNotFound(group_uuid=id)
     return grp
예제 #3
0
    def _save_in_db(context, group_uuid, values):
        grp = _instance_group_get_query(context,
                                        id_field=api_models.InstanceGroup.uuid,
                                        id=group_uuid).first()
        if not grp:
            raise exception.InstanceGroupNotFound(group_uuid=group_uuid)

        values_copy = copy.copy(values)
        policies = values_copy.pop('policies', None)
        members = values_copy.pop('members', None)
        # WRS extension -- metadata
        metadata = values_copy.pop('metadata', None)

        grp.update(values_copy)

        if policies is not None:
            _instance_group_policies_add(context, grp, policies)
        if members is not None:
            _instance_group_members_add(context, grp, members)
        # WRS extension -- metadata
        if metadata is not None:
            _instance_group_metadata_add(context, grp, metadata,
                                         update_group=True)

        return grp
예제 #4
0
 def test_get_by_instance_uuid_main(self, mock_api_get, mock_db_get):
     error = exception.InstanceGroupNotFound(group_uuid='')
     mock_api_get.side_effect = error
     objects.InstanceGroup.get_by_instance_uuid(self.context,
                                                mock.sentinel.instance_uuid)
     mock_db_get.assert_called_once_with(self.context,
                                         mock.sentinel.instance_uuid)
예제 #5
0
 def test_get_by_name(self, mock_api_get):
     db_group = copy.deepcopy(_INST_GROUP_DB)
     mock_api_get.side_effect = [
         db_group, exception.InstanceGroupNotFound(group_uuid='unknown')]
     ig = objects.InstanceGroup.get_by_name(self.context, 'fake_name')
     mock_api_get.assert_called_once_with(self.context, 'fake_name')
     self.assertEqual('fake_name', ig.name)
     self.assertRaises(exception.InstanceGroupNotFound,
                       objects.InstanceGroup.get_by_name,
                       self.context, 'unknown')
 def get_by_name(cls, context, name):
     try:
         db_group = cls._get_from_db_by_name(context, name)
     except exception.InstanceGroupNotFound:
         igs = InstanceGroupList._get_main_by_project_id(
             context, context.project_id)
         for ig in igs:
             if ig.name == name:
                 return ig
         raise exception.InstanceGroupNotFound(group_uuid=name)
     return cls._from_db_object(context, cls(), db_group)
예제 #7
0
    def get_by_name(cls, context, name):
        # TODO(russellb) We need to get the group by name here.  There's no
        # db.api method for this yet.  Come back and optimize this by
        # adding a new query by name.  This is unnecessarily expensive if a
        # tenant has lots of groups.
        igs = InstanceGroupList.get_by_project_id(context, context.project_id)
        for ig in igs:
            if ig.name == name:
                return ig

        raise exception.InstanceGroupNotFound(group_uuid=name)
예제 #8
0
def _instance_group_members_add_by_uuid(context, group_uuid, members):
    # NOTE(melwitt): The condition on the join limits the number of members
    # returned to only those we wish to check as already existing.
    group = context.session.query(api_models.InstanceGroup).\
            outerjoin(api_models.InstanceGroupMember,
            api_models.InstanceGroupMember.instance_uuid.in_(set(members))).\
            filter(api_models.InstanceGroup.uuid == group_uuid).\
            options(contains_eager('_members')).first()
    if not group:
        raise exception.InstanceGroupNotFound(group_uuid=group_uuid)
    return _instance_group_model_add(context, api_models.InstanceGroupMember,
                                     members, group._members, 'instance_uuid',
                                     group.id)
예제 #9
0
 def test_get_by_name_main(self, mock_api_get, mock_db_get):
     error = exception.InstanceGroupNotFound(group_uuid='f1')
     mock_api_get.side_effect = error
     mock_db_get.side_effect = _mock_db_list_get
     # Need the project_id value set, otherwise we'd use mock.sentinel
     mock_ctx = mock.MagicMock()
     mock_ctx.project_id = 'fake_project'
     ig = objects.InstanceGroup.get_by_name(mock_ctx, 'f1')
     mock_db_get.assert_called_once_with(mock_ctx, 'fake_project')
     self.assertEqual('f1', ig.name)
     self.assertRaises(exception.InstanceGroupNotFound,
                       objects.InstanceGroup.get_by_name, mock_ctx,
                       'unknown')
예제 #10
0
    def _destroy_in_db(context, group_uuid):
        qry = _instance_group_get_query(context,
                                        id_field=api_models.InstanceGroup.uuid,
                                        id=group_uuid)
        if qry.count() == 0:
            raise exception.InstanceGroupNotFound(group_uuid=group_uuid)

        # Delete policies and members
        group_id = qry.first().id
        instance_models = [api_models.InstanceGroupPolicy,
                           api_models.InstanceGroupMember]
        for model in instance_models:
            context.session.query(model).filter_by(group_id=group_id).delete()

        qry.delete()
예제 #11
0
 def _get_from_db_by_name(context, name):
     grp = _instance_group_get_query(context).filter_by(name=name).first()
     if not grp:
         raise exception.InstanceGroupNotFound(group_uuid=name)
     return grp
예제 #12
0
class _TestInstanceGroupObject(object):
    @mock.patch('nova.db.instance_group_get', return_value=_INST_GROUP_DB)
    @mock.patch(
        'nova.objects.InstanceGroup._get_from_db_by_uuid',
        side_effect=exception.InstanceGroupNotFound(group_uuid=_DB_UUID))
    def test_get_by_uuid_main(self, mock_api_get, mock_db_get):
        obj = objects.InstanceGroup.get_by_uuid(self.context, _DB_UUID)
        mock_db_get.assert_called_once_with(self.context, _DB_UUID)
        self.assertEqual(_INST_GROUP_DB['members'], obj.members)
        self.assertEqual(_INST_GROUP_DB['policies'], obj.policies)
        self.assertEqual(_DB_UUID, obj.uuid)
        self.assertEqual(_INST_GROUP_DB['project_id'], obj.project_id)
        self.assertEqual(_INST_GROUP_DB['user_id'], obj.user_id)
        self.assertEqual(_INST_GROUP_DB['name'], obj.name)

    @mock.patch('nova.db.instance_group_get_by_instance',
                return_value=_INST_GROUP_DB)
    @mock.patch('nova.objects.InstanceGroup._get_from_db_by_instance')
    def test_get_by_instance_uuid_main(self, mock_api_get, mock_db_get):
        error = exception.InstanceGroupNotFound(group_uuid='')
        mock_api_get.side_effect = error
        objects.InstanceGroup.get_by_instance_uuid(self.context,
                                                   mock.sentinel.instance_uuid)
        mock_db_get.assert_called_once_with(self.context,
                                            mock.sentinel.instance_uuid)

    @mock.patch('nova.db.instance_group_get')
    def test_refresh(self, mock_db_get):
        changed_group = copy.deepcopy(_INST_GROUP_DB)
        changed_group['name'] = 'new_name'
        mock_db_get.side_effect = [_INST_GROUP_DB, changed_group]
        obj = objects.InstanceGroup.get_by_uuid(self.context, _DB_UUID)
        self.assertEqual(_INST_GROUP_DB['name'], obj.name)
        obj.refresh()
        self.assertEqual('new_name', obj.name)
        self.assertEqual(set([]), obj.obj_what_changed())

    @mock.patch('nova.compute.utils.notify_about_server_group_update')
    @mock.patch('nova.db.instance_group_update')
    @mock.patch('nova.db.instance_group_get')
    def test_save_main(self, mock_db_get, mock_db_update, mock_notify):
        changed_group = copy.deepcopy(_INST_GROUP_DB)
        changed_group['name'] = 'new_name'
        mock_db_get.side_effect = [_INST_GROUP_DB, changed_group]
        obj = objects.InstanceGroup.get_by_uuid(self.context, _DB_UUID)
        self.assertEqual(obj.name, 'fake_name')
        obj.name = 'new_name'
        obj.policies = ['policy1']  # Remove policy 2
        obj.members = ['instance_id1']  # Remove member 2
        obj.save()
        mock_db_update.assert_called_once_with(
            self.context, _DB_UUID, {
                'name': 'new_name',
                'members': ['instance_id1'],
                'policies': ['policy1']
            })
        mock_notify.assert_called_once_with(
            self.context, "update", {
                'name': 'new_name',
                'members': ['instance_id1'],
                'policies': ['policy1'],
                'server_group_id': _DB_UUID
            })

    @mock.patch('nova.compute.utils.notify_about_server_group_update')
    @mock.patch('nova.db.instance_group_update')
    @mock.patch('nova.db.instance_group_get')
    def test_save_without_hosts_main(self, mock_db_get, mock_db_update,
                                     mock_notify):
        mock_db_get.side_effect = [_INST_GROUP_DB, _INST_GROUP_DB]
        obj = objects.InstanceGroup.get_by_uuid(self.context, _DB_UUID)
        obj.hosts = ['fake-host1']
        self.assertRaises(exception.InstanceGroupSaveException, obj.save)
        # make sure that we can save by removing hosts from what is updated
        obj.obj_reset_changes(['hosts'])
        obj.save()
        # since hosts was the only update, there is no actual call
        self.assertFalse(mock_db_update.called)
        self.assertFalse(mock_notify.called)

    @mock.patch('nova.compute.utils.notify_about_server_group_action')
    @mock.patch('nova.compute.utils.notify_about_server_group_update')
    @mock.patch('nova.objects.InstanceGroup._create_in_db',
                return_value=_INST_GROUP_DB)
    def test_create(self, mock_db_create, mock_notify, mock_notify_action):
        obj = objects.InstanceGroup(context=self.context)
        obj.uuid = _DB_UUID
        obj.name = _INST_GROUP_DB['name']
        obj.user_id = _INST_GROUP_DB['user_id']
        obj.project_id = _INST_GROUP_DB['project_id']
        obj.members = _INST_GROUP_DB['members']
        obj.policies = _INST_GROUP_DB['policies']
        obj.updated_at = _TS_NOW
        obj.created_at = _TS_NOW
        obj.deleted_at = None
        obj.deleted = False
        obj.create()
        mock_db_create.assert_called_once_with(
            self.context, {
                'uuid': _DB_UUID,
                'name': _INST_GROUP_DB['name'],
                'user_id': _INST_GROUP_DB['user_id'],
                'project_id': _INST_GROUP_DB['project_id'],
                'created_at': _TS_NOW,
                'updated_at': _TS_NOW,
                'deleted_at': None,
                'deleted': False,
            },
            members=_INST_GROUP_DB['members'],
            policies=_INST_GROUP_DB['policies'])
        mock_notify.assert_called_once_with(
            self.context, "create", {
                'uuid': _DB_UUID,
                'name': _INST_GROUP_DB['name'],
                'user_id': _INST_GROUP_DB['user_id'],
                'project_id': _INST_GROUP_DB['project_id'],
                'created_at': _TS_NOW,
                'updated_at': _TS_NOW,
                'deleted_at': None,
                'deleted': False,
                'members': _INST_GROUP_DB['members'],
                'policies': _INST_GROUP_DB['policies'],
                'server_group_id': _DB_UUID
            })

        def _group_matcher(group):
            """Custom mock call matcher method."""
            return (group.uuid == _DB_UUID
                    and group.name == _INST_GROUP_DB['name']
                    and group.user_id == _INST_GROUP_DB['user_id']
                    and group.project_id == _INST_GROUP_DB['project_id']
                    and group.created_at == _TS_NOW
                    and group.updated_at == _TS_NOW
                    and group.deleted_at is None and group.deleted is False
                    and group.members == _INST_GROUP_DB['members']
                    and group.policies == _INST_GROUP_DB['policies']
                    and group.id == 1)

        group_matcher = test_utils.CustomMockCallMatcher(_group_matcher)

        self.assertRaises(exception.ObjectActionError, obj.create)
        mock_notify_action.assert_called_once_with(context=self.context,
                                                   group=group_matcher,
                                                   action='create')

    @mock.patch('nova.compute.utils.notify_about_server_group_action')
    @mock.patch('nova.compute.utils.notify_about_server_group_update')
    @mock.patch('nova.objects.InstanceGroup._destroy_in_db')
    def test_destroy(self, mock_db_delete, mock_notify, mock_notify_action):
        obj = objects.InstanceGroup(context=self.context)
        obj.uuid = _DB_UUID
        obj.destroy()

        group_matcher = test_utils.CustomMockCallMatcher(
            lambda group: group.uuid == _DB_UUID)

        mock_notify_action.assert_called_once_with(context=obj._context,
                                                   group=group_matcher,
                                                   action='delete')
        mock_db_delete.assert_called_once_with(self.context, _DB_UUID)
        mock_notify.assert_called_once_with(self.context, "delete",
                                            {'server_group_id': _DB_UUID})

    @mock.patch('nova.compute.utils.notify_about_server_group_update')
    @mock.patch('nova.objects.InstanceGroup._add_members_in_db')
    def test_add_members(self, mock_members_add_db, mock_notify):
        fake_member_models = [{'instance_uuid': mock.sentinel.uuid}]
        fake_member_uuids = [mock.sentinel.uuid]
        mock_members_add_db.return_value = fake_member_models
        members = objects.InstanceGroup.add_members(self.context, _DB_UUID,
                                                    fake_member_uuids)
        self.assertEqual(fake_member_uuids, members)
        mock_members_add_db.assert_called_once_with(self.context, _DB_UUID,
                                                    fake_member_uuids)
        mock_notify.assert_called_once_with(self.context, "addmember", {
            'instance_uuids': fake_member_uuids,
            'server_group_id': _DB_UUID
        })

    @mock.patch('nova.objects.InstanceList.get_by_filters')
    @mock.patch('nova.objects.InstanceGroup._get_from_db_by_uuid',
                return_value=_INST_GROUP_DB)
    def test_count_members_by_user(self, mock_get_db, mock_il_get):
        mock_il_get.return_value = [mock.ANY]
        obj = objects.InstanceGroup.get_by_uuid(self.context, _DB_UUID)
        expected_filters = {
            'uuid': ['instance_id1', 'instance_id2'],
            'user_id': 'fake_user',
            'deleted': False
        }
        self.assertEqual(1, obj.count_members_by_user('fake_user'))
        mock_il_get.assert_called_once_with(self.context,
                                            filters=expected_filters)

    @mock.patch('nova.objects.InstanceList.get_by_filters')
    @mock.patch('nova.objects.InstanceGroup._get_from_db_by_uuid',
                return_value=_INST_GROUP_DB)
    def test_get_hosts(self, mock_get_db, mock_il_get):
        mock_il_get.return_value = [
            objects.Instance(host='host1'),
            objects.Instance(host='host2'),
            objects.Instance(host=None)
        ]
        obj = objects.InstanceGroup.get_by_uuid(self.context, _DB_UUID)
        hosts = obj.get_hosts()
        self.assertEqual(['instance_id1', 'instance_id2'], obj.members)
        expected_filters = {
            'uuid': ['instance_id1', 'instance_id2'],
            'deleted': False
        }
        mock_il_get.assert_called_once_with(self.context,
                                            filters=expected_filters)
        self.assertEqual(2, len(hosts))
        self.assertIn('host1', hosts)
        self.assertIn('host2', hosts)

        # Test manual exclusion
        mock_il_get.reset_mock()
        hosts = obj.get_hosts(exclude=['instance_id1'])
        expected_filters = {'uuid': set(['instance_id2']), 'deleted': False}
        mock_il_get.assert_called_once_with(self.context,
                                            filters=expected_filters)

    def test_obj_make_compatible(self):
        obj = objects.InstanceGroup(self.context, **_INST_GROUP_DB)
        obj_primitive = obj.obj_to_primitive()
        self.assertNotIn('metadetails', obj_primitive)
        obj.obj_make_compatible(obj_primitive, '1.6')
        self.assertEqual({}, obj_primitive['metadetails'])

    @mock.patch.object(objects.InstanceList, 'get_by_filters')
    def test_load_hosts(self, mock_get_by_filt):
        mock_get_by_filt.return_value = [
            objects.Instance(host='host1'),
            objects.Instance(host='host2')
        ]

        obj = objects.InstanceGroup(self.context,
                                    members=['uuid1'],
                                    uuid=uuids.group)
        self.assertEqual(2, len(obj.hosts))
        self.assertIn('host1', obj.hosts)
        self.assertIn('host2', obj.hosts)
        self.assertNotIn('hosts', obj.obj_what_changed())

    def test_load_anything_else_but_hosts(self):
        obj = objects.InstanceGroup(self.context)
        self.assertRaises(exception.ObjectActionError, getattr, obj, 'members')
예제 #13
0
class _TestInstanceGroupObject(object):

    @mock.patch('nova.db.instance_group_get', return_value=_INST_GROUP_DB)
    @mock.patch('nova.objects.InstanceGroup._get_from_db_by_uuid',
            side_effect=exception.InstanceGroupNotFound(group_uuid=_DB_UUID))
    def test_get_by_uuid_main(self, mock_api_get, mock_db_get):
        obj = objects.InstanceGroup.get_by_uuid(self.context,
                                                       _DB_UUID)
        mock_db_get.assert_called_once_with(self.context, _DB_UUID)
        self.assertEqual(_INST_GROUP_DB['members'], obj.members)
        self.assertEqual(_INST_GROUP_DB['metadetails'], obj.metadetails)
        self.assertEqual(_INST_GROUP_DB['policies'], obj.policies)
        self.assertEqual(_DB_UUID, obj.uuid)
        self.assertEqual(_INST_GROUP_DB['project_id'], obj.project_id)
        self.assertEqual(_INST_GROUP_DB['user_id'], obj.user_id)
        self.assertEqual(_INST_GROUP_DB['name'], obj.name)

    @mock.patch('nova.db.instance_group_get_by_instance',
                return_value=_INST_GROUP_DB)
    @mock.patch('nova.objects.InstanceGroup._get_from_db_by_instance')
    def test_get_by_instance_uuid_main(self, mock_api_get, mock_db_get):
        error = exception.InstanceGroupNotFound(group_uuid='')
        mock_api_get.side_effect = error
        objects.InstanceGroup.get_by_instance_uuid(
                self.context, mock.sentinel.instance_uuid)
        mock_db_get.assert_called_once_with(
                self.context, mock.sentinel.instance_uuid)

    @mock.patch('nova.db.instance_group_get')
    def test_refresh(self, mock_db_get):
        changed_group = copy.deepcopy(_INST_GROUP_DB)
        changed_group['name'] = 'new_name'
        mock_db_get.side_effect = [_INST_GROUP_DB, changed_group]
        obj = objects.InstanceGroup.get_by_uuid(self.context,
                                                       _DB_UUID)
        self.assertEqual(_INST_GROUP_DB['name'], obj.name)
        obj.refresh()
        self.assertEqual('new_name', obj.name)
        self.assertEqual(set([]), obj.obj_what_changed())

    @mock.patch('nova.compute.utils.notify_about_server_group_update')
    @mock.patch('nova.db.instance_group_update')
    @mock.patch('nova.db.instance_group_get')
    def test_save_main(self, mock_db_get, mock_db_update, mock_notify):
        changed_group = copy.deepcopy(_INST_GROUP_DB)
        changed_group['name'] = 'new_name'
        mock_db_get.side_effect = [_INST_GROUP_DB, changed_group]
        obj = objects.InstanceGroup.get_by_uuid(self.context,
                                                       _DB_UUID)
        self.assertEqual(obj.name, 'fake_name')
        obj.name = 'new_name'
        obj.policies = ['policy1']  # Remove policy 2
        obj.members = ['instance_id1']  # Remove member 2
        obj.save()
        mock_db_update.assert_called_once_with(self.context, _DB_UUID,
                                               {'name': 'new_name',
                                                'members': ['instance_id1'],
                                                'policies': ['policy1']})
        mock_notify.assert_called_once_with(self.context, "update",
                                               {'name': 'new_name',
                                                'members': ['instance_id1'],
                                                'policies': ['policy1'],
                                                'server_group_id': _DB_UUID})

    @mock.patch('nova.compute.utils.notify_about_server_group_update')
    @mock.patch('nova.db.instance_group_update')
    @mock.patch('nova.db.instance_group_get')
    def test_save_without_hosts_main(self, mock_db_get, mock_db_update,
                                     mock_notify):
        mock_db_get.side_effect = [_INST_GROUP_DB, _INST_GROUP_DB]
        obj = objects.InstanceGroup.get_by_uuid(self.context, _DB_UUID)
        obj.hosts = ['fake-host1']
        self.assertRaises(exception.InstanceGroupSaveException,
                          obj.save)
        # make sure that we can save by removing hosts from what is updated
        obj.obj_reset_changes(['hosts'])
        obj.save()
        # since hosts was the only update, there is no actual call
        self.assertFalse(mock_db_update.called)
        self.assertFalse(mock_notify.called)

    @mock.patch('nova.compute.utils.notify_about_server_group_update')
    @mock.patch('nova.objects.InstanceGroup._create_in_db',
                return_value=_INST_GROUP_DB)
    def test_create(self, mock_db_create, mock_notify):
        obj = objects.InstanceGroup(context=self.context)
        obj.uuid = _DB_UUID
        obj.name = _INST_GROUP_DB['name']
        obj.user_id = _INST_GROUP_DB['user_id']
        obj.project_id = _INST_GROUP_DB['project_id']
        obj.members = _INST_GROUP_DB['members']
        obj.metadetails = _INST_GROUP_DB['metadetails']
        obj.policies = _INST_GROUP_DB['policies']
        obj.updated_at = _TS_NOW
        obj.created_at = _TS_NOW
        obj.deleted_at = None
        obj.deleted = False
        obj.create()
        mock_db_create.assert_called_once_with(
            self.context,
            {'uuid': _DB_UUID,
             'name': _INST_GROUP_DB['name'],
             'user_id': _INST_GROUP_DB['user_id'],
             'project_id': _INST_GROUP_DB['project_id'],
             'created_at': _TS_NOW,
             'updated_at': _TS_NOW,
             'deleted_at': None,
             'deleted': False,
             },
            members=_INST_GROUP_DB['members'],
            metadata=_INST_GROUP_DB['metadetails'],
            policies=_INST_GROUP_DB['policies'])
        mock_notify.assert_called_once_with(
            self.context, "create",
            {'uuid': _DB_UUID,
             'name': _INST_GROUP_DB['name'],
             'user_id': _INST_GROUP_DB['user_id'],
             'project_id': _INST_GROUP_DB['project_id'],
             'created_at': _TS_NOW,
             'updated_at': _TS_NOW,
             'deleted_at': None,
             'deleted': False,
             'members': _INST_GROUP_DB['members'],
             'metadetails': _INST_GROUP_DB['metadetails'],
             'policies': _INST_GROUP_DB['policies'],
             'server_group_id': _DB_UUID})

        self.assertRaises(exception.ObjectActionError, obj.create)

    @mock.patch('nova.compute.utils.notify_about_server_group_update')
    @mock.patch('nova.objects.InstanceGroup._destroy_in_db')
    def test_destroy(self, mock_db_delete, mock_notify):
        obj = objects.InstanceGroup(context=self.context)
        obj.uuid = _DB_UUID
        obj.destroy()
        mock_db_delete.assert_called_once_with(self.context, _DB_UUID)
        mock_notify.assert_called_once_with(self.context, "delete",
                                            {'server_group_id': _DB_UUID})

    @mock.patch('nova.compute.utils.notify_about_server_group_update')
    @mock.patch('nova.objects.InstanceGroup._add_members_in_db')
    def test_add_members(self, mock_members_add_db, mock_notify):
        fake_member_models = [{'instance_uuid': mock.sentinel.uuid}]
        fake_member_uuids = [mock.sentinel.uuid]
        mock_members_add_db.return_value = fake_member_models
        members = objects.InstanceGroup.add_members(self.context,
                                                    _DB_UUID,
                                                    fake_member_uuids)
        self.assertEqual(fake_member_uuids, members)
        mock_members_add_db.assert_called_once_with(
                self.context,
                _DB_UUID,
                fake_member_uuids)
        mock_notify.assert_called_once_with(
                self.context, "addmember",
                {'instance_uuids': fake_member_uuids,
                 'server_group_id': _DB_UUID})

    @mock.patch('nova.objects.InstanceList.get_by_filters')
    @mock.patch('nova.objects.InstanceGroup._get_from_db_by_uuid',
                return_value=_INST_GROUP_DB)
    def test_count_members_by_user(self, mock_get_db, mock_il_get):
        mock_il_get.return_value = [mock.ANY]
        obj = objects.InstanceGroup.get_by_uuid(self.context, _DB_UUID)
        expected_filters = {
            'uuid': ['instance_id1', 'instance_id2'],
            'user_id': 'fake_user',
            'deleted': False
        }
        self.assertEqual(1, obj.count_members_by_user('fake_user'))
        mock_il_get.assert_called_once_with(self.context,
                                            filters=expected_filters)

    @mock.patch('nova.objects.InstanceList.get_by_filters')
    @mock.patch('nova.objects.InstanceGroup._get_from_db_by_uuid',
                return_value=_INST_GROUP_DB)
    def test_get_hosts(self, mock_get_db, mock_il_get):
        mock_il_get.return_value = [objects.Instance(host='host1'),
                                    objects.Instance(host='host2'),
                                    objects.Instance(host=None)]
        obj = objects.InstanceGroup.get_by_uuid(self.context, _DB_UUID)
        hosts = obj.get_hosts()
        self.assertEqual(['instance_id1', 'instance_id2'], obj.members)
        expected_filters = {
            'uuid': ['instance_id1', 'instance_id2'],
            'deleted': False
        }
        mock_il_get.assert_called_once_with(self.context,
                                            filters=expected_filters)
        self.assertEqual(2, len(hosts))
        self.assertIn('host1', hosts)
        self.assertIn('host2', hosts)

        # Test manual exclusion
        mock_il_get.reset_mock()
        hosts = obj.get_hosts(exclude=['instance_id1'])
        expected_filters = {
            'uuid': set(['instance_id2']),
            'deleted': False
        }
        mock_il_get.assert_called_once_with(self.context,
                                            filters=expected_filters)

    def test_obj_make_compatible(self):
        obj = objects.InstanceGroup(self.context, **_INST_GROUP_DB)
        obj_primitive = obj.obj_to_primitive()
        self.assertNotIn('metadetails', obj_primitive)
        obj.obj_make_compatible(obj_primitive, '1.6')
        self.assertEqual({}, obj_primitive['metadetails'])

    @mock.patch.object(objects.InstanceList, 'get_by_filters')
    def test_load_hosts(self, mock_get_by_filt):
        mock_get_by_filt.return_value = [objects.Instance(host='host1'),
                                         objects.Instance(host='host2')]

        obj = objects.InstanceGroup(self.context, members=['uuid1'])
        self.assertEqual(2, len(obj.hosts))
        self.assertIn('host1', obj.hosts)
        self.assertIn('host2', obj.hosts)
        self.assertNotIn('hosts', obj.obj_what_changed())

    def test_load_anything_else_but_hosts(self):
        obj = objects.InstanceGroup(self.context)
        self.assertRaises(exception.ObjectActionError, getattr, obj, 'members')

    # WRS: add testcase for get_older members
    @mock.patch.object(objects.InstanceList, 'get_by_filters')
    def test_get_older_member_hosts(self, mock_get_by_filt):
        mock_get_by_filt.return_value = [
            objects.Instance(id=1, uuid='uuid1', host='host1',
                             vm_state=vm_states.BUILDING, task_state=None),
            objects.Instance(id=2, uuid='uuid2', host='host2',
                             vm_state=vm_states.BUILDING, task_state=None),
            objects.Instance(id=3, uuid='uuid3', host='host2',
                             vm_state=vm_states.BUILDING, task_state=None)]

        obj = objects.InstanceGroup(mock.sentinel.ctx,
                                    members=['uuid1', 'uuid2', 'uuid3'])

        hosts = obj.get_older_member_hosts('uuid1')
        self.assertEqual(0, len(hosts))
        hosts = obj.get_older_member_hosts('uuid2')
        self.assertEqual(1, len(hosts))
        self.assertIn('host1', hosts)
        hosts = obj.get_older_member_hosts('uuid3')
        self.assertEqual(2, len(hosts))
        self.assertIn('host1', hosts)
        self.assertIn('host2', hosts)

    @mock.patch.object(objects.InstanceList, 'get_by_filters')
    def test_get_older_member_hosts_with_some_none(self, mock_get_by_filt):
        mock_get_by_filt.return_value = [
            objects.Instance(id=1, uuid='uuid1', host=None,
                             vm_state=vm_states.BUILDING, task_state=None),
            objects.Instance(id=2, uuid='uuid2', host='host2',
                             vm_state=vm_states.BUILDING, task_state=None),
            objects.Instance(id=3, uuid='uuid3', host='host3',
                             vm_state=vm_states.BUILDING, task_state=None)]

        obj = objects.InstanceGroup(mock.sentinel.ctx,
                                    members=['uuid1', 'uuid2', 'uuid3'])

        hosts = obj.get_older_member_hosts('uuid1')
        self.assertEqual(0, len(hosts))
        hosts = obj.get_older_member_hosts('uuid2')
        self.assertEqual(0, len(hosts))
        hosts = obj.get_older_member_hosts('uuid3')
        self.assertEqual(1, len(hosts))
        self.assertIn('host2', hosts)

    @mock.patch.object(objects.InstanceList, 'get_by_filters')
    def test_get_older_member_hosts_inverted_id(self, mock_get_by_filt):
        mock_get_by_filt.return_value = [
            objects.Instance(id=1, uuid='uuid1', host='host1',
                             vm_state=vm_states.BUILDING, task_state=None),
            objects.Instance(id=2, uuid='uuid2', host='host2',
                             vm_state=vm_states.BUILDING, task_state=None),
            # setting task_state to spawning will force execution
            # of code that adds host for more recent id=3,
            objects.Instance(id=3, uuid='uuid3', host='host2',
                             vm_state=vm_states.BUILDING,
                             task_state=task_states.SPAWNING)]

        obj = objects.InstanceGroup(mock.sentinel.ctx,
                                    members=['uuid1', 'uuid2', 'uuid3'])

        hosts = obj.get_older_member_hosts('uuid1')
        self.assertEqual(1, len(hosts))
        self.assertIn('host2', hosts)
        hosts = obj.get_older_member_hosts('uuid2')
        self.assertEqual(2, len(hosts))
        self.assertIn('host1', hosts)
        self.assertIn('host2', hosts)
        hosts = obj.get_older_member_hosts('uuid3')
        self.assertEqual(2, len(hosts))
        self.assertIn('host1', hosts)
        self.assertIn('host2', hosts)