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-02-18 02:53:35 +03:00
from . fetch import load
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
2016-02-25 23:57:12 +03:00
from . refresh import handle_external_event , event_complete
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 )
2016-02-25 23:57:12 +03:00
def _discard_pending_refreshes ( ) :
# We just handled a refresh, if we have any in the queue they can be
# removed because by definition they are older than the refresh we just did.
# As we limit the number of refreshes getting into the queue
# we should only ever have one to remove.
requests = [ ]
while not cfg . worker_q . empty ( ) :
try :
r = cfg . worker_q . get ( block = False )
if r . method != handle_external_event :
requests . append ( r )
else :
# Make sure we make this event complete even though it didn't
# run, otherwise no other events will get processed
event_complete ( )
break
except queue . Empty :
break
# Any requests we removed, but did not discard need to be re-queued
for r in requests :
cfg . worker_q . put ( r )
2016-02-18 02:53:35 +03:00
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 )
start = cfg . db . num_refreshes
log_debug (
" Running method: %s with args %s " %
( str ( req . method ) , str ( req . arguments ) ) )
req . run_cmd ( )
end = cfg . db . num_refreshes
2016-02-25 23:57:12 +03:00
num_refreshes = end - start
if num_refreshes > 0 :
_discard_pending_refreshes ( )
if num_refreshes > 1 :
log_debug (
" Inspect method %s for too many refreshes " %
( str ( req . method ) ) )
2016-11-02 01:52:51 +03:00
log_debug ( " Method complete " )
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
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-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 ( )
2016-02-18 02:53:35 +03:00
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 )
2016-08-25 02:29:35 +03:00
cmdhandler . set_execution ( cfg . args . use_lvm_shell )
2016-02-18 02:53:35 +03:00
# List of threads that we start up
thread_list = [ ]
# Install signal handlers
for s in [ signal . SIGHUP , signal . SIGINT ] :
try :
signal . signal ( s , utils . handler )
except RuntimeError :
pass
dbus . mainloop . glib . DBusGMainLoop ( set_as_default = True )
dbus . mainloop . glib . threads_init ( )
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 ) )
cfg . load = load
2016-08-25 02:29:35 +03:00
cfg . db = lvmdb . DataStore ( cfg . args . use_json )
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
2016-02-18 02:53:35 +03:00
thread_list . append ( threading . Thread ( target = process_request ) )
2016-11-02 01:50:10 +03:00
cfg . load ( refresh = False , emit_signal = False , need_main_thread = False )
2016-03-09 01:04:44 +03:00
cfg . loop = GLib . MainLoop ( )
2016-02-18 02:53:35 +03:00
for process in thread_list :
process . damon = True
process . start ( )
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
for process in thread_list :
process . join ( )
except KeyboardInterrupt :
utils . handler ( signal . SIGINT , None )
return 0