main - lvmdbusd: Raise LvmBug exception for invalid JSON
by Tony Asleson
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=f4c03faa6556489444c...
Commit: f4c03faa6556489444cf9402b2a35c46e7282ed3
Parent: 85fcbfd9d7697d3954c4f13a791f127205e260ee
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Wed Aug 31 15:08:09 2022 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Fri Sep 16 10:49:37 2022 -0500
lvmdbusd: Raise LvmBug exception for invalid JSON
This will cause lvm debug data to get logged if it's available.
---
daemons/lvmdbusd/cmdhandler.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/daemons/lvmdbusd/cmdhandler.py b/daemons/lvmdbusd/cmdhandler.py
index 102844739..1a7943f01 100644
--- a/daemons/lvmdbusd/cmdhandler.py
+++ b/daemons/lvmdbusd/cmdhandler.py
@@ -621,9 +621,9 @@ def lvm_full_report_json():
rc, out, err = call(cmd)
# When we have an exported vg the exit code of lvs or fullreport will be 5
if rc == 0 or rc == 5:
- # 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
- # figure out if we completed OK or not
+ # If the 'call' implementation is lvmshell, the out is a dictionary as lvmshell has to
+ # parse the output to get the exit value. When doing fork & exec, out is a string
+ # representing the JSON. TODO: Make this consistent between implementations.
if cfg.SHELL_IN_USE:
assert(type(out) == dict)
return out
@@ -633,7 +633,7 @@ def lvm_full_report_json():
except json.decoder.JSONDecodeError as joe:
log_error("JSONDecodeError %s, \n JSON=\n%s\n" %
(str(joe), out))
- raise joe
+ raise LvmBug("'fullreport' returned invalid JSON")
raise LvmBug("'fullreport' exited with code '%d'" % rc)
6 months, 1 week
main - lvmdbusd: Instruct lvm to output debug to file for fullreport
by Tony Asleson
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=85fcbfd9d7697d3954c...
Commit: 85fcbfd9d7697d3954c4f13a791f127205e260ee
Parent: d42bdb07def72d68c05241823979b28952978c05
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Wed Aug 31 15:04:59 2022 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Fri Sep 16 10:49:37 2022 -0500
lvmdbusd: Instruct lvm to output debug to file for fullreport
Historically we have seen a few different errors which occur when we call
fullreport. Failing exit code and JSON which is missing one or more keys.
Instruct lvm to dump the debug to a file during fullreport calls when we
fork & exec lvm. If we encounter an error, ouput the debug data.
The reason this isn't being done when lvmshell is used is because we
don't have an easy way to test the error paths.
This change is complicated by the following:
1. We don't know if fullreport was good until we evaluate all the JSON.
This is done a bit after we have called into lvm and returned.
2. We don't want to orphan the debug file used by lvm if the daemon is
killed. Thus we try to minimize the window where the debug file hasn't
already been unlinked. A RFE to pass an open FD to lvm for this
purpose is outstanding.
The temp. file is:
-rw------. 1 root root /tmp/lvmdbusd.lvm.debug.XXXXXXXX.log
---
daemons/lvmdbusd/cfg.py | 4 +++
daemons/lvmdbusd/cmdhandler.py | 9 ++++-
daemons/lvmdbusd/fetch.py | 6 ++++
daemons/lvmdbusd/main.py | 4 +++
daemons/lvmdbusd/utils.py | 78 +++++++++++++++++++++++++++++++++++-------
5 files changed, 87 insertions(+), 14 deletions(-)
diff --git a/daemons/lvmdbusd/cfg.py b/daemons/lvmdbusd/cfg.py
index a758b8a77..5b342bc20 100644
--- a/daemons/lvmdbusd/cfg.py
+++ b/daemons/lvmdbusd/cfg.py
@@ -109,3 +109,7 @@ def exit_daemon():
if run and loop:
run.value = 0
loop.quit()
+
+
+# Debug data for lvm
+lvmdebug = None
diff --git a/daemons/lvmdbusd/cmdhandler.py b/daemons/lvmdbusd/cmdhandler.py
index 7a349e87e..102844739 100644
--- a/daemons/lvmdbusd/cmdhandler.py
+++ b/daemons/lvmdbusd/cmdhandler.py
@@ -17,7 +17,7 @@ import os
from lvmdbusd import cfg
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify,\
- make_non_block, read_decoded, extract_stack_trace, LvmBug
+ make_non_block, read_decoded, extract_stack_trace, LvmBug, add_config_option
from lvmdbusd.lvm_shell_proxy import LVMShellProxy
try:
@@ -121,6 +121,12 @@ def call_lvm(command, debug=False, line_cb=None,
command.insert(0, cfg.LVM_CMD)
command = add_no_notify(command)
+ # If we are running the fullreport command, we will ask lvm to output the debug
+ # data, so we can have the required information for lvm to debug the fullreport failures.
+ if "fullreport" in command:
+ fn = cfg.lvmdebug.setup()
+ add_config_option(command, "--config", "log {level=7 file=%s syslog=0}" % fn)
+
process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True,
env=os.environ)
@@ -163,6 +169,7 @@ def call_lvm(command, debug=False, line_cb=None,
break
if process.returncode is not None:
+ cfg.lvmdebug.lvm_complete()
if debug or (process.returncode != 0 and (process.returncode != 5 and "fullreport" in command)):
_debug_c(command, process.returncode, (stdout_text, stderr_text))
diff --git a/daemons/lvmdbusd/fetch.py b/daemons/lvmdbusd/fetch.py
index dc527be36..199b86073 100644
--- a/daemons/lvmdbusd/fetch.py
+++ b/daemons/lvmdbusd/fetch.py
@@ -171,6 +171,7 @@ class StateUpdate(object):
cfg.exit_daemon()
else:
# Slow things down when encountering errors
+ cfg.lvmdebug.complete()
time.sleep(1)
while cfg.run.value != 0:
@@ -205,11 +206,16 @@ class StateUpdate(object):
except SystemExit:
break
except LvmBug as bug:
+ # If a lvm bug occurred, we will dump the lvm debug data if
+ # we have it.
+ cfg.lvmdebug.dump()
log_error(str(bug))
_handle_error()
except Exception as e:
log_error("update_thread: \n%s" % extract_stack_trace(e))
_handle_error()
+ finally:
+ cfg.lvmdebug.complete()
# Make sure to unblock any that may be waiting before we exit this thread
# otherwise they hang forever ...
diff --git a/daemons/lvmdbusd/main.py b/daemons/lvmdbusd/main.py
index a426a535d..ab66efcc9 100644
--- a/daemons/lvmdbusd/main.py
+++ b/daemons/lvmdbusd/main.py
@@ -138,6 +138,10 @@ def main():
os.environ["LC_ALL"] = "C"
os.environ["LVM_COMMAND_PROFILE"] = "lvmdbusd"
+ # Save off the debug data needed for lvm team to debug issues
+ # only used for 'fullreport' at this time.
+ cfg.lvmdebug = utils.LvmDebugData()
+
# Add simple command line handling
cfg.args = process_args()
diff --git a/daemons/lvmdbusd/utils.py b/daemons/lvmdbusd/utils.py
index 6c7a25f8d..ec40236a5 100644
--- a/daemons/lvmdbusd/utils.py
+++ b/daemons/lvmdbusd/utils.py
@@ -18,6 +18,7 @@ import os
import stat
import string
import datetime
+import tempfile
import dbus
from lvmdbusd import cfg
@@ -614,6 +615,23 @@ def validate_tag(interface, tag):
% (tag, _ALLOWABLE_TAG_CH))
+def add_config_option(cmdline, key, value):
+ if 'help' in cmdline:
+ return cmdline
+
+ if key in cmdline:
+ for i, arg in enumerate(cmdline):
+ if arg == key:
+ if len(cmdline) <= i + 1:
+ raise dbus.exceptions.DBusException("Missing value for --config option.")
+ cmdline[i + 1] += " %s" % value
+ break
+ else:
+ cmdline.extend([key, value])
+
+ return cmdline
+
+
def add_no_notify(cmdline):
"""
Given a command line to execute we will see if `--config` is present, if it
@@ -627,20 +645,11 @@ def add_no_notify(cmdline):
# Only after we have seen an external event will we disable lvm from sending
# us one when we call lvm
+ rv = cmdline
if cfg.got_external_event:
- if 'help' in cmdline:
- return cmdline
-
- if '--config' in cmdline:
- for i, arg in enumerate(cmdline):
- if arg == '--config':
- if len(cmdline) <= i+1:
- raise dbus.exceptions.DBusException("Missing value for --config option.")
- cmdline[i+1] += " global/notify_dbus=0"
- break
- else:
- cmdline.extend(['--config', 'global/notify_dbus=0'])
- return cmdline
+ rv = add_config_option(rv, "--config", "global/notify_dbus=0")
+
+ return rv
# The methods below which start with mt_* are used to execute the desired code
@@ -777,3 +786,46 @@ class LvmBug(RuntimeError):
def __str__(self):
return "lvm bug encountered: %s" % ' '.join(self.args)
+
+
+class LvmDebugData:
+ def __init__(self):
+ self.fd = -1
+ self.fn = None
+
+ def _remove_file(self):
+ if self.fn is not None:
+ os.unlink(self.fn)
+ self.fn = None
+
+ def _close_fd(self):
+ if self.fd != -1:
+ os.close(self.fd)
+ self.fd = -1
+
+ def setup(self):
+ # Create a secure filename
+ self.fd, self.fn = tempfile.mkstemp(suffix=".log", prefix="lvmdbusd.lvm.debug.")
+ return self.fn
+
+ def lvm_complete(self):
+ # Remove the file ASAP, so we decrease our odds of leaving it
+ # around if the daemon gets killed by a signal -9
+ self._remove_file()
+
+ def dump(self):
+ # Read the file and log it to log_err
+ if self.fd != -1:
+ # How big could the verbose debug get?
+ debug = os.read(self.fd, 1024*1024*5)
+ debug_txt = debug.decode("utf-8")
+ for line in debug_txt.split("\n"):
+ log_error("lvm debug >>> %s" % line)
+ self._close_fd()
+ # In case lvm_complete doesn't get called.
+ self._remove_file()
+
+ def complete(self):
+ self._close_fd()
+ # In case lvm_complete doesn't get called.
+ self._remove_file()
6 months, 1 week
main - lvmdbusd: Re-work error handling
by Tony Asleson
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=d42bdb07def72d68c05...
Commit: d42bdb07def72d68c05241823979b28952978c05
Parent: cb32b0a87f9c2c5b9d79f02e59e3925d8350c70b
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Wed Aug 31 11:20:49 2022 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Fri Sep 16 10:49:37 2022 -0500
lvmdbusd: Re-work error handling
Introduce an exception which is used for known existing issues with lvm.
This is used to distinguish between errors between lvm itself and lvmdbusd.
In the case of lvm bugs, when we simply retry the operation we will log
very little. Otherwise, we will dump a full traceback for investigation
when we do the retry.
---
daemons/lvmdbusd/cmdhandler.py | 4 +-
daemons/lvmdbusd/fetch.py | 33 ++++++----
daemons/lvmdbusd/lv.py | 133 ++++++++++++++++++++++-------------------
daemons/lvmdbusd/pv.py | 29 +++++----
daemons/lvmdbusd/utils.py | 9 +++
daemons/lvmdbusd/vg.py | 32 ++++++----
6 files changed, 140 insertions(+), 100 deletions(-)
diff --git a/daemons/lvmdbusd/cmdhandler.py b/daemons/lvmdbusd/cmdhandler.py
index fd6ecf326..7a349e87e 100644
--- a/daemons/lvmdbusd/cmdhandler.py
+++ b/daemons/lvmdbusd/cmdhandler.py
@@ -17,7 +17,7 @@ import os
from lvmdbusd import cfg
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify,\
- make_non_block, read_decoded, extract_stack_trace
+ make_non_block, read_decoded, extract_stack_trace, LvmBug
from lvmdbusd.lvm_shell_proxy import LVMShellProxy
try:
@@ -628,7 +628,7 @@ def lvm_full_report_json():
(str(joe), out))
raise joe
- return None
+ raise LvmBug("'fullreport' exited with code '%d'" % rc)
def pv_resize(device, size_bytes, create_options):
diff --git a/daemons/lvmdbusd/fetch.py b/daemons/lvmdbusd/fetch.py
index d1759f7dd..dc527be36 100644
--- a/daemons/lvmdbusd/fetch.py
+++ b/daemons/lvmdbusd/fetch.py
@@ -11,11 +11,10 @@ from .pv import load_pvs
from .vg import load_vgs
from .lv import load_lvs
from . import cfg
-from .utils import MThreadRunner, log_debug, log_error
+from .utils import MThreadRunner, log_debug, log_error, LvmBug, extract_stack_trace
import threading
import queue
import time
-import traceback
def _main_thread_load(refresh=True, emit_signal=True):
@@ -160,6 +159,20 @@ class StateUpdate(object):
except queue.Empty:
pass
+ def _handle_error():
+ nonlocal exception_count
+ exception_count += 1
+
+ if exception_count >= 5:
+ log_error("Too many errors in update_thread, exiting daemon")
+ cfg.debug.dump()
+ cfg.flightrecorder.dump()
+ bailing(e)
+ cfg.exit_daemon()
+ else:
+ # Slow things down when encountering errors
+ time.sleep(1)
+
while cfg.run.value != 0:
# noinspection PyBroadException
try:
@@ -191,18 +204,12 @@ class StateUpdate(object):
pass
except SystemExit:
break
+ except LvmBug as bug:
+ log_error(str(bug))
+ _handle_error()
except Exception as e:
- exception_count += 1
- if exception_count >= 5:
- st = traceback.format_exc()
- log_error("Too many errors in update_thread, exiting daemon (last exception reported): \n %s" % st)
- cfg.debug.dump()
- cfg.flightrecorder.dump()
- bailing(e)
- cfg.exit_daemon()
- else:
- # Slow things down when encountering errors
- time.sleep(1)
+ log_error("update_thread: \n%s" % extract_stack_trace(e))
+ _handle_error()
# Make sure to unblock any that may be waiting before we exit this thread
# otherwise they hang forever ...
diff --git a/daemons/lvmdbusd/lv.py b/daemons/lvmdbusd/lv.py
index 8c55f5ffd..134843346 100644
--- a/daemons/lvmdbusd/lv.py
+++ b/daemons/lvmdbusd/lv.py
@@ -10,7 +10,7 @@
from .automatedproperties import AutomatedProperties
from . import utils
-from .utils import vg_obj_path_generate, log_error, _handle_execute
+from .utils import vg_obj_path_generate, log_error, _handle_execute, LvmBug
import dbus
from . import cmdhandler
from . import cfg
@@ -71,67 +71,76 @@ def lvs_state_retrieve(selection, cache_refresh=True):
# don't have information available yet.
lvs = sorted(cfg.db.fetch_lvs(selection), key=get_key)
- for l in lvs:
- if cfg.vdo_support:
- rc.append(LvStateVdo(
- 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'],
- n32(l['snap_percent']),
- n32(l['metadata_percent']),
- n32(l['copy_percent']),
- n32(l['sync_percent']),
- n(l['lv_metadata_size']),
- l['move_pv'],
- l['move_pv_uuid'],
- l['vdo_operating_mode'],
- l['vdo_compression_state'],
- l['vdo_index_state'],
- n(l['vdo_used_size']),
- d(l['vdo_saving_percent']),
- l['vdo_compression'],
- l['vdo_deduplication'],
- l['vdo_use_metadata_hints'],
- n32(l['vdo_minimum_io_size']),
- n(l['vdo_block_map_cache_size']),
- n32(l['vdo_block_map_era_length']),
- l['vdo_use_sparse_index'],
- n(l['vdo_index_memory_size']),
- n(l['vdo_slab_size']),
- n32(l['vdo_ack_threads']),
- n32(l['vdo_bio_threads']),
- n32(l['vdo_bio_rotation']),
- n32(l['vdo_cpu_threads']),
- n32(l['vdo_hash_zone_threads']),
- n32(l['vdo_logical_threads']),
- n32(l['vdo_physical_threads']),
- n32(l['vdo_max_discard']),
- l['vdo_write_policy'],
- n32(l['vdo_header_size'])))
- else:
- 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'],
- n32(l['snap_percent']),
- n32(l['metadata_percent']),
- n32(l['copy_percent']),
- n32(l['sync_percent']),
- n(l['lv_metadata_size']),
- l['move_pv'],
- l['move_pv_uuid']))
+ try:
+ for l in lvs:
+ if cfg.vdo_support:
+ rc.append(LvStateVdo(
+ 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'],
+ n32(l['snap_percent']),
+ n32(l['metadata_percent']),
+ n32(l['copy_percent']),
+ n32(l['sync_percent']),
+ n(l['lv_metadata_size']),
+ l['move_pv'],
+ l['move_pv_uuid'],
+ l['vdo_operating_mode'],
+ l['vdo_compression_state'],
+ l['vdo_index_state'],
+ n(l['vdo_used_size']),
+ d(l['vdo_saving_percent']),
+ l['vdo_compression'],
+ l['vdo_deduplication'],
+ l['vdo_use_metadata_hints'],
+ n32(l['vdo_minimum_io_size']),
+ n(l['vdo_block_map_cache_size']),
+ n32(l['vdo_block_map_era_length']),
+ l['vdo_use_sparse_index'],
+ n(l['vdo_index_memory_size']),
+ n(l['vdo_slab_size']),
+ n32(l['vdo_ack_threads']),
+ n32(l['vdo_bio_threads']),
+ n32(l['vdo_bio_rotation']),
+ n32(l['vdo_cpu_threads']),
+ n32(l['vdo_hash_zone_threads']),
+ n32(l['vdo_logical_threads']),
+ n32(l['vdo_physical_threads']),
+ n32(l['vdo_max_discard']),
+ l['vdo_write_policy'],
+ n32(l['vdo_header_size'])))
+ else:
+ 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'],
+ n32(l['snap_percent']),
+ n32(l['metadata_percent']),
+ n32(l['copy_percent']),
+ n32(l['sync_percent']),
+ n(l['lv_metadata_size']),
+ l['move_pv'],
+ l['move_pv_uuid']))
+ except KeyError as ke:
+ # Sometimes lvm omits returning one of the keys we requested.
+ key = ke.args[0]
+ if key.startswith("lv_") or key.startswith("vg_") or key.startswith("pool_") or \
+ key.endswith("_percent") or key.startswith("move_") or key.startswith("vdo_") or \
+ key in ["origin_uuid", "segtype", "origin", "data_lv", "metadata_lv"]:
+ raise LvmBug("missing JSON key: '%s'" % key)
+ raise ke
return rc
diff --git a/daemons/lvmdbusd/pv.py b/daemons/lvmdbusd/pv.py
index 8a25cbf5d..2037f9c91 100644
--- a/daemons/lvmdbusd/pv.py
+++ b/daemons/lvmdbusd/pv.py
@@ -18,7 +18,7 @@ from .utils import vg_obj_path_generate, n, pv_obj_path_generate, \
from .loader import common
from .request import RequestEntry
from .state import State
-from .utils import round_size
+from .utils import round_size, LvmBug
# noinspection PyUnusedLocal
@@ -28,16 +28,23 @@ def pvs_state_retrieve(selection, cache_refresh=True):
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"]))
+ try:
+ 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"]))
+ except KeyError as ke:
+ # Sometimes lvm omits returning one of the keys we requested.
+ key = ke.args[0]
+ if key.startswith("pv") or key.startswith("vg") or (key in ['dev_size', 'pe_start']):
+ raise LvmBug("missing JSON key: '%s'" % key)
+ raise ke
return rc
diff --git a/daemons/lvmdbusd/utils.py b/daemons/lvmdbusd/utils.py
index d5c37de46..6c7a25f8d 100644
--- a/daemons/lvmdbusd/utils.py
+++ b/daemons/lvmdbusd/utils.py
@@ -768,3 +768,12 @@ def extract_stack_trace(exception):
return ''.join(traceback.format_exception(None, exception, exception.__traceback__))
+class LvmBug(RuntimeError):
+ """
+ Things that are clearly a bug with lvm itself.
+ """
+ def __init__(self, msg):
+ super().__init__(msg)
+
+ def __str__(self):
+ return "lvm bug encountered: %s" % ' '.join(self.args)
diff --git a/daemons/lvmdbusd/vg.py b/daemons/lvmdbusd/vg.py
index 51fd07e8c..928146fdb 100644
--- a/daemons/lvmdbusd/vg.py
+++ b/daemons/lvmdbusd/vg.py
@@ -20,7 +20,7 @@ from .request import RequestEntry
from .loader import common
from .state import State
from . import background
-from .utils import round_size, mt_remove_dbus_objects
+from .utils import round_size, mt_remove_dbus_objects, LvmBug
from .job import JobState
@@ -31,17 +31,25 @@ def vgs_state_retrieve(selection, cache_refresh=True):
if cache_refresh:
cfg.db.refresh()
- for v in cfg.db.fetch_vgs(selection):
- rc.append(
- VgState(
- v['vg_uuid'], v['vg_name'], v['vg_fmt'], n(v['vg_size']),
- n(v['vg_free']), v['vg_sysid'], n(v['vg_extent_size']),
- n(v['vg_extent_count']), n(v['vg_free_count']),
- v['vg_profile'], n(v['max_lv']), n(v['max_pv']),
- n(v['pv_count']), n(v['lv_count']), n(v['snap_count']),
- n(v['vg_seqno']), n(v['vg_mda_count']),
- n(v['vg_mda_free']), n(v['vg_mda_size']),
- n(v['vg_mda_used_count']), v['vg_attr'], v['vg_tags']))
+ try:
+ for v in cfg.db.fetch_vgs(selection):
+ rc.append(
+ VgState(
+ v['vg_uuid'], v['vg_name'], v['vg_fmt'], n(v['vg_size']),
+ n(v['vg_free']), v['vg_sysid'], n(v['vg_extent_size']),
+ n(v['vg_extent_count']), n(v['vg_free_count']),
+ v['vg_profile'], n(v['max_lv']), n(v['max_pv']),
+ n(v['pv_count']), n(v['lv_count']), n(v['snap_count']),
+ n(v['vg_seqno']), n(v['vg_mda_count']),
+ n(v['vg_mda_free']), n(v['vg_mda_size']),
+ n(v['vg_mda_used_count']), v['vg_attr'], v['vg_tags']))
+ except KeyError as ke:
+ # Sometimes lvm omits returning one of the keys we requested.
+ key = ke.args[0]
+ if key.startswith("vg_") or key.startswith("lv_") or key.startswith("pv_") or \
+ key in ["max_lv", "max_pv", "snap_count"]:
+ raise LvmBug("missing JSON key: '%s'" % key)
+ raise ke
return rc
6 months, 1 week
main - lvmdbusd: Use common function for traceback
by Tony Asleson
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=cb32b0a87f9c2c5b9d7...
Commit: cb32b0a87f9c2c5b9d79f02e59e3925d8350c70b
Parent: 22942f49162bca9e99172d64dfd03e7a881ce5b2
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Wed Aug 31 11:18:55 2022 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Fri Sep 16 10:49:37 2022 -0500
lvmdbusd: Use common function for traceback
We were using a number of different ways to achieve the same result. Use
a common function to make this consistent.
---
daemons/lvmdbusd/cmdhandler.py | 13 ++++++-------
daemons/lvmdbusd/lv.py | 6 ++----
daemons/lvmdbusd/lvm_shell_proxy.py.in | 6 +++---
daemons/lvmdbusd/main.py | 5 ++---
daemons/lvmdbusd/objectmanager.py | 7 +++----
daemons/lvmdbusd/request.py | 5 ++---
daemons/lvmdbusd/utils.py | 15 ++++++++++-----
7 files changed, 28 insertions(+), 29 deletions(-)
diff --git a/daemons/lvmdbusd/cmdhandler.py b/daemons/lvmdbusd/cmdhandler.py
index d5dceb64e..fd6ecf326 100644
--- a/daemons/lvmdbusd/cmdhandler.py
+++ b/daemons/lvmdbusd/cmdhandler.py
@@ -13,12 +13,11 @@ import time
import threading
from itertools import chain
import collections
-import traceback
import os
from lvmdbusd import cfg
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify,\
- make_non_block, read_decoded
+ make_non_block, read_decoded, extract_stack_trace
from lvmdbusd.lvm_shell_proxy import LVMShellProxy
try:
@@ -149,8 +148,8 @@ def call_lvm(command, debug=False, line_cb=None,
if i != -1:
try:
line_cb(cb_data, stdout_text[stdout_index:i])
- except:
- st = traceback.format_exc()
+ except BaseException as be:
+ st = extract_stack_trace(be)
log_error("call_lvm: line_cb exception: \n %s" % st)
stdout_index = i + 1
else:
@@ -189,11 +188,11 @@ def _shell_cfg():
_t_call = lvm_shell.call_lvm
cfg.SHELL_IN_USE = lvm_shell
return True
- except Exception:
+ except Exception as e:
_t_call = call_lvm
cfg.SHELL_IN_USE = None
- 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\n%s" % extract_stack_trace(e))
return False
diff --git a/daemons/lvmdbusd/lv.py b/daemons/lvmdbusd/lv.py
index 349ada006..8c55f5ffd 100644
--- a/daemons/lvmdbusd/lv.py
+++ b/daemons/lvmdbusd/lv.py
@@ -24,8 +24,6 @@ from . import background
from .utils import round_size, mt_remove_dbus_objects
from .job import JobState
-import traceback
-
# 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
@@ -371,8 +369,8 @@ class LvCommon(AutomatedProperties):
return dbus.Struct((self.state.Attr[index],
type_map.get(self.state.Attr[index], default)),
signature="(ss)")
- except BaseException:
- st = traceback.format_exc()
+ except BaseException as b:
+ st = utils.extract_stack_trace(b)
log_error("attr_struct: \n%s" % st)
return dbus.Struct(('?', 'Unavailable'), signature="(ss)")
diff --git a/daemons/lvmdbusd/lvm_shell_proxy.py.in b/daemons/lvmdbusd/lvm_shell_proxy.py.in
index feb93fbfa..77c0078ee 100644
--- a/daemons/lvmdbusd/lvm_shell_proxy.py.in
+++ b/daemons/lvmdbusd/lvm_shell_proxy.py.in
@@ -14,11 +14,11 @@
import subprocess
import shlex
import os
-import traceback
import sys
import tempfile
import time
import select
+from .utils import extract_stack_trace
try:
import simplejson as json
@@ -279,8 +279,8 @@ if __name__ == "__main__":
pass
except EOFError:
pass
- except Exception:
- traceback.print_exc(file=sys.stdout)
+ except Exception as e:
+ log_error("main process exiting on exception!\n%s", extract_stack_trace(e))
sys.exit(1)
sys.exit(0)
diff --git a/daemons/lvmdbusd/main.py b/daemons/lvmdbusd/main.py
index b485e0245..a426a535d 100644
--- a/daemons/lvmdbusd/main.py
+++ b/daemons/lvmdbusd/main.py
@@ -22,7 +22,6 @@ from . import lvmdb
from gi.repository import GLib
from .fetch import StateUpdate
from .manager import Manager
-import traceback
import queue
from . import udevwatch
from .utils import log_debug, log_error, log_msg, DebugMessages
@@ -52,8 +51,8 @@ def process_request():
pass
except SystemExit:
break
- except Exception:
- st = traceback.format_exc()
+ except Exception as e:
+ st = utils.extract_stack_trace(e)
utils.log_error("process_request exception: \n%s" % st)
log_debug("process_request thread exiting!")
diff --git a/daemons/lvmdbusd/objectmanager.py b/daemons/lvmdbusd/objectmanager.py
index a0c4a50ef..b84e16904 100644
--- a/daemons/lvmdbusd/objectmanager.py
+++ b/daemons/lvmdbusd/objectmanager.py
@@ -9,12 +9,11 @@
import sys
import threading
-import traceback
import dbus
import os
import copy
from . import cfg
-from .utils import log_debug, pv_obj_path_generate, log_error
+from .utils import log_debug, pv_obj_path_generate, log_error, extract_stack_trace
from .automatedproperties import AutomatedProperties
@@ -40,8 +39,8 @@ class ObjectManager(AutomatedProperties):
for k, v in list(obj._objects.items()):
path, props = v[0].emit_data()
rc[path] = props
- except Exception:
- traceback.print_exc(file=sys.stdout)
+ except Exception as e:
+ log_error("_get_managed_objects exception, bailing: \n%s" % extract_stack_trace(e))
sys.exit(1)
return rc
diff --git a/daemons/lvmdbusd/request.py b/daemons/lvmdbusd/request.py
index 57d72d8af..5d4d7e30a 100644
--- a/daemons/lvmdbusd/request.py
+++ b/daemons/lvmdbusd/request.py
@@ -13,8 +13,7 @@ import threading
from gi.repository import GLib
from .job import Job
from . import cfg
-import traceback
-from .utils import log_error, mt_async_call
+from .utils import log_error, mt_async_call, extract_stack_trace
class RequestEntry(object):
@@ -86,7 +85,7 @@ class RequestEntry(object):
# exception in the journal for figuring out what went wrong.
cfg.debug.dump()
cfg.flightrecorder.dump()
- tb = ''.join(traceback.format_tb(e.__traceback__))
+ tb = extract_stack_trace(e)
log_error("While processing %s: we encountered\n%s" % (str(self.method), tb))
log_error("Error returned to client: %s" % str(e))
self.register_error(-1, str(e), e)
diff --git a/daemons/lvmdbusd/utils.py b/daemons/lvmdbusd/utils.py
index ae925aa5f..d5c37de46 100644
--- a/daemons/lvmdbusd/utils.py
+++ b/daemons/lvmdbusd/utils.py
@@ -389,8 +389,8 @@ def handler(signum):
log_error('Exiting daemon with signal %d' % signum)
if cfg.loop is not None:
cfg.loop.quit()
- except:
- st = traceback.format_exc()
+ except BaseException as be:
+ st = extract_stack_trace(be)
log_error("signal handler: exception (logged, not reported!) \n %s" % st)
# It's important we report that we handled the exception for the exception
@@ -659,9 +659,8 @@ def _async_handler(call_back, parameters):
call_back(*parameters)
else:
call_back()
- except:
- st = traceback.format_exc()
- log_error("mt_async_call: exception (logged, not reported!) \n %s" % st)
+ except BaseException as be:
+ log_error("mt_async_call: exception (logged, not reported!) \n %s" % extract_stack_trace(be))
# Execute the function on the main thread with the provided parameters, do
@@ -763,3 +762,9 @@ class LockFile(object):
def __exit__(self, _type, _value, _traceback):
os.close(self.fd)
+
+
+def extract_stack_trace(exception):
+ return ''.join(traceback.format_exception(None, exception, exception.__traceback__))
+
+
6 months, 1 week
main - lvmdbusd: Don't output debug for fullreport exit code 5
by Tony Asleson
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=22942f49162bca9e991...
Commit: 22942f49162bca9e99172d64dfd03e7a881ce5b2
Parent: f5876a1f3fb729d255ea0bc3974d2891381620b3
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Wed Aug 31 11:05:36 2022 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Fri Sep 16 10:49:37 2022 -0500
lvmdbusd: Don't output debug for fullreport exit code 5
This is expected with an exported vg
---
daemons/lvmdbusd/cmdhandler.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/daemons/lvmdbusd/cmdhandler.py b/daemons/lvmdbusd/cmdhandler.py
index 23104e93e..d5dceb64e 100644
--- a/daemons/lvmdbusd/cmdhandler.py
+++ b/daemons/lvmdbusd/cmdhandler.py
@@ -164,7 +164,7 @@ def call_lvm(command, debug=False, line_cb=None,
break
if process.returncode is not None:
- if debug or process.returncode != 0:
+ if debug or (process.returncode != 0 and (process.returncode != 5 and "fullreport" in command)):
_debug_c(command, process.returncode, (stdout_text, stderr_text))
return process.returncode, stdout_text, stderr_text
6 months, 1 week
main - lvmdbustest: Skip test_nesting if scan_lvs is not enabled
by Tony Asleson
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=f5876a1f3fb729d255e...
Commit: f5876a1f3fb729d255ea0bc3974d2891381620b3
Parent: e5c41b94b841abe1ce3c23c814f7f7c31048b6e8
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Tue Aug 30 12:47:14 2022 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Fri Sep 16 10:49:37 2022 -0500
lvmdbustest: Skip test_nesting if scan_lvs is not enabled
---
test/dbus/lvmdbustest.py | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/test/dbus/lvmdbustest.py b/test/dbus/lvmdbustest.py
index 772313246..c932d0830 100755
--- a/test/dbus/lvmdbustest.py
+++ b/test/dbus/lvmdbustest.py
@@ -2040,6 +2040,17 @@ class TestDbusService(unittest.TestCase):
return new_pv_object_path
+ @staticmethod
+ def _scan_lvs_enabled():
+ cmd = ['lvmconfig', '--typeconfig', 'full', 'devices/scan_lvs']
+ config = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True, env=os.environ)
+ out = config.communicate()
+ if config.returncode != 0:
+ return False
+ if "scan_lvs=1" == out[0].decode("utf-8").strip():
+ return True
+ return False
+
def test_nesting(self):
# check to see if we handle an LV becoming a PV which has it's own
# LV
@@ -2053,6 +2064,8 @@ class TestDbusService(unittest.TestCase):
if dm_dev_dir != '/dev':
raise unittest.SkipTest('test not running in real /dev')
+ if not TestDbusService._scan_lvs_enabled():
+ raise unittest.SkipTest('scan_lvs=0 in config, unit test requires scan_lvs=1')
pv_object_path = self.objs[PV_INT][0].object_path
if not self.objs[PV_INT][0].Pv.Name.startswith("/dev"):
raise unittest.SkipTest('test not running in /dev')
6 months, 1 week
main - lvmdbusd: refactor and correct fetch thread logic
by Tony Asleson
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=e5c41b94b841abe1ce3...
Commit: e5c41b94b841abe1ce3c23c814f7f7c31048b6e8
Parent: 25abe41b00e1c9b525a1ff5e043b4b8507ba03cf
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Mon Aug 29 16:18:06 2022 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Fri Sep 16 10:49:37 2022 -0500
lvmdbusd: refactor and correct fetch thread logic
Simplify the fetch thread and correct the logic used for selecting the
options which are used when we batch update a state refresh.
---
daemons/lvmdbusd/fetch.py | 53 +++++++++++++++++++++--------------------------
1 file changed, 24 insertions(+), 29 deletions(-)
diff --git a/daemons/lvmdbusd/fetch.py b/daemons/lvmdbusd/fetch.py
index 6cf64f148..d1759f7dd 100644
--- a/daemons/lvmdbusd/fetch.py
+++ b/daemons/lvmdbusd/fetch.py
@@ -140,15 +140,29 @@ class StateUpdate(object):
except queue.Empty:
pass
+ def _load_args(requests):
+ """
+ If we have multiple requests in the queue, they might not all have the same options. If any of the requests
+ have an option set we need to honor it.
+ """
+ refresh = any([r.refresh for r in requests])
+ emit_signal = any([r.emit_signal for r in requests])
+ cache_refresh = any([r.cache_refresh for r in requests])
+ log = any([r.log for r in requests])
+ need_main_thread = any([r.need_main_thread for r in requests])
+
+ return refresh, emit_signal, cache_refresh, log, need_main_thread
+
+ def _drain_queue(queued, incoming):
+ try:
+ while True:
+ queued.append(incoming.get(block=False))
+ except queue.Empty:
+ pass
+
while cfg.run.value != 0:
# noinspection PyBroadException
try:
- refresh = True
- emit_signal = True
- cache_refresh = True
- log = True
- need_main_thread = True
-
with obj.lock:
wait = not obj.deferred
obj.deferred = False
@@ -156,36 +170,17 @@ class StateUpdate(object):
if len(queued_requests) == 0 and wait:
# Note: If we don't have anything for 2 seconds we will
# get a queue.Empty exception raised here
- queued_requests.append(obj.queue.get(True, 2))
+ queued_requests.append(obj.queue.get(block=True, timeout=2))
# Ok we have one or the deferred queue has some,
- # check if any others
- try:
- while True:
- queued_requests.append(obj.queue.get(False))
-
- except queue.Empty:
- pass
+ # check if any others and grab them too
+ _drain_queue(queued_requests, obj.queue)
if len(queued_requests) > 1:
log_debug("Processing %d updates!" % len(queued_requests),
'bg_black', 'fg_light_green')
- # We have what we can, run the update with the needed options
- for i in queued_requests:
- if not i.refresh:
- refresh = False
- if not i.emit_signal:
- emit_signal = False
- if not i.cache_refresh:
- cache_refresh = False
- if not i.log:
- log = False
- if not i.need_main_thread:
- need_main_thread = False
-
- num_changes = load(refresh, emit_signal, cache_refresh, log,
- need_main_thread)
+ num_changes = load(*_load_args(queued_requests))
# Update is done, let everyone know!
set_results(num_changes)
6 months, 1 week
main - lvmdbusd: Re-work error handling for run_cmd
by Tony Asleson
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=25abe41b00e1c9b525a...
Commit: 25abe41b00e1c9b525a1ff5e043b4b8507ba03cf
Parent: e6e874922e05e2b163b7f03b61cd4fb51e0858f6
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Fri Aug 26 13:01:05 2022 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Fri Sep 16 10:49:37 2022 -0500
lvmdbusd: Re-work error handling for run_cmd
Instead of lumping all the exceptions, break them out to handle the dbus
exceptions separately, to reduce the amount of debug information that ends
up in the journal that has questionable value.
---
daemons/lvmdbusd/request.py | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/daemons/lvmdbusd/request.py b/daemons/lvmdbusd/request.py
index d6024d99e..57d72d8af 100644
--- a/daemons/lvmdbusd/request.py
+++ b/daemons/lvmdbusd/request.py
@@ -7,6 +7,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import dbus
import threading
# noinspection PyUnresolvedReferences
from gi.repository import GLib
@@ -74,14 +75,20 @@ class RequestEntry(object):
except SystemExit as se:
self.register_error(-1, str(se), se)
raise se
+ except dbus.exceptions.DBusException as dbe:
+ # This is an expected error path when something goes awry that
+ # we handled
+ self.register_error(-1, str(dbe), dbe)
except Exception as e:
# Use the request entry to return the result as the client may
# have gotten a job by the time we hit an error
- # Lets get the stacktrace and set that to the error message
- st = traceback.format_exc()
+ # Lets set the exception text as the error message and log the
+ # exception in the journal for figuring out what went wrong.
cfg.debug.dump()
cfg.flightrecorder.dump()
- log_error("Exception returned to client: \n%s" % st)
+ tb = ''.join(traceback.format_tb(e.__traceback__))
+ log_error("While processing %s: we encountered\n%s" % (str(self.method), tb))
+ log_error("Error returned to client: %s" % str(e))
self.register_error(-1, str(e), e)
def is_done(self):
6 months, 1 week
main - lvmdbusd: Handle SIGINT quietly
by Tony Asleson
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=e6e874922e05e2b163b...
Commit: e6e874922e05e2b163b7f03b61cd4fb51e0858f6
Parent: 0296e56073667216e6b1d7397880b02df8df54c8
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Fri Aug 26 11:10:24 2022 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Fri Sep 16 10:49:37 2022 -0500
lvmdbusd: Handle SIGINT quietly
Change how we exit on SIGINT so that we don't output needless debug.
---
daemons/lvmdbusd/cmdhandler.py | 2 +-
daemons/lvmdbusd/fetch.py | 4 ++++
daemons/lvmdbusd/lvm_shell_proxy.py.in | 17 +++++++++--------
daemons/lvmdbusd/main.py | 2 ++
daemons/lvmdbusd/request.py | 3 +++
5 files changed, 19 insertions(+), 9 deletions(-)
diff --git a/daemons/lvmdbusd/cmdhandler.py b/daemons/lvmdbusd/cmdhandler.py
index 11cd0f0cd..23104e93e 100644
--- a/daemons/lvmdbusd/cmdhandler.py
+++ b/daemons/lvmdbusd/cmdhandler.py
@@ -170,7 +170,7 @@ def call_lvm(command, debug=False, line_cb=None,
return process.returncode, stdout_text, stderr_text
else:
if cfg.run.value == 0:
- raise Exception("Daemon is exiting!")
+ raise SystemExit
# We can bail out before the lvm command finished when we get a signal
# which is requesting we exit
return -errno.EINTR, "", "operation interrupted"
diff --git a/daemons/lvmdbusd/fetch.py b/daemons/lvmdbusd/fetch.py
index 5cb98853a..6cf64f148 100644
--- a/daemons/lvmdbusd/fetch.py
+++ b/daemons/lvmdbusd/fetch.py
@@ -154,6 +154,8 @@ class StateUpdate(object):
obj.deferred = False
if len(queued_requests) == 0 and wait:
+ # Note: If we don't have anything for 2 seconds we will
+ # get a queue.Empty exception raised here
queued_requests.append(obj.queue.get(True, 2))
# Ok we have one or the deferred queue has some,
@@ -192,6 +194,8 @@ class StateUpdate(object):
except queue.Empty:
pass
+ except SystemExit:
+ break
except Exception as e:
exception_count += 1
if exception_count >= 5:
diff --git a/daemons/lvmdbusd/lvm_shell_proxy.py.in b/daemons/lvmdbusd/lvm_shell_proxy.py.in
index 66c90c38a..feb93fbfa 100644
--- a/daemons/lvmdbusd/lvm_shell_proxy.py.in
+++ b/daemons/lvmdbusd/lvm_shell_proxy.py.in
@@ -109,6 +109,13 @@ class LVMShellProxy(object):
log_debug(str(ioe))
pass
+ if keep_reading and run.value == 0:
+ # We didn't complete as we are shutting down
+ # Try to clean up lvm shell process
+ log_debug("exiting lvm shell as we are shutting down")
+ self.exit_shell()
+ raise SystemExit
+
return stdout, report_json, stderr
def _write_cmd(self, cmd):
@@ -226,16 +233,10 @@ class LVMShellProxy(object):
error_msg = 'No error reason provided! (missing "log" section)'
if debug or rc != 0:
- log_error(('CMD: %s' % cmd))
- log_error(("EC = %d" % rc))
+ log_error(("CMD= %s" % cmd))
+ log_error(("EC= %d" % rc))
log_error(("ERROR_MSG=\n %s\n" % error_msg))
- if run.value == 0:
- # Try to clean up lvm shelll process
- log_debug("exiting lvm shell as we are shutting down")
- self.exit_shell()
- raise Exception("Daemon is exiting!")
-
return rc, report_json, error_msg
def exit_shell(self):
diff --git a/daemons/lvmdbusd/main.py b/daemons/lvmdbusd/main.py
index 3fcabe6b6..b485e0245 100644
--- a/daemons/lvmdbusd/main.py
+++ b/daemons/lvmdbusd/main.py
@@ -50,6 +50,8 @@ def process_request():
log_debug("Method complete: %s" % str(req.method))
except queue.Empty:
pass
+ except SystemExit:
+ break
except Exception:
st = traceback.format_exc()
utils.log_error("process_request exception: \n%s" % st)
diff --git a/daemons/lvmdbusd/request.py b/daemons/lvmdbusd/request.py
index 546b85b23..d6024d99e 100644
--- a/daemons/lvmdbusd/request.py
+++ b/daemons/lvmdbusd/request.py
@@ -71,6 +71,9 @@ class RequestEntry(object):
try:
result = self.method(*self.arguments)
self.register_result(result)
+ except SystemExit as se:
+ self.register_error(-1, str(se), se)
+ raise se
except Exception as e:
# Use the request entry to return the result as the client may
# have gotten a job by the time we hit an error
6 months, 1 week
main - lvmdbusd: Don't report recoverable error
by Tony Asleson
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=0296e56073667216e6b...
Commit: 0296e56073667216e6b1d7397880b02df8df54c8
Parent: 29189948732b4385fa053c94ac2dc31e3cfc3dfa
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Thu Aug 25 09:33:50 2022 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Fri Sep 16 10:49:37 2022 -0500
lvmdbusd: Don't report recoverable error
Lvm occasionally fails to return all the request JSON keys in the output of
"fullreport". This happens very rarely. When it does the daemon was reporting
the resulting informational exception:
MThreadRunner: exception
Traceback (most recent call last):
File "/usr/lib/python3.9/site-packages/lvmdbusd/utils.py", line 667, in _run
self.rc = self.f(*self.args)
File "/usr/lib/python3.9/site-packages/lvmdbusd/fetch.py", line 40, in _main_thread_load
(lv_changes, remove) = load_lvs(
File "/usr/lib/python3.9/site-packages/lvmdbusd/lv.py", line 143, in load_lvs
return common(
File "/usr/lib/python3.9/site-packages/lvmdbusd/loader.py", line 37, in common
objects = retrieve(search_keys, cache_refresh=False)
File "/usr/lib/python3.9/site-packages/lvmdbusd/lv.py", line 95, in lvs_state_retrieve
l['vdo_operating_mode'],
KeyError: 'vdo_operating_mode'
The daemon retries the operation, which usually works and the daemon continues.
However, simply reporting this informational stack trace is causing CI and other
automated tests to fail as they expect no tracebacks in the log output.
Remove the reporting of this code path unless it persists and causes the daemon
to give up and exit.
Ref: https://bugzilla.redhat.com/show_bug.cgi?id=2120267
---
daemons/lvmdbusd/fetch.py | 10 ++++------
daemons/lvmdbusd/utils.py | 3 ---
2 files changed, 4 insertions(+), 9 deletions(-)
diff --git a/daemons/lvmdbusd/fetch.py b/daemons/lvmdbusd/fetch.py
index ed519b660..5cb98853a 100644
--- a/daemons/lvmdbusd/fetch.py
+++ b/daemons/lvmdbusd/fetch.py
@@ -193,16 +193,14 @@ class StateUpdate(object):
except queue.Empty:
pass
except Exception as e:
- st = traceback.format_exc()
- log_error("update_thread exception: \n%s" % st)
- cfg.debug.dump()
- cfg.flightrecorder.dump()
exception_count += 1
if exception_count >= 5:
+ st = traceback.format_exc()
+ log_error("Too many errors in update_thread, exiting daemon (last exception reported): \n %s" % st)
+ cfg.debug.dump()
+ cfg.flightrecorder.dump()
bailing(e)
- log_error("Too many errors in update_thread, exiting daemon")
cfg.exit_daemon()
-
else:
# Slow things down when encountering errors
time.sleep(1)
diff --git a/daemons/lvmdbusd/utils.py b/daemons/lvmdbusd/utils.py
index 802f71173..ae925aa5f 100644
--- a/daemons/lvmdbusd/utils.py
+++ b/daemons/lvmdbusd/utils.py
@@ -711,9 +711,6 @@ class MThreadRunner(object):
self.rc = self.f()
except BaseException as be:
self.exception = be
- st = traceback.format_exc()
- log_error("MThreadRunner: exception \n %s" % st)
- log_error("Exception will be raised in calling thread!")
def _remove_objects(dbus_objects_rm):
6 months, 1 week