diff --git a/SoftLayer/CLI/hardware/power.py b/SoftLayer/CLI/hardware/power.py index 22f32ade5..64bba114b 100644 --- a/SoftLayer/CLI/hardware/power.py +++ b/SoftLayer/CLI/hardware/power.py @@ -77,3 +77,20 @@ def power_cycle(env, identifier): raise exceptions.CLIAbort('Aborted.') env.client['Hardware_Server'].powerCycle(id=hw_id) + + +@click.command() +@click.argument('identifier') +@environment.pass_env +def rescue(env, identifier): + """Reboot server into a rescue image.""" + + mgr = SoftLayer.HardwareManager(env.client) + hw_id = helpers.resolve_id(mgr.resolve_ids, identifier, 'hardware') + + if not (env.skip_confirmations or + formatting.confirm("This action will reboot this server. Continue?")): + + raise exceptions.CLIAbort('Aborted') + + env.client['Hardware_Server'].bootToRescueLayer(id=hw_id) diff --git a/SoftLayer/CLI/hardware/rescue.py b/SoftLayer/CLI/hardware/rescue.py deleted file mode 100644 index 6aaca3efa..000000000 --- a/SoftLayer/CLI/hardware/rescue.py +++ /dev/null @@ -1,28 +0,0 @@ -"""Reboot server into a rescue image.""" -# :license: MIT, see LICENSE for more details. - -import click - -import SoftLayer -from SoftLayer.CLI import environment -from SoftLayer.CLI import exceptions -from SoftLayer.CLI import formatting -from SoftLayer.CLI import helpers - - -@click.command() -@click.argument('identifier') -@environment.pass_env -def cli(env, identifier): - """Reboot server into a rescue image.""" - - server = SoftLayer.HardwareManager(env.client) - server_id = helpers.resolve_id(server.resolve_ids, identifier, 'hardware') - - if not (env.skip_confirmations or - formatting.confirm("This action will reboot this server. " - "Continue?")): - - raise exceptions.CLIAbort('Aborted') - - server.rescue(server_id) diff --git a/SoftLayer/CLI/routes.py b/SoftLayer/CLI/routes.py index eae0c763d..2ff3379ac 100644 --- a/SoftLayer/CLI/routes.py +++ b/SoftLayer/CLI/routes.py @@ -210,6 +210,7 @@ ('hardware:reload', 'SoftLayer.CLI.hardware.reload:cli'), ('hardware:credentials', 'SoftLayer.CLI.hardware.credentials:cli'), ('hardware:update-firmware', 'SoftLayer.CLI.hardware.update_firmware:cli'), + ('hardware:rescue', 'SoftLayer.CLI.hardware.power:rescue'), ('securitygroup', 'SoftLayer.CLI.securitygroup'), ('securitygroup:list', 'SoftLayer.CLI.securitygroup.list:cli'), diff --git a/SoftLayer/transports.py b/SoftLayer/transports.py index b3239fc14..32bda03e7 100644 --- a/SoftLayer/transports.py +++ b/SoftLayer/transports.py @@ -99,12 +99,7 @@ def __init__(self, items, total_count): class XmlRpcTransport(object): """XML-RPC transport.""" - def __init__(self, - endpoint_url=None, - timeout=None, - proxy=None, - user_agent=None, - verify=True): + def __init__(self, endpoint_url=None, timeout=None, proxy=None, user_agent=None, verify=True): self.endpoint_url = (endpoint_url or consts.API_PUBLIC_ENDPOINT).rstrip('/') @@ -202,19 +197,13 @@ def __call__(self, request): class RestTransport(object): """REST transport. - Currently only supports GET requests (no POST, PUT, DELETE) and lacks - support for masks, filters, limits and offsets. + REST calls should mostly work, but is not fully tested. + XML-RPC should be used when in doubt """ - def __init__(self, - endpoint_url=None, - timeout=None, - proxy=None, - user_agent=None, - verify=True): + def __init__(self, endpoint_url=None, timeout=None, proxy=None, user_agent=None, verify=True): - self.endpoint_url = (endpoint_url or - consts.API_PUBLIC_ENDPOINT_REST).rstrip('/') + self.endpoint_url = (endpoint_url or consts.API_PUBLIC_ENDPOINT_REST).rstrip('/') self.timeout = timeout or None self.proxy = proxy self.user_agent = user_agent or consts.USER_AGENT @@ -223,12 +212,12 @@ def __init__(self, def __call__(self, request): """Makes a SoftLayer API call against the REST endpoint. - This currently only works with GET requests + REST calls should mostly work, but is not fully tested. + XML-RPC should be used when in doubt :param request request: Request object """ - request.transport_headers.setdefault('Content-Type', - 'application/json') + request.transport_headers.setdefault('Content-Type', 'application/json') request.transport_headers.setdefault('User-Agent', self.user_agent) params = request.headers.copy() @@ -252,9 +241,8 @@ def __call__(self, request): ) method = REST_SPECIAL_METHODS.get(request.method) - is_special_method = True + if method is None: - is_special_method = False method = 'GET' body = {} @@ -272,9 +260,7 @@ def __call__(self, request): if request.identifier is not None: url_parts.append(str(request.identifier)) - # Special methods (createObject, editObject, etc) use the HTTP verb - # to determine the action on the resource - if request.method is not None and not is_special_method: + if request.method is not None: url_parts.append(request.method) url = '%s.%s' % ('/'.join(url_parts), 'json') diff --git a/tests/CLI/modules/server_tests.py b/tests/CLI/modules/server_tests.py index aecda810c..25de71511 100644 --- a/tests/CLI/modules/server_tests.py +++ b/tests/CLI/modules/server_tests.py @@ -445,3 +445,20 @@ def test_edit(self): args=(100,), identifier=100, ) + + @mock.patch('SoftLayer.CLI.formatting.confirm') + def test_rescue(self, confirm_mock): + confirm_mock.return_value = True + result = self.run_command(['server', 'rescue', '1000']) + + self.assert_no_fail(result) + self.assertEqual(result.output, "") + self.assert_called_with('SoftLayer_Hardware_Server', 'bootToRescueLayer', identifier=1000) + + @mock.patch('SoftLayer.CLI.formatting.confirm') + def test_server_rescue_negative(self, confirm_mock): + confirm_mock.return_value = False + result = self.run_command(['server', 'rescue', '1000']) + + self.assertEqual(result.exit_code, 2) + self.assertIsInstance(result.exception, exceptions.CLIAbort)