mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-06-03 10:50:20 +00:00
config: Add option to set logging mode: none/volatile/persistent
- None disables logging altogether. This is useful when we want to prevent FreedomBox from collecting IP addresses of visitors and other sensitive information. - Volatile logs are kept in RAM until the system is rebooted. Only 5% of RAM will be used at most and only 2 days worth of logs are kept. - Permanent will store logs into /var/log/journal. systemd-journald defaults will apply. 10% of disk capacity is used at most, capped at 4GiB. Also logging will stop if free space is below 15%. Maximum of 100 files are kept. No time based cleanup is done. Tests: - Set the logging mode to disabled. Observe that `journalctl -f` does not show any logs (say when performing plinth actions). - Set the logging mode to volatile. Observe that `journalctl` shows that logging is set to /run/log/journal/ and 5% of available memory is set as maximum. - Set the logging mode to persistent. Observe that `journalctl` shows that logging is set to /var/log/journal/ and 10% of disk space is set as maximum. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
parent
bf1ed7d064
commit
80a203bd23
@ -99,3 +99,15 @@ class ConfigurationForm(forms.Form):
|
||||
help_text=gettext_lazy(
|
||||
'Show apps and features that require more technical '
|
||||
'knowledge.'))
|
||||
|
||||
logging_mode = forms.ChoiceField(
|
||||
label=gettext_lazy('System-wide logging'),
|
||||
choices=(('none', gettext_lazy('Disable logging, for privacy')),
|
||||
('volatile',
|
||||
gettext_lazy('Keep some in memory until a restart, '
|
||||
'for performance')),
|
||||
('persistent',
|
||||
gettext_lazy('Write to disk, useful for debugging'))),
|
||||
help_text=gettext_lazy(
|
||||
'Logs contain information about who accessed the system and debug '
|
||||
'information from various services'))
|
||||
|
||||
58
plinth/modules/config/privileged.py
Normal file
58
plinth/modules/config/privileged.py
Normal file
@ -0,0 +1,58 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""Configure miscellaneous system settings."""
|
||||
|
||||
import pathlib
|
||||
|
||||
import augeas
|
||||
|
||||
from plinth import action_utils
|
||||
from plinth.actions import privileged
|
||||
|
||||
JOURNALD_FILE = pathlib.Path('/etc/systemd/journald.conf.d/50-freedombox.conf')
|
||||
|
||||
|
||||
def load_augeas():
|
||||
"""Initialize Augeas."""
|
||||
aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
|
||||
augeas.Augeas.NO_MODL_AUTOLOAD)
|
||||
aug.transform('Puppet', str(JOURNALD_FILE))
|
||||
aug.set('/augeas/context', '/files' + str(JOURNALD_FILE))
|
||||
aug.load()
|
||||
return aug
|
||||
|
||||
|
||||
def get_logging_mode() -> str:
|
||||
"""Return the logging mode as none, volatile or persistent."""
|
||||
aug = load_augeas()
|
||||
storage = aug.get('Journal/Storage')
|
||||
if storage in ('volatile', 'persistent', 'none'):
|
||||
return storage
|
||||
|
||||
# journald's default is 'auto'. On Debian systems, 'auto' is same
|
||||
# 'persistent' because /var/log/journal exists by default.
|
||||
return 'persistent'
|
||||
|
||||
|
||||
@privileged
|
||||
def set_logging_mode(mode: str) -> None:
|
||||
"""Set the current logging mode."""
|
||||
if mode not in ('volatile', 'persistent', 'none'):
|
||||
raise ValueError('Invalid mode')
|
||||
|
||||
aug = load_augeas()
|
||||
aug.set('Journal/Storage', mode)
|
||||
if mode == 'volatile':
|
||||
aug.set('Journal/RuntimeMaxUse', '5%')
|
||||
aug.set('Journal/MaxFileSec', '6h')
|
||||
aug.set('Journal/MaxRetentionSec', '2day')
|
||||
else:
|
||||
aug.remove('Journal/RuntimeMaxUse')
|
||||
aug.remove('Journal/MaxFileSec')
|
||||
aug.remove('Journal/MaxRetentionSec')
|
||||
|
||||
JOURNALD_FILE.parent.mkdir(exist_ok=True)
|
||||
aug.save()
|
||||
|
||||
# systemd-journald is socket activated, it may not be running and it does
|
||||
# not support reload.
|
||||
action_utils.service_try_restart('systemd-journald')
|
||||
@ -29,14 +29,16 @@ def test_hostname_field():
|
||||
for hostname in valid_hostnames:
|
||||
form = ConfigurationForm({
|
||||
'hostname': hostname,
|
||||
'domainname': 'example.com'
|
||||
'domainname': 'example.com',
|
||||
'logging_mode': 'volatile'
|
||||
})
|
||||
assert form.is_valid()
|
||||
|
||||
for hostname in invalid_hostnames:
|
||||
form = ConfigurationForm({
|
||||
'hostname': hostname,
|
||||
'domainname': 'example.com'
|
||||
'domainname': 'example.com',
|
||||
'logging_mode': 'volatile'
|
||||
})
|
||||
assert not form.is_valid()
|
||||
|
||||
@ -57,14 +59,16 @@ def test_domainname_field():
|
||||
for domainname in valid_domainnames:
|
||||
form = ConfigurationForm({
|
||||
'hostname': 'example',
|
||||
'domainname': domainname
|
||||
'domainname': domainname,
|
||||
'logging_mode': 'volatile'
|
||||
})
|
||||
assert form.is_valid()
|
||||
|
||||
for domainname in invalid_domainnames:
|
||||
form = ConfigurationForm({
|
||||
'hostname': 'example',
|
||||
'domainname': domainname
|
||||
'domainname': domainname,
|
||||
'logging_mode': 'volatile'
|
||||
})
|
||||
assert not form.is_valid()
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@ from plinth.modules import config
|
||||
from plinth.signals import (domain_added, domain_removed, post_hostname_change,
|
||||
pre_hostname_change)
|
||||
|
||||
from . import privileged
|
||||
from .forms import ConfigurationForm
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
@ -30,6 +31,7 @@ class ConfigAppView(views.AppView):
|
||||
'domainname': config.get_domainname(),
|
||||
'homepage': config.get_home_page(),
|
||||
'advanced_mode': config.get_advanced_mode(),
|
||||
'logging_mode': privileged.get_logging_mode(),
|
||||
}
|
||||
|
||||
def form_valid(self, form):
|
||||
@ -37,6 +39,8 @@ class ConfigAppView(views.AppView):
|
||||
old_status = form.initial
|
||||
new_status = form.cleaned_data
|
||||
|
||||
is_changed = False
|
||||
|
||||
if old_status['hostname'] != new_status['hostname']:
|
||||
try:
|
||||
set_hostname(new_status['hostname'])
|
||||
@ -87,6 +91,13 @@ class ConfigAppView(views.AppView):
|
||||
messages.success(self.request,
|
||||
_('Hiding advanced apps and features'))
|
||||
|
||||
if old_status['logging_mode'] != new_status['logging_mode']:
|
||||
privileged.set_logging_mode(new_status['logging_mode'])
|
||||
is_changed = True
|
||||
|
||||
if is_changed:
|
||||
messages.success(self.request, _('Configuration updated'))
|
||||
|
||||
return super(views.AppView, self).form_valid(form)
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user