implements the feature of automatic switch `backend = auto` to backend `systemd`, when:

- no files matching `logpath` found for this jail;
- no `systemd_if_nologs = false` (`true` by default) is specified for the jail;
- option `journalmatch` is set for the jail or its filter (otherwise it'd be too heavy to allow all auto-jails, even if they have never been foreseen for journal);
- option `skip_if_nologs` will be ignored if we could switch backend to `systemd`;
closes gh-3768
pull/3927/merge
sebres 2025-03-30 22:31:44 +02:00
parent 5a2fd9b31c
commit b2352f113e
4 changed files with 83 additions and 51 deletions

View File

@ -117,12 +117,13 @@ class JailReader(ConfigReader):
"logencoding": ["string", None],
"logpath": ["string", None],
"skip_if_nologs": ["bool", False],
"systemd_if_nologs": ["bool", True],
"action": ["string", ""]
}
_configOpts.update(FilterReader._configOpts)
_ignoreOpts = set(
['action', 'filter', 'enabled', 'backend', 'skip_if_nologs'] +
['action', 'filter', 'enabled', 'backend', 'skip_if_nologs', 'systemd_if_nologs'] +
list(FilterReader._configOpts.keys())
)
@ -239,7 +240,7 @@ class JailReader(ConfigReader):
return self.__opts
return _merge_dicts(self.__opts, self.__filter.getCombined())
def convert(self, allow_no_files=False):
def convert(self, allow_no_files=False, systemd_if_nologs=True):
"""Convert read before __opts to the commands stream
Parameters
@ -277,14 +278,25 @@ class JailReader(ConfigReader):
stream2.append(
["set", self.__name, "addlogpath", p, tail])
if not found_files:
msg = "Have not found any log file for %s jail" % self.__name
msg = "Have not found any log file for '%s' jail." % self.__name
skip_if_nologs = self.__opts.get('skip_if_nologs', False)
if not allow_no_files and not skip_if_nologs:
# if auto and we can switch to systemd backend (only possible if jail have journalmatch):
if backend.startswith("auto") and systemd_if_nologs and (
self.__opts.get('systemd_if_nologs', True) and
self.__opts.get('journalmatch', None) is not None
):
# switch backend to systemd:
backend = 'systemd'
msg += " Jail will monitor systemd journal."
skip_if_nologs = False
elif not allow_no_files and not skip_if_nologs:
raise ValueError(msg)
logSys.warning(msg)
if skip_if_nologs:
self.__opts['config-error'] = msg
stream = [['config-error', "Jail '%s' skipped, because of missing log files." % (self.__name,)]]
self.__opts['runtime-error'] = msg
msg = "Jail '%s' skipped, because of missing log files." % (self.__name,)
logSys.warning(msg)
stream = [['config-error', msg]]
return stream
elif opt == "ignoreip":
stream.append(["set", self.__name, "addignoreip"] + splitwords(value))

View File

@ -88,7 +88,7 @@ class JailsReader(ConfigReader):
parse_status |= 2
return ((ignoreWrong and parse_status & 1) or not (parse_status & 2))
def convert(self, allow_no_files=False):
def convert(self, allow_no_files=False, systemd_if_nologs=True):
"""Convert read before __opts and jails to the commands stream
Parameters
@ -101,11 +101,14 @@ class JailsReader(ConfigReader):
stream = list()
# Convert jails
for jail in self.__jails:
stream.extend(jail.convert(allow_no_files=allow_no_files))
stream.extend(jail.convert(allow_no_files, systemd_if_nologs))
# Start jails
for jail in self.__jails:
if not jail.options.get('config-error'):
if not jail.options.get('config-error') and not jail.options.get('runtime-error'):
stream.append(["start", jail.getName()])
else:
# just delete rtm-errors (to check next time if cached)
jail.options.pop('runtime-error', None)
return stream

View File

@ -719,51 +719,67 @@ class JailsReaderTest(LogCaptureTestCase):
jails = JailsReader(basedir=IMPERFECT_CONFIG, share_config=IMPERFECT_CONFIG_SHARE_CFG)
self.assertTrue(jails.read())
self.assertFalse(jails.getOptions(ignoreWrong=False))
self.assertRaises(ValueError, jails.convert)
comm_commands = jails.convert(allow_no_files=True)
self.maxDiff = None
self.assertSortedEqual(comm_commands,
[['add', 'emptyaction', 'auto'],
['add', 'test-known-interp', 'auto'],
['multi-set', 'test-known-interp', 'addfailregex', [
'failure test 1 (filter.d/test.conf) <HOST>',
'failure test 2 (filter.d/test.local) <HOST>',
'failure test 3 (jail.local) <HOST>'
]],
['start', 'test-known-interp'],
['add', 'missinglogfiles', 'auto'],
['set', 'missinglogfiles', 'addfailregex', '<IP>'],
['config-error', "Jail 'missinglogfiles_skip' skipped, because of missing log files."],
['add', 'brokenaction', 'auto'],
['set', 'brokenaction', 'addfailregex', '<IP>'],
['set', 'brokenaction', 'addaction', 'brokenaction'],
['multi-set', 'brokenaction', 'action', 'brokenaction', [
['actionban', 'hit with big stick <ip>'],
['actname', 'brokenaction'],
['name', 'brokenaction']
]],
['add', 'parse_to_end_of_jail.conf', 'auto'],
['set', 'parse_to_end_of_jail.conf', 'addfailregex', '<IP>'],
['set', 'tz_correct', 'addfailregex', '<IP>'],
['set', 'tz_correct', 'logtimezone', 'UTC+0200'],
['start', 'emptyaction'],
['start', 'missinglogfiles'],
['start', 'brokenaction'],
['start', 'parse_to_end_of_jail.conf'],
['add', 'tz_correct', 'auto'],
['start', 'tz_correct'],
['config-error',
"Jail 'brokenactiondef' skipped, because of wrong configuration: Invalid action definition 'joho[foo': unexpected option syntax"],
['config-error',
"Jail 'brokenfilterdef' skipped, because of wrong configuration: Invalid filter definition 'flt[test': unexpected option syntax"],
['config-error',
"Jail 'missingaction' skipped, because of wrong configuration: Unable to read action 'noactionfileforthisaction'"],
['config-error',
"Jail 'missingbitsjail' skipped, because of wrong configuration: Unable to read the filter 'catchallthebadies'"],
])
self.assertRaises(ValueError, lambda: jails.convert(systemd_if_nologs=False))
self.assertLogged("Errors in jail 'missingbitsjail'.")
self.assertNotLogged("Skipping...")
# check with allow no files (just to cover other jail problems), but without switch to systemd:
self.pruneLog('[test-phase] allow no files, no switch to systemd ...')
comm_commands = jails.convert(allow_no_files=True, systemd_if_nologs=False)
self.maxDiff = None
def _checkStream(comm_commands, backend='auto'):
self.assertSortedEqual(comm_commands,
[['add', 'emptyaction', 'auto'],
['add', 'test-known-interp', 'auto'],
['multi-set', 'test-known-interp', 'addfailregex', [
'failure test 1 (filter.d/test.conf) <HOST>',
'failure test 2 (filter.d/test.local) <HOST>',
'failure test 3 (jail.local) <HOST>'
]],
['start', 'test-known-interp'],
['add', 'missinglogfiles', backend], # can switch backend because have journalmatch
['set', 'missinglogfiles', 'addfailregex', '<IP>'],
['set', 'missinglogfiles', 'addjournalmatch', '_COMM=test'],
['config-error', "Jail 'missinglogfiles_skip' skipped, because of missing log files."],
['add', 'brokenaction', 'auto'],
['set', 'brokenaction', 'addfailregex', '<IP>'],
['set', 'brokenaction', 'addaction', 'brokenaction'],
['multi-set', 'brokenaction', 'action', 'brokenaction', [
['actionban', 'hit with big stick <ip>'],
['actname', 'brokenaction'],
['name', 'brokenaction']
]],
['add', 'parse_to_end_of_jail.conf', 'auto'],
['set', 'parse_to_end_of_jail.conf', 'addfailregex', '<IP>'],
['set', 'tz_correct', 'addfailregex', '<IP>'],
['set', 'tz_correct', 'logtimezone', 'UTC+0200'],
['start', 'emptyaction'],
['start', 'missinglogfiles'],
['start', 'brokenaction'],
['start', 'parse_to_end_of_jail.conf'],
['add', 'tz_correct', 'auto'],
['start', 'tz_correct'],
['config-error',
"Jail 'brokenactiondef' skipped, because of wrong configuration: Invalid action definition 'joho[foo': unexpected option syntax"],
['config-error',
"Jail 'brokenfilterdef' skipped, because of wrong configuration: Invalid filter definition 'flt[test': unexpected option syntax"],
['config-error',
"Jail 'missingaction' skipped, because of wrong configuration: Unable to read action 'noactionfileforthisaction'"],
['config-error',
"Jail 'missingbitsjail' skipped, because of wrong configuration: Unable to read the filter 'catchallthebadies'"],
])
_checkStream(comm_commands, backend='auto')
self.assertNotLogged("Have not found any log file for 'missinglogfiles' jail. Jail will monitor systemd journal.")
self.assertLogged("No file(s) found for glob /weapons/of/mass/destruction")
self.assertLogged("Jail 'missinglogfiles_skip' skipped, because of missing log files.")
# switch backend auto to systemd if no files found, note that jail "missinglogfiles_skip" will be skipped yet,
# because for this jail configured skip_if_nologs = true, all other jails shall switch to systemd with warning
self.pruneLog('[test-phase] auto -> systemd')
comm_commands = jails.convert(allow_no_files=True)
_checkStream(comm_commands, backend='systemd')
self.assertNotLogged("Errors in jail 'missingbitsjail'.")
self.assertLogged("Have not found any log file for 'missinglogfiles' jail. Jail will monitor systemd journal.")
self.assertLogged("No file(s) found for glob /weapons/of/mass/destruction")
self.assertLogged("Jail 'missinglogfiles_skip' skipped, because of missing log files.")
def testReadStockActionConf(self):
unittest.F2B.SkipIfCfgMissing(stock=True)

View File

@ -21,6 +21,7 @@ failregex = %(known/failregex)s
[missinglogfiles]
enabled = true
journalmatch = _COMM=test ;# allow to switch to systemd (by backend = `auto` and no logs found)
logpath = /weapons/of/mass/destruction
[missinglogfiles_skip]