Skip to content

Commit b80948c

Browse files
committed
lvm: Add support for reading lvm.conf
Just a simple API using the lvmconfig command.
1 parent 3bd5185 commit b80948c

File tree

8 files changed

+235
-1
lines changed

8 files changed

+235
-1
lines changed

docs/libblockdev-sections.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ bd_lvm_set_devices_filter
388388
bd_lvm_writecache_attach
389389
bd_lvm_writecache_create_cached_lv
390390
bd_lvm_writecache_detach
391+
bd_lvm_config_get
391392
BDLVMTech
392393
BDLVMTechMode
393394
bd_lvm_is_tech_avail

src/lib/plugin_apis/lvm.api

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,7 @@ typedef enum {
737737
BD_LVM_TECH_WRITECACHE,
738738
BD_LVM_TECH_DEVICES,
739739
BD_LVM_TECH_SHARED,
740+
BD_LVM_TECH_CONFIG,
740741
} BDLVMTech;
741742

742743
typedef enum {
@@ -2026,4 +2027,21 @@ gboolean bd_lvm_devices_add (const gchar *device, const gchar *devices_file, con
20262027
*/
20272028
gboolean bd_lvm_devices_delete (const gchar *device, const gchar *devices_file, const BDExtraArg **extra, GError **error);
20282029

2030+
/**
2031+
* bd_lvm_config_get:
2032+
* @section: (nullable): LVM config section, e.g. 'global' or %NULL to print the entire config
2033+
* @setting: (nullable): name of the specific setting, e.g. 'umask' or %NULL to print the entire @section
2034+
* @type: type of the config, e.g. 'full' or 'current'
2035+
* @values_only: whether to include only values without keys in the output
2036+
* @global_config: whether to include our internal global config in the call or not
2037+
* @extra: (nullable) (array zero-terminated=1): extra options for the lvmconfig command
2038+
* (just passed to LVM as is)
2039+
* @error: (out) (optional): place to store error (if any)
2040+
*
2041+
* Returns: (transfer full): Requested LVM config @section and @setting configuration or %NULL in case of error.
2042+
*
2043+
* Tech category: %BD_LVM_TECH_CONFIG no mode (it is ignored)
2044+
*/
2045+
gchar* bd_lvm_config_get (const gchar *section, const gchar *setting, const gchar *type, gboolean values_only, gboolean global_config, const BDExtraArg **extra, GError **error);
2046+
20292047
#endif /* BD_LVM_API */

src/plugins/lvm-dbus.c

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,11 +293,14 @@ static GMutex deps_check_lock;
293293
#define DEPS_LVM_MASK (1 << DEPS_LVM)
294294
#define DEPS_LVMDEVICES 1
295295
#define DEPS_LVMDEVICES_MASK (1 << DEPS_LVMDEVICES)
296-
#define DEPS_LAST 2
296+
#define DEPS_LVMCONFIG 2
297+
#define DEPS_LVMCONFIG_MASK (1 << DEPS_LVMCONFIG)
298+
#define DEPS_LAST 3
297299

298300
static const UtilDep deps[DEPS_LAST] = {
299301
{"lvm", LVM_MIN_VERSION, "version", "LVM version:\\s+([\\d\\.]+)"},
300302
{"lvmdevices", NULL, NULL, NULL},
303+
{"lvmconfig", NULL, NULL, NULL},
301304
};
302305

303306
#define DBUS_DEPS_LVMDBUSD 0
@@ -415,6 +418,8 @@ gboolean bd_lvm_is_tech_avail (BDLVMTech tech, guint64 mode, GError **error) {
415418
check_features (&avail_features, FEATURES_WRITECACHE_MASK, features, FEATURES_LAST, &deps_check_lock, error);
416419
case BD_LVM_TECH_DEVICES:
417420
return check_deps (&avail_deps, DEPS_LVMDEVICES_MASK, deps, DEPS_LAST, &deps_check_lock, error);
421+
case BD_LVM_TECH_CONFIG:
422+
return check_deps (&avail_deps, DEPS_LVMCONFIG_MASK, deps, DEPS_LAST, &deps_check_lock, error);
418423
default:
419424
/* everything is supported by this implementation of the plugin */
420425
return check_dbus_deps (&avail_dbus_deps, DBUS_DEPS_LVMDBUSD_MASK, dbus_deps, DBUS_DEPS_LAST, &deps_check_lock, error);
@@ -4917,3 +4922,58 @@ gboolean bd_lvm_devices_delete (const gchar *device, const gchar *devices_file,
49174922

49184923
return bd_utils_exec_and_report_error (args, extra, error);
49194924
}
4925+
4926+
/**
4927+
* bd_lvm_config_get:
4928+
* @section: (nullable): LVM config section, e.g. 'global' or %NULL to print the entire config
4929+
* @setting: (nullable): name of the specific setting, e.g. 'umask' or %NULL to print the entire @section
4930+
* @type: type of the config, e.g. 'full' or 'current'
4931+
* @values_only: whether to include only values without keys in the output
4932+
* @global_config: whether to include our internal global config in the call or not
4933+
* @extra: (nullable) (array zero-terminated=1): extra options for the lvmconfig command
4934+
* (just passed to LVM as is)
4935+
* @error: (out) (optional): place to store error (if any)
4936+
*
4937+
* Returns: Requested LVM config @section and @setting configuration or %NULL in case of error.
4938+
*
4939+
* Tech category: (transfer full): %BD_LVM_TECH_CONFIG no mode (it is ignored)
4940+
*/
4941+
gchar* bd_lvm_config_get (const gchar *section, const gchar *setting, const gchar *type, gboolean values_only, gboolean global_config, const BDExtraArg **extra, GError **error) {
4942+
g_autofree gchar *conf_spec = NULL;
4943+
g_autofree gchar *config_arg = NULL;
4944+
const gchar *args[7] = {"lvmconfig", "--typeconfig", NULL, NULL, NULL, NULL, NULL};
4945+
guint next_arg = 2;
4946+
gchar *output = NULL;
4947+
gboolean success = FALSE;
4948+
4949+
if (!section && setting) {
4950+
g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_FAIL,
4951+
"Specifying setting without section is not supported.");
4952+
return NULL;
4953+
}
4954+
4955+
if (section)
4956+
if (setting)
4957+
conf_spec = g_strdup_printf ("%s/%s", section, setting);
4958+
else
4959+
conf_spec = g_strdup (section);
4960+
else
4961+
conf_spec = NULL;
4962+
4963+
args[next_arg++] = type;
4964+
args[next_arg++] = conf_spec;
4965+
if (values_only)
4966+
args[next_arg++] = "--valuesonly";
4967+
4968+
g_mutex_lock (&global_config_lock);
4969+
if (global_config && global_config_str) {
4970+
config_arg = g_strdup_printf ("--config=%s", global_config_str);
4971+
args[next_arg++] = config_arg;
4972+
}
4973+
g_mutex_unlock (&global_config_lock);
4974+
4975+
success = bd_utils_exec_and_capture_output (args, extra, &output, error);
4976+
if (!success)
4977+
return NULL;
4978+
return g_strchomp (output);
4979+
}

src/plugins/lvm.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3970,3 +3970,58 @@ gboolean bd_lvm_devices_delete (const gchar *device, const gchar *devices_file,
39703970

39713971
return bd_utils_exec_and_report_error (args, extra, error);
39723972
}
3973+
3974+
/**
3975+
* bd_lvm_config_get:
3976+
* @section: (nullable): LVM config section, e.g. 'global' or %NULL to print the entire config
3977+
* @setting: (nullable): name of the specific setting, e.g. 'umask' or %NULL to print the entire @section
3978+
* @type: type of the config, e.g. 'full' or 'current'
3979+
* @values_only: whether to include only values without keys in the output
3980+
* @global_config: whether to include our internal global config in the call or not
3981+
* @extra: (nullable) (array zero-terminated=1): extra options for the lvmconfig command
3982+
* (just passed to LVM as is)
3983+
* @error: (out) (optional): place to store error (if any)
3984+
*
3985+
* Returns: (transfer full): Requested LVM config @section and @setting configuration or %NULL in case of error.
3986+
*
3987+
* Tech category: %BD_LVM_TECH_CONFIG no mode (it is ignored)
3988+
*/
3989+
gchar* bd_lvm_config_get (const gchar *section, const gchar *setting, const gchar *type, gboolean values_only, gboolean global_config, const BDExtraArg **extra, GError **error) {
3990+
g_autofree gchar *conf_spec = NULL;
3991+
g_autofree gchar *config_arg = NULL;
3992+
const gchar *args[7] = {"lvmconfig", "--typeconfig", NULL, NULL, NULL, NULL, NULL};
3993+
guint next_arg = 2;
3994+
gchar *output = NULL;
3995+
gboolean success = FALSE;
3996+
3997+
if (!section && setting) {
3998+
g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_FAIL,
3999+
"Specifying setting without section is not supported.");
4000+
return NULL;
4001+
}
4002+
4003+
if (section)
4004+
if (setting)
4005+
conf_spec = g_strdup_printf ("%s/%s", section, setting);
4006+
else
4007+
conf_spec = g_strdup (section);
4008+
else
4009+
conf_spec = NULL;
4010+
4011+
args[next_arg++] = type;
4012+
args[next_arg++] = conf_spec;
4013+
if (values_only)
4014+
args[next_arg++] = "--valuesonly";
4015+
4016+
g_mutex_lock (&global_config_lock);
4017+
if (global_config && global_config_str) {
4018+
config_arg = g_strdup_printf ("--config=%s", global_config_str);
4019+
args[next_arg++] = config_arg;
4020+
}
4021+
g_mutex_unlock (&global_config_lock);
4022+
4023+
success = bd_utils_exec_and_capture_output (args, extra, &output, error);
4024+
if (!success)
4025+
return NULL;
4026+
return g_strchomp (output);
4027+
}

src/plugins/lvm.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ typedef enum {
201201
BD_LVM_TECH_WRITECACHE,
202202
BD_LVM_TECH_DEVICES,
203203
BD_LVM_TECH_SHARED,
204+
BD_LVM_TECH_CONFIG,
204205
} BDLVMTech;
205206

206207
typedef enum {
@@ -330,4 +331,6 @@ GHashTable* bd_lvm_vdo_get_stats_full (const gchar *vg_name, const gchar *pool_n
330331
gboolean bd_lvm_devices_add (const gchar *device, const gchar *devices_file, const BDExtraArg **extra, GError **error);
331332
gboolean bd_lvm_devices_delete (const gchar *device, const gchar *devices_file, const BDExtraArg **extra, GError **error);
332333

334+
gchar* bd_lvm_config_get (const gchar *section, const gchar *setting, const gchar *type, gboolean values_only, gboolean global_config, const BDExtraArg **extra, GError **error);
335+
333336
#endif /* BD_LVM */

src/python/gi/overrides/BlockDev.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,6 +1016,13 @@ def lvm_devices_delete(device, devices_file=None, extra=None, **kwargs):
10161016
return _lvm_devices_delete(device, devices_file, extra)
10171017
__all__.append("lvm_devices_delete")
10181018

1019+
_lvm_config_get = BlockDev.lvm_config_get
1020+
@override(BlockDev.lvm_config_get)
1021+
def lvm_config_get(section=None, setting=None, type="full", values_only=True, global_config=True, extra=None, **kwargs):
1022+
extra = _get_extra(extra, kwargs)
1023+
return _lvm_config_get(section, setting, type, values_only, global_config, extra)
1024+
__all__.append("lvm_config_get")
1025+
10191026

10201027
_md_get_superblock_size = BlockDev.md_get_superblock_size
10211028
@override(BlockDev.md_get_superblock_size)

tests/lvm_dbus_tests.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ def setUpClass(cls):
8383
def tearDownClass(cls):
8484
# reset back to default
8585
BlockDev.utils_set_log_level(BlockDev.UTILS_LOG_WARNING)
86+
BlockDev.lvm_set_global_config(None)
8687

8788
super(LvmNoDevTestCase, cls).tearDownClass()
8889

@@ -338,6 +339,52 @@ def test_cache_mode_bijection(self):
338339
with self.assertRaises(GLib.GError):
339340
BlockDev.lvm_cache_get_mode_from_str("bla")
340341

342+
@tag_test(TestTags.NOSTORAGE)
343+
def test_lvm_config(self):
344+
"""Verify that we can correctly read from LVM config"""
345+
346+
# should be always available, "lvmconfig" command is just alias for "lvm config"
347+
succ = BlockDev.lvm_is_tech_avail(BlockDev.LVMTech.CONFIG, 0)
348+
self.assertTrue(succ)
349+
350+
with self.assertRaises(GLib.GError):
351+
BlockDev.lvm_config_get(None, "dir")
352+
353+
# get entire config
354+
conf = BlockDev.lvm_config_get()
355+
self.assertTrue(conf)
356+
self.assertTrue(conf.startswith("config"))
357+
358+
# get just the "devices" section
359+
conf = BlockDev.lvm_config_get("devices")
360+
self.assertTrue(conf)
361+
self.assertTrue(conf.startswith("devices"))
362+
363+
# let's be brave and assume devices/dir is set everywhere ti /dev
364+
devdir = BlockDev.lvm_config_get("devices", "dir", "full")
365+
self.assertEqual(devdir, "\"/dev\"")
366+
367+
devdir = BlockDev.lvm_config_get("devices", "dir", "full", values_only=False)
368+
self.assertEqual(devdir, "dir=\"/dev\"")
369+
370+
devdir = BlockDev.lvm_config_get("devices", "dir", "default")
371+
self.assertEqual(devdir, "\"/dev\"")
372+
373+
# let's try to override some results with --config
374+
BlockDev.lvm_set_global_config("devices/dir=/test")
375+
376+
devdir = BlockDev.lvm_config_get("devices", "dir", "full")
377+
self.assertEqual(devdir, "\"/test\"")
378+
379+
# "default" config should not be affected by --config
380+
devdir = BlockDev.lvm_config_get("devices", "dir", "default")
381+
self.assertEqual(devdir, "\"/dev\"")
382+
383+
# disable global config
384+
devdir = BlockDev.lvm_config_get("devices", "dir", "full", global_config=False)
385+
self.assertEqual(devdir, "\"/dev\"")
386+
387+
341388
@unittest.skipUnless(lvm_dbus_running, "LVM DBus not running")
342389
class LvmPVonlyTestCase(LVMTestCase):
343390

tests/lvm_test.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ def setUpClass(cls):
8282
def tearDownClass(cls):
8383
# reset back to default
8484
BlockDev.utils_set_log_level(BlockDev.UTILS_LOG_WARNING)
85+
BlockDev.lvm_set_global_config(None)
8586

8687
super(LvmNoDevTestCase, cls).tearDownClass()
8788

@@ -332,6 +333,48 @@ def test_cache_mode_bijection(self):
332333
with self.assertRaises(GLib.GError):
333334
BlockDev.lvm_cache_get_mode_from_str("bla")
334335

336+
@tag_test(TestTags.NOSTORAGE)
337+
def test_lvm_config(self):
338+
"""Verify that we can correctly read from LVM config"""
339+
340+
with self.assertRaises(GLib.GError):
341+
BlockDev.lvm_config_get(None, "dir")
342+
343+
# get entire config
344+
conf = BlockDev.lvm_config_get()
345+
self.assertTrue(conf)
346+
self.assertTrue(conf.startswith("config"))
347+
348+
# get just the "devices" section
349+
conf = BlockDev.lvm_config_get("devices")
350+
self.assertTrue(conf)
351+
self.assertTrue(conf.startswith("devices"))
352+
353+
# let's be brave and assume devices/dir is set everywhere ti /dev
354+
devdir = BlockDev.lvm_config_get("devices", "dir", "full")
355+
self.assertEqual(devdir, "\"/dev\"")
356+
357+
devdir = BlockDev.lvm_config_get("devices", "dir", "full", values_only=False)
358+
self.assertEqual(devdir, "dir=\"/dev\"")
359+
360+
devdir = BlockDev.lvm_config_get("devices", "dir", "default")
361+
self.assertEqual(devdir, "\"/dev\"")
362+
363+
# let's try to override some results with --config
364+
BlockDev.lvm_set_global_config("devices/dir=/test")
365+
366+
devdir = BlockDev.lvm_config_get("devices", "dir", "full")
367+
self.assertEqual(devdir, "\"/test\"")
368+
369+
# "default" config should not be affected by --config
370+
devdir = BlockDev.lvm_config_get("devices", "dir", "default")
371+
self.assertEqual(devdir, "\"/dev\"")
372+
373+
# disable global config
374+
devdir = BlockDev.lvm_config_get("devices", "dir", "full", global_config=False)
375+
self.assertEqual(devdir, "\"/dev\"")
376+
377+
335378
class LvmPVonlyTestCase(LVMTestCase):
336379

337380
_sparse_size = 1024**3

0 commit comments

Comments
 (0)