@@ -13,15 +13,14 @@ use crate::IsolationType;
13
13
use crate :: NoPetriVmInspector ;
14
14
use crate :: OpenHclConfig ;
15
15
use crate :: OpenHclServicingFlags ;
16
+ use crate :: PetriHaltReason ;
16
17
use crate :: PetriVmConfig ;
17
- use crate :: PetriVmFramebufferAccess ;
18
18
use crate :: PetriVmResources ;
19
19
use crate :: PetriVmRuntime ;
20
20
use crate :: PetriVmmBackend ;
21
21
use crate :: SecureBootTemplate ;
22
22
use crate :: ShutdownKind ;
23
23
use crate :: UefiConfig ;
24
- use crate :: VmScreenshotMeta ;
25
24
use crate :: disk_image:: AgentImage ;
26
25
use crate :: hyperv:: powershell:: HyperVSecureBootTemplate ;
27
26
use crate :: kmsg_log_task;
@@ -43,22 +42,18 @@ use petri_artifacts_common::tags::OsFlavor;
43
42
use petri_artifacts_core:: ArtifactResolver ;
44
43
use petri_artifacts_core:: ResolvedArtifact ;
45
44
use pipette_client:: PipetteClient ;
46
- use std:: fs;
47
45
use std:: io:: ErrorKind ;
48
46
use std:: io:: Write ;
49
47
use std:: path:: Path ;
50
- use std:: sync:: Arc ;
51
- use std:: sync:: Weak ;
52
48
use std:: time:: Duration ;
53
49
use vm:: HyperVVM ;
54
- use vmm_core_defs:: HaltReason ;
55
50
56
51
/// The Hyper-V Petri backend
57
52
pub struct HyperVPetriBackend { }
58
53
59
54
/// Resources needed at runtime for a Hyper-V Petri VM
60
55
pub struct HyperVPetriRuntime {
61
- vm : Arc < HyperVVM > ,
56
+ vm : HyperVVM ,
62
57
log_tasks : Vec < Task < anyhow:: Result < ( ) > > > ,
63
58
temp_dir : tempfile:: TempDir ,
64
59
is_openhcl : bool ,
@@ -71,7 +66,14 @@ impl PetriVmmBackend for HyperVPetriBackend {
71
66
type VmmConfig = ( ) ;
72
67
type VmRuntime = HyperVPetriRuntime ;
73
68
74
- fn check_compat ( firmware : & Firmware , arch : MachineArch ) -> bool {
69
+ fn check_compat ( firmware : & mut Firmware , arch : MachineArch ) -> bool {
70
+ // Workaround for Ubuntu OpenHCL Hyper-V VMs automatically resetting
71
+ if matches ! ( firmware. os_flavor( ) , OsFlavor :: Linux ) && firmware. is_openhcl ( ) {
72
+ if let Some ( quirks) = firmware. quirks_mut ( ) {
73
+ quirks. initial_reboot_required = true ;
74
+ }
75
+ }
76
+
75
77
arch == MachineArch :: host ( )
76
78
&& !firmware. is_linux_direct ( )
77
79
&& !( firmware. is_pcat ( ) && arch == MachineArch :: Aarch64 )
@@ -292,7 +294,7 @@ impl PetriVmmBackend for HyperVPetriBackend {
292
294
// location at runtime.
293
295
let imc_hive = temp_dir. path ( ) . join ( "imc.hiv" ) ;
294
296
{
295
- let mut imc_hive_file = fs :: File :: create_new ( & imc_hive) ?;
297
+ let mut imc_hive_file = fs_err :: File :: create_new ( & imc_hive) ?;
296
298
imc_hive_file
297
299
. write_all ( include_bytes ! ( "../../../guest-bootstrap/imc.hiv" ) )
298
300
. context ( "failed to write imc hive" ) ?;
@@ -427,7 +429,7 @@ impl PetriVmmBackend for HyperVPetriBackend {
427
429
vm. start ( ) . await ?;
428
430
429
431
Ok ( HyperVPetriRuntime {
430
- vm : Arc :: new ( vm ) ,
432
+ vm,
431
433
log_tasks,
432
434
temp_dir,
433
435
is_openhcl : openhcl_config. is_some ( ) ,
@@ -440,19 +442,15 @@ impl PetriVmmBackend for HyperVPetriBackend {
440
442
#[ async_trait]
441
443
impl PetriVmRuntime for HyperVPetriRuntime {
442
444
type VmInspector = NoPetriVmInspector ;
443
- type VmFramebufferAccess = HyperVFramebufferAccess ;
445
+ type VmFramebufferAccess = vm :: HyperVFramebufferAccess ;
444
446
445
447
async fn teardown ( mut self ) -> anyhow:: Result < ( ) > {
446
448
futures:: future:: join_all ( self . log_tasks . into_iter ( ) . map ( |t| t. cancel ( ) ) ) . await ;
447
- Arc :: into_inner ( self . vm )
448
- . context ( "all references to the Hyper-V VM object have not been closed" ) ?
449
- . remove ( )
450
- . await
449
+ self . vm . remove ( ) . await
451
450
}
452
451
453
- async fn wait_for_halt ( & mut self ) -> anyhow:: Result < HaltReason > {
454
- self . vm . wait_for_halt ( ) . await ?;
455
- Ok ( HaltReason :: PowerOff ) // TODO: Get actual halt reason
452
+ async fn wait_for_halt ( & mut self , allow_reset : bool ) -> anyhow:: Result < PetriHaltReason > {
453
+ self . vm . wait_for_halt ( allow_reset) . await
456
454
}
457
455
458
456
async fn wait_for_agent ( & mut self , set_high_vtl : bool ) -> anyhow:: Result < PipetteClient > {
@@ -531,26 +529,8 @@ impl PetriVmRuntime for HyperVPetriRuntime {
531
529
self . vm . restart_openhcl ( flags) . await
532
530
}
533
531
534
- fn take_framebuffer_access ( & mut self ) -> Option < HyperVFramebufferAccess > {
535
- ( !self . is_isolated ) . then ( || HyperVFramebufferAccess {
536
- vm : Arc :: downgrade ( & self . vm ) ,
537
- } )
538
- }
539
- }
540
-
541
- /// Interface to the Hyper-V framebuffer
542
- pub struct HyperVFramebufferAccess {
543
- vm : Weak < HyperVVM > ,
544
- }
545
-
546
- #[ async_trait]
547
- impl PetriVmFramebufferAccess for HyperVFramebufferAccess {
548
- async fn screenshot ( & mut self , image : & mut Vec < u8 > ) -> anyhow:: Result < VmScreenshotMeta > {
549
- self . vm
550
- . upgrade ( )
551
- . context ( "VM no longer exists" ) ?
552
- . screenshot ( image)
553
- . await
532
+ fn take_framebuffer_access ( & mut self ) -> Option < vm:: HyperVFramebufferAccess > {
533
+ ( !self . is_isolated ) . then ( || self . vm . get_framebuffer_access ( ) )
554
534
}
555
535
}
556
536
@@ -644,13 +624,13 @@ async fn hyperv_serial_log_task(
644
624
) -> anyhow:: Result < ( ) > {
645
625
let mut timer = None ;
646
626
loop {
647
- match fs_err :: OpenOptions :: new ( )
627
+ match std :: fs :: OpenOptions :: new ( )
648
628
. read ( true )
649
629
. write ( true )
650
630
. open ( & serial_pipe_path)
651
631
{
652
632
Ok ( file) => {
653
- let pipe = PolledPipe :: new ( & driver, file. into ( ) ) . expect ( "failed to create pipe" ) ;
633
+ let pipe = PolledPipe :: new ( & driver, file) . expect ( "failed to create pipe" ) ;
654
634
// connect/disconnect messages logged internally
655
635
_ = crate :: log_task ( log_file. clone ( ) , pipe, & serial_pipe_path) . await ;
656
636
}
@@ -661,7 +641,7 @@ async fn hyperv_serial_log_task(
661
641
if !( err. kind ( ) == ErrorKind :: NotFound
662
642
|| matches ! ( err. raw_os_error( ) , Some ( ERROR_PIPE_BUSY ) ) )
663
643
{
664
- tracing:: warn!( "{ err:#}" )
644
+ tracing:: warn!( "failed to open {serial_pipe_path}: { err:#}" , )
665
645
}
666
646
// Wait a bit and try again.
667
647
timer
0 commit comments