61580b
From 94d707dd225104ba14422eeb43c73b1f742b12da Mon Sep 17 00:00:00 2001
940a02
From: Vojtech Trefny <vtrefny@redhat.com>
940a02
Date: Tue, 13 Jul 2021 13:22:05 +0200
61580b
Subject: [PATCH 1/7] lvm: Allow configuring global "device filter" for LVM
940a02
 commands
940a02
940a02
Starting with 2.03.12 LVM introduces a new system for telling LVM
940a02
which devices it should use. The old device filters in config are
940a02
no longer working and we need to use either the system.devices
940a02
config file in /etc/lvm/devices (default behaviour) or specify
940a02
all allowed devices using the new --devices option. Because this
940a02
option must be specified for every call which might be incovenient
940a02
for our users, this commit introduces a new function to configure
940a02
this globally, which we already do for the --config option.
940a02
---
940a02
 src/lib/plugin_apis/lvm.api |  23 +++
61580b
 src/plugins/lvm-dbus.c      |  75 ++++++++-
940a02
 src/plugins/lvm.c           |  97 ++++++++++--
940a02
 src/plugins/lvm.h           |   4 +
940a02
 tests/library_test.py       | 304 ++++++++++++++++++++----------------
940a02
 tests/lvm_dbus_tests.py     |  47 +++++-
940a02
 tests/lvm_test.py           |  50 ++++++
940a02
 tests/overrides_test.py     |  23 ++-
61580b
 8 files changed, 470 insertions(+), 153 deletions(-)
940a02
940a02
diff --git a/src/lib/plugin_apis/lvm.api b/src/lib/plugin_apis/lvm.api
61580b
index c695c111..23f68b81 100644
940a02
--- a/src/lib/plugin_apis/lvm.api
940a02
+++ b/src/lib/plugin_apis/lvm.api
940a02
@@ -601,6 +601,7 @@ typedef enum {
940a02
     BD_LVM_TECH_CACHE_CALCS,
940a02
     BD_LVM_TECH_GLOB_CONF,
940a02
     BD_LVM_TECH_VDO,
940a02
+    BD_LVM_TECH_DEVICES,
940a02
 } BDLVMTech;
940a02
 
940a02
 typedef enum {
940a02
@@ -1214,6 +1215,28 @@ gboolean bd_lvm_set_global_config (const gchar *new_config, GError **error);
940a02
  */
940a02
 gchar* bd_lvm_get_global_config (GError **error);
940a02
 
940a02
+/**
940a02
+ * bd_lvm_set_devices_filter:
940a02
+ * @devices: (allow-none) (array zero-terminated=1): list of devices for lvm commands to work on
940a02
+ * @error: (out): place to store error (if any)
940a02
+ *
940a02
+ * Returns: whether the devices filter was successfully set or not
940a02
+ *
940a02
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
940a02
+ */
940a02
+gboolean bd_lvm_set_devices_filter (const gchar **devices, GError **error);
940a02
+
940a02
+/**
940a02
+ * bd_lvm_get_devices_filter:
940a02
+ * @error: (out): place to store error (if any)
940a02
+ *
940a02
+ * Returns: (transfer full) (array zero-terminated=1): a copy of a string representation of
940a02
+ *                                                     the currently set LVM devices filter
940a02
+ *
940a02
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
940a02
+ */
940a02
+gchar** bd_lvm_get_devices_filter (GError **error);
940a02
+
940a02
 /**
940a02
  * bd_lvm_cache_get_default_md_size:
940a02
  * @cache_size: size of the cache to determine MD size for
940a02
diff --git a/src/plugins/lvm-dbus.c b/src/plugins/lvm-dbus.c
61580b
index 51572c9a..b47ed0ef 100644
940a02
--- a/src/plugins/lvm-dbus.c
940a02
+++ b/src/plugins/lvm-dbus.c
940a02
@@ -35,6 +35,8 @@
940a02
 static GMutex global_config_lock;
940a02
 static gchar *global_config_str = NULL;
940a02
 
940a02
+static gchar *global_devices_str = NULL;
940a02
+
940a02
 #define LVM_BUS_NAME "com.redhat.lvmdbus1"
940a02
 #define LVM_OBJ_PREFIX "/com/redhat/lvmdbus1"
940a02
 #define MANAGER_OBJ "/com/redhat/lvmdbus1/Manager"
61580b
@@ -241,11 +243,20 @@ static gboolean setup_dbus_connection (GError **error) {
61580b
     return TRUE;
61580b
 }
61580b
 
61580b
+static volatile guint avail_deps = 0;
61580b
 static volatile guint avail_dbus_deps = 0;
61580b
 static volatile guint avail_features = 0;
940a02
 static volatile guint avail_module_deps = 0;
940a02
 static GMutex deps_check_lock;
940a02
 
940a02
+#define DEPS_LVMDEVICES 0
940a02
+#define DEPS_LVMDEVICES_MASK (1 << DEPS_LVMDEVICES)
940a02
+#define DEPS_LAST 1
940a02
+
940a02
+static const UtilDep deps[DEPS_LAST] = {
940a02
+    {"lvmdevices", NULL, NULL, NULL},
940a02
+};
940a02
+
940a02
 #define DBUS_DEPS_LVMDBUSD 0
940a02
 #define DBUS_DEPS_LVMDBUSD_MASK (1 << DBUS_DEPS_LVMDBUSD)
940a02
 #define DBUS_DEPS_LAST 1
61580b
@@ -378,6 +389,8 @@ gboolean bd_lvm_is_tech_avail (BDLVMTech tech, guint64 mode, GError **error) {
61580b
         return check_dbus_deps (&avail_dbus_deps, DBUS_DEPS_LVMDBUSD_MASK, dbus_deps, DBUS_DEPS_LAST, &deps_check_lock, error) &&
61580b
                check_features (&avail_features, FEATURES_VDO_MASK, features, FEATURES_LAST, &deps_check_lock, error) &&
61580b
                check_module_deps (&avail_module_deps, MODULE_DEPS_VDO_MASK, module_deps, MODULE_DEPS_LAST, &deps_check_lock, error);
940a02
+    case BD_LVM_TECH_DEVICES:
940a02
+        return check_deps (&avail_deps, DEPS_LVMDEVICES_MASK, deps, DEPS_LAST, &deps_check_lock, error);
940a02
     default:
940a02
         /* everything is supported by this implementation of the plugin */
940a02
         return check_dbus_deps (&avail_dbus_deps, DBUS_DEPS_LVMDBUSD_MASK, dbus_deps, DBUS_DEPS_LAST, &deps_check_lock, error);
61580b
@@ -515,6 +528,7 @@ static gboolean unbox_params_and_add (GVariant *params, GVariantBuilder *builder
940a02
 
940a02
 static GVariant* call_lvm_method (const gchar *obj, const gchar *intf, const gchar *method, GVariant *params, GVariant *extra_params, const BDExtraArg **extra_args, guint64 *task_id, guint64 *progress_id, gboolean lock_config, GError **error) {
940a02
     GVariant *config = NULL;
940a02
+    GVariant *devices = NULL;
940a02
     GVariant *param = NULL;
940a02
     GVariantIter iter;
940a02
     GVariantBuilder builder;
61580b
@@ -536,8 +550,8 @@ static GVariant* call_lvm_method (const gchar *obj, const gchar *intf, const gch
940a02
     if (lock_config)
940a02
         g_mutex_lock (&global_config_lock);
940a02
 
940a02
-    if (global_config_str || extra_params || extra_args) {
940a02
-        if (global_config_str || extra_args) {
940a02
+    if (global_config_str || global_devices_str || extra_params || extra_args) {
940a02
+        if (global_config_str || global_devices_str || extra_args) {
940a02
             /* add the global config to the extra_params */
940a02
             g_variant_builder_init (&extra_builder, G_VARIANT_TYPE_DICTIONARY);
940a02
 
61580b
@@ -558,6 +572,11 @@ static GVariant* call_lvm_method (const gchar *obj, const gchar *intf, const gch
940a02
                 g_variant_builder_add (&extra_builder, "{sv}", "--config", config);
940a02
                 added_extra = TRUE;
940a02
             }
940a02
+            if (global_devices_str) {
940a02
+                devices = g_variant_new ("s", global_devices_str);
940a02
+                g_variant_builder_add (&extra_builder, "{sv}", "--devices", devices);
940a02
+                added_extra = TRUE;
940a02
+            }
940a02
 
940a02
             if (added_extra)
940a02
                 config_extra_params = g_variant_builder_end (&extra_builder);
61580b
@@ -2654,6 +2673,58 @@ gchar* bd_lvm_get_global_config (GError **error UNUSED) {
940a02
     return ret;
940a02
 }
940a02
 
940a02
+/**
940a02
+ * bd_lvm_set_devices_filter:
940a02
+ * @devices: (allow-none) (array zero-terminated=1): list of devices for lvm commands to work on
940a02
+ * @error: (out): place to store error (if any)
940a02
+ *
940a02
+ * Returns: whether the devices filter was successfully set or not
940a02
+ *
940a02
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
940a02
+ */
940a02
+gboolean bd_lvm_set_devices_filter (const gchar **devices, GError **error) {
940a02
+    if (!bd_lvm_is_tech_avail (BD_LVM_TECH_DEVICES, 0, error))
940a02
+        return FALSE;
940a02
+
940a02
+    g_mutex_lock (&global_config_lock);
940a02
+
940a02
+    /* first free the old value */
940a02
+    g_free (global_devices_str);
940a02
+
940a02
+    /* now store the new one */
940a02
+    if (!devices || !(*devices))
940a02
+        global_devices_str = NULL;
940a02
+    else
940a02
+        global_devices_str = g_strjoinv (",", (gchar **) devices);
940a02
+
940a02
+    g_mutex_unlock (&global_config_lock);
940a02
+    return TRUE;
940a02
+}
940a02
+
940a02
+/**
940a02
+ * bd_lvm_get_devices_filter:
940a02
+ * @error: (out): place to store error (if any)
940a02
+ *
940a02
+ * Returns: (transfer full) (array zero-terminated=1): a copy of a string representation of
940a02
+ *                                                     the currently set LVM devices filter
940a02
+ *
940a02
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
940a02
+ */
940a02
+gchar** bd_lvm_get_devices_filter (GError **error UNUSED) {
940a02
+    gchar **ret = NULL;
940a02
+
940a02
+    g_mutex_lock (&global_config_lock);
940a02
+
940a02
+    if (global_devices_str)
940a02
+        ret = g_strsplit (global_devices_str, ",", -1);
940a02
+    else
940a02
+        ret = NULL;
940a02
+
940a02
+    g_mutex_unlock (&global_config_lock);
940a02
+
940a02
+    return ret;
940a02
+}
940a02
+
940a02
 /**
940a02
  * bd_lvm_cache_get_default_md_size:
940a02
  * @cache_size: size of the cache to determine MD size for
940a02
diff --git a/src/plugins/lvm.c b/src/plugins/lvm.c
61580b
index 26af0d19..42ee0f90 100644
940a02
--- a/src/plugins/lvm.c
940a02
+++ b/src/plugins/lvm.c
940a02
@@ -34,6 +34,8 @@
940a02
 static GMutex global_config_lock;
940a02
 static gchar *global_config_str = NULL;
940a02
 
940a02
+static gchar *global_devices_str = NULL;
940a02
+
940a02
 /**
940a02
  * SECTION: lvm
940a02
  * @short_description: plugin for operations with LVM
940a02
@@ -212,10 +214,13 @@ static GMutex deps_check_lock;
940a02
 
940a02
 #define DEPS_LVM 0
940a02
 #define DEPS_LVM_MASK (1 << DEPS_LVM)
940a02
-#define DEPS_LAST 1
940a02
+#define DEPS_LVMDEVICES 1
940a02
+#define DEPS_LVMDEVICES_MASK (1 << DEPS_LVMDEVICES)
940a02
+#define DEPS_LAST 2
940a02
 
940a02
 static const UtilDep deps[DEPS_LAST] = {
940a02
     {"lvm", LVM_MIN_VERSION, "version", "LVM version:\\s+([\\d\\.]+)"},
940a02
+    {"lvmdevices", NULL, NULL, NULL},
940a02
 };
940a02
 
940a02
 #define FEATURES_VDO 0
940a02
@@ -327,6 +332,8 @@ gboolean bd_lvm_is_tech_avail (BDLVMTech tech, guint64 mode, GError **error) {
940a02
     case BD_LVM_TECH_VDO:
940a02
             return check_features (&avail_features, FEATURES_VDO_MASK, features, FEATURES_LAST, &deps_check_lock, error) &&
940a02
                    check_module_deps (&avail_module_deps, MODULE_DEPS_VDO_MASK, module_deps, MODULE_DEPS_LAST, &deps_check_lock, error);
940a02
+    case BD_LVM_TECH_DEVICES:
940a02
+            return check_deps (&avail_deps, DEPS_LVMDEVICES_MASK, deps, DEPS_LAST, &deps_check_lock, error);
940a02
     default:
940a02
         /* everything is supported by this implementation of the plugin */
940a02
         return check_deps (&avail_deps, DEPS_LVM_MASK, deps, DEPS_LAST, &deps_check_lock, error);
940a02
@@ -337,6 +344,8 @@ static gboolean call_lvm_and_report_error (const gchar **args, const BDExtraArg
940a02
     gboolean success = FALSE;
940a02
     guint i = 0;
940a02
     guint args_length = g_strv_length ((gchar **) args);
940a02
+    g_autofree gchar *config_arg = NULL;
940a02
+    g_autofree gchar *devices_arg = NULL;
940a02
 
940a02
     if (!check_deps (&avail_deps, DEPS_LVM_MASK, deps, DEPS_LAST, &deps_check_lock, error))
940a02
         return FALSE;
940a02
@@ -345,20 +354,26 @@ static gboolean call_lvm_and_report_error (const gchar **args, const BDExtraArg
940a02
     if (lock_config)
940a02
         g_mutex_lock (&global_config_lock);
940a02
 
940a02
-    /* allocate enough space for the args plus "lvm", "--config" and NULL */
940a02
-    const gchar **argv = g_new0 (const gchar*, args_length + 3);
940a02
+    /* allocate enough space for the args plus "lvm", "--config", "--devices" and NULL */
940a02
+    const gchar **argv = g_new0 (const gchar*, args_length + 4);
940a02
 
940a02
     /* construct argv from args with "lvm" prepended */
940a02
     argv[0] = "lvm";
940a02
     for (i=0; i < args_length; i++)
940a02
         argv[i+1] = args[i];
940a02
-    argv[args_length + 1] = global_config_str ? g_strdup_printf("--config=%s", global_config_str) : NULL;
940a02
-    argv[args_length + 2] = NULL;
940a02
+    if (global_config_str) {
940a02
+        config_arg = g_strdup_printf("--config=%s", global_config_str);
940a02
+        argv[++args_length] = config_arg;
940a02
+    }
940a02
+    if (global_devices_str) {
940a02
+        devices_arg = g_strdup_printf("--devices=%s", global_devices_str);
940a02
+        argv[++args_length] = devices_arg;
940a02
+    }
940a02
+    argv[++args_length] = NULL;
940a02
 
940a02
     success = bd_utils_exec_and_report_error (argv, extra, error);
940a02
     if (lock_config)
940a02
         g_mutex_unlock (&global_config_lock);
940a02
-    g_free ((gchar *) argv[args_length + 1]);
940a02
     g_free (argv);
940a02
 
940a02
     return success;
940a02
@@ -368,6 +383,8 @@ static gboolean call_lvm_and_capture_output (const gchar **args, const BDExtraAr
940a02
     gboolean success = FALSE;
940a02
     guint i = 0;
940a02
     guint args_length = g_strv_length ((gchar **) args);
940a02
+    g_autofree gchar *config_arg = NULL;
940a02
+    g_autofree gchar *devices_arg = NULL;
940a02
 
940a02
     if (!check_deps (&avail_deps, DEPS_LVM_MASK, deps, DEPS_LAST, &deps_check_lock, error))
940a02
         return FALSE;
940a02
@@ -375,19 +392,25 @@ static gboolean call_lvm_and_capture_output (const gchar **args, const BDExtraAr
940a02
     /* don't allow global config string changes during the run */
940a02
     g_mutex_lock (&global_config_lock);
940a02
 
940a02
-    /* allocate enough space for the args plus "lvm", "--config" and NULL */
940a02
-    const gchar **argv = g_new0 (const gchar*, args_length + 3);
940a02
+    /* allocate enough space for the args plus "lvm", "--config", "--devices" and NULL */
940a02
+    const gchar **argv = g_new0 (const gchar*, args_length + 4);
940a02
 
940a02
     /* construct argv from args with "lvm" prepended */
940a02
     argv[0] = "lvm";
940a02
     for (i=0; i < args_length; i++)
940a02
         argv[i+1] = args[i];
940a02
-    argv[args_length + 1] = global_config_str ? g_strdup_printf("--config=%s", global_config_str) : NULL;
940a02
-    argv[args_length + 2] = NULL;
940a02
+    if (global_config_str) {
940a02
+        config_arg = g_strdup_printf("--config=%s", global_config_str);
940a02
+        argv[++args_length] = config_arg;
940a02
+    }
940a02
+    if (global_devices_str) {
940a02
+        devices_arg = g_strdup_printf("--devices=%s", global_devices_str);
940a02
+        argv[++args_length] = devices_arg;
940a02
+    }
940a02
+    argv[++args_length] = NULL;
940a02
 
940a02
     success = bd_utils_exec_and_capture_output (argv, extra, output, error);
940a02
     g_mutex_unlock (&global_config_lock);
940a02
-    g_free ((gchar *) argv[args_length + 1]);
940a02
     g_free (argv);
940a02
 
940a02
     return success;
61580b
@@ -2033,6 +2056,58 @@ gchar* bd_lvm_get_global_config (GError **error UNUSED) {
940a02
     return ret;
940a02
 }
940a02
 
940a02
+/**
940a02
+ * bd_lvm_set_devices_filter:
940a02
+ * @devices: (allow-none) (array zero-terminated=1): list of devices for lvm commands to work on
940a02
+ * @error: (out): place to store error (if any)
940a02
+ *
940a02
+ * Returns: whether the devices filter was successfully set or not
940a02
+ *
940a02
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
940a02
+ */
940a02
+gboolean bd_lvm_set_devices_filter (const gchar **devices, GError **error) {
940a02
+    if (!bd_lvm_is_tech_avail (BD_LVM_TECH_DEVICES, 0, error))
940a02
+        return FALSE;
940a02
+
940a02
+    g_mutex_lock (&global_config_lock);
940a02
+
940a02
+    /* first free the old value */
940a02
+    g_free (global_devices_str);
940a02
+
940a02
+    /* now store the new one */
940a02
+    if (!devices || !(*devices))
940a02
+        global_devices_str = NULL;
940a02
+    else
940a02
+        global_devices_str = g_strjoinv (",", (gchar **) devices);
940a02
+
940a02
+    g_mutex_unlock (&global_config_lock);
940a02
+    return TRUE;
940a02
+}
940a02
+
940a02
+/**
940a02
+ * bd_lvm_get_devices_filter:
940a02
+ * @error: (out): place to store error (if any)
940a02
+ *
940a02
+ * Returns: (transfer full) (array zero-terminated=1): a copy of a string representation of
940a02
+ *                                                     the currently set LVM devices filter
940a02
+ *
940a02
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
940a02
+ */
940a02
+gchar** bd_lvm_get_devices_filter (GError **error UNUSED) {
940a02
+    gchar **ret = NULL;
940a02
+
940a02
+    g_mutex_lock (&global_config_lock);
940a02
+
940a02
+    if (global_devices_str)
940a02
+        ret = g_strsplit (global_devices_str, ",", -1);
940a02
+    else
940a02
+        ret = NULL;
940a02
+
940a02
+    g_mutex_unlock (&global_config_lock);
940a02
+
940a02
+    return ret;
940a02
+}
940a02
+
940a02
 /**
940a02
  * bd_lvm_cache_get_default_md_size:
940a02
  * @cache_size: size of the cache to determine MD size for
940a02
diff --git a/src/plugins/lvm.h b/src/plugins/lvm.h
61580b
index 2162d769..8063693f 100644
940a02
--- a/src/plugins/lvm.h
940a02
+++ b/src/plugins/lvm.h
940a02
@@ -216,6 +216,7 @@ typedef enum {
940a02
     BD_LVM_TECH_CACHE_CALCS,
940a02
     BD_LVM_TECH_GLOB_CONF,
940a02
     BD_LVM_TECH_VDO,
940a02
+    BD_LVM_TECH_DEVICES,
940a02
 } BDLVMTech;
940a02
 
940a02
 typedef enum {
940a02
@@ -289,6 +290,9 @@ gboolean bd_lvm_thsnapshotcreate (const gchar *vg_name, const gchar *origin_name
940a02
 gboolean bd_lvm_set_global_config (const gchar *new_config, GError **error);
940a02
 gchar* bd_lvm_get_global_config (GError **error);
940a02
 
940a02
+gboolean bd_lvm_set_devices_filter (const gchar **devices, GError **error);
940a02
+gchar** bd_lvm_get_devices_filter (GError **error);
940a02
+
940a02
 guint64 bd_lvm_cache_get_default_md_size (guint64 cache_size, GError **error);
940a02
 const gchar* bd_lvm_cache_get_mode_str (BDLVMCacheMode mode, GError **error);
940a02
 BDLVMCacheMode bd_lvm_cache_get_mode_from_str (const gchar *mode_str, GError **error);
940a02
diff --git a/tests/library_test.py b/tests/library_test.py
61580b
index 08e44fdc..efd17bd2 100644
940a02
--- a/tests/library_test.py
940a02
+++ b/tests/library_test.py
940a02
@@ -13,18 +13,178 @@ class LibraryOpsTestCase(unittest.TestCase):
940a02
     # all plugins except for 'btrfs', 'fs' and 'mpath' -- these don't have all
940a02
     # the dependencies on CentOS/Debian and we don't need them for this test
940a02
     requested_plugins = BlockDev.plugin_specs_from_names(("crypto", "dm",
940a02
-                                                          "kbd", "loop", "lvm",
940a02
+                                                          "kbd", "loop",
940a02
                                                           "mdraid", "part", "swap"))
940a02
 
940a02
+    @classmethod
940a02
+    def setUpClass(cls):
940a02
+        if not BlockDev.is_initialized():
940a02
+            BlockDev.init(cls.requested_plugins, None)
940a02
+        else:
940a02
+            BlockDev.reinit(cls.requested_plugins, True, None)
940a02
+
940a02
+    @classmethod
940a02
+    def tearDownClass(cls):
940a02
+        BlockDev.switch_init_checks(True)
940a02
+
940a02
+    def my_log_func(self, level, msg):
940a02
+        # not much to verify here
940a02
+        self.assertTrue(isinstance(level, int))
940a02
+        self.assertTrue(isinstance(msg, str))
940a02
+
940a02
+        self.log += msg + "\n"
940a02
+
940a02
+    @tag_test(TestTags.CORE)
940a02
+    def test_logging_setup(self):
940a02
+        """Verify that setting up logging works as expected"""
940a02
+
940a02
+        self.assertTrue(BlockDev.reinit(self.requested_plugins, False, self.my_log_func))
940a02
+
940a02
+        succ = BlockDev.utils_exec_and_report_error(["true"])
940a02
+        self.assertTrue(succ)
940a02
+
940a02
+        # reinit with no logging function should change nothing about logging
940a02
+        self.assertTrue(BlockDev.reinit(self.requested_plugins, False, None))
940a02
+
940a02
+        succ, out = BlockDev.utils_exec_and_capture_output(["echo", "hi"])
940a02
+        self.assertTrue(succ)
940a02
+        self.assertEqual(out, "hi\n")
940a02
+
940a02
+        match = re.search(r'Running \[(\d+)\] true', self.log)
940a02
+        self.assertIsNot(match, None)
940a02
+        task_id1 = match.group(1)
940a02
+        match = re.search(r'Running \[(\d+)\] echo hi', self.log)
940a02
+        self.assertIsNot(match, None)
940a02
+        task_id2 = match.group(1)
940a02
+
940a02
+        self.assertIn("...done [%s] (exit code: 0)" % task_id1, self.log)
940a02
+        self.assertIn("stdout[%s]:" % task_id1, self.log)
940a02
+        self.assertIn("stderr[%s]:" % task_id1, self.log)
940a02
+
940a02
+        self.assertIn("stdout[%s]: hi" % task_id2, self.log)
940a02
+        self.assertIn("stderr[%s]:" % task_id2, self.log)
940a02
+        self.assertIn("...done [%s] (exit code: 0)" % task_id2, self.log)
940a02
+
940a02
+    @tag_test(TestTags.CORE)
940a02
+    def test_require_plugins(self):
940a02
+        """Verify that loading only required plugins works as expected"""
940a02
+
940a02
+        ps = BlockDev.PluginSpec()
940a02
+        ps.name = BlockDev.Plugin.SWAP
940a02
+        ps.so_name = ""
940a02
+        self.assertTrue(BlockDev.reinit([ps], True, None))
940a02
+        self.assertEqual(BlockDev.get_available_plugin_names(), ["swap"])
940a02
+        self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
940a02
+
940a02
+    @tag_test(TestTags.CORE)
940a02
+    def test_not_implemented(self):
940a02
+        """Verify that unloaded/unimplemented functions report errors"""
940a02
+
940a02
+        # should be loaded and working
940a02
+        self.assertTrue(BlockDev.md_canonicalize_uuid("3386ff85:f5012621:4a435f06:1eb47236"))
940a02
+
940a02
+        ps = BlockDev.PluginSpec()
940a02
+        ps.name = BlockDev.Plugin.SWAP
940a02
+        ps.so_name = ""
940a02
+        self.assertTrue(BlockDev.reinit([ps], True, None))
940a02
+        self.assertEqual(BlockDev.get_available_plugin_names(), ["swap"])
940a02
+
940a02
+        # no longer loaded
940a02
+        with self.assertRaises(GLib.GError):
940a02
+            BlockDev.md_canonicalize_uuid("3386ff85:f5012621:4a435f06:1eb47236")
940a02
+
940a02
+        self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
940a02
+
940a02
+        # loaded again
940a02
+        self.assertTrue(BlockDev.md_canonicalize_uuid("3386ff85:f5012621:4a435f06:1eb47236"))
940a02
+
940a02
+    def test_ensure_init(self):
940a02
+        """Verify that ensure_init just returns when already initialized"""
940a02
+
940a02
+        # the library is already initialized, ensure_init() shonuld do nothing
940a02
+        avail_plugs = BlockDev.get_available_plugin_names()
940a02
+        self.assertTrue(BlockDev.ensure_init(self.requested_plugins, None))
940a02
+        self.assertEqual(avail_plugs, BlockDev.get_available_plugin_names())
940a02
+
940a02
+        # reinit with a subset of plugins
940a02
+        plugins = BlockDev.plugin_specs_from_names(["swap", "part"])
940a02
+        self.assertTrue(BlockDev.reinit(plugins, True, None))
940a02
+        self.assertEqual(set(BlockDev.get_available_plugin_names()), set(["swap", "part"]))
940a02
+
940a02
+        # ensure_init with the same subset -> nothing should change
940a02
+        self.assertTrue(BlockDev.ensure_init(plugins, None))
940a02
+        self.assertEqual(set(BlockDev.get_available_plugin_names()), set(["swap", "part"]))
940a02
+
940a02
+        # ensure_init with more plugins -> extra plugins should be loaded
940a02
+        plugins = BlockDev.plugin_specs_from_names(["swap", "part", "crypto"])
940a02
+        self.assertTrue(BlockDev.ensure_init(plugins, None))
940a02
+        self.assertEqual(set(BlockDev.get_available_plugin_names()), set(["swap", "part", "crypto"]))
940a02
+
940a02
+        # reinit to unload all plugins
940a02
+        self.assertTrue(BlockDev.reinit([], True, None))
940a02
+        self.assertEqual(BlockDev.get_available_plugin_names(), [])
940a02
+
940a02
+        # ensure_init to load all plugins back
940a02
+        self.assertTrue(BlockDev.ensure_init(self.requested_plugins, None))
940a02
+        self.assertGreaterEqual(len(BlockDev.get_available_plugin_names()), 7)
940a02
+
940a02
+    def test_try_reinit(self):
940a02
+        """Verify that try_reinit() works as expected"""
940a02
+
940a02
+        # try reinitializing with only some utilities being available and thus
940a02
+        # only some plugins able to load
940a02
+        with fake_path("tests/lib_missing_utils", keep_utils=["swapon", "swapoff", "mkswap", "swaplabel"]):
940a02
+            succ, loaded = BlockDev.try_reinit(self.requested_plugins, True, None)
940a02
+            self.assertFalse(succ)
940a02
+            for plug_name in ("swap", "crypto"):
940a02
+                self.assertIn(plug_name, loaded)
940a02
+
940a02
+        # reset back to all plugins
940a02
+        self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
940a02
+
940a02
+        # now the same with a subset of plugins requested
940a02
+        plugins = BlockDev.plugin_specs_from_names(["swap", "crypto"])
940a02
+        with fake_path("tests/lib_missing_utils", keep_utils=["swapon", "swapoff", "mkswap", "swaplabel"]):
940a02
+            succ, loaded = BlockDev.try_reinit(plugins, True, None)
940a02
+            self.assertTrue(succ)
940a02
+            self.assertEqual(set(loaded), set(["swap", "crypto"]))
940a02
+
940a02
+    def test_non_en_init(self):
940a02
+        """Verify that the library initializes with lang different from en_US"""
940a02
+
940a02
+        orig_lang = os.environ.get("LANG")
940a02
+        os.environ["LANG"] = "cs.CZ_UTF-8"
940a02
+        self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
940a02
+        if orig_lang:
940a02
+            os.environ["LANG"] = orig_lang
940a02
+        else:
940a02
+            del os.environ["LANG"]
940a02
+        self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
940a02
+
940a02
+
940a02
+class PluginsTestCase(unittest.TestCase):
940a02
+    # only LVM plugin for this test
940a02
+    requested_plugins = BlockDev.plugin_specs_from_names(("lvm",))
940a02
+
940a02
     orig_config_dir = ""
940a02
 
940a02
     @classmethod
940a02
     def setUpClass(cls):
940a02
+        BlockDev.switch_init_checks(False)
940a02
         if not BlockDev.is_initialized():
940a02
             BlockDev.init(cls.requested_plugins, None)
940a02
         else:
940a02
             BlockDev.reinit(cls.requested_plugins, True, None)
940a02
 
940a02
+        try:
940a02
+            cls.devices_avail = BlockDev.lvm_is_tech_avail(BlockDev.LVMTech.DEVICES, 0)
940a02
+        except:
940a02
+            cls.devices_avail = False
940a02
+
940a02
+    @classmethod
940a02
+    def tearDownClass(cls):
940a02
+        BlockDev.switch_init_checks(True)
940a02
+
940a02
     def setUp(self):
940a02
         self.orig_config_dir = os.environ.get("LIBBLOCKDEV_CONFIG_DIR", "")
940a02
         self.addCleanup(self._clean_up)
940a02
@@ -185,6 +345,12 @@ class LibraryOpsTestCase(unittest.TestCase):
940a02
     def test_plugin_fallback(self):
940a02
         """Verify that fallback when loading plugins works as expected"""
940a02
 
940a02
+        if not self.devices_avail:
940a02
+            self.skipTest("skipping plugin fallback test: missing some LVM dependencies")
940a02
+
940a02
+        BlockDev.switch_init_checks(True)
940a02
+        self.addCleanup(BlockDev.switch_init_checks, False)
940a02
+
940a02
         # library should be successfully initialized
940a02
         self.assertTrue(BlockDev.is_initialized())
940a02
 
940a02
@@ -206,7 +372,7 @@ class LibraryOpsTestCase(unittest.TestCase):
940a02
 
940a02
         # now reinit the library with the config preferring the new build
940a02
         orig_conf_dir = os.environ.get("LIBBLOCKDEV_CONFIG_DIR")
940a02
-        os.environ["LIBBLOCKDEV_CONFIG_DIR"] = "tests/plugin_prio_conf.d"
940a02
+        os.environ["LIBBLOCKDEV_CONFIG_DIR"] = "tests/test_configs/plugin_prio_conf.d"
940a02
         self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
940a02
 
940a02
         # the original plugin should be loaded because the new one should fail
940a02
@@ -243,139 +409,9 @@ class LibraryOpsTestCase(unittest.TestCase):
940a02
 
940a02
         self.assertEqual(BlockDev.lvm_get_max_lv_size(), orig_max_size)
940a02
 
940a02
-    def my_log_func(self, level, msg):
940a02
-        # not much to verify here
940a02
-        self.assertTrue(isinstance(level, int))
940a02
-        self.assertTrue(isinstance(msg, str))
940a02
-
940a02
-        self.log += msg + "\n"
940a02
-
940a02
-    @tag_test(TestTags.CORE)
940a02
-    def test_logging_setup(self):
940a02
-        """Verify that setting up logging works as expected"""
940a02
-
940a02
-        self.assertTrue(BlockDev.reinit(self.requested_plugins, False, self.my_log_func))
940a02
-
940a02
-        succ = BlockDev.utils_exec_and_report_error(["true"])
940a02
-        self.assertTrue(succ)
940a02
-
940a02
-        # reinit with no logging function should change nothing about logging
940a02
-        self.assertTrue(BlockDev.reinit(self.requested_plugins, False, None))
940a02
-
940a02
-        succ, out = BlockDev.utils_exec_and_capture_output(["echo", "hi"])
940a02
-        self.assertTrue(succ)
940a02
-        self.assertEqual(out, "hi\n")
940a02
-
940a02
-        match = re.search(r'Running \[(\d+)\] true', self.log)
940a02
-        self.assertIsNot(match, None)
940a02
-        task_id1 = match.group(1)
940a02
-        match = re.search(r'Running \[(\d+)\] echo hi', self.log)
940a02
-        self.assertIsNot(match, None)
940a02
-        task_id2 = match.group(1)
940a02
-
940a02
-        self.assertIn("...done [%s] (exit code: 0)" % task_id1, self.log)
940a02
-        self.assertIn("stdout[%s]:" % task_id1, self.log)
940a02
-        self.assertIn("stderr[%s]:" % task_id1, self.log)
940a02
-
940a02
-        self.assertIn("stdout[%s]: hi" % task_id2, self.log)
940a02
-        self.assertIn("stderr[%s]:" % task_id2, self.log)
940a02
-        self.assertIn("...done [%s] (exit code: 0)" % task_id2, self.log)
940a02
-
940a02
-    @tag_test(TestTags.CORE)
940a02
-    def test_require_plugins(self):
940a02
-        """Verify that loading only required plugins works as expected"""
940a02
-
940a02
-        ps = BlockDev.PluginSpec()
940a02
-        ps.name = BlockDev.Plugin.SWAP
940a02
-        ps.so_name = ""
940a02
-        self.assertTrue(BlockDev.reinit([ps], True, None))
940a02
-        self.assertEqual(BlockDev.get_available_plugin_names(), ["swap"])
940a02
-        self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
940a02
-
940a02
-    @tag_test(TestTags.CORE)
940a02
-    def test_not_implemented(self):
940a02
-        """Verify that unloaded/unimplemented functions report errors"""
940a02
-
940a02
-        # should be loaded and working
940a02
-        self.assertTrue(BlockDev.lvm_get_max_lv_size() > 0)
940a02
 
940a02
-        ps = BlockDev.PluginSpec()
940a02
-        ps.name = BlockDev.Plugin.SWAP
940a02
-        ps.so_name = ""
940a02
-        self.assertTrue(BlockDev.reinit([ps], True, None))
940a02
-        self.assertEqual(BlockDev.get_available_plugin_names(), ["swap"])
940a02
-
940a02
-        # no longer loaded
940a02
-        with self.assertRaises(GLib.GError):
940a02
-            BlockDev.lvm_get_max_lv_size()
940a02
-
940a02
-        self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
940a02
-
940a02
-        # loaded again
940a02
-        self.assertTrue(BlockDev.lvm_get_max_lv_size() > 0)
940a02
-
940a02
-    def test_ensure_init(self):
940a02
-        """Verify that ensure_init just returns when already initialized"""
940a02
-
940a02
-        # the library is already initialized, ensure_init() shonuld do nothing
940a02
-        avail_plugs = BlockDev.get_available_plugin_names()
940a02
-        self.assertTrue(BlockDev.ensure_init(self.requested_plugins, None))
940a02
-        self.assertEqual(avail_plugs, BlockDev.get_available_plugin_names())
940a02
-
940a02
-        # reinit with a subset of plugins
940a02
-        plugins = BlockDev.plugin_specs_from_names(["swap", "lvm"])
940a02
-        self.assertTrue(BlockDev.reinit(plugins, True, None))
940a02
-        self.assertEqual(set(BlockDev.get_available_plugin_names()), set(["swap", "lvm"]))
940a02
-
940a02
-        # ensure_init with the same subset -> nothing should change
940a02
-        self.assertTrue(BlockDev.ensure_init(plugins, None))
940a02
-        self.assertEqual(set(BlockDev.get_available_plugin_names()), set(["swap", "lvm"]))
940a02
-
940a02
-        # ensure_init with more plugins -> extra plugins should be loaded
940a02
-        plugins = BlockDev.plugin_specs_from_names(["swap", "lvm", "crypto"])
940a02
-        self.assertTrue(BlockDev.ensure_init(plugins, None))
940a02
-        self.assertEqual(set(BlockDev.get_available_plugin_names()), set(["swap", "lvm", "crypto"]))
940a02
-
940a02
-        # reinit to unload all plugins
940a02
-        self.assertTrue(BlockDev.reinit([], True, None))
940a02
-        self.assertEqual(BlockDev.get_available_plugin_names(), [])
940a02
-
940a02
-        # ensure_init to load all plugins back
940a02
-        self.assertTrue(BlockDev.ensure_init(self.requested_plugins, None))
940a02
-        self.assertGreaterEqual(len(BlockDev.get_available_plugin_names()), 8)
940a02
-
940a02
-    def test_try_reinit(self):
940a02
-        """Verify that try_reinit() works as expected"""
940a02
-
940a02
-        # try reinitializing with only some utilities being available and thus
940a02
-        # only some plugins able to load
940a02
-        with fake_path("tests/lib_missing_utils", keep_utils=["swapon", "swapoff", "mkswap", "lvm", "swaplabel"]):
940a02
-            succ, loaded = BlockDev.try_reinit(self.requested_plugins, True, None)
940a02
-            self.assertFalse(succ)
940a02
-            for plug_name in ("swap", "lvm", "crypto"):
940a02
-                self.assertIn(plug_name, loaded)
940a02
-
940a02
-        # reset back to all plugins
940a02
-        self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
940a02
-
940a02
-        # now the same with a subset of plugins requested
940a02
-        plugins = BlockDev.plugin_specs_from_names(["lvm", "swap", "crypto"])
940a02
-        with fake_path("tests/lib_missing_utils", keep_utils=["swapon", "swapoff", "mkswap", "lvm","swaplabel"]):
940a02
-            succ, loaded = BlockDev.try_reinit(plugins, True, None)
940a02
-            self.assertTrue(succ)
940a02
-            self.assertEqual(set(loaded), set(["swap", "lvm", "crypto"]))
940a02
-
940a02
-    def test_non_en_init(self):
940a02
-        """Verify that the library initializes with lang different from en_US"""
940a02
-
940a02
-        orig_lang = os.environ.get("LANG")
940a02
-        os.environ["LANG"] = "cs.CZ_UTF-8"
940a02
-        self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
940a02
-        if orig_lang:
940a02
-            os.environ["LANG"] = orig_lang
940a02
-        else:
940a02
-            del os.environ["LANG"]
940a02
-        self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
940a02
+class DepChecksTestCase(unittest.TestCase):
940a02
+    requested_plugins = BlockDev.plugin_specs_from_names(( "swap",))
940a02
 
940a02
     def test_dep_checks_disabled(self):
940a02
         """Verify that disabling runtime dep checks works"""
940a02
diff --git a/tests/lvm_dbus_tests.py b/tests/lvm_dbus_tests.py
61580b
index 3fb7946a..ae26c6d2 100644
940a02
--- a/tests/lvm_dbus_tests.py
940a02
+++ b/tests/lvm_dbus_tests.py
61580b
@@ -50,6 +50,11 @@ class LVMTestCase(unittest.TestCase):
940a02
             else:
940a02
                 BlockDev.reinit([cls.ps, cls.ps2], True, None)
940a02
 
940a02
+        try:
940a02
+            cls.devices_avail = BlockDev.lvm_is_tech_avail(BlockDev.LVMTech.DEVICES, 0)
940a02
+        except:
940a02
+            cls.devices_avail = False
940a02
+
940a02
     @classmethod
940a02
     def _get_lvm_version(cls):
940a02
         _ret, out, _err = run_command("lvm version")
61580b
@@ -61,8 +66,7 @@ class LVMTestCase(unittest.TestCase):
940a02
 @unittest.skipUnless(lvm_dbus_running, "LVM DBus not running")
940a02
 class LvmNoDevTestCase(LVMTestCase):
940a02
 
940a02
-    def __init__(self, *args, **kwargs):
940a02
-        super(LvmNoDevTestCase, self).__init__(*args, **kwargs)
940a02
+    def setUp(self):
940a02
         self._log = ""
940a02
 
940a02
     @tag_test(TestTags.NOSTORAGE)
61580b
@@ -250,6 +254,45 @@ class LvmNoDevTestCase(LVMTestCase):
940a02
         succ = BlockDev.lvm_set_global_config(None)
940a02
         self.assertTrue(succ)
940a02
 
940a02
+    @tag_test(TestTags.NOSTORAGE)
940a02
+    def test_get_set_global_devices_filter(self):
940a02
+        """Verify that getting and setting LVM devices filter works as expected"""
940a02
+        if not self.devices_avail:
940a02
+            self.skipTest("skipping LVM devices filter test: not supported")
940a02
+
940a02
+        # setup logging
940a02
+        self.assertTrue(BlockDev.reinit([self.ps], False, self._store_log))
940a02
+
940a02
+        # no global config set initially
940a02
+        self.assertListEqual(BlockDev.lvm_get_devices_filter(), [])
940a02
+
940a02
+        # set and try to get back
940a02
+        succ = BlockDev.lvm_set_devices_filter(["/dev/sda"])
940a02
+        self.assertTrue(succ)
940a02
+        self.assertListEqual(BlockDev.lvm_get_devices_filter(), ["/dev/sda"])
940a02
+
940a02
+        # reset and try to get back
940a02
+        succ = BlockDev.lvm_set_devices_filter(None)
940a02
+        self.assertTrue(succ)
940a02
+        self.assertListEqual(BlockDev.lvm_get_devices_filter(), [])
940a02
+
940a02
+        # set twice and try to get back twice
940a02
+        succ = BlockDev.lvm_set_devices_filter(["/dev/sda"])
940a02
+        self.assertTrue(succ)
940a02
+        succ = BlockDev.lvm_set_devices_filter(["/dev/sdb"])
940a02
+        self.assertTrue(succ)
940a02
+        self.assertEqual(BlockDev.lvm_get_devices_filter(), ["/dev/sdb"])
940a02
+
940a02
+        # set something sane and check it's really used
940a02
+        succ = BlockDev.lvm_set_devices_filter(["/dev/sdb", "/dev/sdc"])
940a02
+        BlockDev.lvm_pvscan()
940a02
+        self.assertIn("'--devices'", self._log)
940a02
+        self.assertIn("'/dev/sdb,/dev/sdc'", self._log)
940a02
+
940a02
+        # reset back to default
940a02
+        succ = BlockDev.lvm_set_devices_filter(None)
940a02
+        self.assertTrue(succ)
940a02
+
940a02
     @tag_test(TestTags.NOSTORAGE)
940a02
     def test_cache_get_default_md_size(self):
940a02
         """Verify that default cache metadata size is calculated properly"""
940a02
diff --git a/tests/lvm_test.py b/tests/lvm_test.py
61580b
index 7be8f1ab..11d8c94e 100644
940a02
--- a/tests/lvm_test.py
940a02
+++ b/tests/lvm_test.py
61580b
@@ -39,10 +39,17 @@ class LVMTestCase(unittest.TestCase):
940a02
         ps.so_name = "libbd_lvm.so.2"
940a02
         cls.requested_plugins = [ps]
940a02
 
940a02
+        BlockDev.switch_init_checks(False)
940a02
         if not BlockDev.is_initialized():
940a02
             BlockDev.init(cls.requested_plugins, None)
940a02
         else:
940a02
             BlockDev.reinit(cls.requested_plugins, True, None)
940a02
+        BlockDev.switch_init_checks(True)
940a02
+
940a02
+        try:
940a02
+            cls.devices_avail = BlockDev.lvm_is_tech_avail(BlockDev.LVMTech.DEVICES, 0)
940a02
+        except:
940a02
+            cls.devices_avail = False
940a02
 
940a02
     @classmethod
940a02
     def _get_lvm_version(cls):
61580b
@@ -56,6 +63,8 @@ class LVMTestCase(unittest.TestCase):
940a02
 class LvmNoDevTestCase(LVMTestCase):
940a02
     def __init__(self, *args, **kwargs):
940a02
         super(LvmNoDevTestCase, self).__init__(*args, **kwargs)
940a02
+
940a02
+    def setUp(self):
940a02
         self._log = ""
940a02
 
940a02
     @tag_test(TestTags.NOSTORAGE)
61580b
@@ -236,6 +245,44 @@ class LvmNoDevTestCase(LVMTestCase):
940a02
         succ = BlockDev.lvm_set_global_config(None)
940a02
         self.assertTrue(succ)
940a02
 
940a02
+    @tag_test(TestTags.NOSTORAGE)
940a02
+    def test_get_set_global_devices_filter(self):
940a02
+        """Verify that getting and setting LVM devices filter works as expected"""
940a02
+        if not self.devices_avail:
940a02
+            self.skipTest("skipping LVM devices filter test: not supported")
940a02
+
940a02
+        # setup logging
940a02
+        self.assertTrue(BlockDev.reinit(self.requested_plugins, False, self._store_log))
940a02
+
940a02
+        # no global config set initially
940a02
+        self.assertListEqual(BlockDev.lvm_get_devices_filter(), [])
940a02
+
940a02
+        # set and try to get back
940a02
+        succ = BlockDev.lvm_set_devices_filter(["/dev/sda"])
940a02
+        self.assertTrue(succ)
940a02
+        self.assertListEqual(BlockDev.lvm_get_devices_filter(), ["/dev/sda"])
940a02
+
940a02
+        # reset and try to get back
940a02
+        succ = BlockDev.lvm_set_devices_filter(None)
940a02
+        self.assertTrue(succ)
940a02
+        self.assertListEqual(BlockDev.lvm_get_devices_filter(), [])
940a02
+
940a02
+        # set twice and try to get back twice
940a02
+        succ = BlockDev.lvm_set_devices_filter(["/dev/sda"])
940a02
+        self.assertTrue(succ)
940a02
+        succ = BlockDev.lvm_set_devices_filter(["/dev/sdb"])
940a02
+        self.assertTrue(succ)
940a02
+        self.assertEqual(BlockDev.lvm_get_devices_filter(), ["/dev/sdb"])
940a02
+
940a02
+        # set something sane and check it's really used
940a02
+        succ = BlockDev.lvm_set_devices_filter(["/dev/sdb", "/dev/sdc"])
940a02
+        BlockDev.lvm_lvs(None)
940a02
+        self.assertIn("--devices=/dev/sdb,/dev/sdc", self._log)
940a02
+
940a02
+        # reset back to default
940a02
+        succ = BlockDev.lvm_set_devices_filter(None)
940a02
+        self.assertTrue(succ)
940a02
+
940a02
     @tag_test(TestTags.NOSTORAGE)
940a02
     def test_cache_get_default_md_size(self):
940a02
         """Verify that default cache metadata size is calculated properly"""
61580b
@@ -1406,6 +1453,9 @@ class LvmPVVGcachedThpoolstatsTestCase(LvmPVVGLVTestCase):
940a02
 
940a02
 class LVMUnloadTest(LVMTestCase):
940a02
     def setUp(self):
940a02
+        if not self.devices_avail:
940a02
+            self.skipTest("skipping LVM unload test: missing some LVM dependencies")
940a02
+
940a02
         # make sure the library is initialized with all plugins loaded for other
940a02
         # tests
940a02
         self.addCleanup(BlockDev.reinit, self.requested_plugins, True, None)
940a02
diff --git a/tests/overrides_test.py b/tests/overrides_test.py
61580b
index 8e7f5a5a..d3faf3cf 100644
940a02
--- a/tests/overrides_test.py
940a02
+++ b/tests/overrides_test.py
940a02
@@ -15,10 +15,12 @@ class OverridesTest(unittest.TestCase):
940a02
 
940a02
     @classmethod
940a02
     def setUpClass(cls):
940a02
+        BlockDev.switch_init_checks(False)
940a02
         if not BlockDev.is_initialized():
940a02
             BlockDev.init(cls.requested_plugins, None)
940a02
         else:
940a02
             BlockDev.reinit(cls.requested_plugins, True, None)
940a02
+        BlockDev.switch_init_checks(True)
940a02
 
940a02
 class OverridesTestCase(OverridesTest):
940a02
     @tag_test(TestTags.NOSTORAGE, TestTags.CORE)
940a02
@@ -65,7 +67,20 @@ class OverridesTestCase(OverridesTest):
940a02
         self.assertEqual(BlockDev.lvm_get_thpool_padding(11 * 1024**2),
940a02
                          expected_padding)
940a02
 
940a02
-class OverridesUnloadTestCase(OverridesTest):
940a02
+class OverridesUnloadTestCase(unittest.TestCase):
940a02
+    # all plugins except for 'btrfs', 'fs' and 'mpath' -- these don't have all
940a02
+    # the dependencies on CentOS/Debian and we don't need them for this test
940a02
+    requested_plugins = BlockDev.plugin_specs_from_names(("crypto", "dm",
940a02
+                                                          "kbd", "loop",
940a02
+                                                          "mdraid", "part", "swap"))
940a02
+
940a02
+    @classmethod
940a02
+    def setUpClass(cls):
940a02
+        if not BlockDev.is_initialized():
940a02
+            BlockDev.init(cls.requested_plugins, None)
940a02
+        else:
940a02
+            BlockDev.reinit(cls.requested_plugins, True, None)
940a02
+
940a02
     def tearDown(self):
940a02
         # make sure the library is initialized with all plugins loaded for other
940a02
         # tests
940a02
@@ -80,7 +95,7 @@ class OverridesUnloadTestCase(OverridesTest):
940a02
 
940a02
         # no longer loaded
940a02
         with self.assertRaises(BlockDev.BlockDevNotImplementedError):
940a02
-            BlockDev.lvm.get_max_lv_size()
940a02
+            BlockDev.md.canonicalize_uuid("3386ff85:f5012621:4a435f06:1eb47236")
940a02
 
940a02
         # load the plugins back
940a02
         self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
940a02
@@ -92,9 +107,9 @@ class OverridesUnloadTestCase(OverridesTest):
940a02
 
940a02
         # the exception should be properly inherited from two classes
940a02
         with self.assertRaises(NotImplementedError):
940a02
-            BlockDev.lvm.get_max_lv_size()
940a02
+            BlockDev.md.canonicalize_uuid("3386ff85:f5012621:4a435f06:1eb47236")
940a02
         with self.assertRaises(BlockDev.BlockDevError):
940a02
-            BlockDev.lvm.get_max_lv_size()
940a02
+            BlockDev.md.canonicalize_uuid("3386ff85:f5012621:4a435f06:1eb47236")
940a02
 
940a02
         # load the plugins back
940a02
         self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
940a02
-- 
61580b
2.37.3
940a02
940a02
61580b
From 707de091b8848b95cc78faa4299119844aab4172 Mon Sep 17 00:00:00 2001
940a02
From: Vojtech Trefny <vtrefny@redhat.com>
940a02
Date: Tue, 13 Jul 2021 13:27:32 +0200
61580b
Subject: [PATCH 2/7] lvm: Add functions for managing LVM devices file
940a02
940a02
Currently covers only --adddev and --deldev from the lvmdevices
940a02
command.
940a02
---
940a02
 src/lib/plugin_apis/lvm.api         | 26 +++++++++++++++
940a02
 src/plugins/lvm-dbus.c              | 52 +++++++++++++++++++++++++++++
940a02
 src/plugins/lvm.c                   | 52 +++++++++++++++++++++++++++++
940a02
 src/plugins/lvm.h                   |  3 ++
940a02
 src/python/gi/overrides/BlockDev.py | 15 +++++++++
940a02
 tests/lvm_dbus_tests.py             | 37 +++++++++++++++++++-
940a02
 tests/lvm_test.py                   | 37 +++++++++++++++++++-
940a02
 7 files changed, 220 insertions(+), 2 deletions(-)
940a02
940a02
diff --git a/src/lib/plugin_apis/lvm.api b/src/lib/plugin_apis/lvm.api
61580b
index 23f68b81..b869afcc 100644
940a02
--- a/src/lib/plugin_apis/lvm.api
940a02
+++ b/src/lib/plugin_apis/lvm.api
940a02
@@ -1685,4 +1685,30 @@ GHashTable* bd_lvm_vdo_get_stats_full (const gchar *vg_name, const gchar *pool_n
940a02
  */
940a02
 BDLVMVDOStats* bd_lvm_vdo_get_stats (const gchar *vg_name, const gchar *pool_name, GError **error);
940a02
 
940a02
+/**
940a02
+ * bd_lvm_devices_add:
940a02
+ * @device: device (PV) to add to the devices file
940a02
+ * @devices_file: (allow-none): LVM devices file or %NULL for default
940a02
+ * @extra: (allow-none) (array zero-terminated=1): extra options for the lvmdevices command
940a02
+ * @error: (out): place to store error (if any)
940a02
+ *
940a02
+ * Returns: whether the @device was successfully added to @devices_file or not
940a02
+ *
940a02
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
940a02
+ */
940a02
+gboolean bd_lvm_devices_add (const gchar *device, const gchar *devices_file, const BDExtraArg **extra, GError **error);
940a02
+
940a02
+/**
940a02
+ * bd_lvm_devices_delete:
940a02
+ * @device: device (PV) to delete from the devices file
940a02
+ * @devices_file: (allow-none): LVM devices file or %NULL for default
940a02
+ * @extra: (allow-none) (array zero-terminated=1): extra options for the lvmdevices command
940a02
+ * @error: (out): place to store error (if any)
940a02
+ *
940a02
+ * Returns: whether the @device was successfully removed from @devices_file or not
940a02
+ *
940a02
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
940a02
+ */
940a02
+gboolean bd_lvm_devices_delete (const gchar *device, const gchar *devices_file, const BDExtraArg **extra, GError **error);
940a02
+
940a02
 #endif  /* BD_LVM_API */
940a02
diff --git a/src/plugins/lvm-dbus.c b/src/plugins/lvm-dbus.c
61580b
index b47ed0ef..86ca28ca 100644
940a02
--- a/src/plugins/lvm-dbus.c
940a02
+++ b/src/plugins/lvm-dbus.c
61580b
@@ -3950,3 +3950,55 @@ BDLVMVDOStats* bd_lvm_vdo_get_stats (const gchar *vg_name, const gchar *pool_nam
940a02
 
940a02
     return stats;
940a02
 }
940a02
+
940a02
+/**
940a02
+ * bd_lvm_devices_add:
940a02
+ * @device: device (PV) to add to the devices file
940a02
+ * @devices_file: (allow-none): LVM devices file or %NULL for default
940a02
+ * @extra: (allow-none) (array zero-terminated=1): extra options for the lvmdevices command
940a02
+ * @error: (out): place to store error (if any)
940a02
+ *
940a02
+ * Returns: whether the @device was successfully added to @devices_file or not
940a02
+ *
940a02
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
940a02
+ */
940a02
+gboolean bd_lvm_devices_add (const gchar *device, const gchar *devices_file, const BDExtraArg **extra, GError **error) {
940a02
+    const gchar *args[5] = {"lvmdevices", "--adddev", device, NULL, NULL};
940a02
+    g_autofree gchar *devfile = NULL;
940a02
+
940a02
+    if (!bd_lvm_is_tech_avail (BD_LVM_TECH_DEVICES, 0, error))
940a02
+        return FALSE;
940a02
+
940a02
+    if (devices_file) {
940a02
+        devfile = g_strdup_printf ("--devicesfile=%s", devices_file);
940a02
+        args[3] = devfile;
940a02
+    }
940a02
+
940a02
+    return bd_utils_exec_and_report_error (args, extra, error);
940a02
+}
940a02
+
940a02
+/**
940a02
+ * bd_lvm_devices_delete:
940a02
+ * @device: device (PV) to delete from the devices file
940a02
+ * @devices_file: (allow-none): LVM devices file or %NULL for default
940a02
+ * @extra: (allow-none) (array zero-terminated=1): extra options for the lvmdevices command
940a02
+ * @error: (out): place to store error (if any)
940a02
+ *
940a02
+ * Returns: whether the @device was successfully removed from @devices_file or not
940a02
+ *
940a02
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
940a02
+ */
940a02
+gboolean bd_lvm_devices_delete (const gchar *device, const gchar *devices_file, const BDExtraArg **extra, GError **error) {
940a02
+    const gchar *args[5] = {"lvmdevices", "--deldev", device, NULL, NULL};
940a02
+    g_autofree gchar *devfile = NULL;
940a02
+
940a02
+    if (!bd_lvm_is_tech_avail (BD_LVM_TECH_DEVICES, 0, error))
940a02
+        return FALSE;
940a02
+
940a02
+    if (devices_file) {
940a02
+        devfile = g_strdup_printf ("--devicesfile=%s", devices_file);
940a02
+        args[3] = devfile;
940a02
+    }
940a02
+
940a02
+    return bd_utils_exec_and_report_error (args, extra, error);
940a02
+}
940a02
diff --git a/src/plugins/lvm.c b/src/plugins/lvm.c
61580b
index 42ee0f90..3bd8fae1 100644
940a02
--- a/src/plugins/lvm.c
940a02
+++ b/src/plugins/lvm.c
61580b
@@ -3250,3 +3250,55 @@ BDLVMVDOStats* bd_lvm_vdo_get_stats (const gchar *vg_name, const gchar *pool_nam
940a02
 
940a02
     return stats;
940a02
 }
940a02
+
940a02
+/**
940a02
+ * bd_lvm_devices_add:
940a02
+ * @device: device (PV) to add to the devices file
940a02
+ * @devices_file: (allow-none): LVM devices file or %NULL for default
940a02
+ * @extra: (allow-none) (array zero-terminated=1): extra options for the lvmdevices command
940a02
+ * @error: (out): place to store error (if any)
940a02
+ *
940a02
+ * Returns: whether the @device was successfully added to @devices_file or not
940a02
+ *
940a02
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
940a02
+ */
940a02
+gboolean bd_lvm_devices_add (const gchar *device, const gchar *devices_file, const BDExtraArg **extra, GError **error) {
940a02
+    const gchar *args[5] = {"lvmdevices", "--adddev", device, NULL, NULL};
940a02
+    g_autofree gchar *devfile = NULL;
940a02
+
940a02
+    if (!bd_lvm_is_tech_avail (BD_LVM_TECH_DEVICES, 0, error))
940a02
+        return FALSE;
940a02
+
940a02
+    if (devices_file) {
940a02
+        devfile = g_strdup_printf ("--devicesfile=%s", devices_file);
940a02
+        args[3] = devfile;
940a02
+    }
940a02
+
940a02
+    return bd_utils_exec_and_report_error (args, extra, error);
940a02
+}
940a02
+
940a02
+/**
940a02
+ * bd_lvm_devices_delete:
940a02
+ * @device: device (PV) to delete from the devices file
940a02
+ * @devices_file: (allow-none): LVM devices file or %NULL for default
940a02
+ * @extra: (allow-none) (array zero-terminated=1): extra options for the lvmdevices command
940a02
+ * @error: (out): place to store error (if any)
940a02
+ *
940a02
+ * Returns: whether the @device was successfully removed from @devices_file or not
940a02
+ *
940a02
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
940a02
+ */
940a02
+gboolean bd_lvm_devices_delete (const gchar *device, const gchar *devices_file, const BDExtraArg **extra, GError **error) {
940a02
+    const gchar *args[5] = {"lvmdevices", "--deldev", device, NULL, NULL};
940a02
+    g_autofree gchar *devfile = NULL;
940a02
+
940a02
+    if (!bd_lvm_is_tech_avail (BD_LVM_TECH_DEVICES, 0, error))
940a02
+        return FALSE;
940a02
+
940a02
+    if (devices_file) {
940a02
+        devfile = g_strdup_printf ("--devicesfile=%s", devices_file);
940a02
+        args[3] = devfile;
940a02
+    }
940a02
+
940a02
+    return bd_utils_exec_and_report_error (args, extra, error);
940a02
+}
940a02
diff --git a/src/plugins/lvm.h b/src/plugins/lvm.h
61580b
index 8063693f..5ca2a9d7 100644
940a02
--- a/src/plugins/lvm.h
940a02
+++ b/src/plugins/lvm.h
940a02
@@ -333,4 +333,7 @@ BDLVMVDOWritePolicy bd_lvm_get_vdo_write_policy_from_str (const gchar *policy_st
940a02
 BDLVMVDOStats* bd_lvm_vdo_get_stats (const gchar *vg_name, const gchar *pool_name, GError **error);
940a02
 GHashTable* bd_lvm_vdo_get_stats_full (const gchar *vg_name, const gchar *pool_name, GError **error);
940a02
 
940a02
+gboolean bd_lvm_devices_add (const gchar *device, const gchar *devices_file, const BDExtraArg **extra, GError **error);
940a02
+gboolean bd_lvm_devices_delete (const gchar *device, const gchar *devices_file, const BDExtraArg **extra, GError **error);
940a02
+
940a02
 #endif /* BD_LVM */
940a02
diff --git a/src/python/gi/overrides/BlockDev.py b/src/python/gi/overrides/BlockDev.py
61580b
index ea059060..8574ab04 100644
940a02
--- a/src/python/gi/overrides/BlockDev.py
940a02
+++ b/src/python/gi/overrides/BlockDev.py
940a02
@@ -724,6 +724,21 @@ def lvm_vdo_pool_convert(vg_name, lv_name, pool_name, virtual_size, index_memory
940a02
     return _lvm_vdo_pool_convert(vg_name, lv_name, pool_name, virtual_size, index_memory, compression, deduplication, write_policy, extra)
940a02
 __all__.append("lvm_vdo_pool_convert")
940a02
 
940a02
+_lvm_devices_add = BlockDev.lvm_devices_add
940a02
+@override(BlockDev.lvm_devices_add)
940a02
+def lvm_devices_add(device, devices_file=None, extra=None, **kwargs):
940a02
+    extra = _get_extra(extra, kwargs)
940a02
+    return _lvm_devices_add(device, devices_file, extra)
940a02
+__all__.append("lvm_devices_add")
940a02
+
940a02
+_lvm_devices_delete = BlockDev.lvm_devices_delete
940a02
+@override(BlockDev.lvm_devices_delete)
940a02
+def lvm_devices_delete(device, devices_file=None, extra=None, **kwargs):
940a02
+    extra = _get_extra(extra, kwargs)
940a02
+    return _lvm_devices_delete(device, devices_file, extra)
940a02
+__all__.append("lvm_devices_delete")
940a02
+
940a02
+
940a02
 _md_get_superblock_size = BlockDev.md_get_superblock_size
940a02
 @override(BlockDev.md_get_superblock_size)
940a02
 def md_get_superblock_size(size, version=None):
940a02
diff --git a/tests/lvm_dbus_tests.py b/tests/lvm_dbus_tests.py
61580b
index ae26c6d2..82e4761d 100644
940a02
--- a/tests/lvm_dbus_tests.py
940a02
+++ b/tests/lvm_dbus_tests.py
61580b
@@ -12,7 +12,7 @@ from contextlib import contextmanager
940a02
 from distutils.version import LooseVersion
940a02
 from itertools import chain
940a02
 
940a02
-from utils import create_sparse_tempfile, create_lio_device, delete_lio_device, run_command, TestTags, tag_test
940a02
+from utils import create_sparse_tempfile, create_lio_device, delete_lio_device, run_command, TestTags, tag_test, read_file
940a02
 from gi.repository import BlockDev, GLib
940a02
 
940a02
 import dbus
61580b
@@ -1785,3 +1785,38 @@ class LvmConfigTestPvremove(LvmPVonlyTestCase):
61580b
         BlockDev.lvm_set_global_config("")
61580b
         succ = BlockDev.lvm_pvremove(self.loop_dev)
61580b
         self.assertTrue(succ)
940a02
+
940a02
+
940a02
+class LvmTestDevicesFile(LvmPVonlyTestCase):
940a02
+    devicefile = "bd_lvm_dbus_tests.devices"
940a02
+
940a02
+    @classmethod
940a02
+    def tearDownClass(cls):
940a02
+        shutil.rmtree("/etc/lvm/devices/" + cls.devicefile, ignore_errors=True)
940a02
+
940a02
+        super(LvmTestDevicesFile, cls).tearDownClass()
940a02
+
940a02
+    def test_devices_add_delete(self):
940a02
+        if not self.devices_avail:
940a02
+            self.skipTest("skipping LVM devices file test: not supported")
940a02
+
940a02
+        succ = BlockDev.lvm_pvcreate(self.loop_dev)
940a02
+        self.assertTrue(succ)
940a02
+
940a02
+        with self.assertRaises(GLib.GError):
940a02
+            BlockDev.lvm_devices_add("/non/existing/device", self.devicefile)
940a02
+
940a02
+        with self.assertRaises(GLib.GError):
940a02
+            BlockDev.lvm_devices_delete(self.loop_dev, self.devicefile)
940a02
+
940a02
+        succ = BlockDev.lvm_devices_add(self.loop_dev, self.devicefile)
940a02
+        self.assertTrue(succ)
940a02
+
940a02
+        dfile = read_file("/etc/lvm/devices/" + self.devicefile)
940a02
+        self.assertIn(self.loop_dev, dfile)
940a02
+
940a02
+        succ = BlockDev.lvm_devices_delete(self.loop_dev, self.devicefile)
940a02
+        self.assertTrue(succ)
940a02
+
940a02
+        dfile = read_file("/etc/lvm/devices/" + self.devicefile)
940a02
+        self.assertNotIn(self.loop_dev, dfile)
940a02
diff --git a/tests/lvm_test.py b/tests/lvm_test.py
61580b
index 11d8c94e..6ddeaa6a 100644
940a02
--- a/tests/lvm_test.py
940a02
+++ b/tests/lvm_test.py
61580b
@@ -11,7 +11,7 @@ import time
61580b
 from contextlib import contextmanager
940a02
 from distutils.version import LooseVersion
940a02
 
940a02
-from utils import create_sparse_tempfile, create_lio_device, delete_lio_device, fake_utils, fake_path, TestTags, tag_test, run_command
940a02
+from utils import create_sparse_tempfile, create_lio_device, delete_lio_device, fake_utils, fake_path, TestTags, tag_test, run_command, read_file
940a02
 from gi.repository import BlockDev, GLib
940a02
 
940a02
 
61580b
@@ -1765,3 +1765,38 @@ class LvmConfigTestPvremove(LvmPVonlyTestCase):
61580b
         BlockDev.lvm_set_global_config("")
61580b
         succ = BlockDev.lvm_pvremove(self.loop_dev)
61580b
         self.assertTrue(succ)
940a02
+
940a02
+
940a02
+class LvmTestDevicesFile(LvmPVonlyTestCase):
940a02
+    devicefile = "bd_lvm_test.devices"
940a02
+
940a02
+    @classmethod
940a02
+    def tearDownClass(cls):
940a02
+        shutil.rmtree("/etc/lvm/devices/" + cls.devicefile, ignore_errors=True)
940a02
+
940a02
+        super(LvmTestDevicesFile, cls).tearDownClass()
940a02
+
940a02
+    def test_devices_add_delete(self):
940a02
+        if not self.devices_avail:
940a02
+            self.skipTest("skipping LVM devices file test: not supported")
940a02
+
940a02
+        succ = BlockDev.lvm_pvcreate(self.loop_dev)
940a02
+        self.assertTrue(succ)
940a02
+
940a02
+        with self.assertRaises(GLib.GError):
940a02
+            BlockDev.lvm_devices_add("/non/existing/device", self.devicefile)
940a02
+
940a02
+        with self.assertRaises(GLib.GError):
940a02
+            BlockDev.lvm_devices_delete(self.loop_dev, self.devicefile)
940a02
+
940a02
+        succ = BlockDev.lvm_devices_add(self.loop_dev, self.devicefile)
940a02
+        self.assertTrue(succ)
940a02
+
940a02
+        dfile = read_file("/etc/lvm/devices/" + self.devicefile)
940a02
+        self.assertIn(self.loop_dev, dfile)
940a02
+
940a02
+        succ = BlockDev.lvm_devices_delete(self.loop_dev, self.devicefile)
940a02
+        self.assertTrue(succ)
940a02
+
940a02
+        dfile = read_file("/etc/lvm/devices/" + self.devicefile)
940a02
+        self.assertNotIn(self.loop_dev, dfile)
940a02
-- 
61580b
2.37.3
940a02
940a02
61580b
From 4c832576df8918c269db8fe2cb7eb74e45628d6c Mon Sep 17 00:00:00 2001
940a02
From: Vojtech Trefny <vtrefny@redhat.com>
940a02
Date: Fri, 15 Oct 2021 13:18:54 +0200
61580b
Subject: [PATCH 3/7] lvm: Report special error when system.devices file is not
940a02
 enabled
940a02
940a02
This can be disabled either in LVM by a compile time option or
940a02
by a lvm.conf option so we should report a specific error for this
940a02
case so users can distinguish between the feature not being enabled
940a02
and not being supported at all.
940a02
---
940a02
 src/lib/plugin_apis/lvm.api |  1 +
940a02
 src/plugins/lvm-dbus.c      | 70 +++++++++++++++++++++++++++++++++++++
940a02
 src/plugins/lvm.c           | 60 +++++++++++++++++++++++++++++++
940a02
 src/plugins/lvm.h           |  1 +
940a02
 tests/lvm_dbus_tests.py     | 15 ++++++++
940a02
 tests/lvm_test.py           | 15 ++++++++
940a02
 6 files changed, 162 insertions(+)
940a02
940a02
diff --git a/src/lib/plugin_apis/lvm.api b/src/lib/plugin_apis/lvm.api
61580b
index b869afcc..b8cde70b 100644
940a02
--- a/src/lib/plugin_apis/lvm.api
940a02
+++ b/src/lib/plugin_apis/lvm.api
940a02
@@ -44,6 +44,7 @@ typedef enum {
940a02
     BD_LVM_ERROR_FAIL,
940a02
     BD_LVM_ERROR_NOT_SUPPORTED,
940a02
     BD_LVM_ERROR_VDO_POLICY_INVAL,
940a02
+    BD_LVM_ERROR_DEVICES_DISABLED,
940a02
 } BDLVMError;
940a02
 
940a02
 typedef enum {
940a02
diff --git a/src/plugins/lvm-dbus.c b/src/plugins/lvm-dbus.c
61580b
index 86ca28ca..7f48e422 100644
940a02
--- a/src/plugins/lvm-dbus.c
940a02
+++ b/src/plugins/lvm-dbus.c
61580b
@@ -3951,6 +3951,64 @@ BDLVMVDOStats* bd_lvm_vdo_get_stats (const gchar *vg_name, const gchar *pool_nam
940a02
     return stats;
940a02
 }
940a02
 
940a02
+/* check whether the LVM devices file is enabled by LVM
940a02
+ * we use the existence of the "lvmdevices" command to check whether the feature is available
940a02
+ * or not, but this can still be disabled either in LVM or in lvm.conf
940a02
+ */
940a02
+static gboolean _lvm_devices_enabled () {
940a02
+    const gchar *args[6] = {"lvmconfig", "--typeconfig", NULL, "devices/use_devicesfile", NULL, NULL};
940a02
+    gboolean ret = FALSE;
940a02
+    GError *loc_error = NULL;
940a02
+    gchar *output = NULL;
940a02
+    gboolean enabled = FALSE;
940a02
+    gint scanned = 0;
940a02
+    g_autofree gchar *config_arg = NULL;
940a02
+
940a02
+    /* try current config first -- if we get something from this it means the feature is
940a02
+       explicitly enabled or disabled by system lvm.conf or using the --config option */
940a02
+    args[2] = "current";
940a02
+
940a02
+    /* make sure to include the global config from us when getting the current config value */
940a02
+    g_mutex_lock (&global_config_lock);
940a02
+    if (global_config_str) {
940a02
+        config_arg = g_strdup_printf ("--config=%s", global_config_str);
940a02
+        args[4] = config_arg;
940a02
+    }
940a02
+
940a02
+    ret = bd_utils_exec_and_capture_output (args, NULL, &output, &loc_error);
940a02
+    g_mutex_unlock (&global_config_lock);
940a02
+    if (ret) {
940a02
+        scanned = sscanf (output, "use_devicesfile=%u", &enabled);
940a02
+        g_free (output);
940a02
+        if (scanned != 1)
940a02
+            return FALSE;
940a02
+
940a02
+        return enabled;
940a02
+    } else {
940a02
+        g_clear_error (&loc_error);
940a02
+        g_free (output);
940a02
+    }
940a02
+
940a02
+    output = NULL;
940a02
+
940a02
+    /* now try default */
940a02
+    args[2] = "default";
940a02
+    ret = bd_utils_exec_and_capture_output (args, NULL, &output, &loc_error);
940a02
+    if (ret) {
940a02
+        scanned = sscanf (output, "# use_devicesfile=%u", &enabled);
940a02
+        g_free (output);
940a02
+        if (scanned != 1)
940a02
+            return FALSE;
940a02
+
940a02
+        return enabled;
940a02
+    } else {
940a02
+        g_clear_error (&loc_error);
940a02
+        g_free (output);
940a02
+    }
940a02
+
940a02
+    return FALSE;
940a02
+}
940a02
+
940a02
 /**
940a02
  * bd_lvm_devices_add:
940a02
  * @device: device (PV) to add to the devices file
61580b
@@ -3969,6 +4027,12 @@ gboolean bd_lvm_devices_add (const gchar *device, const gchar *devices_file, con
940a02
     if (!bd_lvm_is_tech_avail (BD_LVM_TECH_DEVICES, 0, error))
940a02
         return FALSE;
940a02
 
940a02
+    if (!_lvm_devices_enabled ()) {
940a02
+        g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_DEVICES_DISABLED,
940a02
+                     "LVM devices file not enabled.");
940a02
+        return FALSE;
940a02
+    }
940a02
+
940a02
     if (devices_file) {
940a02
         devfile = g_strdup_printf ("--devicesfile=%s", devices_file);
940a02
         args[3] = devfile;
61580b
@@ -3995,6 +4059,12 @@ gboolean bd_lvm_devices_delete (const gchar *device, const gchar *devices_file,
940a02
     if (!bd_lvm_is_tech_avail (BD_LVM_TECH_DEVICES, 0, error))
940a02
         return FALSE;
940a02
 
940a02
+    if (!_lvm_devices_enabled ()) {
940a02
+        g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_DEVICES_DISABLED,
940a02
+                     "LVM devices file not enabled.");
940a02
+        return FALSE;
940a02
+    }
940a02
+
940a02
     if (devices_file) {
940a02
         devfile = g_strdup_printf ("--devicesfile=%s", devices_file);
940a02
         args[3] = devfile;
940a02
diff --git a/src/plugins/lvm.c b/src/plugins/lvm.c
61580b
index 3bd8fae1..73d5005f 100644
940a02
--- a/src/plugins/lvm.c
940a02
+++ b/src/plugins/lvm.c
61580b
@@ -3251,6 +3251,54 @@ BDLVMVDOStats* bd_lvm_vdo_get_stats (const gchar *vg_name, const gchar *pool_nam
940a02
     return stats;
940a02
 }
940a02
 
940a02
+/* check whether the LVM devices file is enabled by LVM
940a02
+ * we use the existence of the "lvmdevices" command to check whether the feature is available
940a02
+ * or not, but this can still be disabled either in LVM or in lvm.conf
940a02
+ */
940a02
+static gboolean _lvm_devices_enabled () {
940a02
+    const gchar *args[5] = {"config", "--typeconfig", NULL, "devices/use_devicesfile", NULL};
940a02
+    gboolean ret = FALSE;
940a02
+    GError *loc_error = NULL;
940a02
+    gchar *output = NULL;
940a02
+    gboolean enabled = FALSE;
940a02
+    gint scanned = 0;
940a02
+
940a02
+    /* try current config first -- if we get something from this it means the feature is
940a02
+       explicitly enabled or disabled by system lvm.conf or using the --config option */
940a02
+    args[2] = "current";
940a02
+    ret = call_lvm_and_capture_output (args, NULL, &output, &loc_error);
940a02
+    if (ret) {
940a02
+        scanned = sscanf (output, "use_devicesfile=%u", &enabled);
940a02
+        g_free (output);
940a02
+        if (scanned != 1)
940a02
+            return FALSE;
940a02
+
940a02
+        return enabled;
940a02
+    } else {
940a02
+        g_clear_error (&loc_error);
940a02
+        g_free (output);
940a02
+    }
940a02
+
940a02
+    output = NULL;
940a02
+
940a02
+    /* now try default */
940a02
+    args[2] = "default";
940a02
+    ret = call_lvm_and_capture_output (args, NULL, &output, &loc_error);
940a02
+    if (ret) {
940a02
+        scanned = sscanf (output, "# use_devicesfile=%u", &enabled);
940a02
+        g_free (output);
940a02
+        if (scanned != 1)
940a02
+            return FALSE;
940a02
+
940a02
+        return enabled;
940a02
+    } else {
940a02
+        g_clear_error (&loc_error);
940a02
+        g_free (output);
940a02
+    }
940a02
+
940a02
+    return FALSE;
940a02
+}
940a02
+
940a02
 /**
940a02
  * bd_lvm_devices_add:
940a02
  * @device: device (PV) to add to the devices file
61580b
@@ -3269,6 +3317,12 @@ gboolean bd_lvm_devices_add (const gchar *device, const gchar *devices_file, con
940a02
     if (!bd_lvm_is_tech_avail (BD_LVM_TECH_DEVICES, 0, error))
940a02
         return FALSE;
940a02
 
940a02
+    if (!_lvm_devices_enabled ()) {
940a02
+        g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_DEVICES_DISABLED,
940a02
+                     "LVM devices file not enabled.");
940a02
+        return FALSE;
940a02
+    }
940a02
+
940a02
     if (devices_file) {
940a02
         devfile = g_strdup_printf ("--devicesfile=%s", devices_file);
940a02
         args[3] = devfile;
61580b
@@ -3295,6 +3349,12 @@ gboolean bd_lvm_devices_delete (const gchar *device, const gchar *devices_file,
940a02
     if (!bd_lvm_is_tech_avail (BD_LVM_TECH_DEVICES, 0, error))
940a02
         return FALSE;
940a02
 
940a02
+    if (!_lvm_devices_enabled ()) {
940a02
+        g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_DEVICES_DISABLED,
940a02
+                     "LVM devices file not enabled.");
940a02
+        return FALSE;
940a02
+    }
940a02
+
940a02
     if (devices_file) {
940a02
         devfile = g_strdup_printf ("--devicesfile=%s", devices_file);
940a02
         args[3] = devfile;
940a02
diff --git a/src/plugins/lvm.h b/src/plugins/lvm.h
61580b
index 5ca2a9d7..fabf091f 100644
940a02
--- a/src/plugins/lvm.h
940a02
+++ b/src/plugins/lvm.h
940a02
@@ -53,6 +53,7 @@ typedef enum {
940a02
     BD_LVM_ERROR_FAIL,
940a02
     BD_LVM_ERROR_NOT_SUPPORTED,
940a02
     BD_LVM_ERROR_VDO_POLICY_INVAL,
940a02
+    BD_LVM_ERROR_DEVICES_DISABLED,
940a02
 } BDLVMError;
940a02
 
940a02
 typedef enum {
940a02
diff --git a/tests/lvm_dbus_tests.py b/tests/lvm_dbus_tests.py
61580b
index 82e4761d..792c1cc8 100644
940a02
--- a/tests/lvm_dbus_tests.py
940a02
+++ b/tests/lvm_dbus_tests.py
61580b
@@ -1820,3 +1820,18 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
940a02
 
940a02
         dfile = read_file("/etc/lvm/devices/" + self.devicefile)
940a02
         self.assertNotIn(self.loop_dev, dfile)
940a02
+
940a02
+    def test_devices_enabled(self):
940a02
+        if not self.devices_avail:
940a02
+            self.skipTest("skipping LVM devices file test: not supported")
940a02
+
940a02
+        self.addCleanup(BlockDev.lvm_set_global_config, "")
940a02
+
940a02
+        # checking if the feature is enabled or disabled is hard so lets just disable
940a02
+        # the devices file using the global config and check lvm_devices_add fails
940a02
+        # with the correct exception message
940a02
+        succ = BlockDev.lvm_set_global_config("devices { use_devicesfile=0 }")
940a02
+        self.assertTrue(succ)
940a02
+
940a02
+        with self.assertRaisesRegex(GLib.GError, "LVM devices file not enabled."):
940a02
+            BlockDev.lvm_devices_add("", self.devicefile)
940a02
diff --git a/tests/lvm_test.py b/tests/lvm_test.py
61580b
index 6ddeaa6a..73fb1030 100644
940a02
--- a/tests/lvm_test.py
940a02
+++ b/tests/lvm_test.py
61580b
@@ -1800,3 +1800,18 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
940a02
 
940a02
         dfile = read_file("/etc/lvm/devices/" + self.devicefile)
940a02
         self.assertNotIn(self.loop_dev, dfile)
940a02
+
940a02
+    def test_devices_enabled(self):
940a02
+        if not self.devices_avail:
940a02
+            self.skipTest("skipping LVM devices file test: not supported")
940a02
+
940a02
+        self.addCleanup(BlockDev.lvm_set_global_config, "")
940a02
+
940a02
+        # checking if the feature is enabled or disabled is hard so lets just disable
940a02
+        # the devices file using the global config and check lvm_devices_add fails
940a02
+        # with the correct exception message
940a02
+        succ = BlockDev.lvm_set_global_config("devices { use_devicesfile=0 }")
940a02
+        self.assertTrue(succ)
940a02
+
940a02
+        with self.assertRaisesRegex(GLib.GError, "LVM devices file not enabled."):
940a02
+            BlockDev.lvm_devices_add("", self.devicefile)
940a02
-- 
61580b
2.37.3
940a02
940a02
61580b
From 2fdec5f7e42de869d4b2ec80dce597d22dd57617 Mon Sep 17 00:00:00 2001
940a02
From: Vojtech Trefny <vtrefny@redhat.com>
940a02
Date: Fri, 15 Oct 2021 14:21:03 +0200
61580b
Subject: [PATCH 4/7] lvm: Force enable LVM devices file for LvmTestDevicesFile
940a02
940a02
This feauture might be disabled in lvm.conf so to be able to test
940a02
it we need to override this. The correct handling of the disabled
940a02
state is checked in a separate test case.
940a02
---
940a02
 tests/lvm_dbus_tests.py | 8 ++++++++
940a02
 tests/lvm_test.py       | 8 ++++++++
940a02
 2 files changed, 16 insertions(+)
940a02
940a02
diff --git a/tests/lvm_dbus_tests.py b/tests/lvm_dbus_tests.py
61580b
index 792c1cc8..e55535cc 100644
940a02
--- a/tests/lvm_dbus_tests.py
940a02
+++ b/tests/lvm_dbus_tests.py
61580b
@@ -1800,6 +1800,12 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
940a02
         if not self.devices_avail:
940a02
             self.skipTest("skipping LVM devices file test: not supported")
940a02
 
940a02
+        self.addCleanup(BlockDev.lvm_set_global_config, "")
940a02
+
940a02
+        # force-enable the feature, it might be disabled by default
940a02
+        succ = BlockDev.lvm_set_global_config("devices { use_devicesfile=1 }")
940a02
+        self.assertTrue(succ)
940a02
+
940a02
         succ = BlockDev.lvm_pvcreate(self.loop_dev)
940a02
         self.assertTrue(succ)
940a02
 
61580b
@@ -1821,6 +1827,8 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
940a02
         dfile = read_file("/etc/lvm/devices/" + self.devicefile)
940a02
         self.assertNotIn(self.loop_dev, dfile)
940a02
 
940a02
+        BlockDev.lvm_set_global_config("")
940a02
+
940a02
     def test_devices_enabled(self):
940a02
         if not self.devices_avail:
940a02
             self.skipTest("skipping LVM devices file test: not supported")
940a02
diff --git a/tests/lvm_test.py b/tests/lvm_test.py
61580b
index 73fb1030..907b4f59 100644
940a02
--- a/tests/lvm_test.py
940a02
+++ b/tests/lvm_test.py
61580b
@@ -1780,6 +1780,12 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
940a02
         if not self.devices_avail:
940a02
             self.skipTest("skipping LVM devices file test: not supported")
940a02
 
940a02
+        self.addCleanup(BlockDev.lvm_set_global_config, "")
940a02
+
940a02
+        # force-enable the feature, it might be disabled by default
940a02
+        succ = BlockDev.lvm_set_global_config("devices { use_devicesfile=1 }")
940a02
+        self.assertTrue(succ)
940a02
+
940a02
         succ = BlockDev.lvm_pvcreate(self.loop_dev)
940a02
         self.assertTrue(succ)
940a02
 
61580b
@@ -1801,6 +1807,8 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
940a02
         dfile = read_file("/etc/lvm/devices/" + self.devicefile)
940a02
         self.assertNotIn(self.loop_dev, dfile)
940a02
 
940a02
+        BlockDev.lvm_set_global_config("")
940a02
+
940a02
     def test_devices_enabled(self):
940a02
         if not self.devices_avail:
940a02
             self.skipTest("skipping LVM devices file test: not supported")
940a02
-- 
61580b
2.37.3
940a02
940a02
61580b
From 1809a41c0b2b99c8d6a077b5aa70834686980181 Mon Sep 17 00:00:00 2001
940a02
From: Vojtech Trefny <vtrefny@redhat.com>
940a02
Date: Fri, 12 Nov 2021 14:51:39 +0100
61580b
Subject: [PATCH 5/7] tests: Fix resetting global LVM config after LVM devices
940a02
 file test
940a02
940a02
We need to set the config to None/NULL not to an empty string.
940a02
---
940a02
 tests/lvm_dbus_tests.py | 6 +++---
940a02
 tests/lvm_test.py       | 6 +++---
940a02
 2 files changed, 6 insertions(+), 6 deletions(-)
940a02
940a02
diff --git a/tests/lvm_dbus_tests.py b/tests/lvm_dbus_tests.py
61580b
index e55535cc..8ae670d5 100644
940a02
--- a/tests/lvm_dbus_tests.py
940a02
+++ b/tests/lvm_dbus_tests.py
61580b
@@ -1800,7 +1800,7 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
940a02
         if not self.devices_avail:
940a02
             self.skipTest("skipping LVM devices file test: not supported")
940a02
 
940a02
-        self.addCleanup(BlockDev.lvm_set_global_config, "")
940a02
+        self.addCleanup(BlockDev.lvm_set_global_config, None)
940a02
 
940a02
         # force-enable the feature, it might be disabled by default
940a02
         succ = BlockDev.lvm_set_global_config("devices { use_devicesfile=1 }")
61580b
@@ -1827,13 +1827,13 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
940a02
         dfile = read_file("/etc/lvm/devices/" + self.devicefile)
940a02
         self.assertNotIn(self.loop_dev, dfile)
940a02
 
940a02
-        BlockDev.lvm_set_global_config("")
940a02
+        BlockDev.lvm_set_global_config(None)
940a02
 
940a02
     def test_devices_enabled(self):
940a02
         if not self.devices_avail:
940a02
             self.skipTest("skipping LVM devices file test: not supported")
940a02
 
940a02
-        self.addCleanup(BlockDev.lvm_set_global_config, "")
940a02
+        self.addCleanup(BlockDev.lvm_set_global_config, None)
940a02
 
940a02
         # checking if the feature is enabled or disabled is hard so lets just disable
940a02
         # the devices file using the global config and check lvm_devices_add fails
940a02
diff --git a/tests/lvm_test.py b/tests/lvm_test.py
61580b
index 907b4f59..095e4bac 100644
940a02
--- a/tests/lvm_test.py
940a02
+++ b/tests/lvm_test.py
61580b
@@ -1780,7 +1780,7 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
940a02
         if not self.devices_avail:
940a02
             self.skipTest("skipping LVM devices file test: not supported")
940a02
 
940a02
-        self.addCleanup(BlockDev.lvm_set_global_config, "")
940a02
+        self.addCleanup(BlockDev.lvm_set_global_config, None)
940a02
 
940a02
         # force-enable the feature, it might be disabled by default
940a02
         succ = BlockDev.lvm_set_global_config("devices { use_devicesfile=1 }")
61580b
@@ -1807,13 +1807,13 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
940a02
         dfile = read_file("/etc/lvm/devices/" + self.devicefile)
940a02
         self.assertNotIn(self.loop_dev, dfile)
940a02
 
940a02
-        BlockDev.lvm_set_global_config("")
940a02
+        BlockDev.lvm_set_global_config(None)
940a02
 
940a02
     def test_devices_enabled(self):
940a02
         if not self.devices_avail:
940a02
             self.skipTest("skipping LVM devices file test: not supported")
940a02
 
940a02
-        self.addCleanup(BlockDev.lvm_set_global_config, "")
940a02
+        self.addCleanup(BlockDev.lvm_set_global_config, None)
940a02
 
940a02
         # checking if the feature is enabled or disabled is hard so lets just disable
940a02
         # the devices file using the global config and check lvm_devices_add fails
940a02
-- 
61580b
2.37.3
940a02
940a02
61580b
From 1c2f1d20a3cfa522b78ab007e8e4f9a5a4bb579d Mon Sep 17 00:00:00 2001
940a02
From: Vojtech Trefny <vtrefny@redhat.com>
940a02
Date: Fri, 12 Nov 2021 15:10:45 +0100
61580b
Subject: [PATCH 6/7] lvm: Do not set global config to and empty string
940a02
940a02
If we set it to an empty string we end up running "--config"
940a02
without a parameter and lvm will use whatever is next parameter
940a02
like the device path for pvremove.
940a02
---
940a02
 tests/lvm_dbus_tests.py | 12 ++++++++++++
940a02
 tests/lvm_test.py       | 12 ++++++++++++
61580b
 2 files changed, 24 insertions(+)
940a02
940a02
diff --git a/tests/lvm_dbus_tests.py b/tests/lvm_dbus_tests.py
61580b
index 8ae670d5..61c898c1 100644
940a02
--- a/tests/lvm_dbus_tests.py
940a02
+++ b/tests/lvm_dbus_tests.py
61580b
@@ -1843,3 +1843,15 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
940a02
 
940a02
         with self.assertRaisesRegex(GLib.GError, "LVM devices file not enabled."):
940a02
             BlockDev.lvm_devices_add("", self.devicefile)
940a02
+
940a02
+
940a02
+class LvmConfigTestPvremove(LvmPVonlyTestCase):
940a02
+
940a02
+    @tag_test(TestTags.REGRESSION)
940a02
+    def test_set_empty_config(self):
940a02
+        succ = BlockDev.lvm_pvcreate(self.loop_dev)
940a02
+        self.assertTrue(succ)
940a02
+
940a02
+        BlockDev.lvm_set_global_config("")
940a02
+        succ = BlockDev.lvm_pvremove(self.loop_dev)
940a02
+        self.assertTrue(succ)
940a02
diff --git a/tests/lvm_test.py b/tests/lvm_test.py
61580b
index 095e4bac..36ff10ec 100644
940a02
--- a/tests/lvm_test.py
940a02
+++ b/tests/lvm_test.py
61580b
@@ -1823,3 +1823,15 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
940a02
 
940a02
         with self.assertRaisesRegex(GLib.GError, "LVM devices file not enabled."):
940a02
             BlockDev.lvm_devices_add("", self.devicefile)
940a02
+
940a02
+
940a02
+class LvmConfigTestPvremove(LvmPVonlyTestCase):
940a02
+
940a02
+    @tag_test(TestTags.REGRESSION)
940a02
+    def test_set_empty_config(self):
940a02
+        succ = BlockDev.lvm_pvcreate(self.loop_dev)
940a02
+        self.assertTrue(succ)
940a02
+
940a02
+        BlockDev.lvm_set_global_config("")
940a02
+        succ = BlockDev.lvm_pvremove(self.loop_dev)
940a02
+        self.assertTrue(succ)
940a02
-- 
61580b
2.37.3
940a02
940a02
61580b
From 05cfb84777c5472550673a1f2150ca357718b3f2 Mon Sep 17 00:00:00 2001
940a02
From: Vojtech Trefny <vtrefny@redhat.com>
940a02
Date: Fri, 26 Nov 2021 15:19:55 +0100
61580b
Subject: [PATCH 7/7] lvm: Use "lvmconfig full" to get valid config instead of
940a02
 "current"
940a02
940a02
"lvmconfig current" doesn't work together with --config even if we
940a02
don't override the "use_devicefile" key. "lvmconfig full" seems to
940a02
be working in all cases.
940a02
---
940a02
 src/plugins/lvm-dbus.c | 4 ++--
940a02
 src/plugins/lvm.c      | 4 ++--
940a02
 2 files changed, 4 insertions(+), 4 deletions(-)
940a02
940a02
diff --git a/src/plugins/lvm-dbus.c b/src/plugins/lvm-dbus.c
61580b
index 7f48e422..d4b542e2 100644
940a02
--- a/src/plugins/lvm-dbus.c
940a02
+++ b/src/plugins/lvm-dbus.c
61580b
@@ -3964,9 +3964,9 @@ static gboolean _lvm_devices_enabled () {
940a02
     gint scanned = 0;
940a02
     g_autofree gchar *config_arg = NULL;
940a02
 
940a02
-    /* try current config first -- if we get something from this it means the feature is
940a02
+    /* try full config first -- if we get something from this it means the feature is
940a02
        explicitly enabled or disabled by system lvm.conf or using the --config option */
940a02
-    args[2] = "current";
940a02
+    args[2] = "full";
940a02
 
940a02
     /* make sure to include the global config from us when getting the current config value */
940a02
     g_mutex_lock (&global_config_lock);
940a02
diff --git a/src/plugins/lvm.c b/src/plugins/lvm.c
61580b
index 73d5005f..03211f8a 100644
940a02
--- a/src/plugins/lvm.c
940a02
+++ b/src/plugins/lvm.c
61580b
@@ -3263,9 +3263,9 @@ static gboolean _lvm_devices_enabled () {
940a02
     gboolean enabled = FALSE;
940a02
     gint scanned = 0;
940a02
 
940a02
-    /* try current config first -- if we get something from this it means the feature is
940a02
+    /* try full config first -- if we get something from this it means the feature is
940a02
        explicitly enabled or disabled by system lvm.conf or using the --config option */
940a02
-    args[2] = "current";
940a02
+    args[2] = "full";
940a02
     ret = call_lvm_and_capture_output (args, NULL, &output, &loc_error);
940a02
     if (ret) {
940a02
         scanned = sscanf (output, "use_devicesfile=%u", &enabled);
940a02
-- 
61580b
2.37.3
940a02