@@ -6,6 +6,8 @@ pub mod powershell;
6
6
pub mod vm;
7
7
use vmsocket:: VmAddress ;
8
8
use vmsocket:: VmSocket ;
9
+ use std:: collections:: hash_map:: DefaultHasher ;
10
+ use std:: hash:: { Hash , Hasher } ;
9
11
10
12
use super :: ProcessorTopology ;
11
13
use crate :: Firmware ;
@@ -231,6 +233,33 @@ impl PetriVmArtifactsHyperV {
231
233
}
232
234
233
235
impl PetriVmConfigHyperV {
236
+ /// Creates a valid Hyper-V VM name from a test name.
237
+ ///
238
+ /// Hyper-V limits VM names to 100 characters. If the test name exceeds this limit,
239
+ /// we truncate it and append a hash to maintain uniqueness.
240
+ fn create_vm_name ( test_name : & str ) -> String {
241
+ const MAX_VM_NAME_LENGTH : usize = 100 ;
242
+
243
+ if test_name. len ( ) <= MAX_VM_NAME_LENGTH {
244
+ return test_name. to_owned ( ) ;
245
+ }
246
+
247
+ // Create a hash of the full name for uniqueness
248
+ let mut hasher = DefaultHasher :: new ( ) ;
249
+ test_name. hash ( & mut hasher) ;
250
+ let hash = hasher. finish ( ) ;
251
+ let hash_suffix = format ! ( "-{:x}" , hash) ;
252
+
253
+ // Reserve space for the hash suffix
254
+ let max_prefix_length = MAX_VM_NAME_LENGTH - hash_suffix. len ( ) ;
255
+
256
+ // Take the end of the test name to preserve the most specific part
257
+ let start_pos = test_name. len ( ) . saturating_sub ( max_prefix_length) ;
258
+ let truncated = & test_name[ start_pos..] ;
259
+
260
+ format ! ( "{}{}" , truncated, hash_suffix)
261
+ }
262
+
234
263
/// Create a new Hyper-V petri VM config
235
264
pub fn new (
236
265
params : & PetriTestParams < ' _ > ,
@@ -287,7 +316,7 @@ impl PetriVmConfigHyperV {
287
316
let openhcl_igvm = igvm_artifact. cloned ( ) ;
288
317
289
318
Ok ( PetriVmConfigHyperV {
290
- name : params. test_name . to_owned ( ) ,
319
+ name : Self :: create_vm_name ( params. test_name ) ,
291
320
arch,
292
321
generation,
293
322
guest_state_isolation_type,
@@ -778,3 +807,51 @@ fn acl_read_for_vm(path: &Path, id: Option<guid::Guid>) -> anyhow::Result<()> {
778
807
}
779
808
Ok ( ( ) )
780
809
}
810
+
811
+ #[ cfg( test) ]
812
+ mod tests {
813
+ use super :: * ;
814
+
815
+ #[ test]
816
+ fn test_create_vm_name ( ) {
817
+ // Test short names remain unchanged
818
+ let short_name = "test::short_name" ;
819
+ assert_eq ! ( PetriVmConfigHyperV :: create_vm_name( short_name) , short_name) ;
820
+
821
+ // Test long names are truncated to 100 characters
822
+ let long_name = "multiarch::openhcl_servicing::hyperv_openhcl_uefi_aarch64_ubuntu_2404_server_aarch64_openhcl_servicing" ;
823
+ let vm_name = PetriVmConfigHyperV :: create_vm_name ( long_name) ;
824
+ assert ! ( vm_name. len( ) <= 100 ) ;
825
+ assert ! ( vm_name. len( ) == 100 ) ; // Should be exactly 100 for this case
826
+
827
+ // Test different long names get different hashes
828
+ let long_name2 = "multiarch::openhcl_servicing::hyperv_openhcl_uefi_aarch64_ubuntu_2404_server_aarch64_openhcl_different" ;
829
+ let vm_name2 = PetriVmConfigHyperV :: create_vm_name ( long_name2) ;
830
+ assert ! ( vm_name2. len( ) <= 100 ) ;
831
+ assert_ne ! ( vm_name, vm_name2) ;
832
+
833
+ // Test the most specific part is preserved
834
+ assert ! ( vm_name. contains( "openhcl_servicing" ) ) ;
835
+ assert ! ( vm_name2. contains( "openhcl_different" ) ) ;
836
+ }
837
+
838
+ #[ test]
839
+ fn test_vm_name_exactly_100_chars ( ) {
840
+ let exactly_100 = "a" . repeat ( 100 ) ;
841
+ let result = PetriVmConfigHyperV :: create_vm_name ( & exactly_100) ;
842
+ assert_eq ! ( result, exactly_100) ;
843
+ assert_eq ! ( result. len( ) , 100 ) ;
844
+ }
845
+
846
+ #[ test]
847
+ fn test_vm_name_101_chars ( ) {
848
+ let exactly_101 = "a" . repeat ( 101 ) ;
849
+ let result = PetriVmConfigHyperV :: create_vm_name ( & exactly_101) ;
850
+ assert_eq ! ( result. len( ) , 100 ) ;
851
+ assert ! ( result. ends_with( & format!( "-{:x}" , {
852
+ let mut hasher = DefaultHasher :: new( ) ;
853
+ exactly_101. hash( & mut hasher) ;
854
+ hasher. finish( )
855
+ } ) ) ) ;
856
+ }
857
+ }
0 commit comments