Merge "Add new search APIs using query pipeline and aggregate search"
This commit is contained in:
commit
c004c601db
|
@ -1896,6 +1896,25 @@ class TestNsxSearch(nsxlib_testcase.NsxClientTestCase):
|
|||
self.nsxlib._build_query,
|
||||
tags=user_tags)
|
||||
|
||||
def test_nsx_search_all(self):
|
||||
"""Test search all base method."""
|
||||
mock_search = mock.Mock()
|
||||
mock_search.side_effect = [
|
||||
{"cursor": "2",
|
||||
"result_count": 3,
|
||||
"results": [{"id": "s1"}, {"id": "s2"}]},
|
||||
{"cursor": "3",
|
||||
"result_count": 3,
|
||||
"results": [{"id": "s3"}]}]
|
||||
args = "foo"
|
||||
kwargs = {"a1": "v1", "a2": "v2"}
|
||||
results = self.nsxlib._search_all(mock_search, *args, **kwargs)
|
||||
mock_search.assert_has_calls([
|
||||
mock.call(*args, cursor=0, **kwargs),
|
||||
mock.call(*args, cursor=2, **kwargs)])
|
||||
self.assertEqual(3, len(results))
|
||||
self.assertEqual([{"id": "s1"}, {"id": "s2"}, {"id": "s3"}], results)
|
||||
|
||||
def test_nsx_search_all_by_tags(self):
|
||||
"""Test search all of resources with the specified tag."""
|
||||
with mock.patch.object(self.nsxlib.client, 'url_get') as search:
|
||||
|
@ -1915,6 +1934,57 @@ class TestNsxSearch(nsxlib_testcase.NsxClientTestCase):
|
|||
mock.call((self.search_path + '&cursor=2') % query)])
|
||||
self.assertEqual(3, len(results))
|
||||
|
||||
@mock.patch("vmware_nsxlib.v3.lib.NsxLibBase._search_all")
|
||||
def test_nsx_search_all_by_attribute_values(self, mock_search_all):
|
||||
"""Test search all resources with the specified attribute values."""
|
||||
resource_type = "dummy_type"
|
||||
name, values = "dummy_attr", ["id1", "id2", "id3"]
|
||||
self.nsxlib.search_all_resource_by_attribute_values(
|
||||
resource_type, name, values)
|
||||
mock_search_all.assert_called_once_with(
|
||||
self.nsxlib.search_resource_by_attribute_values, resource_type,
|
||||
name, values)
|
||||
|
||||
@mock.patch("vmware_nsxlib.v3.lib.NsxLibBase._search_all")
|
||||
def test_nsx_search_all_by_filters(self, mock_search_all):
|
||||
"""Test search all resources with the specified filters."""
|
||||
resource_type = "dummy_type"
|
||||
filters = [{"field_names": "foo", "value": "bar"}]
|
||||
extra_attrs = {"related": [{"resource_type": "FirewallRule",
|
||||
"join_condition": "section_id:id"}]}
|
||||
self.nsxlib.search_all_resource_by_filters(
|
||||
resource_type, filters, **extra_attrs)
|
||||
mock_search_all.assert_called_once_with(
|
||||
self.nsxlib.search_resource_by_filters, resource_type, filters,
|
||||
**extra_attrs)
|
||||
|
||||
def test_nsx_search_resource_by_attribute_values(self):
|
||||
"""Test search resources with the specified attribute values."""
|
||||
with mock.patch.object(self.nsxlib.client, "url_post") as search:
|
||||
resource_type = "dummy_type"
|
||||
attr_name, attr_values = "dummy_name", ["value1", "value2"]
|
||||
attr_query = " OR ".join(attr_values)
|
||||
query = "resource_type:%s AND %s:(%s)" % (
|
||||
resource_type, attr_name, attr_query)
|
||||
body = {"query_pipeline": [{"query": query}]}
|
||||
self.nsxlib.search_resource_by_attribute_values(
|
||||
resource_type, attr_name, attr_values)
|
||||
search.assert_called_with("search/querypipeline", body)
|
||||
|
||||
def test_nsx_search_resource_by_filters(self):
|
||||
"""Test search resources with the specified filters."""
|
||||
with mock.patch.object(self.nsxlib.client, "url_post") as search:
|
||||
parent_type, child_type = "parent_type", "child_type"
|
||||
filters = [{"field_names": "foo", "value": "bar"}]
|
||||
related = [{"resource_type": child_type,
|
||||
"join_condition": "section_id:id"}]
|
||||
body = {"primary": {"resource_type": parent_type,
|
||||
"filters": filters},
|
||||
"related": related}
|
||||
self.nsxlib.search_resource_by_filters(
|
||||
parent_type, filters, related=related)
|
||||
search.assert_called_with("search/aggregate", body)
|
||||
|
||||
def test_get_id_by_resource_and_tag(self):
|
||||
id = 'test'
|
||||
scope = 'user'
|
||||
|
|
|
@ -203,14 +203,83 @@ class NsxLibBase(object):
|
|||
|
||||
return do_search(url)
|
||||
|
||||
def search_all_by_tags(self, tags, resource_type=None, **extra_attrs):
|
||||
"""Return all the results searched based on tags."""
|
||||
def search_resource_by_attribute_values(self, resource_type, name, values,
|
||||
cursor=None, page_size=None):
|
||||
"""Search resources of a given type matching values of an attribute.
|
||||
|
||||
:param resource_type: String parameter specifying the desired
|
||||
resource_type.
|
||||
:param name: Attribute name to match.
|
||||
:param values: List of attribute values to search for.
|
||||
:param cursor: Opaque cursor to be used for getting next page of
|
||||
records (supplied by current result page).
|
||||
:param page_size: Maximum number of results to return in this page.
|
||||
|
||||
:returns: a list of resources of the requested type matching
|
||||
specified attribute values.
|
||||
"""
|
||||
attribute_query = " OR ".join(values)
|
||||
query = 'resource_type:%s' % resource_type + (
|
||||
" AND %s:(%s)" % (name, attribute_query)
|
||||
if attribute_query else "")
|
||||
body = {"query_pipeline": [{"query": query}]}
|
||||
args = []
|
||||
if cursor:
|
||||
args.append("cursor=%d" % cursor)
|
||||
if page_size:
|
||||
args.append("page_size=%d" % page_size)
|
||||
url = "search/querypipeline" + ("?%s" % "&".join(args) if args else "")
|
||||
|
||||
# Retry the search in case of error
|
||||
@utils.retry_upon_exception(exceptions.NsxSearchError,
|
||||
max_attempts=self.client.max_attempts)
|
||||
def do_search(url):
|
||||
return self.client.url_post(url, body)
|
||||
|
||||
return do_search(url)
|
||||
|
||||
def search_resource_by_filters(self, resource_type, filters,
|
||||
cursor=None, page_size=None, **extra_attrs):
|
||||
"""Search resources of a given type matching specific filters.
|
||||
|
||||
:param resource_type: String parameter specifying the desired
|
||||
resource_type.
|
||||
:param filters: List of dictionaries containing filters. Each
|
||||
filter dictionary is of the form:
|
||||
{'field_names': <filter_key>, 'value': <filter_value>}
|
||||
:param cursor: Opaque cursor to be used for getting next page of
|
||||
records (supplied by current result page).
|
||||
:param page_size: Maximum number of results to return in this page.
|
||||
:param extra_attrs: Support querying by user specified attributes.
|
||||
|
||||
:returns: a list of resources of the requested type matching
|
||||
specified filters.
|
||||
"""
|
||||
body = {"primary": {"resource_type": resource_type,
|
||||
"filters": filters}}
|
||||
related = extra_attrs.get("related")
|
||||
if related:
|
||||
body["related"] = related
|
||||
args = []
|
||||
if cursor:
|
||||
args.append("cursor=%d" % cursor)
|
||||
if page_size:
|
||||
args.append("page_size=%d" % page_size)
|
||||
url = "search/aggregate" + ("?%s" % "&".join(args) if args else "")
|
||||
|
||||
# Retry the search in case of error
|
||||
@utils.retry_upon_exception(exceptions.NsxSearchError,
|
||||
max_attempts=self.client.max_attempts)
|
||||
def do_search(url):
|
||||
return self.client.url_post(url, body)
|
||||
|
||||
return do_search(url)
|
||||
|
||||
def _search_all(self, search_func, *args, **kwargs):
|
||||
results = []
|
||||
cursor = 0
|
||||
while True:
|
||||
response = self.search_by_tags(
|
||||
resource_type=resource_type, tags=tags, cursor=cursor,
|
||||
**extra_attrs)
|
||||
response = search_func(*args, cursor=cursor, **kwargs)
|
||||
if not response['results']:
|
||||
return results
|
||||
results.extend(response['results'])
|
||||
|
@ -219,21 +288,32 @@ class NsxLibBase(object):
|
|||
if cursor >= result_count:
|
||||
return results
|
||||
|
||||
def search_all_by_tags(self, tags, resource_type=None, **extra_attrs):
|
||||
"""Return all the results searched based on tags."""
|
||||
return self._search_all(self.search_by_tags,
|
||||
resource_type=resource_type, tags=tags,
|
||||
**extra_attrs)
|
||||
|
||||
def search_all_resource_by_attributes(self, resource_type, **attributes):
|
||||
"""Return all the results searched based on attributes."""
|
||||
results = []
|
||||
cursor = 0
|
||||
while True:
|
||||
response = self.search_resource_by_attributes(
|
||||
resource_type=resource_type,
|
||||
cursor=cursor, **attributes)
|
||||
if not response['results']:
|
||||
return results
|
||||
results.extend(response['results'])
|
||||
cursor = int(response['cursor'])
|
||||
result_count = int(response['result_count'])
|
||||
if cursor >= result_count:
|
||||
return results
|
||||
"""Return all resources of a given type matching specific attributes.
|
||||
|
||||
"""
|
||||
return self._search_all(self.search_resource_by_attributes,
|
||||
resource_type=resource_type, **attributes)
|
||||
|
||||
def search_all_resource_by_attribute_values(self, resource_type, name,
|
||||
values):
|
||||
"""Return all resources of a given type matching an attribute value.
|
||||
|
||||
"""
|
||||
return self._search_all(self.search_resource_by_attribute_values,
|
||||
resource_type, name, values)
|
||||
|
||||
def search_all_resource_by_filters(self, resource_type, filters,
|
||||
**extra_attrs):
|
||||
"""Return all resources of a given type matching specific filters."""
|
||||
return self._search_all(self.search_resource_by_filters, resource_type,
|
||||
filters, **extra_attrs)
|
||||
|
||||
def get_id_by_resource_and_tag(self, resource_type, scope, tag,
|
||||
alert_not_found=False,
|
||||
|
|
Loading…
Reference in New Issue