Merge "Plugin types are not exposed to the client."

This commit is contained in:
Jenkins 2015-04-24 01:05:00 +00:00 committed by Gerrit Code Review
commit 80e46b745a
7 changed files with 138 additions and 12 deletions

View File

@ -3,5 +3,6 @@
"default": "", "default": "",
"catalog_index": "role:admin", "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', {}) self.policy.enforce(self.context, 'catalog_search', {})
return self.search_repo.search(*args, **kwargs) 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): def index(self, *args, **kwargs):
self.policy.enforce(self.context, 'catalog_index', {}) self.policy.enforce(self.context, 'catalog_index', {})
return self.search_repo.index(*args, **kwargs) return self.search_repo.index(*args, **kwargs)

View File

@ -32,6 +32,7 @@ import functools
import os import os
import platform import platform
import re import re
import stevedore
import subprocess import subprocess
import sys import sys
import uuid import uuid
@ -729,3 +730,10 @@ def stash_conf_values():
conf['cert_file'] = CONF.cert_file conf['cert_file'] = CONF.cert_file
return conf 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 elasticsearch import helpers
from oslo_config import cfg from oslo_config import cfg
from glance.common import utils
search_opts = [ search_opts = [
cfg.ListOpt('hosts', default=['127.0.0.1:9200'], cfg.ListOpt('hosts', default=['127.0.0.1:9200'],
@ -40,6 +42,8 @@ class CatalogSearchRepo(object):
def __init__(self, context, es_api): def __init__(self, context, es_api):
self.context = context self.context = context
self.es_api = es_api 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, def search(self, index, doc_type, query, fields, offset, limit,
ignore_unavailable=True): ignore_unavailable=True):
@ -58,3 +62,16 @@ class CatalogSearchRepo(object):
index=default_index, index=default_index,
doc_type=default_type, doc_type=default_type,
actions=actions) 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', conditions={'method': ['PUT', 'DELETE',
'PATCH', 'HEAD']}) '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', mapper.connect('/index',
controller=search_catalog_resource, controller=search_catalog_resource,
action='index', action='index',

View File

@ -18,7 +18,6 @@ import json
from oslo.config import cfg from oslo.config import cfg
from oslo_log import log as logging from oslo_log import log as logging
import six import six
import stevedore
import webob.exc import webob.exc
from glance.api import policy from glance.api import policy
@ -76,6 +75,18 @@ class SearchController(object):
LOG.error(utils.exception_to_str(e)) LOG.error(utils.exception_to_str(e))
raise webob.exc.HTTPInternalServerError() 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): def index(self, req, actions, default_index=None, default_type=None):
try: try:
search_repo = self.gateway.get_catalog_search_repo(req.context) 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.unicode_body = six.text_type(body)
response.content_type = 'application/json' 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): def index(self, response, query_result):
body = json.dumps(query_result, ensure_ascii=False) body = json.dumps(query_result, ensure_ascii=False)
response.unicode_body = six.text_type(body) response.unicode_body = six.text_type(body)
response.content_type = 'application/json' 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(): def create_resource():
"""Search resource factory method""" """Search resource factory method"""
plugins = get_plugins() plugins = utils.get_search_plugins()
deserializer = RequestDeserializer(plugins) deserializer = RequestDeserializer(plugins)
serializer = ResponseSerializer() serializer = ResponseSerializer()
controller = SearchController(plugins) controller = SearchController(plugins)

View File

@ -18,6 +18,7 @@ from oslo.serialization import jsonutils
import webob.exc import webob.exc
from glance.common import exception from glance.common import exception
from glance.common import utils
import glance.gateway import glance.gateway
import glance.search import glance.search
from glance.search.api.v0_1 import search as 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, webob.exc.HTTPInternalServerError, self.search_controller.index,
request, actions) 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): class TestSearchDeserializer(test_utils.BaseTestCase):
def setUp(self): def setUp(self):
super(TestSearchDeserializer, self).setUp() super(TestSearchDeserializer, self).setUp()
self.deserializer = search.RequestDeserializer(search.get_plugins()) self.deserializer = search.RequestDeserializer(
utils.get_search_plugins()
)
def test_single_index(self): def test_single_index(self):
request = unit_test_utils.get_fake_request() request = unit_test_utils.get_fake_request()
@ -411,7 +452,9 @@ class TestIndexDeserializer(test_utils.BaseTestCase):
def setUp(self): def setUp(self):
super(TestIndexDeserializer, self).setUp() super(TestIndexDeserializer, self).setUp()
self.deserializer = search.RequestDeserializer(search.get_plugins()) self.deserializer = search.RequestDeserializer(
utils.get_search_plugins()
)
def test_empty_request(self): def test_empty_request(self):
request = unit_test_utils.get_fake_request() request = unit_test_utils.get_fake_request()
@ -874,6 +917,39 @@ class TestResponseSerializer(test_utils.BaseTestCase):
super(TestResponseSerializer, self).setUp() super(TestResponseSerializer, self).setUp()
self.serializer = search.ResponseSerializer() 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): def test_search(self):
expected = [{ expected = [{
'id': '1', 'id': '1',