The current sanlock plugin requires a central management
application to manually add <lease> elements to each guest,
to protect resources that are assigned to it (eg writable
disks). This makes the sanlock plugin useless for usage
in more ad hoc deployment environments where there is no
central authority to associate disks with leases.
This patch adds a mode where the sanlock plugin will
automatically create leases for each assigned read-write
disk, using a md5 checksum of the fully qualified disk
path. This can work pretty well if guests are using
stable disk paths for block devices eg /dev/disk/by-path/XXXX
symlinks, or if all hosts have NFS volumes mounted in
a consistent pattern.
The plugin will create one lockspace for managing disks
with filename /var/lib/libvirt/sanlock/__LIBVIRT__DISKS__.
For each VM disks, there will be another file to hold
a lease /var/lib/libvirt/sanlock/5903e5d25e087e60a20fe4566fab41fd
Each VM disk lease is usually 1 MB in size. The script
virt-sanlock-cleanup should be run periodically to remove
unused lease files from the lockspace directory.
To make use of this capability the admin will need to do
several tasks:
- Mount an NFS volume (or other shared filesystem)
on /var/lib/libvirt/sanlock
- Configure 'host_id' in /etc/libvirt/qemu-sanlock.conf
with a unique value for each host with the same NFS
mount
- Toggle the 'auto_disk_leases' parameter in qemu-sanlock.conf
Technically the first step can be skipped, in which case
sanlock will only protect against 2 vms on the same host
using the same disk (or the same VM being started twice
due to error by libvirt).
* src/locking/libvirt_sanlock.aug,
src/locking/sanlock.conf,
src/locking/test_libvirt_sanlock.aug: Add config params
for configuring auto lease setup
* libvirt.spec.in: Add virt-sanlock-cleanup program, man
page
* tools/virt-sanlock-cleanup.in: Script to purge unused
disk resource lease files
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
Allow a 'configFile' parameter to be passed into the lock
drivers to provide configuration. Wire up the QEMU driver
to pass in file names '/etc/libvirt/qemu-$NAME.conf
eg qemu-sanlock.conf
* src/locking/lock_driver.h, src/locking/lock_driver_nop.c,
src/locking/lock_driver_sanlock.c, src/locking/lock_manager.c,
src/locking/lock_manager.h: Add configFile parameter
* src/qemu/qemu_conf.c: Pass in configuration file path to
lock driver plugins
The libvirt sanlock plugin is intentionally leaking a file
descriptor to QEMU. To enable QEMU to use this FD under
SELinux, it must be labelled correctly. We dont want to use
the svirt_image_t for this, since QEMU must not be allowed
to actually use the FD. So instead we label it with svirt_t
using virSecurityManagerSetProcessFDLabel
* src/locking/domain_lock.c, src/locking/domain_lock.h,
src/locking/lock_driver.h, src/locking/lock_driver_nop.c,
src/locking/lock_driver_sanlock.c, src/locking/lock_manager.c,
src/locking/lock_manager.h: Optionally pass an FD back to
the hypervisor for security driver labelling
* src/qemu/qemu_process.c: label the lock manager plugin
FD with the process label
Done as a separate commit to make backporting the next patch easier.
We are already using "intprops.h", but this makes it explicit.
* .gnulib: Update, for syntax-check fix.
* bootstrap.conf (gnulib_modules): Make intprops use explicit.
* src/locking/domain_lock.c (includes): Drop unused header.
* src/nwfilter/nwfilter_learnipaddr.c (includes): Use "", not <>,
for gnulib.
When virLockDriverAcquire is invoked during hotplug the state
parameter will be left as NULL.
* src/locking/lock_driver_nop.c,
src/locking/lock_driver_sanlock.c: Don't reference NULL state
parameter
Refactoring of the lock manager hotplug methods lost the
ret = 0 assignment for successful return path
* src/locking/domain_lock.c: Add missing ret = 0 assignments
In between fork and exec, a connection to sanlock is acquired
and the socket file descriptor is intionally leaked to the
child process. sanlock watches this FD for POLL_HANGUP to
detect when QEMU has exited. We don't want a rogus/compromised
QEMU from issuing sanlock RPC calls on the leaked FD though,
since that could be used to DOS other guests. By calling
sanlock_restrict() on the socket before exec() we can lock
it down.
* configure.ac: Check for sanlock_restrict API
* src/locking/domain_lock.c: Restrict lock acquired in
process startup phase
* src/locking/lock_driver.h: Add VIR_LOCK_MANAGER_ACQUIRE_RESTRICT
* src/locking/lock_driver_sanlock.c: Add call to sanlock_restrict
when requested by VIR_LOCK_MANAGER_ACQUIRE_RESTRICT flag
Sanlock is a project that implements a disk-paxos locking
algorithm. This is suitable for cluster deployments with
shared storage.
* src/Makefile.am: Add dlopen plugin for sanlock
* src/locking/lock_driver_sanlock.c: Sanlock driver
* configure.ac: Check for sanlock
* libvirt.spec.in: Add a libvirt-lock-sanlock RPM
To facilitate use of the locking plugins from hypervisor drivers,
introduce a higher level API for locking virDomainObjPtr instances.
In includes APIs targetted to VM startup, and hotplug/unplug
* src/Makefile.am: Add domain lock API
* src/locking/domain_lock.c, src/locking/domain_lock.h: High
level API for domain locking
To allow hypervisor drivers to assume that a lock driver impl
will be guaranteed to exist, provide a 'nop' impl that is
compiled into the library
* src/Makefile.am: Add nop driver
* src/locking/lock_driver_nop.c, src/locking/lock_driver_nop.h:
Nop lock driver implementation
* src/locking/lock_manager.c: Enable direct access of 'nop'
driver, instead of dlopen()ing it.
Define the basic framework lock manager plugins. The
basic plugin API for 3rd parties to implemented is
defined in
src/locking/lock_driver.h
This allows dlopen()able modules for alternative locking
schemes, however, we do not install the header. This
requires lock plugins to be in-tree allowing changing of
the lock manager plugin API in future.
The libvirt code for loading & calling into plugins
is in
src/locking/lock_manager.{c,h}
* include/libvirt/virterror.h, src/util/virterror.c: Add
VIR_FROM_LOCKING
* src/locking/lock_driver.h: API for lock driver plugins
to implement
* src/locking/lock_manager.c, src/locking/lock_manager.h:
Internal API for managing locking
* src/Makefile.am: Add locking code