main - lvmdbusd: WS, imports, grammar
by Tony Asleson
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=29189948732b4385fa0...
Commit: 29189948732b4385fa053c94ac2dc31e3cfc3dfa
Parent: b0c7220dbbb38c54f3d47afc9748b53438bc154e
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Thu Aug 25 08:33:50 2022 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Fri Sep 16 10:49:37 2022 -0500
lvmdbusd: WS, imports, grammar
---
daemons/lvmdbusd/automatedproperties.py | 1 -
daemons/lvmdbusd/background.py | 5 +----
daemons/lvmdbusd/cmdhandler.py | 2 --
daemons/lvmdbusd/lv.py | 38 ++++++++++++++++-----------------
daemons/lvmdbusd/lvm_shell_proxy.py.in | 2 +-
daemons/lvmdbusd/lvmdb.py.in | 2 +-
6 files changed, 22 insertions(+), 28 deletions(-)
diff --git a/daemons/lvmdbusd/automatedproperties.py b/daemons/lvmdbusd/automatedproperties.py
index d9f2c5e9f..be41502bd 100644
--- a/daemons/lvmdbusd/automatedproperties.py
+++ b/daemons/lvmdbusd/automatedproperties.py
@@ -88,7 +88,6 @@ class AutomatedProperties(dbus.service.Object):
cb, cbe, False)
cfg.worker_q.put(r)
-
@staticmethod
def _get_all_prop(obj, interface_name):
if interface_name in obj.interface(True):
diff --git a/daemons/lvmdbusd/background.py b/daemons/lvmdbusd/background.py
index 21617c47a..50b19c817 100644
--- a/daemons/lvmdbusd/background.py
+++ b/daemons/lvmdbusd/background.py
@@ -7,16 +7,13 @@
# 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 subprocess
from . import cfg
from .cmdhandler import options_to_cli_args, LvmExecutionMeta, call_lvm
import dbus
-from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug,\
- mt_async_call
+from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug
from .request import RequestEntry
import threading
import time
-import traceback
def pv_move_lv_cmd(move_options, lv_full_name,
diff --git a/daemons/lvmdbusd/cmdhandler.py b/daemons/lvmdbusd/cmdhandler.py
index 7605f8298..11cd0f0cd 100644
--- a/daemons/lvmdbusd/cmdhandler.py
+++ b/daemons/lvmdbusd/cmdhandler.py
@@ -26,7 +26,6 @@ try:
except ImportError:
import json
-SEP = '{|}'
total_time = 0.0
total_count = 0
@@ -177,7 +176,6 @@ def call_lvm(command, debug=False, line_cb=None,
return -errno.EINTR, "", "operation interrupted"
-
# The actual method which gets called to invoke the lvm command, can vary
# from forking a new process to using lvm shell
_t_call = call_lvm
diff --git a/daemons/lvmdbusd/lv.py b/daemons/lvmdbusd/lv.py
index edfdd0d30..349ada006 100644
--- a/daemons/lvmdbusd/lv.py
+++ b/daemons/lvmdbusd/lv.py
@@ -274,15 +274,15 @@ class LvStateVdo(LvState):
MetaDataPercent, CopyPercent, SyncPercent,
MetaDataSizeBytes, move_pv, move_pv_uuid,
vdo_operating_mode, vdo_compression_state, vdo_index_state,
- vdo_used_size,vdo_saving_percent,vdo_compression,
- vdo_deduplication,vdo_use_metadata_hints,
- vdo_minimum_io_size,vdo_block_map_cache_size,
- vdo_block_map_era_length,vdo_use_sparse_index,
- vdo_index_memory_size,vdo_slab_size,vdo_ack_threads,
- vdo_bio_threads,vdo_bio_rotation,vdo_cpu_threads,
- vdo_hash_zone_threads,vdo_logical_threads,
- vdo_physical_threads,vdo_max_discard,
- vdo_write_policy,vdo_header_size):
+ vdo_used_size, vdo_saving_percent, vdo_compression,
+ vdo_deduplication, vdo_use_metadata_hints,
+ vdo_minimum_io_size, vdo_block_map_cache_size,
+ vdo_block_map_era_length, vdo_use_sparse_index,
+ vdo_index_memory_size, vdo_slab_size, vdo_ack_threads,
+ vdo_bio_threads, vdo_bio_rotation, vdo_cpu_threads,
+ vdo_hash_zone_threads, vdo_logical_threads,
+ vdo_physical_threads, vdo_max_discard,
+ vdo_write_policy, vdo_header_size):
super(LvStateVdo, self).__init__(Uuid, Name, Path, SizeBytes,
vg_name, vg_uuid, pool_lv_uuid, PoolLv,
origin_uuid, OriginLv, DataPercent, Attr, Tags, active,
@@ -595,7 +595,7 @@ class Lv(LvCommon):
optional_size = space + 512 - remainder
LvCommon.handle_execute(*cmdhandler.vg_lv_snapshot(
- lv_name, snapshot_options,name, optional_size))
+ lv_name, snapshot_options, name, optional_size))
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
return cfg.om.get_object_path_by_lvm_id(full_name)
@@ -635,7 +635,7 @@ class Lv(LvCommon):
size_change = new_size_bytes - dbo.SizeBytes
LvCommon.handle_execute(*cmdhandler.lv_resize(
- dbo.lvm_id, size_change,pv_dests, resize_options))
+ dbo.lvm_id, size_change, pv_dests, resize_options))
return "/"
@dbus.service.method(
@@ -845,10 +845,10 @@ class LvVdoPool(Lv):
cfg.worker_q.put(r)
@dbus.service.method(
- dbus_interface=VDO_POOL_INTERFACE,
- in_signature='ia{sv}',
- out_signature='o',
- async_callbacks=('cb', 'cbe'))
+ dbus_interface=VDO_POOL_INTERFACE,
+ in_signature='ia{sv}',
+ out_signature='o',
+ async_callbacks=('cb', 'cbe'))
def DisableCompression(self, tmo, comp_options, cb, cbe):
r = RequestEntry(
tmo, LvVdoPool._enable_disable_compression,
@@ -878,10 +878,10 @@ class LvVdoPool(Lv):
cfg.worker_q.put(r)
@dbus.service.method(
- dbus_interface=VDO_POOL_INTERFACE,
- in_signature='ia{sv}',
- out_signature='o',
- async_callbacks=('cb', 'cbe'))
+ dbus_interface=VDO_POOL_INTERFACE,
+ in_signature='ia{sv}',
+ out_signature='o',
+ async_callbacks=('cb', 'cbe'))
def DisableDeduplication(self, tmo, dedup_options, cb, cbe):
r = RequestEntry(
tmo, LvVdoPool._enable_disable_deduplication,
diff --git a/daemons/lvmdbusd/lvm_shell_proxy.py.in b/daemons/lvmdbusd/lvm_shell_proxy.py.in
index ebab57e97..66c90c38a 100644
--- a/daemons/lvmdbusd/lvm_shell_proxy.py.in
+++ b/daemons/lvmdbusd/lvm_shell_proxy.py.in
@@ -166,7 +166,7 @@ class LVMShellProxy(object):
def get_last_log(self):
self._write_cmd('lastlog\n')
- report_json= self._read_response()[1]
+ report_json = self._read_response()[1]
return LVMShellProxy.get_error_msg(report_json)
@staticmethod
diff --git a/daemons/lvmdbusd/lvmdb.py.in b/daemons/lvmdbusd/lvmdb.py.in
index d462e0cf8..2346d01e9 100644
--- a/daemons/lvmdbusd/lvmdb.py.in
+++ b/daemons/lvmdbusd/lvmdb.py.in
@@ -58,7 +58,7 @@ class DataStore(object):
c_lookup = {}
c_pvs_in_vgs = {}
- # Each item item in the report is a collection of information pertaining
+ # Each item in the report is a collection of information pertaining
# to the vg
for r in _all['report']:
tmp_pv = []
6 months, 1 week
main - lvmdbusd: Add debug circular buffer
by Tony Asleson
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=b0c7220dbbb38c54f3d...
Commit: b0c7220dbbb38c54f3d47afc9748b53438bc154e
Parent: f65f7da76065b2e36920ae4f866e9e912f74dde2
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Wed Aug 17 17:24:08 2022 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Fri Sep 16 10:49:37 2022 -0500
lvmdbusd: Add debug circular buffer
When the daemon isn't started with --debug we will keep a circular
buffer of the past N number of debug messages which we will output
when we encounter an issue.
---
daemons/lvmdbusd/cfg.py | 3 +++
daemons/lvmdbusd/cmdhandler.py | 2 ++
daemons/lvmdbusd/fetch.py | 1 +
daemons/lvmdbusd/main.py | 5 ++++-
daemons/lvmdbusd/manager.py | 1 +
daemons/lvmdbusd/request.py | 1 +
daemons/lvmdbusd/utils.py | 38 +++++++++++++++++++++++++++++++++++---
7 files changed, 47 insertions(+), 4 deletions(-)
diff --git a/daemons/lvmdbusd/cfg.py b/daemons/lvmdbusd/cfg.py
index d7a653b54..a758b8a77 100644
--- a/daemons/lvmdbusd/cfg.py
+++ b/daemons/lvmdbusd/cfg.py
@@ -97,6 +97,9 @@ flightrecorder = None
# RequestEntry ctor
create_request_entry = None
+# Circular debug log
+debug = None
+
def exit_daemon():
"""
diff --git a/daemons/lvmdbusd/cmdhandler.py b/daemons/lvmdbusd/cmdhandler.py
index b2d3077ad..7605f8298 100644
--- a/daemons/lvmdbusd/cmdhandler.py
+++ b/daemons/lvmdbusd/cmdhandler.py
@@ -88,6 +88,7 @@ class LvmFlightRecorder(object):
for c in reversed(self.queue):
log_error(str(c))
log_error("LVM dbus flight recorder END")
+ self.queue.clear()
cfg.flightrecorder = LvmFlightRecorder()
@@ -176,6 +177,7 @@ def call_lvm(command, debug=False, line_cb=None,
return -errno.EINTR, "", "operation interrupted"
+
# The actual method which gets called to invoke the lvm command, can vary
# from forking a new process to using lvm shell
_t_call = call_lvm
diff --git a/daemons/lvmdbusd/fetch.py b/daemons/lvmdbusd/fetch.py
index f1e9104a8..ed519b660 100644
--- a/daemons/lvmdbusd/fetch.py
+++ b/daemons/lvmdbusd/fetch.py
@@ -195,6 +195,7 @@ class StateUpdate(object):
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:
diff --git a/daemons/lvmdbusd/main.py b/daemons/lvmdbusd/main.py
index c58c518d1..3fcabe6b6 100644
--- a/daemons/lvmdbusd/main.py
+++ b/daemons/lvmdbusd/main.py
@@ -25,7 +25,7 @@ from .manager import Manager
import traceback
import queue
from . import udevwatch
-from .utils import log_debug, log_error, log_msg
+from .utils import log_debug, log_error, log_msg, DebugMessages
import argparse
import os
import sys
@@ -147,6 +147,9 @@ def main():
# cmdhandler is for when we are running other code with a different main.
cfg.flightrecorder = LvmFlightRecorder(cfg.args.fr_size)
+ # Create a circular buffer for debug logs
+ cfg.debug = DebugMessages()
+
log_debug("Using lvm binary: %s" % cfg.LVM_CMD)
# We will dynamically add interfaces which support vdo if it
diff --git a/daemons/lvmdbusd/manager.py b/daemons/lvmdbusd/manager.py
index 45e7bb0b8..9c41f0fc3 100644
--- a/daemons/lvmdbusd/manager.py
+++ b/daemons/lvmdbusd/manager.py
@@ -137,6 +137,7 @@ class Manager(AutomatedProperties):
"""
Dump the flight recorder to syslog
"""
+ cfg.debug.dump()
cfg.flightrecorder.dump()
@staticmethod
diff --git a/daemons/lvmdbusd/request.py b/daemons/lvmdbusd/request.py
index e069cfdc1..546b85b23 100644
--- a/daemons/lvmdbusd/request.py
+++ b/daemons/lvmdbusd/request.py
@@ -76,6 +76,7 @@ class RequestEntry(object):
# 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()
+ cfg.debug.dump()
cfg.flightrecorder.dump()
log_error("Exception returned to client: \n%s" % st)
self.register_error(-1, str(e), e)
diff --git a/daemons/lvmdbusd/utils.py b/daemons/lvmdbusd/utils.py
index 75a5348f5..802f71173 100644
--- a/daemons/lvmdbusd/utils.py
+++ b/daemons/lvmdbusd/utils.py
@@ -10,6 +10,7 @@
import xml.etree.ElementTree as Et
import sys
import inspect
+import collections
import ctypes
import errno
import fcntl
@@ -282,8 +283,28 @@ def parse_tags(tags):
return dbus.Array([], signature='s')
-def _common_log(msg, *attributes):
- cfg.stdout_lock.acquire()
+class DebugMessages(object):
+
+ def __init__(self, size=5000):
+ self.queue = collections.deque(maxlen=size)
+ self.lock = threading.RLock()
+
+ def add(self, message):
+ with self.lock:
+ self.queue.append(message)
+
+ def dump(self):
+ if cfg.args and not cfg.args.debug:
+ with self.lock:
+ if len(self.queue):
+ log_error("LVM dbus debug messages START last (%d max) messages" % self.queue.maxlen)
+ for m in self.queue:
+ print(m)
+ log_error("LVM dbus debug messages END")
+ self.queue.clear()
+
+
+def _format_log_entry(msg):
tid = ctypes.CDLL('libc.so.6').syscall(186)
if STDOUT_TTY:
@@ -293,6 +314,12 @@ def _common_log(msg, *attributes):
else:
msg = "%d:%d - %s" % (os.getpid(), tid, msg)
+ return msg
+
+
+def _common_log(msg, *attributes):
+ cfg.stdout_lock.acquire()
+ msg = _format_log_entry(msg)
if STDOUT_TTY and attributes:
print(color(msg, *attributes))
@@ -309,6 +336,9 @@ def _common_log(msg, *attributes):
def log_debug(msg, *attributes):
if cfg.args and cfg.args.debug:
_common_log(msg, *attributes)
+ else:
+ if cfg.debug:
+ cfg.debug.add(_format_log_entry(msg))
def log_error(msg, *attributes):
@@ -348,13 +378,15 @@ def handler(signum):
try:
# signal 10
if signum == signal.SIGUSR1:
+ cfg.debug.dump()
dump_threads_stackframe()
# signal 12
elif signum == signal.SIGUSR2:
+ cfg.debug.dump()
cfg.flightrecorder.dump()
else:
cfg.run.value = 0
- log_debug('Exiting daemon with signal %d' % signum)
+ log_error('Exiting daemon with signal %d' % signum)
if cfg.loop is not None:
cfg.loop.quit()
except:
6 months, 1 week
main - lvmdbustest: Skip test_singleton_daemon running systemd svc.
by Tony Asleson
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=f65f7da76065b2e3692...
Commit: f65f7da76065b2e36920ae4f866e9e912f74dde2
Parent: a5e6947d74f7b88f7f0df4328a923ad82a970634
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Wed Aug 24 15:41:03 2022 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Fri Sep 16 10:49:37 2022 -0500
lvmdbustest: Skip test_singleton_daemon running systemd svc.
---
test/dbus/lvmdbustest.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/test/dbus/lvmdbustest.py b/test/dbus/lvmdbustest.py
index ba93379dc..772313246 100755
--- a/test/dbus/lvmdbustest.py
+++ b/test/dbus/lvmdbustest.py
@@ -2342,6 +2342,8 @@ class TestDbusService(unittest.TestCase):
# Ensure we can only have 1 daemon running at a time, daemon should exit with 114 if already running
di = DaemonInfo.get()
self.assertTrue(di is not None)
+ if di.systemd:
+ raise unittest.SkipTest('existing dameon running via systemd')
if di:
ec = di.start(True)
self.assertEqual(ec, 114)
6 months, 1 week
main - lvmdbusd: Set LVM_COMMAND_PROFILE=lvmdbusd
by Tony Asleson
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=a5e6947d74f7b88f7f0...
Commit: a5e6947d74f7b88f7f0df4328a923ad82a970634
Parent: 9693709b4642c7ef0c82f117b4f776a1e688d851
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Wed Aug 24 15:37:56 2022 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Fri Sep 16 10:49:37 2022 -0500
lvmdbusd: Set LVM_COMMAND_PROFILE=lvmdbusd
We need this to prevent lvm from interleaving the JSON output with errors
written to stderr.
---
daemons/lvmdbusd/main.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/daemons/lvmdbusd/main.py b/daemons/lvmdbusd/main.py
index dc6aa2277..c58c518d1 100644
--- a/daemons/lvmdbusd/main.py
+++ b/daemons/lvmdbusd/main.py
@@ -132,8 +132,10 @@ def main():
start = time.time()
use_session = os.getenv('LVMDBUSD_USE_SESSION', False)
- # Ensure that we get consistent output for parsing stdout/stderr
+ # Ensure that we get consistent output for parsing stdout/stderr and that we
+ # are using the lvmdbusd profile.
os.environ["LC_ALL"] = "C"
+ os.environ["LVM_COMMAND_PROFILE"] = "lvmdbusd"
# Add simple command line handling
cfg.args = process_args()
6 months, 1 week
main - lvmdbustest: Add systemctl daemon start
by Tony Asleson
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=9693709b4642c7ef0c8...
Commit: 9693709b4642c7ef0c82f117b4f776a1e688d851
Parent: f252e05aaeb1a34598cc9d93e3c65ce2e311621b
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Tue Aug 23 10:54:22 2022 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Fri Sep 16 10:49:37 2022 -0500
lvmdbustest: Add systemctl daemon start
---
test/dbus/lvmdbustest.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/dbus/lvmdbustest.py b/test/dbus/lvmdbustest.py
index 72a75edea..ba93379dc 100755
--- a/test/dbus/lvmdbustest.py
+++ b/test/dbus/lvmdbustest.py
@@ -278,7 +278,7 @@ class DaemonInfo(object):
def start(self, expect_fail=False):
if self.systemd:
- pass
+ subprocess.run(["/usr/bin/systemctl", "start", "lvm2-lvmdbusd"], check=True)
else:
stdin_stream = None
stdout_stream = None
6 months, 1 week
main - lvmdbustest: Add test for ensuring only 1 instance of daemon
by Tony Asleson
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=f252e05aaeb1a34598c...
Commit: f252e05aaeb1a34598cc9d93e3c65ce2e311621b
Parent: d16c0a3e2bc1d36fc11ed763ac32184f09c6c67c
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Tue Aug 23 10:31:31 2022 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Fri Sep 16 10:49:37 2022 -0500
lvmdbustest: Add test for ensuring only 1 instance of daemon
---
test/dbus/lvmdbustest.py | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/test/dbus/lvmdbustest.py b/test/dbus/lvmdbustest.py
index 7a03c46a2..72a75edea 100755
--- a/test/dbus/lvmdbustest.py
+++ b/test/dbus/lvmdbustest.py
@@ -2338,6 +2338,14 @@ class TestDbusService(unittest.TestCase):
"Failed to exit after sending signal %f seconds after "
"queuing up work for signal %d" % (sleep_amt, signal.SIGINT))
+ def test_singleton_daemon(self):
+ # Ensure we can only have 1 daemon running at a time, daemon should exit with 114 if already running
+ di = DaemonInfo.get()
+ self.assertTrue(di is not None)
+ if di:
+ ec = di.start(True)
+ self.assertEqual(ec, 114)
+
class AggregateResults(object):
6 months, 1 week
main - lvmdbustest: Add test_sigint test
by Tony Asleson
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=d16c0a3e2bc1d36fc11...
Commit: d16c0a3e2bc1d36fc11ed763ac32184f09c6c67c
Parent: 52415b5708aa26fe322b13a9ffdb8cc16904ab45
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Tue Aug 23 10:30:53 2022 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Fri Sep 16 10:49:37 2022 -0500
lvmdbustest: Add test_sigint test
Get the daemon busy and send it SIGINT to ensure the daemon exits.
---
test/dbus/lvmdbustest.py | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/test/dbus/lvmdbustest.py b/test/dbus/lvmdbustest.py
index 2f1aa98a6..7a03c46a2 100755
--- a/test/dbus/lvmdbustest.py
+++ b/test/dbus/lvmdbustest.py
@@ -2303,6 +2303,41 @@ class TestDbusService(unittest.TestCase):
self.assertTrue('Job is not complete!' in str(e))
raise e
+ def test_sigint(self):
+ # Issue SIGINT while daemon is processing work to ensure we shut down.
+ di = DaemonInfo.get()
+ self.assertTrue(di is not None)
+ if di:
+ # Find out how long it takes to create a VG and a number of LVs
+ # we will then issue the creation of the LVs async., wait, then issue a signal
+ # and repeat stepping through the entire time range.
+ start = time.time()
+ vg_proxy = self._create_num_lvs(20)
+ end = time.time()
+
+ self.handle_return(vg_proxy.Vg.Remove(dbus.Int32(g_tmo), EOD))
+ total = end - start
+
+ for i in range(5):
+ sleep_amt = i * (total/5.0)
+ self._create_num_lvs(20, True)
+ time.sleep(sleep_amt)
+
+ exited = False
+ try:
+ di.term_signal(signal.SIGINT)
+ exited = True
+ except Exception:
+ std_err_print("Failed to exit on SIGINT, sending SIGKILL...")
+ di.term_signal(signal.SIGKILL)
+ finally:
+ di.start()
+ self.clean_up()
+
+ self.assertTrue(exited,
+ "Failed to exit after sending signal %f seconds after "
+ "queuing up work for signal %d" % (sleep_amt, signal.SIGINT))
+
class AggregateResults(object):
6 months, 1 week
main - lvmdbustest: Add optional option to _create_num_lvs
by Tony Asleson
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=52415b5708aa26fe322...
Commit: 52415b5708aa26fe322b13a9ffdb8cc16904ab45
Parent: d05d2328e0868c60ba95d3bd87b654146c078316
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Tue Aug 23 10:29:26 2022 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Fri Sep 16 10:49:37 2022 -0500
lvmdbustest: Add optional option to _create_num_lvs
This allows us to create the LVs async., thus queuing them up in daemon.
---
test/dbus/lvmdbustest.py | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/test/dbus/lvmdbustest.py b/test/dbus/lvmdbustest.py
index bee6eb085..2f1aa98a6 100755
--- a/test/dbus/lvmdbustest.py
+++ b/test/dbus/lvmdbustest.py
@@ -1288,24 +1288,28 @@ class TestDbusService(unittest.TestCase):
vg_path = self._wait_for_job(vg_job)
self._validate_lookup(vg_name, vg_path)
- def _create_num_lvs(self, num_lvs):
+ def _create_num_lvs(self, num_lvs, no_wait=False):
vg_proxy = self._vg_create(self._all_pv_object_paths())
+ if no_wait:
+ tmo = 0
+ else:
+ tmo = g_tmo
for i in range(0, num_lvs):
lv_name = lv_n()
vg_proxy.update()
if vg_proxy.Vg.FreeCount > 0:
- lv_path = self.handle_return(
- vg_proxy.Vg.LvCreateLinear(
+ create_result = vg_proxy.Vg.LvCreateLinear(
dbus.String(lv_name),
dbus.UInt64(mib(4)),
dbus.Boolean(False),
- dbus.Int32(g_tmo),
- EOD))
- self.assertTrue(lv_path != '/')
- self._validate_lookup(
- "%s/%s" % (vg_proxy.Vg.Name, lv_name), lv_path)
+ dbus.Int32(tmo),
+ EOD)
+ if not no_wait:
+ lv_path = self.handle_return(create_result)
+ self.assertTrue(lv_path != '/')
+ self._validate_lookup("%s/%s" % (vg_proxy.Vg.Name, lv_name), lv_path)
else:
# We ran out of space, test(s) may fail
break
6 months, 1 week
main - lvmdbustest: Factor out tearDown implementation for re-use
by Tony Asleson
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=d05d2328e0868c60ba9...
Commit: d05d2328e0868c60ba95d3bd87b654146c078316
Parent: de0258a60054166fd3a2b1732d74e7bae85e92f5
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Tue Aug 23 10:28:27 2022 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Fri Sep 16 10:49:37 2022 -0500
lvmdbustest: Factor out tearDown implementation for re-use
---
test/dbus/lvmdbustest.py | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/test/dbus/lvmdbustest.py b/test/dbus/lvmdbustest.py
index 5c352313d..bee6eb085 100755
--- a/test/dbus/lvmdbustest.py
+++ b/test/dbus/lvmdbustest.py
@@ -419,9 +419,7 @@ class TestDbusService(unittest.TestCase):
rc = self._pv_remove(pv_proxy)
self.assertTrue(rc == '/')
- def tearDown(self):
- # If we get here it means we passed setUp, so lets remove anything
- # and everything that remains, besides the PVs themselves
+ def clean_up(self):
self.objs, self.bus = get_objects()
# The self.objs[PV_INT] list only contains those which we should be
@@ -447,7 +445,7 @@ class TestDbusService(unittest.TestCase):
# the properties are current and correct.
p.update()
if p.Pv.Vg != '/':
- v = ClientProxy(self.bus, p.Pv.Vg, interfaces=(VG_INT, ))
+ v = ClientProxy(self.bus, p.Pv.Vg, interfaces=(VG_INT,))
self._recurse_vg_delete(v, p, nested_pvs)
# Check to make sure the PVs we had to start exist, else re-create
@@ -465,6 +463,11 @@ class TestDbusService(unittest.TestCase):
# print('Re-creating PV=', p)
self._pv_create(p)
+ def tearDown(self):
+ # If we get here it means we passed setUp, so lets remove anything
+ # and everything that remains, besides the PVs themselves
+ self.clean_up()
+
def _check_consistency(self):
# Only do consistency checks if we aren't running the unit tests
# concurrently
6 months, 1 week
main - lvmdbustest: Add DaemonInfo class
by Tony Asleson
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=de0258a60054166fd3a...
Commit: de0258a60054166fd3a2b1732d74e7bae85e92f5
Parent: ec50979b031e85ab155126aae51ab15b255f4be9
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Tue Aug 23 10:27:30 2022 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Fri Sep 16 10:49:37 2022 -0500
lvmdbustest: Add DaemonInfo class
This class handles identifying daemon, sending signals to it, and starting
it back up again.
---
test/dbus/lvmdbustest.py | 182 +++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 176 insertions(+), 6 deletions(-)
diff --git a/test/dbus/lvmdbustest.py b/test/dbus/lvmdbustest.py
index c4e95b7cc..5c352313d 100755
--- a/test/dbus/lvmdbustest.py
+++ b/test/dbus/lvmdbustest.py
@@ -9,23 +9,28 @@
# 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 signal
# noinspection PyUnresolvedReferences
+import subprocess
+import unittest
+from glob import glob
+from subprocess import Popen, PIPE
+
import dbus
+import pyudev
# noinspection PyUnresolvedReferences
from dbus.mainloop.glib import DBusGMainLoop
-import unittest
-import pyudev
-from testlib import *
+
import testlib
-from subprocess import Popen, PIPE
-from glob import glob
-import os
+from testlib import *
g_tmo = 0
# Approx. min size
VDO_MIN_SIZE = mib(8192)
+EXE_NAME="/lvmdbusd"
+
# Prefix on created objects to enable easier clean-up
g_prefix = os.getenv('PREFIX', '')
@@ -210,6 +215,171 @@ def supports_vdo():
return True
+def process_exists(name):
+ # Walk the process table looking for executable 'name'
+ for p in [pid for pid in os.listdir('/proc') if pid.isdigit()]:
+ try:
+ cmdline_args = read_file_split_nuls("/proc/%s/cmdline" % p)
+ except OSError:
+ continue
+ for arg in cmdline_args:
+ if name in arg:
+ return int(p)
+ return None
+
+
+def read_file_split_nuls(fn):
+ with open(fn, "rb") as fh:
+ return [p.decode("utf-8") for p in fh.read().split(b'\x00') if len(p) > 0]
+
+
+def read_file_build_hash(fn):
+ rc = dict()
+ lines = read_file_split_nuls(fn)
+ for line in lines:
+ if line.count("=") == 1:
+ k, v = line.split("=")
+ rc[k] = v
+ return rc
+
+
+class DaemonInfo(object):
+ def __init__(self, pid):
+ # The daemon is running, we have a pid, lets see how it's being run.
+ # When running under systemd, fd 0 -> /dev/null, fd 1&2 -> socket
+ # when ran manually it may have output re-directed to a file etc.
+ # we need the following
+ # command line arguments
+ # cwd
+ # where the output is going (in case it's directed to a file)
+ # Which lvm binary is being used (check LVM_BINARY env. variable)
+ # PYTHONPATH
+ base = "/proc/%d" % pid
+ self.cwd = os.readlink("%s/cwd" % base)
+ self.cmdline = read_file_split_nuls("%s/cmdline" % (base))[1:]
+ self.env = read_file_build_hash("%s/environ" % base)
+ self.stdin = os.readlink("%s/fd/0" % base)
+ self.stdout = os.readlink("%s/fd/1" % base)
+ self.stderr = os.readlink("%s/fd/2" % base)
+
+ if self.cwd == "/" and self.stdin == "/dev/null":
+ self.systemd = True
+ else:
+ self.systemd = False
+
+ self.process = None
+
+ @classmethod
+ def get(cls):
+ pid = process_exists(EXE_NAME)
+ if pid:
+ return cls(pid)
+ return None
+
+ def start(self, expect_fail=False):
+ if self.systemd:
+ pass
+ else:
+ stdin_stream = None
+ stdout_stream = None
+ stderr_stream = None
+ try:
+ stdout_stream = open(self.stdout, "ab")
+ stdin_stream = open(self.stdin, "rb")
+ stderr_stream = open(self.stderr, "ab")
+
+ self.process = Popen(self.cmdline, cwd=self.cwd, stdin=stdin_stream,
+ stdout=stdout_stream, stderr=stderr_stream, env=self.env)
+
+ if expect_fail:
+ # Let's wait a bit to see if this process dies as expected and return the exit code
+ try:
+ self.process.wait(10)
+ return self.process.returncode
+ except subprocess.TimeoutExpired as e:
+ # Process did not fail as expected, lets kill it
+ os.kill(self.process.pid, signal.SIGKILL)
+ self.process.wait(20)
+ raise e
+ else:
+ # This is a hack to set the returncode. When the Popen object goes out of scope during the unit test
+ # the __del__ method gets called. As we leave the daemon running the process.returncode
+ # hasn't been set, so it incorrectly raises an exception that the process is still running
+ # which in our case is correct and expected.
+ self.process.returncode = 0
+ finally:
+ # Close these in the parent
+ if stdin_stream:
+ stdin_stream.close()
+ if stderr_stream:
+ stderr_stream.close()
+ if stdout_stream:
+ stdout_stream.close()
+
+ # Make sure daemon is responding to dbus events before returning
+ DaemonInfo._ensure_daemon("Daemon is not responding on dbus within 20 seconds of starting!")
+
+ # During local testing it usually takes ~0.25 seconds for daemon to be ready
+ return None
+
+ @staticmethod
+ def _ensure_no_daemon():
+ start = time.time()
+ pid = process_exists(EXE_NAME)
+ while pid is not None and (time.time() - start) <= 20:
+ time.sleep(0.3)
+ pid = process_exists(EXE_NAME)
+
+ if pid:
+ raise Exception(
+ "lsmd daemon did not exit within 20 seconds, pid = %s" % pid)
+
+ @staticmethod
+ def _ensure_daemon(msg):
+ start = time.time()
+ running = False
+ while True and (time.time() - start) < 20:
+ try:
+ get_objects()
+ running = True
+ break
+ except dbus.exceptions.DBusException:
+ time.sleep(0.2)
+ pass
+ if not running:
+ raise RuntimeError(msg)
+
+ def term_signal(self, sig_number):
+ # Used for signals that we expect with terminate the daemon, eg. SIGINT, SIGKILL
+ if self.process:
+ os.kill(self.process.pid, sig_number)
+ # Note: The following should work, but doesn't!
+ # self.process.send_signal(sig_number)
+ try:
+ self.process.wait(10)
+ except subprocess.TimeoutExpired:
+ std_err_print("Daemon hasn't exited within 10 seconds")
+ if self.process.poll() is None:
+ std_err_print("Daemon still running...")
+ else:
+ self.process = None
+ else:
+ pid = process_exists(EXE_NAME)
+ os.kill(pid, sig_number)
+
+ # Make sure there is no daemon present before we return for things to be "good"
+ DaemonInfo._ensure_no_daemon()
+
+ def non_term_signal(self, sig_number):
+ if sig_number not in [signal.SIGUSR1, signal.SIGUSR2]:
+ raise ValueError("Incorrect signal number! %d" % sig_number)
+ if self.process:
+ os.kill(self.process.pid, sig_number)
+ else:
+ pid = process_exists(EXE_NAME)
+ os.kill(pid, sig_number)
+
+
# noinspection PyUnresolvedReferences
class TestDbusService(unittest.TestCase):
def setUp(self):
6 months, 1 week