|
9 | 9 | from SoftLayer import utils |
10 | 10 |
|
11 | 11 |
|
| 12 | +ENDURANCE_TIERS = { |
| 13 | + '0.25': '100', |
| 14 | + '2': '200', |
| 15 | + '4': '300' |
| 16 | +} |
| 17 | + |
| 18 | + |
12 | 19 | class BlockStorageManager(utils.IdentifierMixin, object): |
13 | 20 | """Manages Block Storage volumes.""" |
14 | 21 |
|
@@ -149,16 +156,27 @@ def order_block_volume(self, storage_type, location, size, os_type, |
149 | 156 | try: |
150 | 157 | location_id = self._get_location_id(location) |
151 | 158 | 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)") |
153 | 162 |
|
154 | 163 | base_type_name = 'SoftLayer_Container_Product_Order_Network_' |
155 | 164 | package = self._get_package(storage_type) |
156 | 165 | if package['name'] == 'Performance': |
157 | 166 | 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 | + ] |
159 | 172 | elif package['name'] == 'Endurance': |
160 | 173 | 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 | + ] |
162 | 180 | else: |
163 | 181 | raise exceptions.SoftLayerError( |
164 | 182 | "storage_type must be either Performance or Endurance") |
@@ -199,108 +217,6 @@ def _get_package(self, category_code, **kwargs): |
199 | 217 | func = getattr(self.product_package, 'getAllObjects') |
200 | 218 | return func(**kwargs).pop() |
201 | 219 |
|
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 | | - |
304 | 220 | def _get_location_id(self, location): |
305 | 221 | """Returns location id |
306 | 222 |
|
@@ -335,3 +251,145 @@ def cancel_block_volume(self, volume_id, |
335 | 251 | True, |
336 | 252 | reason, |
337 | 253 | 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