From 5f9522986cec8eb87acff3fc8d49679a4d7b4c37 Mon Sep 17 00:00:00 2001 From: Goutham Pacha Ravi Date: Mon, 1 Feb 2021 17:37:51 -0800 Subject: [PATCH] Add shared file systems support Introduce the shared file systems storage service proxy, and add a basic service resource to list availability zones. [1] https://tree.taiga.io/project/ashrod98-openstacksdk-manila-support/us/11?kanban-status=2360120 Depends-On: Ia2e62d3a11a08adeb6d488b7c9b365f7ff2be3c8 Change-Id: I20f1f713583c53a2df7fd01af11234960c9c8291 Signed-off-by: Goutham Pacha Ravi --- doc/source/user/guides/shared_file_system.rst | 22 +++++++++ doc/source/user/index.rst | 3 ++ .../user/proxies/shared_file_system.rst | 24 ++++++++++ .../resources/shared_file_system/index.rst | 7 +++ .../v2/availability_zone.rst | 13 ++++++ examples/shared_file_system/__init__.py | 0 .../shared_file_system/availability_zones.py | 24 ++++++++++ openstack/_services_mixin.py | 3 +- openstack/cloud/_shared_file_system.py | 23 ++++++++++ openstack/connection.py | 5 +- openstack/shared_file_system/__init__.py | 0 .../shared_file_system_service.py | 21 +++++++++ openstack/shared_file_system/v2/__init__.py | 0 openstack/shared_file_system/v2/_proxy.py | 26 +++++++++++ .../v2/availability_zone.py | 36 +++++++++++++++ .../functional/shared_file_system/__init__.py | 0 .../functional/shared_file_system/base.py | 23 ++++++++++ .../test_availability_zone.py | 26 +++++++++++ openstack/tests/unit/base.py | 16 +++++++ .../unit/cloud/test_shared_file_system.py | 46 +++++++++++++++++++ .../unit/fixtures/shared-file-system.json | 28 +++++++++++ .../tests/unit/shared_file_system/__init__.py | 0 .../unit/shared_file_system/v2/__init__.py | 0 .../v2/test_availability_zone.py | 38 +++++++++++++++ ...-shared-file-systems-83a3767429fd5e8c.yaml | 8 ++++ 25 files changed, 390 insertions(+), 2 deletions(-) create mode 100644 doc/source/user/guides/shared_file_system.rst create mode 100644 doc/source/user/proxies/shared_file_system.rst create mode 100644 doc/source/user/resources/shared_file_system/index.rst create mode 100644 doc/source/user/resources/shared_file_system/v2/availability_zone.rst create mode 100644 examples/shared_file_system/__init__.py create mode 100644 examples/shared_file_system/availability_zones.py create mode 100644 openstack/cloud/_shared_file_system.py create mode 100644 openstack/shared_file_system/__init__.py create mode 100644 openstack/shared_file_system/shared_file_system_service.py create mode 100644 openstack/shared_file_system/v2/__init__.py create mode 100644 openstack/shared_file_system/v2/_proxy.py create mode 100644 openstack/shared_file_system/v2/availability_zone.py create mode 100644 openstack/tests/functional/shared_file_system/__init__.py create mode 100644 openstack/tests/functional/shared_file_system/base.py create mode 100644 openstack/tests/functional/shared_file_system/test_availability_zone.py create mode 100644 openstack/tests/unit/cloud/test_shared_file_system.py create mode 100644 openstack/tests/unit/fixtures/shared-file-system.json create mode 100644 openstack/tests/unit/shared_file_system/__init__.py create mode 100644 openstack/tests/unit/shared_file_system/v2/__init__.py create mode 100644 openstack/tests/unit/shared_file_system/v2/test_availability_zone.py create mode 100644 releasenotes/notes/add-shared-file-systems-83a3767429fd5e8c.yaml diff --git a/doc/source/user/guides/shared_file_system.rst b/doc/source/user/guides/shared_file_system.rst new file mode 100644 index 000000000..40ffc3f2a --- /dev/null +++ b/doc/source/user/guides/shared_file_system.rst @@ -0,0 +1,22 @@ +Using OpenStack Shared File Systems +=================================== + +Before working with the Shared File System service, you'll need to create a +connection to your OpenStack cloud by following the :doc:`connect` user +guide. This will provide you with the ``conn`` variable used in the examples +below. + +.. contents:: Table of Contents + :local: + + +List Availability Zones +----------------------- + +A Shared File System service **availability zone** is a failure domain for +your shared file systems. You may create a shared file system (referred +to simply as **shares**) in a given availability zone, and create replicas +of the share in other availability zones. + +.. literalinclude:: ../examples/shared_file_system/availability_zones.py + :pyobject: list_availability_zones diff --git a/doc/source/user/index.rst b/doc/source/user/index.rst index 9559f41de..a08f00416 100644 --- a/doc/source/user/index.rst +++ b/doc/source/user/index.rst @@ -48,6 +48,7 @@ approach, this is where you'll want to begin. Network Object Store Orchestration + Shared File System API Documentation ----------------- @@ -113,6 +114,7 @@ control which services can be used. Network Object Store Orchestration + Shared File System Workflow Resource Interface @@ -145,6 +147,7 @@ The following services have exposed *Resource* classes. Network Orchestration Object Store + Shared File System Workflow Low-Level Classes diff --git a/doc/source/user/proxies/shared_file_system.rst b/doc/source/user/proxies/shared_file_system.rst new file mode 100644 index 000000000..3e8ae7388 --- /dev/null +++ b/doc/source/user/proxies/shared_file_system.rst @@ -0,0 +1,24 @@ +Shared File System API +====================== + +.. automodule:: openstack.shared_file_system.v2._proxy + +The Shared File System Class +---------------------------- + +The high-level interface for accessing the shared file systems service API is +available through the ``shared_file_system`` member of a :class:`~openstack +.connection.Connection` object. The ``shared_file_system`` member will only +be added if the service is detected. ``share`` is an alias of the +``shared_file_system`` member. + + +Shared File System Availability Zones +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Interact with Availability Zones supported by the Shared File Systems +service. + +.. autoclass:: openstack.shared_file_system.v2._proxy.Proxy + :noindex: + :members: availability_zones diff --git a/doc/source/user/resources/shared_file_system/index.rst b/doc/source/user/resources/shared_file_system/index.rst new file mode 100644 index 000000000..1be3611bd --- /dev/null +++ b/doc/source/user/resources/shared_file_system/index.rst @@ -0,0 +1,7 @@ +Shared File System service resources +==================================== + +.. toctree:: + :maxdepth: 1 + + v2/availability_zone diff --git a/doc/source/user/resources/shared_file_system/v2/availability_zone.rst b/doc/source/user/resources/shared_file_system/v2/availability_zone.rst new file mode 100644 index 000000000..9a518908c --- /dev/null +++ b/doc/source/user/resources/shared_file_system/v2/availability_zone.rst @@ -0,0 +1,13 @@ +openstack.shared_file_system.v2.availability_zone +================================================= + +.. automodule:: openstack.shared_file_system.v2.availability_zone + +The AvailabilityZone Class +-------------------------- + +The ``AvailabilityZone`` class inherits from +:class:`~openstack.resource.Resource`. + +.. autoclass:: openstack.shared_file_system.v2.availability_zone.AvailabilityZone + :members: diff --git a/examples/shared_file_system/__init__.py b/examples/shared_file_system/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/examples/shared_file_system/availability_zones.py b/examples/shared_file_system/availability_zones.py new file mode 100644 index 000000000..73c0e3fb5 --- /dev/null +++ b/examples/shared_file_system/availability_zones.py @@ -0,0 +1,24 @@ +# 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. + +""" +List resources from the Shared File System service. + +For a full guide see +https://docs.openstack.org/openstacksdk/latest/user/guides/shared_file_system.html +""" + + +def list_availability_zones(conn): + print("List Shared File System Availability Zones:") + for az in conn.share.availability_zones(): + print(az) diff --git a/openstack/_services_mixin.py b/openstack/_services_mixin.py index 75c1d19e7..48f45f282 100644 --- a/openstack/_services_mixin.py +++ b/openstack/_services_mixin.py @@ -17,6 +17,7 @@ from openstack.message import message_service from openstack.network import network_service from openstack.object_store import object_store_service from openstack.orchestration import orchestration_service +from openstack.shared_file_system import shared_file_system_service from openstack.workflow import workflow_service @@ -68,7 +69,7 @@ class ServicesMixin: operator_policy = service_description.ServiceDescription(service_type='operator-policy') policy = operator_policy - shared_file_system = service_description.ServiceDescription(service_type='shared-file-system') + shared_file_system = shared_file_system_service.SharedFilesystemService(service_type='shared-file-system') share = shared_file_system data_protection_orchestration = service_description.ServiceDescription(service_type='data-protection-orchestration') diff --git a/openstack/cloud/_shared_file_system.py b/openstack/cloud/_shared_file_system.py new file mode 100644 index 000000000..9302a8a68 --- /dev/null +++ b/openstack/cloud/_shared_file_system.py @@ -0,0 +1,23 @@ +# 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.cloud import _normalize + + +class SharedFileSystemCloudMixin(_normalize.Normalizer): + + def list_share_availability_zones(self): + """List all availability zones for the Shared File Systems service. + + :returns: A list of Shared File Systems Availability Zones. + """ + return list(self.share.availability_zones()) diff --git a/openstack/connection.py b/openstack/connection.py index 7c36b9dbd..8b8994941 100644 --- a/openstack/connection.py +++ b/openstack/connection.py @@ -208,6 +208,7 @@ from openstack.cloud import _network_common from openstack.cloud import _object_store from openstack.cloud import _orchestration from openstack.cloud import _security_group +from openstack.cloud import _shared_file_system from openstack import config as _config from openstack.config import cloud_region from openstack import exceptions @@ -271,7 +272,8 @@ class Connection( _network_common.NetworkCommonCloudMixin, _object_store.ObjectStoreCloudMixin, _orchestration.OrchestrationCloudMixin, - _security_group.SecurityGroupCloudMixin + _security_group.SecurityGroupCloudMixin, + _shared_file_system.SharedFileSystemCloudMixin, ): def __init__(self, cloud=None, config=None, session=None, @@ -415,6 +417,7 @@ class Connection( _object_store.ObjectStoreCloudMixin.__init__(self) _orchestration.OrchestrationCloudMixin.__init__(self) _security_group.SecurityGroupCloudMixin.__init__(self) + _shared_file_system.SharedFileSystemCloudMixin.__init__(self) # Allow vendors to provide hooks. They will normally only receive a # connection object and a responsible to register additional services diff --git a/openstack/shared_file_system/__init__.py b/openstack/shared_file_system/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/openstack/shared_file_system/shared_file_system_service.py b/openstack/shared_file_system/shared_file_system_service.py new file mode 100644 index 000000000..bf6c7541a --- /dev/null +++ b/openstack/shared_file_system/shared_file_system_service.py @@ -0,0 +1,21 @@ +# 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 service_description +from openstack.shared_file_system.v2 import _proxy + + +class SharedFilesystemService(service_description.ServiceDescription): + """The shared file systems service.""" + supported_versions = { + '2': _proxy.Proxy, + } diff --git a/openstack/shared_file_system/v2/__init__.py b/openstack/shared_file_system/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/openstack/shared_file_system/v2/_proxy.py b/openstack/shared_file_system/v2/_proxy.py new file mode 100644 index 000000000..0f6a688c4 --- /dev/null +++ b/openstack/shared_file_system/v2/_proxy.py @@ -0,0 +1,26 @@ +# 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 proxy +from openstack.shared_file_system.v2 import availability_zone + + +class Proxy(proxy.Proxy): + + def availability_zones(self): + """Retrieve shared file system availability zones + + :returns: A generator of availability zone resources + :rtype: :class:`~openstack.shared_file_system.v2. + \availability_zone.AvailabilityZone` + """ + return self._list(availability_zone.AvailabilityZone) diff --git a/openstack/shared_file_system/v2/availability_zone.py b/openstack/shared_file_system/v2/availability_zone.py new file mode 100644 index 000000000..d05e188b3 --- /dev/null +++ b/openstack/shared_file_system/v2/availability_zone.py @@ -0,0 +1,36 @@ +# 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 AvailabilityZone(resource.Resource): + resource_key = "availability_zone" + resources_key = "availability_zones" + base_path = "/availability-zones" + + # capabilities + allow_create = False + allow_fetch = False + allow_commit = False + allow_delete = False + allow_list = True + + #: Properties + #: The ID of the availability zone + id = resource.Body("id", type=str) + #: The name of the availability zone. + name = resource.Body("name", type=str) + #: Date and time the availability zone was created at. + created_at = resource.Body("created_at", type=str) + #: Date and time the availability zone was last updated at. + updated_at = resource.Body("updated_at", type=str) diff --git a/openstack/tests/functional/shared_file_system/__init__.py b/openstack/tests/functional/shared_file_system/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/openstack/tests/functional/shared_file_system/base.py b/openstack/tests/functional/shared_file_system/base.py new file mode 100644 index 000000000..3714dcebe --- /dev/null +++ b/openstack/tests/functional/shared_file_system/base.py @@ -0,0 +1,23 @@ +# 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.tests.functional import base + + +class BaseSharedFileSystemTest(base.BaseFunctionalTest): + + min_microversion = None + + def setUp(self): + super(BaseSharedFileSystemTest, self).setUp() + self.require_service('shared-file-system', + min_microversion=self.min_microversion) diff --git a/openstack/tests/functional/shared_file_system/test_availability_zone.py b/openstack/tests/functional/shared_file_system/test_availability_zone.py new file mode 100644 index 000000000..4cb39014d --- /dev/null +++ b/openstack/tests/functional/shared_file_system/test_availability_zone.py @@ -0,0 +1,26 @@ +# 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.tests.functional.shared_file_system import base + + +class AvailabilityZoneTest(base.BaseSharedFileSystemTest): + + min_microversion = '2.7' + + def test_availability_zones(self): + azs = self.conn.shared_file_system.availability_zones() + self.assertGreater(len(list(azs)), 0) + for az in azs: + for attribute in ('id', 'name', 'created_at', 'updated_at'): + self.assertTrue(hasattr(az, attribute)) + self.assertIsInstance(getattr(az, attribute), 'str') diff --git a/openstack/tests/unit/base.py b/openstack/tests/unit/base.py index 9eb597ea5..0847577ad 100644 --- a/openstack/tests/unit/base.py +++ b/openstack/tests/unit/base.py @@ -574,6 +574,13 @@ class TestCase(base.TestCase): return dict(method='GET', uri="https://accelerator.example.com/", text=open(discovery_fixture, 'r').read()) + def get_manila_discovery_mock_dict(self): + discovery_fixture = os.path.join( + self.fixtures_directory, "shared-file-system.json") + return dict(method='GET', + uri="https://shared-file-system.example.com/", + text=open(discovery_fixture, 'r').read()) + def use_glance( self, image_version_json='image-version.json', image_discovery_url='https://image.example.com/'): @@ -630,6 +637,15 @@ class TestCase(base.TestCase): self.__do_register_uris([ self.get_cyborg_discovery_mock_dict()]) + def use_manila(self): + # NOTE(gouthamr): This method is only meant to be used in "setUp" + # where the ordering of the url being registered is tightly controlled + # if the functionality of .use_manila is meant to be used during an + # actual test case, use .get_manila_discovery_mock and apply to the + # right location in the mock_uris when calling .register_uris + self.__do_register_uris([ + self.get_manila_discovery_mock_dict()]) + def register_uris(self, uri_mock_list=None): """Mock a list of URIs and responses via requests mock. diff --git a/openstack/tests/unit/cloud/test_shared_file_system.py b/openstack/tests/unit/cloud/test_shared_file_system.py new file mode 100644 index 000000000..2c87f4678 --- /dev/null +++ b/openstack/tests/unit/cloud/test_shared_file_system.py @@ -0,0 +1,46 @@ +# 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.tests.unit import base +import uuid + +IDENTIFIER = str(uuid.uuid4()) +MANILA_AZ_DICT = { + "id": IDENTIFIER, + "name": "manila-zone-0", + "created_at": "2021-01-21T20:13:55.000000", + "updated_at": None, +} + + +class TestSharedFileSystem(base.TestCase): + + def setUp(self): + super(TestSharedFileSystem, self).setUp() + self.use_manila() + + def test_list_availability_zones(self): + self.register_uris([ + dict(method='GET', + uri=self.get_mock_url( + 'shared-file-system', + 'public', + append=['v2', 'availability-zones']), + json={'availability_zones': [MANILA_AZ_DICT]}), + ]) + az_list = self.cloud.list_share_availability_zones() + self.assertEqual(len(az_list), 1) + self.assertEqual(MANILA_AZ_DICT['id'], az_list[0].id) + self.assertEqual(MANILA_AZ_DICT['name'], az_list[0].name) + self.assertEqual(MANILA_AZ_DICT['created_at'], az_list[0].created_at) + self.assertEqual(MANILA_AZ_DICT['updated_at'], az_list[0].updated_at) + self.assert_calls() diff --git a/openstack/tests/unit/fixtures/shared-file-system.json b/openstack/tests/unit/fixtures/shared-file-system.json new file mode 100644 index 000000000..3d22f6e5c --- /dev/null +++ b/openstack/tests/unit/fixtures/shared-file-system.json @@ -0,0 +1,28 @@ +{ + "versions": [ + { + "id": "v2.0", + "status": "CURRENT", + "version": "2.58", + "min_version": "2.0", + "updated": "2015-08-27T11:33:21Z", + "links": [ + { + "rel": "describedby", + "type": "text/html", + "href": "http://docs.openstack.org/" + }, + { + "rel": "self", + "href": "https://shared-file-system.example.com/v2/" + } + ], + "media-types": [ + { + "base": "application/json", + "type": "application/vnd.openstack.share+json;version=1" + } + ] + } + ] +} \ No newline at end of file diff --git a/openstack/tests/unit/shared_file_system/__init__.py b/openstack/tests/unit/shared_file_system/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/openstack/tests/unit/shared_file_system/v2/__init__.py b/openstack/tests/unit/shared_file_system/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/openstack/tests/unit/shared_file_system/v2/test_availability_zone.py b/openstack/tests/unit/shared_file_system/v2/test_availability_zone.py new file mode 100644 index 000000000..d37a7328f --- /dev/null +++ b/openstack/tests/unit/shared_file_system/v2/test_availability_zone.py @@ -0,0 +1,38 @@ +# 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 availability_zone as az +from openstack.tests.unit import base + +IDENTIFIER = '08a87d37-5ca2-4308-86c5-cba06d8d796c' +EXAMPLE = { + "id": IDENTIFIER, + "name": "nova", + "created_at": "2021-01-21T20:13:55.000000", + "updated_at": None, +} + + +class TestAvailabilityZone(base.TestCase): + + def test_basic(self): + az_resource = az.AvailabilityZone() + self.assertEqual('availability_zones', az_resource.resources_key) + self.assertEqual('/availability-zones', az_resource.base_path) + self.assertTrue(az_resource.allow_list) + + def test_make_availability_zone(self): + az_resource = az.AvailabilityZone(**EXAMPLE) + self.assertEqual(EXAMPLE['id'], az_resource.id) + self.assertEqual(EXAMPLE['name'], az_resource.name) + self.assertEqual(EXAMPLE['created_at'], az_resource.created_at) + self.assertEqual(EXAMPLE['updated_at'], az_resource.updated_at) diff --git a/releasenotes/notes/add-shared-file-systems-83a3767429fd5e8c.yaml b/releasenotes/notes/add-shared-file-systems-83a3767429fd5e8c.yaml new file mode 100644 index 000000000..9f770db32 --- /dev/null +++ b/releasenotes/notes/add-shared-file-systems-83a3767429fd5e8c.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + Support for the OpenStack Shared File System API (manila) has been + introduced. + - | + Added support to list Shared File System Service API Versions + and Availability Zones.