def test_image_member_list(self):
        with mock.patch('glanceclient.v2.image_members.Controller.list',
                        return_value=self.members_image_members):
            serialized = self.plugin.serialize(self.members_image)

        # Admin context
        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT1, '/v1/search', is_admin=True
        )
        result_hit = {'_source': copy.deepcopy(serialized)}

        # Expect to see all three tenants
        self.plugin.filter_result(result_hit, fake_request.context)
        self.assertEqual(set([TENANT1, TENANT2, TENANT3]),
                         set(result_hit['_source']['members']))

        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT1, '/v1/search', is_admin=False
        )
        result_hit = {'_source': copy.deepcopy(serialized)}

        # Tenant1 can see the image but doesn't own it
        self.plugin.filter_result(result_hit, fake_request.context)
        self.assertEqual(set([TENANT1]),
                         set(result_hit['_source']['members']))

        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT2, '/v1/search', is_admin=False
        )
        result_hit = {'_source': copy.deepcopy(serialized)}

        # Tenant2 owns the image and should see all three members
        self.plugin.filter_result(result_hit, fake_request.context)
        self.assertEqual(set([TENANT1, TENANT2, TENANT3]),
                         set(result_hit['_source']['members']))
    def test_image_member_list(self):
        with mock.patch('glanceclient.v2.image_members.Controller.list',
                        return_value=self.members_image_members):
            serialized = self.plugin.serialize(self.members_image)

        # Admin context
        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT1, '/v1/search', is_admin=True
        )
        result_hit = {'_source': copy.deepcopy(serialized)}

        # Expect to see all three tenants
        self.plugin.filter_result(result_hit, fake_request.context)
        self.assertEqual(set([TENANT1, TENANT2, TENANT3]),
                         set(result_hit['_source']['members']))

        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT1, '/v1/search', is_admin=False
        )
        result_hit = {'_source': copy.deepcopy(serialized)}

        # Tenant1 can see the image but doesn't own it
        self.plugin.filter_result(result_hit, fake_request.context)
        self.assertEqual(set([TENANT1]),
                         set(result_hit['_source']['members']))

        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT2, '/v1/search', is_admin=False
        )
        result_hit = {'_source': copy.deepcopy(serialized)}

        # Tenant2 owns the image and should see all three members
        self.plugin.filter_result(result_hit, fake_request.context)
        self.assertEqual(set([TENANT1, TENANT2, TENANT3]),
                         set(result_hit['_source']['members']))
    def test_facets_all_projects(self):
        # For non admins, all_projects should have no effect
        mock_engine = mock.Mock()
        self.plugin.engine = mock_engine

        # Don't really care about the return values
        mock_engine.search.return_value = {'aggregations': {}}

        fake_request = unit_test_utils.get_fake_request(USER1,
                                                        TENANT1,
                                                        '/v1/search/facets',
                                                        is_admin=False)

        self.plugin.get_facets(fake_request.context, all_projects=True)

        expected_agg_query_filter = {
            'filtered': {
                'filter': {
                    'and': [{
                        'term': {
                            ROLE_USER_FIELD: 'user'
                        }
                    }, {
                        'term': {
                            'tenant_id': TENANT1
                        }
                    }]
                }
            }
        }

        # Call args are a tuple (name, posargs, kwargs)
        search_call = mock_engine.search.mock_calls[0]
        search_call_body = search_call[2]['body']
        self.assertEqual(set(['aggs', 'query']), set(search_call_body.keys()))

        # The aggregation query's tested elsewhere, just check the query filter
        self.assertEqual(expected_agg_query_filter, search_call_body['query'])

        # Admins can request all_projects
        fake_request = unit_test_utils.get_fake_request(USER1,
                                                        TENANT1,
                                                        '/v1/search/facets',
                                                        is_admin=True)

        self.plugin.get_facets(fake_request.context, all_projects=True)

        # Test the SECOND call to the mock
        search_call = mock_engine.search.mock_calls[1]
        search_call_body = search_call[2]['body']

        # We don't expect any filter query here, just the aggregations.
        self.assertEqual(set(['aggs', 'query']), set(search_call_body.keys()))
    def test_facets_all_projects(self):
        # For non admins, all_projects should have no effect
        mock_engine = mock.Mock()
        self.plugin.engine = mock_engine

        # Don't really care about the return values
        mock_engine.search.return_value = {
            'aggregations': {}
        }

        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT1, '/v1/search/facets', is_admin=False
        )

        self.plugin.get_facets(fake_request.context, all_projects=True)

        expected_agg_query_filter = {
            'filtered': {
                'filter': {
                    'and': [
                        {'term': {ROLE_USER_FIELD: 'user'}},
                        {'term': {'tenant_id': TENANT1}}
                    ]
                }
            }
        }

        # Call args are a tuple (name, posargs, kwargs)
        search_call = mock_engine.search.mock_calls[0]
        search_call_body = search_call[2]['body']
        self.assertEqual(set(['aggs', 'query']), set(search_call_body.keys()))

        # The aggregation query's tested elsewhere, just check the query filter
        self.assertEqual(expected_agg_query_filter, search_call_body['query'])

        # Admins can request all_projects
        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT1, '/v1/search/facets', is_admin=True
        )

        self.plugin.get_facets(fake_request.context, all_projects=True)

        # Test the SECOND call to the mock
        search_call = mock_engine.search.mock_calls[1]
        search_call_body = search_call[2]['body']

        # We don't expect any filter query here, just the aggregations.
        self.assertEqual(set(['aggs', 'query']), set(search_call_body.keys()))
    def test_protected_properties(self):
        with mock.patch(nova_server_getter, return_value=self.instance1):
            serialized = self.plugin.serialize(self.instance1.id)

        elasticsearch_results = {
            "hits": {
                "hits": [
                    {
                        "_source": copy.deepcopy(serialized),
                        "_type": self.plugin.get_document_type(),
                        "_index": self.plugin.get_index_name(),
                    }
                ]
            }
        }

        protected_fields = (u"OS-EXT-SRV-ATTR:host", u"OS-EXT-SRV-ATTR:hypervisor_hostname")

        fake_request = unit_test_utils.get_fake_request(USER1, TENANT1, "/v1/search", is_admin=True)
        self.plugin.filter_result(elasticsearch_results["hits"]["hits"][0], fake_request.context)

        # Result should contain all the fields
        single_result = elasticsearch_results["hits"]["hits"][0]["_source"]
        self.assertEqual(serialized, single_result)
        for field in protected_fields:
            self.assertTrue(field in single_result)

        # Refresh the mock results since they can be modified in-place
        elasticsearch_results = {
            "hits": {
                "hits": [
                    {
                        "_source": copy.deepcopy(serialized),
                        "_type": self.plugin.get_document_type(),
                        "_index": self.plugin.get_index_name(),
                    }
                ]
            }
        }
        # Make the same request as a non-admin
        fake_request = unit_test_utils.get_fake_request(USER1, TENANT1, "/v1/search", is_admin=False)

        self.plugin.filter_result(elasticsearch_results["hits"]["hits"][0], fake_request.context)

        single_result = elasticsearch_results["hits"]["hits"][0]["_source"]

        for field in protected_fields:
            self.assertFalse(field in single_result)
Пример #6
0
    def test_facets(self):
        request = unit_test_utils.get_fake_request()
        doc_types = ["OS::Glance::Image", "OS::Nova::Server"]
        gf_path = 'searchlight.elasticsearch.plugins.base.IndexBase.get_facets'
        with mock.patch(gf_path) as mock_facets:
            mock_facets.return_value = [{"name": "fake", "type": "string"}], 0

            default_response = self.search_controller.facets(
                request, doc_type=doc_types)

            expected = {
                "OS::Nova::Server": {
                    "doc_count": 0,
                    "facets": [{"name": "fake", "type": "string"}]
                },
                "OS::Glance::Image": {
                    "doc_count": 0,
                    "facets": [{"name": "fake", "type": "string"}]
                }
            }
            self.assertEqual(expected, default_response)

            totals_only_response = self.search_controller.facets(
                request, doc_type=doc_types, include_fields=False)

            expected = {"OS::Nova::Server": {"doc_count": 0},
                        "OS::Glance::Image": {"doc_count": 0}}
            self.assertEqual(expected, totals_only_response)
Пример #7
0
    def test_policy_all_disallowed(self):
        request = unit_test_utils.get_fake_request(is_admin=False)
        search_deserializer = search.RequestDeserializer(
            utils.get_search_plugins(), policy_enforcer=self.enforcer)

        types = ['OS::Glance::Image']
        self.enforcer.add_rules(
            policy.policy.Rules.from_dict({
                'resource:OS::Glance::Image': '!',
                'resource:OS::Nova::Server': '!',
            }))

        expected_message = (
            "There are no resource types accessible to you to serve "
            "your request. You do not have access to the following "
            "resource types: OS::Glance::Image")
        self.assertRaisesRegex(webob.exc.HTTPForbidden, expected_message,
                               search_deserializer._filter_types_by_policy,
                               request.context, types)

        types = ['OS::Glance::Image', 'OS::Nova::Server']
        expected_message = (
            "There are no resource types accessible to you to serve "
            "your request. You do not have access to the following "
            "resource types: OS::Glance::Image, OS::Nova::Server")
        self.assertRaisesRegex(webob.exc.HTTPForbidden, expected_message,
                               search_deserializer._filter_types_by_policy,
                               request.context, types)
    def test_facets_no_mapping(self):
        mock_engine = mock.Mock()
        self.plugin.engine = mock_engine

        fake_request = unit_test_utils.get_fake_request(USER1,
                                                        TENANT1,
                                                        '/v1/search/facets',
                                                        is_admin=True)

        mock_engine.search.return_value = {
            'aggregations': {
                'status': {
                    'buckets': []
                },
                'image.id': {
                    'doc_count': 0
                }
            }
        }

        facets = self.plugin.get_facets(fake_request.context)

        status_facet = list(filter(lambda f: f['name'] == 'status', facets))[0]
        image_facet = list(filter(lambda f: f['name'] == 'image.id',
                                  facets))[0]
        expected_status = {'name': 'status', 'options': [], 'type': 'string'}
        expected_image = {
            'name': 'image.id',
            'options': [],
            'type': 'string',
            'resource_type': 'OS::Glance::Image'
        }

        self.assertEqual(expected_status, status_facet)
        self.assertEqual(expected_image, image_facet)
 def test_rbac_filter(self):
     fake_request = unit_test_utils.get_fake_request(USER1,
                                                     TENANT1,
                                                     '/v1/search',
                                                     is_admin=False)
     rbac_terms = self.plugin._get_rbac_field_filters(fake_request.context)
     self.assertEqual([{
         'bool': {
             'should': [{
                 'term': {
                     'tenant_id': TENANT1
                 }
             }, {
                 'terms': {
                     'members': [TENANT1, '*']
                 }
             }, {
                 'term': {
                     'router:external': True
                 }
             }, {
                 'term': {
                     'shared': True
                 }
             }]
         }
     }], rbac_terms)
    def test_facets(self):
        fake_request = unit_test_utils.get_fake_request(USER1, TENANT1, "/v1/search/facets", is_admin=False)

        mock_engine = mock.Mock()
        self.plugin.engine = mock_engine

        mock_engine.search.return_value = {
            "aggregations": {
                "status": {"buckets": [{"key": "pending", "doc_count": 2}]},
                "type": {"buckets": [{"key": "PRIMARY", "doc_count": 2}]},
            }
        }

        facets = self.plugin.get_facets(fake_request.context)

        status_facet = list(filter(lambda f: f["name"] == "status", facets))[0]
        expected_status = {"name": "status", "options": [{"key": "pending", "doc_count": 2}], "type": "string"}
        self.assertEqual(expected_status, status_facet)

        expected_agg_query = {
            "aggs": dict(unit_test_utils.simple_facet_field_agg(name) for name in ("status", "type")),
            "query": {"filtered": {"filter": {"and": [{"term": {"project_id": TENANT1}}]}}},
        }
        mock_engine.search.assert_called_with(
            index=self.plugin.get_index_name(),
            doc_type=self.plugin.get_document_type(),
            body=expected_agg_query,
            ignore_unavailable=True,
            search_type="count",
        )
Пример #11
0
    def test_policy_all_disallowed(self):
        request = unit_test_utils.get_fake_request(is_admin=False)
        search_deserializer = search.RequestDeserializer(
            utils.get_search_plugins(),
            policy_enforcer=self.enforcer)

        types = ['OS::Glance::Image']
        self.enforcer.add_rules(policy.policy.Rules.from_dict({
            'resource:OS::Glance::Image': '!',
            'resource:OS::Nova::Server': '!',
        }))

        expected_message = (
            "There are no resource types accessible to you to serve "
            "your request. You do not have access to the following "
            "resource types: OS::Glance::Image")
        self.assertRaisesRegex(
            webob.exc.HTTPForbidden, expected_message,
            search_deserializer._filter_types_by_policy,
            request.context, types)

        types = ['OS::Glance::Image', 'OS::Nova::Server']
        expected_message = (
            "There are no resource types accessible to you to serve "
            "your request. You do not have access to the following "
            "resource types: OS::Glance::Image, OS::Nova::Server")
        self.assertRaisesRegex(
            webob.exc.HTTPForbidden, expected_message,
            search_deserializer._filter_types_by_policy,
            request.context, types)
Пример #12
0
    def test_resource_policy_allows_admin(self):
        request = unit_test_utils.get_fake_request(is_admin=True)
        search_deserializer = search.RequestDeserializer(
            utils.get_search_plugins(),
            policy_enforcer=self.enforcer)
        types = ['OS::Glance::Image', 'OS::Nova::Server']

        self.enforcer.add_rules(policy.policy.Rules.from_dict({
            'resource:OS::Glance::Image:allow': 'role:admin',
            'resource:OS::Nova::Server:query': 'role:admin'
        }))

        request = unit_test_utils.get_fake_request(is_admin=True)
        filtered_types = search_deserializer._filter_types_by_policy(
            request.context, types, "query")
        self.assertEqual(types, filtered_types)
Пример #13
0
    def test_empty_request(self):
        """Tests that ALL registered resource types are searched"""
        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({}))

        output = self.deserializer.search(request)
        self.assertEqual(['searchlight-search'], output['index'])

        types = [
            'OS::Designate::RecordSet',
            'OS::Designate::Zone',
            'OS::Glance::Image',
            'OS::Glance::Metadef',
            'OS::Ironic::Chassis',
            'OS::Ironic::Node',
            'OS::Ironic::Port',
            'OS::Nova::Flavor',
            'OS::Nova::Server',
            'OS::Nova::ServerGroup',
            'OS::Nova::Hypervisor',
            'OS::Neutron::FloatingIP',
            'OS::Neutron::Net',
            'OS::Neutron::Port',
            'OS::Neutron::Subnet',
            'OS::Neutron::Router',
            'OS::Neutron::SecurityGroup',
            'OS::Cinder::Volume',
            'OS::Cinder::Snapshot'
        ]

        self.assertEqual(['searchlight-search'], output['index'])
        self.assertEqual(sorted(types), sorted(output['doc_type']))
Пример #14
0
    def test_filter_result(self):
        """Verify that any highlighted query results will filter out
           the ROLE_USER_FIELD field.
        """
        request = unit_test_utils.get_fake_request(is_admin=True)
        mock_engine = mock.Mock()
        simple_plugin = fake_plugins.FakeSimplePlugin(es_engine=mock_engine)

        # Verify with ROLE_USER_FIELD
        hit = {"_source": {"owner": "<em>admin</em>"},
               "highlight": {
                   "owner": "<em>admin</em>",
                   "__searchlight-user-role": "<em>admin</em>"}}

        simple_plugin.filter_result(hit, request.context)
        self.assertNotIn('__searchlight-user-role', hit['highlight'])

        # Verify without ROLE_USER_FIELD
        hit = {"_source": {"owner": "<em>admin</em>"},
               "highlight": {
                   "owner": "<em>admin</em>"}}

        original_hit = copy.deepcopy(hit)
        simple_plugin.filter_result(hit, request.context)
        self.assertEqual(original_hit, hit)
Пример #15
0
    def test_create_multiple(self):
        actions = [
            _image_fixture('create', '1'),
            _image_fixture('create', '2', data={'name': 'image-2'}),
        ]

        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'actions': actions,
        }))

        output = self.deserializer.index(request)
        expected = {
            'actions': [
                {
                    '_id': '1',
                    '_index': 'searchlight',
                    '_op_type': 'create',
                    '_source': {'disk_format': 'raw', 'name': 'image-1'},
                    '_type': 'OS::Glance::Image'
                },
                {
                    '_id': '2',
                    '_index': 'searchlight',
                    '_op_type': 'create',
                    '_source': {'disk_format': 'raw', 'name': 'image-2'},
                    '_type': 'OS::Glance::Image'
                },
            ],
            'default_index': None,
            'default_type': None
        }
        self.assertEqual(expected, output)
Пример #16
0
    def test_multiple_sort(self):
        """Test multiple sort fields"""
        request = unit_test_utils.get_fake_request()
        request.body = six.b(
            jsonutils.dumps({
                'query': {
                    'match_all': {}
                },
                'sort': [
                    'status', {
                        'created_at': 'desc'
                    }, {
                        'members': {
                            'order': 'asc',
                            'mode': 'max'
                        }
                    }
                ]
            }))

        output = self.deserializer.search(request)
        expected = [
            'status', {
                'created_at': 'desc'
            }, {
                'members': {
                    'order': 'asc',
                    'mode': 'max'
                }
            }
        ]
        self.assertEqual(expected, output['query']['sort'])
Пример #17
0
    def test_plugins_info_not_found(self):
        request = unit_test_utils.get_fake_request()
        repo = searchlight.elasticsearch.CatalogSearchRepo
        repo.plugins_info = mock.Mock(side_effect=exception.NotFound)

        self.assertRaises(webob.exc.HTTPNotFound,
                          self.search_controller.plugins_info, request)
Пример #18
0
    def test_plugins_info_internal_server_error(self):
        request = unit_test_utils.get_fake_request()
        repo = searchlight.elasticsearch.CatalogSearchRepo
        repo.plugins_info = mock.Mock(side_effect=Exception)

        self.assertRaises(webob.exc.HTTPInternalServerError,
                          self.search_controller.plugins_info, request)
Пример #19
0
    def test_global_aggregation_not_allowed(self):
        """The 'global' aggregation type bypasses the search query (thus
        bypassing RBAC). This is Bad, so we won't allow it. It can only occur
        as a top level aggregation.
        """
        request = unit_test_utils.get_fake_request()

        aggs = {
            'cheating_rbac': {
                'global': {},
                'aggregations': {
                    'name': {
                        'terms': {
                            'field': 'name'
                        }
                    }
                }
            }
        }
        request.body = six.b(
            jsonutils.dumps({
                'type': ['OS::Glance::Metadef'],
                'query': {
                    'match_all': {}
                },
                'aggregations': aggs
            }))

        self.assertRaises(webob.exc.HTTPForbidden, self.deserializer.search,
                          request)
Пример #20
0
    def test_delete_multiple(self):
        action_1 = _image_fixture('delete', '1')
        action_1.pop('data')
        action_2 = _image_fixture('delete', '2')
        action_2.pop('data')

        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'actions': [action_1, action_2],
        }))

        output = self.deserializer.index(request)
        expected = {
            'actions': [
                {
                    '_id': '1',
                    '_index': 'searchlight',
                    '_op_type': 'delete',
                    '_source': {},
                    '_type': 'OS::Glance::Image'
                },
                {
                    '_id': '2',
                    '_index': 'searchlight',
                    '_op_type': 'delete',
                    '_source': {},
                    '_type': 'OS::Glance::Image'
                },
            ],
            'default_index': None,
            'default_type': None
        }
        self.assertEqual(expected, output)
Пример #21
0
    def test_search_aggregations(self):
        request = unit_test_utils.get_fake_request()
        with mock.patch(REPO_SEARCH, return_value={}) as mock_search:
            query = {
                "query": {
                    "match_all": {}
                },
                "aggs": {
                    "test": {
                        "terms": {
                            "field": "some_field"
                        }
                    }
                }
            }
            index_name = "searchlight"
            limit = 10
            offset = 0
            doc_type = "OS::Glance::Image"

            self.search_controller.search(request,
                                          query,
                                          index_name,
                                          doc_type,
                                          offset,
                                          limit,
                                          version=True)

            mock_search.assert_called_once_with(index_name,
                                                doc_type,
                                                query,
                                                offset,
                                                limit,
                                                ignore_unavailable=True,
                                                version=True)
Пример #22
0
    def test_nested_object_facets(self):
        """Check 'nested' and 'object' types are treated the same for facets"""
        mock_engine = mock.Mock()
        plugin = fake_plugins.FakeSimplePlugin(es_engine=mock_engine)
        fake_request = unit_test_utils.get_fake_request(
            'a', 'b', '/v1/search/facets', is_admin=True
        )

        mock_engine.search.return_value = {
            "hits": {"total": 1}
        }

        fake_mapping = {
            "properties": {
                "nested": {
                    "type": "nested",
                    "properties": {"inner": {"type": "string"}}
                },
                "object": {
                    "type": "object",
                    "properties": {"inner": {"type": "string"}}
                }
            }
        }
        with mock.patch.object(plugin, 'get_mapping',
                               return_value=fake_mapping):
            facets, _ = plugin.get_facets(fake_request.context)
            facets = sorted(facets, key=operator.itemgetter("name"))
            expected = [
                {"name": "nested.inner", "type": "string", "nested": True},
                {"name": "object.inner", "type": "string", "nested": False},
            ]

            self.assertEqual(expected, facets)
Пример #23
0
    def test_rbac_non_admin(self):
        """Test that a non-admin request results in an RBACed query"""
        request = unit_test_utils.get_fake_request(is_admin=False)
        request.body = jsonutils.dumps({
            'query': {
                'match_all': {}
            },
            'type': 'OS::Nova::Server',
        }).encode("latin-1")
        output = self.deserializer.search(request)
        tenant_id = '6838eb7b-6ded-dead-beef-b344c77fe8df'

        nova_rbac_filter = {
            'indices': {
                'query': {
                    'bool': {
                        'filter': {
                            'bool': {
                                'must': {
                                    'type': {
                                        'value': 'OS::Nova::Server'
                                    }
                                },
                                'should': [{
                                    'term': {
                                        'tenant_id': tenant_id
                                    }
                                }],
                                'minimum_should_match': 1
                            }
                        }
                    }
                },
                'index': 'searchlight-search',
                'no_match_query': 'none'
            }
        }

        role_field = searchlight.elasticsearch.ROLE_USER_FIELD
        expected_query = {
            'query': {
                'bool': {
                    'filter': {
                        'bool': {
                            'must': {
                                'term': {
                                    role_field: 'user'
                                }
                            },
                            'should': [nova_rbac_filter],
                            'minimum_should_match': 1
                        }
                    },
                    'must': {
                        'match_all': {}
                    }
                }
            }
        }
        self.assertEqual(expected_query, output['query'])
Пример #24
0
    def test_plugins_info(self):
        request = unit_test_utils.get_fake_request()
        expected = {
            "plugins": [
                {
                    "index": "searchlight",
                    "type": "OS::Designate::RecordSet",
                    "name": "OS::Designate::RecordSet"
                },
                {
                    "index": "searchlight",
                    "type": "OS::Designate::Zone",
                    "name": "OS::Designate::Zone"
                },
                {
                    "index": "searchlight", "type": "OS::Glance::Image",
                    "name": "OS::Glance::Image"
                },
                {
                    "index": "searchlight", "type": "OS::Glance::Metadef",
                    "name": "OS::Glance::Metadef"
                },
                {
                    "index": "searchlight", "type": "OS::Nova::Server",
                    "name": "OS::Nova::Server"
                }
            ]
        }

        actual = self.search_controller.plugins_info(request)
        self.assertEqual(sorted(expected), sorted(actual))
Пример #25
0
    def test_filter_result(self):
        """Verify that any highlighted query results will filter out
           the ROLE_USER_FIELD field.
        """
        request = unit_test_utils.get_fake_request(is_admin=True)
        mock_engine = mock.Mock()
        simple_plugin = fake_plugins.FakeSimplePlugin(es_engine=mock_engine)

        # Verify with ROLE_USER_FIELD
        hit = {
            "_source": {
                "owner": "<em>admin</em>"
            },
            "highlight": {
                "owner": "<em>admin</em>",
                "__searchlight-user-role": "<em>admin</em>"
            }
        }

        simple_plugin.filter_result(hit, request.context)
        self.assertNotIn('__searchlight-user-role', hit['highlight'])

        # Verify without ROLE_USER_FIELD
        hit = {
            "_source": {
                "owner": "<em>admin</em>"
            },
            "highlight": {
                "owner": "<em>admin</em>"
            }
        }

        original_hit = copy.deepcopy(hit)
        simple_plugin.filter_result(hit, request.context)
        self.assertEqual(original_hit, hit)
Пример #26
0
    def test_search_policy_check(self, _):
        request = unit_test_utils.get_fake_request()
        with mock.patch.object(self.search_controller.policy,
                               'enforce') as mock_enforce:

            self.search_controller.search(request, query={"match_all": {}})
            mock_enforce.assert_called_with(request.context, 'query', {})
 def test_metadef_rbac(self):
     """Test metadefs RBAC query terms"""
     fake_request = unit_test_utils.get_fake_request(
         USER1, TENANT1, '/v1/search'
     )
     rbac_filter = self.plugin.get_query_filters(fake_request.context)
     expected_fragment = {
         "indices": {
             "index": "searchlight-search",
             "no_match_query": "none",
             "query": {
                 "bool": {
                     "filter": {
                         "bool": {
                             "must": {
                                 "type": {"value": "OS::Glance::Metadef"}
                             },
                             "should": [
                                 {"term": {"owner": TENANT1}},
                                 {"term": {"visibility": "public"}},
                             ],
                             "minimum_should_match": 1
                         }
                     }
                 }
             }
         }
     }
     self.assertEqual(expected_fragment, rbac_filter)
    def test_image_rbac(self):
        """Test the image plugin RBAC query terms"""
        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT1, '/v1/search'
        )
        rbac_query_fragment = self.plugin.get_query_filters(
            fake_request.context)
        expected_fragment = {
            "indices": {
                "index": "searchlight-search",
                "no_match_filter": "none",
                "filter": {
                    "and": [
                        {
                            "type": {"value": "OS::Glance::Image"}
                        },
                        {
                            "or": [
                                {"term": {"owner": TENANT1}},
                                {"term": {"visibility": "public"}},
                                {"term": {"members": TENANT1}}
                            ]
                        }
                    ]
                },
            }
        }

        self.assertEqual(expected_fragment, rbac_query_fragment)
    def test_image_rbac(self):
        """Test the image plugin RBAC query terms"""
        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT1, '/v1/search'
        )
        rbac_query_fragment = self.plugin.get_rbac_filter(fake_request.context)
        expected_fragment = [{
            "indices": {
                "index": "searchlight",
                "no_match_filter": "none",
                "filter": {
                    "and": [
                        {
                            "or": [
                                {"term": {"owner": TENANT1}},
                                {"term": {"visibility": "public"}},
                                {"term": {"members": TENANT1}}
                            ]
                        },
                        {
                            "type": {"value": "OS::Glance::Image"}
                        },
                    ]
                },
            }
        }]

        self.assertEqual(expected_fragment, rbac_query_fragment)
 def test_rbac_filters(self):
     fake_request = unit_test_utils.get_fake_request(
         USER1, TENANT1, '/v1/search', is_admin=False
     )
     self.assertEqual(
         [{"term": {"project_id": TENANT1}}],
         self.plugin._get_rbac_field_filters(fake_request.context))
    def test_image_rbac(self):
        """Test the image plugin RBAC query terms"""
        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT1, '/v1/search'
        )
        rbac_query_fragment = self.plugin.get_query_filters(
            fake_request.context)
        expected_fragment = {
            "indices": {
                "index": "searchlight-search",
                "no_match_query": "none",
                "query": {
                    "bool": {
                        "filter": {
                            "bool": {
                                "must": {
                                    "type": {"value": "OS::Glance::Image"}
                                },
                                "should": [
                                    {"term": {"owner": TENANT1}},
                                    {"term": {"visibility": "public"}},
                                    {"term": {"members": TENANT1}}
                                ],
                                'minimum_should_match': 1
                            }
                        }
                    }
                },
            }
        }

        self.assertEqual(expected_fragment, rbac_query_fragment)
    def test_facets_no_mapping(self):
        mock_engine = mock.Mock()
        self.plugin.engine = mock_engine

        fake_request = unit_test_utils.get_fake_request(
            USER1, TENANT1, '/v1/search/facets', is_admin=True
        )

        mock_engine.search.return_value = {
            'aggregations': {
                'status': {'buckets': []},
                'image.id': {'doc_count': 0}
            }
        }

        facets = self.plugin.get_facets(fake_request.context)

        status_facet = list(filter(lambda f: f['name'] == 'status',
                                   facets))[0]
        image_facet = list(filter(lambda f: f['name'] == 'image.id',
                                  facets))[0]
        expected_status = {'name': 'status', 'options': [], 'type': 'string'}
        expected_image = {'name': 'image.id', 'options': [], 'type': 'string'}

        self.assertEqual(expected_status, status_facet)
        self.assertEqual(expected_image, image_facet)
Пример #33
0
    def test_nested_object_facets(self):
        """Check 'nested' and 'object' types are treated the same for facets"""
        mock_engine = mock.Mock()
        plugin = fake_plugins.FakeSimplePlugin(es_engine=mock_engine)
        fake_request = unit_test_utils.get_fake_request(
            'a', 'b', '/v1/search/facets', is_admin=True
        )

        mock_engine.search.return_value = {
            "hits": {"total": 1}
        }

        fake_mapping = {
            "properties": {
                "nested": {
                    "type": "nested",
                    "properties": {"inner": {"type": "string"}}
                },
                "object": {
                    "type": "object",
                    "properties": {"inner": {"type": "string"}}
                }
            }
        }
        with mock.patch.object(plugin, 'get_mapping',
                               return_value=fake_mapping):
            facets, _ = plugin.get_facets(fake_request.context)
            facets = sorted(facets, key=operator.itemgetter("name"))
            expected = [
                {"name": "nested.inner", "type": "string", "nested": True},
                {"name": "object.inner", "type": "string", "nested": False},
            ]

            self.assertEqual(expected, facets)
Пример #34
0
    def test_search_policy_check(self, _):
        request = unit_test_utils.get_fake_request()
        with mock.patch.object(self.search_controller.policy,
                               'enforce') as mock_enforce:

            self.search_controller.search(request, query={"match_all": {}})
            mock_enforce.assert_called_with(request.context, 'query', {})
 def test_rbac_filter(self):
     fake_request = unit_test_utils.get_fake_request(USER1,
                                                     TENANT1,
                                                     '/v1/search',
                                                     is_admin=False)
     rbac_terms = self.plugin._get_rbac_field_filters(fake_request.context)
     self.assertEqual([{"term": {"id": AUTH_PREFIX + TENANT1}}], rbac_terms)
Пример #36
0
    def test_default_facet_options(self):
        request = unit_test_utils.get_fake_request(path='/v1/search/facets')
        output = self.deserializer.facets(request)

        expected = {'index_name': None, 'doc_type': None,
                    'all_projects': False, 'limit_terms': 0}
        self.assertEqual(expected, output)
Пример #37
0
 def test_facets(self):
     """If you have a weak constitution, we may want to avert your eyes
        now. We want to verify that the "exclude_options" parameter for
        facets will not result in any aggregation in the Elasticsearch
        query. The actual ES query is buried in the bowels of Searchlight.
        Instead of trying to call it directly through the searchcontroller
        and mock mutliple levels of Servers/Requests/Catalogs/etc we will
        go directly to the IndexBase call.
     """
     request = unit_test_utils.get_fake_request(is_admin=True)
     mock_engine = mock.Mock()
     simple_plugin = fake_plugins.FakeSimplePlugin(es_engine=mock_engine)
     mock_engine.search.return_value = {"hits": {"total": 0}}
     simple_plugin._get_facet_terms(fields={},
                                    request_context=request.context,
                                    all_projects=False, limit_terms=False,
                                    exclude_options=True)
     # Verify there is no aggregation when searching Elasticsearch.
     body = {'query': {
             'filtered': {'filter': {'and':
                          [{'term': {
                            '__searchlight-user-role': 'admin'}}]}}}
             }
     mock_engine.search.assert_called_with(body=body,
                                           doc_type='fake-simple',
                                           ignore_unavailable=True,
                                           index='searchlight-search',
                                           size=0)
Пример #38
0
 def test_rbac_filter_admin_role(self):
     fake_request = unit_test_utils.get_fake_request(
         USER1, TENANT1, '/v1/search', is_admin=True
     )
     rbac_terms = self.plugin._get_rbac_field_filters(fake_request.context)
     expected_rbac = [
         {
             "or": [
                 {
                     'term': {'tenant_id': TENANT1}
                 },
                 {
                     'has_parent': {
                         'type': self.plugin.parent_plugin_type(),
                         'query': {
                             "bool": {
                                 "should": [
                                     {'term': {'shared': True}},
                                     {'term': {'router:external': True}}
                                 ]
                             }
                         }
                     }
                 }
             ]
         }
     ]
     self.assertEqual(expected_rbac, rbac_terms)
Пример #39
0
    def test_plugins_info(self):
        request = unit_test_utils.get_fake_request()
        expected = {
            "plugins": [{
                "index": "searchlight-search",
                "type": "OS::Designate::RecordSet",
                "name": "OS::Designate::RecordSet"
            }, {
                "index": "searchlight-search",
                "type": "OS::Designate::Zone",
                "name": "OS::Designate::Zone"
            }, {
                "index": "searchlight-search",
                "type": "OS::Glance::Image",
                "name": "OS::Glance::Image"
            }, {
                "index": "searchlight-search",
                "type": "OS::Glance::Metadef",
                "name": "OS::Glance::Metadef"
            }, {
                "index": "searchlight-search",
                "type": "OS::Nova::Server",
                "name": "OS::Nova::Server"
            }]
        }

        # Simulate policy filtering
        doc_types = [p['name'] for p in expected['plugins']]
        actual = self.search_controller.plugins_info(request, doc_types)
        self.assertEqual(['plugins'], list(actual.keys()))

        self.assertEqual(
            sorted(expected['plugins'], key=operator.itemgetter('name')),
            sorted(actual['plugins'], key=operator.itemgetter('name')))
Пример #40
0
    def test_invalid_type(self):
        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'type': 'invalid',
        }))

        self.assertRaises(webob.exc.HTTPBadRequest, self.deserializer.index,
                          request)
Пример #41
0
 def test_facet_policy(self):
     request = unit_test_utils.get_fake_request()
     search_repo = mock.Mock()
     with mock.patch.object(self.enforcer, 'enforce') as mock_enforce:
         repo = policy.CatalogSearchRepoProxy(search_repo, request.context,
                                              self.enforcer)
         repo.facets()
         mock_enforce.assert_called_with(request.context, 'facets', {})
Пример #42
0
    def test_forbidden_self(self):
        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'self': {},
        }))

        self.assertRaises(webob.exc.HTTPForbidden, self.deserializer.search,
                          request)
Пример #43
0
    def test_forbidden_schema(self):
        request = unit_test_utils.get_fake_request()
        request.body = jsonutils.dumps({
            'schema': {},
        }).encode("latin-1")

        self.assertRaises(webob.exc.HTTPForbidden, self.deserializer.search,
                          request)
Пример #44
0
    def test_empty_operation_type(self):
        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'actions': [_image_fixture('', '1')]
        }))

        self.assertRaises(webob.exc.HTTPBadRequest, self.deserializer.index,
                          request)
Пример #45
0
    def test_single_index(self):
        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'index': 'searchlight-search',
        }))

        output = self.deserializer.search(request)
        self.assertEqual(['searchlight-search'], output['index'])
Пример #46
0
 def test_context_policy_target(self):
     request = unit_test_utils.get_fake_request()
     expected = {
         'user_id': unit_test_utils.SOMEUSER,
         'project_id': unit_test_utils.SOMETENANT,
         'tenant_id': unit_test_utils.SOMETENANT
     }
     self.assertEqual(expected, request.context.policy_target)
Пример #47
0
    def test_forbidden_self(self):
        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'self': {},
        }))

        self.assertRaises(webob.exc.HTTPForbidden, self.deserializer.search,
                          request)
Пример #48
0
    def test_create_invalid_index(self):
        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'actions': [_image_fixture('create', index='invalid')]
        }))

        self.assertRaises(webob.exc.HTTPBadRequest, self.deserializer.index,
                          request)
Пример #49
0
    def test_create_missing_doc_type(self):
        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'actions': [_image_fixture('create', '1', doc_type=None)]
        }))

        self.assertRaises(webob.exc.HTTPBadRequest, self.deserializer.index,
                          request)
Пример #50
0
    def test_single_index(self):
        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'index': 'searchlight-search',
        }))

        output = self.deserializer.search(request)
        self.assertEqual(['searchlight-search'], output['index'])
Пример #51
0
    def test_missing_actions(self):
        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'default_type': 'OS::Glance::Image'
        }))

        self.assertRaises(webob.exc.HTTPBadRequest, self.deserializer.index,
                          request)
Пример #52
0
 def test_search_version(self):
     request = unit_test_utils.get_fake_request(is_admin=True)
     request.body = six.b(jsonutils.dumps({
         'query': {'match_all': {}},
         'version': True
     }))
     output = self.deserializer.search(request)
     self.assertEqual(True, output['version'])
Пример #53
0
    def test_rbac_filter(self):
        fake_request = unit_test_utils.get_fake_request(USER1,
                                                        TENANT1,
                                                        '/v1/search',
                                                        is_admin=False)
        rbac_terms = self.plugin._get_rbac_field_filters(fake_request.context)

        expected = [{"term": {"tenant_id": TENANT1}}]
        self.assertEqual(expected, rbac_terms)
Пример #54
0
    def test_single_type(self):
        request = unit_test_utils.get_fake_request()
        request.body = six.b(jsonutils.dumps({
            'type': 'OS::Glance::Image',
        }))

        output = self.deserializer.search(request)
        self.assertEqual(['searchlight-search'], output['index'])
        self.assertEqual(['OS::Glance::Image'], output['doc_type'])
Пример #55
0
    def test_admin_or_owner(self):
        """Since this a commonly used rule, check that it works"""
        self.enforcer.add_rules(
            policy.policy.Rules.from_dict({
                'admin_or_owner': 'role:admin or project_id:%(project_id)s',
                'test_rule': 'rule:admin_or_owner'
            }))

        request = unit_test_utils.get_fake_request(is_admin=False)
        self.assertTrue(
            self.enforcer.check(request.context, 'test_rule',
                                request.context.policy_target))

        request = unit_test_utils.get_fake_request(is_admin=False)
        self.assertFalse(self.enforcer.check(request.context, 'test_rule', {}))

        request = unit_test_utils.get_fake_request(is_admin=True)
        self.assertTrue(self.enforcer.check(request.context, 'test_rule', {}))
Пример #56
0
    def test_fields_exclude_rbac(self):
        """Test various forms for source_exclude"""
        role_field = searchlight.elasticsearch.ROLE_USER_FIELD
        request = unit_test_utils.get_fake_request()
        request.body = six.b(
            jsonutils.dumps({
                'type': ['OS::Glance::Metadef'],
                'query': {
                    'match_all': {}
                },
                '_source': {
                    'exclude': ['something', 'other thing']
                }
            }))
        output = self.deserializer.search(request)
        self.assertEqual([role_field, 'something', 'other thing'],
                         output['_source_exclude'])

        # Test with a single field
        request.body = six.b(
            jsonutils.dumps({
                'type': ['OS::Glance::Metadef'],
                'query': {
                    'match_all': {}
                },
                '_source': {
                    'exclude': "something"
                }
            }))
        output = self.deserializer.search(request)
        self.assertEqual([role_field, 'something'], output['_source_exclude'])

        # Test with a single field
        request.body = six.b(
            jsonutils.dumps({
                'type': ['OS::Glance::Metadef'],
                'query': {
                    'match_all': {}
                },
                '_source': "includeme"
            }))
        output = self.deserializer.search(request)
        self.assertEqual([role_field], output['_source_exclude'])
        self.assertEqual("includeme", output['_source_include'])

        # Test with a single field
        request.body = six.b(
            jsonutils.dumps({
                'type': ['OS::Glance::Metadef'],
                'query': {
                    'match_all': {}
                },
                '_source': ["includeme", "andme"]
            }))
        output = self.deserializer.search(request)
        self.assertEqual([role_field], output['_source_exclude'])
        self.assertEqual(["includeme", "andme"], output['_source_include'])