From 43c64a041320fd9f08050d1764f8fd4d6b9cf3cf Mon Sep 17 00:00:00 2001 From: Fernando Ojeda Date: Tue, 22 Sep 2020 18:14:39 -0400 Subject: [PATCH 1/3] Add prices to vs create-options. --- SoftLayer/CLI/virt/create_options.py | 325 ++++++++++++++++++++++----- SoftLayer/managers/vs.py | 103 +++++++-- tests/CLI/modules/vs/vs_tests.py | 8 + tests/managers/hardware_tests.py | 3 - tests/managers/vs/vs_tests.py | 85 ++++++- 5 files changed, 443 insertions(+), 81 deletions(-) diff --git a/SoftLayer/CLI/virt/create_options.py b/SoftLayer/CLI/virt/create_options.py index 4e73d55be..c6bca1946 100644 --- a/SoftLayer/CLI/virt/create_options.py +++ b/SoftLayer/CLI/virt/create_options.py @@ -9,16 +9,21 @@ @click.command(short_help="Get options to use for creating virtual servers.") +@click.argument('location', required=False) @click.option('--vsi-type', required=False, show_default=True, default='PUBLIC_CLOUD_SERVER', - type=click.Choice(['TRANSIENT_CLOUD_SERVER', 'SUSPEND_CLOUD_SERVER', 'PUBLIC_CLOUD_SERVER']), + type=click.Choice(['PUBLIC_CLOUD_SERVER', 'TRANSIENT_CLOUD_SERVER', 'SUSPEND_CLOUD_SERVER', + 'CLOUD_SERVER']), help="Display options for a specific virtual server packages, for default is PUBLIC_CLOUD_SERVER, " - "choose between TRANSIENT_CLOUD_SERVER, SUSPEND_CLOUD_SERVER, PUBLIC_CLOUD_SERVER") + "choose between TRANSIENT_CLOUD_SERVER, SUSPEND_CLOUD_SERVER, CLOUD_SERVER") +@click.option('--prices', '-p', is_flag=True, + help='Use --prices to list the server item prices, and to list the Item Prices by location,' + 'add it to the --prices option using location short name, e.g. --prices dal13') @environment.pass_env -def cli(env, vsi_type): +def cli(env, vsi_type, prices, location=None): """Virtual server order options.""" vsi = SoftLayer.VSManager(env.client) - options = vsi.get_create_options(vsi_type) + options = vsi.get_create_options(vsi_type, location) tables = [] @@ -26,72 +31,290 @@ def cli(env, vsi_type): dc_table = formatting.Table(['datacenter', 'Value'], title="Datacenters") dc_table.sortby = 'Value' dc_table.align = 'l' - - for location in options['locations']: - dc_table.add_row([location['name'], location['key']]) + for location_info in options['locations']: + dc_table.add_row([location_info['name'], location_info['key']]) tables.append(dc_table) - # Operation system - os_table = formatting.Table(['OS', 'Key', 'Reference Code'], title="Operating Systems") - os_table.sortby = 'Key' - os_table.align = 'l' + if prices: + preset_prices_table(options['sizes'], tables) + os_prices_table(options['operating_systems'], tables) + port_speed_prices_table(options['port_speed'], tables) + ram_prices_table(options['ram'], tables) + database_prices_table(options['database'], tables) + guest_core_prices_table(options['guest_core'], tables) + guest_disk_prices_table(options['guest_disk'], tables) + extras_prices_table(options['extras'], tables) + else: + # Operation system + os_table = formatting.Table(['OS', 'Key', 'Reference Code'], title="Operating Systems") + os_table.sortby = 'Key' + os_table.align = 'l' - for operating_system in options['operating_systems']: - os_table.add_row([operating_system['name'], operating_system['key'], operating_system['referenceCode']]) - tables.append(os_table) + for operating_system in options['operating_systems']: + os_table.add_row([operating_system['name'], operating_system['key'], operating_system['referenceCode']]) + tables.append(os_table) + + # Sizes + preset_table = formatting.Table(['Size', 'Value'], title="Sizes") + preset_table.sortby = 'Value' + preset_table.align = 'l' + + for size in options['sizes']: + preset_table.add_row([size['name'], size['key']]) + tables.append(preset_table) + + # RAM + ram_table = formatting.Table(['memory', 'Value'], title="RAM") + ram_table.sortby = 'Value' + ram_table.align = 'l' + + for ram in options['ram']: + ram_table.add_row([ram['name'], ram['key']]) + tables.append(ram_table) + + # Data base + database_table = formatting.Table(['database', 'Value'], title="Databases") + database_table.sortby = 'Value' + database_table.align = 'l' + + for database in options['database']: + database_table.add_row([database['name'], database['key']]) + tables.append(database_table) + + # Guest_core + guest_core_table = formatting.Table(['cpu', 'Value', 'Capacity'], title="Guest_core") + guest_core_table.sortby = 'Value' + guest_core_table.align = 'l' + + for guest_core in options['guest_core']: + guest_core_table.add_row([guest_core['name'], guest_core['key'], guest_core['capacity']]) + tables.append(guest_core_table) + + # Guest_core + guest_disk_table = formatting.Table(['guest_disk', 'Value', 'Capacity', 'Disk'], title="Guest_disks") + guest_disk_table.sortby = 'Value' + guest_disk_table.align = 'l' + + for guest_disk in options['guest_disk']: + guest_disk_table.add_row( + [guest_disk['name'], guest_disk['key'], guest_disk['capacity'], guest_disk['disk']]) + tables.append(guest_disk_table) - # Sizes - preset_table = formatting.Table(['Size', 'Value'], title="Sizes") + # Port speed + port_speed_table = formatting.Table(['network', 'Key'], title="Network Options") + port_speed_table.sortby = 'Key' + port_speed_table.align = 'l' + + for speed in options['port_speed']: + port_speed_table.add_row([speed['name'], speed['key']]) + tables.append(port_speed_table) + + env.fout(formatting.listing(tables, separator='\n')) + + +def preset_prices_table(sizes, tables): + """Shows Server Preset options prices. + + :param [] sizes: List of Hardware Server sizes. + :param tables: Table formatting. + """ + preset_table = formatting.Table(['Size', 'Value', 'Hourly', 'Monthly'], title="Sizes Prices") preset_table.sortby = 'Value' preset_table.align = 'l' - - for size in options['sizes']: - preset_table.add_row([size['name'], size['key']]) + for size in sizes: + preset_table.add_row([size['name'], size['key'], "%.4f" % size['hourlyRecurringFee'], + "%.4f" % size['recurringFee']]) tables.append(preset_table) - # RAM - ram_table = formatting.Table(['memory', 'Value'], title="RAM") - ram_table.sortby = 'Value' - ram_table.align = 'l' - for ram in options['ram']: - ram_table.add_row([ram['name'], ram['key']]) +def os_prices_table(operating_systems, tables): + """Shows Server Operating Systems prices cost and capacity restriction. + + :param [] operating_systems: List of Hardware Server operating systems. + :param tables: Table formatting. + """ + os_table = formatting.Table(['OS Key', 'Hourly', 'Monthly', 'Restriction'], + title="Operating Systems Prices") + os_table.sortby = 'OS Key' + os_table.align = 'l' + for operating_system in operating_systems: + for price in operating_system['prices']: + cr_max = _get_price_data(price, 'capacityRestrictionMaximum') + cr_min = _get_price_data(price, 'capacityRestrictionMinimum') + cr_type = _get_price_data(price, 'capacityRestrictionType') + os_table.add_row( + [operating_system['key'], + _get_price_data(price, 'hourlyRecurringFee'), + _get_price_data(price, 'recurringFee'), + "%s - %s %s" % (cr_min, cr_max, cr_type)]) + tables.append(os_table) + + +def port_speed_prices_table(port_speeds, tables): + """Shows Server Port Speeds prices cost and capacity restriction. + + :param [] port_speeds: List of Hardware Server Port Speeds. + :param tables: Table formatting. + """ + port_speed_table = formatting.Table(['Key', 'Speed', 'Hourly', 'Monthly', 'Restriction'], + title="Network Options Prices") + port_speed_table.sortby = 'Speed' + port_speed_table.align = 'l' + for speed in port_speeds: + for price in speed['prices']: + cr_max = _get_price_data(price, 'capacityRestrictionMaximum') + cr_min = _get_price_data(price, 'capacityRestrictionMinimum') + cr_type = _get_price_data(price, 'capacityRestrictionType') + port_speed_table.add_row( + [speed['key'], speed['speed'], + _get_price_data(price, 'hourlyRecurringFee'), + _get_price_data(price, 'recurringFee'), + "%s - %s %s" % (cr_min, cr_max, cr_type)]) + tables.append(port_speed_table) + + +def extras_prices_table(extras, tables): + """Shows Server extras prices cost and capacity restriction. + + :param [] extras: List of Hardware Server Extras. + :param tables: Table formatting. + """ + extras_table = formatting.Table(['Extra Option Key', 'Hourly', 'Monthly', 'Restriction'], + title="Extras Prices") + extras_table.align = 'l' + for extra in extras: + for price in extra['prices']: + cr_max = _get_price_data(price, 'capacityRestrictionMaximum') + cr_min = _get_price_data(price, 'capacityRestrictionMinimum') + cr_type = _get_price_data(price, 'capacityRestrictionType') + extras_table.add_row( + [extra['key'], + _get_price_data(price, 'hourlyRecurringFee'), + _get_price_data(price, 'recurringFee'), + "%s - %s %s" % (cr_min, cr_max, cr_type)]) + tables.append(extras_table) + + +def _location_item_prices(location_prices, tables): + """Get a specific data from HS price. + + :param price: Hardware Server price. + :param string item: Hardware Server price data. + """ + location_prices_table = formatting.Table(['keyName', 'priceId', 'Hourly', 'Monthly', 'Restriction']) + location_prices_table.sortby = 'keyName' + location_prices_table.align = 'l' + for price in location_prices: + cr_max = _get_price_data(price, 'capacityRestrictionMaximum') + cr_min = _get_price_data(price, 'capacityRestrictionMinimum') + cr_type = _get_price_data(price, 'capacityRestrictionType') + location_prices_table.add_row( + [price['item']['keyName'], price['id'], + _get_price_data(price, 'hourlyRecurringFee'), + _get_price_data(price, 'recurringFee'), + "%s - %s %s" % (cr_min, cr_max, cr_type)]) + tables.append(location_prices_table) + + +def ram_prices_table(ram_list, tables): + """Shows Server Port Speeds prices cost and capacity restriction. + + :param [] ram_list: List of Virtual Server Ram. + :param tables: Table formatting. + """ + ram_table = formatting.Table(['Key', 'Hourly', 'Monthly', 'Restriction'], + title="Ram Prices") + ram_table.sortby = 'Key' + ram_table.align = 'l' + for ram in ram_list: + for price in ram['prices']: + cr_max = _get_price_data(price, 'capacityRestrictionMaximum') + cr_min = _get_price_data(price, 'capacityRestrictionMinimum') + cr_type = _get_price_data(price, 'capacityRestrictionType') + ram_table.add_row( + [ram['key'], + _get_price_data(price, 'hourlyRecurringFee'), + _get_price_data(price, 'recurringFee'), + "%s - %s %s" % (cr_min, cr_max, cr_type)]) tables.append(ram_table) - # Data base - database_table = formatting.Table(['database', 'Value'], title="Databases") - database_table.sortby = 'Value' - database_table.align = 'l' - for database in options['database']: - database_table.add_row([database['name'], database['key']]) +def database_prices_table(database_list, tables): + """Shows Server Port Speeds prices cost and capacity restriction. + + :param [] database_list: List of Virtual Server database. + :param tables: Table formatting. + """ + database_table = formatting.Table(['Key', 'Hourly', 'Monthly', 'Restriction'], + title="Data Base Prices") + database_table.sortby = 'Key' + database_table.align = 'l' + for database in database_list: + for price in database['prices']: + cr_max = _get_price_data(price, 'capacityRestrictionMaximum') + cr_min = _get_price_data(price, 'capacityRestrictionMinimum') + cr_type = _get_price_data(price, 'capacityRestrictionType') + database_table.add_row( + [database['key'], + _get_price_data(price, 'hourlyRecurringFee'), + _get_price_data(price, 'recurringFee'), + "%s - %s %s" % (cr_min, cr_max, cr_type)]) tables.append(database_table) - # Guest_core - guest_core_table = formatting.Table(['cpu', 'Value', 'Capacity'], title="Guest_core") - guest_core_table.sortby = 'Value' - guest_core_table.align = 'l' - for guest_core in options['guest_core']: - guest_core_table.add_row([guest_core['name'], guest_core['key'], guest_core['capacity']]) +def guest_core_prices_table(guest_core_list, tables): + """Shows Server Port Speeds prices cost and capacity restriction. + + :param [] guest_core_list: List of Virtual Server guest_core. + :param tables: Table formatting. + """ + guest_core_table = formatting.Table(['Key', 'Hourly', 'Monthly', 'Restriction'], + title="Guest Core Prices") + guest_core_table.sortby = 'Key' + guest_core_table.align = 'l' + for guest_core in guest_core_list: + for price in guest_core['prices']: + cr_max = _get_price_data(price, 'capacityRestrictionMaximum') + cr_min = _get_price_data(price, 'capacityRestrictionMinimum') + cr_type = _get_price_data(price, 'capacityRestrictionType') + guest_core_table.add_row( + [guest_core['key'], + _get_price_data(price, 'hourlyRecurringFee'), + _get_price_data(price, 'recurringFee'), + "%s - %s %s" % (cr_min, cr_max, cr_type)]) tables.append(guest_core_table) - # Guest_core - guest_disk_table = formatting.Table(['guest_disk', 'Value', 'Capacity', 'Disk'], title="Guest_disks") - guest_disk_table.sortby = 'Value' - guest_disk_table.align = 'l' - for guest_disk in options['guest_disk']: - guest_disk_table.add_row([guest_disk['name'], guest_disk['key'], guest_disk['capacity'], guest_disk['disk']]) +def guest_disk_prices_table(guest_disk_list, tables): + """Shows Server Port Speeds prices cost and capacity restriction. + + :param [] guest_disk_list: List of Virtual Server guest_disk. + :param tables: Table formatting. + """ + guest_disk_table = formatting.Table(['Key', 'Hourly', 'Monthly', 'Restriction'], + title="Guest Disk Prices") + guest_disk_table.sortby = 'Key' + guest_disk_table.align = 'l' + for guest_disk in guest_disk_list: + for price in guest_disk['prices']: + cr_max = _get_price_data(price, 'capacityRestrictionMaximum') + cr_min = _get_price_data(price, 'capacityRestrictionMinimum') + cr_type = _get_price_data(price, 'capacityRestrictionType') + guest_disk_table.add_row( + [guest_disk['key'], + _get_price_data(price, 'hourlyRecurringFee'), + _get_price_data(price, 'recurringFee'), + "%s - %s %s" % (cr_min, cr_max, cr_type)]) tables.append(guest_disk_table) - # Port speed - port_speed_table = formatting.Table(['network', 'Key'], title="Network Options") - port_speed_table.sortby = 'Key' - port_speed_table.align = 'l' - for speed in options['port_speed']: - port_speed_table.add_row([speed['name'], speed['key']]) - tables.append(port_speed_table) +def _get_price_data(price, item): + """Get a specific data from HS price. - env.fout(formatting.listing(tables, separator='\n')) + :param price: Hardware Server price. + :param string item: Hardware Server price data. + """ + result = '-' + if item in price: + result = price[item] + return result diff --git a/SoftLayer/managers/vs.py b/SoftLayer/managers/vs.py index 1ddbdc3e1..1a03db1c6 100644 --- a/SoftLayer/managers/vs.py +++ b/SoftLayer/managers/vs.py @@ -13,11 +13,20 @@ from SoftLayer.decoration import retry from SoftLayer import exceptions +from SoftLayer.exceptions import SoftLayerError +from SoftLayer.managers.hardware import _get_preset_cost +from SoftLayer.managers.hardware import get_item_price from SoftLayer.managers import ordering from SoftLayer import utils LOGGER = logging.getLogger(__name__) +EXTRA_CATEGORIES = ['pri_ipv6_addresses', + 'static_ipv6_addresses', + 'sec_ip_addresses', + 'trusted_platform_module', + 'software_guard_extensions'] + # pylint: disable=no-self-use,too-many-lines @@ -249,9 +258,11 @@ def get_instance(self, instance_id, **kwargs): return self.guest.getObject(id=instance_id, **kwargs) @retry(logger=LOGGER) - def get_create_options(self, vsi_type="PUBLIC_CLOUD_SERVER"): + def get_create_options(self, vsi_type="PUBLIC_CLOUD_SERVER", datacenter=None): """Retrieves the available options for creating a VS. + :param string vsi_type: vs keyName. + :param string datacenter: short name, like dal09 :returns: A dictionary of creation options. Example:: @@ -265,26 +276,45 @@ def get_create_options(self, vsi_type="PUBLIC_CLOUD_SERVER"): # SUSPEND_CLOUD_SERVER package = self._get_package(vsi_type) + location_group_id = None + if datacenter: + _filter = {"name": {"operation": datacenter}} + _mask = "mask[priceGroups]" + dc_details = self.client.call('SoftLayer_Location', 'getDatacenters', mask=_mask, filter=_filter, limit=1) + if not dc_details: + raise SoftLayerError("Unable to find a datacenter named {}".format(datacenter)) + # A DC will have several price groups, no good way to deal with this other than checking each. + # An item should only belong to one type of price group. + for group in dc_details[0].get('priceGroups', []): + # We only care about SOME of the priceGroups, which all SHOULD start with `Location Group X` + # Hopefully this never changes.... + if group.get('description').startswith('Location'): + location_group_id = group.get('id') + # Locations locations = [] for region in package['regions']: - locations.append({ - 'name': region['location']['location']['longName'], - 'key': region['location']['location']['name'], - }) + if datacenter is None or datacenter == region['location']['location']['name']: + locations.append({ + 'name': region['location']['location']['longName'], + 'key': region['location']['location']['name'], + }) operating_systems = [] database = [] port_speeds = [] guest_core = [] local_disk = [] + extras = [] ram = [] sizes = [] for preset in package['activePresets'] + package['accountRestrictedActivePresets']: sizes.append({ 'name': preset['description'], - 'key': preset['keyName'] + 'key': preset['keyName'], + 'hourlyRecurringFee': _get_preset_cost(preset, package['items'], 'hourly', location_group_id), + 'recurringFee': _get_preset_cost(preset, package['items'], 'monthly', location_group_id) }) for item in package['items']: @@ -294,33 +324,39 @@ def get_create_options(self, vsi_type="PUBLIC_CLOUD_SERVER"): operating_systems.append({ 'name': item['softwareDescription']['longDescription'], 'key': item['keyName'], - 'referenceCode': item['softwareDescription']['referenceCode'] + 'referenceCode': item['softwareDescription']['referenceCode'], + 'prices': get_item_price(item['prices'], location_group_id) }) # database elif category == 'database': database.append({ 'name': item['description'], - 'key': item['keyName'] + 'key': item['keyName'], + 'prices': get_item_price(item['prices'], location_group_id) }) elif category == 'port_speed': port_speeds.append({ 'name': item['description'], - 'key': item['keyName'] + 'speed': item['capacity'], + 'key': item['keyName'], + 'prices': get_item_price(item['prices'], location_group_id) }) elif category == 'guest_core': guest_core.append({ 'name': item['description'], 'capacity': item['capacity'], - 'key': item['keyName'] + 'key': item['keyName'], + 'prices': get_item_price(item['prices'], location_group_id) }) elif category == 'ram': ram.append({ 'name': item['description'], 'capacity': item['capacity'], - 'key': item['keyName'] + 'key': item['keyName'], + 'prices': get_item_price(item['prices'], location_group_id) }) elif category.__contains__('guest_disk'): @@ -328,9 +364,16 @@ def get_create_options(self, vsi_type="PUBLIC_CLOUD_SERVER"): 'name': item['description'], 'capacity': item['capacity'], 'key': item['keyName'], - 'disk': category + 'disk': category, + 'prices': get_item_price(item['prices'], location_group_id) }) # Extras + elif category in EXTRA_CATEGORIES: + extras.append({ + 'name': item['description'], + 'key': item['keyName'], + 'prices': get_item_price(item['prices'], location_group_id) + }) return { 'locations': locations, @@ -340,22 +383,34 @@ def get_create_options(self, vsi_type="PUBLIC_CLOUD_SERVER"): 'guest_core': guest_core, 'port_speed': port_speeds, 'guest_disk': local_disk, - 'sizes': sizes + 'sizes': sizes, + 'extras': extras, } @retry(logger=LOGGER) def _get_package(self, package_keyname): - """Get the package related to simple hardware ordering.""" - mask = ''' - activePresets, accountRestrictedActivePresets, - items[description, keyName, capacity, - attributes[id, attributeTypeKeyName], - itemCategory[id, categoryCode], - softwareDescription[id, referenceCode, longDescription], prices], - regions[location[location[priceGroups]]]''' - - package_id = self.ordering_manager.get_package_by_key(package_keyname, mask="mask[id]")['id'] - package = self.client.call('Product_Package', 'getObject', id=package_id, mask=mask) + """Get the package related to simple vs ordering. + + :param string package_keyname: Virtual Server package keyName. + """ + items_mask = 'mask[id,keyName,capacity,description,attributes[id,attributeTypeKeyName],' \ + 'itemCategory[id,categoryCode],softwareDescription[id,referenceCode,longDescription],' \ + 'prices[categories]]' + # The preset prices list will only have default prices. The prices->item->prices will have location specific + presets_mask = 'mask[prices]' + region_mask = 'location[location[priceGroups]]' + package = {'items': [], 'activePresets': [], 'accountRestrictedActivePresets': [], 'regions': []} + package_info = self.ordering_manager.get_package_by_key(package_keyname, mask="mask[id]") + + package['items'] = self.client.call('SoftLayer_Product_Package', 'getItems', + id=package_info.get('id'), mask=items_mask) + package['activePresets'] = self.client.call('SoftLayer_Product_Package', 'getActivePresets', + id=package_info.get('id'), mask=presets_mask) + package['accountRestrictedActivePresets'] = self.client.call('SoftLayer_Product_Package', + 'getAccountRestrictedActivePresets', + id=package_info.get('id'), mask=presets_mask) + package['regions'] = self.client.call('SoftLayer_Product_Package', 'getRegions', + id=package_info.get('id'), mask=region_mask) return package def cancel_instance(self, instance_id): diff --git a/tests/CLI/modules/vs/vs_tests.py b/tests/CLI/modules/vs/vs_tests.py index a680e3c72..7fb23b97b 100644 --- a/tests/CLI/modules/vs/vs_tests.py +++ b/tests/CLI/modules/vs/vs_tests.py @@ -317,6 +317,14 @@ def test_create_options(self): result = self.run_command(['vs', 'create-options', '--vsi-type', 'TRANSIENT_CLOUD_SERVER']) self.assert_no_fail(result) + def test_create_options_prices(self): + result = self.run_command(['vs', 'create-options', '--prices', '--vsi-type', 'TRANSIENT_CLOUD_SERVER']) + self.assert_no_fail(result) + + def test_create_options_prices_location(self): + result = self.run_command(['vs', 'create-options', '--prices', 'dal13', '--vsi-type', 'TRANSIENT_CLOUD_SERVER']) + self.assert_no_fail(result) + @mock.patch('SoftLayer.CLI.formatting.confirm') def test_dns_sync_both(self, confirm_mock): confirm_mock.return_value = True diff --git a/tests/managers/hardware_tests.py b/tests/managers/hardware_tests.py index e5b532647..062cafc30 100644 --- a/tests/managers/hardware_tests.py +++ b/tests/managers/hardware_tests.py @@ -247,9 +247,6 @@ def test_get_create_options_prices_by_location(self): 'recurringFee': 0.0 } - print("---------") - print(options) - self.assertEqual(options['extras'][0]['prices'][0]['hourlyRecurringFee'], extras['prices'][0]['hourlyRecurringFee']) self.assertEqual(options['locations'][0], locations) diff --git a/tests/managers/vs/vs_tests.py b/tests/managers/vs/vs_tests.py index cf701d21f..e858b2577 100644 --- a/tests/managers/vs/vs_tests.py +++ b/tests/managers/vs/vs_tests.py @@ -116,9 +116,88 @@ def test_get_instance(self): identifier=100) def test_get_create_options(self): - self.vs.get_create_options() - self.assert_called_with('SoftLayer_Product_Package', 'getObject', - identifier=200) + options = self.vs.get_create_options() + + extras = {'key': '1_IPV6_ADDRESS', 'name': '1 IPv6 Address'} + locations = {'key': 'wdc07', 'name': 'Washington 7'} + operating_systems = { + 'key': 'OS_UBUNTU_14_04_LTS_TRUSTY_TAHR_64_BIT', + 'name': 'Ubuntu / 14.04-64', + 'referenceCode': 'UBUNTU_14_64' + } + + port_speeds = { + 'key': '10', + 'name': '10 Mbps Public & Private Network Uplinks' + } + sizes = { + 'key': 'M1_64X512X25', + 'name': 'M1.64x512x25', + 'hourlyRecurringFee': 0.0, + 'recurringFee': 0.0 + } + + self.assertEqual(options['extras'][0]['key'], extras['key']) + self.assertEqual(options['locations'][0], locations) + self.assertEqual(options['operating_systems'][0]['referenceCode'], + operating_systems['referenceCode']) + self.assertEqual(options['port_speed'][0]['name'], port_speeds['name']) + self.assertEqual(options['sizes'][0], sizes) + + def test_get_create_options_prices_by_location(self): + options = self.vs.get_create_options('wdc07') + + extras = {'key': '1_IPV6_ADDRESS', 'name': '1 IPv6 Address', + 'prices': [ + { + 'hourlyRecurringFee': '0', + 'id': 272, + 'locationGroupId': '', + 'recurringFee': '0', + } + ] + } + locations = {'key': 'wdc07', 'name': 'Washington 7'} + operating_systems = { + 'key': 'OS_UBUNTU_14_04_LTS_TRUSTY_TAHR_64_BIT', + 'name': 'Ubuntu / 14.04-64', + 'referenceCode': 'UBUNTU_14_64', + 'prices': [ + { + 'hourlyRecurringFee': '0', + 'id': 272, + 'locationGroupId': '', + 'recurringFee': '0', + } + ] + } + + port_speeds = { + 'key': '10', + 'name': '10 Mbps Public & Private Network Uplinks', + 'prices': [ + { + 'hourlyRecurringFee': '0', + 'id': 272, + 'locationGroupId': '', + 'recurringFee': '0', + } + ] + } + sizes = { + 'key': 'M1_64X512X25', + 'name': 'M1.64x512x25', + 'hourlyRecurringFee': 0.0, + 'recurringFee': 0.0 + } + + self.assertEqual(options['extras'][0]['prices'][0]['hourlyRecurringFee'], + extras['prices'][0]['hourlyRecurringFee']) + self.assertEqual(options['locations'][0], locations) + self.assertEqual(options['operating_systems'][0]['prices'][0]['locationGroupId'], + operating_systems['prices'][0]['locationGroupId']) + self.assertEqual(options['port_speed'][0]['prices'][0]['id'], port_speeds['prices'][0]['id']) + self.assertEqual(options['sizes'][0], sizes) def test_cancel_instance(self): result = self.vs.cancel_instance(1) From f1abe1a522693d4445a82f9a1a93c2f382886bf9 Mon Sep 17 00:00:00 2001 From: Fernando Ojeda Date: Thu, 1 Oct 2020 18:59:21 -0400 Subject: [PATCH 2/3] Refactor code review. --- SoftLayer/CLI/virt/create_options.py | 310 ++++++++++++--------------- 1 file changed, 133 insertions(+), 177 deletions(-) diff --git a/SoftLayer/CLI/virt/create_options.py b/SoftLayer/CLI/virt/create_options.py index c6bca1946..462090e13 100644 --- a/SoftLayer/CLI/virt/create_options.py +++ b/SoftLayer/CLI/virt/create_options.py @@ -13,8 +13,7 @@ @click.option('--vsi-type', required=False, show_default=True, default='PUBLIC_CLOUD_SERVER', type=click.Choice(['PUBLIC_CLOUD_SERVER', 'TRANSIENT_CLOUD_SERVER', 'SUSPEND_CLOUD_SERVER', 'CLOUD_SERVER']), - help="Display options for a specific virtual server packages, for default is PUBLIC_CLOUD_SERVER, " - "choose between TRANSIENT_CLOUD_SERVER, SUSPEND_CLOUD_SERVER, CLOUD_SERVER") + help="VS keyName type.") @click.option('--prices', '-p', is_flag=True, help='Use --prices to list the server item prices, and to list the Item Prices by location,' 'add it to the --prices option using location short name, e.g. --prices dal13') @@ -35,277 +34,234 @@ def cli(env, vsi_type, prices, location=None): dc_table.add_row([location_info['name'], location_info['key']]) tables.append(dc_table) - if prices: - preset_prices_table(options['sizes'], tables) - os_prices_table(options['operating_systems'], tables) - port_speed_prices_table(options['port_speed'], tables) - ram_prices_table(options['ram'], tables) - database_prices_table(options['database'], tables) - guest_core_prices_table(options['guest_core'], tables) - guest_disk_prices_table(options['guest_disk'], tables) - extras_prices_table(options['extras'], tables) + if vsi_type == 'CLOUD_SERVER': + tables.append(guest_core_prices_table(options['guest_core'], prices)) + tables.append(ram_prices_table(options['ram'], prices)) else: - # Operation system - os_table = formatting.Table(['OS', 'Key', 'Reference Code'], title="Operating Systems") - os_table.sortby = 'Key' - os_table.align = 'l' - - for operating_system in options['operating_systems']: - os_table.add_row([operating_system['name'], operating_system['key'], operating_system['referenceCode']]) - tables.append(os_table) - - # Sizes - preset_table = formatting.Table(['Size', 'Value'], title="Sizes") - preset_table.sortby = 'Value' - preset_table.align = 'l' - - for size in options['sizes']: - preset_table.add_row([size['name'], size['key']]) - tables.append(preset_table) - - # RAM - ram_table = formatting.Table(['memory', 'Value'], title="RAM") - ram_table.sortby = 'Value' - ram_table.align = 'l' - - for ram in options['ram']: - ram_table.add_row([ram['name'], ram['key']]) - tables.append(ram_table) - - # Data base - database_table = formatting.Table(['database', 'Value'], title="Databases") - database_table.sortby = 'Value' - database_table.align = 'l' - - for database in options['database']: - database_table.add_row([database['name'], database['key']]) - tables.append(database_table) - - # Guest_core - guest_core_table = formatting.Table(['cpu', 'Value', 'Capacity'], title="Guest_core") - guest_core_table.sortby = 'Value' - guest_core_table.align = 'l' - - for guest_core in options['guest_core']: - guest_core_table.add_row([guest_core['name'], guest_core['key'], guest_core['capacity']]) - tables.append(guest_core_table) - - # Guest_core - guest_disk_table = formatting.Table(['guest_disk', 'Value', 'Capacity', 'Disk'], title="Guest_disks") - guest_disk_table.sortby = 'Value' - guest_disk_table.align = 'l' - - for guest_disk in options['guest_disk']: - guest_disk_table.add_row( - [guest_disk['name'], guest_disk['key'], guest_disk['capacity'], guest_disk['disk']]) - tables.append(guest_disk_table) - - # Port speed - port_speed_table = formatting.Table(['network', 'Key'], title="Network Options") - port_speed_table.sortby = 'Key' - port_speed_table.align = 'l' - - for speed in options['port_speed']: - port_speed_table.add_row([speed['name'], speed['key']]) - tables.append(port_speed_table) - - env.fout(formatting.listing(tables, separator='\n')) - - -def preset_prices_table(sizes, tables): + tables.append(preset_prices_table(options['sizes'], prices)) + tables.append(os_prices_table(options['operating_systems'], prices)) + tables.append(port_speed_prices_table(options['port_speed'], prices)) + tables.append(database_prices_table(options['database'], prices)) + tables.append(guest_disk_prices_table(options['guest_disk'], prices)) + tables.append(extras_prices_table(options['extras'], prices)) + + env.fout(tables) + + +def preset_prices_table(sizes, prices=False): """Shows Server Preset options prices. :param [] sizes: List of Hardware Server sizes. - :param tables: Table formatting. + :param prices: Include pricing information or not. """ - preset_table = formatting.Table(['Size', 'Value', 'Hourly', 'Monthly'], title="Sizes Prices") + preset_price_table = formatting.Table(['Size', 'Value', 'Hourly', 'Monthly'], title="Sizes Prices") + preset_price_table.sortby = 'Value' + preset_price_table.align = 'l' + + preset_table = formatting.Table(['Size', 'Value'], title="Sizes") preset_table.sortby = 'Value' preset_table.align = 'l' + for size in sizes: - preset_table.add_row([size['name'], size['key'], "%.4f" % size['hourlyRecurringFee'], - "%.4f" % size['recurringFee']]) - tables.append(preset_table) + if (size['hourlyRecurringFee'] > 0) or (size['recurringFee'] > 0): + preset_price_table.add_row([size['name'], size['key'], "%.4f" % size['hourlyRecurringFee'], + "%.4f" % size['recurringFee']]) + preset_table.add_row([size['name'], size['key']]) + if prices: + return preset_price_table + return preset_table -def os_prices_table(operating_systems, tables): +def os_prices_table(operating_systems, prices=False): """Shows Server Operating Systems prices cost and capacity restriction. :param [] operating_systems: List of Hardware Server operating systems. - :param tables: Table formatting. + :param prices: Include pricing information or not. """ - os_table = formatting.Table(['OS Key', 'Hourly', 'Monthly', 'Restriction'], - title="Operating Systems Prices") - os_table.sortby = 'OS Key' + os_price_table = formatting.Table(['OS Key', 'Hourly', 'Monthly', 'Restriction'], + title="Operating Systems Prices") + os_price_table.sortby = 'OS Key' + os_price_table.align = 'l' + + os_table = formatting.Table(['OS', 'Key', 'Reference Code'], title="Operating Systems") + os_table.sortby = 'Key' os_table.align = 'l' + for operating_system in operating_systems: for price in operating_system['prices']: cr_max = _get_price_data(price, 'capacityRestrictionMaximum') cr_min = _get_price_data(price, 'capacityRestrictionMinimum') cr_type = _get_price_data(price, 'capacityRestrictionType') - os_table.add_row( + os_price_table.add_row( [operating_system['key'], _get_price_data(price, 'hourlyRecurringFee'), _get_price_data(price, 'recurringFee'), "%s - %s %s" % (cr_min, cr_max, cr_type)]) - tables.append(os_table) + os_table.add_row([operating_system['name'], operating_system['key'], operating_system['referenceCode']]) + if prices: + return os_price_table + return os_table -def port_speed_prices_table(port_speeds, tables): +def port_speed_prices_table(port_speeds, prices=False): """Shows Server Port Speeds prices cost and capacity restriction. :param [] port_speeds: List of Hardware Server Port Speeds. - :param tables: Table formatting. + :param prices: Include pricing information or not. """ - port_speed_table = formatting.Table(['Key', 'Speed', 'Hourly', 'Monthly', 'Restriction'], - title="Network Options Prices") - port_speed_table.sortby = 'Speed' + port_speed_price_table = formatting.Table(['Key', 'Speed', 'Hourly', 'Monthly'], title="Network Options Prices") + port_speed_price_table.sortby = 'Speed' + port_speed_price_table.align = 'l' + + port_speed_table = formatting.Table(['network', 'Key'], title="Network Options") + port_speed_table.sortby = 'Key' port_speed_table.align = 'l' + for speed in port_speeds: for price in speed['prices']: - cr_max = _get_price_data(price, 'capacityRestrictionMaximum') - cr_min = _get_price_data(price, 'capacityRestrictionMinimum') - cr_type = _get_price_data(price, 'capacityRestrictionType') - port_speed_table.add_row( + port_speed_price_table.add_row( [speed['key'], speed['speed'], _get_price_data(price, 'hourlyRecurringFee'), - _get_price_data(price, 'recurringFee'), - "%s - %s %s" % (cr_min, cr_max, cr_type)]) - tables.append(port_speed_table) + _get_price_data(price, 'recurringFee')]) + port_speed_table.add_row([speed['name'], speed['key']]) + if prices: + return port_speed_price_table + return port_speed_table -def extras_prices_table(extras, tables): +def extras_prices_table(extras, prices=False): """Shows Server extras prices cost and capacity restriction. :param [] extras: List of Hardware Server Extras. - :param tables: Table formatting. + :param prices: Include pricing information or not. """ - extras_table = formatting.Table(['Extra Option Key', 'Hourly', 'Monthly', 'Restriction'], - title="Extras Prices") + extras_price_table = formatting.Table(['Extra Option Key', 'Hourly', 'Monthly'], title="Extras Prices") + extras_price_table.align = 'l' + + extras_table = formatting.Table(['Extra Option', 'Value'], title="Extras") + extras_table.sortby = 'Value' extras_table.align = 'l' + for extra in extras: for price in extra['prices']: - cr_max = _get_price_data(price, 'capacityRestrictionMaximum') - cr_min = _get_price_data(price, 'capacityRestrictionMinimum') - cr_type = _get_price_data(price, 'capacityRestrictionType') - extras_table.add_row( + extras_price_table.add_row( [extra['key'], _get_price_data(price, 'hourlyRecurringFee'), - _get_price_data(price, 'recurringFee'), - "%s - %s %s" % (cr_min, cr_max, cr_type)]) - tables.append(extras_table) - + _get_price_data(price, 'recurringFee')]) + extras_table.add_row([extra['name'], extra['key']]) + if prices: + return extras_price_table + return extras_table -def _location_item_prices(location_prices, tables): - """Get a specific data from HS price. - :param price: Hardware Server price. - :param string item: Hardware Server price data. - """ - location_prices_table = formatting.Table(['keyName', 'priceId', 'Hourly', 'Monthly', 'Restriction']) - location_prices_table.sortby = 'keyName' - location_prices_table.align = 'l' - for price in location_prices: - cr_max = _get_price_data(price, 'capacityRestrictionMaximum') - cr_min = _get_price_data(price, 'capacityRestrictionMinimum') - cr_type = _get_price_data(price, 'capacityRestrictionType') - location_prices_table.add_row( - [price['item']['keyName'], price['id'], - _get_price_data(price, 'hourlyRecurringFee'), - _get_price_data(price, 'recurringFee'), - "%s - %s %s" % (cr_min, cr_max, cr_type)]) - tables.append(location_prices_table) - - -def ram_prices_table(ram_list, tables): +def ram_prices_table(ram_list, prices=False): """Shows Server Port Speeds prices cost and capacity restriction. :param [] ram_list: List of Virtual Server Ram. - :param tables: Table formatting. + :param prices: Include pricing information or not. """ - ram_table = formatting.Table(['Key', 'Hourly', 'Monthly', 'Restriction'], - title="Ram Prices") - ram_table.sortby = 'Key' + ram_price_table = formatting.Table(['Key', 'Hourly', 'Monthly'], title="Ram Prices") + ram_price_table.sortby = 'Key' + ram_price_table.align = 'l' + + ram_table = formatting.Table(['memory', 'Value'], title="RAM") + ram_table.sortby = 'Value' ram_table.align = 'l' + for ram in ram_list: for price in ram['prices']: - cr_max = _get_price_data(price, 'capacityRestrictionMaximum') - cr_min = _get_price_data(price, 'capacityRestrictionMinimum') - cr_type = _get_price_data(price, 'capacityRestrictionType') - ram_table.add_row( + ram_price_table.add_row( [ram['key'], _get_price_data(price, 'hourlyRecurringFee'), - _get_price_data(price, 'recurringFee'), - "%s - %s %s" % (cr_min, cr_max, cr_type)]) - tables.append(ram_table) + _get_price_data(price, 'recurringFee')]) + ram_table.add_row([ram['name'], ram['key']]) + if prices: + return ram_price_table + return ram_table -def database_prices_table(database_list, tables): +def database_prices_table(database_list, prices=False): """Shows Server Port Speeds prices cost and capacity restriction. :param [] database_list: List of Virtual Server database. - :param tables: Table formatting. + :param prices: Include pricing information or not. """ - database_table = formatting.Table(['Key', 'Hourly', 'Monthly', 'Restriction'], + database_price_table = formatting.Table(['Key', 'Hourly', 'Monthly', 'Restriction'], title="Data Base Prices") - database_table.sortby = 'Key' + database_price_table.sortby = 'Key' + database_price_table.align = 'l' + + database_table = formatting.Table(['database', 'Value'], title="Databases") + database_table.sortby = 'Value' database_table.align = 'l' + for database in database_list: for price in database['prices']: cr_max = _get_price_data(price, 'capacityRestrictionMaximum') cr_min = _get_price_data(price, 'capacityRestrictionMinimum') cr_type = _get_price_data(price, 'capacityRestrictionType') - database_table.add_row( + database_price_table.add_row( [database['key'], _get_price_data(price, 'hourlyRecurringFee'), _get_price_data(price, 'recurringFee'), "%s - %s %s" % (cr_min, cr_max, cr_type)]) - tables.append(database_table) + database_table.add_row([database['name'], database['key']]) + if prices: + return database_price_table + return database_table -def guest_core_prices_table(guest_core_list, tables): +def guest_core_prices_table(guest_core_list, prices=False): """Shows Server Port Speeds prices cost and capacity restriction. :param [] guest_core_list: List of Virtual Server guest_core. - :param tables: Table formatting. + :param prices: Include pricing information or not. """ - guest_core_table = formatting.Table(['Key', 'Hourly', 'Monthly', 'Restriction'], - title="Guest Core Prices") - guest_core_table.sortby = 'Key' + guest_core_price_table = formatting.Table(['Key', 'Hourly', 'Monthly'], title="Guest Core Prices") + guest_core_price_table.sortby = 'Key' + guest_core_price_table.align = 'l' + + guest_core_table = formatting.Table(['cpu', 'Value', 'Capacity'], title="Guest_core") + guest_core_table.sortby = 'Value' guest_core_table.align = 'l' + for guest_core in guest_core_list: for price in guest_core['prices']: - cr_max = _get_price_data(price, 'capacityRestrictionMaximum') - cr_min = _get_price_data(price, 'capacityRestrictionMinimum') - cr_type = _get_price_data(price, 'capacityRestrictionType') - guest_core_table.add_row( + guest_core_price_table.add_row( [guest_core['key'], _get_price_data(price, 'hourlyRecurringFee'), - _get_price_data(price, 'recurringFee'), - "%s - %s %s" % (cr_min, cr_max, cr_type)]) - tables.append(guest_core_table) + _get_price_data(price, 'recurringFee')]) + guest_core_table.add_row([guest_core['name'], guest_core['key'], guest_core['capacity']]) + if prices: + return guest_core_price_table + return guest_core_table -def guest_disk_prices_table(guest_disk_list, tables): +def guest_disk_prices_table(guest_disk_list, prices=False): """Shows Server Port Speeds prices cost and capacity restriction. :param [] guest_disk_list: List of Virtual Server guest_disk. - :param tables: Table formatting. + :param prices: Include pricing information or not. """ - guest_disk_table = formatting.Table(['Key', 'Hourly', 'Monthly', 'Restriction'], - title="Guest Disk Prices") - guest_disk_table.sortby = 'Key' + guest_disk_price_table = formatting.Table(['Key', 'Hourly', 'Monthly'], title="Guest Disk Prices") + guest_disk_price_table.sortby = 'Key' + guest_disk_price_table.align = 'l' + + guest_disk_table = formatting.Table(['guest_disk', 'Value', 'Capacity', 'Disk'], title="Guest_disks") + guest_disk_table.sortby = 'Value' guest_disk_table.align = 'l' + for guest_disk in guest_disk_list: for price in guest_disk['prices']: - cr_max = _get_price_data(price, 'capacityRestrictionMaximum') - cr_min = _get_price_data(price, 'capacityRestrictionMinimum') - cr_type = _get_price_data(price, 'capacityRestrictionType') - guest_disk_table.add_row( + guest_disk_price_table.add_row( [guest_disk['key'], _get_price_data(price, 'hourlyRecurringFee'), - _get_price_data(price, 'recurringFee'), - "%s - %s %s" % (cr_min, cr_max, cr_type)]) - tables.append(guest_disk_table) + _get_price_data(price, 'recurringFee')]) + guest_disk_table.add_row( + [guest_disk['name'], guest_disk['key'], guest_disk['capacity'], guest_disk['disk']]) + if prices: + return guest_disk_price_table + return guest_disk_table def _get_price_data(price, item): From 2d1e2bc6e2525771bed11b0a9b82a57e32340a19 Mon Sep 17 00:00:00 2001 From: Fernando Ojeda Date: Thu, 1 Oct 2020 19:05:21 -0400 Subject: [PATCH 3/3] Fix tox analysis. --- SoftLayer/CLI/virt/create_options.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/SoftLayer/CLI/virt/create_options.py b/SoftLayer/CLI/virt/create_options.py index 462090e13..a3ee24314 100644 --- a/SoftLayer/CLI/virt/create_options.py +++ b/SoftLayer/CLI/virt/create_options.py @@ -186,8 +186,7 @@ def database_prices_table(database_list, prices=False): :param [] database_list: List of Virtual Server database. :param prices: Include pricing information or not. """ - database_price_table = formatting.Table(['Key', 'Hourly', 'Monthly', 'Restriction'], - title="Data Base Prices") + database_price_table = formatting.Table(['Key', 'Hourly', 'Monthly', 'Restriction'], title="Data Base Prices") database_price_table.sortby = 'Key' database_price_table.align = 'l'