Skip to content

Commit 9035b10

Browse files
authored
Merge pull request #56 from release-engineering/fixazure
Azure: Fix update_skus rountine for Gen1 default
2 parents ea39a5c + 0eb8e95 commit 9035b10

2 files changed

Lines changed: 121 additions & 29 deletions

File tree

cloudpub/ms_azure/utils.py

Lines changed: 58 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,38 @@ def prepare_vm_images(
235235
return [VMImageDefinition.from_json(json_gen1)]
236236

237237

238+
def _build_skus(
239+
disk_versions: List[DiskVersion],
240+
default_gen: str,
241+
alt_gen: str,
242+
plan_name: str,
243+
security_type: Optional[List[str]] = None,
244+
) -> List[VMISku]:
245+
sku_mapping: Dict[str, str] = {}
246+
# Update the SKUs for each image in DiskVersions if needed
247+
for disk_version in disk_versions:
248+
# Each disk version may have multiple images (Gen1 / Gen2)
249+
for vmid in disk_version.vm_images:
250+
# We'll name the main generation SKU as "{plan_name}" and
251+
# the alternate generation SKU as "{plan-name}-genX"
252+
arch = vmid.image_type.split("Gen")[0]
253+
new_img_type = get_image_type_mapping(arch, default_gen)
254+
new_img_alt_type = get_image_type_mapping(arch, alt_gen)
255+
256+
# we just want to add SKU whenever it's not set
257+
if vmid.image_type == new_img_type:
258+
sku_mapping.setdefault(new_img_type, plan_name)
259+
elif vmid.image_type == new_img_alt_type:
260+
sku_mapping.setdefault(new_img_alt_type, f"{plan_name}-gen{alt_gen[1:]}")
261+
262+
# Return the expected SKUs list
263+
res = [
264+
VMISku.from_json({"image_type": k, "id": v, "security_type": security_type})
265+
for k, v in sku_mapping.items()
266+
]
267+
return sorted(res, key=attrgetter("id"))
268+
269+
238270
def update_skus(
239271
disk_versions: List[DiskVersion],
240272
generation: str,
@@ -257,33 +289,33 @@ def update_skus(
257289
Returns:
258290
The updated list with VMISkus.
259291
"""
260-
sku_mapping: Dict[str, str] = {}
261-
# All SKUs must have the same security_type thus picking the first one is OK
262-
security_type = old_skus[0].security_type if old_skus else None
263-
264-
# Update the SKUs for each image in DiskVersions
265-
for disk_version in disk_versions:
266-
# Each disk version may have multiple images (Gen1 / Gen2)
267-
for vmid in disk_version.vm_images:
268-
# We'll name the main generation SKU as "{plan_name}" and
269-
# the alternate generation SKU as "{plan-name}-genX"
270-
alt_gen = 2 if generation == "V1" else 1
271-
arch = vmid.image_type.split("Gen")[0]
272-
new_img_type = get_image_type_mapping(arch, generation)
273-
new_img_alt_type = get_image_type_mapping(arch, f"V{alt_gen}")
274-
275-
# we just want to add SKU whenever it's not set
276-
if vmid.image_type == new_img_type:
277-
sku_mapping.setdefault(new_img_type, plan_name)
278-
elif vmid.image_type == new_img_alt_type:
279-
sku_mapping.setdefault(new_img_alt_type, f"{plan_name}-gen{alt_gen}")
292+
if not old_skus:
293+
alt_gen = "V2" if generation == "V1" else "V1"
294+
return _build_skus(
295+
disk_versions, default_gen=generation, alt_gen=alt_gen, plan_name=plan_name
296+
)
280297

281-
# Return the expected SKUs list
282-
res = [
283-
VMISku.from_json({"image_type": k, "id": v, "security_type": security_type})
284-
for k, v in sku_mapping.items()
285-
]
286-
return sorted(res, key=attrgetter("id"))
298+
# The security type may exist only for Gen2, so it iterates over all gens to find it
299+
security_type = None
300+
# The alternate plan name ends with the suffix "-genX" and we can't change that once
301+
# the offer is live, otherwise it will raise "BadRequest" with the message:
302+
# "The property 'PlanId' is locked by a previous submission".
303+
default_gen = "V2"
304+
alt_gen = "V1"
305+
for osku in old_skus:
306+
if osku.security_type is not None:
307+
security_type = osku.security_type
308+
if osku.id.endswith("-gen2"): # alternate is gen2 hence V1 is the default.
309+
default_gen = "V1"
310+
alt_gen = "V2"
311+
312+
return _build_skus(
313+
disk_versions,
314+
default_gen=default_gen,
315+
alt_gen=alt_gen,
316+
plan_name=plan_name,
317+
security_type=security_type,
318+
)
287319

288320

289321
def create_disk_version_from_scratch(

tests/ms_azure/test_utils.py

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
VMImageDefinition,
1212
VMImageSource,
1313
VMIPlanTechConfig,
14+
VMISku,
1415
)
1516
from cloudpub.ms_azure.utils import (
1617
AzurePublishingMetadata,
@@ -198,18 +199,77 @@ def test_prepare_vm_images_empty(
198199
)
199200
assert expected_err in caplog.text
200201

201-
def test_update_skus(
202+
def test_update_new_skus_gen2_default(
202203
self, technical_config_obj: VMIPlanTechConfig, metadata_azure_obj: AzurePublishingMetadata
203204
) -> None:
204205
"""Test for a "SKU update" from scratch."""
205-
skus = technical_config_obj.skus
206+
expected = technical_config_obj.skus
206207

207208
res = update_skus(
208209
disk_versions=technical_config_obj.disk_versions,
209210
generation=metadata_azure_obj.generation,
210211
plan_name="plan-1",
211212
)
212-
assert res == skus
213+
assert res == expected
214+
215+
def test_update_new_skus_gen1_default(self, technical_config_obj: VMIPlanTechConfig) -> None:
216+
"""Test for a "SKU update" from scratch."""
217+
expected = [
218+
VMISku.from_json(x)
219+
for x in [
220+
{"imageType": "x64Gen1", "skuId": "plan1", "security_type": None},
221+
{"imageType": "x64Gen2", "skuId": "plan1-gen2", "security_type": None},
222+
]
223+
]
224+
res = update_skus(
225+
disk_versions=technical_config_obj.disk_versions,
226+
generation="V1",
227+
plan_name="plan1",
228+
)
229+
assert res == expected
230+
231+
def test_update_existing_skus_gen2_default(
232+
self, technical_config_obj: VMIPlanTechConfig, metadata_azure_obj: AzurePublishingMetadata
233+
) -> None:
234+
"""Test for a "SKU update" from scratch."""
235+
res = update_skus(
236+
disk_versions=technical_config_obj.disk_versions,
237+
generation=metadata_azure_obj.generation,
238+
plan_name="plan-1",
239+
old_skus=technical_config_obj.skus,
240+
)
241+
assert res == [
242+
VMISku.from_json(x)
243+
for x in [
244+
{"imageType": "x64Gen2", "skuId": "plan-1", "securityType": None},
245+
{"imageType": "x64Gen1", "skuId": "plan-1-gen1", "securityType": None},
246+
]
247+
]
248+
249+
def test_update_existing_skus_gen1_default(
250+
self, technical_config_obj: VMIPlanTechConfig
251+
) -> None:
252+
skus = [
253+
VMISku.from_json(x)
254+
for x in [
255+
{"imageType": "x64Gen1", "skuId": "plan1"},
256+
{"imageType": "x64Gen2", "skuId": "plan1-gen2", "securityType": ["trusted"]},
257+
]
258+
]
259+
technical_config_obj.skus = skus
260+
res = update_skus(
261+
disk_versions=technical_config_obj.disk_versions,
262+
generation="V1",
263+
plan_name="plan1",
264+
old_skus=technical_config_obj.skus,
265+
)
266+
assert res == [
267+
VMISku.from_json(x)
268+
for x in [
269+
{"imageType": "x64Gen1", "skuId": "plan1", "securityType": ["trusted"]},
270+
{"imageType": "x64Gen2", "skuId": "plan1-gen2", "securityType": ["trusted"]},
271+
]
272+
]
213273

214274
def test_create_disk_version_from_scratch(
215275
self,

0 commit comments

Comments
 (0)