Merge "Plugin types are not exposed to the client."
This commit is contained in:
commit
80e46b745a
@ -3,5 +3,6 @@
|
|||||||
"default": "",
|
"default": "",
|
||||||
|
|
||||||
"catalog_index": "role:admin",
|
"catalog_index": "role:admin",
|
||||||
"catalog_search": ""
|
"catalog_search": "",
|
||||||
|
"catalog_plugins": ""
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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',
|
||||||
|
@ -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)
|
||||||
|
@ -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',
|
||||||
|
Loading…
Reference in New Issue
Block a user