|
32 | 32 | SecurityProfileType, |
33 | 33 | ) |
34 | 34 | from lisa.node import Node |
35 | | -from lisa.operating_system import BSD, Posix, Windows |
| 35 | +from lisa.operating_system import BSD, AlmaLinux, CBLMariner, Posix, Redhat, Windows |
36 | 36 | from lisa.schema import DiskControllerType, DiskOptionSettings, DiskType |
37 | 37 | from lisa.sut_orchestrator import AZURE, HYPERV |
38 | 38 | from lisa.sut_orchestrator.azure.features import AzureDiskOptionSettings, AzureFileShare |
39 | 39 | from lisa.sut_orchestrator.azure.tools import Waagent |
40 | | -from lisa.tools import Blkid, Cat, Dmesg, Echo, Lsblk, Mount, NFSClient, Swap, Sysctl |
| 40 | +from lisa.tools import ( |
| 41 | + Blkid, |
| 42 | + Cat, |
| 43 | + Dmesg, |
| 44 | + Echo, |
| 45 | + Ls, |
| 46 | + Lsblk, |
| 47 | + Mount, |
| 48 | + NFSClient, |
| 49 | + Rm, |
| 50 | + SmbClient, |
| 51 | + SmbServer, |
| 52 | + Swap, |
| 53 | + Sysctl, |
| 54 | +) |
41 | 55 | from lisa.tools.blkid import PartitionInfo |
42 | 56 | from lisa.tools.journalctl import Journalctl |
43 | 57 | from lisa.tools.kernel_config import KernelConfig |
@@ -590,6 +604,182 @@ def after_case(self, log: Logger, **kwargs: Any) -> None: |
590 | 604 | except Exception: |
591 | 605 | raise BadEnvironmentStateException |
592 | 606 |
|
| 607 | + @TestCaseMetadata( |
| 608 | + description=""" |
| 609 | + A comprehensive test to verify CIFS module and SMB share functionality between |
| 610 | + two Linux VMs. |
| 611 | + This test case will |
| 612 | + 1. Create an 2 VMs in azure |
| 613 | + 2. Check if CONFIG_CIFS is enabled in KCONFIG |
| 614 | + 3. Configure one VM as SMB server and create a share |
| 615 | + 4. Mount the other VM to the SMB share |
| 616 | + 5. Verify mount is successful |
| 617 | + 6. Write a test file to the SMB share and read it back to verify IO |
| 618 | + 7. Clean up the SMB share and unmount |
| 619 | + 8. repeat steps 4-7 for SMB versions ["2.0", "2.1", "3.0", "3.1.1"] |
| 620 | + """, |
| 621 | + timeout=TIME_OUT, |
| 622 | + requirement=simple_requirement( |
| 623 | + min_count=2, |
| 624 | + unsupported_os=[Redhat, CBLMariner, AlmaLinux, BSD, Windows], |
| 625 | + ), |
| 626 | + use_new_environment=True, |
| 627 | + priority=1, |
| 628 | + ) |
| 629 | + def verify_smb_linux( |
| 630 | + self, log: Logger, node: Node, environment: Environment |
| 631 | + ) -> None: |
| 632 | + # Check if CONFIG_CIFS is enabled in KCONFIG |
| 633 | + if not node.tools[KernelConfig].is_enabled("CONFIG_CIFS"): |
| 634 | + raise LisaException("CIFS module must be present for SMB testing") |
| 635 | + |
| 636 | + # Assign server and client roles to the 2 VMs |
| 637 | + server_node = cast(RemoteNode, environment.nodes[0]) |
| 638 | + client_node = cast(RemoteNode, environment.nodes[1]) |
| 639 | + |
| 640 | + # Install and setup SMB tools on both nodes |
| 641 | + smb_server = server_node.tools[SmbServer] |
| 642 | + smb_client = client_node.tools[SmbClient] |
| 643 | + |
| 644 | + # SMB versions to test |
| 645 | + smb_versions = ["3.0", "3.1.1", "2.1", "2.0"] |
| 646 | + |
| 647 | + # Test configuration |
| 648 | + share_name = "testshare" |
| 649 | + share_path = f"/tmp/{share_name}" |
| 650 | + mount_point = f"/mnt/{share_name}" |
| 651 | + |
| 652 | + try: |
| 653 | + # Step 3: Configure SMB server and create a share |
| 654 | + smb_server.create_share(share_name, share_path) |
| 655 | + |
| 656 | + # Step 8: Repeat for different SMB versions |
| 657 | + for smb_version in smb_versions: |
| 658 | + log.info(f"Testing SMB version {smb_version}") |
| 659 | + |
| 660 | + # Step 4: Mount the SMB share on client |
| 661 | + smb_client.mount_share( |
| 662 | + server_node.internal_address, share_name, mount_point, smb_version |
| 663 | + ) |
| 664 | + |
| 665 | + # Step 5& 6: Verify mount is successful |
| 666 | + self._verify_smb_mount( |
| 667 | + client_node, |
| 668 | + mount_point, |
| 669 | + server_node, |
| 670 | + share_path, |
| 671 | + log, |
| 672 | + ) |
| 673 | + |
| 674 | + # Step 7: Cleanup between version tests |
| 675 | + smb_client.unmount_share(mount_point) |
| 676 | + finally: |
| 677 | + # Cleanup |
| 678 | + self._cleanup_smb_test( |
| 679 | + server_node, client_node, share_path, mount_point, log |
| 680 | + ) |
| 681 | + |
| 682 | + def _verify_smb_mount( |
| 683 | + self, |
| 684 | + client_node: RemoteNode, |
| 685 | + mount_point: str, |
| 686 | + server_node: RemoteNode, |
| 687 | + share_path: str, |
| 688 | + log: Logger, |
| 689 | + ) -> None: |
| 690 | + """ |
| 691 | + Verify SMB mount is working by creating and reading a file from |
| 692 | + both client and server. |
| 693 | + """ |
| 694 | + test_file = "smb_test.txt" |
| 695 | + test_content = "SMB test content" |
| 696 | + mount = client_node.tools[Mount] |
| 697 | + |
| 698 | + # Verify mount point exists and is mounted |
| 699 | + mount_point_exists = mount.check_mount_point_exist(mount_point) |
| 700 | + if not mount_point_exists: |
| 701 | + raise LisaException( |
| 702 | + f"Mount point {mount_point} does not exist or is not mounted" |
| 703 | + ) |
| 704 | + |
| 705 | + # Create test file on mounted share from client |
| 706 | + test_file_path = f"{mount_point}/{test_file}" |
| 707 | + echo = client_node.tools[Echo] |
| 708 | + echo.write_to_file( |
| 709 | + test_content, |
| 710 | + client_node.get_pure_path(test_file_path), |
| 711 | + sudo=True, |
| 712 | + ignore_error=False, |
| 713 | + ) |
| 714 | + |
| 715 | + # Read and verify file content from client side |
| 716 | + file_content_client = client_node.tools[Cat].read( |
| 717 | + test_file_path, sudo=True, force_run=True |
| 718 | + ) |
| 719 | + |
| 720 | + assert_that(file_content_client).described_as( |
| 721 | + "SMB file content should match written content on client" |
| 722 | + ).is_equal_to(test_content) |
| 723 | + |
| 724 | + # Verify content from server VM if server_node and share_path are provided |
| 725 | + if server_node and share_path: |
| 726 | + server_file_path = f"{share_path}/{test_file}" |
| 727 | + |
| 728 | + # Check if file exists on server |
| 729 | + if not server_node.tools[Ls].path_exists(server_file_path, sudo=True): |
| 730 | + raise LisaException( |
| 731 | + f"Test file {server_file_path} not found on server VM" |
| 732 | + ) |
| 733 | + |
| 734 | + # Read file content directly from server VM |
| 735 | + file_content_server = server_node.tools[Cat].read( |
| 736 | + server_file_path, sudo=True, force_run=True |
| 737 | + ) |
| 738 | + |
| 739 | + assert_that(file_content_server).described_as( |
| 740 | + "SMB file content should match on server VM" |
| 741 | + ).is_equal_to(test_content) |
| 742 | + |
| 743 | + log.info( |
| 744 | + f"Successfully verified file content on both client and server: " |
| 745 | + f"'{test_content}'" |
| 746 | + ) |
| 747 | + |
| 748 | + # Clean up test file from client (will also remove from server via SMB) |
| 749 | + client_node.tools[Rm].remove_file(test_file_path, sudo=True) |
| 750 | + |
| 751 | + def _cleanup_smb_test( |
| 752 | + self, |
| 753 | + server_node: RemoteNode, |
| 754 | + client_node: RemoteNode, |
| 755 | + share_path: str, |
| 756 | + mount_point: str, |
| 757 | + log: Logger, |
| 758 | + ) -> None: |
| 759 | + """Clean up SMB test resources.""" |
| 760 | + # Cleanup on client |
| 761 | + try: |
| 762 | + smb_client = client_node.tools[SmbClient] |
| 763 | + if smb_client.is_mounted(mount_point): |
| 764 | + smb_client.unmount_share(mount_point) |
| 765 | + smb_client.cleanup_mount_point(mount_point) |
| 766 | + except Exception as e: |
| 767 | + raise LisaException( |
| 768 | + f"fail to cleanup SMB client mount point {mount_point}: " |
| 769 | + f"{e.__class__.__name__}: {e}." |
| 770 | + ) |
| 771 | + |
| 772 | + # Cleanup on server |
| 773 | + try: |
| 774 | + smb_server = server_node.tools[SmbServer] |
| 775 | + smb_server.stop() |
| 776 | + smb_server.remove_share(share_path) |
| 777 | + except Exception as e: |
| 778 | + raise LisaException( |
| 779 | + f"fail to remove share {share_path} from SMB server: " |
| 780 | + f"{e.__class__.__name__}: {e}." |
| 781 | + ) |
| 782 | + |
593 | 783 | @TestCaseMetadata( |
594 | 784 | description=""" |
595 | 785 | This test case will |
|
0 commit comments