Plugin types are not exposed to the client.

Glance Search clients currently don't have
anyway to know what "types" are available.

Search clients need to know the "type" to
include in the search request for the
particular resource.

Change-Id: I8baed7c5183752b1f52f8050ce321aacec701f1c
Closes-Bug: #1439061
This commit is contained in:
Lakshmi N Sampath 2015-04-01 08:38:15 -07:00
parent 503a7bb4dd
commit d6d5c501c1
7 changed files with 138 additions and 12 deletions

View File

@ -3,5 +3,6 @@
"default": "",
"catalog_index": "role:admin",
"catalog_search": ""
"catalog_search": "",
"catalog_plugins": ""
}

View File

@ -690,6 +690,10 @@ class CatalogSearchRepoProxy(object):
self.policy.enforce(self.context, 'catalog_search', {})
return self.search_repo.search(*args, **kwargs)
def plugins_info(self, *args, **kwargs):
self.policy.enforce(self.context, 'catalog_plugins', {})
return self.search_repo.plugins_info(*args, **kwargs)
def index(self, *args, **kwargs):
self.policy.enforce(self.context, 'catalog_index', {})
return self.search_repo.index(*args, **kwargs)

View File

@ -32,6 +32,7 @@ import functools
import os
import platform
import re
import stevedore
import subprocess
import sys
import uuid
@ -729,3 +730,10 @@ def stash_conf_values():
conf['cert_file'] = CONF.cert_file
return conf
def get_search_plugins():
namespace = 'glance.search.index_backend'
ext_manager = stevedore.extension.ExtensionManager(
namespace, invoke_on_load=True)
return ext_manager.extensions

View File

@ -17,6 +17,8 @@ import elasticsearch
from elasticsearch import helpers
from oslo_config import cfg
from glance.common import utils
search_opts = [
cfg.ListOpt('hosts', default=['127.0.0.1:9200'],
@ -40,6 +42,8 @@ class CatalogSearchRepo(object):
def __init__(self, context, es_api):
self.context = context
self.es_api = es_api
self.plugins = utils.get_search_plugins() or []
self.plugins_info_dict = self._get_plugin_info()
def search(self, index, doc_type, query, fields, offset, limit,
ignore_unavailable=True):
@ -58,3 +62,16 @@ class CatalogSearchRepo(object):
index=default_index,
doc_type=default_type,
actions=actions)
def plugins_info(self):
return self.plugins_info_dict
def _get_plugin_info(self):
plugin_info = dict()
plugin_info['plugins'] = []
for plugin in self.plugins:
info = dict()
info['type'] = plugin.obj.get_document_type()
info['index'] = plugin.obj.get_index_name()
plugin_info['plugins'].append(info)
return plugin_info

View File

@ -41,6 +41,17 @@ class API(wsgi.Router):
conditions={'method': ['PUT', 'DELETE',
'PATCH', 'HEAD']})
mapper.connect('/search/plugins',
controller=search_catalog_resource,
action='plugins_info',
conditions={'method': ['GET']})
mapper.connect('/search/plugins',
controller=reject_method_resource,
action='reject',
allowed_methods='GET',
conditions={'method': ['POST', 'PUT', 'DELETE',
'PATCH', 'HEAD']})
mapper.connect('/index',
controller=search_catalog_resource,
action='index',

View File

@ -18,7 +18,6 @@ import json
from oslo.config import cfg
from oslo_log import log as logging
import six
import stevedore
import webob.exc
from glance.api import policy
@ -76,6 +75,18 @@ class SearchController(object):
LOG.error(utils.exception_to_str(e))
raise webob.exc.HTTPInternalServerError()
def plugins_info(self, req):
try:
search_repo = self.gateway.get_catalog_search_repo(req.context)
return search_repo.plugins_info()
except exception.Forbidden as e:
raise webob.exc.HTTPForbidden(explanation=e.msg)
except exception.NotFound as e:
raise webob.exc.HTTPNotFound(explanation=e.msg)
except Exception as e:
LOG.error(utils.exception_to_str(e))
raise webob.exc.HTTPInternalServerError()
def index(self, req, actions, default_index=None, default_type=None):
try:
search_repo = self.gateway.get_catalog_search_repo(req.context)
@ -351,22 +362,20 @@ class ResponseSerializer(wsgi.JSONResponseSerializer):
response.unicode_body = six.text_type(body)
response.content_type = 'application/json'
def plugins_info(self, response, query_result):
body = json.dumps(query_result, ensure_ascii=False)
response.unicode_body = six.text_type(body)
response.content_type = 'application/json'
def index(self, response, query_result):
body = json.dumps(query_result, ensure_ascii=False)
response.unicode_body = six.text_type(body)
response.content_type = 'application/json'
def get_plugins():
namespace = 'glance.search.index_backend'
ext_manager = stevedore.extension.ExtensionManager(
namespace, invoke_on_load=True)
return ext_manager.extensions
def create_resource():
"""Search resource factory method"""
plugins = get_plugins()
plugins = utils.get_search_plugins()
deserializer = RequestDeserializer(plugins)
serializer = ResponseSerializer()
controller = SearchController(plugins)

View File

@ -18,6 +18,7 @@ from oslo.serialization import jsonutils
import webob.exc
from glance.common import exception
from glance.common import utils
import glance.gateway
import glance.search
from glance.search.api.v0_1 import search as search
@ -234,12 +235,52 @@ class TestSearchController(base.IsolatedUnitTest):
webob.exc.HTTPInternalServerError, self.search_controller.index,
request, actions)
def test_plugins_info(self):
request = unit_test_utils.get_fake_request()
self.search_controller.plugins_info = mock.Mock(return_value="{}")
self.search_controller.plugins_info(request)
self.search_controller.plugins_info.assert_called_once_with(request)
def test_plugins_info_repo(self):
request = unit_test_utils.get_fake_request()
repo = glance.search.CatalogSearchRepo
repo.plugins_info = mock.Mock(return_value="{}")
self.search_controller.plugins_info(request)
repo.plugins_info.assert_called_once_with()
def test_plugins_info_forbidden(self):
request = unit_test_utils.get_fake_request()
repo = glance.search.CatalogSearchRepo
repo.plugins_info = mock.Mock(side_effect=exception.Forbidden)
self.assertRaises(
webob.exc.HTTPForbidden, self.search_controller.plugins_info,
request)
def test_plugins_info_not_found(self):
request = unit_test_utils.get_fake_request()
repo = glance.search.CatalogSearchRepo
repo.plugins_info = mock.Mock(side_effect=exception.NotFound)
self.assertRaises(webob.exc.HTTPNotFound,
self.search_controller.plugins_info, request)
def test_plugins_info_internal_server_error(self):
request = unit_test_utils.get_fake_request()
repo = glance.search.CatalogSearchRepo
repo.plugins_info = mock.Mock(side_effect=Exception)
self.assertRaises(webob.exc.HTTPInternalServerError,
self.search_controller.plugins_info, request)
class TestSearchDeserializer(test_utils.BaseTestCase):
def setUp(self):
super(TestSearchDeserializer, self).setUp()
self.deserializer = search.RequestDeserializer(search.get_plugins())
self.deserializer = search.RequestDeserializer(
utils.get_search_plugins()
)
def test_single_index(self):
request = unit_test_utils.get_fake_request()
@ -411,7 +452,9 @@ class TestIndexDeserializer(test_utils.BaseTestCase):
def setUp(self):
super(TestIndexDeserializer, self).setUp()
self.deserializer = search.RequestDeserializer(search.get_plugins())
self.deserializer = search.RequestDeserializer(
utils.get_search_plugins()
)
def test_empty_request(self):
request = unit_test_utils.get_fake_request()
@ -874,6 +917,39 @@ class TestResponseSerializer(test_utils.BaseTestCase):
super(TestResponseSerializer, self).setUp()
self.serializer = search.ResponseSerializer()
def test_plugins_info(self):
expected = {
"plugins": [
{
"index": "glance",
"type": "image"
},
{
"index": "glance",
"type": "metadef"
}
]
}
request = webob.Request.blank('/v0.1/search')
response = webob.Response(request=request)
result = {
"plugins": [
{
"index": "glance",
"type": "image"
},
{
"index": "glance",
"type": "metadef"
}
]
}
self.serializer.search(response, result)
actual = jsonutils.loads(response.body)
self.assertEqual(expected, actual)
self.assertEqual('application/json', response.content_type)
def test_search(self):
expected = [{
'id': '1',