diff --git a/vmware_nsxlib/tests/unit/v3/test_resources.py b/vmware_nsxlib/tests/unit/v3/test_resources.py index 943dc617..be9e6f7c 100644 --- a/vmware_nsxlib/tests/unit/v3/test_resources.py +++ b/vmware_nsxlib/tests/unit/v3/test_resources.py @@ -1474,6 +1474,41 @@ class TestNsxSearch(nsxlib_testcase.NsxClientTestCase): self.nsxlib.search_by_tags(tags=user_tags) search.assert_called_with('search?query=%s' % query) + def test_nsx_search_by_resouce_type_and_attributes(self): + with mock.patch.object(self.nsxlib.client, 'url_get') as search: + resource_type = 'HorseWithNoName' + attributes = {'color': 'mauve'} + self.nsxlib.search_resource_by_attributes(resource_type, + **attributes) + exp_query = 'resource_type:%s AND color:%s' % ( + resource_type, attributes['color']) + search.assert_called_with( + 'search?query=%s' % exp_query) + + def test_nsx_search_by_resouce_type_only(self): + with mock.patch.object(self.nsxlib.client, 'url_get') as search: + resource_type = 'HorseWithNoName' + self.nsxlib.search_resource_by_attributes(resource_type) + exp_query = 'resource_type:%s' % resource_type + search.assert_called_with( + 'search?query=%s' % exp_query) + + def test_nsx_search_no_resource_type_fails(self): + self.assertRaises(exceptions.NsxSearchInvalidQuery, + self.nsxlib.search_resource_by_attributes, + None, attributes={'meh': 'whatever'}) + + def test_nsx_search_resource_by_attributes_cursor_page_size(self): + with mock.patch.object(self.nsxlib.client, 'url_get') as search: + resource_type = 'HorseWithNoName' + attributes = {'color': 'mauve'} + self.nsxlib.search_resource_by_attributes( + resource_type, cursor=50, page_size=100, **attributes) + exp_query = 'resource_type:%s AND color:%s' % ( + resource_type, attributes['color']) + search.assert_called_with( + 'search?query=%s&cursor=50&page_size=100' % exp_query) + def test_nsx_search_tags_tag_and_scope(self): """Test search of resources with the specified tag.""" with mock.patch.object(self.nsxlib.client, 'url_get') as search: diff --git a/vmware_nsxlib/v3/lib.py b/vmware_nsxlib/v3/lib.py index 7e8dfd89..cebe3794 100644 --- a/vmware_nsxlib/v3/lib.py +++ b/vmware_nsxlib/v3/lib.py @@ -100,6 +100,13 @@ class NsxLibBase(object): def subscribe(self, callback, event): self.cluster.subscribe(callback, event) + def _add_pagination_parameters(self, url, cursor, page_size): + if cursor: + url += "&cursor=%d" % cursor + if page_size: + url += "&page_size=%d" % page_size + return url + # TODO(abhiraut): Revisit this method to generate complex boolean # queries to search resources. def search_by_tags(self, tags, resource_type=None, cursor=None, @@ -126,11 +133,45 @@ class NsxLibBase(object): query += " AND %s" % query_tags else: query = query_tags - url = "search?query=%s" % query - if cursor: - url += "&cursor=%d" % cursor - if page_size: - url += "&page_size=%d" % page_size + url = self._add_pagination_parameters("search?query=%s" % query, + cursor, page_size) + + # Retry the search on case of error + @utils.retry_upon_exception(exceptions.NsxIndexingInProgress, + max_attempts=self.client.max_attempts) + def do_search(url): + return self.client.url_get(url) + + return do_search(url) + + def search_resource_by_attributes(self, resource_type, cursor=None, + page_size=None, **attributes): + """Search resources of a given type matching specific attributes. + + It is optional to specify attributes. If multiple attributes are + specified they are ANDed together to form the search query. + + :param resource_type: String parameter specifying the desired + resource_type + :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 **attributes: an optional set of keyword arguments + specifying filters for the search query. + Wildcards will not be interpeted. + + :returns: a list of resources of the requested type matching + specified filters. + """ + if not resource_type: + raise exceptions.NsxSearchInvalidQuery( + reason=_("Resource type was not specified")) + attributes_query = " AND ".join(['%s:%s' % (k, v) for (k, v) + in attributes.items()]) + query = 'resource_type:%s' % resource_type + ( + " AND %s" % attributes_query if attributes_query else "") + url = self._add_pagination_parameters("search?query=%s" % query, + cursor, page_size) # Retry the search on case of error @utils.retry_upon_exception(exceptions.NsxIndexingInProgress, @@ -155,6 +196,22 @@ class NsxLibBase(object): if cursor >= result_count: return results + 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 + def get_id_by_resource_and_tag(self, resource_type, scope, tag, alert_not_found=False, alert_multiple=False):