Skip to content

Commit 139b39f

Browse files
Merge pull request #1919 from BrianSantivanez/issue1913
New Command: `slcli user apikey`
2 parents 13502c3 + e681da9 commit 139b39f

File tree

9 files changed

+128
-3
lines changed

9 files changed

+128
-3
lines changed

SoftLayer/CLI/routes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,7 @@
391391
('user:remove-access', 'SoftLayer.CLI.user.remove_access:cli'),
392392
('user:grant-access', 'SoftLayer.CLI.user.grant_access:cli'),
393393
('user:vpn-password', 'SoftLayer.CLI.user.vpn_password:cli'),
394+
('user:apikey', 'SoftLayer.CLI.user.apikey:cli'),
394395

395396
('vlan', 'SoftLayer.CLI.vlan'),
396397
('vlan:create', 'SoftLayer.CLI.vlan.create:cli'),

SoftLayer/CLI/user/apikey.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"""Allows to create, remove or refresh user's API authentication key."""
2+
import click
3+
4+
import SoftLayer
5+
from SoftLayer.CLI import environment
6+
from SoftLayer.CLI import exceptions
7+
from SoftLayer.CLI import helpers
8+
9+
10+
@click.command(cls=SoftLayer.CLI.command.SLCommand, )
11+
@click.argument('identifier')
12+
@click.option('--add', is_flag=True, default=False,
13+
help="Create an user's API authentication key.")
14+
@click.option('--remove', is_flag=True, default=False,
15+
help="Remove an user's API authentication key.")
16+
@click.option('--refresh', is_flag=True, default=False,
17+
help="Refresh an user's API authentication key.")
18+
@environment.pass_env
19+
def cli(env, identifier, add, remove, refresh):
20+
21+
"""Allows to create, remove or refresh user's API authentication key.
22+
23+
Each user can only have a single API key.
24+
"""
25+
26+
options = {
27+
'--add': add,
28+
'--remove': remove,
29+
'--refresh': refresh,
30+
}
31+
32+
if not any(options.values()):
33+
raise exceptions.CLIAbort(f'At least one option is required: [{",".join(options.keys())}]')
34+
35+
if sum(options.values()) > 1:
36+
raise exceptions.CLIAbort(f'Can only specify one option of [{",".join(options.keys())}]')
37+
38+
mgr = SoftLayer.UserManager(env.client)
39+
user_id = helpers.resolve_id(mgr.resolve_ids, identifier, 'username')
40+
41+
if remove or refresh:
42+
mgr.remove_api_authentication_key(user_id)
43+
click.secho('Successfully removed API authentication key', fg='green')
44+
45+
if add or refresh:
46+
api_authentication_key = mgr.add_api_authentication_key(user_id)
47+
click.secho(f'Successfully added. New API Authentication Key: {api_authentication_key}', fg='green')

SoftLayer/fixtures/SoftLayer_User_Customer.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@
8484
removeBulkPortalPermission = True
8585
createObject = getObject
8686
editObject = True
87-
addApiAuthenticationKey = True
87+
addApiAuthenticationKey = "1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a"
88+
removeApiAuthenticationKey = True
8889
updateVpnUser = True
8990
removeDedicatedHostAccess = True
9091
removeHardwareAccess = True
@@ -94,6 +95,17 @@
9495
addVirtualGuestAccess = True
9596
updateVpnPassword = True
9697

98+
getApiAuthenticationKeys = [
99+
{
100+
"authenticationKey": "1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a",
101+
"id": 123456,
102+
"timestampKey": 12121212,
103+
"userId": 111111
104+
}
105+
]
106+
107+
getEmptyApiAuthenticationKeys = []
108+
97109
getHardware = [{
98110
"domain": "testedit.com",
99111
"fullyQualifiedDomainName": "test.testedit.com",

SoftLayer/managers/user.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,26 @@ def add_api_authentication_key(self, user_id):
332332
"""
333333
return self.user_service.addApiAuthenticationKey(id=user_id)
334334

335+
def get_api_authentication_keys(self, user_id):
336+
"""Calls SoftLayer_User_Customer::getApiAuthenticationKeys
337+
338+
:param int user_id: User to add API key to
339+
"""
340+
return self.user_service.getApiAuthenticationKeys(id=user_id)
341+
342+
def remove_api_authentication_key(self, user_id):
343+
"""Calls SoftLayer_User_Customer::getApiAuthenticationKeys and
344+
345+
SoftLayer_User_Customer::removeApiAuthenticationKey
346+
347+
:param int user_id: User to remove API key
348+
"""
349+
api_authentication_keys = self.get_api_authentication_keys(user_id)
350+
if len(api_authentication_keys) == 0:
351+
return True
352+
353+
return self.user_service.removeApiAuthenticationKey(api_authentication_keys[0]['id'])
354+
335355
def vpn_manual(self, user_id, value):
336356
"""Enable or disable the manual config of subnets.
337357

docs/cli/users.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,7 @@ Version 5.6.0 introduces the ability to interact with user accounts from the cli
6464
:prog: user vpn-password
6565
:show-nested:
6666

67+
.. click:: SoftLayer.CLI.user.apikey:cli
68+
:prog: user apikey
69+
:show-nested:
70+

tests/CLI/modules/sshkey_tests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ def test_print_key(self):
118118
{'id': 1234, 'label': 'label', 'notes': 'notes'})
119119

120120
def test_print_key_file(self):
121-
if (sys.platform.startswith("win")):
121+
if sys.platform.startswith("win"):
122122
self.skipTest("Test doesn't work in Windows")
123123
with tempfile.NamedTemporaryFile() as sshkey_file:
124124
service = self.client['Security_Ssh_Key']

tests/CLI/modules/user_tests.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
from unittest import mock as mock
1212

13+
from SoftLayer.fixtures import SoftLayer_User_Customer
1314
from SoftLayer import testing
1415

1516

@@ -387,3 +388,31 @@ def test_remove_without_password(self):
387388
result = self.run_command(['user', 'vpn-password', '123456'])
388389
self.assertEqual(2, result.exit_code)
389390
self.assertIn("Missing option '--password'", result.output)
391+
392+
def test_api_key_without_option(self):
393+
result = self.run_command(['user', 'apikey', '123456'])
394+
self.assertEqual(2, result.exit_code)
395+
self.assertIn('At least one option is required', result.exception.message)
396+
397+
def test_api_key_with_all_option(self):
398+
result = self.run_command(['user', 'apikey', '123456', '--add', '--remove', '--refresh'])
399+
self.assertEqual(2, result.exit_code)
400+
self.assertIn('Can only specify one option', result.exception.message)
401+
402+
def test_remove_api_authentication_key_without_api_key(self):
403+
mock = self.set_mock('SoftLayer_User_Customer', 'getApiAuthenticationKeys')
404+
mock.return_value = SoftLayer_User_Customer.getEmptyApiAuthenticationKeys
405+
result = self.run_command(['user', 'apikey', '123456', '--remove'])
406+
self.assert_no_fail(result)
407+
408+
def test_add_api_authentication_key(self):
409+
result = self.run_command(['user', 'apikey', '123456', '--add'])
410+
self.assert_no_fail(result)
411+
412+
def test_remove_api_authentication_key(self):
413+
result = self.run_command(['user', 'apikey', '123456', '--remove'])
414+
self.assert_no_fail(result)
415+
416+
def test_refresh_api_authentication_key(self):
417+
result = self.run_command(['user', 'apikey', '123456', '--refresh'])
418+
self.assert_no_fail(result)

tests/CLI/modules/vs/vs_create_tests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,7 @@ def test_create_vs_no_confirm(self, confirm_mock):
692692
self.assertEqual(result.exit_code, 2)
693693

694694
def test_create_vs_export(self):
695-
if (sys.platform.startswith("win")):
695+
if sys.platform.startswith("win"):
696696
self.skipTest("Test doesn't work in Windows")
697697
with tempfile.NamedTemporaryFile() as config_file:
698698
result = self.run_command(['vs', 'create', '--hostname', 'TEST', '--export', config_file.name,

tests/managers/user_tests.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,3 +334,15 @@ def test_remove_dedicated(self):
334334
def test_update_vpn_password(self):
335335
self.manager.update_vpn_password(123456, "Mypassword1.")
336336
self.assert_called_with('SoftLayer_User_Customer', 'updateVpnPassword')
337+
338+
def test_add_api_authentication_key(self):
339+
self.manager.add_api_authentication_key(123456)
340+
self.assert_called_with('SoftLayer_User_Customer', 'addApiAuthenticationKey')
341+
342+
def test_get_api_authentication_keys(self):
343+
self.manager.get_api_authentication_keys(123456)
344+
self.assert_called_with('SoftLayer_User_Customer', 'getApiAuthenticationKeys')
345+
346+
def test_remove_api_authentication_key(self):
347+
self.manager.remove_api_authentication_key(123456)
348+
self.assert_called_with('SoftLayer_User_Customer', 'removeApiAuthenticationKey')

0 commit comments

Comments
 (0)