diff --git a/actions/shadowsocks b/actions/shadowsocks
index 61a98bfd5..d5bd93bfe 100755
--- a/actions/shadowsocks
+++ b/actions/shadowsocks
@@ -14,7 +14,7 @@ import sys
from shutil import move
from plinth import action_utils
-from plinth.modules import shadowsocks
+from plinth.modules.shadowsocks import ShadowsocksApp
SHADOWSOCKS_CONFIG_SYMLINK = '/etc/shadowsocks-libev/freedombox.json'
SHADOWSOCKS_CONFIG_ACTUAL = \
@@ -76,8 +76,8 @@ def subcommand_setup(_):
if not wrong_state_dir.is_symlink() and wrong_state_dir.is_dir():
wrong_state_dir.rmdir()
- if action_utils.service_is_enabled(shadowsocks.managed_services[0]):
- action_utils.service_restart(shadowsocks.managed_services[0])
+ if action_utils.service_is_enabled(ShadowsocksApp.DAEMON):
+ action_utils.service_restart(ShadowsocksApp.DAEMON)
def subcommand_get_config(_):
@@ -110,8 +110,8 @@ def subcommand_merge_config(_):
# Don't try_restart because initial configuration may not be valid so
# shadowsocks will not be running even when enabled.
- if action_utils.service_is_enabled(shadowsocks.managed_services[0]):
- action_utils.service_restart(shadowsocks.managed_services[0])
+ if action_utils.service_is_enabled(ShadowsocksApp.DAEMON):
+ action_utils.service_restart(ShadowsocksApp.DAEMON)
def main():
diff --git a/plinth/modules/apache/__init__.py b/plinth/modules/apache/__init__.py
index 995a9dd2c..ba49356d7 100644
--- a/plinth/modules/apache/__init__.py
+++ b/plinth/modules/apache/__init__.py
@@ -9,7 +9,7 @@ from django.utils.translation import gettext_lazy as _
from plinth import actions
from plinth import app as app_module
from plinth import cfg
-from plinth.daemon import Daemon
+from plinth.daemon import Daemon, RelatedDaemon
from plinth.modules.firewall.components import Firewall
from plinth.modules.letsencrypt.components import LetsEncrypt
from plinth.package import Packages
@@ -19,8 +19,6 @@ version = 9
is_essential = True
-managed_services = ['apache2', 'uwsgi']
-
app = None
@@ -55,10 +53,13 @@ class ApacheApp(app_module.App):
self.add(freedombox_ports)
letsencrypt = LetsEncrypt('letsencrypt-apache', domains='*',
- daemons=[managed_services[0]])
+ daemons=['apache2'])
self.add(letsencrypt)
- daemon = Daemon('daemon-apache', managed_services[0])
+ daemon = Daemon('daemon-apache', 'apache2')
+ self.add(daemon)
+
+ daemon = RelatedDaemon('related-daemon-apache', 'uwsgi')
self.add(daemon)
diff --git a/plinth/modules/avahi/__init__.py b/plinth/modules/avahi/__init__.py
index d0dabaec1..32e3e4313 100644
--- a/plinth/modules/avahi/__init__.py
+++ b/plinth/modules/avahi/__init__.py
@@ -27,8 +27,6 @@ is_essential = True
depends = ['names']
-managed_services = ['avahi-daemon']
-
_description = [
format_lazy(
_('Service discovery allows other devices on the network to '
@@ -74,7 +72,7 @@ class AvahiApp(app_module.App):
is_external=False)
self.add(firewall)
- daemon = Daemon('daemon-avahi', managed_services[0])
+ daemon = Daemon('daemon-avahi', 'avahi-daemon')
self.add(daemon)
backup_restore = BackupRestore('backup-restore-avahi',
diff --git a/plinth/modules/bind/__init__.py b/plinth/modules/bind/__init__.py
index 2de4e1bb8..3c2bb37c5 100644
--- a/plinth/modules/bind/__init__.py
+++ b/plinth/modules/bind/__init__.py
@@ -23,8 +23,6 @@ from . import manifest
version = 2
-managed_services = ['named']
-
_description = [
_('BIND enables you to publish your Domain Name System (DNS) information '
'on the Internet, and to resolve DNS queries for your user devices on '
@@ -93,10 +91,8 @@ class BindApp(app_module.App):
self.add(firewall)
daemon = Daemon(
- 'daemon-bind', managed_services[0], listen_ports=[(53, 'tcp6'),
- (53, 'udp6'),
- (53, 'tcp4'),
- (53, 'udp4')])
+ 'daemon-bind', 'named', listen_ports=[(53, 'tcp6'), (53, 'udp6'),
+ (53, 'tcp4'), (53, 'udp4')])
self.add(daemon)
backup_restore = BackupRestore('backup-restore-bind',
diff --git a/plinth/modules/calibre/__init__.py b/plinth/modules/calibre/__init__.py
index 22c8a9165..ffee9a87b 100644
--- a/plinth/modules/calibre/__init__.py
+++ b/plinth/modules/calibre/__init__.py
@@ -23,8 +23,6 @@ from . import manifest
version = 1
-managed_services = ['calibre-server-freedombox']
-
_description = [
format_lazy(
_('calibre server provides online access to your e-book collection. '
@@ -50,6 +48,8 @@ class CalibreApp(app_module.App):
app_id = 'calibre'
+ DAEMON = 'calibre-server-freedombox'
+
def __init__(self):
"""Create components for the app."""
super().__init__()
@@ -88,7 +88,7 @@ class CalibreApp(app_module.App):
urls=['https://{host}/calibre'])
self.add(webserver)
- daemon = Daemon('daemon-calibre', managed_services[0],
+ daemon = Daemon('daemon-calibre', self.DAEMON,
listen_ports=[(8844, 'tcp4')])
self.add(daemon)
@@ -123,10 +123,10 @@ def list_libraries():
def create_library(name):
"""Create an empty library."""
actions.superuser_run('calibre', ['create-library', name])
- actions.superuser_run('service', ['try-restart', managed_services[0]])
+ actions.superuser_run('service', ['try-restart', CalibreApp.DAEMON])
def delete_library(name):
"""Delete a library and its contents."""
actions.superuser_run('calibre', ['delete-library', name])
- actions.superuser_run('service', ['try-restart', managed_services[0]])
+ actions.superuser_run('service', ['try-restart', CalibreApp.DAEMON])
diff --git a/plinth/modules/cockpit/__init__.py b/plinth/modules/cockpit/__init__.py
index 5fc886b69..f5817894d 100644
--- a/plinth/modules/cockpit/__init__.py
+++ b/plinth/modules/cockpit/__init__.py
@@ -24,8 +24,6 @@ version = 1
is_essential = True
-managed_services = ['cockpit.socket']
-
_description = [
format_lazy(
_('Cockpit is a server manager that makes it easy to administer '
@@ -56,6 +54,8 @@ class CockpitApp(app_module.App):
app_id = 'cockpit'
+ DAEMON = 'cockpit.socket'
+
def __init__(self):
"""Create components for the app."""
super().__init__()
@@ -92,7 +92,7 @@ class CockpitApp(app_module.App):
urls=['https://{host}/_cockpit/'])
self.add(webserver)
- daemon = Daemon('daemon-cockpit', managed_services[0])
+ daemon = Daemon('daemon-cockpit', self.DAEMON)
self.add(daemon)
backup_restore = BackupRestore('backup-restore-cockpit',
@@ -123,7 +123,7 @@ def on_domain_added(sender, domain_type, name, description='', services=None,
if name not in utils.get_domains():
actions.superuser_run('cockpit', ['add-domain', name])
actions.superuser_run('service',
- ['try-restart', managed_services[0]])
+ ['try-restart', CockpitApp.DAEMON])
def on_domain_removed(sender, domain_type, name, **kwargs):
@@ -133,4 +133,4 @@ def on_domain_removed(sender, domain_type, name, **kwargs):
if name in utils.get_domains():
actions.superuser_run('cockpit', ['remove-domain', name])
actions.superuser_run('service',
- ['try-restart', managed_services[0]])
+ ['try-restart', CockpitApp.DAEMON])
diff --git a/plinth/modules/config/__init__.py b/plinth/modules/config/__init__.py
index 169bc3fea..c1c200114 100644
--- a/plinth/modules/config/__init__.py
+++ b/plinth/modules/config/__init__.py
@@ -12,6 +12,7 @@ from django.utils.translation import gettext_lazy as _
from plinth import actions
from plinth import app as app_module
from plinth import frontpage, menu
+from plinth.daemon import RelatedDaemon
from plinth.modules.apache import (get_users_with_website, user_of_uws_url,
uws_url_of_user)
from plinth.modules.names.components import DomainType
@@ -22,8 +23,6 @@ version = 3
is_essential = True
-managed_services = ['systemd-journald', 'rsyslog']
-
_description = [
_('Here you can set some general configuration options '
'like hostname, domain name, webserver home page etc.')
@@ -66,6 +65,12 @@ class ConfigApp(app_module.App):
packages = Packages('packages-config', ['zram-tools'])
self.add(packages)
+ daemon1 = RelatedDaemon('related-daemon-config1', 'systemd-journald')
+ self.add(daemon1)
+
+ daemon2 = RelatedDaemon('related-daemon-config2', 'rsyslog')
+ self.add(daemon2)
+
domain_type = DomainType('domain-type-static', _('Domain Name'),
'config:index', can_have_certificate=True)
self.add(domain_type)
diff --git a/plinth/modules/coturn/__init__.py b/plinth/modules/coturn/__init__.py
index a774049d5..dadca2b8c 100644
--- a/plinth/modules/coturn/__init__.py
+++ b/plinth/modules/coturn/__init__.py
@@ -27,8 +27,6 @@ from . import manifest
version = 1
-managed_services = ['coturn']
-
managed_paths = [pathlib.Path('/etc/coturn/')]
_description = [
@@ -76,8 +74,8 @@ class CoturnApp(app_module.App):
self.add(firewall)
letsencrypt = LetsEncrypt(
- 'letsencrypt-coturn', domains=get_domains,
- daemons=managed_services, should_copy_certificates=True,
+ 'letsencrypt-coturn', domains=get_domains, daemons=['coturn'],
+ should_copy_certificates=True,
private_key_path='/etc/coturn/certs/pkey.pem',
certificate_path='/etc/coturn/certs/cert.pem',
user_owner='turnserver', group_owner='turnserver',
@@ -85,13 +83,22 @@ class CoturnApp(app_module.App):
self.add(letsencrypt)
daemon = Daemon(
- 'daemon-coturn', managed_services[0],
- listen_ports=[(3478, 'udp4'), (3478, 'udp6'), (3478, 'tcp4'),
- (3478, 'tcp6'), (3479, 'udp4'), (3479, 'udp6'),
- (3479, 'tcp4'), (3479, 'tcp6'), (5349, 'udp4'),
- (5349, 'udp6'), (5349, 'tcp4'), (5349, 'tcp6'),
- (5350, 'udp4'), (5350, 'udp6'), (5350, 'tcp4'),
- (5350, 'tcp6')])
+ 'daemon-coturn', 'coturn', listen_ports=[(3478, 'udp4'),
+ (3478, 'udp6'),
+ (3478, 'tcp4'),
+ (3478, 'tcp6'),
+ (3479, 'udp4'),
+ (3479, 'udp6'),
+ (3479, 'tcp4'),
+ (3479, 'tcp6'),
+ (5349, 'udp4'),
+ (5349, 'udp6'),
+ (5349, 'tcp4'),
+ (5349, 'tcp6'),
+ (5350, 'udp4'),
+ (5350, 'udp6'),
+ (5350, 'tcp4'),
+ (5350, 'tcp6')])
self.add(daemon)
users_and_groups = UsersAndGroups('users-and-groups-coturn',
diff --git a/plinth/modules/datetime/__init__.py b/plinth/modules/datetime/__init__.py
index 7110aedd5..aefdec394 100644
--- a/plinth/modules/datetime/__init__.py
+++ b/plinth/modules/datetime/__init__.py
@@ -18,8 +18,6 @@ version = 2
is_essential = True
-managed_services = ['systemd-timesyncd']
-
_description = [
_('Network time server is a program that maintains the system time '
'in synchronization with servers on the Internet.')
@@ -76,7 +74,7 @@ class DateTimeApp(app_module.App):
self.add(menu_item)
if self._is_time_managed():
- daemon = Daemon('daemon-datetime', managed_services[0])
+ daemon = Daemon('daemon-datetime', 'systemd-timesyncd')
self.add(daemon)
backup_restore = BackupRestore('backup-restore-datetime',
diff --git a/plinth/modules/deluge/__init__.py b/plinth/modules/deluge/__init__.py
index c563f81d4..68be81004 100644
--- a/plinth/modules/deluge/__init__.py
+++ b/plinth/modules/deluge/__init__.py
@@ -20,8 +20,6 @@ from . import manifest
version = 6
-managed_services = ['deluged', 'deluge-web']
-
_description = [
_('Deluge is a BitTorrent client that features a Web UI.'),
_('The default password is \'deluge\', but you should log in and '
@@ -79,11 +77,11 @@ class DelugeApp(app_module.App):
urls=['https://{host}/deluge'])
self.add(webserver)
- daemon = Daemon('daemon-deluged', managed_services[0],
+ daemon = Daemon('daemon-deluged', 'deluged',
listen_ports=[(58846, 'tcp4')])
self.add(daemon)
- daemon_web = Daemon('daemon-deluge-web', managed_services[1],
+ daemon_web = Daemon('daemon-deluge-web', 'deluge-web',
listen_ports=[(8112, 'tcp4')])
self.add(daemon_web)
diff --git a/plinth/modules/diaspora/__init__.py b/plinth/modules/diaspora/__init__.py
index 53f39f216..a144fee75 100644
--- a/plinth/modules/diaspora/__init__.py
+++ b/plinth/modules/diaspora/__init__.py
@@ -38,8 +38,6 @@ def get_configured_domain_name():
version = 1
-managed_services = ['diaspora']
-
_description = [
_('diaspora* is a decentralized social network where you can store '
'and control your own data.'),
@@ -92,7 +90,7 @@ class DiasporaApp(app_module.App):
webserver = Webserver('webserver-diaspora', 'diaspora-plinth')
self.add(webserver)
- daemon = Daemon('daemon-diaspora', managed_services[0])
+ daemon = Daemon('daemon-diaspora', 'diaspora')
self.add(daemon)
def diagnose(self):
diff --git a/plinth/modules/ejabberd/__init__.py b/plinth/modules/ejabberd/__init__.py
index 48ca1a85f..5926d5441 100644
--- a/plinth/modules/ejabberd/__init__.py
+++ b/plinth/modules/ejabberd/__init__.py
@@ -30,8 +30,6 @@ from . import manifest
version = 4
-managed_services = ['ejabberd']
-
managed_paths = [pathlib.Path('/etc/ejabberd/')]
_description = [
@@ -110,9 +108,12 @@ class EjabberdApp(app_module.App):
self.add(letsencrypt)
daemon = Daemon(
- 'daemon-ejabberd', managed_services[0],
- listen_ports=[(5222, 'tcp4'), (5222, 'tcp6'), (5269, 'tcp4'),
- (5269, 'tcp6'), (5443, 'tcp4'), (5443, 'tcp6')])
+ 'daemon-ejabberd', 'ejabberd', listen_ports=[(5222, 'tcp4'),
+ (5222, 'tcp6'),
+ (5269, 'tcp4'),
+ (5269, 'tcp6'),
+ (5443, 'tcp4'),
+ (5443, 'tcp6')])
self.add(daemon)
users_and_groups = UsersAndGroups('users-and-groups-ejabberd',
diff --git a/plinth/modules/email_server/__init__.py b/plinth/modules/email_server/__init__.py
index 2d21fe87f..83311b4fa 100644
--- a/plinth/modules/email_server/__init__.py
+++ b/plinth/modules/email_server/__init__.py
@@ -35,8 +35,6 @@ port_info = {
'dovecot': ('imaps', 993, 'pop3s', 995),
}
-managed_services = ['postfix', 'dovecot', 'rspamd']
-
_description = [
_('Roundcube app provides web '
'interface for users to access email.'),
@@ -105,7 +103,7 @@ class EmailServerApp(plinth.app.App):
self.add(menu_item)
def _add_daemons(self):
- for srvname in managed_services:
+ for srvname in ['postfix', 'dovecot', 'rspamd']:
# Construct `listen_ports` parameter for the daemon
mixed = port_info.get(srvname, ())
port_numbers = [v for v in mixed if isinstance(v, int)]
@@ -168,8 +166,9 @@ def setup(helper, old_version=None):
helper.call('post', audit.rcube.repair)
# Reload
- for srvname in managed_services:
- actions.superuser_run('service', ['reload', srvname])
+ actions.superuser_run('service', ['reload', 'postfix'])
+ actions.superuser_run('service', ['reload', 'dovecot'])
+ actions.superuser_run('service', ['reload', 'rspamd'])
# Expose to public internet
helper.call('post', app.enable)
diff --git a/plinth/modules/firewall/__init__.py b/plinth/modules/firewall/__init__.py
index c05e1cdac..343f19be5 100644
--- a/plinth/modules/firewall/__init__.py
+++ b/plinth/modules/firewall/__init__.py
@@ -25,8 +25,6 @@ version = 2
is_essential = True
-managed_services = ['firewalld']
-
_description = [
format_lazy(
_('Firewall is a security system that controls the incoming and '
@@ -75,7 +73,7 @@ class FirewallApp(app_module.App):
packages = Packages('packages-firewall', ['firewalld', 'nftables'])
self.add(packages)
- daemon = Daemon('daemon-firewall', managed_services[0])
+ daemon = Daemon('daemon-firewall', 'firewalld')
self.add(daemon)
backup_restore = BackupRestore('backup-restore-firewall',
diff --git a/plinth/modules/i2p/__init__.py b/plinth/modules/i2p/__init__.py
index ac60af7da..5a477c355 100644
--- a/plinth/modules/i2p/__init__.py
+++ b/plinth/modules/i2p/__init__.py
@@ -20,10 +20,6 @@ from . import manifest
version = 1
-service_name = 'i2p'
-
-managed_services = [service_name]
-
_description = [
_('The Invisible Internet Project is an anonymous network layer intended '
'to protect communication from censorship and surveillance. I2P '
@@ -92,8 +88,7 @@ class I2PApp(app_module.App):
urls=['https://{host}/i2p/'])
self.add(webserver)
- daemon = Daemon('daemon-i2p', managed_services[0],
- listen_ports=[(7657, 'tcp6')])
+ daemon = Daemon('daemon-i2p', 'i2p', listen_ports=[(7657, 'tcp6')])
self.add(daemon)
users_and_groups = UsersAndGroups('users-and-groups-i2p',
diff --git a/plinth/modules/infinoted/__init__.py b/plinth/modules/infinoted/__init__.py
index 36a76503d..b02009b36 100644
--- a/plinth/modules/infinoted/__init__.py
+++ b/plinth/modules/infinoted/__init__.py
@@ -19,8 +19,6 @@ from . import manifest
version = 3
-managed_services = ['infinoted']
-
_description = [
_('infinoted is a server for Gobby, a collaborative text editor.'),
format_lazy(
@@ -70,7 +68,7 @@ class InfinotedApp(app_module.App):
ports=['infinoted-plinth'], is_external=True)
self.add(firewall)
- daemon = Daemon('daemon-infinoted', managed_services[0],
+ daemon = Daemon('daemon-infinoted', 'infinoted',
listen_ports=[(6523, 'tcp4'), (6523, 'tcp6')])
self.add(daemon)
diff --git a/plinth/modules/matrixsynapse/__init__.py b/plinth/modules/matrixsynapse/__init__.py
index 5736d1ea5..a3c9c5481 100644
--- a/plinth/modules/matrixsynapse/__init__.py
+++ b/plinth/modules/matrixsynapse/__init__.py
@@ -28,8 +28,6 @@ from . import manifest
version = 7
-managed_services = ['matrix-synapse']
-
managed_paths = [pathlib.Path('/etc/matrix-synapse/')]
_description = [
@@ -107,14 +105,14 @@ class MatrixSynapseApp(app_module.App):
letsencrypt = LetsEncrypt(
'letsencrypt-matrixsynapse', domains=get_domains,
- daemons=[managed_services[0]], should_copy_certificates=True,
+ daemons=['matrix-synapse'], should_copy_certificates=True,
private_key_path='/etc/matrix-synapse/homeserver.tls.key',
certificate_path='/etc/matrix-synapse/homeserver.tls.crt',
user_owner='matrix-synapse', group_owner='nogroup',
managing_app='matrixsynapse')
self.add(letsencrypt)
- daemon = Daemon('daemon-matrixsynapse', managed_services[0],
+ daemon = Daemon('daemon-matrixsynapse', 'matrix-synapse',
listen_ports=[(8008, 'tcp4'), (8448, 'tcp4')])
self.add(daemon)
diff --git a/plinth/modules/mediawiki/__init__.py b/plinth/modules/mediawiki/__init__.py
index e78069ba0..387b14d6d 100644
--- a/plinth/modules/mediawiki/__init__.py
+++ b/plinth/modules/mediawiki/__init__.py
@@ -21,8 +21,6 @@ from . import manifest
version = 10
-managed_services = ['mediawiki-jobrunner']
-
_description = [
_('MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia '
'projects. A wiki engine is a program for creating a collaboratively '
@@ -89,7 +87,7 @@ class MediaWikiApp(app_module.App):
'mediawiki-freedombox')
self.add(webserver)
- daemon = Daemon('daemon-mediawiki', managed_services[0])
+ daemon = Daemon('daemon-mediawiki', 'mediawiki-jobrunner')
self.add(daemon)
backup_restore = BackupRestore('backup-restore-mediawiki',
diff --git a/plinth/modules/minetest/__init__.py b/plinth/modules/minetest/__init__.py
index 3d0027d6e..f56d48f0d 100644
--- a/plinth/modules/minetest/__init__.py
+++ b/plinth/modules/minetest/__init__.py
@@ -20,8 +20,6 @@ from . import manifest
version = 2
-managed_services = ['minetest-server']
-
_mods = [
'minetest-mod-character-creator', 'minetest-mod-craftguide',
'minetest-mod-infinite-chest', 'minetest-mod-lucky-block',
@@ -85,7 +83,7 @@ class MinetestApp(app_module.App):
ports=['minetest-plinth'], is_external=True)
self.add(firewall)
- daemon = Daemon('daemon-minetest', managed_services[0],
+ daemon = Daemon('daemon-minetest', 'minetest-server',
listen_ports=[(30000, 'udp4')])
self.add(daemon)
diff --git a/plinth/modules/minidlna/__init__.py b/plinth/modules/minidlna/__init__.py
index b256e2144..680c5d089 100644
--- a/plinth/modules/minidlna/__init__.py
+++ b/plinth/modules/minidlna/__init__.py
@@ -18,8 +18,6 @@ from . import manifest
version = 2
-managed_services = ['minidlna']
-
_description = [
_('MiniDLNA is a simple media server software, with the aim of being '
'fully compliant with DLNA/UPnP-AV clients. '
@@ -81,7 +79,7 @@ class MiniDLNAApp(app_module.App):
urls=['http://localhost:8200/'])
self.add(webserver)
- daemon = Daemon('daemon-minidlna', managed_services[0])
+ daemon = Daemon('daemon-minidlna', 'minidlna')
self.add(daemon)
backup_restore = BackupRestore('backup-restore-minidlna',
diff --git a/plinth/modules/mldonkey/__init__.py b/plinth/modules/mldonkey/__init__.py
index 1a11f6c3a..1b5934230 100644
--- a/plinth/modules/mldonkey/__init__.py
+++ b/plinth/modules/mldonkey/__init__.py
@@ -21,8 +21,6 @@ from . import manifest
version = 2
-managed_services = ['mldonkey-server']
-
_description = [
_('MLDonkey is a peer-to-peer file sharing application used to exchange '
'large files. It can participate in multiple peer-to-peer networks '
@@ -46,6 +44,8 @@ class MLDonkeyApp(app_module.App):
app_id = 'mldonkey'
+ DAEMON = 'mldonkey-server'
+
def __init__(self):
"""Create components for the app."""
super().__init__()
@@ -83,7 +83,7 @@ class MLDonkeyApp(app_module.App):
urls=['https://{host}/mldonkey/'])
self.add(webserver)
- daemon = Daemon('daemon-mldonkey', managed_services[0],
+ daemon = Daemon('daemon-mldonkey', self.DAEMON,
listen_ports=[(4080, 'tcp4')])
self.add(daemon)
@@ -104,4 +104,4 @@ def setup(helper, old_version=None):
if not old_version:
helper.call('post', app.enable)
- add_user_to_share_group(_SYSTEM_USER, managed_services[0])
+ add_user_to_share_group(_SYSTEM_USER, MLDonkeyApp.DAEMON)
diff --git a/plinth/modules/mumble/__init__.py b/plinth/modules/mumble/__init__.py
index 4321c7f87..a60ab450d 100644
--- a/plinth/modules/mumble/__init__.py
+++ b/plinth/modules/mumble/__init__.py
@@ -24,8 +24,6 @@ from . import manifest
version = 2
-managed_services = ['mumble-server']
-
managed_paths = [pathlib.Path('/var/lib/mumble-server')]
_description = [
@@ -76,7 +74,7 @@ class MumbleApp(app_module.App):
letsencrypt = LetsEncrypt(
'letsencrypt-mumble', domains=get_domains,
- daemons=managed_services, should_copy_certificates=True,
+ daemons=['mumble-server'], should_copy_certificates=True,
private_key_path='/var/lib/mumble-server/privkey.pem',
certificate_path='/var/lib/mumble-server/fullchain.pem',
user_owner='mumble-server', group_owner='mumble-server',
@@ -84,9 +82,10 @@ class MumbleApp(app_module.App):
self.add(letsencrypt)
daemon = Daemon(
- 'daemon-mumble', managed_services[0],
- listen_ports=[(64738, 'tcp4'), (64738, 'tcp6'), (64738, 'udp4'),
- (64738, 'udp6')])
+ 'daemon-mumble', 'mumble-server', listen_ports=[(64738, 'tcp4'),
+ (64738, 'tcp6'),
+ (64738, 'udp4'),
+ (64738, 'udp6')])
self.add(daemon)
users_and_groups = UsersAndGroups('users-and-groups-mumble',
diff --git a/plinth/modules/openvpn/__init__.py b/plinth/modules/openvpn/__init__.py
index a3ed018b4..a156d110d 100644
--- a/plinth/modules/openvpn/__init__.py
+++ b/plinth/modules/openvpn/__init__.py
@@ -22,8 +22,6 @@ from . import manifest
version = 4
-managed_services = ['openvpn-server@freedombox']
-
_description = [
format_lazy(
_('Virtual Private Network (VPN) is a technique for securely '
@@ -87,7 +85,7 @@ class OpenVPNApp(app_module.App):
is_external=True)
self.add(firewall)
- daemon = Daemon('daemon-openvpn', managed_services[0],
+ daemon = Daemon('daemon-openvpn', 'openvpn-server@freedombox',
listen_ports=[(1194, 'udp4'), (1194, 'udp6')])
self.add(daemon)
diff --git a/plinth/modules/pagekite/__init__.py b/plinth/modules/pagekite/__init__.py
index bef97337a..531f5393e 100644
--- a/plinth/modules/pagekite/__init__.py
+++ b/plinth/modules/pagekite/__init__.py
@@ -20,8 +20,6 @@ version = 2
depends = ['names']
-managed_services = ['pagekite']
-
_description = [
format_lazy(
_('PageKite is a system for exposing {box_name} services when '
@@ -56,6 +54,8 @@ class PagekiteApp(app_module.App):
app_id = 'pagekite'
+ DAEMON = 'pagekite'
+
def __init__(self):
"""Create components for the app."""
super().__init__()
@@ -80,7 +80,7 @@ class PagekiteApp(app_module.App):
'pagekite:index', can_have_certificate=True)
self.add(domain_type)
- daemon = Daemon('daemon-pagekite', managed_services[0])
+ daemon = Daemon('daemon-pagekite', self.DAEMON)
self.add(daemon)
backup_restore = BackupRestore('backup-restore-pagekite',
@@ -112,4 +112,4 @@ def setup(helper, old_version=None):
helper.call('post', app.enable)
if old_version == 1:
- actions.superuser_run('service', ['try-restart', managed_services[0]])
+ actions.superuser_run('service', ['try-restart', PagekiteApp.DAEMON])
diff --git a/plinth/modules/performance/__init__.py b/plinth/modules/performance/__init__.py
index 9bdb5bd4c..0901ece69 100644
--- a/plinth/modules/performance/__init__.py
+++ b/plinth/modules/performance/__init__.py
@@ -17,10 +17,6 @@ version = 1
name = _('Performance')
-managed_services = [
- 'pmcd.service', 'pmie.service', 'pmlogger.service', 'pmproxy.service'
-]
-
_description = [
_('Performance app allows you to collect, store and view information '
'about utilization of the hardware. This can give you basic insights '
@@ -62,19 +58,19 @@ class PerformanceApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
- daemon_0 = Daemon('daemon-performance-0', managed_services[0],
+ daemon_0 = Daemon('daemon-performance-0', 'pmcd.service',
listen_ports=None)
self.add(daemon_0)
- daemon_1 = Daemon('daemon-performance-1', managed_services[1],
+ daemon_1 = Daemon('daemon-performance-1', 'pmie.service',
listen_ports=None)
self.add(daemon_1)
- daemon_2 = Daemon('daemon-performance-2', managed_services[2],
+ daemon_2 = Daemon('daemon-performance-2', 'pmlogger.service',
listen_ports=None)
self.add(daemon_2)
- daemon_3 = Daemon('daemon-performance-3', managed_services[3],
+ daemon_3 = Daemon('daemon-performance-3', 'pmproxy.service',
listen_ports=None)
self.add(daemon_3)
diff --git a/plinth/modules/privoxy/__init__.py b/plinth/modules/privoxy/__init__.py
index def21d497..ee256a55e 100644
--- a/plinth/modules/privoxy/__init__.py
+++ b/plinth/modules/privoxy/__init__.py
@@ -23,8 +23,6 @@ version = 1
is_essential = False
-managed_services = ['privoxy']
-
_description = [
_('Privoxy is a non-caching web proxy with advanced filtering '
'capabilities for enhancing privacy, modifying web page data and '
@@ -78,7 +76,7 @@ class PrivoxyApp(app_module.App):
is_external=False)
self.add(firewall)
- daemon = Daemon('daemon-privoxy', managed_services[0],
+ daemon = Daemon('daemon-privoxy', 'privoxy',
listen_ports=[(8118, 'tcp4'), (8118, 'tcp6')])
self.add(daemon)
diff --git a/plinth/modules/quassel/__init__.py b/plinth/modules/quassel/__init__.py
index f15f86f56..a7e0c1764 100644
--- a/plinth/modules/quassel/__init__.py
+++ b/plinth/modules/quassel/__init__.py
@@ -24,8 +24,6 @@ from . import manifest
version = 1
-managed_services = ['quasselcore']
-
managed_paths = [pathlib.Path('/var/lib/quassel/')]
_description = [
@@ -85,14 +83,14 @@ class QuasselApp(app_module.App):
letsencrypt = LetsEncrypt(
'letsencrypt-quassel', domains=get_domains,
- daemons=managed_services, should_copy_certificates=True,
+ daemons=['quasselcore'], should_copy_certificates=True,
private_key_path='/var/lib/quassel/quasselCert.pem',
certificate_path='/var/lib/quassel/quasselCert.pem',
user_owner='quasselcore', group_owner='quassel',
managing_app='quassel')
self.add(letsencrypt)
- daemon = Daemon('daemon-quassel', managed_services[0],
+ daemon = Daemon('daemon-quassel', 'quasselcore',
listen_ports=[(4242, 'tcp4'), (4242, 'tcp6')])
self.add(daemon)
diff --git a/plinth/modules/samba/__init__.py b/plinth/modules/samba/__init__.py
index 22f131460..dc31a9608 100644
--- a/plinth/modules/samba/__init__.py
+++ b/plinth/modules/samba/__init__.py
@@ -25,8 +25,6 @@ from . import manifest
version = 2
-managed_services = ['smbd', 'nmbd']
-
_description = [
_('Samba allows to share files and folders between FreedomBox and '
'other computers in your local network.'),
@@ -85,13 +83,12 @@ class SambaApp(app_module.App):
self.add(firewall)
daemon = Daemon(
- 'daemon-samba', managed_services[0], listen_ports=[(139, 'tcp4'),
- (139, 'tcp6'),
- (445, 'tcp4'),
- (445, 'tcp6')])
+ 'daemon-samba', 'smbd', listen_ports=[(139, 'tcp4'), (139, 'tcp6'),
+ (445, 'tcp4'),
+ (445, 'tcp6')])
self.add(daemon)
- daemon_nmbd = Daemon('daemon-samba-nmbd', managed_services[1],
+ daemon_nmbd = Daemon('daemon-samba-nmbd', 'nmbd',
listen_ports=[(137, 'udp4'), (138, 'udp4')])
self.add(daemon_nmbd)
diff --git a/plinth/modules/security/__init__.py b/plinth/modules/security/__init__.py
index 88c1aca8e..ed32c4b95 100644
--- a/plinth/modules/security/__init__.py
+++ b/plinth/modules/security/__init__.py
@@ -12,7 +12,7 @@ from django.utils.translation import gettext_lazy as _
from plinth import actions
from plinth import app as app_module
from plinth import menu, module_loader
-from plinth.daemon import Daemon
+from plinth.daemon import Daemon, RelatedDaemon
from plinth.modules.backups.components import BackupRestore
from plinth.package import Packages
@@ -22,8 +22,6 @@ version = 7
is_essential = True
-managed_services = ['fail2ban']
-
ACCESS_CONF_FILE = '/etc/security/access.d/50freedombox.conf'
ACCESS_CONF_FILE_OLD = '/etc/security/access.conf'
ACCESS_CONF_SNIPPET = '-:ALL EXCEPT root fbx plinth (admin) (sudo):ALL'
@@ -54,6 +52,9 @@ class SecurityApp(app_module.App):
packages = Packages('packages-security', ['fail2ban', 'debsecan'])
self.add(packages)
+ daemon = RelatedDaemon('related-daemon-fail2ban', 'fail2ban')
+ self.add(daemon)
+
backup_restore = BackupRestore('backup-restore-security',
**manifest.backup)
self.add(backup_restore)
diff --git a/plinth/modules/shadowsocks/__init__.py b/plinth/modules/shadowsocks/__init__.py
index af4c2b516..a851cb600 100644
--- a/plinth/modules/shadowsocks/__init__.py
+++ b/plinth/modules/shadowsocks/__init__.py
@@ -19,8 +19,6 @@ from . import manifest
version = 3
-managed_services = ['shadowsocks-libev-local@freedombox']
-
_description = [
_('Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to '
'protect your Internet traffic. It can be used to bypass Internet '
@@ -43,6 +41,8 @@ class ShadowsocksApp(app_module.App):
app_id = 'shadowsocks'
+ DAEMON = 'shadowsocks-libev-local@freedombox'
+
def __init__(self):
"""Create components for the app."""
super().__init__()
@@ -76,7 +76,7 @@ class ShadowsocksApp(app_module.App):
is_external=False)
self.add(firewall)
- daemon = Daemon('daemon-shadowsocks', managed_services[0],
+ daemon = Daemon('daemon-shadowsocks', self.DAEMON,
listen_ports=[(1080, 'tcp4'), (1080, 'tcp6')])
self.add(daemon)
diff --git a/plinth/modules/ssh/__init__.py b/plinth/modules/ssh/__init__.py
index ebe2aa3aa..7b6bcd272 100644
--- a/plinth/modules/ssh/__init__.py
+++ b/plinth/modules/ssh/__init__.py
@@ -23,8 +23,6 @@ version = 1
is_essential = True
-managed_services = ['ssh']
-
_description = [
_('A Secure Shell server uses the secure shell protocol to accept '
'connections from remote computers. An authorized remote computer '
@@ -61,7 +59,7 @@ class SSHApp(app_module.App):
is_external=True)
self.add(firewall)
- daemon = Daemon('daemon-ssh', managed_services[0])
+ daemon = Daemon('daemon-ssh', 'ssh')
self.add(daemon)
backup_restore = BackupRestore('backup-restore-ssh', **manifest.backup)
diff --git a/plinth/modules/syncthing/__init__.py b/plinth/modules/syncthing/__init__.py
index ecacc3a09..de89b2b68 100644
--- a/plinth/modules/syncthing/__init__.py
+++ b/plinth/modules/syncthing/__init__.py
@@ -21,8 +21,6 @@ from . import manifest
version = 5
-managed_services = ['syncthing@syncthing']
-
_description = [
_('Syncthing is an application to synchronize files across multiple '
'devices, e.g. your desktop computer and mobile phone. Creation, '
@@ -49,6 +47,8 @@ class SyncthingApp(app_module.App):
app_id = 'syncthing'
+ DAEMON = 'syncthing@syncthing'
+
def __init__(self):
"""Create components for the app."""
super().__init__()
@@ -94,7 +94,7 @@ class SyncthingApp(app_module.App):
urls=['https://{host}/syncthing/'])
self.add(webserver)
- daemon = Daemon('daemon-syncthing', managed_services[0])
+ daemon = Daemon('daemon-syncthing', self.DAEMON)
self.add(daemon)
users_and_groups = UsersAndGroups('users-and-groups-syncthing',
@@ -110,7 +110,7 @@ def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', actions.superuser_run, 'syncthing', ['setup'])
- add_user_to_share_group(SYSTEM_USER, managed_services[0])
+ add_user_to_share_group(SYSTEM_USER, SyncthingApp.DAEMON)
if not old_version:
helper.call('post', app.enable)
diff --git a/plinth/modules/tahoe/__init__.py b/plinth/modules/tahoe/__init__.py
index ec654780d..98a0e0fcc 100644
--- a/plinth/modules/tahoe/__init__.py
+++ b/plinth/modules/tahoe/__init__.py
@@ -24,8 +24,6 @@ from .errors import TahoeConfigurationError
version = 1
-managed_services = ['tahoe-lafs']
-
_description = [
_('Tahoe-LAFS is a decentralized secure file storage system. '
'It uses provider independent security to store files over a '
@@ -88,7 +86,7 @@ class TahoeApp(app_module.App):
webserver = Webserver('webserver-tahoe', 'tahoe-plinth')
self.add(webserver)
- daemon = Daemon('daemon-tahoe', managed_services[0])
+ daemon = Daemon('daemon-tahoe', 'tahoe-lafs')
self.add(daemon)
backup_restore = BackupRestore('backup-restore-tahoe',
diff --git a/plinth/modules/tor/__init__.py b/plinth/modules/tor/__init__.py
index f9fa4e5bb..3c58bd758 100644
--- a/plinth/modules/tor/__init__.py
+++ b/plinth/modules/tor/__init__.py
@@ -26,8 +26,6 @@ version = 5
depends = ['names']
-managed_services = ['tor@plinth']
-
_description = [
_('Tor is an anonymous communication system. You can learn more '
'about it from the Tor '
@@ -81,7 +79,7 @@ class TorApp(app_module.App):
self.add(firewall)
daemon = Daemon(
- 'daemon-tor', managed_services[0], strict_check=True,
+ 'daemon-tor', 'tor@plinth', strict_check=True,
listen_ports=[(9050, 'tcp4'), (9050, 'tcp6'), (9040, 'tcp4'),
(9040, 'tcp6'), (9053, 'udp4'), (9053, 'udp6')])
self.add(daemon)
diff --git a/plinth/modules/transmission/__init__.py b/plinth/modules/transmission/__init__.py
index 2d6191138..7fc8363aa 100644
--- a/plinth/modules/transmission/__init__.py
+++ b/plinth/modules/transmission/__init__.py
@@ -22,8 +22,6 @@ from . import manifest
version = 4
-managed_services = ['transmission-daemon']
-
_description = [
_('Transmission is a BitTorrent client with a web interface.'),
_('BitTorrent is a peer-to-peer file sharing protocol. '
@@ -41,6 +39,8 @@ class TransmissionApp(app_module.App):
app_id = 'transmission'
+ DAEMON = 'transmission-daemon'
+
def __init__(self):
"""Create components for the app."""
super().__init__()
@@ -83,7 +83,7 @@ class TransmissionApp(app_module.App):
self.add(webserver)
daemon = Daemon(
- 'daemon-transmission', managed_services[0], listen_ports=[
+ 'daemon-transmission', self.DAEMON, listen_ports=[
(9091, 'tcp4'),
(51413, 'tcp4'),
(51413, 'tcp6'),
@@ -115,5 +115,5 @@ def setup(helper, old_version=None):
helper.call('post', actions.superuser_run, 'transmission',
['merge-configuration'],
input=json.dumps(new_configuration).encode())
- add_user_to_share_group(SYSTEM_USER, managed_services[0])
+ add_user_to_share_group(SYSTEM_USER, TransmissionApp.DAEMON)
helper.call('post', app.enable)
diff --git a/plinth/modules/ttrss/__init__.py b/plinth/modules/ttrss/__init__.py
index 0983224d5..6713e44b8 100644
--- a/plinth/modules/ttrss/__init__.py
+++ b/plinth/modules/ttrss/__init__.py
@@ -21,8 +21,6 @@ from . import manifest
version = 3
-managed_services = ['tt-rss']
-
_description = [
_('Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, '
'designed to allow reading news from any location, while feeling as '
@@ -85,7 +83,7 @@ class TTRSSApp(app_module.App):
urls=['https://{host}/tt-rss'])
self.add(webserver)
- daemon = Daemon('daemon-ttrss', managed_services[0])
+ daemon = Daemon('daemon-ttrss', 'tt-rss')
self.add(daemon)
users_and_groups = UsersAndGroups('users-and-groups-ttrss',
diff --git a/plinth/modules/upgrades/__init__.py b/plinth/modules/upgrades/__init__.py
index a8d539833..34c879297 100644
--- a/plinth/modules/upgrades/__init__.py
+++ b/plinth/modules/upgrades/__init__.py
@@ -16,6 +16,7 @@ import plinth
from plinth import actions
from plinth import app as app_module
from plinth import cfg, glib, kvstore, menu
+from plinth.daemon import RelatedDaemon
from plinth.modules.backups.components import BackupRestore
from plinth.package import Packages
@@ -25,8 +26,6 @@ version = 9
is_essential = True
-managed_services = ['freedombox-dist-upgrade']
-
first_boot_steps = [
{
'id': 'backports_wizard',
@@ -87,6 +86,10 @@ class UpgradesApp(app_module.App):
['unattended-upgrades', 'needrestart'])
self.add(packages)
+ daemon = RelatedDaemon('related-daemon-upgrades',
+ 'freedombox-dist-upgrade')
+ self.add(daemon)
+
backup_restore = BackupRestore('backup-restore-upgrades',
**manifest.backup)
self.add(backup_restore)
diff --git a/plinth/modules/users/__init__.py b/plinth/modules/users/__init__.py
index fcba80e57..908cae761 100644
--- a/plinth/modules/users/__init__.py
+++ b/plinth/modules/users/__init__.py
@@ -21,8 +21,6 @@ version = 3
is_essential = True
-managed_services = ['slapd']
-
first_boot_steps = [
{
'id': 'users_firstboot',
@@ -73,8 +71,8 @@ class UsersApp(app_module.App):
])
self.add(packages)
- daemon = Daemon('daemon-users', managed_services[0],
- listen_ports=[(389, 'tcp4'), (389, 'tcp6')])
+ daemon = Daemon('daemon-users', 'slapd', listen_ports=[(389, 'tcp4'),
+ (389, 'tcp6')])
self.add(daemon)
# Add the admin group
diff --git a/plinth/modules/wordpress/__init__.py b/plinth/modules/wordpress/__init__.py
index 5b825a2d5..707d2ec5e 100644
--- a/plinth/modules/wordpress/__init__.py
+++ b/plinth/modules/wordpress/__init__.py
@@ -21,8 +21,6 @@ PUBLIC_ACCESS_FILE = '/etc/wordpress/is_public'
version = 1
-managed_services = ['wordpress-freedombox.timer']
-
_description = [
_('WordPress is a popular way to create and manage websites and blogs. '
'Content can be managed using a visual interface. Layout and '
@@ -102,7 +100,7 @@ class WordPressApp(app_module.App):
urls=['https://{host}/wordpress/'])
self.add(webserver)
- daemon = Daemon('daemon-wordpress', managed_services[0])
+ daemon = Daemon('daemon-wordpress', 'wordpress-freedombox.timer')
self.add(daemon)
backup_restore = WordPressBackupRestore('backup-restore-wordpress',