Skip to content

Commit 273bea5

Browse files
Merge pull request softlayer#1253 from ATGE/issue1239
1239 VPN subnet access to a use
2 parents d50b6bb + 423eda1 commit 273bea5

9 files changed

Lines changed: 203 additions & 6 deletions

File tree

SoftLayer/CLI/routes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,9 @@
194194
('loadbal:order-options', 'SoftLayer.CLI.loadbal.order:order_options'),
195195
('loadbal:cancel', 'SoftLayer.CLI.loadbal.order:cancel'),
196196

197-
198197
('loadbal:ns-detail', 'SoftLayer.CLI.loadbal.ns_detail:cli'),
199198
('loadbal:ns-list', 'SoftLayer.CLI.loadbal.ns_list:cli'),
200199

201-
202200
('metadata', 'SoftLayer.CLI.metadata:cli'),
203201

204202
('nas', 'SoftLayer.CLI.nas'),
@@ -307,6 +305,8 @@
307305
('user:edit-details', 'SoftLayer.CLI.user.edit_details:cli'),
308306
('user:create', 'SoftLayer.CLI.user.create:cli'),
309307
('user:delete', 'SoftLayer.CLI.user.delete:cli'),
308+
('user:vpn-manual', 'SoftLayer.CLI.user.vpn_manual:cli'),
309+
('user:vpn-subnet', 'SoftLayer.CLI.user.vpn_subnet:cli'),
310310

311311
('vlan', 'SoftLayer.CLI.vlan'),
312312
('vlan:detail', 'SoftLayer.CLI.vlan.detail:cli'),

SoftLayer/CLI/user/vpn_manual.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""Enable or Disable vpn subnets manual config for a user."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
5+
import click
6+
7+
import SoftLayer
8+
from SoftLayer.CLI import environment
9+
from SoftLayer.CLI import helpers
10+
11+
12+
@click.command()
13+
@click.argument('user')
14+
@click.option('--enable/--disable', default=True,
15+
help="Enable or disable vpn subnets manual config.")
16+
@environment.pass_env
17+
def cli(env, user, enable):
18+
"""Enable or disable user vpn subnets manual config"""
19+
mgr = SoftLayer.UserManager(env.client)
20+
user_id = helpers.resolve_id(mgr.resolve_ids, user, 'username')
21+
22+
result = mgr.vpn_manual(user_id, enable)
23+
message = "{} vpn manual config {}".format(user, 'enable' if enable else 'disable')
24+
25+
if result:
26+
click.secho(message, fg='green')
27+
else:
28+
click.secho("Failed to update {}".format(user), fg='red')

SoftLayer/CLI/user/vpn_subnet.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
"""Add or remove specific subnets access for a user."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
5+
import click
6+
7+
import SoftLayer
8+
from SoftLayer.CLI import environment
9+
from SoftLayer.CLI import helpers
10+
11+
12+
@click.command()
13+
@click.option('--add/--remove', default=True,
14+
help="Add or remove access to subnets.")
15+
@click.argument('user', nargs=1, required=True)
16+
@click.argument('subnet', nargs=-1, required=True)
17+
@environment.pass_env
18+
def cli(env, user, add, subnet):
19+
"""Add or remove subnets access for a user."""
20+
mgr = SoftLayer.UserManager(env.client)
21+
user_id = helpers.resolve_id(mgr.resolve_ids, user, 'username')
22+
if add:
23+
result = mgr.vpn_subnet_add(user_id, subnet)
24+
else:
25+
result = mgr.vpn_subnet_remove(user_id, subnet)
26+
27+
if result:
28+
click.secho("%s updated successfully" % (user), fg='green')
29+
else:
30+
click.secho("Failed to update %s" % (user), fg='red')
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
createObjects = True
2+
deleteObjects = True

SoftLayer/fixtures/SoftLayer_User_Customer.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@
6363
'name': 'Add/Upgrade Storage (StorageLayer)'}
6464
]
6565

66-
6766
getLoginAttempts = [
6867
{
6968
"createDate": "2017-10-03T09:28:33-06:00",
@@ -74,8 +73,16 @@
7473
}
7574
]
7675

76+
getOverrides = [
77+
{
78+
'id': 3661234,
79+
'subnetId': 1234
80+
}
81+
]
82+
7783
addBulkPortalPermission = True
7884
removeBulkPortalPermission = True
7985
createObject = getObject
8086
editObject = True
8187
addApiAuthenticationKey = True
88+
updateVpnUser = True

SoftLayer/managers/user.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class UserManager(utils.IdentifierMixin, object):
3434
def __init__(self, client):
3535
self.client = client
3636
self.user_service = self.client['SoftLayer_User_Customer']
37+
self.override_service = self.client['Network_Service_Vpn_Overrides']
3738
self.account_service = self.client['SoftLayer_Account']
3839
self.resolvers = [self._get_id_from_username]
3940
self.all_permissions = None
@@ -267,6 +268,66 @@ def add_api_authentication_key(self, user_id):
267268
"""
268269
return self.user_service.addApiAuthenticationKey(id=user_id)
269270

271+
def vpn_manual(self, user_id, value):
272+
"""Enable or disable the manual config of subnets.
273+
274+
:param int user_id: User to edit.
275+
:param bool value: Value for vpnManualConfig flag.
276+
"""
277+
user_object = {'vpnManualConfig': value}
278+
return self.edit_user(user_id, user_object)
279+
280+
def vpn_subnet_add(self, user_id, subnet_ids):
281+
"""Add subnets for a user.
282+
283+
:param int user_id: User to edit.
284+
:param list subnet_ids: list of subnet Ids.
285+
"""
286+
overrides = [{"userId": user_id, "subnetId": subnet_id} for subnet_id in subnet_ids]
287+
return_value = self.override_service.createObjects(overrides)
288+
update_success = self.user_service.updateVpnUser(id=user_id)
289+
if not update_success:
290+
raise exceptions.SoftLayerAPIError("Overrides created, but unable to update VPN user")
291+
return return_value
292+
293+
def vpn_subnet_remove(self, user_id, subnet_ids):
294+
"""Remove subnets for a user.
295+
296+
:param int user_id: User to edit.
297+
:param list subnet_ids: list of subnet Ids.
298+
"""
299+
overrides = self.get_overrides_list(user_id, subnet_ids)
300+
return_value = self.override_service.deleteObjects(overrides)
301+
update_success = self.user_service.updateVpnUser(id=user_id)
302+
if not update_success:
303+
raise exceptions.SoftLayerAPIError("Overrides deleted, but unable to update VPN user")
304+
return return_value
305+
306+
def get_overrides_list(self, user_id, subnet_ids):
307+
"""Converts a list of subnets to a list of overrides.
308+
309+
:param int user_id: The ID of the user.
310+
:param list subnet_ids: A list of subnets.
311+
:returns: A list of overrides associated with the given subnets.
312+
"""
313+
314+
overrides_list = []
315+
matching_overrides = {}
316+
output_error = "Subnet {} does not exist in the subnets assigned for user {}"
317+
_mask = 'mask[id,subnetId]'
318+
overrides = self.user_service.getOverrides(id=user_id, mask=_mask)
319+
for subnet in subnet_ids:
320+
for override in overrides:
321+
if int(subnet) == override.get('subnetId'):
322+
matching_overrides = override
323+
break
324+
if matching_overrides.get('subnetId') is None:
325+
raise exceptions.SoftLayerError(output_error.format(subnet, user_id))
326+
327+
overrides_list.append(matching_overrides)
328+
329+
return overrides_list
330+
270331

271332
def _keyname_search(haystack, needle):
272333
for item in haystack:

docs/cli/users.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,12 @@ Version 5.6.0 introduces the ability to interact with user accounts from the cli
3232
:prog: user delete
3333
:show-nested:
3434

35+
.. click:: SoftLayer.CLI.user.vpn-manual:cli
36+
:prog: user vpn-manual
37+
:show-nested:
38+
39+
.. click:: SoftLayer.CLI.user.vpn-subnet:cli
40+
:prog: user vpn-subnet
41+
:show-nested:
42+
3543

tests/CLI/modules/user_tests.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515

1616
class UserCLITests(testing.TestCase):
17-
1817
"""User list tests"""
1918

2019
def test_user_list(self):
@@ -153,6 +152,7 @@ def test_edit_perms_from_user(self):
153152
self.assert_called_with('SoftLayer_User_Customer', 'addBulkPortalPermission', identifier=11100)
154153

155154
"""User create tests"""
155+
156156
@mock.patch('SoftLayer.CLI.formatting.confirm')
157157
def test_create_user(self, confirm_mock):
158158
confirm_mock.return_value = True
@@ -228,6 +228,7 @@ def test_create_user_from_user(self, confirm_mock):
228228
self.assert_called_with('SoftLayer_User_Customer', 'getObject', identifier=1234)
229229

230230
"""User edit-details tests"""
231+
231232
@mock.patch('SoftLayer.CLI.user.edit_details.click')
232233
def test_edit_details(self, click):
233234
result = self.run_command(['user', 'edit-details', '1234', '-t', '{"firstName":"Supermand"}'])
@@ -252,6 +253,7 @@ def test_edit_details_bad_json(self):
252253
self.assertEqual(result.exit_code, 2)
253254

254255
"""User delete tests"""
256+
255257
@mock.patch('SoftLayer.CLI.user.delete.click')
256258
def test_delete(self, click):
257259
result = self.run_command(['user', 'delete', '12345'])
@@ -269,3 +271,37 @@ def test_delete_failure(self, click):
269271
self.assert_no_fail(result)
270272
self.assert_called_with('SoftLayer_User_Customer', 'editObject',
271273
args=({'userStatusId': 1021},), identifier=12345)
274+
275+
"""User vpn manual config tests"""
276+
277+
@mock.patch('SoftLayer.CLI.user.vpn_manual.click')
278+
def test_vpn_manual(self, click):
279+
result = self.run_command(['user', 'vpn-manual', '12345', '--enable'])
280+
click.secho.assert_called_with('12345 vpn manual config enable', fg='green')
281+
self.assert_no_fail(result)
282+
283+
def test_vpn_manual_fail(self):
284+
mock = self.set_mock('SoftLayer_User_Customer', 'editObject')
285+
mock.return_value = False
286+
result = self.run_command(['user', 'vpn-manual', '12345', '--enable'])
287+
self.assert_no_fail(result)
288+
289+
"""User vpn subnet tests"""
290+
291+
@mock.patch('SoftLayer.CLI.user.vpn_subnet.click')
292+
def test_vpn_subnet_add(self, click):
293+
result = self.run_command(['user', 'vpn-subnet', '12345', '--add', '1234'])
294+
click.secho.assert_called_with('12345 updated successfully', fg='green')
295+
self.assert_no_fail(result)
296+
297+
def test_vpn_subnet_add_fail(self):
298+
mock = self.set_mock('SoftLayer_Network_Service_Vpn_Overrides', 'createObjects')
299+
mock.return_value = False
300+
result = self.run_command(['user', 'vpn-subnet', '12345', '--add', '1234'])
301+
self.assert_no_fail(result)
302+
303+
@mock.patch('SoftLayer.CLI.user.vpn_subnet.click')
304+
def test_vpn_subnet_remove(self, click):
305+
result = self.run_command(['user', 'vpn-subnet', '12345', '--remove', '1234'])
306+
click.secho.assert_called_with('12345 updated successfully', fg='green')
307+
self.assert_no_fail(result)

tests/managers/user_tests.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
from SoftLayer import exceptions
1010
from SoftLayer import testing
1111

12-
1312
real_datetime_class = datetime.datetime
1413

1514

@@ -18,6 +17,7 @@ def mock_datetime(target, datetime_module):
1817
1918
https://solidgeargroup.com/mocking-the-time
2019
"""
20+
2121
class DatetimeSubclassMeta(type):
2222
@classmethod
2323
def __instancecheck__(mcs, obj):
@@ -106,7 +106,6 @@ def test_get_logins_default(self):
106106
def test_get_events_default(self):
107107
target = datetime.datetime(2018, 5, 15)
108108
with mock_datetime(target, datetime):
109-
110109
self.manager.get_events(1234)
111110
expected_filter = {
112111
'userId': {
@@ -221,3 +220,29 @@ def test_create_user_handle_paas_exception(self):
221220
self.assertEqual(ex.args[0], "Your request for a new user was received, but it needs to be processed by "
222221
"the Platform Services API first. Barring any errors on the Platform Services "
223222
"side, your new user should be created shortly.")
223+
224+
def test_vpn_manual(self):
225+
user_id = 1234
226+
self.manager.vpn_manual(user_id, True)
227+
self.assert_called_with('SoftLayer_User_Customer', 'editObject', identifier=user_id)
228+
229+
def test_vpn_subnet_add(self):
230+
user_id = 1234
231+
subnet_id = 1234
232+
expected_args = (
233+
[{"userId": user_id, "subnetId": subnet_id}],
234+
)
235+
self.manager.vpn_subnet_add(user_id, [subnet_id])
236+
self.assert_called_with('SoftLayer_Network_Service_Vpn_Overrides', 'createObjects', args=expected_args)
237+
self.assert_called_with('SoftLayer_User_Customer', 'updateVpnUser', identifier=user_id)
238+
239+
def test_vpn_subnet_remove(self):
240+
user_id = 1234
241+
subnet_id = 1234
242+
overrides = [{'id': 3661234, 'subnetId': subnet_id}]
243+
expected_args = (
244+
overrides,
245+
)
246+
self.manager.vpn_subnet_remove(user_id, [subnet_id])
247+
self.assert_called_with('SoftLayer_Network_Service_Vpn_Overrides', 'deleteObjects', args=expected_args)
248+
self.assert_called_with('SoftLayer_User_Customer', 'updateVpnUser', identifier=user_id)

0 commit comments

Comments
 (0)