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 . utils import vg_obj_path_generate
import dbus
from . import cmdhandler
from . import cfg
from . cfg import LV_INTERFACE , THIN_POOL_INTERFACE , SNAPSHOT_INTERFACE , \
LV_COMMON_INTERFACE , CACHE_POOL_INTERFACE , LV_CACHED
from . request import RequestEntry
from . utils import n , n32
from . loader import common
from . state import State
from . import background
from . utils import round_size
2016-06-28 20:07:21 +03:00
from . job import JobState
2016-02-18 02:53:35 +03:00
2016-06-10 19:58:55 +03:00
# Try and build a key for a LV, so that we sort the LVs with least dependencies
# first. This may be error prone because of the flexibility LVM
# provides and what you can stack.
def get_key ( i ) :
name = i [ ' lv_name ' ]
parent = i [ ' lv_parent ' ]
pool = i [ ' pool_lv ' ]
a1 = " "
a2 = " "
if name [ 0 ] == ' [ ' :
a1 = ' # '
# We have a parent
if parent :
# Check if parent is hidden
if parent [ 0 ] == ' [ ' :
a2 = ' ## '
else :
a2 = ' # '
# If a LV has a pool, then it should be sorted/loaded after the pool
# lv, unless it's a hidden too, then after other hidden, but before visible
if pool :
if pool [ 0 ] != ' [ ' :
a2 + = ' ~ '
else :
a1 = ' $ ' + a1
return " %s %s %s " % ( a1 , a2 , name )
2016-02-18 02:53:35 +03:00
# noinspection PyUnusedLocal
def lvs_state_retrieve ( selection , cache_refresh = True ) :
rc = [ ]
if cache_refresh :
cfg . db . refresh ( )
2016-06-10 19:58:55 +03:00
# When building up the model, it's best to process LVs with the least
# dependencies to those that are dependant upon other LVs. Otherwise, when
# we are trying to gather information we could be in a position where we
# don't have information available yet.
lvs = sorted ( cfg . db . fetch_lvs ( selection ) , key = get_key )
for l in lvs :
2016-02-18 02:53:35 +03:00
rc . append ( LvState (
l [ ' lv_uuid ' ] , l [ ' lv_name ' ] ,
l [ ' lv_path ' ] , n ( l [ ' lv_size ' ] ) ,
l [ ' vg_name ' ] ,
l [ ' vg_uuid ' ] , l [ ' pool_lv_uuid ' ] ,
l [ ' pool_lv ' ] , l [ ' origin_uuid ' ] , l [ ' origin ' ] ,
n32 ( l [ ' data_percent ' ] ) , l [ ' lv_attr ' ] ,
l [ ' lv_tags ' ] , l [ ' lv_active ' ] , l [ ' data_lv ' ] ,
l [ ' metadata_lv ' ] , l [ ' segtype ' ] , l [ ' lv_role ' ] ,
l [ ' lv_layout ' ] ) )
return rc
def load_lvs ( lv_name = None , object_path = None , refresh = False , emit_signal = False ,
cache_refresh = True ) :
# noinspection PyUnresolvedReferences
return common (
lvs_state_retrieve ,
( LvCommon , Lv , LvThinPool , LvSnapShot ) ,
lv_name , object_path , refresh , emit_signal , cache_refresh )
# noinspection PyPep8Naming,PyUnresolvedReferences,PyUnusedLocal
class LvState ( State ) :
@staticmethod
def _pv_devices ( uuid ) :
rc = [ ]
for pv in sorted ( cfg . db . lv_contained_pv ( uuid ) ) :
( pv_uuid , pv_name , pv_segs ) = pv
2016-06-10 20:03:04 +03:00
pv_obj = cfg . om . get_object_path_by_uuid_lvm_id (
2016-02-18 02:53:35 +03:00
pv_uuid , pv_name , gen_new = False )
rc . append ( ( pv_obj , pv_segs ) )
return dbus . Array ( rc , signature = " (oa(tts)) " )
def vg_name_lookup ( self ) :
return cfg . om . get_object_by_path ( self . Vg ) . Name
@property
def lvm_id ( self ) :
return " %s / %s " % ( self . vg_name_lookup ( ) , self . Name )
def identifiers ( self ) :
return ( self . Uuid , self . lvm_id )
def _get_hidden_lv ( self ) :
rc = dbus . Array ( [ ] , " o " )
vg_name = self . vg_name_lookup ( )
for l in cfg . db . hidden_lvs ( self . Uuid ) :
full_name = " %s / %s " % ( vg_name , l [ 1 ] )
2016-06-10 20:03:04 +03:00
op = cfg . om . get_object_path_by_uuid_lvm_id (
2016-02-18 02:53:35 +03:00
l [ 0 ] , full_name , gen_new = False )
assert op
rc . append ( op )
return rc
def __init__ ( self , Uuid , Name , Path , SizeBytes ,
vg_name , vg_uuid , pool_lv_uuid , PoolLv ,
origin_uuid , OriginLv , DataPercent , Attr , Tags , active ,
data_lv , metadata_lv , segtypes , role , layout ) :
utils . init_class_from_arguments ( self )
# The segtypes is possibly an array with potentially dupes or a single
# value
self . _segs = dbus . Array ( [ ] , signature = ' s ' )
if not isinstance ( segtypes , list ) :
self . _segs . append ( segtypes )
else :
self . _segs . extend ( set ( segtypes ) )
2016-06-10 20:03:04 +03:00
self . Vg = 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 )
self . Devices = LvState . _pv_devices ( self . Uuid )
if PoolLv :
gen = utils . lv_object_path_method ( Name , ( Attr , layout , role ) )
2016-06-10 20:03:04 +03:00
self . PoolLv = cfg . om . get_object_path_by_uuid_lvm_id (
2016-02-18 02:53:35 +03:00
pool_lv_uuid , ' %s / %s ' % ( vg_name , PoolLv ) ,
gen )
else :
self . PoolLv = ' / '
if OriginLv :
self . OriginLv = \
2016-06-10 20:03:04 +03:00
cfg . om . get_object_path_by_uuid_lvm_id (
2016-02-18 02:53:35 +03:00
origin_uuid , ' %s / %s ' % ( vg_name , OriginLv ) ,
vg_obj_path_generate )
else :
self . OriginLv = ' / '
self . HiddenLvs = self . _get_hidden_lv ( )
@property
def SegType ( self ) :
return self . _segs
def _object_path_create ( self ) :
return utils . lv_object_path_method (
self . Name , ( self . Attr , self . layout , self . role ) )
def _object_type_create ( self ) :
if self . Attr [ 0 ] == ' t ' :
return LvThinPool
elif self . Attr [ 0 ] == ' C ' :
if ' pool ' in self . layout :
return LvCachePool
else :
return LvCacheLv
2016-06-10 20:11:17 +03:00
elif self . Name [ 0 ] == ' [ ' :
return LvCommon
2016-02-18 02:53:35 +03:00
elif self . OriginLv != ' / ' :
return LvSnapShot
else :
return Lv
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 (
2016-02-18 02:53:35 +03:00
self . Uuid , self . lvm_id , self . _object_path_create ( ) )
obj_ctor = self . _object_type_create ( )
return obj_ctor ( path , self )
def creation_signature ( self ) :
klass = self . _object_type_create ( )
path_method = self . _object_path_create ( )
return ( klass , path_method )
# noinspection PyPep8Naming
@utils.dbus_property ( LV_COMMON_INTERFACE , ' Uuid ' , ' s ' )
@utils.dbus_property ( LV_COMMON_INTERFACE , ' Name ' , ' s ' )
@utils.dbus_property ( LV_COMMON_INTERFACE , ' Path ' , ' s ' )
@utils.dbus_property ( LV_COMMON_INTERFACE , ' SizeBytes ' , ' t ' )
@utils.dbus_property ( LV_COMMON_INTERFACE , ' DataPercent ' , ' u ' )
@utils.dbus_property ( LV_COMMON_INTERFACE , ' SegType ' , ' as ' )
@utils.dbus_property ( LV_COMMON_INTERFACE , ' Vg ' , ' o ' )
@utils.dbus_property ( LV_COMMON_INTERFACE , ' OriginLv ' , ' o ' )
@utils.dbus_property ( LV_COMMON_INTERFACE , ' PoolLv ' , ' o ' )
@utils.dbus_property ( LV_COMMON_INTERFACE , ' Devices ' , " a(oa(tts)) " )
@utils.dbus_property ( LV_COMMON_INTERFACE , ' HiddenLvs ' , " ao " )
class LvCommon ( AutomatedProperties ) :
_Tags_meta = ( " as " , LV_COMMON_INTERFACE )
2016-06-04 01:07:37 +03:00
_Roles_meta = ( " as " , LV_COMMON_INTERFACE )
2016-02-18 02:53:35 +03:00
_IsThinVolume_meta = ( " b " , LV_COMMON_INTERFACE )
_IsThinPool_meta = ( " b " , LV_COMMON_INTERFACE )
_Active_meta = ( " b " , LV_COMMON_INTERFACE )
_VolumeType_meta = ( " (ss) " , LV_COMMON_INTERFACE )
_Permissions_meta = ( " (ss) " , LV_COMMON_INTERFACE )
_AllocationPolicy_meta = ( " (ss) " , LV_COMMON_INTERFACE )
_State_meta = ( " (ss) " , LV_COMMON_INTERFACE )
_TargetType_meta = ( " (ss) " , LV_COMMON_INTERFACE )
_Health_meta = ( " (ss) " , LV_COMMON_INTERFACE )
_FixedMinor_meta = ( ' b ' , LV_COMMON_INTERFACE )
_ZeroBlocks_meta = ( ' b ' , LV_COMMON_INTERFACE )
_SkipActivation_meta = ( ' b ' , LV_COMMON_INTERFACE )
# noinspection PyUnusedLocal,PyPep8Naming
def __init__ ( self , object_path , object_state ) :
super ( LvCommon , self ) . __init__ ( object_path , lvs_state_retrieve )
self . set_interface ( LV_COMMON_INTERFACE )
self . state = object_state
@property
def VolumeType ( self ) :
type_map = { ' C ' : ' Cache ' , ' m ' : ' mirrored ' ,
' M ' : ' Mirrored without initial sync ' , ' o ' : ' origin ' ,
' O ' : ' Origin with merging snapshot ' , ' r ' : ' raid ' ,
' R ' : ' Raid without initial sync ' , ' s ' : ' snapshot ' ,
' S ' : ' merging Snapshot ' , ' p ' : ' pvmove ' ,
' v ' : ' virtual ' , ' i ' : ' mirror or raid image ' ,
' I ' : ' mirror or raid Image out-of-sync ' ,
' l ' : ' mirror log device ' , ' c ' : ' under conversion ' ,
' V ' : ' thin Volume ' , ' t ' : ' thin pool ' , ' T ' : ' Thin pool data ' ,
' e ' : ' raid or pool metadata or pool metadata spare ' ,
' - ' : ' Unspecified ' }
return ( self . state . Attr [ 0 ] , type_map [ self . state . Attr [ 0 ] ] )
@property
def Permissions ( self ) :
type_map = { ' w ' : ' writable ' , ' r ' : ' read-only ' ,
' R ' : ' Read-only activation of non-read-only volume ' ,
' - ' : ' Unspecified ' }
return ( self . state . Attr [ 1 ] , type_map [ self . state . Attr [ 1 ] ] )
@property
def AllocationPolicy ( self ) :
type_map = { ' a ' : ' anywhere ' , ' A ' : ' anywhere locked ' ,
' c ' : ' contiguous ' , ' C ' : ' contiguous locked ' ,
' i ' : ' inherited ' , ' I ' : ' inherited locked ' ,
' l ' : ' cling ' , ' L ' : ' cling locked ' ,
' n ' : ' normal ' , ' N ' : ' normal locked ' , ' - ' : ' Unspecified ' }
return ( self . state . Attr [ 2 ] , type_map [ self . state . Attr [ 2 ] ] )
@property
def FixedMinor ( self ) :
return self . state . Attr [ 3 ] == ' m '
@property
def State ( self ) :
type_map = { ' a ' : ' active ' , ' s ' : ' suspended ' , ' I ' : ' Invalid snapshot ' ,
' S ' : ' invalid Suspended snapshot ' ,
' m ' : ' snapshot merge failed ' ,
' M ' : ' suspended snapshot (M)erge failed ' ,
' d ' : ' mapped device present without tables ' ,
' i ' : ' mapped device present with inactive table ' ,
' X ' : ' unknown ' , ' - ' : ' Unspecified ' }
return ( self . state . Attr [ 4 ] , type_map [ self . state . Attr [ 4 ] ] )
@property
def TargetType ( self ) :
type_map = { ' C ' : ' Cache ' , ' m ' : ' mirror ' , ' r ' : ' raid ' ,
' s ' : ' snapshot ' , ' t ' : ' thin ' , ' u ' : ' unknown ' ,
' v ' : ' virtual ' , ' - ' : ' Unspecified ' }
return ( self . state . Attr [ 6 ] , type_map [ self . state . Attr [ 6 ] ] )
@property
def ZeroBlocks ( self ) :
return self . state . Attr [ 7 ] == ' z '
@property
def Health ( self ) :
type_map = { ' p ' : ' partial ' , ' r ' : ' refresh ' ,
' m ' : ' mismatches ' , ' w ' : ' writemostly ' ,
' X ' : ' X unknown ' , ' - ' : ' Unspecified ' }
return ( self . state . Attr [ 8 ] , type_map [ self . state . Attr [ 8 ] ] )
@property
def SkipActivation ( self ) :
return self . state . Attr [ 9 ] == ' k '
def vg_name_lookup ( self ) :
return self . state . vg_name_lookup ( )
def lv_full_name ( self ) :
return " %s / %s " % ( self . state . vg_name_lookup ( ) , self . state . Name )
@property
def identifiers ( self ) :
return self . state . identifiers
@property
def Tags ( self ) :
return utils . parse_tags ( self . state . Tags )
2016-06-04 01:07:37 +03:00
@property
def Roles ( self ) :
return utils . parse_tags ( self . state . role )
2016-02-18 02:53:35 +03:00
@property
def lvm_id ( self ) :
return self . state . lvm_id
@property
def IsThinVolume ( self ) :
return self . state . Attr [ 0 ] == ' V '
@property
def IsThinPool ( self ) :
return self . state . Attr [ 0 ] == ' t '
@property
def Active ( self ) :
return self . state . active == " active "
@dbus.service.method (
dbus_interface = LV_COMMON_INTERFACE ,
in_signature = ' ia {sv} ' ,
out_signature = ' o ' )
def _Future ( self , tmo , open_options ) :
raise dbus . exceptions . DBusException ( LV_COMMON_INTERFACE , ' Do not use! ' )
# noinspection PyPep8Naming
class Lv ( LvCommon ) :
2016-06-06 23:03:02 +03:00
def _fetch_hidden ( self , name ) :
# The name is vg/name
full_name = " %s / %s " % ( self . vg_name_lookup ( ) , name )
2016-06-10 20:05:52 +03:00
return cfg . om . get_object_path_by_lvm_id ( full_name )
2016-06-06 23:03:02 +03:00
def _get_data_meta ( self ) :
# Get the data
return ( self . _fetch_hidden ( self . state . data_lv ) ,
self . _fetch_hidden ( self . state . metadata_lv ) )
2016-02-18 02:53:35 +03:00
# noinspection PyUnusedLocal,PyPep8Naming
def __init__ ( self , object_path , object_state ) :
super ( Lv , self ) . __init__ ( object_path , object_state )
self . set_interface ( LV_INTERFACE )
self . state = object_state
@staticmethod
def _remove ( lv_uuid , lv_name , remove_options ) :
# Make sure we have a dbus object representing it
dbo = cfg . om . get_object_by_uuid_lvm_id ( lv_uuid , lv_name )
if dbo :
# Remove the LV, if successful then remove from the model
rc , out , err = cmdhandler . lv_remove ( lv_name , remove_options )
if rc == 0 :
cfg . om . remove_object ( dbo , True )
cfg . load ( )
else :
# Need to work on error handling, need consistent
raise dbus . exceptions . DBusException (
LV_INTERFACE ,
' Exit code %s , stderr = %s ' % ( str ( rc ) , err ) )
else :
raise dbus . exceptions . DBusException (
LV_INTERFACE ,
' LV with uuid %s and name %s not present! ' %
( lv_uuid , lv_name ) )
return ' / '
@dbus.service.method (
dbus_interface = LV_INTERFACE ,
in_signature = ' ia {sv} ' ,
out_signature = ' o ' ,
async_callbacks = ( ' cb ' , ' cbe ' ) )
def Remove ( self , tmo , remove_options , cb , cbe ) :
r = RequestEntry (
tmo , Lv . _remove ,
( self . Uuid , self . lvm_id , remove_options ) ,
cb , cbe , False )
cfg . worker_q . put ( r )
@staticmethod
def _rename ( lv_uuid , lv_name , new_name , rename_options ) :
# Make sure we have a dbus object representing it
dbo = cfg . om . get_object_by_uuid_lvm_id ( lv_uuid , lv_name )
if dbo :
# Rename the logical volume
rc , out , err = cmdhandler . lv_rename ( lv_name , new_name ,
rename_options )
if rc == 0 :
cfg . load ( )
else :
# Need to work on error handling, need consistent
raise dbus . exceptions . DBusException (
LV_INTERFACE ,
' Exit code %s , stderr = %s ' % ( str ( rc ) , err ) )
else :
raise dbus . exceptions . DBusException (
LV_INTERFACE ,
' LV with uuid %s and name %s not present! ' %
( lv_uuid , lv_name ) )
return ' / '
@dbus.service.method (
dbus_interface = LV_INTERFACE ,
in_signature = ' sia {sv} ' ,
out_signature = ' o ' ,
async_callbacks = ( ' cb ' , ' cbe ' ) )
def Rename ( self , name , tmo , rename_options , cb , cbe ) :
2016-02-18 03:27:57 +03:00
utils . validate_lv_name ( LV_INTERFACE , self . vg_name_lookup ( ) , name )
2016-02-18 02:53:35 +03:00
r = RequestEntry (
tmo , Lv . _rename ,
( self . Uuid , self . lvm_id , name , rename_options ) ,
cb , cbe , False )
cfg . worker_q . put ( r )
@dbus.service.method (
dbus_interface = LV_INTERFACE ,
in_signature = ' o(tt)a(ott)ia {sv} ' ,
2016-06-28 20:07:21 +03:00
out_signature = ' o ' ,
async_callbacks = ( ' cb ' , ' cbe ' ) )
2016-02-18 02:53:35 +03:00
def Move ( self , pv_src_obj , pv_source_range ,
pv_dests_and_ranges ,
2016-06-28 20:07:21 +03:00
tmo , move_options , cb , cbe ) :
job_state = JobState ( )
r = RequestEntry (
tmo , background . move ,
( LV_INTERFACE , self . lvm_id , pv_src_obj , pv_source_range ,
pv_dests_and_ranges , move_options , job_state ) , cb , cbe , False ,
job_state )
cfg . worker_q . put ( r )
2016-02-18 02:53:35 +03:00
@staticmethod
def _snap_shot ( lv_uuid , lv_name , name , optional_size ,
snapshot_options ) :
# Make sure we have a dbus object representing it
dbo = cfg . om . get_object_by_uuid_lvm_id ( lv_uuid , lv_name )
if dbo :
# If you specify a size you get a 'thick' snapshot even if
# it is a thin lv
if not dbo . IsThinVolume :
if optional_size == 0 :
# TODO: Should we pick a sane default or force user to
# make a decision?
space = dbo . SizeBytes / 80
remainder = space % 512
optional_size = space + 512 - remainder
rc , out , err = cmdhandler . vg_lv_snapshot (
lv_name , snapshot_options , name , optional_size )
if rc == 0 :
return_path = ' / '
full_name = " %s / %s " % ( dbo . vg_name_lookup ( ) , name )
lvs = load_lvs ( [ full_name ] , emit_signal = True ) [ 0 ]
for l in lvs :
return_path = l . dbus_object_path ( )
# Refresh self and all included PVs
cfg . load ( cache_refresh = False )
return return_path
else :
raise dbus . exceptions . DBusException (
LV_INTERFACE ,
' Exit code %s , stderr = %s ' % ( str ( rc ) , err ) )
else :
raise dbus . exceptions . DBusException (
LV_INTERFACE ,
' LV with uuid %s and name %s not present! ' %
( lv_uuid , lv_name ) )
@dbus.service.method (
dbus_interface = LV_INTERFACE ,
in_signature = ' stia {sv} ' ,
out_signature = ' (oo) ' ,
async_callbacks = ( ' cb ' , ' cbe ' ) )
def Snapshot ( self , name , optional_size , tmo ,
snapshot_options , cb , cbe ) :
2016-02-18 03:27:57 +03:00
utils . validate_lv_name ( LV_INTERFACE , self . vg_name_lookup ( ) , name )
2016-02-18 02:53:35 +03:00
r = RequestEntry (
tmo , Lv . _snap_shot ,
( self . Uuid , self . lvm_id , name ,
optional_size , snapshot_options ) , cb , cbe )
cfg . worker_q . put ( r )
@staticmethod
def _resize ( lv_uuid , lv_name , new_size_bytes , pv_dests_and_ranges ,
resize_options ) :
# Make sure we have a dbus object representing it
pv_dests = [ ]
dbo = cfg . om . get_object_by_uuid_lvm_id ( lv_uuid , lv_name )
if dbo :
# If we have PVs, verify them
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 (
LV_INTERFACE ,
' PV Destination ( %s ) not found ' % pr [ 0 ] )
pv_dests . append ( ( pv_dbus_obj . lvm_id , pr [ 1 ] , pr [ 2 ] ) )
size_change = new_size_bytes - dbo . SizeBytes
rc , out , err = cmdhandler . lv_resize ( dbo . lvm_id , size_change ,
pv_dests , resize_options )
if rc == 0 :
# Refresh what's changed
cfg . load ( )
return " / "
else :
raise dbus . exceptions . DBusException (
LV_INTERFACE ,
' Exit code %s , stderr = %s ' % ( str ( rc ) , err ) )
else :
raise dbus . exceptions . DBusException (
LV_INTERFACE ,
' LV with uuid %s and name %s not present! ' %
( lv_uuid , lv_name ) )
@dbus.service.method (
dbus_interface = LV_INTERFACE ,
in_signature = ' ta(ott)ia {sv} ' ,
out_signature = ' o ' ,
async_callbacks = ( ' cb ' , ' cbe ' ) )
def Resize ( self , new_size_bytes , pv_dests_and_ranges , tmo ,
resize_options , cb , cbe ) :
"""
Resize a LV
: param new_size_bytes : The requested final size in bytes
: param pv_dests_and_ranges : An array of pv object paths and src &
dst . segment ranges
: param tmo : - 1 to wait forever , 0 to return job immediately , else
number of seconds to wait for operation to complete
before getting a job
: param resize_options : key / value hash of options
: param cb : Used by framework not client facing API
: param cbe : Used by framework not client facing API
: return : ' / ' if complete , else job object path
"""
r = RequestEntry (
tmo , Lv . _resize ,
( self . Uuid , self . lvm_id , round_size ( new_size_bytes ) ,
pv_dests_and_ranges ,
resize_options ) , cb , cbe , return_tuple = False )
cfg . worker_q . put ( r )
@staticmethod
def _lv_activate_deactivate ( uuid , lv_name , activate , control_flags ,
options ) :
# Make sure we have a dbus object representing it
dbo = cfg . om . get_object_by_uuid_lvm_id ( uuid , lv_name )
if dbo :
rc , out , err = cmdhandler . activate_deactivate (
' lvchange ' , lv_name , activate , control_flags , options )
if rc == 0 :
dbo . refresh ( )
return ' / '
else :
raise dbus . exceptions . DBusException (
LV_INTERFACE ,
' Exit code %s , stderr = %s ' % ( str ( rc ) , err ) )
else :
raise dbus . exceptions . DBusException (
LV_INTERFACE ,
' LV with uuid %s and name %s not present! ' %
( uuid , lv_name ) )
@dbus.service.method (
dbus_interface = LV_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 , Lv . _lv_activate_deactivate ,
( self . state . Uuid , self . state . lvm_id , True ,
control_flags , activate_options ) ,
cb , cbe , return_tuple = False )
cfg . worker_q . put ( r )
# noinspection PyProtectedMember
@dbus.service.method (
dbus_interface = LV_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 , Lv . _lv_activate_deactivate ,
( self . state . Uuid , self . state . lvm_id , False ,
control_flags , activate_options ) ,
cb , cbe , return_tuple = False )
cfg . worker_q . put ( r )
@staticmethod
def _add_rm_tags ( uuid , lv_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 , lv_name )
if dbo :
rc , out , err = cmdhandler . lv_tag (
lv_name , tags_add , tags_del , tag_options )
if rc == 0 :
dbo . refresh ( )
return ' / '
else :
raise dbus . exceptions . DBusException (
LV_INTERFACE ,
' Exit code %s , stderr = %s ' % ( str ( rc ) , err ) )
else :
raise dbus . exceptions . DBusException (
LV_INTERFACE ,
' LV with uuid %s and name %s not present! ' %
( uuid , lv_name ) )
@dbus.service.method (
dbus_interface = LV_INTERFACE ,
in_signature = ' asia {sv} ' ,
out_signature = ' o ' ,
async_callbacks = ( ' cb ' , ' cbe ' ) )
def TagsAdd ( self , tags , tmo , tag_options , cb , cbe ) :
2016-02-18 03:27:57 +03:00
for t in tags :
utils . validate_tag ( LV_INTERFACE , t )
2016-02-18 02:53:35 +03:00
r = RequestEntry (
tmo , Lv . _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 = LV_INTERFACE ,
in_signature = ' asia {sv} ' ,
out_signature = ' o ' ,
async_callbacks = ( ' cb ' , ' cbe ' ) )
def TagsDel ( self , tags , tmo , tag_options , cb , cbe ) :
2016-02-18 03:27:57 +03:00
for t in tags :
utils . validate_tag ( LV_INTERFACE , t )
2016-02-18 02:53:35 +03:00
r = RequestEntry (
tmo , Lv . _add_rm_tags ,
( self . state . Uuid , self . state . lvm_id ,
None , tags , tag_options ) ,
cb , cbe , return_tuple = False )
cfg . worker_q . put ( r )
# noinspection PyPep8Naming
class LvThinPool ( Lv ) :
_DataLv_meta = ( " o " , THIN_POOL_INTERFACE )
_MetaDataLv_meta = ( " o " , THIN_POOL_INTERFACE )
def __init__ ( self , object_path , object_state ) :
super ( LvThinPool , self ) . __init__ ( object_path , object_state )
self . set_interface ( THIN_POOL_INTERFACE )
self . _data_lv , self . _metadata_lv = self . _get_data_meta ( )
@property
def DataLv ( self ) :
return self . _data_lv
@property
def MetaDataLv ( self ) :
return self . _metadata_lv
@staticmethod
def _lv_create ( lv_uuid , lv_name , name , size_bytes , create_options ) :
# Make sure we have a dbus object representing it
dbo = cfg . om . get_object_by_uuid_lvm_id ( lv_uuid , lv_name )
lv_created = ' / '
if dbo :
rc , out , err = cmdhandler . lv_lv_create (
lv_name , create_options , name , size_bytes )
if rc == 0 :
full_name = " %s / %s " % ( dbo . vg_name_lookup ( ) , name )
lvs = load_lvs ( [ full_name ] , emit_signal = True ) [ 0 ]
for l in lvs :
lv_created = l . dbus_object_path ( )
else :
raise dbus . exceptions . DBusException (
LV_INTERFACE ,
' Exit code %s , stderr = %s ' % ( str ( rc ) , err ) )
else :
raise dbus . exceptions . DBusException (
LV_INTERFACE ,
' LV with uuid %s and name %s not present! ' %
( lv_uuid , lv_name ) )
return lv_created
@dbus.service.method (
dbus_interface = THIN_POOL_INTERFACE ,
in_signature = ' stia {sv} ' ,
out_signature = ' (oo) ' ,
async_callbacks = ( ' cb ' , ' cbe ' ) )
def LvCreate ( self , name , size_bytes , tmo , create_options , cb , cbe ) :
2016-02-18 03:27:57 +03:00
utils . validate_lv_name ( THIN_POOL_INTERFACE , self . vg_name_lookup ( ) , name )
2016-02-18 02:53:35 +03:00
r = RequestEntry (
tmo , LvThinPool . _lv_create ,
( self . Uuid , self . lvm_id , name ,
round_size ( size_bytes ) , create_options ) , cb , cbe )
cfg . worker_q . put ( r )
# noinspection PyPep8Naming
class LvCachePool ( Lv ) :
2016-06-06 23:03:02 +03:00
_DataLv_meta = ( " o " , CACHE_POOL_INTERFACE )
_MetaDataLv_meta = ( " o " , CACHE_POOL_INTERFACE )
2016-02-18 02:53:35 +03:00
def __init__ ( self , object_path , object_state ) :
super ( LvCachePool , self ) . __init__ ( object_path , object_state )
self . set_interface ( CACHE_POOL_INTERFACE )
2016-06-06 23:03:02 +03:00
self . _data_lv , self . _metadata_lv = self . _get_data_meta ( )
@property
def DataLv ( self ) :
return self . _data_lv
@property
def MetaDataLv ( self ) :
return self . _metadata_lv
2016-02-18 02:53:35 +03:00
@staticmethod
def _cache_lv ( lv_uuid , lv_name , lv_object_path , cache_options ) :
# Make sure we have a dbus object representing cache pool
dbo = cfg . om . get_object_by_uuid_lvm_id ( lv_uuid , lv_name )
# Make sure we have dbus object representing lv to cache
lv_to_cache = cfg . om . get_object_by_path ( lv_object_path )
if dbo and lv_to_cache :
fcn = lv_to_cache . lv_full_name ( )
rc , out , err = cmdhandler . lv_cache_lv (
dbo . lv_full_name ( ) , fcn , cache_options )
if rc == 0 :
# When we cache an LV, the cache pool and the lv that is getting
# cached need to be removed from the object manager and
# re-created as their interfaces have changed!
cfg . om . remove_object ( dbo , emit_signal = True )
cfg . om . remove_object ( lv_to_cache , emit_signal = True )
cfg . load ( )
2016-06-10 20:05:52 +03:00
lv_converted = cfg . om . get_object_path_by_lvm_id ( fcn )
2016-02-18 02:53:35 +03:00
else :
raise dbus . exceptions . DBusException (
LV_INTERFACE ,
' Exit code %s , stderr = %s ' % ( str ( rc ) , err ) )
else :
msg = " "
if not dbo :
dbo + = ' CachePool LV with uuid %s and name %s not present! ' % \
( lv_uuid , lv_name )
if not lv_to_cache :
dbo + = ' LV to cache with object path %s not present! ' % \
( lv_object_path )
raise dbus . exceptions . DBusException ( LV_INTERFACE , msg )
return lv_converted
@dbus.service.method (
dbus_interface = CACHE_POOL_INTERFACE ,
in_signature = ' oia {sv} ' ,
out_signature = ' (oo) ' ,
async_callbacks = ( ' cb ' , ' cbe ' ) )
def CacheLv ( self , lv_object , tmo , cache_options , cb , cbe ) :
r = RequestEntry (
tmo , LvCachePool . _cache_lv ,
( self . Uuid , self . lvm_id , lv_object ,
cache_options ) , cb , cbe )
cfg . worker_q . put ( r )
# noinspection PyPep8Naming
class LvCacheLv ( Lv ) :
_CachePool_meta = ( " o " , LV_CACHED )
def __init__ ( self , object_path , object_state ) :
super ( LvCacheLv , self ) . __init__ ( object_path , object_state )
self . set_interface ( LV_CACHED )
@property
def CachePool ( self ) :
return self . state . PoolLv
@staticmethod
def _detach_lv ( lv_uuid , lv_name , detach_options , destroy_cache ) :
# Make sure we have a dbus object representing cache pool
dbo = cfg . om . get_object_by_uuid_lvm_id ( lv_uuid , lv_name )
if dbo :
# Get current cache name
cache_pool = cfg . om . get_object_by_path ( dbo . CachePool )
rc , out , err = cmdhandler . lv_detach_cache (
dbo . lv_full_name ( ) , detach_options , destroy_cache )
if rc == 0 :
# The cache pool gets removed as hidden and put back to
# visible, so lets delete
cfg . om . remove_object ( cache_pool , emit_signal = True )
cfg . om . remove_object ( dbo , emit_signal = True )
cfg . load ( )
2016-06-10 20:05:52 +03:00
uncached_lv_path = cfg . om . get_object_path_by_lvm_id ( lv_name )
2016-02-18 02:53:35 +03:00
else :
raise dbus . exceptions . DBusException (
LV_INTERFACE ,
' Exit code %s , stderr = %s ' % ( str ( rc ) , err ) )
else :
raise dbus . exceptions . DBusException (
LV_INTERFACE ,
' LV with uuid %s and name %s not present! ' %
( lv_uuid , lv_name ) )
return uncached_lv_path
@dbus.service.method (
dbus_interface = LV_CACHED ,
in_signature = ' bia {sv} ' ,
out_signature = ' (oo) ' ,
async_callbacks = ( ' cb ' , ' cbe ' ) )
def DetachCachePool ( self , destroy_cache , tmo , detach_options , cb , cbe ) :
r = RequestEntry (
tmo , LvCacheLv . _detach_lv ,
( self . Uuid , self . lvm_id , detach_options ,
destroy_cache ) , cb , cbe )
cfg . worker_q . put ( r )
# noinspection PyPep8Naming
class LvSnapShot ( Lv ) :
def __init__ ( self , object_path , object_state ) :
super ( LvSnapShot , self ) . __init__ ( object_path , object_state )
self . set_interface ( SNAPSHOT_INTERFACE )
@dbus.service.method (
dbus_interface = SNAPSHOT_INTERFACE ,
in_signature = ' ia {sv} ' ,
2016-06-28 20:07:21 +03:00
out_signature = ' o ' ,
async_callbacks = ( ' cb ' , ' cbe ' ) )
def Merge ( self , tmo , merge_options , cb , cbe ) :
job_state = JobState ( )
r = RequestEntry ( tmo , background . merge ,
( SNAPSHOT_INTERFACE , self . Uuid , self . lvm_id ,
merge_options , job_state ) , cb , cbe , False ,
job_state )
cfg . worker_q . put ( r )