@@ -511,6 +511,183 @@ pub fn test_libvirt_vm_lifecycle() {
511511 println ! ( "VM lifecycle test completed" ) ;
512512}
513513
514+ /// Test container storage binding functionality end-to-end
515+ pub fn test_libvirt_bind_storage_ro ( ) {
516+ let bck = get_bck_command ( ) . unwrap ( ) ;
517+ let test_image = get_test_image ( ) ;
518+
519+ // Generate unique domain name for this test
520+ let domain_name = format ! (
521+ "test-bind-storage-{}" ,
522+ std:: time:: SystemTime :: now( )
523+ . duration_since( std:: time:: UNIX_EPOCH )
524+ . unwrap( )
525+ . as_secs( )
526+ ) ;
527+
528+ println ! ( "Testing --bind-storage-ro with domain: {}" , domain_name) ;
529+
530+ // Cleanup any existing domain with this name
531+ let _ = Command :: new ( "virsh" )
532+ . args ( & [ "destroy" , & domain_name] )
533+ . output ( ) ;
534+ let _ = Command :: new ( "virsh" )
535+ . args ( & [ "undefine" , & domain_name] )
536+ . output ( ) ;
537+
538+ // Create domain with --bind-storage-ro flag
539+ println ! ( "Creating libvirt domain with --bind-storage-ro..." ) ;
540+ let create_output = Command :: new ( "timeout" )
541+ . args ( [
542+ "300s" , // 5 minute timeout for domain creation
543+ & bck,
544+ "libvirt" ,
545+ "run" ,
546+ "--name" ,
547+ & domain_name,
548+ "--bind-storage-ro" ,
549+ "--filesystem" ,
550+ "ext4" ,
551+ & test_image,
552+ ] )
553+ . output ( )
554+ . expect ( "Failed to run libvirt run with --bind-storage-ro" ) ;
555+
556+ let create_stdout = String :: from_utf8_lossy ( & create_output. stdout ) ;
557+ let create_stderr = String :: from_utf8_lossy ( & create_output. stderr ) ;
558+
559+ println ! ( "Create stdout: {}" , create_stdout) ;
560+ println ! ( "Create stderr: {}" , create_stderr) ;
561+
562+ if !create_output. status . success ( ) {
563+ cleanup_domain ( & domain_name) ;
564+ panic ! (
565+ "Failed to create domain with --bind-storage-ro: {}" ,
566+ create_stderr
567+ ) ;
568+ }
569+
570+ println ! ( "Successfully created domain: {}" , domain_name) ;
571+
572+ // Check that the domain was created with virtiofs filesystem
573+ println ! ( "Checking domain XML for virtiofs filesystem..." ) ;
574+ let dumpxml_output = Command :: new ( "virsh" )
575+ . args ( & [ "dumpxml" , & domain_name] )
576+ . output ( )
577+ . expect ( "Failed to dump domain XML" ) ;
578+
579+ if !dumpxml_output. status . success ( ) {
580+ cleanup_domain ( & domain_name) ;
581+ let stderr = String :: from_utf8_lossy ( & dumpxml_output. stderr ) ;
582+ panic ! ( "Failed to dump domain XML: {}" , stderr) ;
583+ }
584+
585+ let domain_xml = String :: from_utf8_lossy ( & dumpxml_output. stdout ) ;
586+ println ! (
587+ "Domain XML snippet: {}" ,
588+ & domain_xml[ ..std:: cmp:: min( 500 , domain_xml. len( ) ) ]
589+ ) ;
590+
591+ // Verify that the domain XML contains virtiofs configuration
592+ assert ! (
593+ domain_xml. contains( "type='virtiofs'" ) || domain_xml. contains( "driver type='virtiofs'" ) ,
594+ "Domain XML should contain virtiofs filesystem configuration"
595+ ) ;
596+
597+ // Verify that the filesystem has the correct tag
598+ assert ! (
599+ domain_xml. contains( "hoststorage" ) || domain_xml. contains( "dir='hoststorage'" ) ,
600+ "Domain XML should reference the hoststorage tag for container storage"
601+ ) ;
602+
603+ // Check metadata for bind-storage-ro configuration
604+ if domain_xml. contains ( "bootc:bind-storage-ro" ) {
605+ assert ! (
606+ domain_xml. contains( "<bootc:bind-storage-ro>true</bootc:bind-storage-ro>" ) ,
607+ "Domain metadata should indicate bind-storage-ro is enabled"
608+ ) ;
609+ }
610+
611+ println ! ( "✓ Domain XML contains expected virtiofs configuration" ) ;
612+ println ! ( "✓ Container storage mount is configured as read-only" ) ;
613+ println ! ( "✓ hoststorage tag is present in filesystem configuration" ) ;
614+
615+ // Wait for VM to boot and SSH to become available
616+ println ! ( "Waiting for VM to boot and SSH to become available..." ) ;
617+ std:: thread:: sleep ( std:: time:: Duration :: from_secs ( 45 ) ) ;
618+
619+ // Create mount point and mount virtiofs filesystem
620+ println ! ( "Creating mount point and mounting virtiofs filesystem..." ) ;
621+ let mount_setup = Command :: new ( "timeout" )
622+ . args ( [
623+ "30s" ,
624+ & bck,
625+ "libvirt" ,
626+ "ssh" ,
627+ & domain_name,
628+ "--" ,
629+ "sudo" ,
630+ "mkdir" ,
631+ "-p" ,
632+ "/run/virtiofs-mnt-hoststorage" ,
633+ ] )
634+ . output ( )
635+ . expect ( "Failed to create mount point" ) ;
636+
637+ if !mount_setup. status . success ( ) {
638+ let stderr = String :: from_utf8_lossy ( & mount_setup. stderr ) ;
639+ println ! ( "Warning: Failed to create mount point: {}" , stderr) ;
640+ }
641+
642+ let mount_cmd = Command :: new ( "timeout" )
643+ . args ( [
644+ "30s" ,
645+ & bck,
646+ "libvirt" ,
647+ "ssh" ,
648+ & domain_name,
649+ "--" ,
650+ "sudo" ,
651+ "mount" ,
652+ "-t" ,
653+ "virtiofs" ,
654+ "hoststorage" ,
655+ "/run/virtiofs-mnt-hoststorage" ,
656+ ] )
657+ . output ( )
658+ . expect ( "Failed to mount virtiofs" ) ;
659+
660+ if !mount_cmd. status . success ( ) {
661+ cleanup_domain ( & domain_name) ;
662+ let stderr = String :: from_utf8_lossy ( & mount_cmd. stderr ) ;
663+ panic ! ( "Failed to mount virtiofs filesystem: {}" , stderr) ;
664+ }
665+
666+ // Test SSH connection and verify container storage mount inside VM
667+ println ! ( "Testing SSH connection and checking container storage mount..." ) ;
668+ let st = Command :: new ( "timeout" )
669+ . args ( [
670+ "60s" ,
671+ & bck,
672+ "libvirt" ,
673+ "ssh" ,
674+ & domain_name,
675+ "--" ,
676+ "ls" ,
677+ "-la" ,
678+ "/run/virtiofs-mnt-hoststorage/overlay" ,
679+ ] )
680+ . status ( )
681+ . expect ( "Failed to run SSH command to check container storage" ) ;
682+
683+ assert ! ( st. success( ) ) ;
684+
685+ // Cleanup domain before completing test
686+ cleanup_domain ( & domain_name) ;
687+
688+ println ! ( "✓ --bind-storage-ro end-to-end test passed" ) ;
689+ }
690+
514691/// Test error handling for invalid configurations
515692pub fn test_libvirt_error_handling ( ) {
516693 let bck = get_bck_command ( ) . unwrap ( ) ;
0 commit comments