Skip to content

Commit 2fe44f5

Browse files
Merge pull request #1455 from FernandoOjeda/ft/hw_upgrade_disk
Add the option to add and upgrade the hw disk.
2 parents 9a5f20a + 9c4f3ba commit 2fe44f5

File tree

5 files changed

+201
-9
lines changed

5 files changed

+201
-9
lines changed

SoftLayer/CLI/hardware/upgrade.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,24 +24,40 @@
2424
default=None,
2525
type=click.Choice(['Non-RAID', 'RAID']))
2626
@click.option('--public-bandwidth', type=click.INT, help="Public Bandwidth in GB")
27+
@click.option('--add-disk', nargs=2, multiple=True, type=(int, int),
28+
help="Add a Hard disk in GB to a specific channel, e.g 1000 GB in disk2, it will be "
29+
"--add-disk 1000 2")
30+
@click.option('--resize-disk', nargs=2, multiple=True, type=(int, int),
31+
help="Upgrade a specific disk size in GB, e.g --resize-disk 2000 2")
2732
@click.option('--test', is_flag=True, default=False, help="Do not actually upgrade the hardware server")
2833
@environment.pass_env
29-
def cli(env, identifier, memory, network, drive_controller, public_bandwidth, test):
34+
def cli(env, identifier, memory, network, drive_controller, public_bandwidth, add_disk, resize_disk, test):
3035
"""Upgrade a Hardware Server."""
3136

3237
mgr = SoftLayer.HardwareManager(env.client)
3338

34-
if not any([memory, network, drive_controller, public_bandwidth]):
39+
if not any([memory, network, drive_controller, public_bandwidth, add_disk, resize_disk]):
3540
raise exceptions.ArgumentError("Must provide "
36-
" [--memory], [--network], [--drive-controller], or [--public-bandwidth]")
41+
" [--memory], [--network], [--drive-controller], [--public-bandwidth],"
42+
"[--add-disk] or [--resize-disk]")
3743

3844
hw_id = helpers.resolve_id(mgr.resolve_ids, identifier, 'Hardware')
3945
if not test:
4046
if not (env.skip_confirmations or formatting.confirm(
4147
"This action will incur charges on your account. Continue?")):
4248
raise exceptions.CLIAbort('Aborted')
4349

50+
disk_list = list()
51+
if add_disk:
52+
for guest_disk in add_disk:
53+
disks = {'description': 'add_disk', 'capacity': guest_disk[0], 'number': guest_disk[1]}
54+
disk_list.append(disks)
55+
if resize_disk:
56+
for guest_disk in resize_disk:
57+
disks = {'description': 'resize_disk', 'capacity': guest_disk[0], 'number': guest_disk[1]}
58+
disk_list.append(disks)
59+
4460
if not mgr.upgrade(hw_id, memory=memory, nic_speed=network, drive_controller=drive_controller,
45-
public_bandwidth=public_bandwidth, test=test):
61+
public_bandwidth=public_bandwidth, disk=disk_list, test=test):
4662
raise exceptions.CLIAbort('Hardware Server Upgrade Failed')
4763
env.fout('Successfully Upgraded.')

SoftLayer/fixtures/SoftLayer_Hardware_Server.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
'children': [
1414
{'description': 'test', 'nextInvoiceTotalRecurringAmount': 1},
1515
],
16+
'nextInvoiceChildren': [
17+
{'description': 'test', 'nextInvoiceTotalRecurringAmount': 1, 'categoryCode': 'disk1'},
18+
{'description': 'test2', 'nextInvoiceTotalRecurringAmount': 2, 'categoryCode': 'disk3'}
19+
],
1620
'orderItem': {
1721
'order': {
1822
'userRecord': {
@@ -336,5 +340,40 @@
336340
"id": 6177,
337341
"keyName": "BANDWIDTH_500_GB"
338342
}
343+
},
344+
{
345+
"hourlyRecurringFee": ".023",
346+
"id": 49759,
347+
"recurringFee": "15",
348+
"categories": [
349+
{
350+
"categoryCode": "disk2",
351+
"id": 6,
352+
"name": "Third Hard Drive"
353+
}
354+
],
355+
"item": {
356+
"capacity": "1000",
357+
"description": "1.00 TB SATA",
358+
"id": 6159,
359+
"keyName": "HARD_DRIVE_1_00_TB_SATA_2",
360+
}
361+
},
362+
{
363+
"id": 49759,
364+
"recurringFee": "0",
365+
"categories": [
366+
{
367+
"categoryCode": "disk1",
368+
"id": 5,
369+
"name": "Second Hard Drive"
370+
}
371+
],
372+
"item": {
373+
"capacity": "1000",
374+
"description": "1.00 TB SATA",
375+
"id": 6159,
376+
"keyName": "HARD_DRIVE_1_00_TB_SATA_2"
377+
}
339378
}
340379
]

SoftLayer/managers/hardware.py

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -821,14 +821,15 @@ def authorize_storage(self, hardware_id, username_storage):
821821

822822
def upgrade(self, instance_id, memory=None,
823823
nic_speed=None, drive_controller=None,
824-
public_bandwidth=None, test=False):
824+
public_bandwidth=None, disk=None, test=False):
825825
"""Upgrades a hardware server instance.
826826
827827
:param int instance_id: Instance id of the hardware server to be upgraded.
828828
:param int memory: Memory size.
829829
:param string nic_speed: Network Port Speed data.
830830
:param string drive_controller: Drive Controller data.
831831
:param int public_bandwidth: Public keyName data.
832+
:param list disk: List of disks to add or upgrade Hardware Server.
832833
:param bool test: Test option to verify the request.
833834
834835
:returns: bool
@@ -860,6 +861,10 @@ def upgrade(self, instance_id, memory=None,
860861
'packageId': package_id
861862
}
862863

864+
if disk:
865+
prices = self._get_disk_price_list(instance_id, disk)
866+
order['prices'] = prices
867+
863868
for option, value in data.items():
864869
price_id = self._get_prices_for_upgrade_option(upgrade_prices, option, value)
865870
if not price_id:
@@ -888,13 +893,13 @@ def get_instance(self, instance_id):
888893
the specified instance.
889894
"""
890895
mask = [
891-
'billingItem[id,package[id,keyName]]'
896+
'billingItem[id,package[id,keyName],nextInvoiceChildren]'
892897
]
893898
mask = "mask[%s]" % ','.join(mask)
894899

895900
return self.hardware.getObject(id=instance_id, mask=mask)
896901

897-
def _get_upgrade_prices(self, instance_id, include_downgrade_options=True):
902+
def _get_upgrade_prices(self, instance_id):
898903
"""Following Method gets all the price ids related to upgrading a Hardware Server.
899904
900905
:param int instance_id: Instance id of the Hardware Server to be upgraded.
@@ -908,7 +913,7 @@ def _get_upgrade_prices(self, instance_id, include_downgrade_options=True):
908913
'item[keyName,description,capacity,units]'
909914
]
910915
mask = "mask[%s]" % ','.join(mask)
911-
return self.hardware.getUpgradeItemPrices(include_downgrade_options, id=instance_id, mask=mask)
916+
return self.hardware.getUpgradeItemPrices(id=instance_id, mask=mask)
912917

913918
@staticmethod
914919
def _get_prices_for_upgrade_option(upgrade_prices, option, value):
@@ -927,7 +932,10 @@ def _get_prices_for_upgrade_option(upgrade_prices, option, value):
927932
'disk_controller': 'disk_controller',
928933
'bandwidth': 'bandwidth'
929934
}
930-
category_code = option_category.get(option)
935+
if 'disk' in option:
936+
category_code = option
937+
else:
938+
category_code = option_category.get(option)
931939

932940
for price in upgrade_prices:
933941
if price.get('categories') is None or price.get('item') is None:
@@ -953,12 +961,75 @@ def _get_prices_for_upgrade_option(upgrade_prices, option, value):
953961
elif option == 'bandwidth':
954962
if str(product.get('capacity')) == str(value):
955963
price_id = price.get('id')
964+
elif 'disk' in option:
965+
if str(product.get('capacity')) == str(value):
966+
price_id = price
956967
else:
957968
if str(product.get('capacity')) == str(value):
958969
price_id = price.get('id')
959970

960971
return price_id
961972

973+
def _get_disk_price_list(self, instance_id, disk):
974+
"""Get the disks prices to be added or upgraded.
975+
976+
:param int instance_id: Hardware Server instance id.
977+
:param list disk: List of disks to be added o upgraded to the HW.
978+
979+
:return list.
980+
"""
981+
prices = []
982+
disk_exist = False
983+
upgrade_prices = self._get_upgrade_prices(instance_id)
984+
server_response = self.get_instance(instance_id)
985+
for disk_data in disk:
986+
disk_channel = 'disk' + str(disk_data.get('number'))
987+
for item in utils.lookup(server_response, 'billingItem', 'nextInvoiceChildren'):
988+
if disk_channel == item['categoryCode']:
989+
disk_exist = True
990+
break
991+
if disk_exist:
992+
disk_price_detail = self._get_disk_price_detail(disk_data, upgrade_prices, disk_channel, 'add_disk')
993+
prices.append(disk_price_detail)
994+
else:
995+
disk_price_detail = self._get_disk_price_detail(disk_data, upgrade_prices, disk_channel, 'resize_disk')
996+
prices.append(disk_price_detail)
997+
998+
return prices
999+
1000+
def _get_disk_price_detail(self, disk_data, upgrade_prices, disk_channel, disk_type):
1001+
"""Get the disk price detail.
1002+
1003+
:param disk_data: List of disks to be added or upgraded.
1004+
:param list upgrade_prices: List of item prices.
1005+
:param String disk_channel: Disk position.
1006+
:param String disk_type: Disk type.
1007+
1008+
"""
1009+
if disk_data.get('description') == disk_type:
1010+
if "add" in disk_type:
1011+
raise SoftLayerError("Unable to add the disk because this already exists.")
1012+
if "resize" in disk_type:
1013+
raise SoftLayerError("Unable to resize the disk because this does not exists.")
1014+
else:
1015+
price_id = self._get_prices_for_upgrade_option(upgrade_prices, disk_channel,
1016+
disk_data.get('capacity'))
1017+
if not price_id:
1018+
raise SoftLayerError("The item price was not found for %s with 'capacity:' %i" %
1019+
(disk_channel, disk_data.get('capacity')))
1020+
1021+
disk_price = {
1022+
"id": price_id.get('id'),
1023+
"categories": [
1024+
{
1025+
"categoryCode": price_id['categories'][0]['categoryCode'],
1026+
"id": price_id['categories'][0]['id']
1027+
}
1028+
]
1029+
}
1030+
1031+
return disk_price
1032+
9621033

9631034
def _get_bandwidth_key(items, hourly=True, no_public=False, location=None):
9641035
"""Picks a valid Bandwidth Item, returns the KeyName"""

tests/CLI/modules/server_tests.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -944,6 +944,41 @@ def test_upgrade_test(self, confirm_mock):
944944
'--drive-controller=RAID', '--network=10000 Redundant'])
945945
self.assert_no_fail(result)
946946

947+
@mock.patch('SoftLayer.CLI.formatting.confirm')
948+
def test_upgrade_add_disk(self, confirm_mock):
949+
confirm_mock.return_value = True
950+
result = self.run_command(['hw', 'upgrade', '100', '--add-disk=1000', '2'])
951+
952+
self.assert_no_fail(result)
953+
954+
@mock.patch('SoftLayer.CLI.formatting.confirm')
955+
def test_upgrade_resize_disk(self, confirm_mock):
956+
confirm_mock.return_value = True
957+
result = self.run_command(['hw', 'upgrade', '100', '--resize-disk=1000', '1'])
958+
959+
self.assert_no_fail(result)
960+
961+
@mock.patch('SoftLayer.CLI.formatting.confirm')
962+
def test_upgrade_disk_not_price_found(self, confirm_mock):
963+
confirm_mock.return_value = False
964+
result = self.run_command(['hw', 'upgrade', '100', '--add-disk=1000', '3'])
965+
self.assertEqual(result.exit_code, 2)
966+
self.assertIsInstance(result.exception, exceptions.CLIAbort)
967+
968+
@mock.patch('SoftLayer.CLI.formatting.confirm')
969+
def test_upgrade_disk_already_exist(self, confirm_mock):
970+
confirm_mock.return_value = False
971+
result = self.run_command(['hw', 'upgrade', '100', '--add-disk=1000', '1'])
972+
self.assertEqual(result.exit_code, 2)
973+
self.assertIsInstance(result.exception, exceptions.CLIAbort)
974+
975+
@mock.patch('SoftLayer.CLI.formatting.confirm')
976+
def test_upgrade_disk_does_not_exist(self, confirm_mock):
977+
confirm_mock.return_value = False
978+
result = self.run_command(['hw', 'upgrade', '100', '--resize-disk=1000', '3'])
979+
self.assertEqual(result.exit_code, 2)
980+
self.assertIsInstance(result.exception, exceptions.CLIAbort)
981+
947982
@mock.patch('SoftLayer.CLI.formatting.confirm')
948983
def test_upgrade(self, confirm_mock):
949984
confirm_mock.return_value = True

tests/managers/hardware_tests.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,13 @@ def test_get_price_id_mismatch_capacity(self):
869869
result = self.hardware._get_prices_for_upgrade_option(upgrade_prices, 'memory', 1)
870870
self.assertEqual(92, result)
871871

872+
def test_get_price_id_disk_capacity(self):
873+
upgrade_prices = [
874+
{'categories': [{'categoryCode': 'disk1'}], 'item': {'capacity': 1}, 'id': 99}
875+
]
876+
result = self.hardware._get_prices_for_upgrade_option(upgrade_prices, 'disk1', 1)
877+
self.assertEqual(99, result['id'])
878+
872879
def test_upgrade(self):
873880
result = self.hardware.upgrade(1, memory=32)
874881

@@ -878,6 +885,30 @@ def test_upgrade(self):
878885
order_container = call.args[0]
879886
self.assertEqual(order_container['prices'], [{'id': 209391}])
880887

888+
def test_upgrade_add_disk(self):
889+
disk_list = list()
890+
disks = {'description': 'add_disk', 'capacity': 1000, 'number': 2}
891+
disk_list.append(disks)
892+
result = self.hardware.upgrade(1, disk=disk_list)
893+
894+
self.assertEqual(result, True)
895+
self.assert_called_with('SoftLayer_Product_Order', 'placeOrder')
896+
call = self.calls('SoftLayer_Product_Order', 'placeOrder')[0]
897+
order_container = call.args[0]
898+
self.assertEqual(order_container['prices'][0]['id'], 49759)
899+
900+
def test_upgrade_resize_disk(self):
901+
disk_list = list()
902+
disks = {'description': 'resize_disk', 'capacity': 1000, 'number': 1}
903+
disk_list.append(disks)
904+
result = self.hardware.upgrade(1, disk=disk_list)
905+
906+
self.assertEqual(result, True)
907+
self.assert_called_with('SoftLayer_Product_Order', 'placeOrder')
908+
call = self.calls('SoftLayer_Product_Order', 'placeOrder')[0]
909+
order_container = call.args[0]
910+
self.assertEqual(order_container['prices'][0]['id'], 49759)
911+
881912
def test_upgrade_blank(self):
882913
result = self.hardware.upgrade(1)
883914

0 commit comments

Comments
 (0)