2424 get_date_str ,
2525 get_datetime_path ,
2626)
27+ from lisa .secret import PATTERN_URL , add_secret
2728
2829from .common import (
2930 AZURE_SHARED_RG_NAME ,
@@ -481,9 +482,21 @@ class SigTransformerSchema(schema.Transformer):
481482 azure_sig_url: shared_gallery
482483 """
483484
484- # raw vhd URL, it can be the blob under the same subscription of SIG
485- # or SASURL
486- vhd : str = field (default = "" , metadata = field_metadata (required = True ))
485+ # Raw VHD URL or VHD schema object. String form keeps backward compatibility:
486+ # vhd: "https://.../os.vhd"
487+ # Object form supports data disk VHDs:
488+ # vhd:
489+ # vhd_path: "https://.../os.vhd"
490+ # data_vhd_paths:
491+ # - data_vhd:
492+ # lun: 0
493+ # url: "https://.../data0.vhd"
494+ # - data_vhd:
495+ # lun: 1
496+ # url: "https://.../data1.vhd"
497+ vhd : Union [str , Dict [Any , Any ]] = field (
498+ default = "" , metadata = field_metadata (required = True )
499+ )
487500 # if not specify gallery_resource_group_name, use shared resource group name
488501 gallery_resource_group_name : str = field (default = AZURE_SHARED_RG_NAME )
489502 # if not specified, will use the first location of gallery image
@@ -610,18 +623,24 @@ def _internal_run(self) -> Dict[str, Any]:
610623 runbook .gallery_resource_group_location = image_location
611624 if not runbook .gallery_location :
612625 runbook .gallery_location = image_location
626+
627+ source_vhd_path , source_data_vhd_paths = self ._resolve_vhd_sources (runbook )
613628 vhd_path = get_deployable_storage_path (
614- platform , runbook .vhd , image_location , self ._log
615- )
616- vhd_details = get_vhd_details (platform , vhd_path )
617- check_blob_exist (
618- platform = platform ,
619- account_name = vhd_details ["account_name" ],
620- container_name = vhd_details ["container_name" ],
621- resource_group_name = vhd_details ["resource_group_name" ],
622- blob_name = vhd_details ["blob_name" ],
623- raise_error = True ,
629+ platform , source_vhd_path , image_location , self ._log
624630 )
631+ vhd_details = self ._check_blob_exists (platform , vhd_path )
632+
633+ data_vhd_paths : List [Dict [str , Any ]] = []
634+ for source_data_vhd in source_data_vhd_paths :
635+ source_data_vhd_path = source_data_vhd ["url" ]
636+ data_vhd_path = get_deployable_storage_path (
637+ platform , source_data_vhd_path , image_location , self ._log
638+ )
639+ self ._check_blob_exists (platform , data_vhd_path )
640+ data_vhd : Dict [str , Any ] = {"url" : data_vhd_path }
641+ if "lun" in source_data_vhd :
642+ data_vhd ["lun" ] = source_data_vhd ["lun" ]
643+ data_vhd_paths .append (data_vhd )
625644
626645 # Get features from marketplace image if specified
627646 features = self ._get_image_features (platform , runbook .marketplace_source )
@@ -696,6 +715,7 @@ def _internal_run(self) -> Dict[str, Any]:
696715 vhd_details ["resource_group_name" ],
697716 vhd_details ["account_name" ],
698717 runbook .gallery_image_location ,
718+ data_vhd_paths = data_vhd_paths ,
699719 )
700720
701721 sig_url = (
@@ -707,6 +727,75 @@ def _internal_run(self) -> Dict[str, Any]:
707727 self ._log .info (f"SIG Url: { sig_url } " )
708728 return {self .__sig_name : sig_url }
709729
730+ def _check_blob_exists (
731+ self , platform : AzurePlatform , vhd_path : str
732+ ) -> Dict [str , str ]:
733+ vhd_details = cast (Dict [str , str ], get_vhd_details (platform , vhd_path ))
734+ check_blob_exist (
735+ platform = platform ,
736+ account_name = vhd_details ["account_name" ],
737+ container_name = vhd_details ["container_name" ],
738+ resource_group_name = vhd_details ["resource_group_name" ],
739+ blob_name = vhd_details ["blob_name" ],
740+ raise_error = True ,
741+ )
742+ return vhd_details
743+
744+ def _resolve_vhd_sources (
745+ self , runbook : SigTransformerSchema
746+ ) -> tuple [str , List [Dict [str , Any ]]]:
747+ data_vhd_paths : List [Dict [str , Any ]] = []
748+
749+ def _add_data_vhd (url : str , lun : Optional [int ] = None ) -> None :
750+ normalized_url = url .strip ()
751+ if not normalized_url :
752+ return
753+ add_secret (normalized_url , PATTERN_URL )
754+ item : Dict [str , Any ] = {"url" : normalized_url }
755+ if lun is not None :
756+ item ["lun" ] = lun
757+ data_vhd_paths .append (item )
758+
759+ def _parse_lun (raw_lun : Any ) -> Optional [int ]:
760+ if isinstance (raw_lun , int ) and raw_lun >= 0 :
761+ return raw_lun
762+ if isinstance (raw_lun , str ):
763+ raw_lun = raw_lun .strip ()
764+ if raw_lun .isdigit ():
765+ return int (raw_lun )
766+ return None
767+
768+ if isinstance (runbook .vhd , str ):
769+ vhd_path = runbook .vhd
770+ elif isinstance (runbook .vhd , dict ):
771+ raw_vhd_path = runbook .vhd .get ("vhd_path" , "" )
772+ vhd_path = raw_vhd_path .strip () if isinstance (raw_vhd_path , str ) else ""
773+
774+ raw_data_vhd_paths = runbook .vhd .get ("data_vhd_paths" )
775+ if isinstance (raw_data_vhd_paths , list ):
776+ for item in raw_data_vhd_paths :
777+ if not isinstance (item , dict ):
778+ continue
779+
780+ # Supported format:
781+ # - data_vhd:
782+ # lun: 0
783+ # url: "https://.../data0.vhd"
784+ raw_data_vhd = item .get ("data_vhd" )
785+ if isinstance (raw_data_vhd , dict ):
786+ url = raw_data_vhd .get ("url" )
787+ if isinstance (url , str ) and url .strip ():
788+ _add_data_vhd (url , _parse_lun (raw_data_vhd .get ("lun" )))
789+ else :
790+ raise LisaException (
791+ f"unsupported type for transformer vhd: { type (runbook .vhd )} "
792+ )
793+
794+ if not vhd_path :
795+ raise LisaException ("vhd or vhd.vhd_path must not be empty." )
796+
797+ return vhd_path , data_vhd_paths
798+
710799 def _get_image_features (
711800 self , platform : AzurePlatform , marketplace : str
712801 ) -> Dict [str , Any ]:
0 commit comments