2016-02-18 02:53:35 +03:00
# 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 . 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
from . loader import common
from . request import RequestEntry
from . state import State
2016-11-16 19:45:31 +03:00
from . utils import round_size
2016-02-18 02:53:35 +03:00
# noinspection PyUnusedLocal
def pvs_state_retrieve ( selection , cache_refresh = True ) :
rc = [ ]
if cache_refresh :
cfg . db . refresh ( )
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 " ] ) )
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 )
2016-06-10 20:03:04 +03:00
lv_path = cfg . om . get_object_path_by_uuid_lvm_id (
2016-02-18 02:53:35 +03:00
lv_uuid , full_name , path_create )
rc . append ( ( lv_path , segs ) )
2016-08-25 02:31:15 +03:00
return rc
2016-02-18 02:53:35 +03:00
# 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 )
lvmdbusd: Ensure vg_uuid is present
In some cases we are seeing where there are no VGs, but the data returned from
lvm shows that the PVs have the following for the VG:
"vg_name":"[unknown]", "vg_uuid":""
The code was only checking for the exitence of the VG name and we called into
the function get_object_path_by_uuid_lvm_id which requires both the VG name and
the LV name to exist (asserts this) which results in the following stack trace:
Traceback (most recent call last):
File "/home/tasleson/lvm2/daemons/lvmdbusd/utils.py", line 563, in runner
obj._run()
File "/home/tasleson/lvm2/daemons/lvmdbusd/utils.py", line 584, in _run
self.rc = self.f(*self.args)
File "/home/tasleson/lvm2/daemons/lvmdbusd/fetch.py", line 26, in
_main_thread_load
cache_refresh=False)[1]
File "/home/tasleson/lvm2/daemons/lvmdbusd/pv.py", line 48, in load_pvs
emit_signal, cache_refresh)
File "/home/tasleson/lvm2/daemons/lvmdbusd/loader.py", line 37, in common
objects = retrieve(search_keys, cache_refresh=False)
File "/home/tasleson/lvm2/daemons/lvmdbusd/pv.py", line 40, in
pvs_state_retrieve
p["pv_attr"], p["pv_tags"], p["vg_name"], p["vg_uuid"]))
File "/home/tasleson/lvm2/daemons/lvmdbusd/pv.py", line 84, in __init__
vg_uuid, vg_name, vg_obj_path_generate)
File "/home/tasleson/lvm2/daemons/lvmdbusd/objectmanager.py", line 318,
in get_object_path_by_uuid_lvm_id
assert uuid
AssertionError
2017-09-21 00:39:35 +03:00
# 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 :
2016-06-10 20:03:04 +03:00
self . vg_path = cfg . om . get_object_path_by_uuid_lvm_id (
2016-02-18 02:53:35 +03:00
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 :
2016-06-10 20:03:04 +03:00
path = cfg . om . get_object_path_by_uuid_lvm_id ( self . Uuid , self . Name ,
pv_obj_path_generate )
2016-02-18 02:53:35 +03:00
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
2017-02-02 01:51:00 +03:00
Pv . validate_dbus_object ( pv_uuid , pv_name )
rc , out , err = cmdhandler . pv_remove ( pv_name , remove_options )
Pv . handle_execute ( rc , out , err )
return ' / '
2016-02-18 02:53:35 +03:00
2017-02-02 01:51:00 +03:00
@staticmethod
def handle_execute ( rc , out , err ) :
if rc == 0 :
cfg . load ( )
2016-02-18 02:53:35 +03:00
else :
2017-02-02 01:51:00 +03:00
# Need to work on error handling, need consistent
raise dbus . exceptions . DBusException (
PV_INTERFACE ,
' Exit code %s , stderr = %s ' % ( str ( rc ) , err ) )
@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 :
2016-02-18 02:53:35 +03:00
raise dbus . exceptions . DBusException (
PV_INTERFACE ,
' PV with uuid %s and name %s not present! ' %
( pv_uuid , pv_name ) )
2017-02-02 01:51:00 +03:00
return dbo
2016-02-18 02:53:35 +03:00
@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
2017-02-02 01:51:00 +03:00
Pv . validate_dbus_object ( pv_uuid , pv_name )
2016-02-18 02:53:35 +03:00
2017-02-02 01:51:00 +03:00
rc , out , err = cmdhandler . pv_resize ( pv_name , new_size_bytes ,
2016-02-18 02:53:35 +03:00
resize_options )
2017-02-02 01:51:00 +03:00
Pv . handle_execute ( rc , out , err )
2016-02-18 02:53:35 +03:00
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
2017-02-02 01:51:00 +03:00
Pv . validate_dbus_object ( pv_uuid , pv_name )
rc , out , err = cmdhandler . pv_allocatable (
pv_name , yes_no , allocation_options )
Pv . handle_execute ( rc , out , err )
2016-02-18 02:53:35 +03:00
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 ) :
2016-08-25 02:31:15 +03:00
return dbus . Array ( self . state . pe_segments , signature = ' (tt) ' )
2016-08-29 20:33:00 +03:00
return dbus . Array ( [ ] , ' (tt) ' )
2016-02-18 02:53:35 +03:00
@property
def Exportable ( self ) :
2016-08-25 02:31:15 +03:00
return dbus . Boolean ( self . state . attr [ 1 ] == ' x ' )
2016-02-18 02:53:35 +03:00
@property
def Allocatable ( self ) :
2016-08-25 02:31:15 +03:00
return dbus . Boolean ( self . state . attr [ 0 ] == ' a ' )
2016-02-18 02:53:35 +03:00
@property
def Missing ( self ) :
2016-08-25 02:31:15 +03:00
return dbus . Boolean ( self . state . attr [ 2 ] == ' m ' )
2016-02-18 02:53:35 +03:00
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 ) :
2016-08-25 02:31:15 +03:00
return dbus . Array ( self . state . lv , signature = " (oa(tts)) " )
2016-02-18 02:53:35 +03:00
@property
def Vg ( self ) :
2016-08-25 02:31:15 +03:00
return dbus . ObjectPath ( self . state . vg_path )