Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package crmsh for openSUSE:Factory checked in at 2026-06-05 14:56:49 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/crmsh (Old) and /work/SRC/openSUSE:Factory/.crmsh.new.2375 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "crmsh" Fri Jun 5 14:56:49 2026 rev:410 rq:1357047 version:5.1.0+20260604.45e70fd3 Changes: -------- --- /work/SRC/openSUSE:Factory/crmsh/crmsh.changes 2026-06-01 18:06:18.872049963 +0200 +++ /work/SRC/openSUSE:Factory/.crmsh.new.2375/crmsh.changes 2026-06-05 14:56:53.395844354 +0200 @@ -1,0 +2,16 @@ +Thu Jun 04 02:57:23 UTC 2026 - [email protected] + +- Update to version 5.1.0+20260604.45e70fd3: + * Refactor: crash_test: Use log filters to control output instead of removing handlers + * Refactor: log: replace crmsh.log.setup_logger with logging.setupLogger + * Dev: log: Use filters to control handler output and simplify logger setup + * Dev: corosync_config_format: lower the level of debug logs from tokenizer to DEBUG2 + * Refactor: log: Decouple logging from config module + +------------------------------------------------------------------- +Mon Jun 01 03:57:54 UTC 2026 - [email protected] + +- Update to version 5.1.0+20260601.363253ce: + * Fix: sbd: Compare SBD device UUID when adding SBD via sbd stage + +------------------------------------------------------------------- Old: ---- crmsh-5.1.0+20260528.b0973362.tar.bz2 New: ---- crmsh-5.1.0+20260604.45e70fd3.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ crmsh.spec ++++++ --- /var/tmp/diff_new_pack.W4e5yA/_old 2026-06-05 14:56:54.371884719 +0200 +++ /var/tmp/diff_new_pack.W4e5yA/_new 2026-06-05 14:56:54.375884884 +0200 @@ -41,7 +41,7 @@ Summary: High Availability cluster command-line interface License: GPL-2.0-or-later Group: %{pkg_group} -Version: 5.1.0+20260528.b0973362 +Version: 5.1.0+20260604.45e70fd3 Release: 0 URL: http://crmsh.github.io Source0: %{name}-%{version}.tar.bz2 ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.W4e5yA/_old 2026-06-05 14:56:54.475889020 +0200 +++ /var/tmp/diff_new_pack.W4e5yA/_new 2026-06-05 14:56:54.479889186 +0200 @@ -9,7 +9,7 @@ </service> <service name="tar_scm"> <param name="url">https://github.com/ClusterLabs/crmsh.git</param> - <param name="changesrevision">b097336298cdaa1df6f28dd5b1b20ef75b5b54b9</param> + <param name="changesrevision">8e3ca73e5ebe9d8f3d58a654d5ce30f246380215</param> </service> </servicedata> (No newline at EOF) ++++++ crmsh-5.1.0+20260528.b0973362.tar.bz2 -> crmsh-5.1.0+20260604.45e70fd3.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/bootstrap.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/bootstrap.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/bootstrap.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/bootstrap.py 2026-06-04 04:20:38.000000000 +0200 @@ -13,6 +13,7 @@ import dataclasses import io import json +import logging import os import subprocess import sys @@ -56,7 +57,7 @@ import crmsh.healthcheck -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) logger_utils = log.LoggerUtils(logger) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/cibconfig.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/cibconfig.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/cibconfig.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/cibconfig.py 2026-06-04 04:20:38.000000000 +0200 @@ -3,6 +3,7 @@ from __future__ import annotations import copy +import logging import os import sys import re @@ -31,7 +32,7 @@ from . import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) logger_utils = log.LoggerUtils(logger) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/cibstatus.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/cibstatus.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/cibstatus.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/cibstatus.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,6 +1,6 @@ # Copyright (C) 2008-2011 Dejan Muhamedagic <[email protected]> # See COPYING for license information. - +import logging import os from tempfile import mkstemp from lxml import etree @@ -11,7 +11,7 @@ from . import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) def get_tag_by_id(node, tag, ident): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/cibverify.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/cibverify.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/cibverify.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/cibverify.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,12 +1,12 @@ # Copyright (C) 2014 Kristoffer Gronlund <[email protected]> # See COPYING for license information. - +import logging import re from .sh import ShellUtils from . import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) cib_verify = "crm_verify -VV -p" VALIDATE_RE = re.compile(r"^Entity: line (\d)+: element (\w+): " + r"Relax-NG validity error : (.+)$") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/cluster_fs.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/cluster_fs.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/cluster_fs.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/cluster_fs.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,3 +1,4 @@ +import logging import re from contextlib import contextmanager from . import utils, sh @@ -10,7 +11,7 @@ from . import sbd from .service_manager import ServiceManager -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) logger_utils = log.LoggerUtils(logger) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/command.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/command.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/command.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/command.py 2026-06-04 04:20:38.000000000 +0200 @@ -7,6 +7,7 @@ # inside the functions. import inspect +import logging import re import ctypes.util from . import help as help_module @@ -16,7 +17,7 @@ from . import utils -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) def name(n): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/config.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/config.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/config.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/config.py 2026-06-04 04:20:38.000000000 +0200 @@ -413,6 +413,26 @@ _configuration = _Configuration() +_change_listeners = {} + + +def add_change_listener(section, option, callback): + """Register a callback for when a specific option is changed.""" + key = (section, option) + if key not in _change_listeners: + _change_listeners[key] = [] + _change_listeners[key].append(callback) + # Notify immediately with current value + callback(get_option(section, option)) + + +def _notify_change_listeners(section, option, value): + """Notify all registered listeners for an option.""" + listeners = _change_listeners.get((section, option), []) + for callback in listeners: + callback(value) + + class _Section(object): def __init__(self, section): object.__setattr__(self, 'section', section) @@ -422,6 +442,7 @@ def __setattr__(self, name, value): _configuration.set(self.section, name, value) + _notify_change_listeners(self.section, name, get_option(self.section, name)) def items(self): return _configuration.items(self.section) @@ -443,6 +464,7 @@ def set_option(section, option, value): if not isinstance(value, List): _configuration.set(section, option, value) + _notify_change_listeners(section, option, get_option(section, option)) return string = "" first = True @@ -453,6 +475,7 @@ string += ", " string += str(item) _configuration.set(section, option, string) + _notify_change_listeners(section, option, get_option(section, option)) def get_option(section, option, raw=False): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/corosync.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/corosync.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/corosync.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/corosync.py 2026-06-04 04:20:38.000000000 +0200 @@ -5,6 +5,7 @@ configuration file, and also the corosync-* utilities. ''' import dataclasses +import logging import os import re import typing @@ -20,7 +21,7 @@ from .sh import ShellUtils -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) COROSYNC_TOKEN_DEFAULT = 3000 # in ms units diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/corosync_config_format.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/corosync_config_format.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/corosync_config_format.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/corosync_config_format.py 2026-06-04 04:20:38.000000000 +0200 @@ -3,9 +3,10 @@ import logging import re -from io import StringIO import typing +from .log import DEBUG2 + logger = logging.getLogger(__name__) COMMENT_PREFIX = '#comment' @@ -39,7 +40,7 @@ tokens = self._tokenize(line) except ValueError as e: raise MalformedLineException(lineno, line) - logger.debug('tokens: %s', tokens) + logger.log(DEBUG2, 'tokens: %s', tokens) if tokens[1] == '#': fake_key = f'{COMMENT_PREFIX}_{lineno}' self.on_key_value(fake_key, tokens[2]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/crash_test/main.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/crash_test/main.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/crash_test/main.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/crash_test/main.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,3 +1,4 @@ +import logging import os import sys import argparse @@ -9,7 +10,7 @@ from crmsh import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) class Context(object): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/crash_test/task.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/crash_test/task.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/crash_test/task.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/crash_test/task.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,3 +1,4 @@ +import logging import os import time import threading @@ -13,7 +14,7 @@ from ..service_manager import ServiceManager from ..sh import ShellUtils -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) class TaskError(Exception): @@ -242,8 +243,8 @@ """ Define the format of results to stdout """ - with utils.manage_handler("file", keep=False): - utils.get_handler(logger, "stream").setFormatter(utils.MyLoggingFormatter(flush=False)) + with utils.block_log_filter(log.LOGFILE_FILTER): + utils.get_handler(logger, "console").setFormatter(utils.MyLoggingFormatter(flush=False)) if self.passed: message = "{} [{}]".format(self.description, utils.CGREEN + "Pass" + utils.CEND) @@ -254,7 +255,7 @@ for msg in self.messages: logger.log(utils.LEVEL[msg[0]], msg[1], extra={'timestamp': ' '}) - utils.get_handler(logger, "stream").setFormatter(utils.MyLoggingFormatter()) + utils.get_handler(logger, "console").setFormatter(utils.MyLoggingFormatter()) def to_json(self): """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/crash_test/utils.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/crash_test/utils.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/crash_test/utils.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/crash_test/utils.py 2026-06-04 04:20:38.000000000 +0200 @@ -14,7 +14,7 @@ from crmsh import xmlutil -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) CRED = constants.RED @@ -60,23 +60,24 @@ @contextmanager -def manage_handler(_type, keep=True): +def block_log_filter(filter: log.LevelFilter): """ - Define a contextmanager to remove specific logging handler temporarily + Define a contextmanager to block a logging filter temporarily """ + saved_level = filter.level + filter.level = logging.CRITICAL + 1 try: - handler = get_handler(logger, _type) - if not keep: - logger.removeHandler(handler) yield finally: - if not keep: - logger.addHandler(handler) + filter.level = saved_level def msg_raw(level, msg, to_stdout=True): - with manage_handler("console", to_stdout): + if to_stdout: logger.log(level, msg) + else: + with block_log_filter(log.CONSOLE_FILTER): + logger.log(level, msg) def msg_info(msg, to_stdout=True): @@ -169,13 +170,16 @@ return datetime.strptime(str_time, fmt) -def get_handler(logger, _type): +def get_handler(logger, name): """ - Get logger specific handler + Find a handler by name from crmsh.crash_test logger. """ - for h in logger.handlers: - if getattr(h, '_name') == _type: + if hasattr(logging, 'getHandlerByName'): + return logging.getHandlerByName(name) + for h in logging.getLogger("crmsh.crash_test").handlers: + if getattr(h, 'name', None) == name or getattr(h, '_name', None) == name: return h + return None def is_root(): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/crm_gv.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/crm_gv.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/crm_gv.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/crm_gv.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,6 +1,6 @@ # Copyright (C) 2013 Dejan Muhamedagic <[email protected]> # See COPYING for license information. - +import logging import re from . import config from . import tmpfiles @@ -8,7 +8,7 @@ from . import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) # graphviz stuff diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/crm_pssh.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/crm_pssh.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/crm_pssh.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/crm_pssh.py 2026-06-04 04:20:38.000000000 +0200 @@ -10,7 +10,7 @@ directory. Each output file in that directory will be named by the corresponding remote node's hostname or IP address. """ - +import logging import os import glob import typing @@ -19,7 +19,7 @@ from . import log from .prun import prun -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) _DEFAULT_TIMEOUT = 60 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/help.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/help.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/help.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/help.py 2026-06-04 04:20:38.000000000 +0200 @@ -27,6 +27,7 @@ import dataclasses import functools import io +import logging import os import re import typing @@ -39,7 +40,7 @@ from . import ra -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) class HelpFilter(object): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/history.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/history.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/history.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/history.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,7 +1,7 @@ # Copyright (C) 2011 Dejan Muhamedagic <[email protected]> # Copyright (C) 2013-2016 Kristoffer Gronlund <[email protected]> # See COPYING for license information. - +import logging import os import time import re @@ -18,7 +18,7 @@ from crmsh.report import core -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) _LOG_FILES = ("ha-log.txt", "messages", "ha-log", "cluster-log.txt", "journal.log", "pacemaker.log") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/idmgmt.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/idmgmt.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/idmgmt.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/idmgmt.py 2026-06-04 04:20:38.000000000 +0200 @@ -2,7 +2,7 @@ # See COPYING for license information. # # Make sure that ids are unique. - +import logging import re import copy from . import constants @@ -10,7 +10,7 @@ from . import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) logger_utils = log.LoggerUtils(logger) _id_store = {} _state = [] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/lock.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/lock.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/lock.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/lock.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,7 +1,6 @@ # Copyright (C) 2020 Xin Liang <[email protected]> # See COPYING for license information. - - +import logging import re import time from contextlib import contextmanager @@ -13,7 +12,7 @@ from .sh import ShellUtils -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) class SSHError(Exception): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/log.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/log.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/log.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/log.py 2026-06-04 04:20:38.000000000 +0200 @@ -13,7 +13,7 @@ from . import options from . import constants -DEBUG2 = logging.DEBUG + 5 +DEBUG2 = logging.DEBUG - 1 CRMSH_LOG_FILE = "/var/log/crmsh/crmsh.log" @@ -92,6 +92,18 @@ stream.write(self.terminator) +class LevelFilter(logging.Filter): + """ + A filter to block log records + """ + def __init__(self, level: int): + super().__init__() + self.level = level + + def filter(self, record): + return record.levelno >= self.level + + class NoBacktraceFormatter(logging.Formatter): """Suppress backtrace unless option debug is set.""" def format(self, record): @@ -108,8 +120,7 @@ it is formatted using formatException() and appended to the message. """ if record.exc_info or record.stack_info: - from crmsh import config - if config.core.debug: + if logging.getLogger('crmsh').isEnabledFor(logging.DEBUG): return super().format(record) else: record.message = record.getMessage() @@ -163,20 +174,6 @@ return formatter.format(record) -class DebugCustomFilter(logging.Filter): - """ - A custom filter for debug and debug2 messages - """ - def filter(self, record): - from .config import core, report - if record.levelno == logging.DEBUG: - return core.debug or int(report.verbosity) >= 1 - elif record.levelno == DEBUG2: - return int(report.verbosity) > 1 - else: - return True - - class GroupWriteRotatingFileHandler(logging.handlers.RotatingFileHandler): """ A custom rotating file handler which keeps log files group wirtable after rotating @@ -210,6 +207,11 @@ } +CONSOLE_FILTER = LevelFilter(DEBUG2) +BUFFERED_FILTER = LevelFilter(logging.CRITICAL + 1) +LOGFILE_FILTER = LevelFilter(DEBUG2) + + LOGGING_CFG = { "version": 1, "disable_existing_loggers": "False", @@ -232,11 +234,6 @@ }, "file": LOGFILE_FORMATTER }, - "filters": { - "filter": { - "()": DebugCustomFilter - }, - }, "handlers": { 'null': { 'class': 'logging.NullHandler' @@ -244,41 +241,49 @@ "console_report": { "()": ConsoleCustomHandler, "formatter": "console_report", - "filters": ["filter"] + "filters": [ + CONSOLE_FILTER, + ] }, "console": { "()": ConsoleCustomHandler, "formatter": "console", - "filters": ["filter"] + "filters": [ + CONSOLE_FILTER, + ] }, - "buffer": { + "buffered_console": { "class": "logging.handlers.MemoryHandler", "capacity": 1024*100, "flushLevel": logging.CRITICAL, + "target": "console", + "filters": [ + BUFFERED_FILTER, + ] }, "file": { "()": GroupWriteRotatingFileHandler, "filename": CRMSH_LOG_FILE, "formatter": "file", - "filters": ["filter"], "maxBytes": 1*1024*1024, - "backupCount": 10 + "backupCount": 10, + "filters": [ + LOGFILE_FILTER, + ] } }, "loggers": { "crmsh": { - "handlers": ["null", "file", "console", "buffer"], - "level": "DEBUG" + "handlers": ["null", "file", "console", "buffered_console"], + "level": "INFO" }, "crmsh.crash_test": { "handlers": ["null", "file", "console"], - "propagate": False, - "level": "DEBUG" + "propagate": False }, "crmsh.report": { "handlers": ["null", "file", "console_report"], - "propagate": False, - "level": "DEBUG" + "propagate": False } } } @@ -319,22 +324,23 @@ # used in regression test self.__save_lineno = 0 - def get_handler(self, _type): + def get_handler(self, name): """ - Get logger specific handler + Find a handler by name from known root loggers. """ - for h in self.logger.handlers: - if getattr(h, '_name') == _type: - return h - else: - raise ValueError("Failed to find \"{}\" handler in logger \"{}\"".format(_type, self.logger.name)) + if hasattr(logging, 'getHandlerByName'): + return logging.getHandlerByName(name) + for logger_name in ("crmsh", "crmsh.report"): + for h in logging.getLogger(logger_name).handlers: + if getattr(h, 'name', None) == name or getattr(h, '_name', None) == name: + return h + raise KeyError(f'Log handler not found: {name}') def disable_info_in_console(self): """ Set log level as warning in console """ - console_handler = self.get_handler("console") - console_handler.setLevel(logging.WARNING) + CONSOLE_FILTER.level = logging.WARNING def reset_lineno(self, to=0): """ @@ -353,16 +359,15 @@ """ Only log to file in bootstrap logger """ - console_handler = self.get_handler("console") + saved_level = CONSOLE_FILTER.level + CONSOLE_FILTER.level = logging.CRITICAL + 1 try: - self.logger.removeHandler(console_handler) yield finally: - self.logger.addHandler(console_handler) + CONSOLE_FILTER.level = saved_level def log_only_to_file(self, msg, level=logging.INFO): - from .config import core - if core.debug: + if self.logger.isEnabledFor(logging.DEBUG): self.logger.log(logging.DEBUG, msg) else: with self.only_file(): @@ -373,21 +378,18 @@ """ Keep log messages in memory and finally show them in console """ - console_handler = self.get_handler("console") - buffer_handler = self.get_handler("buffer") + buffer_handler = self.get_handler("buffered_console") + saved_console_level = CONSOLE_FILTER.level try: - # remove console handler temporarily - self.logger.removeHandler(console_handler) buffer_handler.buffer.clear() - # set the target of buffer handler as console - buffer_handler.setTarget(console_handler) + CONSOLE_FILTER.level = logging.CRITICAL + 1 + BUFFERED_FILTER.level = DEBUG2 yield finally: empty = not buffer_handler.buffer - # close the buffer handler(flush to console handler) - buffer_handler.close() - # add console handler back - self.logger.addHandler(console_handler) + BUFFERED_FILTER.level = logging.CRITICAL + 1 + CONSOLE_FILTER.level = saved_console_level + buffer_handler.flush() if not empty and not options.batch: try: input("Press enter to continue... ") @@ -573,23 +575,3 @@ if not all(os.isatty(fd) for fd in range(3)): LOGGING_CFG['formatters'] = NO_COLOR_FORMATTERS logging.config.dictConfig(LOGGING_CFG) - - -def setup_logger(name): - """ - Get the logger - name could be any module name - should assign parent's handlers for inherit - """ - logger = logging.getLogger(name) - logger.handlers = logger.parent.handlers - logger.propagate = False - return logger - - -def setup_report_logger(name): - """ - Get the logger for crm report - """ - logger = setup_logger(name) - return logger diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/logparser.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/logparser.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/logparser.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/logparser.py 2026-06-04 04:20:38.000000000 +0200 @@ -3,6 +3,7 @@ import bz2 import gzip +import logging import re import os import sys @@ -17,7 +18,7 @@ from . import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) _METADATA_FILENAME = "__meta.json" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/logtime.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/logtime.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/logtime.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/logtime.py 2026-06-04 04:20:38.000000000 +0200 @@ -4,7 +4,7 @@ """ Helpers for handling log timestamps. """ - +import logging import re import time import datetime @@ -12,7 +12,7 @@ from . import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) YEAR = None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/main.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/main.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/main.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/main.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,6 +1,6 @@ # Copyright (C) 2008-2011 Dejan Muhamedagic <[email protected]> # See COPYING for license information. - +import logging import sys import os import atexit @@ -19,10 +19,21 @@ from . import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) logger_utils = log.LoggerUtils(logger) +def _update_core_debug(enabled): + """ + Update crmsh logger level based on core.debug + """ + level = log.logging.DEBUG if enabled else log.logging.INFO + log.logging.getLogger('crmsh').setLevel(level) + + +config.add_change_listener('core', 'debug', _update_core_debug) + + random.seed() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/parse.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/parse.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/parse.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/parse.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,7 +1,7 @@ # Copyright (C) 2008-2011 Dejan Muhamedagic <[email protected]> # Copyright (C) 2013-2016 Kristoffer Gronlund <[email protected]> # See COPYING for license information. - +import logging import shlex import re import inspect @@ -16,7 +16,7 @@ from . import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) logger_utils = log.LoggerUtils(logger) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/qdevice.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/qdevice.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/qdevice.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/qdevice.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,5 +1,6 @@ import ipaddress import json +import logging import os import re import socket @@ -20,7 +21,7 @@ from .service_manager import ServiceManager -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) logger_utils = log.LoggerUtils(logger) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/ra.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ra.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/ra.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ra.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,6 +1,6 @@ # Copyright (C) 2008-2011 Dejan Muhamedagic <[email protected]> # See COPYING for license information. - +import logging import os import subprocess import copy @@ -18,7 +18,7 @@ from . import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) # diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/report/collect.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/report/collect.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/report/collect.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/report/collect.py 2026-06-04 04:20:38.000000000 +0200 @@ -2,6 +2,7 @@ Define functions to collect log and info Function starts with "collect_" will be called in parallel """ +import logging import sys import os import shutil @@ -19,8 +20,7 @@ from crmsh.sh import ShellUtils from crmsh.service_manager import ServiceManager - -logger = log.setup_report_logger(__name__) +logger = logging.getLogger(__name__) DIVIDER = "=" * 50 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/report/core.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/report/core.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/report/core.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/report/core.py 2026-06-04 04:20:38.000000000 +0200 @@ -6,6 +6,7 @@ import multiprocessing import os import re +import logging import subprocess import sys import shutil @@ -23,8 +24,7 @@ from crmsh import config, log, tmpfiles, ui_cluster from crmsh.sh import ShellUtils - -logger = log.setup_report_logger(__name__) +logger = logging.getLogger(__name__) class Context: @@ -475,11 +475,22 @@ def adjust_verbosity(context: Context) -> None: if context.debug > 0: - config.report.verbosity = context.debug + config.report.verbosity = str(context.debug) elif config.core.debug: - config.report.verbosity = 1 + config.report.verbosity = "1" context.debug = 1 + verbosity = int(config.report.verbosity) + + if verbosity > 1: + level = log.DEBUG2 + elif verbosity == 1: + level = logging.DEBUG + else: + level = logging.INFO + + logging.getLogger('crmsh').setLevel(level) + def parse_arguments(context: Context) -> None: """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/report/utils.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/report/utils.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/report/utils.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/report/utils.py 2026-06-04 04:20:38.000000000 +0200 @@ -3,6 +3,7 @@ import datetime import glob +import logging import os import re import shutil @@ -18,8 +19,7 @@ from crmsh.report import constants, collect, core from crmsh.sh import ShellUtils - -logger = log.setup_report_logger(__name__) +logger = logging.getLogger(__name__) class LogType(Enum): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/rsctest.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/rsctest.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/rsctest.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/rsctest.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,6 +1,6 @@ # Copyright (C) 2008-2011 Dejan Muhamedagic <[email protected]> # See COPYING for license information. - +import logging import os import sys from .utils import rmdir_r, quote, this_node, ext_cmd @@ -8,7 +8,7 @@ from . import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) # # Resource testing suite diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/sbd.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/sbd.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/sbd.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/sbd.py 2026-06-04 04:20:38.000000000 +0200 @@ -3,6 +3,7 @@ import typing import shutil import time +import shlex import logging from enum import Enum, IntEnum, auto from . import utils, sh @@ -16,7 +17,7 @@ from .service_manager import ServiceManager from .sh import ShellUtils -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) class SBDUtils: @@ -29,9 +30,13 @@ Extract metadata from sbd device header ''' sbd_info = {} - pattern = r"UUID\s+:\s+(\S+)|Timeout\s+\((\w+)\)\s+:\s+(\d+)" - out = sh.cluster_shell().get_stdout_or_raise_error(f"sbd -d {dev} dump", remote) + cmd = f"sbd -d {shlex.quote(dev)} dump" + rc, out, _ = sh.cluster_shell().get_rc_stdout_stderr_without_input(remote, cmd) + if rc != 0 or not out: + return sbd_info + + pattern = r"UUID\s+:\s+(\S+)|Timeout\s+\((\w+)\)\s+:\s+(\d+)" matches = re.findall(pattern, out) for uuid, timeout_type, timeout_value in matches: if uuid and not timeout_only: @@ -47,14 +52,12 @@ return sbd_info @staticmethod - def get_device_uuid(dev, node=None): + def get_device_uuid(dev, node=None) -> str|None: ''' Get UUID for specific device and node ''' - res = SBDUtils.get_sbd_device_metadata(dev, remote=node).get("uuid") - if not res: - raise ValueError(f"Cannot find sbd device UUID for {dev}") - return res + metadata_info = SBDUtils.get_sbd_device_metadata(dev, remote=node) + return metadata_info.get("uuid") @staticmethod def compare_device_uuid(dev, node_list): @@ -64,13 +67,17 @@ if not node_list: return local_uuid = SBDUtils.get_device_uuid(dev) + if not local_uuid: + raise ValueError(f"Cannot get sbd device UUID for {dev} on {utils.this_node()}") for node in node_list: remote_uuid = SBDUtils.get_device_uuid(dev, node) + if not remote_uuid: + raise ValueError(f"Cannot get sbd device UUID for {dev} on {node}") if local_uuid != remote_uuid: raise ValueError(f"Device {dev} doesn't have the same UUID with {node}") @staticmethod - def verify_sbd_device(dev_list, compare_node_list=[]): + def verify_sbd_device(dev_list, compare_node_list=None): if len(dev_list) > SBDManager.SBD_DEVICE_MAX: raise ValueError(f"Maximum number of SBD device is {SBDManager.SBD_DEVICE_MAX}") for dev in dev_list: @@ -1266,6 +1273,12 @@ logger.debug("Running command: %s", cmd) shell.get_stdout_or_raise_error(cmd) + if self.cluster_is_running: + nodes = utils.list_cluster_nodes_except_me() + if nodes: + for dev in self.device_list_to_init: + SBDUtils.compare_device_uuid(dev, nodes) + def enable_sbd_service(self): if self.cluster_is_running: cluster_nodes = utils.list_cluster_nodes() @@ -1449,7 +1462,7 @@ self._watchdog_inst.join_watchdog() if dev_list: - SBDUtils.verify_sbd_device(dev_list, [peer_host]) + SBDUtils.verify_sbd_device(dev_list, compare_node_list=[peer_host]) logger.info("Got {}SBD configuration".format("" if dev_list else "diskless ")) self.enable_sbd_service() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/schema.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/schema.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/schema.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/schema.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,13 +1,13 @@ # Copyright (C) 2012 Dejan Muhamedagic <[email protected]> # See COPYING for license information. - +import logging import re from . import config from .pacemaker import CrmSchema, PacemakerError from . import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) PCMK_MIN_SCHEMA_VERSION = 1.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/scripts.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/scripts.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/scripts.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/scripts.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,6 +1,6 @@ # Copyright (C) 2015 Kristoffer Gronlund <[email protected]> # See COPYING for license information. - +import logging import os import re import subprocess @@ -31,7 +31,7 @@ import crmsh.parallax -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) _script_cache = None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/template.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/template.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/template.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/template.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,6 +1,6 @@ # Copyright (C) 2008-2011 Dejan Muhamedagic <[email protected]> # See COPYING for license information. - +import logging import os import re from . import config @@ -8,7 +8,7 @@ from . import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) def get_var(l, key): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_cib.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_cib.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_cib.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_cib.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,7 +1,7 @@ # Copyright (C) 2008-2011 Dejan Muhamedagic <[email protected]> # Copyright (C) 2013 Kristoffer Gronlund <[email protected]> # See COPYING for license information. - +import logging import os import glob from . import command @@ -19,7 +19,7 @@ from . import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) logger_utils = log.LoggerUtils(logger) _NEWARGS = ('force', '--force', 'withstatus', 'empty') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_cluster.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_cluster.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_cluster.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_cluster.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,7 +1,7 @@ # Copyright (C) 2008-2011 Dejan Muhamedagic <[email protected]> # Copyright (C) 2013 Kristoffer Gronlund <[email protected]> # See COPYING for license information. - +import logging import os import sys import re @@ -34,7 +34,7 @@ from .utils import TerminateSubCommand import crmsh.options -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) def parse_options(parser, args): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_configure.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_configure.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_configure.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_configure.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,7 +1,7 @@ # Copyright (C) 2008-2011 Dejan Muhamedagic <[email protected]> # Copyright (C) 2013 Kristoffer Gronlund <[email protected]> # See COPYING for license information. - +import logging import os import re import time @@ -34,7 +34,7 @@ from . import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) logger_utils = log.LoggerUtils(logger) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_context.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_context.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_context.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_context.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,6 +1,6 @@ # Copyright (C) 2013 Kristoffer Gronlund <[email protected]> # See COPYING for license information. - +import logging import shlex import sys from . import config @@ -13,7 +13,7 @@ from . import main -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) logger_utils = log.LoggerUtils(logger) _NON_FUNCTIONAL_COMMANDS = {'help', 'ls'} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_corosync.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_corosync.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_corosync.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_corosync.py 2026-06-04 04:20:38.000000000 +0200 @@ -4,6 +4,7 @@ import io import ipaddress import json +import logging import re import subprocess import os @@ -20,7 +21,7 @@ from .prun import prun from .service_manager import ServiceManager -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) def _push_completer(args): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_history.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_history.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_history.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_history.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,7 +1,7 @@ # Copyright (C) 2008-2011 Dejan Muhamedagic <[email protected]> # Copyright (C) 2013 Kristoffer Gronlund <[email protected]> # See COPYING for license information. - +import logging import os import sys import time @@ -22,7 +22,7 @@ from . import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) logger_utils = log.LoggerUtils(logger) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_node.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_node.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_node.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_node.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,6 +1,7 @@ # Copyright (C) 2008-2011 Dejan Muhamedagic <[email protected]> # Copyright (C) 2013 Kristoffer Gronlund <[email protected]> # See COPYING for license information. +import logging import os import copy import subprocess @@ -22,7 +23,7 @@ from . import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) logger_utils = log.LoggerUtils(logger) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_resource.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_resource.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_resource.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_resource.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,7 +1,7 @@ # Copyright (C) 2008-2011 Dejan Muhamedagic <[email protected]> # Copyright (C) 2013-2018 Kristoffer Gronlund <[email protected]> # See COPYING for license information. - +import logging import re from . import command from . import completers as compl @@ -16,7 +16,7 @@ from . import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) logger_utils = log.LoggerUtils(logger) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_script.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_script.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_script.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_script.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,7 +1,6 @@ # Copyright (C) 2013 Kristoffer Gronlund <[email protected]> # See COPYING for license information. - - +import logging import sys try: @@ -18,7 +17,7 @@ from . import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) class ConsolePrinter(object): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_site.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_site.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_site.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_site.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,7 +1,7 @@ # Copyright (C) 2008-2011 Dejan Muhamedagic <[email protected]> # Copyright (C) 2013 Kristoffer Gronlund <[email protected]> # See COPYING for license information. - +import logging import time from . import command from . import completers as compl @@ -10,7 +10,7 @@ from . import options -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) logger_utils = log.LoggerUtils(logger) _ticket_commands = { 'grant': "%s -t '%s' -g", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_template.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_template.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_template.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_template.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,7 +1,7 @@ # Copyright (C) 2008-2011 Dejan Muhamedagic <[email protected]> # Copyright (C) 2013 Kristoffer Gronlund <[email protected]> # See COPYING for license information. - +import logging import os import re import shlex @@ -17,7 +17,7 @@ from . import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) logger_utils = log.LoggerUtils(logger) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_utils.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_utils.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/ui_utils.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/ui_utils.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,7 +1,7 @@ # Copyright (C) 2008-2011 Dejan Muhamedagic <[email protected]> # Copyright (C) 2013 Kristoffer Gronlund <[email protected]> # See COPYING for license information. - +import logging import re import inspect from . import utils @@ -9,7 +9,7 @@ from argparse import ArgumentParser, RawDescriptionHelpFormatter -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) logger_utils = log.LoggerUtils(logger) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/userdir.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/userdir.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/userdir.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/userdir.py 2026-06-04 04:20:38.000000000 +0200 @@ -1,6 +1,6 @@ # Copyright (C) 2013 Kristoffer Gronlund <[email protected]> # See COPYING for license information. - +import logging import os import typing import pwd @@ -8,7 +8,7 @@ from . import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) def getuser(): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/utils.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/utils.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/utils.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/utils.py 2026-06-04 04:20:38.000000000 +0200 @@ -2,6 +2,7 @@ # See COPYING for license information. import asyncio import errno +import logging import os import sys import typing @@ -52,7 +53,7 @@ from .sh import ShellUtils from .service_manager import ServiceManager -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) logger_utils = log.LoggerUtils(logger) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/crmsh/xmlutil.py new/crmsh-5.1.0+20260604.45e70fd3/crmsh/xmlutil.py --- old/crmsh-5.1.0+20260528.b0973362/crmsh/xmlutil.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/crmsh/xmlutil.py 2026-06-04 04:20:38.000000000 +0200 @@ -4,6 +4,8 @@ # import annotations to avoid circular import issues when using type hints from __future__ import annotations + +import logging import os import subprocess import typing @@ -26,7 +28,7 @@ from . import log -logger = log.setup_logger(__name__) +logger = logging.getLogger(__name__) logger_utils = log.LoggerUtils(logger) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/test/unittests/test_crashtest_task.py new/crmsh-5.1.0+20260604.45e70fd3/test/unittests/test_crashtest_task.py --- old/crmsh-5.1.0+20260528.b0973362/test/unittests/test_crashtest_task.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/test/unittests/test_crashtest_task.py 2026-06-04 04:20:38.000000000 +0200 @@ -7,6 +7,7 @@ import mock from datetime import datetime +from crmsh import log from crmsh import utils as crmshutils from crmsh.crash_test import utils, main, config, task @@ -226,10 +227,10 @@ @mock.patch('crmsh.crash_test.utils.MyLoggingFormatter') @mock.patch('crmsh.crash_test.utils.get_handler') - @mock.patch('crmsh.crash_test.utils.manage_handler') - def test_to_stdout(self, mock_manage_handler, mock_get_handler, mock_myformatter): - mock_manage_handler.return_value.__enter__ = mock.Mock() - mock_manage_handler.return_value.__exit__ = mock.Mock() + @mock.patch('crmsh.crash_test.utils.block_log_filter') + def test_to_stdout(self, mock_block_log_filter, mock_get_handler, mock_myformatter): + mock_block_log_filter.return_value.__enter__ = mock.Mock() + mock_block_log_filter.return_value.__exit__ = mock.Mock() task.logger = mock.Mock() task.logger.info = mock.Mock() @@ -252,10 +253,10 @@ self.task_check_inst.to_stdout() - mock_manage_handler.assert_called_once_with("file", keep=False) + mock_block_log_filter.assert_called_once_with(log.LOGFILE_FILTER) mock_get_handler.assert_has_calls([ - mock.call(task.logger, "stream"), - mock.call(task.logger, "stream") + mock.call(task.logger, "console"), + mock.call(task.logger, "console") ]) get_handler_inst1.setFormatter.assert_called_once_with(myformatter_inst1) get_handler_inst2.setFormatter.assert_called_once_with(myformatter_inst2) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/test/unittests/test_crashtest_utils.py new/crmsh-5.1.0+20260604.45e70fd3/test/unittests/test_crashtest_utils.py --- old/crmsh-5.1.0+20260528.b0973362/test/unittests/test_crashtest_utils.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/test/unittests/test_crashtest_utils.py 2026-06-04 04:20:38.000000000 +0200 @@ -8,6 +8,7 @@ import mock import logging +from crmsh import log from crmsh.crash_test import utils, main, config @@ -152,26 +153,10 @@ mock_datetime.now.assert_called_once_with() mock_now.strftime.assert_called_once_with("%Y/%m/%d %H:%M:%S") - @mock.patch('crmsh.crash_test.utils.get_handler') - def test_manage_handler(self, mock_get_handler): - mock_get_handler.return_value = "handler" - utils.logger = mock.Mock() - utils.logger.removeHandler = mock.Mock() - utils.logger.addHandler = mock.Mock() - - with utils.manage_handler("type1", keep=False): - pass - - mock_get_handler.assert_called_once_with(utils.logger, "type1") - utils.logger.removeHandler.assert_called_once_with("handler") - utils.logger.addHandler.assert_called_once_with("handler") - - @mock.patch('crmsh.crash_test.utils.manage_handler') - def test_msg_raw(self, mock_handler): + def test_msg_raw(self): utils.logger = mock.Mock() utils.logger.log = mock.Mock() utils.msg_raw("level1", "msg1") - mock_handler.assert_called_once_with("console", True) utils.logger.log.assert_called_once_with("level1", "msg1") @mock.patch('crmsh.crash_test.utils.msg_raw') @@ -233,12 +218,23 @@ utils.str_to_datetime("Mon Nov 2 15:37:11 2020", "%a %b %d %H:%M:%S %Y") mock_datetime.strptime.assert_called_once_with("Mon Nov 2 15:37:11 2020", "%a %b %d %H:%M:%S %Y") - def test_get_handler(self): + @mock.patch('logging.getLogger') + def test_get_handler(self, mock_get_logger): mock_handler1 = mock.Mock(_name="test1_handler") mock_handler2 = mock.Mock(_name="test2_handler") - mock_logger = mock.Mock(handlers=[mock_handler1, mock_handler2]) - res = utils.get_handler(mock_logger, "test1_handler") - self.assertEqual(res, mock_handler1) + mock_get_logger.return_value = mock.Mock(handlers=[mock_handler1, mock_handler2]) + + # If getHandlerByName exists (Python 3.12+), it will be called first + if hasattr(logging, 'getHandlerByName'): + with mock.patch('logging.getHandlerByName') as mock_get_handler_by_name: + mock_get_handler_by_name.return_value = mock_handler1 + res = utils.get_handler(None, "test1_handler") + self.assertEqual(res, mock_handler1) + mock_get_handler_by_name.assert_called_once_with("test1_handler") + else: + res = utils.get_handler(None, "test1_handler") + self.assertEqual(res, mock_handler1) + mock_get_logger.assert_called_once_with("crmsh.crash_test") @mock.patch('os.getuid') def test_is_root(self, mock_getuid): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.1.0+20260528.b0973362/test/unittests/test_sbd.py new/crmsh-5.1.0+20260604.45e70fd3/test/unittests/test_sbd.py --- old/crmsh-5.1.0+20260528.b0973362/test/unittests/test_sbd.py 2026-05-28 09:45:27.000000000 +0200 +++ new/crmsh-5.1.0+20260604.45e70fd3/test/unittests/test_sbd.py 2026-06-04 04:20:38.000000000 +0200 @@ -17,32 +17,30 @@ @patch('crmsh.sh.cluster_shell') def test_get_sbd_device_metadata_success(self, mock_cluster_shell): - mock_cluster_shell.return_value.get_stdout_or_raise_error.return_value = self.TEST_DATA + mock_cluster_shell.return_value.get_rc_stdout_stderr_without_input.return_value = (0, self.TEST_DATA, None) result = SBDUtils.get_sbd_device_metadata("/dev/sbd_device") expected = {'uuid': '1234-5678', 'watchdog': 5, 'msgwait': 10} self.assertEqual(result, expected) @patch('crmsh.sh.cluster_shell') def test_get_sbd_device_metadata_timeout_only(self, mock_cluster_shell): - mock_cluster_shell.return_value.get_stdout_or_raise_error.return_value = self.TEST_DATA + mock_cluster_shell.return_value.get_rc_stdout_stderr_without_input.return_value = (0, self.TEST_DATA, None) result = SBDUtils.get_sbd_device_metadata("/dev/sbd_device", timeout_only=True) expected = {'watchdog': 5, 'msgwait': 10} self.assertNotIn('uuid', result) self.assertEqual(result, expected) + @patch('crmsh.sh.cluster_shell') + def test_get_sbd_device_metadata_failure(self, mock_cluster_shell): + mock_cluster_shell.return_value.get_rc_stdout_stderr_without_input.return_value = (1, None, None) + self.assertEqual(SBDUtils.get_sbd_device_metadata("/dev/sbd_device"), {}) + @patch('crmsh.sbd.SBDUtils.get_sbd_device_metadata') def test_get_device_uuid_success(self, mock_get_sbd_device_metadata): mock_get_sbd_device_metadata.return_value = {'uuid': '1234-5678'} result = SBDUtils.get_device_uuid("/dev/sbd_device") self.assertEqual(result, '1234-5678') - @patch('crmsh.sbd.SBDUtils.get_sbd_device_metadata') - def test_get_device_uuid_no_uuid_found(self, mock_get_sbd_device_metadata): - mock_get_sbd_device_metadata.return_value = {} - with self.assertRaises(ValueError) as context: - SBDUtils.get_device_uuid("/dev/sbd_device") - self.assertTrue("Cannot find sbd device UUID for /dev/sbd_device" in str(context.exception)) - @patch('crmsh.sbd.SBDUtils.get_device_uuid') def test_compare_device_uuid_empty_node_list(self, mock_get_device_uuid): result = SBDUtils.compare_device_uuid("/dev/sbd_device", []) @@ -1151,14 +1149,18 @@ sbdmanager_instance.initialize_sbd() mock_logger_info.assert_called_once_with("Configuring diskless SBD") + @patch('crmsh.sbd.SBDUtils.compare_device_uuid') + @patch('crmsh.utils.list_cluster_nodes_except_me') @patch('crmsh.sbd.ServiceManager') @patch('logging.Logger.debug') @patch('crmsh.sbd.sh.cluster_shell') @patch('crmsh.sbd.SBDManager.convert_timeout_dict_to_opt_str') - @patch('shutil.which') @patch('logging.Logger.info') - def test_initialize_sbd_diskbased(self, mock_logger_info, mock_which, mock_convert_timeout_dict_to_opt_str, mock_cluster_shell, mock_logger_debug, mock_ServiceManager): - mock_which.return_value = "/sbin/fence_sbd" + def test_initialize_sbd_diskbased(self, mock_logger_info, mock_convert_timeout_dict_to_opt_str, mock_cluster_shell, mock_logger_debug, mock_ServiceManager, mock_list_cluster_nodes_except_me, mock_compare_device_uuid): + mock_list_cluster_nodes_except_me.return_value = ['node2'] + mock_ServiceManager_inst = Mock() + mock_ServiceManager.return_value = mock_ServiceManager_inst + mock_ServiceManager_inst.service_is_active.return_value = True sbdmanager_instance = SBDManager(device_list_to_init=['/dev/sbd_device'], timeout_dict={'watchdog': 5, 'msgwait': 10}) sbdmanager_instance.initialize_sbd() mock_logger_info.assert_has_calls([
