# 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 . from .automatedproperties import AutomatedProperties from . import utils from . import cfg import dbus from .cfg import PV_INTERFACE from . import cmdhandler from .utils import vg_obj_path_generate, n, pv_obj_path_generate, \ lv_object_path_method, _handle_execute, lvm_column_key from .loader import common from .request import RequestEntry from .state import State from .utils import round_size, LvmBug # noinspection PyUnusedLocal def pvs_state_retrieve(selection, cache_refresh=True): rc = [] if cache_refresh: cfg.db.refresh() try: for p in cfg.db.fetch_pvs(selection): rc.append( PvState( p["pv_name"], p["pv_uuid"], p["pv_name"], p["pv_fmt"], n(p["pv_size"]), n(p["pv_free"]), n(p["pv_used"]), n(p["dev_size"]), n(p["pv_mda_size"]), n(p["pv_mda_free"]), int(p["pv_ba_start"]), n(p["pv_ba_size"]), n(p["pe_start"]), int(p["pv_pe_count"]), int(p["pv_pe_alloc_count"]), p["pv_attr"], p["pv_tags"], p["vg_name"], p["vg_uuid"])) except KeyError as ke: # Sometimes lvm omits returning one of the keys we requested. key = ke.args[0] if lvm_column_key(key): raise LvmBug("missing JSON key: '%s'" % key) raise ke return rc def load_pvs(device=None, object_path=None, refresh=False, emit_signal=False, cache_refresh=True): return common( pvs_state_retrieve, (Pv,), device, object_path, refresh, emit_signal, cache_refresh) # noinspection PyUnresolvedReferences class PvState(State): @property def lvm_id(self): return self.lvm_path def _lv_object_list(self, vg_name): rc = [] if vg_name: for lv in sorted(cfg.db.pv_contained_lv(self.lvm_id)): lv_uuid, lv_name, meta, segs = lv full_name = "%s/%s" % (vg_name, lv_name) path_create = lv_object_path_method(lv_name, meta) lv_path = cfg.om.get_object_path_by_uuid_lvm_id( lv_uuid, full_name, path_create) rc.append((lv_path, segs)) return rc # noinspection PyUnusedLocal,PyPep8Naming def __init__(self, lvm_path, Uuid, Name, Fmt, SizeBytes, FreeBytes, UsedBytes, DevSizeBytes, MdaSizeBytes, MdaFreeBytes, BaStart, BaSizeBytes, PeStart, PeCount, PeAllocCount, attr, Tags, vg_name, vg_uuid): utils.init_class_from_arguments(self) self.pe_segments = cfg.db.pv_pe_segments(Uuid) self.lv = self._lv_object_list(vg_name) # It's possible to have a vg_name and no uuid with the main example # being when the vg_name == '[unknown]' if vg_uuid and vg_name: self.vg_path = cfg.om.get_object_path_by_uuid_lvm_id( vg_uuid, vg_name, vg_obj_path_generate) else: self.vg_path = '/' def identifiers(self): return (self.Uuid, self.lvm_path) def create_dbus_object(self, path): if not path: path = cfg.om.get_object_path_by_uuid_lvm_id(self.Uuid, self.Name, pv_obj_path_generate) return Pv(path, self) # noinspection PyMethodMayBeStatic def creation_signature(self): return (Pv, pv_obj_path_generate) # noinspection PyPep8Naming @utils.dbus_property(PV_INTERFACE, 'Uuid', 's') # PV UUID/pv_uuid @utils.dbus_property(PV_INTERFACE, 'Name', 's') # PV/pv_name @utils.dbus_property(PV_INTERFACE, 'Fmt', 's') # Fmt/pv_fmt @utils.dbus_property(PV_INTERFACE, 'SizeBytes', 't') # PSize/pv_size @utils.dbus_property(PV_INTERFACE, 'FreeBytes', 't') # PFree/pv_free @utils.dbus_property(PV_INTERFACE, 'UsedBytes', 't') # Used/pv_used @utils.dbus_property(PV_INTERFACE, 'DevSizeBytes', 't') # DevSize/dev_size @utils.dbus_property(PV_INTERFACE, 'MdaSizeBytes', 't') # PMdaSize/pv_mda_size @utils.dbus_property(PV_INTERFACE, 'MdaFreeBytes', 't') # PMdaFree/pv_mda_free @utils.dbus_property(PV_INTERFACE, 'BaStart', 't') # BA start/pv_ba_start @utils.dbus_property(PV_INTERFACE, 'BaSizeBytes', 't') # BA size/pv_ba_size @utils.dbus_property(PV_INTERFACE, 'PeStart', 't') # 1st PE/pe_start @utils.dbus_property(PV_INTERFACE, 'PeCount', 't') # PE/pv_pe_count @utils.dbus_property(PV_INTERFACE, 'PeAllocCount', 't') # PE Allocation count class Pv(AutomatedProperties): # For properties that we need custom handlers we need these, otherwise # we won't get our introspection data _Tags_meta = ("as", PV_INTERFACE) _PeSegments_meta = ("a(tt)", PV_INTERFACE) _Exportable_meta = ("b", PV_INTERFACE) _Allocatable_meta = ("b", PV_INTERFACE) _Missing_meta = ("b", PV_INTERFACE) _Lv_meta = ("a(oa(tts))", PV_INTERFACE) _Vg_meta = ("o", PV_INTERFACE) # noinspection PyUnusedLocal,PyPep8Naming def __init__(self, object_path, state_obj): super(Pv, self).__init__(object_path, pvs_state_retrieve) self.set_interface(PV_INTERFACE) self.state = state_obj @staticmethod def _remove(pv_uuid, pv_name, remove_options): # Remove the PV, if successful then remove from the model # Make sure we have a dbus object representing it Pv.validate_dbus_object(pv_uuid, pv_name) Pv.handle_execute(*cmdhandler.pv_remove(pv_name, remove_options)) return '/' @staticmethod def handle_execute(rc, out, err): return _handle_execute(rc, out, err, PV_INTERFACE) @staticmethod def validate_dbus_object(pv_uuid, pv_name): dbo = cfg.om.get_object_by_uuid_lvm_id(pv_uuid, pv_name) if not dbo: raise dbus.exceptions.DBusException( PV_INTERFACE, 'PV with uuid %s and name %s not present!' % (pv_uuid, pv_name)) return dbo @dbus.service.method( dbus_interface=PV_INTERFACE, in_signature='ia{sv}', out_signature='o', async_callbacks=('cb', 'cbe')) def Remove(self, tmo, remove_options, cb, cbe): r = RequestEntry( tmo, Pv._remove, (self.Uuid, self.lvm_id, remove_options), cb, cbe, return_tuple=False) cfg.worker_q.put(r) @staticmethod def _resize(pv_uuid, pv_name, new_size_bytes, resize_options): # Make sure we have a dbus object representing it Pv.validate_dbus_object(pv_uuid, pv_name) Pv.handle_execute(*cmdhandler.pv_resize(pv_name, new_size_bytes, resize_options)) return '/' @dbus.service.method( dbus_interface=PV_INTERFACE, in_signature='tia{sv}', out_signature='o', async_callbacks=('cb', 'cbe')) def ReSize(self, new_size_bytes, tmo, resize_options, cb, cbe): r = RequestEntry( tmo, Pv._resize, (self.Uuid, self.lvm_id, round_size(new_size_bytes), resize_options), cb, cbe, False) cfg.worker_q.put(r) @staticmethod def _allocation_enabled(pv_uuid, pv_name, yes_no, allocation_options): # Make sure we have a dbus object representing it Pv.validate_dbus_object(pv_uuid, pv_name) Pv.handle_execute(*cmdhandler.pv_allocatable(pv_name, yes_no, allocation_options)) return '/' @dbus.service.method( dbus_interface=PV_INTERFACE, in_signature='bia{sv}', out_signature='o', async_callbacks=('cb', 'cbe')) def AllocationEnabled(self, yes, tmo, allocation_options, cb, cbe): r = RequestEntry( tmo, Pv._allocation_enabled, (self.Uuid, self.lvm_id, yes, allocation_options), cb, cbe, False) cfg.worker_q.put(r) @property def Tags(self): return utils.parse_tags(self.state.Tags) @property def PeSegments(self): if len(self.state.pe_segments): return dbus.Array(self.state.pe_segments, signature='(tt)') return dbus.Array([], '(tt)') @property def Exportable(self): return dbus.Boolean(self.state.attr[1] == 'x') @property def Allocatable(self): return dbus.Boolean(self.state.attr[0] == 'a') @property def Missing(self): return dbus.Boolean(self.state.attr[2] == 'm') def object_path(self): return self._object_path @property def lvm_id(self): return self.state.lvm_id @property def identifiers(self): return self.state.identifiers() @property def Lv(self): return dbus.Array(self.state.lv, signature="(oa(tts))") @property def Vg(self): return dbus.ObjectPath(self.state.vg_path)