@@ -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+
238270def 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
289321def create_disk_version_from_scratch (
0 commit comments