Skip to content

Support for NVMe Dual Raid card ordering. #2226

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .secrets.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"files": "^.secrets.baseline$",
"lines": null
},
"generated_at": "2025-02-14T20:05:29Z",
"generated_at": "2025-06-11T21:28:32Z",
"plugins_used": [
{
"name": "AWSKeyDetector"
Expand Down Expand Up @@ -700,7 +700,7 @@
"hashed_secret": "8af1f8146d96a3cd862281442d0d6c5cb6f8f9e5",
"is_secret": false,
"is_verified": false,
"line_number": 181,
"line_number": 187,
"type": "Hex High Entropy String",
"verified_result": null
}
Expand Down
41 changes: 32 additions & 9 deletions SoftLayer/managers/ordering.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,10 +357,14 @@ def get_preset_by_key(self, package_keyname, preset_keyname, mask=None):
if len(presets) == 0:
raise exceptions.SoftLayerError(
f"Preset {preset_keyname} does not exist in package {package_keyname}")

return presets[0]

def get_price_id_list(self, package_keyname, item_keynames, core=None):
"""Returns just a list of price IDs for backwards compatability"""
prices = self.get_ordering_prices(package_keyname, item_keynames, core)
return [price.get('id') for price in prices]

def get_ordering_prices(self, package_keyname: str, item_keynames: list, core=None) -> list:
"""Converts a list of item keynames to a list of price IDs.

This function is used to convert a list of item keynames into
Expand All @@ -370,8 +374,7 @@ def get_price_id_list(self, package_keyname, item_keynames, core=None):
:param str package_keyname: The package associated with the prices
:param list item_keynames: A list of item keyname strings
:param str core: preset guest core capacity.
:returns: A list of price IDs associated with the given item
keynames in the given package
:returns: A list of price IDs associated with the given item keynames in the given package

"""
mask = 'id, description, capacity, itemCategory, keyName, prices[categories], ' \
Expand All @@ -380,7 +383,8 @@ def get_price_id_list(self, package_keyname, item_keynames, core=None):
item_capacity = self.get_item_capacity(items, item_keynames)

prices = []
category_dict = {"gpu0": -1, "pcie_slot0": -1}
# start at -1 so we can increment before we use it. 0 is a valid value here
category_dict = {"gpu0": -1, "pcie_slot0": -1, "disk_controller": -1}

for item_keyname in item_keynames:
matching_item = []
Expand Down Expand Up @@ -410,15 +414,33 @@ def get_price_id_list(self, package_keyname, item_keynames, core=None):
# GPU and PCIe items has two generic prices and they are added to the list
# according to the number of items in the order.
category_dict[item_category] += 1
category_code = item_category[:-1] + str(category_dict[item_category])
item_category = self.get_special_category(category_dict[item_category], item_category)

price_id = [p['id'] for p in matching_item['prices']
if not p['locationGroupId']
and p['categories'][0]['categoryCode'] == category_code][0]
and p['categories'][0]['categoryCode'] == item_category][0]

prices.append(price_id)
prices.append({
"id": price_id,
"categories": [{"categoryCode": item_category}],
"item": {"keyName": item_keyname}
})

return prices

@staticmethod
def get_special_category(index: int, base: str) -> str:
"""Handles cases where we need to find price on a special category price id"""
# disk_controller and disk_controller1
if base == "disk_controller":
if index == 0:
return base
else:
return f"{base}1"

# gpu0 and gpu1, pcie_slot0 and pcie_slot1
return base[:-1] + str(index)

@staticmethod
def get_item_price_id(core, prices, term=0):
"""get item price id
Expand Down Expand Up @@ -644,8 +666,9 @@ def generate_order(self, package_keyname, location, item_keynames, complex_type=
raise exceptions.SoftLayerError("A complex type must be specified with the order")
order['complexType'] = complex_type

price_ids = self.get_price_id_list(package_keyname, item_keynames, preset_core)
order['prices'] = [{'id': price_id} for price_id in price_ids]
order['prices'] = self.get_ordering_prices(package_keyname, item_keynames, preset_core)
# price_ids = self.get_price_id_list(package_keyname, item_keynames, preset_core)
# order['prices'] = [{'id': price_id} for price_id in price_ids]

container['orderContainers'] = [order]

Expand Down
18 changes: 9 additions & 9 deletions tests/managers/ordering_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,13 +435,13 @@ def test_generate_order(self):
pkg = 'PACKAGE_KEYNAME'
items = ['ITEM1', 'ITEM2']
complex_type = 'My_Type'
expected_order = {'orderContainers': [
{'complexType': 'My_Type',
'location': 1854895,
'packageId': 1234,
'prices': [{'id': 1111}, {'id': 2222}],
'quantity': 1,
'useHourlyPricing': True}
expected_order = {'orderContainers': [{
'complexType': 'My_Type',
'location': 1854895,
'packageId': 1234,
'prices': [{'id': 1111}, {'id': 2222}],
'quantity': 1,
'useHourlyPricing': True}
]}

mock_pkg, mock_preset, mock_get_ids = self._patch_for_generate()
Expand Down Expand Up @@ -568,7 +568,7 @@ def _patch_for_generate(self):
# with patchers
mock_pkg = mock.patch.object(self.ordering, 'get_package_by_key')
mock_preset = mock.patch.object(self.ordering, 'get_preset_by_key')
mock_get_ids = mock.patch.object(self.ordering, 'get_price_id_list')
mock_get_ids = mock.patch.object(self.ordering, 'get_ordering_prices')

# start each patcher, and set a cleanup to stop each patcher as well
to_return = []
Expand All @@ -579,7 +579,7 @@ def _patch_for_generate(self):
# set the return values on each of the mocks
to_return[0].return_value = {'id': 1234}
to_return[1].return_value = {'id': 5678}
to_return[2].return_value = [1111, 2222]
to_return[2].return_value = [{'id': 1111}, {'id': 2222}]
return to_return

def test_get_location_id_short(self):
Expand Down
14 changes: 10 additions & 4 deletions tests/managers/vs/vs_capacity_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,11 @@ def test_create(self):
'quantity': 5,
'useHourlyPricing': True,
'complexType': 'SoftLayer_Container_Product_Order_Virtual_ReservedCapacity',
'prices': [{'id': 217561}
]
'prices': [{
'id': 217561,
'categories': [{'categoryCode': 'reserved_capacity'}],
'item': {'keyName': 'B1_1X2_1_YEAR_TERM'}
}]
}
]
}
Expand All @@ -103,8 +106,11 @@ def test_create_test(self):
'quantity': 5,
'useHourlyPricing': True,
'complexType': 'SoftLayer_Container_Product_Order_Virtual_ReservedCapacity',
'prices': [{'id': 217561}],

'prices': [{
'id': 217561,
'categories': [{'categoryCode': 'reserved_capacity'}],
'item': {'keyName': 'B1_1X2_1_YEAR_TERM'}
}]
}
]
}
Expand Down