From 0017ffb050e6df0df28716d32e2b6b03e145a4b6 Mon Sep 17 00:00:00 2001 From: Kafilat Adeleke Date: Wed, 23 Jun 2021 08:33:31 +0000 Subject: [PATCH] Adds share group resource to shared file system Introduce Share groups class with basic methods including list, create, delete, get and update to shared file system service. Change-Id: I7d7e4e7addc1c1b040276e10f8152bc0adb8eeb2 --- .../user/proxies/shared_file_system.rst | 12 +++ .../resources/shared_file_system/index.rst | 1 + .../shared_file_system/v2/share_group.rst | 13 +++ openstack/shared_file_system/v2/_proxy.py | 102 ++++++++++++++++++ .../shared_file_system/v2/share_group.py | 56 ++++++++++ .../functional/shared_file_system/base.py | 10 ++ .../shared_file_system/test_share_group.py | 66 ++++++++++++ .../unit/shared_file_system/v2/test_proxy.py | 44 ++++++++ .../shared_file_system/v2/test_share_group.py | 81 ++++++++++++++ ...group-to-shared-file-8cee20d8aa2afbb7.yaml | 5 + 10 files changed, 390 insertions(+) create mode 100644 doc/source/user/resources/shared_file_system/v2/share_group.rst create mode 100644 openstack/shared_file_system/v2/share_group.py create mode 100644 openstack/tests/functional/shared_file_system/test_share_group.py create mode 100644 openstack/tests/unit/shared_file_system/v2/test_share_group.py create mode 100644 releasenotes/notes/add-share_group-to-shared-file-8cee20d8aa2afbb7.yaml diff --git a/doc/source/user/proxies/shared_file_system.rst b/doc/source/user/proxies/shared_file_system.rst index 1887f2668..f954b1847 100644 --- a/doc/source/user/proxies/shared_file_system.rst +++ b/doc/source/user/proxies/shared_file_system.rst @@ -138,3 +138,15 @@ Shared File Systems service. :noindex: :members: access_rules, get_access_rule, create_access_rule, delete_access_rule + + +Shared File System Share Groups +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Interact with Share groups supported by the Shared File Systems +service. + +.. autoclass:: openstack.shared_file_system.v2._proxy.Proxy + :noindex: + :members: share_groups, get_share_group, delete_share_group, + update_share_group, create_share_group, find_share_group diff --git a/doc/source/user/resources/shared_file_system/index.rst b/doc/source/user/resources/shared_file_system/index.rst index 84dd66ed8..c0b6fa4d3 100644 --- a/doc/source/user/resources/shared_file_system/index.rst +++ b/doc/source/user/resources/shared_file_system/index.rst @@ -14,4 +14,5 @@ Shared File System service resources v2/share_snapshot_instance v2/share_network v2/user_message + v2/share_group v2/share_access_rule diff --git a/doc/source/user/resources/shared_file_system/v2/share_group.rst b/doc/source/user/resources/shared_file_system/v2/share_group.rst new file mode 100644 index 000000000..232202b56 --- /dev/null +++ b/doc/source/user/resources/shared_file_system/v2/share_group.rst @@ -0,0 +1,13 @@ +openstack.shared_file_system.v2.share_group +=========================================== + +.. automodule:: openstack.shared_file_system.v2.share_group + +The ShareGroup Class +-------------------- + +The ``ShareGroup`` class inherits from +:class:`~openstack.resource.Resource`. + +.. autoclass:: openstack.shared_file_system.v2.share_group.ShareGroup + :members: diff --git a/openstack/shared_file_system/v2/_proxy.py b/openstack/shared_file_system/v2/_proxy.py index 52495e4ec..a682cdd9b 100644 --- a/openstack/shared_file_system/v2/_proxy.py +++ b/openstack/shared_file_system/v2/_proxy.py @@ -17,6 +17,7 @@ from openstack.shared_file_system.v2 import ( ) from openstack.shared_file_system.v2 import limit as _limit from openstack.shared_file_system.v2 import share as _share +from openstack.shared_file_system.v2 import share_group as _share_group from openstack.shared_file_system.v2 import ( share_access_rule as _share_access_rule, ) @@ -50,6 +51,7 @@ class Proxy(proxy.Proxy): "share_instance": _share_instance.ShareInstance, "share_export_locations": _share_export_locations.ShareExportLocation, "share_access_rule": _share_access_rule.ShareAccessRule, + "share_group": _share_group.ShareGroup, } def availability_zones(self): @@ -211,6 +213,106 @@ class Proxy(proxy.Proxy): elif new_size < res.size and no_shrink is not True: res.shrink_share(self, new_size) + def share_groups(self, **query): + """Lists all share groups. + + :param kwargs query: Optional query parameters to be sent to limit + the share groups being returned. Available parameters include: + + * status: Filters by a share group status. + * name: The user defined name of the resource to filter resources + by. + * description: The user defined description text that can be used + to filter resources. + * project_id: The project ID of the user or service. + * share_server_id: The UUID of the share server. + * snapshot_id: The UUID of the share’s base snapshot to filter + the request based on. + * host: The host name for the back end. + * share_network_id: The UUID of the share network to filter + resources by. + * share_group_type_id: The share group type ID to filter + share groups. + * share_group_snapshot_id: The source share group snapshot ID to + list the share group. + * share_types: A list of one or more share type IDs. Allows + filtering share groups. + * limit: The maximum number of share groups members to return. + * offset: The offset to define start point of share or share + group listing. + * sort_key: The key to sort a list of shares. + * sort_dir: The direction to sort a list of shares + * name~: The name pattern that can be used to filter shares, + share snapshots, share networks or share groups. + * description~: The description pattern that can be used to + filter shares, share snapshots, share networks or share groups. + + :returns: A generator of manila share group resources + :rtype: :class:`~openstack.shared_file_system.v2. + share_group.ShareGroup` + """ + return self._list(_share_group.ShareGroup, **query) + + def get_share_group(self, share_group_id): + """Lists details for a share group. + + :param share: The ID of the share group to get + :returns: Details of the identified share group + :rtype: :class:`~openstack.shared_file_system.v2. + share_group.ShareGroup` + """ + return self._get(_share_group.ShareGroup, share_group_id) + + def find_share_group(self, name_or_id, ignore_missing=True): + """Finds a single share group + + :param name_or_id: The name or ID of a share group. + :param bool ignore_missing: When set to ``False`` + :class:`~openstack.exceptions.ResourceNotFound` will be + raised when the resource does not exist. + When set to ``True``, None will be returned when + attempting to find a nonexistent resource. + :returns: One :class:`~openstack.shared_file_system.v2. + share_group.ShareGroup` + or None + """ + return self._find( + _share_group.ShareGroup, name_or_id, ignore_missing=ignore_missing + ) + + def create_share_group(self, **attrs): + """Creates a share group from attributes + + :returns: Details of the new share group + :rtype: :class:`~openstack.shared_file_system.v2. + share_group.ShareGroup` + """ + return self._create(_share_group.ShareGroup, **attrs) + + def update_share_group(self, share_group_id, **kwargs): + """Updates details of a single share group + + :param share: The ID of the share group + :returns: Updated details of the identified share group + :rtype: :class:`~openstack.shared_file_system.v2. + share_group.ShareGroup` + """ + return self._update(_share_group.ShareGroup, share_group_id, **kwargs) + + def delete_share_group(self, share_group_id, ignore_missing=True): + """Deletes a single share group + + :param share: The ID of the share group + :returns: Result of the "delete" on share group + :rtype: :class:`~openstack.shared_file_system.v2. + share_group.ShareGroup` + """ + return self._delete( + _share_group.ShareGroup, + share_group_id, + ignore_missing=ignore_missing, + ) + def wait_for_status( self, res, status='active', failures=None, interval=2, wait=120 ): diff --git a/openstack/shared_file_system/v2/share_group.py b/openstack/shared_file_system/v2/share_group.py new file mode 100644 index 000000000..1dadbd9e4 --- /dev/null +++ b/openstack/shared_file_system/v2/share_group.py @@ -0,0 +1,56 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from openstack import resource + + +class ShareGroup(resource.Resource): + resource_key = "share_group" + resources_key = "share_groups" + base_path = "/share-groups" + + _query_mapping = resource.QueryParameters("share_group_id") + + # capabilities + allow_create = True + allow_fetch = True + allow_commit = True + allow_delete = True + allow_list = True + allow_head = False + + #: Properties + #: The availability zone ID that the share group exists within. + availability_zone = resource.Body("availability_zone", type=str) + #: The consistency snapshot support. + consistent_snapshot_support = resource.Body( + "consistent_snapshot_support", type=str + ) + #: The date and time stamp when the resource was created within the + #: service’s database. + created_at = resource.Body("created_at", type=str) + #: The user defined description of the resource. + description = resource.Body("description", type=str) + #: The ID of the project that owns the resource. + project_id = resource.Body("project_id", type=str) + #: The share group snapshot ID. + share_group_snapshot_id = resource.Body( + "share_group_snapshot_id", type=str + ) + #: The share group type ID. + share_group_type_id = resource.Body("share_group_type_id", type=str) + #: The share network ID where the resource is exported to. + share_network_id = resource.Body("share_network_id", type=str) + #: A list of share type IDs. + share_types = resource.Body("share_types", type=list) + #: The share status + status = resource.Body("status", type=str) diff --git a/openstack/tests/functional/shared_file_system/base.py b/openstack/tests/functional/shared_file_system/base.py index f319c7368..72926e901 100644 --- a/openstack/tests/functional/shared_file_system/base.py +++ b/openstack/tests/functional/shared_file_system/base.py @@ -65,3 +65,13 @@ class BaseSharedFileSystemTest(base.BaseFunctionalTest): ) self.assertIsNotNone(share_snapshot.id) return share_snapshot + + def create_share_group(self, **kwargs): + share_group = self.user_cloud.share.create_share_group(**kwargs) + self.addCleanup( + self.conn.share.delete_share_group, + share_group.id, + ignore_missing=True, + ) + self.assertIsNotNone(share_group.id) + return share_group diff --git a/openstack/tests/functional/shared_file_system/test_share_group.py b/openstack/tests/functional/shared_file_system/test_share_group.py new file mode 100644 index 000000000..cfd0bd9bb --- /dev/null +++ b/openstack/tests/functional/shared_file_system/test_share_group.py @@ -0,0 +1,66 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from openstack.shared_file_system.v2 import share_group as _share_group +from openstack.tests.functional.shared_file_system import base + + +class ShareGroupTest(base.BaseSharedFileSystemTest): + def setUp(self): + super(ShareGroupTest, self).setUp() + + self.SHARE_GROUP_NAME = self.getUniqueString() + share_grp = self.user_cloud.shared_file_system.create_share_group( + name=self.SHARE_GROUP_NAME + ) + self.user_cloud.shared_file_system.wait_for_status( + share_grp, + status='available', + failures=['error'], + interval=5, + wait=self._wait_for_timeout, + ) + self.assertIsNotNone(share_grp) + self.assertIsNotNone(share_grp.id) + self.SHARE_GROUP_ID = share_grp.id + + def test_get(self): + sot = self.user_cloud.shared_file_system.get_share_group( + self.SHARE_GROUP_ID + ) + assert isinstance(sot, _share_group.ShareGroup) + self.assertEqual(self.SHARE_GROUP_ID, sot.id) + + def test_find(self): + sot = self.user_cloud.shared_file_system.find_share_group( + self.SHARE_GROUP_NAME + ) + assert isinstance(sot, _share_group.ShareGroup) + self.assertEqual(self.SHARE_GROUP_NAME, sot.name) + self.assertEqual(self.SHARE_GROUP_ID, sot.id) + + def test_list_delete_share_group(self): + s_grps = self.user_cloud.shared_file_system.share_groups() + self.assertGreater(len(list(s_grps)), 0) + for s_grp in s_grps: + for attribute in ('id', 'name', 'created_at'): + self.assertTrue(hasattr(s_grp, attribute)) + + sot = self.conn.shared_file_system.delete_share_group(s_grp) + self.assertIsNone(sot) + + def test_update(self): + u_gp = self.user_cloud.shared_file_system.update_share_group( + self.SHARE_GROUP_ID, description='updated share group' + ) + get_u_gp = self.user_cloud.shared_file_system.get_share_group(u_gp.id) + self.assertEqual('updated share group', get_u_gp.description) diff --git a/openstack/tests/unit/shared_file_system/v2/test_proxy.py b/openstack/tests/unit/shared_file_system/v2/test_proxy.py index 18ed60a50..6fc6928d5 100644 --- a/openstack/tests/unit/shared_file_system/v2/test_proxy.py +++ b/openstack/tests/unit/shared_file_system/v2/test_proxy.py @@ -16,6 +16,7 @@ from openstack.shared_file_system.v2 import _proxy from openstack.shared_file_system.v2 import limit from openstack.shared_file_system.v2 import share from openstack.shared_file_system.v2 import share_access_rule +from openstack.shared_file_system.v2 import share_group from openstack.shared_file_system.v2 import share_instance from openstack.shared_file_system.v2 import share_network from openstack.shared_file_system.v2 import share_network_subnet @@ -417,3 +418,46 @@ class TestAccessRuleProxy(test_proxy_base.TestProxyBase): method_args=['access_id', 'share_id', 'ignore_missing'], expected_args=[self.proxy, 'share_id'], ) + + +class TestShareGroupResource(test_proxy_base.TestProxyBase): + def setUp(self): + super(TestShareGroupResource, self).setUp() + self.proxy = _proxy.Proxy(self.session) + + def test_share_groups(self): + self.verify_list(self.proxy.share_groups, share_group.ShareGroup) + + def test_share_groups_query(self): + self.verify_list( + self.proxy.share_groups, + share_group.ShareGroup, + method_kwargs={"query": 1}, + expected_kwargs={"query": 1}, + ) + + def test_share_group_get(self): + self.verify_get(self.proxy.get_share_group, share_group.ShareGroup) + + def test_share_group_find(self): + self.verify_find(self.proxy.find_share_group, share_group.ShareGroup) + + def test_share_group_delete(self): + self.verify_delete( + self.proxy.delete_share_group, share_group.ShareGroup, False + ) + + def test_share_group_delete_ignore(self): + self.verify_delete( + self.proxy.delete_share_group, share_group.ShareGroup, True + ) + + def test_share_group_create(self): + self.verify_create( + self.proxy.create_share_group, share_group.ShareGroup + ) + + def test_share_group_update(self): + self.verify_update( + self.proxy.update_share_group, share_group.ShareGroup + ) diff --git a/openstack/tests/unit/shared_file_system/v2/test_share_group.py b/openstack/tests/unit/shared_file_system/v2/test_share_group.py new file mode 100644 index 000000000..f75976ff8 --- /dev/null +++ b/openstack/tests/unit/shared_file_system/v2/test_share_group.py @@ -0,0 +1,81 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from openstack.shared_file_system.v2 import share_group +from openstack.tests.unit import base + + +EXAMPLE = { + "status": "creating", + "description": None, + "links": "[]", + "availability_zone": None, + "source_share_group_snapshot_id": None, + "share_network_id": None, + "share_server_id": None, + "host": None, + "share_group_type_id": "89861c2a-10bf-4013-bdd4-3d020466aee4", + "consistent_snapshot_support": None, + "id": "f9c1f80c-2392-4e34-bd90-fc89cdc5bf93", + "name": None, + "created_at": "2021-06-03T19:20:33.974421", + "project_id": "e23850eeb91d4fa3866af634223e454c", + "share_types": ["ecd11f4c-d811-4471-b656-c755c77e02ba"], +} + + +class TestShareGroups(base.TestCase): + def test_basic(self): + share_groups = share_group.ShareGroup() + self.assertEqual('share_groups', share_groups.resources_key) + self.assertEqual('/share-groups', share_groups.base_path) + self.assertTrue(share_groups.allow_list) + self.assertTrue(share_groups.allow_fetch) + self.assertTrue(share_groups.allow_create) + self.assertTrue(share_groups.allow_commit) + self.assertTrue(share_groups.allow_delete) + self.assertFalse(share_groups.allow_head) + + self.assertDictEqual( + { + "limit": "limit", + "marker": "marker", + "share_group_id": "share_group_id", + }, + share_groups._query_mapping._mapping, + ) + + def test_make_share_groups(self): + share_group_res = share_group.ShareGroup(**EXAMPLE) + self.assertEqual(EXAMPLE['id'], share_group_res.id) + self.assertEqual(EXAMPLE['status'], share_group_res.status) + self.assertEqual( + EXAMPLE['availability_zone'], share_group_res.availability_zone + ) + self.assertEqual(EXAMPLE['description'], share_group_res.description) + self.assertEqual( + EXAMPLE['source_share_group_snapshot_id'], + share_group_res.share_group_snapshot_id, + ) + self.assertEqual( + EXAMPLE['share_network_id'], share_group_res.share_network_id + ) + self.assertEqual( + EXAMPLE['share_group_type_id'], share_group_res.share_group_type_id + ) + self.assertEqual( + EXAMPLE['consistent_snapshot_support'], + share_group_res.consistent_snapshot_support, + ) + self.assertEqual(EXAMPLE['created_at'], share_group_res.created_at) + self.assertEqual(EXAMPLE['project_id'], share_group_res.project_id) + self.assertEqual(EXAMPLE['share_types'], share_group_res.share_types) diff --git a/releasenotes/notes/add-share_group-to-shared-file-8cee20d8aa2afbb7.yaml b/releasenotes/notes/add-share_group-to-shared-file-8cee20d8aa2afbb7.yaml new file mode 100644 index 000000000..ae76ef055 --- /dev/null +++ b/releasenotes/notes/add-share_group-to-shared-file-8cee20d8aa2afbb7.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Added support to create, update, list, get, and delete share + groups on the shared file system service.