Introduce a configuration file with a single parameter 'require_lease_for_disks', which is used to decide whether it is allowed to start a guest which has read/write disks, but without any leases. * libvirt.spec.in: Add sanlock config file and augeas lens * src/Makefile.am: Install sanlock config file and augeas lens * src/locking/libvirt_sanlock.aug: Augeas master lens * src/locking/test_libvirt_sanlock.aug: Augeas test file * src/locking/sanlock.conf: Example sanlock config * src/locking/lock_driver_sanlock.c: Wire up loading of configuration file --- libvirt.spec.in | 3 + src/Makefile.am | 25 ++++++++++- src/locking/libvirt_sanlock.aug | 31 ++++++++++++++ src/locking/lock_driver_sanlock.c | 77 ++++++++++++++++++++++++++++++++- src/locking/sanlock.conf | 6 +++ src/locking/test_libvirt_sanlock.aug | 7 +++ 6 files changed, 144 insertions(+), 5 deletions(-) create mode 100644 src/locking/libvirt_sanlock.aug create mode 100644 src/locking/sanlock.conf create mode 100644 src/locking/test_libvirt_sanlock.aug diff --git a/libvirt.spec.in b/libvirt.spec.in index 11b8591..9b22983 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -1028,7 +1028,10 @@ fi %if %{with_sanlock} %files lock-sanlock %defattr(-, root, root) +%config(noreplace) %{_sysconfdir}/libvirt/qemu-sanlock.conf %attr(0755, root, root) %{_libdir}/libvirt/lock-driver/sanlock.so +%{_datadir}/augeas/lenses/libvirt_sanlock.aug +%{_datadir}/augeas/lenses/tests/test_libvirt_sanlock.aug %endif %files client -f %{name}.lang diff --git a/src/Makefile.am b/src/Makefile.am index 52fc63c..9208883 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1035,6 +1035,10 @@ if WITH_LXC $(srcdir)/lxc/test_libvirtd_lxc.aug; \ fi endif + $(AM_V_GEN)if test -x '$(AUGPARSE)'; then \ + '$(AUGPARSE)' -I $(srcdir)/locking \ + $(srcdir)/locking/test_libvirt_sanlock.aug; \ + fi # # Build our version script. This is composed of three parts: @@ -1182,9 +1186,26 @@ lockdriver_LTLIBRARIES = sanlock.la sanlock_la_SOURCES = $(LOCK_DRIVER_SANLOCK_SOURCES) sanlock_la_CFLAGS = $(AM_CLFAGS) sanlock_la_LDFLAGS = -module -avoid-version -sanlock_la_LIBADD = -lsanlock +sanlock_la_LIBADD = -lsanlock \ + ../gnulib/lib/libgnu.la + +augeas_DATA += locking/libvirt_sanlock.aug +augeastest_DATA += locking/test_libvirt_sanlock.aug + +EXTRA_DIST += locking/sanlock.conf \ + locking/libvirt_sanlock.aug \ + locking/test_libvirt_sanlock.aug + +$(builddir)/locking/%-sanlock.conf: $(srcdir)/locking/sanlock.conf + $(AM_V_GEN)mkdir locking ; \ + cp $< $@ + +if WITH_QEMU +conf_DATA += locking/qemu-sanlock.conf +BUILT_SOURCES += locking/qemu-sanlock.conf +endif else -EXTRA_DIST += $(LOCK_DRIVER_SANLOCK_SOURCES) +EXTRA_DIST += $(LOCK_DRIVER_SANLOCK_SOURCES) locking/sanlock.conf endif noinst_LTLIBRARIES += libvirt-net-rpc.la libvirt-net-rpc-server.la libvirt-net-rpc-client.la diff --git a/src/locking/libvirt_sanlock.aug b/src/locking/libvirt_sanlock.aug new file mode 100644 index 0000000..baa639a --- /dev/null +++ b/src/locking/libvirt_sanlock.aug @@ -0,0 +1,31 @@ +(* /etc/libvirt/qemu-sanlock.conf *) + +module Libvirt_sanlock = + autoload xfm + + let eol = del /[ \t]*\n/ "\n" + let value_sep = del /[ \t]*=[ \t]*/ " = " + let indent = del /[ \t]*/ "" + + let str_val = del /\"/ "\"" . store /[^\"]*/ . del /\"/ "\"" + let bool_val = store /0|1/ + let int_val = store /[0-9]+/ + + let str_entry (kw:string) = [ key kw . value_sep . str_val ] + let bool_entry (kw:string) = [ key kw . value_sep . bool_val ] + let int_entry (kw:string) = [ key kw . value_sep . int_val ] + + + (* Each enty in the config is one of the following three ... *) + let entry = bool_entry "require_lease_for_disks" + let comment = [ label "#comment" . del /#[ \t]*/ "# " . store /([^ \t\n][^\n]*)?/ . del /\n/ "\n" ] + let empty = [ label "#empty" . eol ] + + let record = indent . entry . eol + + let lns = ( record | comment | empty ) * + + let filter = incl "/etc/libvirt/qemu-sanlock.conf" + . Util.stdexcl + + let xfm = transform lns filter diff --git a/src/locking/lock_driver_sanlock.c b/src/locking/lock_driver_sanlock.c index 3eab23e..7ad54e8 100644 --- a/src/locking/lock_driver_sanlock.c +++ b/src/locking/lock_driver_sanlock.c @@ -45,9 +45,19 @@ virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \ __FUNCTION__, __LINE__, __VA_ARGS__) + +typedef struct _virLockManagerSanlockDriver virLockManagerSanlockDriver; +typedef virLockManagerSanlockDriver *virLockManagerSanlockDriverPtr; + typedef struct _virLockManagerSanlockPrivate virLockManagerSanlockPrivate; typedef virLockManagerSanlockPrivate *virLockManagerSanlockPrivatePtr; +struct _virLockManagerSanlockDriver { + bool requireLeaseForDisks; +}; + +static virLockManagerSanlockDriver *driver = NULL; + struct _virLockManagerSanlockPrivate { char vm_name[SANLK_NAME_LEN]; char vm_uuid[VIR_UUID_BUFLEN]; @@ -62,22 +72,76 @@ struct _virLockManagerSanlockPrivate { /* * sanlock plugin for the libvirt virLockManager API */ +static int virLockManagerSanlockLoadConfig(const char *configFile) +{ + virConfPtr conf; + virConfValuePtr p; + + if (access(configFile, R_OK) == -1) { + if (errno != ENOENT) { + virReportSystemError(errno, + _("Unable to access config file %s"), + configFile); + return -1; + } + return 0; + } + + if (!(conf = virConfReadFile(configFile, 0))) + return -1; + +#define CHECK_TYPE(name,typ) if (p && p->type != (typ)) { \ + virLockError(VIR_ERR_INTERNAL_ERROR, \ + "%s: %s: expected type " #typ, \ + configFile, (name)); \ + virConfFree(conf); \ + return -1; \ + } + + p = virConfGetValue(conf, "require_lease_for_disks"); + CHECK_TYPE("require_lease_for_disks", VIR_CONF_LONG); + if (p) + driver->requireLeaseForDisks = p->l; + + virConfFree(conf); + return 0; +} -static int virLockManagerSanlockInit(unsigned int version ATTRIBUTE_UNUSED, - const char *configFile ATTRIBUTE_UNUSED, + +static int virLockManagerSanlockInit(unsigned int version, + const char *configFile, unsigned int flags) { + VIR_DEBUG("version=%u configFile=%s flags=%u", version, NULLSTR(configFile), flags); virCheckFlags(0, -1); + + if (driver) + return 0; + + if (VIR_ALLOC(driver) < 0) { + virReportOOMError(); + return -1; + } + + driver->requireLeaseForDisks = true; + + if (virLockManagerSanlockLoadConfig(configFile) < 0) + return -1; + return 0; } static int virLockManagerSanlockDeinit(void) { + if (!driver) + return 0; + virLockError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unloading sanlock plugin is forbidden")); return -1; } + static int virLockManagerSanlockNew(virLockManagerPtr lock, unsigned int type, size_t nparams, @@ -90,6 +154,12 @@ static int virLockManagerSanlockNew(virLockManagerPtr lock, virCheckFlags(0, -1); + if (!driver) { + virLockError(VIR_ERR_INTERNAL_ERROR, + _("Sanlock plugin is not initialized")); + return -1; + } + if (type != VIR_LOCK_MANAGER_OBJECT_TYPE_DOMAIN) { virLockError(VIR_ERR_INTERNAL_ERROR, _("Unsupported object type %d"), type); @@ -245,7 +315,8 @@ static int virLockManagerSanlockAcquire(virLockManagerPtr lock, VIR_LOCK_MANAGER_ACQUIRE_REGISTER_ONLY, -1); if (priv->res_count == 0 && - priv->hasRWDisks) { + priv->hasRWDisks && + driver->requireLeaseForDisks) { virLockError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Read/write, exclusive access, disks were present, but no leases specified")); return -1; diff --git a/src/locking/sanlock.conf b/src/locking/sanlock.conf new file mode 100644 index 0000000..818b529 --- /dev/null +++ b/src/locking/sanlock.conf @@ -0,0 +1,6 @@ +# +# Flag to determine whether we allow starting of guests +# which do not have any <lease> elements defined in their +# configuration. +# +#require_lease_for_disks = 1 diff --git a/src/locking/test_libvirt_sanlock.aug b/src/locking/test_libvirt_sanlock.aug new file mode 100644 index 0000000..2f1f57a --- /dev/null +++ b/src/locking/test_libvirt_sanlock.aug @@ -0,0 +1,7 @@ +module Test_libvirt_sanlock = + + let conf = "require_lease_for_disks = 1 +" + + test Libvirt_sanlock.lns get conf = +{ "require_lease_for_disks" = "1" } -- 1.7.4.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list