Skip to content

Commit 653b0da

Browse files
author
Kevin McDonald
committed
Improves code quality of block storage ordering code
1 parent 4eac4db commit 653b0da

2 files changed

Lines changed: 186 additions & 122 deletions

File tree

SoftLayer/CLI/block/order.py

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@
2222
@click.option('--iops',
2323
type=int,
2424
help='Performance Storage IOPs,'
25-
+ ' between 100 and 6000 in multiples of 100'
26-
+ ' [required for storage-type performance]')
25+
' between 100 and 6000 in multiples of 100'
26+
' [required for storage-type performance]')
2727
@click.option('--tier',
2828
help='Endurance Storage Tier (IOP per GB)'
29-
+ ' [required for storage-type endurance]',
29+
' [required for storage-type endurance]',
3030
type=click.Choice(['0.25', '2', '4']))
3131
@click.option('--os-type',
3232
help='Operating System',
@@ -62,26 +62,32 @@ def cli(env, storage_type, size, iops, tier, os_type, location):
6262
'Option --iops must be a multiple of 100'
6363
)
6464

65-
order = block_manager.order_block_volume(
66-
storage_type='performance_storage_iscsi',
67-
location=location,
68-
size=size,
69-
iops=iops,
70-
os_type=os_type
71-
)
65+
try:
66+
order = block_manager.order_block_volume(
67+
storage_type='performance_storage_iscsi',
68+
location=location,
69+
size=size,
70+
iops=iops,
71+
os_type=os_type
72+
)
73+
except ValueError as ex:
74+
raise exceptions.ArgumentError(str(ex))
7275

7376
if storage_type == 'endurance':
7477
if tier is None:
7578
raise exceptions.CLIAbort(
7679
'Option --tier required with Endurance in IOPS/GB [0.25,2,4]')
7780

78-
order = block_manager.order_block_volume(
79-
storage_type='storage_service_enterprise',
80-
location=location,
81-
size=size,
82-
tier_level=tier,
83-
os_type=os_type
84-
)
81+
try:
82+
order = block_manager.order_block_volume(
83+
storage_type='storage_service_enterprise',
84+
location=location,
85+
size=size,
86+
tier_level=tier,
87+
os_type=os_type
88+
)
89+
except ValueError as ex:
90+
raise exceptions.ArgumentError(str(ex))
8591

8692
if 'placedOrder' in order.keys():
8793
click.echo("Order #{0} placed successfully!".format(

SoftLayer/managers/block.py

Lines changed: 163 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@
99
from SoftLayer import utils
1010

1111

12+
ENDURANCE_TIERS = {
13+
'0.25': '100',
14+
'2': '200',
15+
'4': '300'
16+
}
17+
18+
1219
class BlockStorageManager(utils.IdentifierMixin, object):
1320
"""Manages Block Storage volumes."""
1421

@@ -149,16 +156,27 @@ def order_block_volume(self, storage_type, location, size, os_type,
149156
try:
150157
location_id = self._get_location_id(location)
151158
except ValueError:
152-
raise exceptions.SoftLayerError("Invalid datacenter name specified. Please provide the lower case short name (e.g.: dal09)")
159+
raise exceptions.SoftLayerError(
160+
"Invalid datacenter name specified. "
161+
"Please provide the lower case short name (e.g.: dal09)")
153162

154163
base_type_name = 'SoftLayer_Container_Product_Order_Network_'
155164
package = self._get_package(storage_type)
156165
if package['name'] == 'Performance':
157166
complex_type = base_type_name + 'PerformanceStorage_Iscsi'
158-
prices = self._get_item_prices_performance(package, size, iops)
167+
prices = [
168+
_find_performance_block_price(package),
169+
_find_performance_space_price(package, iops),
170+
_find_performance_iops_price(package, size, iops),
171+
]
159172
elif package['name'] == 'Endurance':
160173
complex_type = base_type_name + 'Storage_Enterprise'
161-
prices = self._get_item_prices_endurance(package, size, tier_level)
174+
prices = [
175+
_find_endurance_block_price(package),
176+
_find_endurance_price(package),
177+
_find_endurance_space_price(package, size, tier_level),
178+
_find_endurance_tier_price(package, tier_level),
179+
]
162180
else:
163181
raise exceptions.SoftLayerError(
164182
"storage_type must be either Performance or Endurance")
@@ -199,108 +217,6 @@ def _get_package(self, category_code, **kwargs):
199217
func = getattr(self.product_package, 'getAllObjects')
200218
return func(**kwargs).pop()
201219

202-
@staticmethod
203-
def _get_item_prices_performance(package, size, iops):
204-
"""Returns a collection of prices for performance storage.
205-
206-
:param package: Package object
207-
:param size: Size of volume in GB
208-
:param iops: IOPs of volume
209-
:param kwargs:
210-
:return: Returns a collection of prices for performance storage.
211-
"""
212-
parent_category_code = 'performance_storage_iscsi'
213-
space_category_code = 'performance_storage_space'
214-
iops_category_code = 'performance_storage_iops'
215-
216-
found_space_price = False
217-
found_iops_price = False
218-
219-
prices = []
220-
for item in package['items']:
221-
for price in item['prices']:
222-
for category in price['categories']:
223-
if price['locationGroupId'] == '':
224-
# Find the parent-level price object.
225-
if category['categoryCode'] == parent_category_code:
226-
prices.append(price)
227-
# Find the valid space price object.
228-
elif (category['categoryCode'] == space_category_code
229-
and item['capacity'] == size):
230-
prices.append(price)
231-
found_space_price = True
232-
# Find the valid iops price object.
233-
elif (category['categoryCode'] == iops_category_code
234-
and item['capacity'] == iops
235-
and (price['capacityRestrictionMinimum'] <= size
236-
<= price['capacityRestrictionMaximum'])):
237-
prices.append(price)
238-
found_iops_price = True
239-
240-
if found_space_price is False or found_iops_price is False:
241-
raise ValueError(
242-
"No prices found for the requested size and iops.")
243-
244-
return prices
245-
246-
@staticmethod
247-
def _get_item_prices_endurance(package, size, tier_level):
248-
"""Returns a collection of prices for a endurance storage order.
249-
250-
:param package: Package object
251-
:param size: Size of volume in GB
252-
:param iops: IOPs of volume
253-
:param kwargs:
254-
:return: Returns a collection of prices for a endurance storage order.
255-
"""
256-
257-
tiers = {
258-
'0.25': '100',
259-
'2': '200',
260-
'4': '300'
261-
}
262-
263-
endurance_parent_category_codes = [
264-
'storage_service_enterprise',
265-
'storage_block',
266-
]
267-
268-
space_category_code = 'performance_storage_space'
269-
tier_category_code = 'storage_tier_level'
270-
271-
found_space_price = False
272-
found_iops_price = False
273-
274-
prices = []
275-
for item in package['items']:
276-
for price in item['prices']:
277-
for category in price['categories']:
278-
# Only collect prices from valid location groups.
279-
if price['locationGroupId'] == '':
280-
# Find the parent-level price object.
281-
if any(category['categoryCode'] in s
282-
for s in endurance_parent_category_codes):
283-
prices.append(price)
284-
# Find the valid space price object.
285-
elif (category['categoryCode'] == space_category_code
286-
and price['capacityRestrictionMinimum'] ==
287-
tiers.get(tier_level)
288-
and item['capacity'] == size):
289-
prices.append(price)
290-
found_space_price = True
291-
# Find the valid tier price object.
292-
elif (category['categoryCode'] == tier_category_code
293-
and item['attributes'][0]['value'] ==
294-
tiers.get(tier_level)):
295-
prices.append(price)
296-
found_iops_price = True
297-
298-
if found_space_price is False or found_iops_price is False:
299-
raise ValueError(
300-
"No prices found for the requested size and tier.")
301-
302-
return prices
303-
304220
def _get_location_id(self, location):
305221
"""Returns location id
306222
@@ -335,3 +251,145 @@ def cancel_block_volume(self, volume_id,
335251
True,
336252
reason,
337253
id=billing_item_id)
254+
255+
256+
def _find_endurance_block_price(package):
257+
for item in package['items']:
258+
for price in item['prices']:
259+
if price['locationGroupId'] != '':
260+
continue
261+
262+
if not _has_category(price['categories'], 'storage_block'):
263+
continue
264+
265+
return price
266+
267+
raise ValueError("Could not find price for block storage")
268+
269+
270+
def _find_endurance_price(package):
271+
for item in package['items']:
272+
for price in item['prices']:
273+
if price['locationGroupId'] != '':
274+
continue
275+
276+
if not _has_category(price['categories'],
277+
'storage_service_enterprise'):
278+
continue
279+
280+
return price
281+
282+
raise ValueError("Could not find price for endurance block storage")
283+
284+
285+
def _find_endurance_space_price(package, size, tier_level):
286+
for item in package['items']:
287+
if int(item['capacity']) != size:
288+
continue
289+
290+
for price in item['prices']:
291+
# Only collect prices from valid location groups.
292+
if price['locationGroupId'] != '':
293+
continue
294+
295+
if not _has_category(price['categories'],
296+
'performance_storage_space'):
297+
continue
298+
299+
level = ENDURANCE_TIERS.get(tier_level)
300+
if price['capacityRestrictionMinimum'] != level:
301+
continue
302+
303+
return price
304+
305+
raise ValueError("Could not find price for disk space")
306+
307+
308+
def _find_endurance_tier_price(package, tier_level):
309+
for item in package['items']:
310+
for attribute in item['attributes']:
311+
if attribute['value'] != ENDURANCE_TIERS.get(tier_level):
312+
break
313+
else:
314+
continue
315+
316+
for price in item['prices']:
317+
# Only collect prices from valid location groups.
318+
if price['locationGroupId'] != '':
319+
continue
320+
321+
if not _has_category(price['categories'], 'storage_tier_level'):
322+
continue
323+
324+
return price
325+
326+
raise ValueError("Could not find price for tier")
327+
328+
329+
def _find_performance_block_price(package):
330+
for item in package['items']:
331+
for price in item['prices']:
332+
# Only collect prices from valid location groups.
333+
if price['locationGroupId'] != '':
334+
continue
335+
336+
if not _has_category(price['categories'],
337+
'performance_storage_iscsi'):
338+
continue
339+
340+
return price
341+
342+
raise ValueError("Could not find price for performance storage")
343+
344+
345+
def _find_performance_space_price(package, size):
346+
for item in package['items']:
347+
if int(item['capacity']) != size:
348+
continue
349+
350+
for price in item['prices']:
351+
# Only collect prices from valid location groups.
352+
if price['locationGroupId'] != '':
353+
continue
354+
355+
if not _has_category(price['categories'],
356+
'performance_storage_space'):
357+
continue
358+
359+
return price
360+
361+
raise ValueError("Could not find price for disk space")
362+
363+
364+
def _find_performance_iops_price(package, size, iops):
365+
for item in package['items']:
366+
if int(item['capacity']) != int(iops):
367+
continue
368+
369+
for price in item['prices']:
370+
# Only collect prices from valid location groups.
371+
if price['locationGroupId'] != '':
372+
continue
373+
374+
if not _has_category(price['categories'],
375+
'performance_storage_iops'):
376+
continue
377+
378+
if size < int(price['capacityRestrictionMinimum']):
379+
continue
380+
381+
if size > int(price['capacityRestrictionMaximum']):
382+
continue
383+
384+
return price
385+
386+
raise ValueError("Could not find price for iops")
387+
388+
389+
def _has_category(categories, category_code):
390+
return any(
391+
True
392+
for category
393+
in categories
394+
if category['categoryCode'] == category_code
395+
)

0 commit comments

Comments
 (0)