Skip to content

Commit 940bf8f

Browse files
Add add_users and remove_users methods to Zones class
SDK-344: Implements zone user management capability. - Add add_users() method to add users to a zone by their UserAccount - Add remove_users() method to remove users from a zone - Uses ZoneUserDelta structure with user uid values - Add unit tests for both methods
1 parent 17e424a commit 940bf8f

2 files changed

Lines changed: 184 additions & 0 deletions

File tree

cterasdk/core/cloudfs.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,64 @@ def add_folders(self, name, folder_finding_helpers):
625625
logger.error('Failed adding folders to zone.')
626626
raise CTERAException(f'Failed adding folders to zone: {name}') from error
627627

628+
def add_users(self, name, user_accounts):
629+
"""
630+
Add users to a zone
631+
632+
:param str name: The name of the zone
633+
:param list[cterasdk.core.types.UserAccount] user_accounts: List of user accounts to add
634+
"""
635+
zone = self._core.cloudfs.zones.get(name)
636+
info = self._zone_info(zone.zoneId)
637+
description = info.description if hasattr(info, 'description') else None
638+
param = self._zone_param(info.name, info.policyType, description, info.zoneId)
639+
640+
param.delta.usersDelta = Object()
641+
param.delta.usersDelta._classname = 'ZoneUserDelta' # pylint: disable=protected-access
642+
param.delta.usersDelta.added = []
643+
param.delta.usersDelta.removed = []
644+
645+
for user_account in user_accounts:
646+
user = self._core.users.get(user_account, include=['uid'])
647+
param.delta.usersDelta.added.append(user.uid)
648+
649+
logger.info('Adding users to zone. %s', {'zone': info.name})
650+
651+
try:
652+
self._save(param)
653+
except CTERAException as error:
654+
logger.error('Failed adding users to zone.')
655+
raise CTERAException(f'Failed adding users to zone: {name}') from error
656+
657+
def remove_users(self, name, user_accounts):
658+
"""
659+
Remove users from a zone
660+
661+
:param str name: The name of the zone
662+
:param list[cterasdk.core.types.UserAccount] user_accounts: List of user accounts to remove
663+
"""
664+
zone = self._core.cloudfs.zones.get(name)
665+
info = self._zone_info(zone.zoneId)
666+
description = info.description if hasattr(info, 'description') else None
667+
param = self._zone_param(info.name, info.policyType, description, info.zoneId)
668+
669+
param.delta.usersDelta = Object()
670+
param.delta.usersDelta._classname = 'ZoneUserDelta' # pylint: disable=protected-access
671+
param.delta.usersDelta.added = []
672+
param.delta.usersDelta.removed = []
673+
674+
for user_account in user_accounts:
675+
user = self._core.users.get(user_account, include=['uid'])
676+
param.delta.usersDelta.removed.append(user.uid)
677+
678+
logger.info('Removing users from zone. %s', {'zone': info.name})
679+
680+
try:
681+
self._save(param)
682+
except CTERAException as error:
683+
logger.error('Failed removing users from zone.')
684+
raise CTERAException(f'Failed removing users from zone: {name}') from error
685+
628686
def _zone_info(self, zid):
629687
logger.debug('Obtaining zone info. %s', {'id': zid})
630688
response = self._core.api.execute('', 'getZoneBasicInfo', zid)

tests/ut/core/admin/test_cloudfs_zones.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ def setUp(self):
3838
self._zone_id = TestCoreZones._zone_id
3939
self._device_names = ['dev1', 'dev2', 'dev3']
4040
self._device_ids = [100, 101, 102]
41+
self._user_accounts = [UserAccount('alice'), UserAccount('bruce')]
42+
self._user_uids = [200, 201]
4143

4244
def test_get_zone_success(self):
4345
execute_response = self._get_zones_display_info_response()
@@ -186,6 +188,102 @@ def test_add_devices_raise(self):
186188
self._assert_equal_objects(actual_param, expected_param)
187189
self.assertEqual(f"Failed adding devices: [{', '.join(self._device_names)}] to zone: {self._zone_name}", str(error.exception))
188190

191+
def test_add_users_success(self):
192+
self._init_global_admin()
193+
zone = self._get_zones_display_info_response().objects.pop()
194+
self._global_admin.api.execute = mock.MagicMock(side_effect=TestCoreZones._mock_execute)
195+
self._global_admin.cloudfs.zones.get = mock.MagicMock(return_value=zone)
196+
get_user_mock = self.patch_call("cterasdk.core.users.Users.get")
197+
get_user_mock.side_effect = self._get_user_objects_side_effect
198+
199+
cloudfs.Zones(self._global_admin).add_users(self._zone_name, self._user_accounts)
200+
201+
self._global_admin.cloudfs.zones.get.assert_called_once_with(self._zone_name)
202+
get_user_calls = [mock.call(user_account, include=['uid']) for user_account in self._user_accounts]
203+
get_user_mock.assert_has_calls(get_user_calls)
204+
self._global_admin.api.execute.assert_has_calls(
205+
[
206+
mock.call('', 'getZoneBasicInfo', self._zone_id),
207+
mock.call('', 'saveZone', mock.ANY)
208+
]
209+
)
210+
expected_param = self._get_add_users_param()
211+
actual_param = self._global_admin.api.execute.call_args[0][2]
212+
self._assert_equal_objects(actual_param, expected_param)
213+
214+
def test_add_users_raise(self):
215+
self._init_global_admin()
216+
zone = self._get_zones_display_info_response().objects.pop()
217+
self._global_admin.api.execute = mock.MagicMock(side_effect=TestCoreZones._save_zone_side_effect)
218+
self._global_admin.cloudfs.zones.get = mock.MagicMock(return_value=zone)
219+
get_user_mock = self.patch_call("cterasdk.core.users.Users.get")
220+
get_user_mock.side_effect = self._get_user_objects_side_effect
221+
222+
with self.assertRaises(exceptions.CTERAException) as error:
223+
cloudfs.Zones(self._global_admin).add_users(self._zone_name, self._user_accounts)
224+
225+
self._global_admin.cloudfs.zones.get.assert_called_once_with(self._zone_name)
226+
get_user_calls = [mock.call(user_account, include=['uid']) for user_account in self._user_accounts]
227+
get_user_mock.assert_has_calls(get_user_calls)
228+
self._global_admin.api.execute.assert_has_calls(
229+
[
230+
mock.call('', 'getZoneBasicInfo', self._zone_id),
231+
mock.call('', 'saveZone', mock.ANY)
232+
]
233+
)
234+
expected_param = self._get_add_users_param()
235+
actual_param = self._global_admin.api.execute.call_args[0][2]
236+
self._assert_equal_objects(actual_param, expected_param)
237+
self.assertEqual(f'Failed adding users to zone: {self._zone_name}', str(error.exception))
238+
239+
def test_remove_users_success(self):
240+
self._init_global_admin()
241+
zone = self._get_zones_display_info_response().objects.pop()
242+
self._global_admin.api.execute = mock.MagicMock(side_effect=TestCoreZones._mock_execute)
243+
self._global_admin.cloudfs.zones.get = mock.MagicMock(return_value=zone)
244+
get_user_mock = self.patch_call("cterasdk.core.users.Users.get")
245+
get_user_mock.side_effect = self._get_user_objects_side_effect
246+
247+
cloudfs.Zones(self._global_admin).remove_users(self._zone_name, self._user_accounts)
248+
249+
self._global_admin.cloudfs.zones.get.assert_called_once_with(self._zone_name)
250+
get_user_calls = [mock.call(user_account, include=['uid']) for user_account in self._user_accounts]
251+
get_user_mock.assert_has_calls(get_user_calls)
252+
self._global_admin.api.execute.assert_has_calls(
253+
[
254+
mock.call('', 'getZoneBasicInfo', self._zone_id),
255+
mock.call('', 'saveZone', mock.ANY)
256+
]
257+
)
258+
expected_param = self._get_remove_users_param()
259+
actual_param = self._global_admin.api.execute.call_args[0][2]
260+
self._assert_equal_objects(actual_param, expected_param)
261+
262+
def test_remove_users_raise(self):
263+
self._init_global_admin()
264+
zone = self._get_zones_display_info_response().objects.pop()
265+
self._global_admin.api.execute = mock.MagicMock(side_effect=TestCoreZones._save_zone_side_effect)
266+
self._global_admin.cloudfs.zones.get = mock.MagicMock(return_value=zone)
267+
get_user_mock = self.patch_call("cterasdk.core.users.Users.get")
268+
get_user_mock.side_effect = self._get_user_objects_side_effect
269+
270+
with self.assertRaises(exceptions.CTERAException) as error:
271+
cloudfs.Zones(self._global_admin).remove_users(self._zone_name, self._user_accounts)
272+
273+
self._global_admin.cloudfs.zones.get.assert_called_once_with(self._zone_name)
274+
get_user_calls = [mock.call(user_account, include=['uid']) for user_account in self._user_accounts]
275+
get_user_mock.assert_has_calls(get_user_calls)
276+
self._global_admin.api.execute.assert_has_calls(
277+
[
278+
mock.call('', 'getZoneBasicInfo', self._zone_id),
279+
mock.call('', 'saveZone', mock.ANY)
280+
]
281+
)
282+
expected_param = self._get_remove_users_param()
283+
actual_param = self._global_admin.api.execute.call_args[0][2]
284+
self._assert_equal_objects(actual_param, expected_param)
285+
self.assertEqual(f'Failed removing users from zone: {self._zone_name}', str(error.exception))
286+
189287
def _get_add_devices_param(self):
190288
param = self._get_zone_param(zone_id=self._zone_id)
191289
for device_id in self._device_ids:
@@ -219,6 +317,34 @@ def _get_device_objects(self):
219317
devices.append(param)
220318
return devices
221319

320+
def _get_add_users_param(self):
321+
param = self._get_zone_param(zone_id=self._zone_id)
322+
param.delta.usersDelta = Object()
323+
param.delta.usersDelta._classname = 'ZoneUserDelta' # pylint: disable=protected-access
324+
param.delta.usersDelta.added = list(self._user_uids)
325+
param.delta.usersDelta.removed = []
326+
return param
327+
328+
def _get_remove_users_param(self):
329+
param = self._get_zone_param(zone_id=self._zone_id)
330+
param.delta.usersDelta = Object()
331+
param.delta.usersDelta._classname = 'ZoneUserDelta' # pylint: disable=protected-access
332+
param.delta.usersDelta.added = []
333+
param.delta.usersDelta.removed = list(self._user_uids)
334+
return param
335+
336+
def _get_user_objects_side_effect(self, user_account, include): # pylint: disable=unused-argument
337+
user_index = next(
338+
(i for i, ua in enumerate(self._user_accounts) if ua.name == user_account.name),
339+
None
340+
)
341+
if user_index is not None:
342+
user = Object()
343+
user.uid = self._user_uids[user_index]
344+
user.name = user_account.name
345+
return user
346+
raise exceptions.ObjectNotFoundException(f'User not found: {user_account.name}')
347+
222348
@staticmethod
223349
def _find_cloud_folder(folder_name, folder_owner, include):
224350
# pylint: disable=unused-argument

0 commit comments

Comments
 (0)