Skip to content

Commit

Permalink
Merge pull request #1782 from allmightyspiff/issues1778
Browse files Browse the repository at this point in the history
Fixing preset-list pricing table
  • Loading branch information
allmightyspiff committed Oct 28, 2022
2 parents 743af77 + e87db34 commit 0671651
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 42 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Manager methods should have a decent docblock describing any parameters and what

Docs are generated with [Sphinx](https://docs.readthedocs.io/en/latest/intro/getting-started-with-sphinx.html) and once Sphinx is setup, you can simply do

`make html` in the softlayer-python/docs directory, which should generate the HTML in softlayer-python/docs/_build/html for testing.
`make html` in the softlayer-python/docs directory, which should generate the HTML in `softlayer-python/docs/_build/html` for testing.


## Unit Tests
Expand Down
2 changes: 1 addition & 1 deletion SoftLayer/CLI/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ def format_help_text(self, ctx: click.Context, formatter: click.formatting.HelpF
if text:
text = inspect.cleandoc(text)

self.console.print(f"\n\t{text}\n")
self.console.print(f"\n\t{text}\n", highlight=False)

def format_epilog(self, ctx: click.Context, formatter: click.formatting.HelpFormatter) -> None:
"""Writes the epilog if it exists, then prints out any sub-commands if they exist."""
Expand Down
75 changes: 54 additions & 21 deletions SoftLayer/CLI/order/preset_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,21 @@
from SoftLayer.CLI import formatting
from SoftLayer.managers import ordering

COLUMNS = ['name',
'keyName',
'description', ]
COLUMNS = ['Name', 'Key Name', 'Description']


@click.command(cls=SLCommand)
@click.argument('package_keyname')
@click.option('--keyword',
help="A word (or string) used to filter preset names.")
@click.option('--prices', '-p', is_flag=True, help='Use --prices to list the server item prices, e.g. --prices')
@click.option('--keyword', help="A word (or string) used to filter preset names.")
@click.option('--prices', '-p', is_flag=True, help='Use --prices to list the server item prices.')
@environment.pass_env
def cli(env, package_keyname, keyword, prices):
"""List package presets.
.. Note::
Presets are set CPU / RAM / Disk allotments. You still need to specify required items.
Some packages do not have presets.
Cost includes all items in a preset, and may include optional items.
::
Expand All @@ -34,7 +32,37 @@ def cli(env, package_keyname, keyword, prices):
# List the Bare Metal server presets that include a GPU
slcli order preset-list BARE_METAL_SERVER --keyword gpu
# Get a specific flavor for Virtual Server
slcli order preset-list PUBLIC_CLOUD_SERVER --prices --keyword BL2.56x242x
# All packages with active presets
slcli call-api SoftLayer_Product_Package getAllObjects --mask="mask[id,keyName,activePresetCount]" \
--json-filter='{"activePresets":{"operation":"not null"}}'
┌───────────────────┬──────┬──────────────────────────────────────────────────────────────────┐
│ activePresetCount │ id │ keyName │
├───────────────────┼──────┼──────────────────────────────────────────────────────────────────┤
│ 1 │ 144 │ 3U_GPU │
│ 6 │ 200 │ BARE_METAL_SERVER │
│ 1 │ 571 │ NETWORK_VLAN │
│ 100 │ 835 │ PUBLIC_CLOUD_SERVER │
│ 6 │ 865 │ NETWORK_VLAN_FOR_SERVICE │
│ 5 │ 885 │ 8U_BI_S2_H4 │
│ 56 │ 991 │ TRANSIENT_CLOUD_SERVER │
│ 56 │ 1035 │ SUSPEND_CLOUD_SERVER │
│ 9 │ 1045 │ 2U_BI_S3_H2000 │
│ 7 │ 1075 │ 2U_IC4V_FIXED_CONFIGURATIONS │
│ 32 │ 1109 │ BI_S4_H2000 │
│ 8 │ 1117 │ BI_S4_H4000 │
│ 7 │ 1119 │ BI_S4_H8000 │
│ 5 │ 2636 │ 2U_BI_S4_H2000_AEP_ENABLED │
│ 5 │ 2676 │ 4U_BI_S4_H4000_AEP_ENABLED │
│ 5 │ 2700 │ 4U_BI_S4_H8000_AEP_ENABLED │
│ 6 │ 2866 │ ORACLE_APPLICATION_CLUSTER_CASCADE_LAKE_SCALABLE_FAMILY_4_DRIVES │
│ 1 │ 2874 │ ORACLE_APPLICATION_CLUSTER_COFFEE_LAKE_E2174G │
└───────────────────┴──────┴──────────────────────────────────────────────────────────────────┘
"""
click.secho("*NOTICE*: Cost includes all items in a preset, and may include optional items.", fg="yellow")
manager = ordering.OrderingManager(env.client)

_filter = {}
Expand All @@ -43,19 +71,23 @@ def cli(env, package_keyname, keyword, prices):
presets = manager.list_presets(package_keyname, filter=_filter)

if prices:
table = formatting.Table(['keyName', 'priceId', 'Hourly', 'Monthly', 'Restriction', 'Location'])
table = formatting.Table(['Id', 'Key Name', 'Hourly', 'Monthly', 'Location'])
table.align = {"Id": "center", "Key Name": "left", "Hourly": "right", "Monthly": "right", "Location": "center"}
for price in presets:
locations = []
locations_list = []
if price['locations'] != []:
for location in price['locations']:
locations.append(location['name'])
cr_max = get_item_price_data(price['prices'][0], 'capacityRestrictionMaximum')
cr_min = get_item_price_data(price['prices'][0], 'capacityRestrictionMinimum')
cr_type = get_item_price_data(price['prices'][0], 'capacityRestrictionType')
table.add_row([price['keyName'], price['id'],
get_item_price_data(price['prices'][0], 'hourlyRecurringFee'),
get_item_price_data(price['prices'][0], 'recurringFee'),
"%s - %s %s" % (cr_min, cr_max, cr_type), str(locations)])
locations_list.append(location['name'])
locations = ', '.join(locations_list)
else:
locations = "All"
table.add_row([
price['id'],
price['keyName'],
get_item_price_data(price['prices'], 'hourlyRecurringFee'),
get_item_price_data(price['prices'], 'recurringFee'),
locations
])

else:
table = formatting.Table(COLUMNS)
Expand All @@ -69,9 +101,10 @@ def cli(env, package_keyname, keyword, prices):
env.fout(table)


def get_item_price_data(price, item_attribute):
def get_item_price_data(prices, item_attribute):
"""Given an SoftLayer_Product_Item_Price, returns its default price data"""
result = '-'
if item_attribute in price:
result = price[item_attribute]
return result
result = 0.0
for this_price in prices:
if item_attribute in this_price:
result = result + float(this_price[item_attribute])
return round(result, 3)
2 changes: 1 addition & 1 deletion SoftLayer/managers/ordering.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

PACKAGE_MASK = '''id, name, keyName, isActive, type'''

PRESET_MASK = '''id, name, keyName, description, categories, prices, locations'''
PRESET_MASK = '''id, name, keyName, description, prices[id, hourlyRecurringFee, recurringFee], locations'''


class OrderingManager(object):
Expand Down
36 changes: 18 additions & 18 deletions tests/CLI/modules/order_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,15 +265,11 @@ def test_verify_monthly(self):
json.loads(result.output))

def test_preset_list(self):
active_preset1 = {'name': 'active1', 'keyName': 'PRESET1',
'description': 'description1'}
active_preset2 = {'name': 'active2', 'keyName': 'PRESET2',
'description': 'description2'}
acc_preset = {'name': 'account1', 'keyName': 'PRESET3',
'description': 'description3'}
active_preset1 = {'name': 'active1', 'keyName': 'PRESET1', 'description': 'description1'}
active_preset2 = {'name': 'active2', 'keyName': 'PRESET2', 'description': 'description2'}
acc_preset = {'name': 'account1', 'keyName': 'PRESET3', 'description': 'description3'}
active_mock = self.set_mock('SoftLayer_Product_Package', 'getActivePresets')
account_mock = self.set_mock('SoftLayer_Product_Package',
'getAccountRestrictedActivePresets')
account_mock = self.set_mock('SoftLayer_Product_Package', 'getAccountRestrictedActivePresets')
active_mock.return_value = [active_preset1, active_preset2]
account_mock.return_value = [acc_preset]

Expand All @@ -282,16 +278,9 @@ def test_preset_list(self):
self.assert_no_fail(result)
self.assert_called_with('SoftLayer_Product_Package', 'getActivePresets')
self.assert_called_with('SoftLayer_Product_Package', 'getAccountRestrictedActivePresets')
self.assertEqual([{'name': 'active1',
'keyName': 'PRESET1',
'description': 'description1'},
{'name': 'active2',
'keyName': 'PRESET2',
'description': 'description2'},
{'name': 'account1',
'keyName': 'PRESET3',
'description': 'description3'}],
json.loads(result.output))
self.assertIn('"Key Name": "PRESET1",', result.output)
self.assertIn('"Description": "description2"', result.output)
self.assertIn('"Name": "account1",', result.output)

def test_preset_list_keywork(self):
result = self.run_command(['order', 'preset-list', 'package', '--keyword', 'testKeyWord'])
Expand All @@ -300,9 +289,20 @@ def test_preset_list_keywork(self):
self.assert_called_with('SoftLayer_Product_Package', 'getActivePresets', filter=_filter)

def test_preset_list_prices(self):
active_preset1 = {
'name': 'active1', 'keyName': 'PRESET1', 'description': 'description1', 'locations': [], 'id': 118822,
'prices': [
{'hourlyRecurringFee': 100, 'recurringFee': 55},
{'hourlyRecurringFee': 110, 'recurringFee': 44},
]
}
active_mock = self.set_mock('SoftLayer_Product_Package', 'getActivePresets')
active_mock.return_value = [active_preset1]
result = self.run_command(['order', 'preset-list', 'package', '--prices'])
self.assert_no_fail(result)
self.assert_called_with('SoftLayer_Product_Package', 'getActivePresets')
self.assertIn("210", result.output)
self.assertIn("99", result.output)

def test_location_list(self):
result = self.run_command(['order', 'package-locations', 'package'])
Expand Down

0 comments on commit 0671651

Please sign in to comment.