Skip to content

Commit 926e24b

Browse files
Merge pull request #1951 from BrianSantivanez/issue1942
New Command: `slcli security`
2 parents 7bfe9a3 + ceee75f commit 926e24b

18 files changed

+274
-12
lines changed

SoftLayer/CLI/environment.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,8 @@ def list_commands(self, *path):
138138

139139
# offset is used to exclude the path that the caller requested.
140140
offset = len(path_str) + 1 if path_str else 0
141-
commands.append(command[offset:])
141+
if ':' not in command[offset:]:
142+
commands.append(command[offset:])
142143

143144
return sorted(commands)
144145

SoftLayer/CLI/routes.py

+22-10
Original file line numberDiff line numberDiff line change
@@ -332,18 +332,30 @@
332332
('securitygroup:event-log', 'SoftLayer.CLI.securitygroup.event_log:get_by_request_id'),
333333

334334
('sshkey', 'SoftLayer.CLI.sshkey'),
335-
('sshkey:add', 'SoftLayer.CLI.sshkey.add:cli'),
336-
('sshkey:remove', 'SoftLayer.CLI.sshkey.remove:cli'),
337-
('sshkey:edit', 'SoftLayer.CLI.sshkey.edit:cli'),
338-
('sshkey:list', 'SoftLayer.CLI.sshkey.list:cli'),
339-
('sshkey:print', 'SoftLayer.CLI.sshkey.print:cli'),
335+
('sshkey:add', 'SoftLayer.CLI.security.sshkey_add:cli'),
336+
('sshkey:remove', 'SoftLayer.CLI.security.sshkey_remove:cli'),
337+
('sshkey:edit', 'SoftLayer.CLI.security.sshkey_edit:cli'),
338+
('sshkey:list', 'SoftLayer.CLI.security.sshkey_list:cli'),
339+
('sshkey:print', 'SoftLayer.CLI.security.sshkey_print:cli'),
340340

341341
('ssl', 'SoftLayer.CLI.ssl'),
342-
('ssl:add', 'SoftLayer.CLI.ssl.add:cli'),
343-
('ssl:download', 'SoftLayer.CLI.ssl.download:cli'),
344-
('ssl:edit', 'SoftLayer.CLI.ssl.edit:cli'),
345-
('ssl:list', 'SoftLayer.CLI.ssl.list:cli'),
346-
('ssl:remove', 'SoftLayer.CLI.ssl.remove:cli'),
342+
('ssl:add', 'SoftLayer.CLI.security.cert_add:cli'),
343+
('ssl:download', 'SoftLayer.CLI.security.cert_download:cli'),
344+
('ssl:edit', 'SoftLayer.CLI.security.cert_edit:cli'),
345+
('ssl:list', 'SoftLayer.CLI.security.cert_list:cli'),
346+
('ssl:remove', 'SoftLayer.CLI.security.cert_remove:cli'),
347+
348+
('security', 'SoftLayer.CLI.security'),
349+
('security:sshkey-add', 'SoftLayer.CLI.security.sshkey_add:cli'),
350+
('security:sshkey-remove', 'SoftLayer.CLI.security.sshkey_remove:cli'),
351+
('security:sshkey-edit', 'SoftLayer.CLI.security.sshkey_edit:cli'),
352+
('security:sshkey-list', 'SoftLayer.CLI.security.sshkey_list:cli'),
353+
('security:sshkey-print', 'SoftLayer.CLI.security.sshkey_print:cli'),
354+
('security:cert-add', 'SoftLayer.CLI.security.cert_add:cli'),
355+
('security:cert-download', 'SoftLayer.CLI.security.cert_download:cli'),
356+
('security:cert-edit', 'SoftLayer.CLI.security.cert_edit:cli'),
357+
('security:cert-list', 'SoftLayer.CLI.security.cert_list:cli'),
358+
('security:cert-remove', 'SoftLayer.CLI.security.cert_remove:cli'),
347359

348360
('subnet', 'SoftLayer.CLI.subnet'),
349361
('subnet:cancel', 'SoftLayer.CLI.subnet.cancel:cli'),

SoftLayer/CLI/security/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
"""SSH Keys and SSL Certificates."""
2+
# :license: MIT, see LICENSE for more details.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

docs/cli/security.rst

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
.. _cli_security:
2+
3+
SSH Keys and SSL Certificates
4+
========
5+
6+
.. click:: SoftLayer.CLI.security.sshkey_add:cli
7+
:prog: security sshkey-add
8+
:show-nested:
9+
10+
.. click:: SoftLayer.CLI.security.sshkey_add:cli
11+
:prog: sshkey add
12+
:show-nested:
13+
14+
.. click:: SoftLayer.CLI.security.sshkey_remove:cli
15+
:prog: security sshkey-remove
16+
:show-nested:
17+
18+
.. click:: SoftLayer.CLI.security.sshkey_remove:cli
19+
:prog: sshkey remove
20+
:show-nested:
21+
22+
.. click:: SoftLayer.CLI.security.sshkey_edit:cli
23+
:prog: security sshkey-edit
24+
:show-nested:
25+
26+
.. click:: SoftLayer.CLI.security.sshkey_edit:cli
27+
:prog: sshkey edit
28+
:show-nested:
29+
30+
.. click:: SoftLayer.CLI.security.sshkey_list:cli
31+
:prog: security sshkey-list
32+
:show-nested:
33+
34+
.. click:: SoftLayer.CLI.security.sshkey_list:cli
35+
:prog: sshkey list
36+
:show-nested:
37+
38+
.. click:: SoftLayer.CLI.security.sshkey_print:cli
39+
:prog: security sshkey-print
40+
:show-nested:
41+
42+
.. click:: SoftLayer.CLI.security.sshkey_print:cli
43+
:prog: sshkey print
44+
:show-nested:
45+
46+
.. click:: SoftLayer.CLI.security.cert_add:cli
47+
:prog: security cert-add
48+
:show-nested:
49+
50+
.. click:: SoftLayer.CLI.security.cert_add:cli
51+
:prog: ssl add
52+
:show-nested:
53+
54+
.. click:: SoftLayer.CLI.security.cert_download:cli
55+
:prog: security cert-download
56+
:show-nested:
57+
58+
.. click:: SoftLayer.CLI.security.cert_download:cli
59+
:prog: ssl download
60+
:show-nested:
61+
62+
.. click:: SoftLayer.CLI.security.cert_edit:cli
63+
:prog: security cert-edit
64+
:show-nested:
65+
66+
.. click:: SoftLayer.CLI.security.cert_edit:cli
67+
:prog: ssl edit
68+
:show-nested:
69+
70+
.. click:: SoftLayer.CLI.security.cert_list:cli
71+
:prog: security cert-list
72+
:show-nested:
73+
74+
.. click:: SoftLayer.CLI.security.cert_list:cli
75+
:prog: ssl list
76+
:show-nested:
77+
78+
.. click:: SoftLayer.CLI.security.cert_remove:cli
79+
:prog: security cert-remove
80+
:show-nested:
81+
82+
.. click:: SoftLayer.CLI.security.cert_remove:cli
83+
:prog: ssl remove
84+
:show-nested:

docs/cli/sshkey.rst

+5
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,26 @@ SSH Keys
44
========
55

66
.. click:: SoftLayer.CLI.sshkey.add:cli
7+
This command is an alias for `slcli security sshkey-add`
78
:prog: sshkey add
89
:show-nested:
910

1011
.. click:: SoftLayer.CLI.sshkey.remove:cli
12+
This command is an alias for `slcli security sshkey-remove`
1113
:prog: sshkey remove
1214
:show-nested:
1315

1416
.. click:: SoftLayer.CLI.sshkey.edit:cli
17+
This command is an alias for `slcli security sshkey-edit`
1518
:prog: sshkey edit
1619
:show-nested:
1720

1821
.. click:: SoftLayer.CLI.sshkey.list:cli
22+
This command is an alias for `slcli security sshkey-list`
1923
:prog: sshkey list
2024
:show-nested:
2125

2226
.. click:: SoftLayer.CLI.sshkey.print:cli
27+
This command is an alias for `slcli security sshkey-print`
2328
:prog: sshkey print
2429
:show-nested:

docs/cli/ssl.rst

+5
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,27 @@ SSL Certificates
44
================
55

66
.. click:: SoftLayer.CLI.ssl.add:cli
7+
This command is an alias for `slcli security cert_add`
78
:prog: ssl add
89
:show-nested:
910

1011
.. click:: SoftLayer.CLI.ssl.download:cli
12+
This command is an alias for `slcli security cert_download`
1113
:prog: ssl download
1214
:show-nested:
1315

1416
.. click:: SoftLayer.CLI.ssl.edit:cli
17+
This command is an alias for `slcli security cert_edit`
1518
:prog: ssl edit
1619
:show-nested:
1720

1821
.. click:: SoftLayer.CLI.ssl.list:cli
22+
This command is an alias for `slcli security cert_list`
1923
:prog: ssl list
2024
:show-nested:
2125

2226
.. click:: SoftLayer.CLI.ssl.remove:cli
27+
This command is an alias for `slcli security cert_remove`
2328
:prog: ssl remove
2429
:show-nested:
2530

tests/CLI/modules/security_tests.py

+154
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
"""
2+
SoftLayer.tests.CLI.modules.security_tests
3+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4+
5+
:license: MIT, see LICENSE for more details.
6+
"""
7+
import json
8+
import os.path
9+
import sys
10+
import tempfile
11+
12+
from unittest import mock as mock
13+
14+
from SoftLayer.CLI import exceptions
15+
from SoftLayer import testing
16+
17+
18+
class SecurityTests(testing.TestCase):
19+
def test_add_sshkey_without_key_errors(self):
20+
result = self.run_command(['security', 'sshkey-add', 'key1'])
21+
22+
self.assertEqual(result.exit_code, 2)
23+
self.assertIsInstance(result.exception, exceptions.ArgumentError)
24+
25+
def test_add_sshkey_with_key_file_and_key_argument_errors(self):
26+
path = os.path.join(testing.FIXTURE_PATH, 'id_rsa.pub')
27+
result = self.run_command(['security', 'sshkey-add', 'key1',
28+
'--key=some_key',
29+
'--in-file=%s' % path])
30+
31+
self.assertEqual(result.exit_code, 2)
32+
self.assertIsInstance(result.exception, exceptions.ArgumentError)
33+
34+
def test_add_sshkey_by_option(self):
35+
service = self.client['Security_Ssh_Key']
36+
mock_key = service.getObject()['key']
37+
38+
result = self.run_command(['security', 'sshkey-add', 'key1',
39+
'--key=%s' % mock_key,
40+
'--note=my key'])
41+
42+
self.assert_no_fail(result)
43+
self.assertEqual(json.loads(result.output),
44+
"SSH key added: aa:bb:cc:dd")
45+
self.assert_called_with('SoftLayer_Security_Ssh_Key', 'createObject',
46+
args=({'notes': 'my key',
47+
'key': mock_key,
48+
'label': 'key1'},))
49+
50+
def test_add_sshkey_by_file(self):
51+
path = os.path.join(testing.FIXTURE_PATH, 'id_rsa.pub')
52+
53+
result = self.run_command(['security', 'sshkey-add', 'key1',
54+
'--in-file=%s' % path])
55+
56+
self.assert_no_fail(result)
57+
self.assertEqual(json.loads(result.output),
58+
"SSH key added: aa:bb:cc:dd")
59+
service = self.client['Security_Ssh_Key']
60+
mock_key = service.getObject()['key']
61+
self.assert_called_with('SoftLayer_Security_Ssh_Key', 'createObject',
62+
args=({'notes': None,
63+
'key': mock_key,
64+
'label': 'key1'},))
65+
66+
def test_remove_sshkey_key(self):
67+
result = self.run_command(['--really', 'security', 'sshkey-remove', '1234'])
68+
69+
self.assert_no_fail(result)
70+
self.assert_called_with('SoftLayer_Security_Ssh_Key', 'deleteObject',
71+
identifier=1234)
72+
73+
@mock.patch('SoftLayer.CLI.formatting.no_going_back')
74+
def test_remove_sshkey_fail(self, ngb_mock):
75+
ngb_mock.return_value = False
76+
result = self.run_command(['security', 'sshkey-remove', '1234'])
77+
78+
self.assertEqual(result.exit_code, 2)
79+
80+
def test_edit_sshkey(self):
81+
result = self.run_command(['security', 'sshkey-edit', '1234',
82+
'--label=key1', '--note=my key'])
83+
84+
self.assert_no_fail(result)
85+
self.assert_called_with('SoftLayer_Security_Ssh_Key', 'editObject',
86+
args=({'notes': 'my key',
87+
'label': 'key1'},),
88+
identifier=1234)
89+
90+
def test_edit_sshkey_fail(self):
91+
fixture = self.set_mock('SoftLayer_Security_Ssh_Key', 'editObject')
92+
fixture.return_value = False
93+
94+
result = self.run_command(['security', 'sshkey-edit', '1234',
95+
'--label=key1', '--note=my key'])
96+
97+
self.assertEqual(result.exit_code, 2)
98+
99+
def test_list_sshkeys(self):
100+
result = self.run_command(['security', 'sshkey-list'])
101+
102+
self.assert_no_fail(result)
103+
self.assertEqual(json.loads(result.output),
104+
[{'notes': '-',
105+
'fingerprint': None,
106+
'id': '100',
107+
'label': 'Test 1'},
108+
{'notes': 'my key',
109+
'fingerprint': None,
110+
'id': '101',
111+
'label': 'Test 2'}])
112+
113+
def test_print_sshkey(self):
114+
result = self.run_command(['security', 'sshkey-print', '1234'])
115+
116+
self.assert_no_fail(result)
117+
self.assertEqual(json.loads(result.output),
118+
{'id': 1234, 'label': 'label', 'notes': 'notes'})
119+
120+
def test_print_sshkey_file(self):
121+
if sys.platform.startswith("win"):
122+
self.skipTest("Test doesn't work in Windows")
123+
with tempfile.NamedTemporaryFile() as sshkey_file:
124+
service = self.client['Security_Ssh_Key']
125+
mock_key = service.getObject()['key']
126+
result = self.run_command(['security', 'sshkey-print', '1234',
127+
'--out-file=%s' % sshkey_file.name])
128+
129+
self.assert_no_fail(result)
130+
self.assertEqual(mock_key, sshkey_file.read().decode("utf-8"))
131+
132+
def test_list_certficates(self):
133+
result = self.run_command(['security', 'cert-list', '--status', 'all'])
134+
self.assert_no_fail(result)
135+
self.assertEqual(json.loads(result.output), [
136+
{
137+
"id": 1234,
138+
"common_name": "cert",
139+
"days_until_expire": 0,
140+
"notes": None
141+
}
142+
])
143+
144+
@mock.patch('SoftLayer.CLI.formatting.no_going_back')
145+
def test_remove_certficate(self, confirm_mock):
146+
confirm_mock.return_value = True
147+
result = self.run_command(['security', 'cert-remove', '123456'])
148+
self.assert_no_fail(result)
149+
self.assertEqual(result.exit_code, 0)
150+
151+
def test_download_certficate(self):
152+
result = self.run_command(['security', 'cert-download', '123456'])
153+
self.assert_no_fail(result)
154+
self.assertEqual(result.exit_code, 0)

tests/CLI/modules/ssl_tests.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""
22
SoftLayer.tests.CLI.modules.ssl_tests
33
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4-
54
:license: MIT, see LICENSE for more details.
65
"""
76
from SoftLayer import testing

0 commit comments

Comments
 (0)