1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

lvmdbusd: Use udev until ExternalEvent occurs

The normal mode of operation will be to monitor for udev events until an
ExternalEvent occurs.  In that case the service will disable monitoring
for udev events and use ExternalEvent exclusively.

Note: User specifies --udev the service will always monitor udev regardless
if ExternalEvent is being called too.
This commit is contained in:
Tony Asleson 2016-08-24 18:29:35 -05:00
parent 2352ff24a5
commit 4902034c89
7 changed files with 72 additions and 36 deletions

View File

@ -24,14 +24,18 @@ om = None
# This is the global bus connection # This is the global bus connection
bus = None bus = None
# Command line args
args = None
# Set to true if we are depending on external events for updates
ee = False
# Shared state variable across all processes # Shared state variable across all processes
run = multiprocessing.Value('i', 1) run = multiprocessing.Value('i', 1)
# Debug # If this is set to true, the current setup support lvm shell and we are
DEBUG = True # running in that mode of operation
SHELL_IN_USE = None
# Use lvm shell
USE_SHELL = False
# Lock used by pprint # Lock used by pprint
stdout_lock = multiprocessing.Lock() stdout_lock = multiprocessing.Lock()

View File

@ -13,6 +13,7 @@ import threading
from itertools import chain from itertools import chain
import collections import collections
import traceback import traceback
import os
try: try:
from . import cfg from . import cfg
@ -101,7 +102,8 @@ def call_lvm(command, debug=False):
# in different locations on the same box # in different locations on the same box
command.insert(0, cfg.LVM_CMD) command.insert(0, cfg.LVM_CMD)
process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True) process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True,
env=os.environ)
out = process.communicate() out = process.communicate()
stdout_text = bytes(out[0]).decode("utf-8") stdout_text = bytes(out[0]).decode("utf-8")
@ -111,7 +113,7 @@ def call_lvm(command, debug=False):
_debug_c(command, process.returncode, (stdout_text, stderr_text)) _debug_c(command, process.returncode, (stdout_text, stderr_text))
if process.returncode == 0: if process.returncode == 0:
if cfg.DEBUG and out[1] and len(out[1]) and 'help' not in command: if cfg.args.debug and out[1] and len(out[1]) and 'help' not in command:
log_error('WARNING: lvm is out-putting text to STDERR on success!') log_error('WARNING: lvm is out-putting text to STDERR on success!')
_debug_c(command, process.returncode, (stdout_text, stderr_text)) _debug_c(command, process.returncode, (stdout_text, stderr_text))
@ -123,9 +125,10 @@ def _shell_cfg():
try: try:
lvm_shell = LVMShellProxy() lvm_shell = LVMShellProxy()
_t_call = lvm_shell.call_lvm _t_call = lvm_shell.call_lvm
cfg.USE_SHELL = True cfg.SHELL_IN_USE = lvm_shell
except Exception: except Exception:
_t_call = call_lvm _t_call = call_lvm
cfg.SHELL_IN_USE = None
log_error(traceback.format_exc()) log_error(traceback.format_exc())
log_error("Unable to utilize lvm shell, dropping back to fork & exec") log_error("Unable to utilize lvm shell, dropping back to fork & exec")
@ -133,6 +136,15 @@ def _shell_cfg():
def set_execution(shell): def set_execution(shell):
global _t_call global _t_call
with cmd_lock: with cmd_lock:
# If the user requested lvm shell and we are currently setup that
# way, just return
if cfg.SHELL_IN_USE and shell:
return
else:
if not shell and cfg.SHELL_IN_USE:
cfg.SHELL_IN_USE.exit_shell()
cfg.SHELL_IN_USE = None
_t_call = call_lvm _t_call = call_lvm
if shell: if shell:
_shell_cfg() _shell_cfg()
@ -217,7 +229,7 @@ def pv_remove(device, remove_options):
def _qt(tag_name): def _qt(tag_name):
# When running in lvm shell you need to quote the tags # When running in lvm shell you need to quote the tags
if cfg.USE_SHELL: if cfg.SHELL_IN_USE:
return '"%s"' % tag_name return '"%s"' % tag_name
return tag_name return tag_name
@ -440,7 +452,7 @@ def supports_json():
cmd = ['help'] cmd = ['help']
rc, out, err = call(cmd) rc, out, err = call(cmd)
if rc == 0: if rc == 0:
if cfg.USE_SHELL: if cfg.SHELL_IN_USE:
return True return True
else: else:
if 'fullreport' in err: if 'fullreport' in err:
@ -488,7 +500,7 @@ def lvm_full_report_json():
# With the current implementation, if we are using the shell then we # With the current implementation, if we are using the shell then we
# are using JSON and JSON is returned back to us as it was parsed to # are using JSON and JSON is returned back to us as it was parsed to
# figure out if we completed OK or not # figure out if we completed OK or not
if cfg.USE_SHELL: if cfg.SHELL_IN_USE:
assert(type(out) == dict) assert(type(out) == dict)
return out return out
else: else:

View File

@ -203,6 +203,12 @@ class LVMShellProxy(object):
return rc, json_result, error_msg return rc, json_result, error_msg
def exit_shell(self):
try:
self._write_cmd('exit\n')
except Exception as e:
log_error(str(e))
def __del__(self): def __del__(self):
try: try:
self.lvm_shell.terminate() self.lvm_shell.terminate()

View File

@ -92,6 +92,7 @@ def process_request():
def main(): def main():
start = time.time()
# Add simple command line handling # Add simple command line handling
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument("--udev", action='store_true', parser.add_argument("--udev", action='store_true',
@ -112,16 +113,13 @@ def main():
# Ensure that we get consistent output for parsing stdout/stderr # Ensure that we get consistent output for parsing stdout/stderr
os.environ["LC_ALL"] = "C" os.environ["LC_ALL"] = "C"
args = parser.parse_args() cfg.args = parser.parse_args()
cfg.DEBUG = args.debug cmdhandler.set_execution(cfg.args.use_lvm_shell)
cmdhandler.set_execution(args.use_lvm_shell)
# List of threads that we start up # List of threads that we start up
thread_list = [] thread_list = []
start = time.time()
# Install signal handlers # Install signal handlers
for s in [signal.SIGHUP, signal.SIGINT]: for s in [signal.SIGHUP, signal.SIGINT]:
try: try:
@ -144,7 +142,7 @@ def main():
cfg.load = load cfg.load = load
cfg.db = lvmdb.DataStore(args.use_json) cfg.db = lvmdb.DataStore(cfg.args.use_json)
# Start up thread to monitor pv moves # Start up thread to monitor pv moves
thread_list.append( thread_list.append(
@ -160,23 +158,25 @@ def main():
process.damon = True process.damon = True
process.start() process.start()
# 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()
end = time.time() end = time.time()
log_debug( log_debug(
'Service ready! total time= %.4f, lvm time= %.4f count= %d' % 'Service ready! total time= %.4f, lvm time= %.4f count= %d' %
(end - start, cmdhandler.total_time, cmdhandler.total_count), (end - start, cmdhandler.total_time, cmdhandler.total_count),
'bg_black', 'fg_light_green') 'bg_black', 'fg_light_green')
# Add udev watching
if args.use_udev:
log_debug('Utilizing udev to trigger updates')
udevwatch.add()
try: try:
if cfg.run.value != 0: if cfg.run.value != 0:
cfg.loop.run() cfg.loop.run()
udevwatch.remove()
if args.use_udev:
udevwatch.remove()
for process in thread_list: for process in thread_list:
process.join() process.join()

View File

@ -17,7 +17,7 @@ from . import cmdhandler
from .fetch import load_pvs, load_vgs from .fetch import load_pvs, load_vgs
from .request import RequestEntry from .request import RequestEntry
from .refresh import event_add from .refresh import event_add
from . import udevwatch
# noinspection PyPep8Naming # noinspection PyPep8Naming
class Manager(AutomatedProperties): class Manager(AutomatedProperties):
@ -181,6 +181,13 @@ class Manager(AutomatedProperties):
in_signature='s', out_signature='i') in_signature='s', out_signature='i')
def ExternalEvent(self, command): def ExternalEvent(self, command):
# If a user didn't explicitly specify udev, we will turn it off now.
if not cfg.args.use_udev:
if udevwatch.remove():
utils.log_debug("ExternalEvent received, disabling "
"udev monitoring")
# We are dependent on external events now to stay current!
cfg.ee = True
event_add((command,)) event_add((command,))
return dbus.Int32(0) return dbus.Int32(0)

View File

@ -8,10 +8,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import pyudev import pyudev
import threading
from .refresh import event_add from .refresh import event_add
from . import cfg from . import cfg
observer = None observer = None
observer_lock = threading.RLock()
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
@ -40,15 +42,20 @@ def filter_event(action, device):
def add(): def add():
global observer with observer_lock:
context = pyudev.Context() global observer
monitor = pyudev.Monitor.from_netlink(context) context = pyudev.Context()
monitor.filter_by('block') monitor = pyudev.Monitor.from_netlink(context)
observer = pyudev.MonitorObserver(monitor, filter_event) monitor.filter_by('block')
observer.start() observer = pyudev.MonitorObserver(monitor, filter_event)
observer.start()
def remove(): def remove():
global observer with observer_lock:
observer.stop() global observer
observer = None if observer:
observer.stop()
observer = None
return True
return False

View File

@ -265,7 +265,7 @@ def _common_log(msg, *attributes):
# @param msg Message to output to stdout # @param msg Message to output to stdout
# @return None # @return None
def log_debug(msg, *attributes): def log_debug(msg, *attributes):
if cfg.DEBUG: if cfg.args.debug:
_common_log(msg, *attributes) _common_log(msg, *attributes)