Skip to content

Commit fe0ff03

Browse files
committed
Gateway Share - Add APIs for directly managing NFS Trusted Clients
Mimic the Share ACL functionality
1 parent f8b3536 commit fe0ff03

File tree

3 files changed

+181
-3
lines changed

3 files changed

+181
-3
lines changed

cterasdk/edge/shares.py

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from ..common import Object
66
from ..exception import CTERAException, InputError
77
from .base_command import BaseCommand
8-
from .types import ShareAccessControlEntry, RemoveShareAccessControlEntry
8+
from .types import NFSv3AccessControlEntry, RemoveNFSv3AccessControlEntry, ShareAccessControlEntry, RemoveShareAccessControlEntry
99

1010

1111
class Shares(BaseCommand):
@@ -269,6 +269,73 @@ def delete(self, name):
269269
logging.getLogger().error("Share deletion failed.")
270270
raise CTERAException('Share deletion failed', error)
271271

272+
def get_trusted_nfs_clients(self, name):
273+
"""
274+
Get the current trusted NFS client entries from an existing share.
275+
276+
:param str name: The share name
277+
"""
278+
return self._gateway.get('/config/fileservices/share/' + name + '/trustedNFSClients')
279+
280+
def set_trusted_nfs_clients(self, name, trusted_nfs_clients):
281+
"""
282+
Set a network share's trusted NFS client entries.
283+
284+
:param str name: The share name
285+
:param list[cterasdk.edge.types.NFSv3AccessControlEntry] trusted_nfs_clients: Trusted NFS v3 clients
286+
287+
.. warning:: this method will override the existing access control entries
288+
"""
289+
Shares._validate_trusted_nfs_clients(trusted_nfs_clients)
290+
291+
param = [client.to_server_object() for client in (trusted_nfs_clients or [])]
292+
self._gateway.put('/config/fileservices/share/' + name + '/trustedNFSClients', param)
293+
294+
def add_trusted_nfs_clients(self, name, trusted_nfs_clients):
295+
"""
296+
Add one or more trusted NFS client entries to an existing share.
297+
298+
:param str name: The share name
299+
:param list[cterasdk.edge.types.NFSv3AccessControlEntry] trusted_nfs_clients: Trusted NFS v3 clients
300+
"""
301+
Shares._validate_trusted_nfs_clients(trusted_nfs_clients)
302+
303+
new_trusted_nfs_clients_dict = {
304+
trusted_nfs_client.address + '#' + trusted_nfs_client.netmask: trusted_nfs_client.to_server_object()
305+
for trusted_nfs_client in trusted_nfs_clients
306+
}
307+
308+
def entry_not_in_new(entry):
309+
trusted_nfs_client = NFSv3AccessControlEntry.from_server_object(entry)
310+
entry_key = trusted_nfs_client.address + '#' + trusted_nfs_client.netmask
311+
return entry_key not in new_trusted_nfs_clients_dict
312+
313+
param = list(new_trusted_nfs_clients_dict.values()) + list(filter(entry_not_in_new, self.get_trusted_nfs_clients(name)))
314+
315+
self._gateway.put('/config/fileservices/share/' + name + '/trustedNFSClients', param)
316+
317+
def remove_trusted_nfs_clients(self, name, trusted_nfs_clients):
318+
"""
319+
Remove one or more trusted NFS client entries from an existing share.
320+
321+
:param str name: The share name
322+
:param list[cterasdk.edge.types.RemoveNFSv3AccessControlEntry] trusted_nfs_clients: Trusted NFS v3 clients
323+
"""
324+
Shares._validate_remove_trusted_nfs_clients(trusted_nfs_clients)
325+
326+
remove_trusted_nfs_clients_dict = {
327+
trusted_nfs_client.address + '#' + trusted_nfs_client.netmask
328+
for trusted_nfs_client in trusted_nfs_clients
329+
}
330+
331+
def entry_not_removed(entry):
332+
trusted_nfs_client = NFSv3AccessControlEntry.from_server_object(entry)
333+
entry_key = trusted_nfs_client.address + '#' + trusted_nfs_client.netmask
334+
return entry_key not in remove_trusted_nfs_clients_dict
335+
336+
param = list(filter(entry_not_removed, self.get_trusted_nfs_clients(name)))
337+
self._gateway.put('/config/fileservices/share/' + name + '/trustedNFSClients', param)
338+
272339
def _validate_root_directory(self, name):
273340
param = Object()
274341
param.path = '/'
@@ -303,3 +370,31 @@ def _validate_remove_acl(acl):
303370
repr(acl_entry),
304371
'cterasdk.edge.types.RemoveShareAccessControlEntry'
305372
)
373+
374+
@staticmethod
375+
def _validate_trusted_nfs_clients(trusted_nfs_clients):
376+
if not isinstance(trusted_nfs_clients, list):
377+
raise InputError(
378+
'Invalid Trusted NFS Clients list format',
379+
repr(trusted_nfs_clients),
380+
'[cterasdk.edge.types.NFSv3AccessControlEntry, ...]'
381+
)
382+
for entry in trusted_nfs_clients:
383+
if not isinstance(entry, NFSv3AccessControlEntry):
384+
raise InputError('Invalid Trusted NFS Clients entry format', repr(entry), 'cterasdk.edge.types.NFSv3AccessControlEntry')
385+
386+
@staticmethod
387+
def _validate_remove_trusted_nfs_clients(trusted_nfs_clients):
388+
if not isinstance(trusted_nfs_clients, list):
389+
raise InputError(
390+
'Invalid Trusted NFS Clients list format',
391+
repr(trusted_nfs_clients),
392+
'[cterasdk.edge.types.RemoveNFSv3AccessControlEntry, ...]'
393+
)
394+
for entry in trusted_nfs_clients:
395+
if not isinstance(entry, RemoveNFSv3AccessControlEntry):
396+
raise InputError(
397+
'Invalid Trusted NFS Clients entry format',
398+
repr(entry),
399+
'cterasdk.edge.types.RemoveNFSv3AccessControlEntry'
400+
)

cterasdk/edge/types.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,26 @@ def __str__(self):
143143
return str(dict(address=self.address, netmask=self.netmask, permission=self.perm))
144144

145145

146+
class RemoveNFSv3AccessControlEntry():
147+
"""
148+
Object holding address and netmasak for NFS v3 export access control entry
149+
:ivar str address: IP address, hostname or fully qualified domain name of client machine
150+
:ivar str netmask: Subnet mask
151+
"""
152+
153+
def __init__(self, address, netmask):
154+
self._address = address
155+
self._netmask = netmask
156+
157+
@property
158+
def address(self):
159+
return self._address
160+
161+
@property
162+
def netmask(self):
163+
return self._netmask
164+
165+
146166
class ShareAccessControlEntry():
147167
"""
148168
Share access control entry for filer shares

tests/ut/test_edge_shares.py

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
from cterasdk import exception
44
from cterasdk.edge import shares
55
from cterasdk.edge.enum import Acl, ClientSideCaching, PrincipalType, FileAccessMode
6-
from cterasdk.edge.types import ShareAccessControlEntry, NFSv3AccessControlEntry
6+
from cterasdk.edge.types import ShareAccessControlEntry, NFSv3AccessControlEntry, RemoveNFSv3AccessControlEntry
77
from cterasdk.common import Object
88
from tests.ut import base_edge
99

1010

11-
class TestEdgeShares(base_edge.BaseEdgeTest):
11+
class TestEdgeShares(base_edge.BaseEdgeTest): # pylint: disable=too-many-public-methods
1212

1313
def setUp(self):
1414
super().setUp()
@@ -251,3 +251,66 @@ def test_get_acl(self):
251251
@staticmethod
252252
def _get_acl_object():
253253
return ShareAccessControlEntry(principal_type=PrincipalType.LG, name='Everyone', perm=FileAccessMode.RO)
254+
255+
def test_get_trusted_nfs_clients(self):
256+
share_name = 'share'
257+
get_response = self._get_get_trusted_nfs_client_object()
258+
self._init_filer(get_response=[get_response.to_server_object()])
259+
trusted_nfs_clients = shares.Shares(self._filer).get_trusted_nfs_clients(share_name)
260+
self._filer.get.assert_called_once_with('/config/fileservices/share/' + share_name + '/trustedNFSClients')
261+
self._assert_equal_objects(NFSv3AccessControlEntry.from_server_object(trusted_nfs_clients[0]), get_response)
262+
263+
def test_set_trusted_nfs_clients(self):
264+
share_name = 'share'
265+
new_trusted_nfs_clients = self._get_get_trusted_nfs_client_object()
266+
self._init_filer()
267+
shares.Shares(self._filer).set_trusted_nfs_clients(share_name, [new_trusted_nfs_clients])
268+
self._filer.put.assert_called_once_with('/config/fileservices/share/' + share_name + '/trustedNFSClients', mock.ANY)
269+
expected_param = new_trusted_nfs_clients.to_server_object()
270+
actual_param = self._filer.put.call_args[0][1][0]
271+
self._assert_equal_objects(actual_param, expected_param)
272+
273+
def test_add_trusted_nfs_clients(self):
274+
share_name = 'share'
275+
current_trusted_nfs_clients = self._get_get_trusted_nfs_client_object()
276+
self._init_filer(get_response=[current_trusted_nfs_clients.to_server_object()])
277+
278+
new_trusted_nfs_clients = self._get_get_trusted_nfs_client_object(address="192.168.0.0")
279+
shares.Shares(self._filer).add_trusted_nfs_clients(share_name, [new_trusted_nfs_clients])
280+
self._filer.put.assert_called_once_with('/config/fileservices/share/' + share_name + '/trustedNFSClients', mock.ANY)
281+
282+
def get_address(elem):
283+
return elem.address
284+
285+
actual_param = self._filer.put.call_args[0][1]
286+
actual_param.sort(key=get_address)
287+
288+
expected_param = [current_trusted_nfs_clients.to_server_object(), new_trusted_nfs_clients.to_server_object()]
289+
expected_param.sort(key=get_address)
290+
291+
self.assertEqual(len(expected_param), len(actual_param))
292+
293+
for i in range(len(actual_param)): # pylint: disable=consider-using-enumerate
294+
self._assert_equal_objects(actual_param[i], expected_param[i])
295+
296+
def test_remove_trusted_nfs_clients(self):
297+
share_name = 'share'
298+
trusted_nfs_client_to_keep = self._get_get_trusted_nfs_client_object(address="192.168.0.0")
299+
trusted_nfs_client_to_remove = self._get_get_trusted_nfs_client_object(address="192.168.1.0")
300+
self._init_filer(get_response=[trusted_nfs_client_to_keep.to_server_object(), trusted_nfs_client_to_remove.to_server_object()])
301+
302+
shares.Shares(self._filer).remove_trusted_nfs_clients(
303+
share_name,
304+
[
305+
RemoveNFSv3AccessControlEntry(trusted_nfs_client_to_remove.address, trusted_nfs_client_to_remove.netmask)
306+
]
307+
)
308+
self._filer.put.assert_called_once_with('/config/fileservices/share/' + share_name + '/trustedNFSClients', mock.ANY)
309+
310+
expected_param = trusted_nfs_client_to_keep.to_server_object()
311+
actual_param = self._filer.put.call_args[0][1][0]
312+
self._assert_equal_objects(actual_param, expected_param)
313+
314+
@staticmethod
315+
def _get_get_trusted_nfs_client_object(address=None):
316+
return NFSv3AccessControlEntry(address=address or '192.168.68.0', netmask='255.255.255.0', perm=FileAccessMode.RO)

0 commit comments

Comments
 (0)