Skip to content

Commit 6e2d4ae

Browse files
Merge pull request #1360 from ATGE/issues/1346
Fix order item-list --prices location
2 parents 0423459 + 6464fb8 commit 6e2d4ae

File tree

4 files changed

+118
-74
lines changed

4 files changed

+118
-74
lines changed

SoftLayer/CLI/order/item_list.py

Lines changed: 21 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@
1313

1414

1515
@click.command()
16-
@click.argument('location', required=False, nargs=-1, type=click.UNPROCESSED)
1716
@click.argument('package_keyname')
18-
@click.option('--keyword', help="A word (or string) used to filter item names.")
19-
@click.option('--category', help="Category code to filter items by")
17+
@click.option('--keyword', '-k', help="A word (or string) used to filter item names.")
18+
@click.option('--category', '-c', help="Category code to filter items by")
2019
@click.option('--prices', '-p', is_flag=True, help='Use --prices to list the server item prices, and to list the '
2120
'Item Prices by location, add it to the --prices option using '
2221
'location KeyName, e.g. --prices AMSTERDAM02')
22+
@click.argument('location', required=False)
2323
@environment.pass_env
24-
def cli(env, location, package_keyname, keyword, category, prices):
24+
def cli(env, package_keyname, keyword, category, prices, location=None):
2525
"""List package items used for ordering.
2626
2727
The item keyNames listed can be used with `slcli order place` to specify
@@ -57,14 +57,13 @@ def cli(env, location, package_keyname, keyword, category, prices):
5757
if prices:
5858
_item_list_prices(categories, sorted_items, tables)
5959
if location:
60-
location = location[0]
6160
location_prices = manager.get_item_prices_by_location(location, package_keyname)
6261
_location_item_prices(location_prices, location, tables)
6362
else:
6463
table_items_detail = formatting.Table(COLUMNS)
65-
for catname in sorted(categories):
66-
for item in sorted_items[catname]:
67-
table_items_detail.add_row([catname, item['keyName'], item['description'], get_price(item)])
64+
for category_name in sorted(categories):
65+
for item in sorted_items[category_name]:
66+
table_items_detail.add_row([category_name, item['keyName'], item['description'], get_price(item)])
6867
tables.append(table_items_detail)
6968
env.fout(formatting.listing(tables, separator='\n'))
7069

@@ -94,13 +93,13 @@ def get_price(item):
9493
def _item_list_prices(categories, sorted_items, tables):
9594
"""Add the item prices cost and capacity restriction to the table"""
9695
table_prices = formatting.Table(COLUMNS_ITEM_PRICES)
97-
for catname in sorted(categories):
98-
for item in sorted_items[catname]:
96+
for category in sorted(categories):
97+
for item in sorted_items[category]:
9998
for price in item['prices']:
10099
if not price.get('locationGroupId'):
101-
cr_max = _get_price_data(price, 'capacityRestrictionMaximum')
102-
cr_min = _get_price_data(price, 'capacityRestrictionMinimum')
103-
cr_type = _get_price_data(price, 'capacityRestrictionType')
100+
cr_max = get_item_price_data(price, 'capacityRestrictionMaximum')
101+
cr_min = get_item_price_data(price, 'capacityRestrictionMinimum')
102+
cr_type = get_item_price_data(price, 'capacityRestrictionType')
104103
table_prices.add_row([item['keyName'], price['id'],
105104
get_item_price_data(price, 'hourlyRecurringFee'),
106105
get_item_price_data(price, 'recurringFee'),
@@ -117,33 +116,22 @@ def get_item_price_data(price, item_attribute):
117116

118117

119118
def _location_item_prices(location_prices, location, tables):
120-
"""Get a specific data from HS price.
119+
"""Add a location prices table to tables.
121120
122-
:param price: Hardware Server price.
123-
:param string item: Hardware Server price data.
121+
:param list location_prices : Location prices.
122+
:param string location : Location.
123+
:param list tables: Table list to add location prices table.
124124
"""
125125
location_prices_table = formatting.Table(COLUMNS_ITEM_PRICES_LOCATION, title="Item Prices for %s" % location)
126126
location_prices_table.sortby = 'keyName'
127127
location_prices_table.align = 'l'
128128
for price in location_prices:
129-
cr_max = _get_price_data(price, 'capacityRestrictionMaximum')
130-
cr_min = _get_price_data(price, 'capacityRestrictionMinimum')
131-
cr_type = _get_price_data(price, 'capacityRestrictionType')
129+
cr_max = get_item_price_data(price, 'capacityRestrictionMaximum')
130+
cr_min = get_item_price_data(price, 'capacityRestrictionMinimum')
131+
cr_type = get_item_price_data(price, 'capacityRestrictionType')
132132
location_prices_table.add_row(
133133
[price['item']['keyName'], price['id'],
134-
_get_price_data(price, 'hourlyRecurringFee'),
135-
_get_price_data(price, 'recurringFee'),
134+
get_item_price_data(price, 'hourlyRecurringFee'),
135+
get_item_price_data(price, 'recurringFee'),
136136
"%s - %s %s" % (cr_min, cr_max, cr_type)])
137137
tables.append(location_prices_table)
138-
139-
140-
def _get_price_data(price, item):
141-
"""Get a specific data from HS price.
142-
143-
:param price: Hardware Server price.
144-
:param string item: Hardware Server price data.
145-
"""
146-
result = '-'
147-
if item in price:
148-
result = price[item]
149-
return result

SoftLayer/managers/ordering.py

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -669,14 +669,39 @@ def get_location_id(self, location):
669669
return datacenter[0]['id']
670670

671671
def get_item_prices_by_location(self, location, package_keyname):
672-
"""Returns the hardware server item prices by location.
672+
"""Returns the item prices by location.
673673
674674
:param string package_keyname: The package for which to get the items.
675-
:param string location: location to get the item prices.
675+
:param string location: location name or keyname to get the item prices.
676676
"""
677-
object_mask = "filteredMask[pricingLocationGroup[locations[regions]]]"
677+
object_mask = "filteredMask[pricingLocationGroup[locations]]"
678+
location_name = self.resolve_location_name(location)
678679
object_filter = {
679-
"itemPrices": {"pricingLocationGroup": {"locations": {"regions": {"keyname": {"operation": location}}}}}}
680+
"itemPrices": {"pricingLocationGroup": {"locations": {"name": {"operation": location_name}}}}}
680681
package = self.get_package_by_key(package_keyname)
682+
681683
return self.client.call('SoftLayer_Product_Package', 'getItemPrices', mask=object_mask, filter=object_filter,
682684
id=package['id'])
685+
686+
def resolve_location_name(self, location_key):
687+
"""Resolves a location name using a string location key.
688+
689+
:param string location_key: A string location used to resolve the location name.
690+
:return: An location name.
691+
"""
692+
693+
default_region_keyname = 'unknown'
694+
if not location_key or location_key == default_region_keyname:
695+
raise exceptions.SoftLayerError("Invalid location {}".format(location_key))
696+
697+
default_regions = [{'keyname': default_region_keyname}]
698+
index_first = 0
699+
object_mask = "mask[regions]"
700+
locations = self.client.call('SoftLayer_Location', 'getDatacenters', mask=object_mask)
701+
for location in locations:
702+
location_name = location.get('name')
703+
if location_name == location_key:
704+
return location_key
705+
if location.get('regions', default_regions)[index_first].get('keyname') == location_key:
706+
return location_name
707+
raise exceptions.SoftLayerError("Location {} does not exist".format(location_key))

tests/CLI/modules/order_tests.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def test_item_list(self):
4646
self.assertIn('item2', result.output)
4747

4848
def test_item_list_prices(self):
49-
result = self.run_command(['order', 'item-list', '--prices', 'package'])
49+
result = self.run_command(['order', 'item-list', 'package', '--prices'])
5050

5151
self.assert_no_fail(result)
5252
output = json.loads(result.output)
@@ -55,8 +55,28 @@ def test_item_list_prices(self):
5555
self.assertEqual(output[0][1]['keyName'], 'KeyName015')
5656
self.assert_called_with('SoftLayer_Product_Package', 'getItems')
5757

58-
def test_item_list_location(self):
59-
result = self.run_command(['order', 'item-list', '--prices', 'AMSTERDAM02', 'package'])
58+
def test_item_list_location_keyname(self):
59+
result = self.run_command(['order', 'item-list', 'package', '--prices', 'DALLAS13', ])
60+
61+
self.assert_no_fail(result)
62+
output = json.loads(result.output)
63+
self.assertEqual(output[0][0]['Hourly'], 0.0)
64+
self.assertEqual(output[0][1]['keyName'], 'KeyName015')
65+
self.assertEqual(output[0][1]['priceId'], 1144)
66+
self.assert_called_with('SoftLayer_Product_Package', 'getItemPrices')
67+
68+
def test_item_list_location_name(self):
69+
result = self.run_command(['order', 'item-list', 'package', '--prices', 'dal13', ])
70+
71+
self.assert_no_fail(result)
72+
output = json.loads(result.output)
73+
self.assertEqual(output[0][0]['Hourly'], 0.0)
74+
self.assertEqual(output[0][1]['keyName'], 'KeyName015')
75+
self.assertEqual(output[0][1]['priceId'], 1144)
76+
self.assert_called_with('SoftLayer_Product_Package', 'getItemPrices')
77+
78+
def test_item_list_category_keyword(self):
79+
result = self.run_command(['order', 'item-list', 'package', '--prices', 'dal13', '-c', 'os', '-k' 'test'])
6080

6181
self.assert_no_fail(result)
6282
output = json.loads(result.output)

tests/managers/ordering_tests.py

Lines changed: 45 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -776,40 +776,6 @@ def test_get_item_capacity_intel(self):
776776

777777
self.assertEqual(24, int(item_capacity))
778778

779-
def test_get_item_prices_by_location(self):
780-
options = self.ordering.get_item_prices_by_location("MONTREAL", "MONTREAL")
781-
item_prices = [
782-
{
783-
"hourlyRecurringFee": ".093",
784-
"id": 204015,
785-
"recurringFee": "62",
786-
"item": {
787-
"description": "4 x 2.0 GHz or higher Cores",
788-
"id": 859,
789-
"keyName": "GUEST_CORES_4",
790-
},
791-
"pricingLocationGroup": {
792-
"id": 503,
793-
"locations": [
794-
{
795-
"id": 449610,
796-
"longName": "Montreal 1",
797-
"name": "mon01",
798-
"regions": [
799-
{
800-
"description": "MON01 - Montreal",
801-
"keyname": "MONTREAL",
802-
}
803-
]
804-
}
805-
]
806-
}
807-
}
808-
]
809-
810-
self.assertEqual(options[0]['item']['keyName'], item_prices[0]['item']['keyName'])
811-
self.assertEqual(options[0]['hourlyRecurringFee'], item_prices[0]['hourlyRecurringFee'])
812-
813779
def test_get_oder_detail_mask(self):
814780
order_id = 12345
815781
test_mask = 'mask[id]'
@@ -830,3 +796,48 @@ def test_get_oder_detail_default_mask(self):
830796
'items[description],userRecord[displayName,userStatus]]')
831797
self.ordering.get_order_detail(order_id)
832798
self.assert_called_with('SoftLayer_Billing_Order', 'getObject', identifier=order_id, mask=_default_mask)
799+
800+
def test_get_item_prices_by_location_name(self):
801+
object_mask = "filteredMask[pricingLocationGroup[locations]]"
802+
object_filter = {
803+
"itemPrices": {"pricingLocationGroup": {"locations": {"name": {"operation": 'dal13'}}}}}
804+
self.ordering.get_item_prices_by_location('dal13', 'TEST')
805+
806+
self.assert_called_with('SoftLayer_Product_Package', 'getItemPrices', mask=object_mask, filter=object_filter)
807+
808+
def test_get_item_prices_by_location_keyname(self):
809+
object_mask = "filteredMask[pricingLocationGroup[locations]]"
810+
object_filter = {
811+
"itemPrices": {"pricingLocationGroup": {"locations": {"name": {"operation": 'dal13'}}}}}
812+
self.ordering.get_item_prices_by_location('DALLAS13', 'TEST')
813+
814+
self.assert_called_with('SoftLayer_Product_Package', 'getItemPrices', mask=object_mask, filter=object_filter)
815+
816+
def test_resolve_location_name(self):
817+
location_name_expected = 'dal13'
818+
object_mask = "mask[regions]"
819+
location_name = self.ordering.resolve_location_name('DALLAS13')
820+
self.assertEqual(location_name, location_name_expected)
821+
self.assert_called_with('SoftLayer_Location', 'getDatacenters', mask=object_mask)
822+
823+
def test_resolve_location_name_by_keyname(self):
824+
location_name_expected = 'dal13'
825+
object_mask = "mask[regions]"
826+
location_name = self.ordering.resolve_location_name('DALLAS13')
827+
self.assertEqual(location_name, location_name_expected)
828+
self.assert_called_with('SoftLayer_Location', 'getDatacenters', mask=object_mask)
829+
830+
def test_resolve_location_name_by_name(self):
831+
location_name_expected = 'dal13'
832+
object_mask = "mask[regions]"
833+
location_name = self.ordering.resolve_location_name('dal13')
834+
self.assertEqual(location_name, location_name_expected)
835+
self.assert_called_with('SoftLayer_Location', 'getDatacenters', mask=object_mask)
836+
837+
def test_resolve_location_name_invalid(self):
838+
exc = self.assertRaises(exceptions.SoftLayerError, self.ordering.resolve_location_name, None)
839+
self.assertIn("Invalid location", str(exc))
840+
841+
def test_resolve_location_name_not_exist(self):
842+
exc = self.assertRaises(exceptions.SoftLayerError, self.ordering.resolve_location_name, "UNKNOWN_LOCATION_TEST")
843+
self.assertIn("does not exist", str(exc))

0 commit comments

Comments
 (0)