Add share group snapshots to shared file systems.

Introduce Share Group Snapshot class with basic methods including list,
create, delete, get and update to shared file system storage service.

Change-Id: Ice8750dcf07ff436ba8d9e9cf5e8cb183b5b3825
This commit is contained in:
Ashley Rodriguez 2022-05-12 20:07:42 +00:00
parent 010d89dc53
commit 1e478342b7
11 changed files with 567 additions and 0 deletions

View File

@ -20,3 +20,67 @@ of the share in other availability zones.
.. literalinclude:: ../examples/shared_file_system/availability_zones.py
:pyobject: list_availability_zones
List Share Group Snapshots
--------------------------
A share group snapshot is a point-in-time, read-only copy of the data that is
contained in a share group. You can list all share group snapshots
.. literalinclude:: ../examples/shared_file_system/share_group_snapshots.py
:pyobject: list_share_group_snapshots
Get Share Group Snapshot
------------------------
Show share group snapshot details
.. literalinclude:: ../examples/shared_file_system/share_group_snapshots.py
:pyobject: get_share_group_snapshot
List Share Group Snapshot Members
---------------------------------
Lists all share group snapshots members.
.. literalinclude:: ../examples/shared_file_system/share_group_snapshots.py
:pyobject: share_group_snapshot_members
Create Share Group Snapshot
---------------------------
Creates a snapshot from a share.
.. literalinclude:: ../examples/shared_file_system/share_group_snapshots.py
:pyobject: create_share_group_snapshot
Reset Share Group Snapshot
---------------------------
Reset share group snapshot state.
.. literalinclude:: ../examples/shared_file_system/share_group_snapshots.py
:pyobject: reset_share_group_snapshot_status
Update Share Group Snapshot
---------------------------
Updates a share group snapshot.
.. literalinclude:: ../examples/shared_file_system/share_group_snapshots.py
:pyobject: update_share_group_snapshot
Delete Share Group Snapshot
---------------------------
Deletes a share group snapshot.
.. literalinclude:: ../examples/shared_file_system/share_group_snapshots.py
:pyobject: delete_share_group_snapshot

View File

@ -100,3 +100,16 @@ service.
:noindex:
:members: share_groups, get_share_group, delete_share_group,
update_share_group, create_share_group, find_share_group
Shared File System Share Group Snapshots
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Interact with Share Group Snapshots by the Shared File Systems
service.
.. autoclass:: openstack.shared_file_system.v2._proxy.Proxy
:noindex:
:members: share_group_snapshots, get_share_group_snapshot, create_share_group_snapshot,
reset_share_group_snapshot_status, update_share_group_snapshot,
delete_share_group_snapshot

View File

@ -12,3 +12,4 @@ Shared File System service resources
v2/share_snapshot
v2/share_access_rule
v2/share_group
v2/share_group_snapshot

View File

@ -0,0 +1,13 @@
openstack.shared_file_system.v2.share_group_snapshot
====================================================
.. automodule: : openstack.shared_file_system.v2.share_group_snapshot
The ShareGroupSnapshot Class
----------------------------
The ``ShareGroupSnapshot`` class inherits from
: class: `~openstack.resource.Resource`.
.. autoclass: : openstack.shared_file_system.v2.ShareGroupSnapshot
:members:

View File

@ -0,0 +1,64 @@
# 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_share_group_snapshots(conn, **query):
print("List all share group snapshots:")
share_group_snapshots = conn.share.share_group_snapshots(**query)
for share_group_snapshot in share_group_snapshots:
print(share_group_snapshot)
def get_share_group_snapshot(conn, group_snapshot_id):
print("Show share group snapshot with given Id:")
share_group_snapshot = conn.share.get_share_group_snapshots(
group_snapshot_id)
print(share_group_snapshot)
def share_group_snapshot_members(conn, group_snapshot_id):
print("Show share group snapshot members with given Id:")
members = conn.share.share_group_snapshot_members(
group_snapshot_id)
for member in members:
print(member)
def create_share_group_snapshot(conn, share_group_id, **attrs):
print("Creating a share group snapshot from given attributes:")
share_group_snapshot = conn.share.create_share_group_snapshot(
share_group_id, **attrs)
print(share_group_snapshot)
def reset_share_group_snapshot_status(conn, group_snapshot_id, status):
print("Reseting the share group snapshot status:")
conn.share.reset_share_group_snapshot_status(group_snapshot_id, status)
def update_share_group_snapshot(conn, group_snapshot_id, **attrs):
print("Updating a share group snapshot with given Id:")
share_group_snapshot = conn.share.update_share_group_snapshot(
group_snapshot_id, **attrs)
print(share_group_snapshot)
def delete_share_group_snapshot(conn, group_snapshot_id):
print("Deleting a share group snapshot with given Id:")
conn.share.delete_share_group_snapshot(group_snapshot_id)

View File

@ -20,6 +20,8 @@ from openstack.shared_file_system.v2 import (
from openstack.shared_file_system.v2 import (
share_group as _share_group
)
from openstack.shared_file_system.v2 import (
share_group_snapshot as _share_group_snapshot)
from openstack.shared_file_system.v2 import (
share_snapshot as _share_snapshot
)
@ -445,3 +447,106 @@ class Proxy(proxy.Proxy):
"""
return self._get(
_share_access_rule.ShareAccessRule, access_id)
def share_group_snapshots(self, details=True, **query):
"""Lists all share group snapshots.
:param kwargs query: Optional query parameters to be sent
to limit the share group snapshots being returned.
Available parameters include:
* project_id: The ID of the project that owns the resource.
* name: The user defined name of the resource to filter resources.
* description: The user defined description text that can be used
to filter resources.
* status: Filters by a share status
* share_group_id: The UUID of a share group to filter resource.
* limit: The maximum number of share group snapshot 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. A valid
value is asc, or desc.
:returns: Details of share group snapshots resources
:rtype: :class:`~openstack.shared_file_system.v2.
share_group_snapshot.ShareGroupSnapshot`
"""
base_path = '/share-group-snapshots/detail' if details else None
return self._list(
_share_group_snapshot.ShareGroupSnapshot,
base_path=base_path, **query)
def share_group_snapshot_members(self, group_snapshot_id):
"""Lists all share group snapshots members.
:param group_snapshot_id: The ID of the group snapshot to get
:returns: List of the share group snapshot members, which are
share snapshots.
:rtype: :dict: Attributes of the share snapshots.
"""
res = self._get(
_share_group_snapshot.ShareGroupSnapshot, group_snapshot_id)
response = res.members(self)
return response
def get_share_group_snapshot(self, group_snapshot_id):
"""Show share group snapshot details
:param group_snapshot_id: The ID of the group snapshot to get
:returns: Details of the group snapshot
:rtype: :class:`~openstack.shared_file_system.v2.
share_group_snapshot.ShareGroupSnapshot`
"""
return self._get(
_share_group_snapshot.ShareGroupSnapshot, group_snapshot_id)
def create_share_group_snapshot(self, share_group_id, **attrs):
"""Creates a point-in-time snapshot copy of a share group.
:returns: Details of the new snapshot
:param dict attrs: Attributes which will be used to create
a :class:`~openstack.shared_file_system.v2.
share_group_snapshots.ShareGroupSnapshots`,
'share_group_id' are required to create a share.
:rtype: :class:`~openstack.shared_file_system.v2.
share_group_snapshot.ShareGroupSnapshot`
"""
return self._create(_share_group_snapshot.ShareGroupSnapshot,
share_group_id=share_group_id, **attrs)
def reset_share_group_snapshot_status(self, group_snapshot_id, status):
"""Reset share group snapshot state.
:param group_snapshot_id: The ID of the share group snapshot to reset
:param status: The state of the server to be set, A valid value is
"creating", "error", "available", "deleting", "error_deleting".
:rtype: ``None``
"""
res = self._get(
_share_group_snapshot.ShareGroupSnapshot, group_snapshot_id)
res.reset_status(self, status)
def update_share_group_snapshot(self, group_snapshot_id, **attrs):
"""Updates a share group snapshot.
:param group_snapshot_id: The ID of the share group snapshot to update
:param dict attrs: The attributes to update on the share group snapshot
:returns: the updated share group snapshot
:rtype: :class:`~openstack.shared_file_system.v2.
share_group_snapshot.ShareGroupSnapshot`
"""
return self._update(_share_group_snapshot.ShareGroupSnapshot,
group_snapshot_id, **attrs)
def delete_share_group_snapshot(
self, group_snapshot_id, ignore_missing=True):
"""Deletes a share group snapshot.
:param group_snapshot_id: The ID of the share group snapshot to delete
:rtype: ``None``
"""
self._delete(_share_group_snapshot.ShareGroupSnapshot,
group_snapshot_id,
ignore_missing=ignore_missing)

View File

@ -0,0 +1,83 @@
# 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
from openstack import utils
class ShareGroupSnapshot(resource.Resource):
resource_key = "share_group_snapshot"
resources_key = "share_group_snapshots"
base_path = "/share-group-snapshots"
# capabilities
allow_create = True
allow_fetch = True
allow_commit = True
allow_delete = True
allow_list = True
allow_head = False
_query_mapping = resource.QueryParameters(
'project_id', 'all_tenants', 'name', 'description',
'status', 'share_group_id', 'limit', 'offset',
'sort_key', 'sort_dir'
)
# Share group snapshots were considered non-experimental
# since API version 2.55
_max_microversion = '2.55'
#: Properties
#: The ID of the project that owns the resource.
project_id = resource.Body("project_id", type=str)
#: Filters by a share group snapshot status. A valid value is creating,
#: error, available, deleting, error_deleting.
status = resource.Body("status", type=str)
#: The UUID of the share group.
share_group_id = resource.Body("share_group_id", type=str)
#: The user defined description of the resource.
description = resource.Body("description", type=str)
#: The date and time stamp when the resource was created.
created_at = resource.Body("created_at", type=str)
#: The share group snapshot members.
members = resource.Body("members", type=str)
#: The snapshot size, in GiBs.
size = resource.Body("size", type=int)
#: NFS, CIFS, GlusterFS, HDFS, CephFS or MAPRFS.
share_protocol = resource.Body("share_proto", type=str)
#: The share group snapshot ID.
# share_group_snapshot_id
#: The UUID of the source share that was used to create the snapshot.
share_id = resource.Body("share_id", type=str)
def _action(self, session, body):
"""Perform ShareGroupSnapshot actions given the message body."""
# NOTE: This is using ShareGroupSnapshot.base_path instead of
# self.base_path as ShareGroupSnapshot instances can be acted on,
# but the URL used is sans any additional /detail/ part.
url = utils.urljoin(self.base_path, self.id, 'action')
headers = {'Accept': ''}
session.post(
url, json=body, headers=headers,
microversion=self._max_microversion)
def reset_status(self, session, status):
body = {"reset_status": {"status": status}}
self._action(session, body)
def members(self, session):
url = utils.urljoin(self.base_path, self.id, 'members')
headers = {'Accept': ''}
response = session.get(
url, headers=headers, microversion=self._max_microversion)
return response.json()

View File

@ -0,0 +1,101 @@
# 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
from openstack.shared_file_system.v2 import (
share_group_snapshot as _share_group_snapshot
)
from openstack.tests.functional.shared_file_system import base
class ShareGroupSnapshotTest(base.BaseSharedFileSystemTest):
min_microversion = '2.55'
def setUp(self):
super(ShareGroupSnapshotTest, self).setUp()
self.SHARE_GROUP_NAME = self.getUniqueString()
share_grp = self.operator_cloud.shared_file_system.create_share_group(
name=self.SHARE_GROUP_NAME)
self.operator_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
self.SHARE_GROUP_SNAPSHOT_NAME = self.getUniqueString()
grp_ss = self.operator_cloud.shared_file_system.\
create_share_group_snapshot(
self.SHARE_GROUP_ID,
name=self.SHARE_GROUP_SNAPSHOT_NAME)
self.operator_cloud.shared_file_system.wait_for_status(
grp_ss,
status='available',
failures=['error'],
interval=5,
wait=self._wait_for_timeout)
self.assertIsNotNone(grp_ss)
self.assertIsNotNone(grp_ss.id)
self.SHARE_GROUP_SNAPSHOT_ID = grp_ss.id
def tearDown(self):
sot = self.operator_cloud.shared_file_system.get_share_group_snapshot(
self.SHARE_GROUP_SNAPSHOT_ID)
self.operator_cloud.shared_file_system.delete_share_group_snapshot(
self.SHARE_GROUP_SNAPSHOT_ID,
ignore_missing=False)
resource.wait_for_delete(self.operator_cloud.share, sot,
wait=self._wait_for_timeout,
interval=2)
self.operator_cloud.shared_file_system.delete_share_group(
self.SHARE_GROUP_ID,
ignore_missing=False)
super(ShareGroupSnapshotTest, self).tearDown()
def test_get(self):
sot = self.operator_cloud.shared_file_system.get_share_group_snapshot(
self.SHARE_GROUP_SNAPSHOT_ID)
assert isinstance(sot, _share_group_snapshot.ShareGroupSnapshot)
self.assertEqual(self.SHARE_GROUP_SNAPSHOT_ID, sot.id)
def test_list(self):
snapshots = self.operator_cloud.shared_file_system.\
share_group_snapshots()
self.assertGreater(len(list(snapshots)), 0)
for snapshot in snapshots:
for attribute in ('id', 'name', 'created_at'):
self.assertTrue(hasattr(snapshot, attribute))
def test_update(self):
u_ss = self.operator_cloud.shared_file_system.\
update_share_group_snapshot(
self.SHARE_GROUP_SNAPSHOT_ID,
description='updated share group snapshot')
get_u_ss = self.operator_cloud.shared_file_system.\
get_share_group_snapshot(
u_ss.id)
self.assertEqual('updated share group snapshot',
get_u_ss.description)
def test_reset(self):
res = self.operator_cloud.shared_file_system.\
reset_share_group_snapshot_status(
self.SHARE_GROUP_SNAPSHOT_ID, 'error')
self.assertIsNone(res)
sot = self.operator_cloud.shared_file_system.get_share_group_snapshot(
self.SHARE_GROUP_SNAPSHOT_ID)
self.assertEqual('error', sot.status)

View File

@ -19,6 +19,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_group
from openstack.shared_file_system.v2 import share_group_snapshot
from openstack.shared_file_system.v2 import share_snapshot
from openstack.shared_file_system.v2 import storage_pool
from openstack.shared_file_system.v2 import user_message
@ -235,3 +236,23 @@ class TestShareGroupResource(test_proxy_base.TestProxyBase):
def test_share_group_update(self):
self.verify_update(
self.proxy.update_share_group, share_group.ShareGroup)
def test_share_group_snapshots(self):
self.verify_list(self.proxy.share_group_snapshots,
share_group_snapshot.ShareGroupSnapshot)
def test_share_group_snapshot_get(self):
self.verify_get(self.proxy.get_share_group_snapshot,
share_group_snapshot.ShareGroupSnapshot)
def test_share_group_snapshot_update(self):
self.verify_update(self.proxy.update_share_group_snapshot,
share_group_snapshot.ShareGroupSnapshot)
def test_share_group_snapshot_delete(self):
self.verify_delete(self.proxy.delete_share_group_snapshot,
share_group_snapshot.ShareGroupSnapshot, False)
def test_share_group_snapshot_delete_ignore(self):
self.verify_delete(self.proxy.delete_share_group_snapshot,
share_group_snapshot.ShareGroupSnapshot, True)

View File

@ -0,0 +1,97 @@
# 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 unittest import mock
from keystoneauth1 import adapter
from openstack.shared_file_system.v2 import share_group_snapshot
from openstack.tests.unit import base
IDENTIFIER = '38152b6d-e1b5-465f-91bc-20bca4676a2a'
EXAMPLE = {
"id": IDENTIFIER,
"name": "snapshot_1",
"created_at": "2021-10-24T19:36:49.555325",
"status": "available",
"description": "first snapshot of sg-1",
"project_id": "7343d2f7770b4eb6a7bc33f44dcee1e0",
"share_group_id": "fb41512f-7c49-4304-afb1-66573c7feb14",
}
class TestShareGroupSnapshot(base.TestCase):
def test_basic(self):
share_group_snapshots = share_group_snapshot.ShareGroupSnapshot()
self.assertEqual('share_group_snapshot',
share_group_snapshots.resource_key)
self.assertEqual('share_group_snapshots',
share_group_snapshots.resources_key)
self.assertEqual('/share-group-snapshots',
share_group_snapshots.base_path)
self.assertTrue(share_group_snapshots.allow_create)
self.assertTrue(share_group_snapshots.allow_fetch)
self.assertTrue(share_group_snapshots.allow_commit)
self.assertTrue(share_group_snapshots.allow_delete)
self.assertTrue(share_group_snapshots.allow_list)
self.assertFalse(share_group_snapshots.allow_head)
def test_make_share_groups(self):
share_group_snapshots = share_group_snapshot.ShareGroupSnapshot(
**EXAMPLE)
self.assertEqual(EXAMPLE['id'], share_group_snapshots.id)
self.assertEqual(EXAMPLE['name'], share_group_snapshots.name)
self.assertEqual(EXAMPLE['created_at'],
share_group_snapshots.created_at)
self.assertEqual(EXAMPLE['status'], share_group_snapshots.status)
self.assertEqual(EXAMPLE['description'],
share_group_snapshots.description)
self.assertEqual(EXAMPLE['project_id'],
share_group_snapshots.project_id)
self.assertEqual(EXAMPLE['share_group_id'],
share_group_snapshots.share_group_id)
class TestShareGroupSnapshotActions(TestShareGroupSnapshot):
def setUp(self):
super(TestShareGroupSnapshot, self).setUp()
self.resp = mock.Mock()
self.resp.body = None
self.resp.status_code = 200
self.resp.json = mock.Mock(return_value=self.resp.body)
self.sess = mock.Mock(spec=adapter.Adapter)
self.sess.default_microversion = '3.0'
self.sess.post = mock.Mock(return_value=self.resp)
self.sess._get_connection = mock.Mock(return_value=self.cloud)
def test_reset_status(self):
sot = share_group_snapshot.ShareGroupSnapshot(
**EXAMPLE)
self.assertIsNone(sot.reset_status(self.sess, 'available'))
url = f'share-group-snapshots/{IDENTIFIER}/action'
body = {"reset_status": {"status": 'available'}}
headers = {'Accept': ''}
self.sess.post.assert_called_with(
url, json=body, headers=headers,
microversion=sot._max_microversion)
def test_get_members(self):
sot = share_group_snapshot.ShareGroupSnapshot(
**EXAMPLE)
sot.members(self.sess)
url = f'share-group-snapshots/{IDENTIFIER}/members'
headers = {'Accept': ''}
self.sess.get.assert_called_with(
url, headers=headers,
microversion=sot._max_microversion)

View File

@ -0,0 +1,5 @@
---
features:
- |
Added support for list, show, update, delete, reset and create
Share Group Snapshots for Shared File Systems service.