@@ -585,3 +585,187 @@ impl<'a> Persist<'a> for PciDevices {
585585 Ok ( pci_devices)
586586 }
587587}
588+
589+ #[ cfg( test) ]
590+ mod tests {
591+ use vmm_sys_util:: tempfile:: TempFile ;
592+
593+ use super :: * ;
594+ use crate :: builder:: tests:: * ;
595+ use crate :: device_manager;
596+ use crate :: devices:: virtio:: block:: CacheType ;
597+ use crate :: mmds:: data_store:: MmdsVersion ;
598+ use crate :: resources:: VmmConfig ;
599+ use crate :: snapshot:: Snapshot ;
600+ use crate :: vmm_config:: balloon:: BalloonDeviceConfig ;
601+ use crate :: vmm_config:: entropy:: EntropyDeviceConfig ;
602+ use crate :: vmm_config:: net:: NetworkInterfaceConfig ;
603+ use crate :: vmm_config:: vsock:: VsockDeviceConfig ;
604+
605+ #[ test]
606+ fn test_device_manager_persistence ( ) {
607+ let mut buf = vec ! [ 0 ; 65536 ] ;
608+ // These need to survive so the restored blocks find them.
609+ let _block_files;
610+ let mut tmp_sock_file = TempFile :: new ( ) . unwrap ( ) ;
611+ tmp_sock_file. remove ( ) . unwrap ( ) ;
612+ // Set up a vmm with one of each device, and get the serialized DeviceStates.
613+ {
614+ let mut event_manager = EventManager :: new ( ) . expect ( "Unable to create EventManager" ) ;
615+ let mut vmm = default_vmm ( ) ;
616+ vmm. device_manager . enable_pci ( & vmm. vm ) . unwrap ( ) ;
617+ let mut cmdline = default_kernel_cmdline ( ) ;
618+
619+ // Add a balloon device.
620+ let balloon_cfg = BalloonDeviceConfig {
621+ amount_mib : 123 ,
622+ deflate_on_oom : false ,
623+ stats_polling_interval_s : 1 ,
624+ } ;
625+ insert_balloon_device ( & mut vmm, & mut cmdline, & mut event_manager, balloon_cfg) ;
626+ // Add a block device.
627+ let drive_id = String :: from ( "root" ) ;
628+ let block_configs = vec ! [ CustomBlockConfig :: new(
629+ drive_id,
630+ true ,
631+ None ,
632+ true ,
633+ CacheType :: Unsafe ,
634+ ) ] ;
635+ _block_files =
636+ insert_block_devices ( & mut vmm, & mut cmdline, & mut event_manager, block_configs) ;
637+ // Add a net device.
638+ let network_interface = NetworkInterfaceConfig {
639+ iface_id : String :: from ( "netif" ) ,
640+ host_dev_name : String :: from ( "hostname" ) ,
641+ guest_mac : None ,
642+ rx_rate_limiter : None ,
643+ tx_rate_limiter : None ,
644+ } ;
645+ insert_net_device_with_mmds (
646+ & mut vmm,
647+ & mut cmdline,
648+ & mut event_manager,
649+ network_interface,
650+ MmdsVersion :: V2 ,
651+ ) ;
652+ // Add a vsock device.
653+ let vsock_dev_id = "vsock" ;
654+ let vsock_config = VsockDeviceConfig {
655+ vsock_id : Some ( vsock_dev_id. to_string ( ) ) ,
656+ guest_cid : 3 ,
657+ uds_path : tmp_sock_file. as_path ( ) . to_str ( ) . unwrap ( ) . to_string ( ) ,
658+ } ;
659+ insert_vsock_device ( & mut vmm, & mut cmdline, & mut event_manager, vsock_config) ;
660+ // Add an entropy device.
661+ let entropy_config = EntropyDeviceConfig :: default ( ) ;
662+ insert_entropy_device ( & mut vmm, & mut cmdline, & mut event_manager, entropy_config) ;
663+
664+ Snapshot :: serialize ( & mut buf. as_mut_slice ( ) , & vmm. device_manager . save ( ) ) . unwrap ( ) ;
665+ }
666+
667+ tmp_sock_file. remove ( ) . unwrap ( ) ;
668+
669+ let mut event_manager = EventManager :: new ( ) . expect ( "Unable to create EventManager" ) ;
670+ // Keep in mind we are re-creating here an empty DeviceManager. Restoring later on
671+ // will create a new PciDevices manager different than vmm.pci_devices. We're doing
672+ // this to avoid restoring the whole Vmm, since what we really need from Vmm is the Vm
673+ // object and calling default_vmm() is the easiest way to create one.
674+ let vmm = default_vmm ( ) ;
675+ let device_manager_state: device_manager:: DevicesState =
676+ Snapshot :: deserialize ( & mut buf. as_slice ( ) ) . unwrap ( ) ;
677+ let vm_resources = & mut VmResources :: default ( ) ;
678+ let restore_args = PciDevicesConstructorArgs {
679+ vm : vmm. vm . clone ( ) ,
680+ mem : vmm. vm . guest_memory ( ) ,
681+ vm_resources,
682+ instance_id : "microvm-id" ,
683+ restored_from_file : true ,
684+ event_manager : & mut event_manager,
685+ } ;
686+ let _restored_dev_manager =
687+ PciDevices :: restore ( restore_args, & device_manager_state. pci_state ) . unwrap ( ) ;
688+
689+ let expected_vm_resources = format ! (
690+ r#"{{
691+ "balloon": {{
692+ "amount_mib": 123,
693+ "deflate_on_oom": false,
694+ "stats_polling_interval_s": 1
695+ }},
696+ "drives": [
697+ {{
698+ "drive_id": "root",
699+ "partuuid": null,
700+ "is_root_device": true,
701+ "cache_type": "Unsafe",
702+ "is_read_only": true,
703+ "path_on_host": "{}",
704+ "rate_limiter": null,
705+ "io_engine": "Sync",
706+ "socket": null
707+ }}
708+ ],
709+ "boot-source": {{
710+ "kernel_image_path": "",
711+ "initrd_path": null,
712+ "boot_args": null
713+ }},
714+ "cpu-config": null,
715+ "logger": null,
716+ "machine-config": {{
717+ "vcpu_count": 1,
718+ "mem_size_mib": 128,
719+ "smt": false,
720+ "track_dirty_pages": false,
721+ "huge_pages": "None"
722+ }},
723+ "metrics": null,
724+ "mmds-config": {{
725+ "version": "V2",
726+ "network_interfaces": [
727+ "netif"
728+ ],
729+ "ipv4_address": "169.254.169.254"
730+ }},
731+ "network-interfaces": [
732+ {{
733+ "iface_id": "netif",
734+ "host_dev_name": "hostname",
735+ "guest_mac": null,
736+ "rx_rate_limiter": null,
737+ "tx_rate_limiter": null
738+ }}
739+ ],
740+ "vsock": {{
741+ "guest_cid": 3,
742+ "uds_path": "{}"
743+ }},
744+ "entropy": {{
745+ "rate_limiter": null
746+ }}
747+ }}"# ,
748+ _block_files. last( ) . unwrap( ) . as_path( ) . to_str( ) . unwrap( ) ,
749+ tmp_sock_file. as_path( ) . to_str( ) . unwrap( )
750+ ) ;
751+
752+ assert_eq ! (
753+ vm_resources
754+ . mmds
755+ . as_ref( )
756+ . unwrap( )
757+ . lock( )
758+ . unwrap( )
759+ . version( ) ,
760+ MmdsVersion :: V2
761+ ) ;
762+ assert_eq ! (
763+ device_manager_state. pci_state. mmds_version. unwrap( ) ,
764+ MmdsVersion :: V2 . into( )
765+ ) ;
766+ assert_eq ! (
767+ expected_vm_resources,
768+ serde_json:: to_string_pretty( & VmmConfig :: from( & * vm_resources) ) . unwrap( )
769+ ) ;
770+ }
771+ }
0 commit comments