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 . import cfg
from . import objectmanager
from . import utils
2016-11-04 21:26:31 +03:00
from . cfg import BUS_NAME , BASE_INTERFACE , BASE_OBJ_PATH , MANAGER_OBJ_PATH
2016-02-18 02:53:35 +03:00
import threading
from . import cmdhandler
import time
import signal
import dbus
2016-09-19 18:29:26 +03:00
import dbus . mainloop . glib
2016-02-18 02:53:35 +03:00
from . import lvmdb
# noinspection PyUnresolvedReferences
2016-03-09 01:04:44 +03:00
from gi . repository import GLib
2016-11-10 21:19:48 +03:00
from . fetch import StateUpdate
2016-02-18 02:53:35 +03:00
from . manager import Manager
import traceback
import queue
from . import udevwatch
2016-08-29 22:26:16 +03:00
from . utils import log_debug , log_error
2016-02-18 02:53:35 +03:00
import argparse
2016-02-22 23:28:11 +03:00
import os
2016-08-29 22:26:16 +03:00
import sys
2019-10-08 00:57:05 +03:00
from . cmdhandler import LvmFlightRecorder , supports_vdo
2017-03-09 00:31:45 +03:00
from . request import RequestEntry
2016-02-18 02:53:35 +03:00
class Lvm ( objectmanager . ObjectManager ) :
def __init__ ( self , object_path ) :
super ( Lvm , self ) . __init__ ( object_path , BASE_INTERFACE )
def process_request ( ) :
while cfg . run . value != 0 :
2016-11-04 02:27:22 +03:00
# noinspection PyBroadException
2016-02-18 02:53:35 +03:00
try :
req = cfg . worker_q . get ( True , 5 )
log_debug (
2019-10-11 18:46:22 +03:00
" Method start: %s with args %s (callback = %s ) " %
( str ( req . method ) , str ( req . arguments ) , str ( req . cb ) ) )
2016-02-18 02:53:35 +03:00
req . run_cmd ( )
2019-10-11 18:46:22 +03:00
log_debug ( " Method complete: %s " % str ( req . method ) )
2016-02-18 02:53:35 +03:00
except queue . Empty :
pass
except Exception :
2016-02-25 23:57:12 +03:00
st = traceback . format_exc ( )
utils . log_error ( " process_request exception: \n %s " % st )
2016-02-18 02:53:35 +03:00
2016-12-01 01:45:50 +03:00
def check_bb_size ( value ) :
v = int ( value )
if v < 0 :
raise argparse . ArgumentTypeError (
" positive integers only ( ' %s ' invalid) " % value )
return v
2017-09-25 23:20:03 +03:00
def install_signal_handlers ( ) :
# Because of the glib main loop stuff the python signal handler code is
# apparently not usable and we need to use the glib calls instead
signal_add = None
if hasattr ( GLib , ' unix_signal_add ' ) :
signal_add = GLib . unix_signal_add
elif hasattr ( GLib , ' unix_signal_add_full ' ) :
signal_add = GLib . unix_signal_add_full
if signal_add :
signal_add ( GLib . PRIORITY_HIGH , signal . SIGHUP , utils . handler , signal . SIGHUP )
signal_add ( GLib . PRIORITY_HIGH , signal . SIGINT , utils . handler , signal . SIGINT )
signal_add ( GLib . PRIORITY_HIGH , signal . SIGUSR1 , utils . handler , signal . SIGUSR1 )
else :
log_error ( " GLib.unix_signal_[add|add_full] are NOT available! " )
2016-02-18 02:53:35 +03:00
def main ( ) :
2016-08-25 02:29:35 +03:00
start = time . time ( )
2016-02-18 02:53:35 +03:00
# Add simple command line handling
parser = argparse . ArgumentParser ( )
2016-08-29 23:07:55 +03:00
parser . add_argument (
" --udev " , action = ' store_true ' ,
help = " Use udev for updating state " ,
default = False ,
dest = ' use_udev ' )
parser . add_argument (
" --debug " , action = ' store_true ' ,
help = " Dump debug messages " , default = False ,
dest = ' debug ' )
parser . add_argument (
" --nojson " , action = ' store_false ' ,
help = " Do not use LVM JSON output (disables lvmshell) " , default = True ,
dest = ' use_json ' )
parser . add_argument (
" --lvmshell " , action = ' store_true ' ,
help = " Use the lvm shell, not fork & exec lvm " ,
default = False ,
dest = ' use_lvm_shell ' )
2016-11-30 03:01:56 +03:00
parser . add_argument (
" --blackboxsize " ,
help = " Size of the black box flight recorder, 0 to disable " ,
default = 10 ,
2016-12-01 01:45:50 +03:00
type = check_bb_size ,
2016-11-30 03:01:56 +03:00
dest = ' bb_size ' )
2016-06-28 21:32:39 +03:00
2016-02-22 23:28:11 +03:00
use_session = os . getenv ( ' LVMDBUSD_USE_SESSION ' , False )
2016-03-04 19:13:04 +03:00
# Ensure that we get consistent output for parsing stdout/stderr
os . environ [ " LC_ALL " ] = " C "
2016-08-25 02:29:35 +03:00
cfg . args = parser . parse_args ( )
2017-03-09 00:31:45 +03:00
cfg . create_request_entry = RequestEntry
2016-02-18 02:53:35 +03:00
2016-11-30 03:01:56 +03:00
# We create a flight recorder in cmdhandler too, but we replace it here
# as the user may be specifying a different size. The default one in
# cmdhandler is for when we are running other code with a different main.
cfg . blackbox = LvmFlightRecorder ( cfg . args . bb_size )
2016-08-29 22:26:16 +03:00
if cfg . args . use_lvm_shell and not cfg . args . use_json :
log_error ( " You cannot specify --lvmshell and --nojson " )
sys . exit ( 1 )
2019-10-08 00:57:05 +03:00
# We will dynamically add interfaces which support vdo if it
# exists.
cfg . vdo_support = supports_vdo ( )
2019-10-09 19:20:18 +03:00
if cfg . vdo_support and not cfg . args . use_json :
log_error ( " You cannot specify --nojson when lvm has VDO support " )
sys . exit ( 1 )
2016-02-18 02:53:35 +03:00
# List of threads that we start up
thread_list = [ ]
2017-09-25 23:20:03 +03:00
install_signal_handlers ( )
2016-02-18 02:53:35 +03:00
dbus . mainloop . glib . DBusGMainLoop ( set_as_default = True )
dbus . mainloop . glib . threads_init ( )
2016-02-22 23:28:11 +03:00
2016-11-11 18:46:12 +03:00
cmdhandler . set_execution ( cfg . args . use_lvm_shell )
2016-02-22 23:28:11 +03:00
if use_session :
cfg . bus = dbus . SessionBus ( )
else :
cfg . bus = dbus . SystemBus ( )
2016-02-18 02:53:35 +03:00
# The base name variable needs to exist for things to work.
# noinspection PyUnusedLocal
2016-11-04 21:26:31 +03:00
base_name = dbus . service . BusName ( BUS_NAME , cfg . bus )
2016-02-18 02:53:35 +03:00
cfg . om = Lvm ( BASE_OBJ_PATH )
cfg . om . register_object ( Manager ( MANAGER_OBJ_PATH ) )
2019-10-09 15:49:58 +03:00
cfg . db = lvmdb . DataStore ( cfg . args . use_json , cfg . vdo_support )
2016-02-18 02:53:35 +03:00
2016-11-04 02:27:22 +03:00
# Using a thread to process requests, we cannot hang the dbus library
# thread that is handling the dbus interface
2019-10-11 18:46:22 +03:00
thread_list . append (
threading . Thread ( target = process_request , name = ' process_request ' ) )
2016-02-18 02:53:35 +03:00
2016-11-30 03:01:56 +03:00
# Have a single thread handling updating lvm and the dbus model so we
# don't have multiple threads doing this as the same time
2016-11-10 21:19:48 +03:00
updater = StateUpdate ( )
thread_list . append ( updater . thread )
cfg . load = updater . load
2016-03-09 01:04:44 +03:00
cfg . loop = GLib . MainLoop ( )
2016-02-18 02:53:35 +03:00
2016-11-10 21:19:48 +03:00
for thread in thread_list :
thread . damon = True
thread . start ( )
2016-02-18 02:53:35 +03:00
2016-08-25 02:29:35 +03:00
# Add udev watching
if cfg . args . use_udev :
log_debug ( ' Utilizing udev to trigger updates ' )
# In all cases we are going to monitor for udev until we get an
# ExternalEvent. In the case where we get an external event and the user
# didn't specify --udev we will stop monitoring udev
udevwatch . add ( )
2016-02-18 02:53:35 +03:00
end = time . time ( )
log_debug (
2016-08-12 23:23:05 +03:00
' Service ready! total time= %.4f , lvm time= %.4f count= %d ' %
2016-02-18 02:53:35 +03:00
( end - start , cmdhandler . total_time , cmdhandler . total_count ) ,
' bg_black ' , ' fg_light_green ' )
try :
if cfg . run . value != 0 :
cfg . loop . run ( )
2016-08-25 02:29:35 +03:00
udevwatch . remove ( )
2016-02-18 02:53:35 +03:00
2016-11-10 21:19:48 +03:00
for thread in thread_list :
thread . join ( )
2016-02-18 02:53:35 +03:00
except KeyboardInterrupt :
2017-09-25 23:20:03 +03:00
# If we are unable to register signal handler, we will end up here when
# the service gets a ^C or a kill -2 <parent pid>
utils . handler ( signal . SIGINT )
2016-02-18 02:53:35 +03:00
return 0