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