summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLakshmi N Sampath <lakshmi.sampath@hp.com>2015-04-01 08:38:15 -0700
committerNikhil Komawar <nikhilskomawar@gmail.com>2015-04-23 16:38:18 -0400
commite1e3c76392245da912f14b26cf2a585b37c5feb1 (patch)
treeb155279abc440bc0fec3467aa8d08d7aab6c8024
parente3bed85d5123764dfa25059bba31acbf5fa9c035 (diff)
downloadglance-e1e3c76392245da912f14b26cf2a585b37c5feb1.tar.gz
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. Backport change:- Has been cherry picked from commit d6d5c501c16ed7df64944f6646ad32aca345adcd Change-Id: I8baed7c5183752b1f52f8050ce321aacec701f1c Closes-Bug: #1439061
-rw-r--r--etc/search-policy.json3
-rwxr-xr-xglance/api/policy.py4
-rw-r--r--glance/common/utils.py8
-rw-r--r--glance/search/__init__.py17
-rwxr-xr-xglance/search/api/v0_1/router.py11
-rwxr-xr-xglance/search/api/v0_1/search.py27
-rwxr-xr-xglance/tests/unit/v0_1/test_search.py80
7 files changed, 138 insertions, 12 deletions
diff --git a/etc/search-policy.json b/etc/search-policy.json
index abef5b3b0..dc324e259 100644
--- a/etc/search-policy.json
+++ b/etc/search-policy.json
@@ -3,5 +3,6 @@
"default": "",
"catalog_index": "role:admin",
- "catalog_search": ""
+ "catalog_search": "",
+ "catalog_plugins": ""
}
diff --git a/glance/api/policy.py b/glance/api/policy.py
index e3c4d5710..f7939cb24 100755
--- a/glance/api/policy.py
+++ b/glance/api/policy.py
@@ -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)
diff --git a/glance/common/utils.py b/glance/common/utils.py
index 868235e48..1923be411 100644
--- a/glance/common/utils.py
+++ b/glance/common/utils.py
@@ -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
diff --git a/glance/search/__init__.py b/glance/search/__init__.py
index 5b36d7d57..e1cacf01f 100644
--- a/glance/search/__init__.py
+++ b/glance/search/__init__.py
@@ -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
diff --git a/glance/search/api/v0_1/router.py b/glance/search/api/v0_1/router.py
index ad0462a6f..1f08b33b4 100755
--- a/glance/search/api/v0_1/router.py
+++ b/glance/search/api/v0_1/router.py
@@ -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',
diff --git a/glance/search/api/v0_1/search.py b/glance/search/api/v0_1/search.py
index 64ca7ba41..f6aa4bf55 100755
--- a/glance/search/api/v0_1/search.py
+++ b/glance/search/api/v0_1/search.py
@@ -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 index(self, response, query_result):
+ 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 get_plugins():
- namespace = 'glance.search.index_backend'
- ext_manager = stevedore.extension.ExtensionManager(
- namespace, invoke_on_load=True)
- return ext_manager.extensions
+ 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 create_resource():
"""Search resource factory method"""
- plugins = get_plugins()
+ plugins = utils.get_search_plugins()
deserializer = RequestDeserializer(plugins)
serializer = ResponseSerializer()
controller = SearchController(plugins)
diff --git a/glance/tests/unit/v0_1/test_search.py b/glance/tests/unit/v0_1/test_search.py
index d5782a966..09a083cf6 100755
--- a/glance/tests/unit/v0_1/test_search.py
+++ b/glance/tests/unit/v0_1/test_search.py
@@ -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',