[gparted] Create loop devices for LVM2 PV file system interface tests (!49)



commit 268c34e398d8f4e7e6f65513f8e7cc9d6b551e85
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date:   Fri Aug 30 17:25:40 2019 +0100

    Create loop devices for LVM2 PV file system interface tests (!49)
    
    Creating an LVM2 PV as a non-root user on an image file fails like this:
        $ truncate -s 256M test.img
        $ lvm pvcreate `pwd`/test.img
          WARNING: Running as a non-root user. Functionality may be unavailable.
          /run/lvm/lvmetad.socket: access failed: Permission denied
          WARNING: Failed to connect to lvmetad. Falling back to device scanning.
          /run/lock/lvm/P_orphans:aux: open failed: Permission denied
          Can't get lock for orphan PVs.
        $ echo $?
        5
    
    Trying the same as root also fails:
        # truncate -s 256M test.img
        # lvm pvcreate `pwd`/test.img
          Device /root/test.img not found.
        # echo $?
        5
    
    LVM seems strongly predicated on only using block devices [1].  LVM can
    use loop devices though, but loop devices can only be created by root.
        # truncate -s 256M test.img
        # losetup -f --show `pwd`/test.img
        /dev/loop0
        # lvm pvcreate /dev/loop0
          Physical volume "/dev/loop0" successfully created.
        # echo $?
        0
    
    Make the LVM2 PV tests require user root and use loop device over the
    test image.  Tests for the other file system types still directly uses
    the image file.  This makes the LVM2 PV tests pass when run as root, or
    successfully skipped when run as non-root.
    
    [1] lvmconfig --typeconfig default --withcomments --withspace | less
        From the "devices" section of the commented default configuration,
        LVM uses block devices found below /dev, devices provided by udev
        and/or found in sysfs.
    
    Closes !49 - Add file system interface tests

 tests/test_SupportedFileSystems.cc | 109 +++++++++++++++++++++++++++++++++++--
 1 file changed, 105 insertions(+), 4 deletions(-)
---
diff --git a/tests/test_SupportedFileSystems.cc b/tests/test_SupportedFileSystems.cc
index c7a61e8e..57ef1c54 100644
--- a/tests/test_SupportedFileSystems.cc
+++ b/tests/test_SupportedFileSystems.cc
@@ -206,6 +206,19 @@ const std::string param_fsname(const ::testing::TestParamInfo<FSType>& info)
        }
 
 
+#define SKIP_IF_NOT_ROOT_FOR_REQUIRED_LOOPDEV_FOR_FS(fstype)                                    \
+       if (m_fstype == fstype)                                                                 \
+       {                                                                                       \
+               if (getuid() != 0)                                                              \
+               {                                                                               \
+                       std::cout << __FILE__ << ":" << __LINE__ << ": Skip test.  Not root "   \
+                                 << "to be able to create required loop device" << std::endl;  \
+                       return;                                                                 \
+               }                                                                               \
+               m_require_loopdev = true;                                                       \
+       }
+
+
 const Byte_Value IMAGESIZE_Default = 256*MEBIBYTE;
 const Byte_Value IMAGESIZE_Larger  = 512*MEBIBYTE;
 
@@ -229,6 +242,10 @@ protected:
        static void setup_supported_filesystems();
        static void teardown_supported_filesystems();
 
+       virtual const std::string create_loopdev(const std::string& image_name) const;
+       virtual void detach_loopdev(const std::string& loopdev_name) const;
+       virtual void reload_loopdev_size(const std::string& loopdev_name) const;
+
        virtual void reload_partition();
        virtual void resize_image(Byte_Value new_size);
        virtual void shrink_partition(Byte_Value size);
@@ -238,6 +255,8 @@ protected:
 
        FSType          m_fstype;
        FileSystem*     m_fs_object;  // Alias pointer
+       bool            m_require_loopdev;
+       std::string     m_dev_name;
        Partition       m_partition;
        OperationDetail m_operation_detail;
 };
@@ -248,8 +267,9 @@ const char*           SupportedFileSystemsTest::s_image_name            = "test_
 
 
 SupportedFileSystemsTest::SupportedFileSystemsTest()
-                                            // Initialise top-level operation detail object with description 
...
- : m_fstype(GetParam()), m_fs_object(NULL), m_operation_detail("Operation details:", STATUS_NONE)
+ : m_fstype(GetParam()), m_fs_object(NULL), m_require_loopdev(false),
+   // Initialise top-level operation detail object with description ...
+   m_operation_detail("Operation details:", STATUS_NONE)
 {
 }
 
@@ -276,12 +296,19 @@ void SupportedFileSystemsTest::extra_setup(Byte_Value size)
                                                 << size << ".  errno=" << errno << "," << strerror(errno);
        close(fd);
 
+       m_dev_name = s_image_name;
+       if (m_require_loopdev)
+               m_dev_name = create_loopdev(s_image_name);
+
        reload_partition();
 }
 
 
 void SupportedFileSystemsTest::TearDown()
 {
+       if (m_require_loopdev)
+               detach_loopdev(m_dev_name);
+
        unlink(s_image_name);
 
        m_fs_object = NULL;
@@ -339,6 +366,66 @@ void SupportedFileSystemsTest::teardown_supported_filesystems()
 }
 
 
+// Create loop device over named image file and return the device name.
+const std::string SupportedFileSystemsTest::create_loopdev(const std::string& image_name) const
+{
+       Glib::ustring output;
+       Glib::ustring error;
+       Glib::ustring cmd = "losetup --find --show " + Glib::shell_quote(image_name);
+       int exit_status = Utils::execute_command(cmd, output, error, true);
+       if (exit_status != 0)
+       {
+               ADD_FAILURE() << __func__ << "(): Execute: " << cmd << "\n"
+                             << error
+                             << __func__ << "(): Losetup failed with exit status " << exit_status << "\n"
+                             << __func__ << "(): Failed to create required loop device";
+               return "";
+       }
+
+       // Strip trailing New Line.
+       size_t len = output.length();
+       if (len > 0 && output[len-1] == '\n')
+               output.resize(len-1);
+
+       return output;
+}
+
+
+// Detach named loop device.
+void SupportedFileSystemsTest::detach_loopdev(const std::string& loopdev_name) const
+{
+       Glib::ustring output;
+       Glib::ustring error;
+       Glib::ustring cmd = "losetup --detach " + Glib::shell_quote(loopdev_name);
+       int exit_status = Utils::execute_command(cmd, output, error, true);
+       if (exit_status != 0)
+       {
+               // Report losetup detach error but don't fail the test because of it.
+               std::cout << __func__ << "(): Execute: " << cmd << "\n"
+                         << error
+                         << __func__ << "(): Losetup failed with exit status " << exit_status << "\n"
+                         << __func__ << "(): Failed to detach loop device.  Test NOT affected" << std::endl;
+       }
+}
+
+
+// Instruct loop device to reload the size of the underlying image file.
+void SupportedFileSystemsTest::reload_loopdev_size(const std::string& loopdev_name) const
+{
+       Glib::ustring output;
+       Glib::ustring error;
+       Glib::ustring cmd = "losetup --set-capacity " + Glib::shell_quote(loopdev_name);
+       int exit_status = Utils::execute_command(cmd, output, error, true);
+       if (exit_status != 0)
+       {
+               ADD_FAILURE() << __func__ << "(): Execute: " << cmd << "\n"
+                             << error
+                             << __func__ << "(): Losetup failed with exit status " << exit_status << "\n"
+                             << __func__ << "(): Failed to reload loop device size";
+       }
+}
+
+
 // (Re)initialise m_partition as a Partition object spanning the whole of the image file
 // with file system type only.  No file system usage, label or UUID.
 void SupportedFileSystemsTest::reload_partition()
@@ -346,11 +433,11 @@ void SupportedFileSystemsTest::reload_partition()
        m_partition.Reset();
 
        // Use libparted to get the sector size etc. of the image file.
-       PedDevice* lp_device = ped_device_get(s_image_name);
+       PedDevice* lp_device = ped_device_get(m_dev_name.c_str());
        ASSERT_TRUE(lp_device != NULL);
 
        // Prepare partition object spanning whole of the image file.
-       m_partition.set_unpartitioned(s_image_name,
+       m_partition.set_unpartitioned(m_dev_name,
                                      lp_device->path,
                                      m_fstype,
                                      lp_device->length,
@@ -370,6 +457,9 @@ void SupportedFileSystemsTest::resize_image(Byte_Value new_size)
        ASSERT_EQ(ftruncate(fd, (off_t)new_size), 0) << "Failed to resize image file '" << s_image_name << "' 
to size "
                                                     << new_size << ".  errno=" << errno << "," << 
strerror(errno);
        close(fd);
+
+       if (m_require_loopdev)
+               reload_loopdev_size(m_dev_name);
 }
 
 
@@ -384,6 +474,8 @@ void SupportedFileSystemsTest::shrink_partition(Byte_Value new_size)
 TEST_P(SupportedFileSystemsTest, Create)
 {
        SKIP_IF_FS_DOESNT_SUPPORT(create);
+       SKIP_IF_NOT_ROOT_FOR_REQUIRED_LOOPDEV_FOR_FS(FS_LVM2_PV);
+
        extra_setup();
        // Call create, check for success and print operation details on failure.
        ASSERT_TRUE(m_fs_object->create(m_partition, m_operation_detail)) << m_operation_detail;
@@ -394,6 +486,7 @@ TEST_P(SupportedFileSystemsTest, CreateAndReadUsage)
 {
        SKIP_IF_FS_DOESNT_SUPPORT(create);
        SKIP_IF_FS_DOESNT_SUPPORT(read);
+       SKIP_IF_NOT_ROOT_FOR_REQUIRED_LOOPDEV_FOR_FS(FS_LVM2_PV);
 
        extra_setup();
        ASSERT_TRUE(m_fs_object->create(m_partition, m_operation_detail)) << m_operation_detail;
@@ -421,6 +514,7 @@ TEST_P(SupportedFileSystemsTest, CreateAndReadLabel)
 {
        SKIP_IF_FS_DOESNT_SUPPORT(create);
        SKIP_IF_FS_DOESNT_SUPPORT(read_label);
+       SKIP_IF_NOT_ROOT_FOR_REQUIRED_LOOPDEV_FOR_FS(FS_LVM2_PV);
 
        const char* fs_label = "TEST_LABEL";
        extra_setup();
@@ -441,6 +535,7 @@ TEST_P(SupportedFileSystemsTest, CreateAndReadUUID)
 {
        SKIP_IF_FS_DOESNT_SUPPORT(create);
        SKIP_IF_FS_DOESNT_SUPPORT(read_uuid);
+       SKIP_IF_NOT_ROOT_FOR_REQUIRED_LOOPDEV_FOR_FS(FS_LVM2_PV);
 
        extra_setup();
        ASSERT_TRUE(m_fs_object->create(m_partition, m_operation_detail)) << m_operation_detail;
@@ -459,6 +554,7 @@ TEST_P(SupportedFileSystemsTest, CreateAndWriteLabel)
 {
        SKIP_IF_FS_DOESNT_SUPPORT(create);
        SKIP_IF_FS_DOESNT_SUPPORT(write_label);
+       SKIP_IF_NOT_ROOT_FOR_REQUIRED_LOOPDEV_FOR_FS(FS_LVM2_PV);
 
        extra_setup();
        m_partition.set_filesystem_label("FIRST");
@@ -474,6 +570,7 @@ TEST_P(SupportedFileSystemsTest, CreateAndWriteUUID)
 {
        SKIP_IF_FS_DOESNT_SUPPORT(create);
        SKIP_IF_FS_DOESNT_SUPPORT(write_uuid);
+       SKIP_IF_NOT_ROOT_FOR_REQUIRED_LOOPDEV_FOR_FS(FS_LVM2_PV);
 
        extra_setup();
        ASSERT_TRUE(m_fs_object->create(m_partition, m_operation_detail)) << m_operation_detail;
@@ -487,6 +584,7 @@ TEST_P(SupportedFileSystemsTest, CreateAndCheck)
 {
        SKIP_IF_FS_DOESNT_SUPPORT(create);
        SKIP_IF_FS_DOESNT_SUPPORT(check);
+       SKIP_IF_NOT_ROOT_FOR_REQUIRED_LOOPDEV_FOR_FS(FS_LVM2_PV);
 
        extra_setup();
        ASSERT_TRUE(m_fs_object->create(m_partition, m_operation_detail)) << m_operation_detail;
@@ -500,6 +598,7 @@ TEST_P(SupportedFileSystemsTest, CreateAndRemove)
 {
        SKIP_IF_FS_DOESNT_SUPPORT(create);
        SKIP_IF_FS_DOESNT_SUPPORT(remove);
+       SKIP_IF_NOT_ROOT_FOR_REQUIRED_LOOPDEV_FOR_FS(FS_LVM2_PV);
 
        extra_setup();
        ASSERT_TRUE(m_fs_object->create(m_partition, m_operation_detail)) << m_operation_detail;
@@ -514,6 +613,7 @@ TEST_P(SupportedFileSystemsTest, CreateAndGrow)
 {
        SKIP_IF_FS_DOESNT_SUPPORT(create);
        SKIP_IF_FS_DOESNT_SUPPORT(grow);
+       SKIP_IF_NOT_ROOT_FOR_REQUIRED_LOOPDEV_FOR_FS(FS_LVM2_PV);
 
        extra_setup(IMAGESIZE_Default);
        ASSERT_TRUE(m_fs_object->create(m_partition, m_operation_detail)) << m_operation_detail;
@@ -529,6 +629,7 @@ TEST_P(SupportedFileSystemsTest, CreateAndShrink)
 {
        SKIP_IF_FS_DOESNT_SUPPORT(create);
        SKIP_IF_FS_DOESNT_SUPPORT(shrink);
+       SKIP_IF_NOT_ROOT_FOR_REQUIRED_LOOPDEV_FOR_FS(FS_LVM2_PV);
 
        extra_setup(IMAGESIZE_Larger);
        ASSERT_TRUE(m_fs_object->create(m_partition, m_operation_detail)) << m_operation_detail;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]