Skip to content

Commit 746dd22

Browse files
committed
Cancel dedicated hosts option and unittests
1 parent 8a755be commit 746dd22

File tree

5 files changed

+91
-0
lines changed

5 files changed

+91
-0
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""Cancel a dedicated host."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import click
5+
6+
import SoftLayer
7+
from SoftLayer.CLI import environment
8+
from SoftLayer.CLI import exceptions
9+
from SoftLayer.CLI import formatting
10+
from SoftLayer.CLI import helpers
11+
12+
13+
@click.command()
14+
@click.argument('identifier')
15+
@click.option('--immediate',
16+
is_flag=True,
17+
default=False,
18+
help="Cancels the dedicated host immediately (instead of on the billing anniversary)")
19+
@environment.pass_env
20+
def cli(env, identifier, immediate):
21+
"""Cancel a dedicated host server."""
22+
23+
mgr = SoftLayer.DedicatedHostManager(env.client)
24+
25+
host_id = helpers.resolve_id(mgr.resolve_ids, identifier, 'dedicated host')
26+
27+
if not (env.skip_confirmations or formatting.no_going_back(host_id)):
28+
raise exceptions.CLIAbort('Aborted')
29+
30+
mgr.cancel_host(host_id, immediate)
31+
32+
click.secho('Dedicated Host %s was successfully cancelled' % host_id, fg='green')

SoftLayer/CLI/routes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
('dedicatedhost:create', 'SoftLayer.CLI.dedicatedhost.create:cli'),
3838
('dedicatedhost:create-options', 'SoftLayer.CLI.dedicatedhost.create_options:cli'),
3939
('dedicatedhost:detail', 'SoftLayer.CLI.dedicatedhost.detail:cli'),
40+
('dedicatedhost:cancel', 'SoftLayer.CLI.dedicatedhost.cancel:cli'),
4041

4142
('cdn', 'SoftLayer.CLI.cdn'),
4243
('cdn:detail', 'SoftLayer.CLI.cdn.detail:cli'),

SoftLayer/managers/dedicated_host.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,30 @@ def __init__(self, client, ordering_manager=None):
3737
if ordering_manager is None:
3838
self.ordering_manager = ordering.OrderingManager(client)
3939

40+
def cancel_host(self, host_id, immediate=True):
41+
"""Cancels a dedicated host server.
42+
43+
Example::
44+
# Cancels dedicated host id 1234
45+
result = mgr.cancel_host(host_id=1234)
46+
47+
:param host_id: The ID of the dedicated host to be cancelled.
48+
:param immediate: If False the dedicated host will be reclaimed in the anniversary date.
49+
Default is True
50+
:return: True on success or an exception
51+
"""
52+
mask = 'mask[id,billingItem[id,hourlyFlag]]'
53+
host_billing = self.get_host(host_id, mask=mask)
54+
billing_id = host_billing['billingItem']['id']
55+
is_hourly = host_billing['billingItem']['hourlyFlag']
56+
57+
if is_hourly and immediate is False:
58+
raise SoftLayer.SoftLayerError("Hourly Dedicated Hosts can only be cancelled immediately.")
59+
else:
60+
# Monthly dedicated host can be reclaimed immediately and no reasons are required
61+
result = self.client['Billing_Item'].cancelItem(immediate, False, id=billing_id)
62+
return result
63+
4064
def list_instances(self, tags=None, cpus=None, memory=None, hostname=None,
4165
disk=None, datacenter=None, **kwargs):
4266
"""Retrieve a list of all dedicated hosts on the account

tests/CLI/modules/dedicatedhost_tests.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,3 +337,15 @@ def test_create_verify_no_price_or_more_than_one(self):
337337
'quantity': 1},)
338338

339339
self.assert_called_with('SoftLayer_Product_Order', 'verifyOrder', args=args)
340+
341+
@mock.patch('SoftLayer.DedicatedHostManager.cancel_host')
342+
def test_cancel_host(self, cancel_mock):
343+
result = self.run_command(['--really', 'dedicatedhost', 'cancel', '12345'])
344+
self.assert_no_fail(result)
345+
cancel_mock.assert_called_with(12345, False)
346+
self.assertEqual(str(result.output), 'Dedicated Host 12345 was successfully cancelled\n')
347+
348+
def test_cancel_host_abort(self):
349+
result = self.run_command(['dedicatedhost', 'cancel', '12345'])
350+
self.assertEqual(result.exit_code, 2)
351+
self.assertIsInstance(result.exception, exceptions.CLIAbort)

tests/managers/dedicated_host_tests.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,28 @@ def test_get_default_router_no_router_found(self):
540540
self.assertRaises(exceptions.SoftLayerError,
541541
self.dedicated_host._get_default_router, routers, 'notFound')
542542

543+
def test_cancel_host(self):
544+
self.dedicated_host.host = mock.Mock()
545+
self.dedicated_host.host.getObject.return_value = {'id': 987, 'billingItem': {
546+
'id': 1234, 'hourlyFlag': False}}
547+
# Immediate cancellation
548+
result = self.dedicated_host.cancel_host(987)
549+
self.assertEqual(True, result)
550+
551+
# Cancellation on anniversary
552+
result = self.dedicated_host.cancel_host(987, immediate=False)
553+
self.assertEqual(True, result)
554+
555+
def test_cancel_host_billing_hourly_no_immediate(self):
556+
self.dedicated_host.host = mock.Mock()
557+
self.dedicated_host.host.getObject.return_value = {'id': 987, 'billingItem': {
558+
'id': 1234, 'hourlyFlag': True}}
559+
560+
ex = self.assertRaises(SoftLayer.SoftLayerError,
561+
self.dedicated_host.cancel_host,
562+
987, immediate=False)
563+
self.assertEqual("Hourly Dedicated Hosts can only be cancelled immediately.", str(ex))
564+
543565
def _get_routers_sample(self):
544566
routers = [
545567
{

0 commit comments

Comments
 (0)