1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00
lvm2/daemons/lvmdbusd/vg.py
Tony Asleson dd5d865020 lvmdbusd: Fix hang when lvm compiled with 'enable-notify-dbus'
The following operations would hang if lvm was compiled with
'enable-notify-dbus' and the client specified -1 for the timeout:

* LV snapshot merge
* VG move
* LV move

This was caused because the implementation of these three dbus methods is
different.  Most of the dbus method calls are executed by gathering information
needed to fulfill it, placing that information on a thread safe queue and
returning.  The results later to be returned to the client with callbacks.
With this approach we can process an arbitrary number of commands without any
of them blocking other dbus commands.  However, the 3 dbus methods listed
above did not utilize this functionality because they were implemented with a
separate thread that handles the fork & exec of lvm.  This is done because these
operations can be very slow to complete.  However, because of this the lvm
command that we were waiting on is trying to call back into the dbus service to
notify it that something changed.  Because the code was blocking the process
that handles the incoming dbus activity the lvm command blocked.  We were stuck
until the client timed-out the connection, which then causes the service to
unblock and continue.  If the client did not have a timeout, we would have been
hung indefinitely.

The fix is to always utilize the worker queue on all dbus methods.  We need to
ensure that lvm is tested with 'enable-notify-dbus' enabled and disabled.
2016-06-28 12:09:28 -05:00

960 lines
28 KiB
Python

# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .automatedproperties import AutomatedProperties
from . import utils
from .utils import pv_obj_path_generate, vg_obj_path_generate, n
import dbus
from . import cfg
from .cfg import VG_INTERFACE
from . import cmdhandler
from .request import RequestEntry
from .loader import common
from .state import State
from . import background
from .utils import round_size
from .job import JobState
# noinspection PyUnusedLocal
def vgs_state_retrieve(selection, cache_refresh=True):
rc = []
if cache_refresh:
cfg.db.refresh()
for v in cfg.db.fetch_vgs(selection):
rc.append(
VgState(
v['vg_uuid'], v['vg_name'], v['vg_fmt'], n(v['vg_size']),
n(v['vg_free']), v['vg_sysid'], n(v['vg_extent_size']),
n(v['vg_extent_count']), n(v['vg_free_count']),
v['vg_profile'], n(v['max_lv']), n(v['max_pv']),
n(v['pv_count']), n(v['lv_count']), n(v['snap_count']),
n(v['vg_seqno']), n(v['vg_mda_count']),
n(v['vg_mda_free']), n(v['vg_mda_size']),
n(v['vg_mda_used_count']), v['vg_attr'], v['vg_tags']))
return rc
def load_vgs(vg_specific=None, object_path=None, refresh=False,
emit_signal=False, cache_refresh=True):
return common(vgs_state_retrieve, (Vg,), vg_specific, object_path, refresh,
emit_signal, cache_refresh)
# noinspection PyPep8Naming,PyUnresolvedReferences,PyUnusedLocal
class VgState(State):
@property
def lvm_id(self):
return self.Name
def identifiers(self):
return (self.Uuid, self.Name)
def _lv_paths_build(self):
rc = []
for lv in cfg.db.lvs_in_vg(self.Uuid):
(lv_name, meta, lv_uuid) = lv
full_name = "%s/%s" % (self.Name, lv_name)
gen = utils.lv_object_path_method(lv_name, meta)
lv_path = cfg.om.get_object_path_by_uuid_lvm_id(
lv_uuid, full_name, gen)
rc.append(lv_path)
return dbus.Array(rc, signature='o')
def _pv_paths_build(self):
rc = []
for p in cfg.db.pvs_in_vg(self.Uuid):
(pv_name, pv_uuid) = p
rc.append(cfg.om.get_object_path_by_uuid_lvm_id(
pv_uuid, pv_name, pv_obj_path_generate))
return dbus.Array(rc, signature='o')
def __init__(self, Uuid, Name, Fmt,
SizeBytes, FreeBytes, SysId, ExtentSizeBytes,
ExtentCount, FreeCount, Profile, MaxLv, MaxPv, PvCount,
LvCount, SnapCount, Seqno, MdaCount, MdaFree,
MdaSizeBytes, MdaUsedCount, attr, tags):
utils.init_class_from_arguments(self)
self.Pvs = self._pv_paths_build()
self.Lvs = self._lv_paths_build()
def create_dbus_object(self, path):
if not path:
path = cfg.om.get_object_path_by_uuid_lvm_id(
self.Uuid, self.Name, vg_obj_path_generate)
return Vg(path, self)
# noinspection PyMethodMayBeStatic
def creation_signature(self):
return (Vg, vg_obj_path_generate)
# noinspection PyPep8Naming
@utils.dbus_property(VG_INTERFACE, 'Uuid', 's')
@utils.dbus_property(VG_INTERFACE, 'Name', 's')
@utils.dbus_property(VG_INTERFACE, 'Fmt', 's')
@utils.dbus_property(VG_INTERFACE, 'SizeBytes', 't', 0)
@utils.dbus_property(VG_INTERFACE, 'FreeBytes', 't', 0)
@utils.dbus_property(VG_INTERFACE, 'SysId', 's')
@utils.dbus_property(VG_INTERFACE, 'ExtentSizeBytes', 't')
@utils.dbus_property(VG_INTERFACE, 'ExtentCount', 't')
@utils.dbus_property(VG_INTERFACE, 'FreeCount', 't')
@utils.dbus_property(VG_INTERFACE, 'Profile', 's')
@utils.dbus_property(VG_INTERFACE, 'MaxLv', 't')
@utils.dbus_property(VG_INTERFACE, 'MaxPv', 't')
@utils.dbus_property(VG_INTERFACE, 'PvCount', 't')
@utils.dbus_property(VG_INTERFACE, 'LvCount', 't')
@utils.dbus_property(VG_INTERFACE, 'SnapCount', 't')
@utils.dbus_property(VG_INTERFACE, 'Seqno', 't')
@utils.dbus_property(VG_INTERFACE, 'MdaCount', 't')
@utils.dbus_property(VG_INTERFACE, 'MdaFree', 't')
@utils.dbus_property(VG_INTERFACE, 'MdaSizeBytes', 't')
@utils.dbus_property(VG_INTERFACE, 'MdaUsedCount', 't')
class Vg(AutomatedProperties):
_Tags_meta = ("as", VG_INTERFACE)
_Pvs_meta = ("ao", VG_INTERFACE)
_Lvs_meta = ("ao", VG_INTERFACE)
_Writeable_meta = ("b", VG_INTERFACE)
_Readable_meta = ("b", VG_INTERFACE)
_Resizeable_meta = ("b", VG_INTERFACE)
_Exportable_meta = ('b', VG_INTERFACE)
_Partial_meta = ('b', VG_INTERFACE)
_AllocContiguous_meta = ('b', VG_INTERFACE)
_AllocCling_meta = ('b', VG_INTERFACE)
_AllocNormal_meta = ('b', VG_INTERFACE)
_AllocAnywhere_meta = ('b', VG_INTERFACE)
_Clustered_meta = ('b', VG_INTERFACE)
# noinspection PyUnusedLocal,PyPep8Naming
def __init__(self, object_path, object_state):
super(Vg, self).__init__(object_path, vgs_state_retrieve)
self.set_interface(VG_INTERFACE)
self._object_path = object_path
self.state = object_state
@staticmethod
def fetch_new_lv(vg_name, lv_name):
cfg.load()
return cfg.om.get_object_by_lvm_id("%s/%s" % (vg_name, lv_name))
@staticmethod
def _rename(uuid, vg_name, new_name, rename_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_rename(vg_name, new_name,
rename_options)
if rc == 0:
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='sia{sv}', out_signature='o',
async_callbacks=('cb', 'cbe'))
def Rename(self, name, tmo, rename_options, cb, cbe):
utils.validate_vg_name(VG_INTERFACE, name)
r = RequestEntry(tmo, Vg._rename,
(self.state.Uuid, self.state.lvm_id, name,
rename_options), cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _remove(uuid, vg_name, remove_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
# Remove the VG, if successful then remove from the model
rc, out, err = cmdhandler.vg_remove(vg_name, remove_options)
if rc == 0:
# Remove the VG
cfg.om.remove_object(dbo, True)
# If an LV has hidden LVs, things can get quite involved,
# especially if it's the last thin pool to get removed, so
# lets refresh all
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='ia{sv}', out_signature='o',
async_callbacks=('cb', 'cbe'))
def Remove(self, tmo, remove_options, cb, cbe):
r = RequestEntry(tmo, Vg._remove,
(self.state.Uuid, self.state.lvm_id, remove_options),
cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _change(uuid, vg_name, change_options):
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_change(change_options, vg_name)
# To use an example with d-feet (Method input)
# {"activate": __import__('gi.repository.GLib', globals(),
# locals(), ['Variant']).Variant("s", "n")}
if rc == 0:
cfg.load()
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
# TODO: This should be broken into a number of different methods
# instead of having one method that takes a hash for parameters. Some of
# the changes that vgchange does works on entire system, not just a
# specfic vg, thus that should be in the Manager interface.
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def Change(self, tmo, change_options, cb, cbe):
r = RequestEntry(tmo, Vg._change,
(self.state.Uuid, self.state.lvm_id, change_options),
cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _reduce(uuid, vg_name, missing, pv_object_paths, reduce_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
pv_devices = []
# If pv_object_paths is not empty, then get the device paths
if pv_object_paths and len(pv_object_paths) > 0:
for pv_op in pv_object_paths:
pv = cfg.om.get_object_by_path(pv_op)
if pv:
pv_devices.append(pv.lvm_id)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'PV Object path not found = %s!' % pv_op)
rc, out, err = cmdhandler.vg_reduce(vg_name, missing, pv_devices,
reduce_options)
if rc == 0:
cfg.load()
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='baoia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def Reduce(self, missing, pv_object_paths, tmo, reduce_options, cb, cbe):
r = RequestEntry(tmo, Vg._reduce,
(self.state.Uuid, self.state.lvm_id, missing,
pv_object_paths, reduce_options), cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _extend(uuid, vg_name, pv_object_paths, extend_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
extend_devices = []
for i in pv_object_paths:
pv = cfg.om.get_object_by_path(i)
if pv:
extend_devices.append(pv.lvm_id)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'PV Object path not found = %s!' % i)
if len(extend_devices):
rc, out, err = cmdhandler.vg_extend(vg_name, extend_devices,
extend_options)
if rc == 0:
cfg.load()
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'No pv_object_paths provided!')
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='aoia{sv}', out_signature='o',
async_callbacks=('cb', 'cbe'))
def Extend(self, pv_object_paths, tmo, extend_options, cb, cbe):
r = RequestEntry(tmo, Vg._extend,
(self.state.Uuid, self.state.lvm_id, pv_object_paths,
extend_options),
cb, cbe, False)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='o(tt)a(ott)ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def Move(self, pv_src_obj, pv_source_range, pv_dests_and_ranges,
tmo, move_options, cb, cbe):
job_state = JobState()
r = RequestEntry(
tmo, background.move,
(VG_INTERFACE, None, pv_src_obj, pv_source_range,
pv_dests_and_ranges, move_options, job_state), cb, cbe, False,
job_state)
cfg.worker_q.put(r)
@staticmethod
def _lv_create(uuid, vg_name, name, size_bytes, pv_dests_and_ranges,
create_options):
# Make sure we have a dbus object representing it
pv_dests = []
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
if len(pv_dests_and_ranges):
for pr in pv_dests_and_ranges:
pv_dbus_obj = cfg.om.get_object_by_path(pr[0])
if not pv_dbus_obj:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'PV Destination (%s) not found' % pr[0])
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
rc, out, err = cmdhandler.vg_lv_create(
vg_name, create_options, name, size_bytes, pv_dests)
if rc == 0:
return Vg.fetch_new_lv(vg_name, name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='sta(ott)ia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def LvCreate(self, name, size_bytes, pv_dests_and_ranges,
tmo, create_options, cb, cbe):
"""
This one it for the advanced users that want to roll their own
:param name: Name of the LV
:param size_bytes: Size of LV in bytes
:param pv_dests_and_ranges: Optional array of PV object paths and
ranges
:param tmo: -1 == Wait forever, 0 == return job immediately, > 0 ==
willing to wait that number of seconds before
getting a job
:param create_options: hash of key/value pairs
:param cb: Internal, not accessible by dbus API user
:param cbe: Internal, not accessible by dbus API user
:return: (oo) First object path is newly created object, second is
job object path if created. Each == '/' when it doesn't
apply.
"""
utils.validate_lv_name(VG_INTERFACE, self.Name, name)
r = RequestEntry(tmo, Vg._lv_create,
(self.state.Uuid, self.state.lvm_id,
name, round_size(size_bytes), pv_dests_and_ranges,
create_options), cb, cbe)
cfg.worker_q.put(r)
@staticmethod
def _lv_create_linear(uuid, vg_name, name, size_bytes,
thin_pool, create_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_lv_create_linear(
vg_name, create_options, name, size_bytes, thin_pool)
if rc == 0:
created_lv = Vg.fetch_new_lv(vg_name, name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return created_lv
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='stbia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def LvCreateLinear(self, name, size_bytes,
thin_pool, tmo, create_options, cb, cbe):
utils.validate_lv_name(VG_INTERFACE, self.Name, name)
r = RequestEntry(tmo, Vg._lv_create_linear,
(self.state.Uuid, self.state.lvm_id,
name, round_size(size_bytes), thin_pool,
create_options), cb, cbe)
cfg.worker_q.put(r)
@staticmethod
def _lv_create_striped(uuid, vg_name, name, size_bytes, num_stripes,
stripe_size_kb, thin_pool, create_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_lv_create_striped(
vg_name, create_options, name, size_bytes,
num_stripes, stripe_size_kb, thin_pool)
if rc == 0:
created_lv = Vg.fetch_new_lv(vg_name, name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return created_lv
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='stuubia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def LvCreateStriped(self, name, size_bytes, num_stripes,
stripe_size_kb, thin_pool, tmo, create_options,
cb, cbe):
utils.validate_lv_name(VG_INTERFACE, self.Name, name)
r = RequestEntry(
tmo, Vg._lv_create_striped,
(self.state.Uuid, self.state.lvm_id, name,
round_size(size_bytes), num_stripes, stripe_size_kb,
thin_pool, create_options),
cb, cbe)
cfg.worker_q.put(r)
@staticmethod
def _lv_create_mirror(uuid, vg_name, name, size_bytes,
num_copies, create_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_lv_create_mirror(
vg_name, create_options, name, size_bytes, num_copies)
if rc == 0:
created_lv = Vg.fetch_new_lv(vg_name, name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return created_lv
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='stuia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def LvCreateMirror(self, name, size_bytes, num_copies,
tmo, create_options, cb, cbe):
utils.validate_lv_name(VG_INTERFACE, self.Name, name)
r = RequestEntry(
tmo, Vg._lv_create_mirror,
(self.state.Uuid, self.state.lvm_id, name,
round_size(size_bytes), num_copies,
create_options), cb, cbe)
cfg.worker_q.put(r)
@staticmethod
def _lv_create_raid(uuid, vg_name, name, raid_type, size_bytes,
num_stripes, stripe_size_kb, create_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_lv_create_raid(
vg_name, create_options, name, raid_type, size_bytes,
num_stripes, stripe_size_kb)
if rc == 0:
created_lv = Vg.fetch_new_lv(vg_name, name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return created_lv
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='sstuuia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def LvCreateRaid(self, name, raid_type, size_bytes,
num_stripes, stripe_size_kb, tmo,
create_options, cb, cbe):
utils.validate_lv_name(VG_INTERFACE, self.Name, name)
r = RequestEntry(tmo, Vg._lv_create_raid,
(self.state.Uuid, self.state.lvm_id, name,
raid_type, round_size(size_bytes), num_stripes,
stripe_size_kb, create_options), cb, cbe)
cfg.worker_q.put(r)
@staticmethod
def _create_pool(uuid, vg_name, meta_data_lv, data_lv,
create_options, create_method):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
# Retrieve the full names for the metadata and data lv
md = cfg.om.get_object_by_path(meta_data_lv)
data = cfg.om.get_object_by_path(data_lv)
if dbo and md and data:
new_name = data.Name
rc, out, err = create_method(
md.lv_full_name(), data.lv_full_name(), create_options)
if rc == 0:
cfg.om.remove_object(md, emit_signal=True)
cfg.om.remove_object(data, emit_signal=True)
cache_pool_lv = Vg.fetch_new_lv(vg_name, new_name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
msg = ""
if not dbo:
msg += 'VG with uuid %s and name %s not present!' % \
(uuid, vg_name)
if not md:
msg += 'Meta data LV with object path %s not present!' % \
(meta_data_lv)
if not data_lv:
msg += 'Data LV with object path %s not present!' % \
(meta_data_lv)
raise dbus.exceptions.DBusException(VG_INTERFACE, msg)
return cache_pool_lv
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='ooia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def CreateCachePool(self, meta_data_lv, data_lv, tmo, create_options,
cb, cbe):
r = RequestEntry(
tmo, Vg._create_pool,
(self.state.Uuid, self.state.lvm_id, meta_data_lv,
data_lv, create_options, cmdhandler.vg_create_cache_pool), cb, cbe)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='ooia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def CreateThinPool(self, meta_data_lv, data_lv, tmo, create_options,
cb, cbe):
r = RequestEntry(
tmo, Vg._create_pool,
(self.state.Uuid, self.state.lvm_id, meta_data_lv,
data_lv, create_options, cmdhandler.vg_create_thin_pool), cb, cbe)
cfg.worker_q.put(r)
@staticmethod
def _pv_add_rm_tags(uuid, vg_name, pv_object_paths, tags_add,
tags_del, tag_options):
pv_devices = []
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
# Check for existence of pv object paths
for p in pv_object_paths:
pv = cfg.om.get_object_by_path(p)
if pv:
pv_devices.append(pv.Name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'PV object path = %s not found' % p)
rc, out, err = cmdhandler.pv_tag(
pv_devices, tags_add, tags_del, tag_options)
if rc == 0:
cfg.load()
return '/'
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='aoasia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def PvTagsAdd(self, pvs, tags, tmo, tag_options, cb, cbe):
for t in tags:
utils.validate_tag(VG_INTERFACE, t)
r = RequestEntry(tmo, Vg._pv_add_rm_tags,
(self.state.Uuid, self.state.lvm_id,
pvs, tags, None, tag_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='aoasia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def PvTagsDel(self, pvs, tags, tmo, tag_options, cb, cbe):
for t in tags:
utils.validate_tag(VG_INTERFACE, t)
r = RequestEntry(
tmo, Vg._pv_add_rm_tags,
(self.state.Uuid, self.state.lvm_id,
pvs, None, tags, tag_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@staticmethod
def _vg_add_rm_tags(uuid, vg_name, tags_add, tags_del, tag_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_tag(
vg_name, tags_add, tags_del, tag_options)
if rc == 0:
dbo.refresh()
return '/'
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='asia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def TagsAdd(self, tags, tmo, tag_options, cb, cbe):
for t in tags:
utils.validate_tag(VG_INTERFACE, t)
r = RequestEntry(tmo, Vg._vg_add_rm_tags,
(self.state.Uuid, self.state.lvm_id,
tags, None, tag_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='asia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def TagsDel(self, tags, tmo, tag_options, cb, cbe):
for t in tags:
utils.validate_tag(VG_INTERFACE, t)
r = RequestEntry(tmo, Vg._vg_add_rm_tags,
(self.state.Uuid, self.state.lvm_id,
None, tags, tag_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@staticmethod
def _vg_change_set(uuid, vg_name, method, value, options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = method(vg_name, value, options)
if rc == 0:
dbo.refresh()
return '/'
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='sia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def AllocationPolicySet(self, policy, tmo, policy_options, cb, cbe):
r = RequestEntry(tmo, Vg._vg_change_set,
(self.state.Uuid, self.state.lvm_id,
cmdhandler.vg_allocation_policy,
policy, policy_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='tia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def MaxPvSet(self, number, tmo, max_options, cb, cbe):
r = RequestEntry(tmo, Vg._vg_change_set,
(self.state.Uuid, self.state.lvm_id,
cmdhandler.vg_max_pv, number, max_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def UuidGenerate(self, tmo, options, cb, cbe):
r = RequestEntry(tmo, Vg._vg_change_set,
(self.state.Uuid, self.state.lvm_id,
cmdhandler.vg_uuid_gen, None, options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
def _attribute(self, pos, ch):
if self.state.attr[pos] == ch:
return True
return False
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='tia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def MaxLvSet(self, number, tmo, max_options, cb, cbe):
r = RequestEntry(tmo, Vg._vg_change_set,
(self.state.Uuid, self.state.lvm_id,
cmdhandler.vg_max_lv, number, max_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@staticmethod
def _vg_activate_deactivate(uuid, vg_name, activate, control_flags,
options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.activate_deactivate(
'vgchange', vg_name, activate, control_flags, options)
if rc == 0:
cfg.load()
return '/'
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='tia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def Activate(self, control_flags, tmo, activate_options, cb, cbe):
r = RequestEntry(tmo, Vg._vg_activate_deactivate,
(self.state.Uuid, self.state.lvm_id, True,
control_flags, activate_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='tia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def Deactivate(self, control_flags, tmo, activate_options, cb, cbe):
r = RequestEntry(tmo, Vg._vg_activate_deactivate,
(self.state.Uuid, self.state.lvm_id, False,
control_flags, activate_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@property
def Tags(self):
return utils.parse_tags(self.state.tags)
@property
def Pvs(self):
return self.state.Pvs
@property
def Lvs(self):
return self.state.Lvs
@property
def lvm_id(self):
return self.state.lvm_id
@property
def Writeable(self):
return self._attribute(0, 'w')
@property
def Readable(self):
return self._attribute(0, 'r')
@property
def Resizeable(self):
return self._attribute(1, 'z')
@property
def Exportable(self):
return self._attribute(2, 'x')
@property
def Partial(self):
return self._attribute(3, 'p')
@property
def AllocContiguous(self):
return self._attribute(4, 'c')
@property
def AllocCling(self):
return self._attribute(4, 'l')
@property
def AllocNormal(self):
return self._attribute(4, 'n')
@property
def AllocAnywhere(self):
return self._attribute(4, 'a')
@property
def Clustered(self):
return self._attribute(5, 'c')