From 7102440687bc0c49601bfdc4e2925f731a9134da Mon Sep 17 00:00:00 2001 From: Monty Taylor Date: Wed, 1 Feb 2017 11:09:40 -0600 Subject: [PATCH] Support globbing in name or id checks The ansible os_server_facts module support doing this, and a recent change to add support for returning servers by ids there made it seem like perhaps the functionality should get rolled up into the shade layer and be available to everyone. Change-Id: Ib1096d606840767ce884e6dd58a6928fee0ae6e2 --- .../fnmatch-name-or-id-f658fe26f84086c8.yaml | 5 +++++ shade/_utils.py | 10 +++++++--- shade/tests/unit/test__utils.py | 16 ++++++++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 releasenotes/notes/fnmatch-name-or-id-f658fe26f84086c8.yaml diff --git a/releasenotes/notes/fnmatch-name-or-id-f658fe26f84086c8.yaml b/releasenotes/notes/fnmatch-name-or-id-f658fe26f84086c8.yaml new file mode 100644 index 000000000..dcdccd249 --- /dev/null +++ b/releasenotes/notes/fnmatch-name-or-id-f658fe26f84086c8.yaml @@ -0,0 +1,5 @@ +--- +features: + - name_or_id parameters to search/get methods now support + filename-like globbing. This means search_servers('nb0*') + will return all servers whose names start with 'nb0'. diff --git a/shade/_utils.py b/shade/_utils.py index bfcfbd416..b3da5b5c9 100644 --- a/shade/_utils.py +++ b/shade/_utils.py @@ -13,6 +13,7 @@ # limitations under the License. import contextlib +import fnmatch import inspect import jmespath import munch @@ -83,7 +84,8 @@ def _filter_list(data, name_or_id, filters): each dictionary contains an 'id' and 'name' key if a value for name_or_id is given. :param string name_or_id: - The name or ID of the entity being filtered. + The name or ID of the entity being filtered. Can be a glob pattern, + such as 'nb01*'. :param filters: A dictionary of meta data to use for further filtering. Elements of this dictionary may, themselves, be dictionaries. Example:: @@ -100,9 +102,11 @@ def _filter_list(data, name_or_id, filters): if name_or_id: identifier_matches = [] for e in data: - e_id = str(e.get('id', None)) + e_id = e.get('id', None) e_name = e.get('name', None) - if str(name_or_id) in (e_id, e_name): + if ((e_id and fnmatch.fnmatch(str(e_id), str(name_or_id))) or + (e_name and fnmatch.fnmatch( + str(e_name), str(name_or_id)))): identifier_matches.append(e) data = identifier_matches diff --git a/shade/tests/unit/test__utils.py b/shade/tests/unit/test__utils.py index bfe566bd4..28235e8dd 100644 --- a/shade/tests/unit/test__utils.py +++ b/shade/tests/unit/test__utils.py @@ -40,6 +40,22 @@ class TestUtils(base.TestCase): ret = _utils._filter_list(data, 'donald', None) self.assertEqual([el1], ret) + def test__filter_list_name_or_id_glob(self): + el1 = dict(id=100, name='donald') + el2 = dict(id=200, name='pluto') + el3 = dict(id=200, name='pluto-2') + data = [el1, el2, el3] + ret = _utils._filter_list(data, 'pluto*', None) + self.assertEqual([el2, el3], ret) + + def test__filter_list_name_or_id_glob_not_found(self): + el1 = dict(id=100, name='donald') + el2 = dict(id=200, name='pluto') + el3 = dict(id=200, name='pluto-2') + data = [el1, el2, el3] + ret = _utils._filter_list(data, 'q*', None) + self.assertEqual([], ret) + def test__filter_list_filter(self): el1 = dict(id=100, name='donald', other='duck') el2 = dict(id=200, name='donald', other='trump')