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 <gouthampravi@gmail.com>
This commit is contained in:
Goutham Pacha Ravi 2021-02-01 17:37:51 -08:00
parent 39d3529775
commit 5f9522986c
25 changed files with 390 additions and 2 deletions

View File

@ -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

View File

@ -48,6 +48,7 @@ approach, this is where you'll want to begin.
Network <guides/network>
Object Store <guides/object_store>
Orchestration <guides/orchestration>
Shared File System <guides/shared_file_system>
API Documentation
-----------------
@ -113,6 +114,7 @@ control which services can be used.
Network <proxies/network>
Object Store <proxies/object_store>
Orchestration <proxies/orchestration>
Shared File System <proxies/shared_file_system>
Workflow <proxies/workflow>
Resource Interface
@ -145,6 +147,7 @@ The following services have exposed *Resource* classes.
Network <resources/network/index>
Orchestration <resources/orchestration/index>
Object Store <resources/object_store/index>
Shared File System <resources/shared_file_system/index>
Workflow <resources/workflow/index>
Low-Level Classes

View File

@ -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

View File

@ -0,0 +1,7 @@
Shared File System service resources
====================================
.. toctree::
:maxdepth: 1
v2/availability_zone

View File

@ -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:

View File

View File

@ -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)

View File

@ -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')

View File

@ -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())

View File

@ -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

View File

View File

@ -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,
}

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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')

View File

@ -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.

View File

@ -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()

View File

@ -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"
}
]
}
]
}

View File

@ -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)

View File

@ -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.