From e4351b6b97e853827d6232572a1674d87290a515 Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa
Date: Wed, 5 Jun 2019 14:27:09 -0700
Subject: [PATCH] Introduce daemon component to handle systemd units
Signed-off-by: Sunil Mohan Adapa
Reviewed-by: James Valleroy
---
actions/auth-pubtkt | 2 -
actions/cockpit | 12 --
actions/coquelicot | 12 --
actions/deluge | 16 +--
actions/diaspora | 12 --
actions/ejabberd | 13 --
actions/i2p | 15 +--
actions/ikiwiki | 2 -
actions/matrixsynapse | 13 --
actions/mediawiki | 13 --
actions/mldonkey | 14 ---
actions/radicale | 28 ++---
actions/syncthing | 18 +--
actions/tahoe-lafs | 13 --
actions/tor | 17 +--
actions/transmission | 18 +--
actions/ttrss | 16 +--
actions/udiskie | 60 ---------
plinth/__main__.py | 2 +-
plinth/app.py | 11 +-
plinth/daemon.py | 65 ++++++++++
plinth/forms.py | 6 +-
plinth/modules/avahi/__init__.py | 17 ++-
plinth/modules/avahi/urls.py | 7 +-
plinth/modules/backups/__init__.py | 5 +-
plinth/modules/backups/templates/backups.html | 2 +-
.../backups/templates/backups_form.html | 2 +-
.../backups/templates/backups_upload.html | 2 +-
plinth/modules/bind/__init__.py | 29 +----
plinth/modules/bind/forms.py | 4 +-
plinth/modules/bind/urls.py | 6 +-
plinth/modules/bind/views.py | 11 +-
plinth/modules/cockpit/__init__.py | 40 +-----
plinth/modules/cockpit/urls.py | 18 ++-
plinth/modules/coquelicot/__init__.py | 45 +------
plinth/modules/coquelicot/forms.py | 4 +-
plinth/modules/coquelicot/urls.py | 4 +-
plinth/modules/coquelicot/views.py | 8 +-
plinth/modules/datetime/__init__.py | 16 +--
plinth/modules/datetime/forms.py | 12 +-
plinth/modules/datetime/urls.py | 6 +-
plinth/modules/datetime/views.py | 24 ++--
plinth/modules/deluge/__init__.py | 40 ++----
plinth/modules/deluge/urls.py | 13 +-
.../diagnostics/templates/diagnostics.html | 2 +-
plinth/modules/diaspora/__init__.py | 39 +-----
plinth/modules/diaspora/forms.py | 8 +-
.../templates/diaspora-post-setup.html | 2 +-
plinth/modules/diaspora/urls.py | 9 +-
plinth/modules/diaspora/views.py | 23 ++--
.../dynamicdns/templates/dynamicdns.html | 2 +-
.../templates/dynamicdns_configure.html | 2 +-
.../templates/dynamicdns_status.html | 2 +-
plinth/modules/dynamicdns/views.py | 16 +--
plinth/modules/ejabberd/__init__.py | 38 +-----
plinth/modules/ejabberd/forms.py | 24 ++--
.../modules/ejabberd/templates/ejabberd.html | 2 +-
plinth/modules/ejabberd/urls.py | 6 +-
plinth/modules/ejabberd/views.py | 15 ++-
plinth/modules/firewall/components.py | 5 +
.../modules/firewall/templates/firewall.html | 2 +-
plinth/modules/firewall/views.py | 1 -
plinth/modules/i2p/__init__.py | 47 ++-----
plinth/modules/i2p/templates/i2p.html | 8 +-
plinth/modules/i2p/templates/i2p_service.html | 20 ++-
plinth/modules/i2p/urls.py | 5 +-
plinth/modules/i2p/views.py | 8 +-
plinth/modules/ikiwiki/__init__.py | 32 +----
.../ikiwiki/templates/ikiwiki_configure.html | 4 +-
.../ikiwiki/templates/ikiwiki_create.html | 2 +-
.../ikiwiki/templates/ikiwiki_manage.html | 2 +-
plinth/modules/ikiwiki/urls.py | 5 +-
plinth/modules/ikiwiki/views.py | 13 +-
plinth/modules/infinoted/__init__.py | 41 ++----
plinth/modules/infinoted/urls.py | 6 +-
plinth/modules/jsxc/__init__.py | 31 +----
plinth/modules/jsxc/templates/jsxc.html | 2 +-
plinth/modules/jsxc/urls.py | 4 +-
plinth/modules/jsxc/views.py | 11 +-
plinth/modules/letsencrypt/__init__.py | 2 -
.../letsencrypt/templates/letsencrypt.html | 2 +-
plinth/modules/matrixsynapse/__init__.py | 40 +-----
plinth/modules/matrixsynapse/forms.py | 10 +-
.../templates/matrix-synapse.html | 2 +-
plinth/modules/matrixsynapse/urls.py | 5 +-
plinth/modules/matrixsynapse/views.py | 15 ++-
plinth/modules/mediawiki/__init__.py | 41 ++----
plinth/modules/mediawiki/forms.py | 4 +-
.../mediawiki/templates/mediawiki.html | 2 +-
plinth/modules/mediawiki/urls.py | 4 +-
plinth/modules/mediawiki/views.py | 16 ++-
plinth/modules/minetest/__init__.py | 33 ++---
plinth/modules/minetest/forms.py | 24 ++--
.../modules/minetest/templates/minetest.html | 2 +-
plinth/modules/minetest/urls.py | 6 +-
plinth/modules/minetest/views.py | 11 +-
plinth/modules/mldonkey/__init__.py | 46 +------
plinth/modules/mldonkey/urls.py | 13 +-
.../monkeysphere/templates/monkeysphere.html | 2 +-
plinth/modules/mumble/__init__.py | 43 ++-----
plinth/modules/mumble/urls.py | 6 +-
plinth/modules/names/templates/names.html | 2 +-
plinth/modules/openvpn/__init__.py | 35 ++----
plinth/modules/openvpn/templates/openvpn.html | 2 +-
plinth/modules/openvpn/views.py | 12 +-
plinth/modules/pagekite/__init__.py | 7 +-
.../pagekite/templates/pagekite_base.html | 2 +-
plinth/modules/pagekite/utils.py | 87 +++++++------
plinth/modules/pagekite/views.py | 16 +--
plinth/modules/power/templates/power.html | 2 +-
plinth/modules/privoxy/__init__.py | 39 ++----
plinth/modules/privoxy/urls.py | 6 +-
plinth/modules/quassel/__init__.py | 43 ++-----
plinth/modules/quassel/urls.py | 6 +-
plinth/modules/radicale/__init__.py | 77 +++++++-----
plinth/modules/radicale/forms.py | 25 ++--
plinth/modules/radicale/urls.py | 6 +-
plinth/modules/radicale/views.py | 9 +-
plinth/modules/repro/__init__.py | 41 ++----
plinth/modules/repro/urls.py | 6 +-
plinth/modules/restore/__init__.py | 16 ++-
plinth/modules/restore/urls.py | 13 +-
plinth/modules/roundcube/__init__.py | 33 +----
plinth/modules/roundcube/urls.py | 17 ++-
plinth/modules/searx/__init__.py | 41 +-----
plinth/modules/searx/forms.py | 4 +-
plinth/modules/searx/urls.py | 4 +-
plinth/modules/searx/views.py | 25 ++--
.../modules/security/templates/security.html | 2 +-
plinth/modules/shaarli/__init__.py | 33 +----
plinth/modules/shaarli/urls.py | 13 +-
plinth/modules/shadowsocks/__init__.py | 45 +------
plinth/modules/shadowsocks/forms.py | 47 +++----
plinth/modules/shadowsocks/urls.py | 6 +-
plinth/modules/shadowsocks/views.py | 15 ++-
plinth/modules/snapshot/__init__.py | 7 +-
.../modules/snapshot/templates/snapshot.html | 2 +-
.../snapshot/templates/snapshot_manage.html | 2 +-
.../templates/snapshot_not_supported.html | 2 +-
plinth/modules/ssh/__init__.py | 17 ++-
plinth/modules/ssh/urls.py | 6 +-
plinth/modules/storage/__init__.py | 39 +-----
plinth/modules/syncthing/__init__.py | 47 ++-----
plinth/modules/syncthing/urls.py | 9 +-
plinth/modules/tahoe/__init__.py | 48 ++-----
.../tahoe/templates/tahoe-post-setup.html | 2 +-
plinth/modules/tahoe/urls.py | 4 +-
plinth/modules/tahoe/views.py | 7 +-
plinth/modules/tor/__init__.py | 57 ++-------
plinth/modules/tor/templates/tor.html | 4 +-
plinth/modules/tor/utils.py | 68 +++++-----
plinth/modules/tor/views.py | 10 +-
plinth/modules/transmission/__init__.py | 41 +-----
plinth/modules/transmission/forms.py | 4 +-
plinth/modules/transmission/urls.py | 7 +-
plinth/modules/transmission/views.py | 16 +--
plinth/modules/ttrss/__init__.py | 45 ++-----
plinth/modules/ttrss/urls.py | 15 +--
plinth/modules/upgrades/__init__.py | 8 --
.../modules/upgrades/templates/upgrades.html | 2 +-
.../templates/upgrades_configure.html | 2 +-
plinth/modules/upgrades/views.py | 19 +--
plinth/service.py | 103 ---------------
...ce-subsubmenu.html => app-subsubmenu.html} | 2 +-
plinth/templates/{service.html => app.html} | 14 +--
plinth/templates/index.html | 2 +-
plinth/templates/internal-zone.html | 38 +++---
.../{simple_service.html => simple_app.html} | 0
plinth/tests/test_app.py | 25 ++++
plinth/tests/test_daemon.py | 119 ++++++++++++++++++
plinth/views.py | 75 +++++++----
171 files changed, 1073 insertions(+), 1993 deletions(-)
delete mode 100755 actions/udiskie
create mode 100644 plinth/daemon.py
delete mode 100644 plinth/service.py
rename plinth/templates/{service-subsubmenu.html => app-subsubmenu.html} (95%)
rename plinth/templates/{service.html => app.html} (85%)
rename plinth/templates/{simple_service.html => simple_app.html} (100%)
create mode 100644 plinth/tests/test_daemon.py
diff --git a/actions/auth-pubtkt b/actions/auth-pubtkt
index e06415d28..c24492315 100755
--- a/actions/auth-pubtkt
+++ b/actions/auth-pubtkt
@@ -27,8 +27,6 @@ import os
from OpenSSL import crypto
-from plinth import action_utils
-
KEYS_DIRECTORY = '/etc/apache2/auth-pubtkt-keys'
diff --git a/actions/cockpit b/actions/cockpit
index b900eb454..513d33528 100755
--- a/actions/cockpit
+++ b/actions/cockpit
@@ -37,8 +37,6 @@ def parse_arguments():
help='Setup Cockpit configuration')
subparser.add_argument('domain_names', nargs='*',
help='Domain names to be allowed')
- subparsers.add_parser('enable', help='Enable Cockpit')
- subparsers.add_parser('disable', help='Disable Cockpit')
subparser = subparsers.add_parser(
'add-domain',
help='Allow a new domain to be origin for Cockpit\'s WebSocket')
@@ -67,16 +65,6 @@ def subcommand_setup(arguments):
action_utils.service_restart('cockpit.socket')
-def subcommand_enable(_):
- """Enable web configuration and reload."""
- action_utils.service_enable('cockpit.socket')
-
-
-def subcommand_disable(_):
- """Disable web configuration and reload."""
- action_utils.service_disable('cockpit.socket')
-
-
def _get_origin_domains(aug):
"""Return the list of allowed origin domains."""
origins = aug.get('/files' + CONFIG_FILE + '/WebService/Origins')
diff --git a/actions/coquelicot b/actions/coquelicot
index 7f1fca3eb..835d50db8 100755
--- a/actions/coquelicot
+++ b/actions/coquelicot
@@ -39,8 +39,6 @@ def parse_arguments():
subparsers.add_parser('setup',
help='Post-installation operations for coquelicot')
- subparsers.add_parser('enable', help='Enable coquelicot')
- subparsers.add_parser('disable', help='Disable coquelicot')
subparsers.add_parser(
'set-upload-password',
@@ -70,16 +68,6 @@ def subcommand_setup(_):
action_utils.service_restart('coquelicot')
-def subcommand_enable(_):
- """Enable web configuration and reload."""
- action_utils.service_enable('coquelicot')
-
-
-def subcommand_disable(_):
- """Disable web configuration and reload."""
- action_utils.service_disable('coquelicot')
-
-
def subcommand_set_upload_password(arguments):
"""Set a new upload password for Coquelicot."""
upload_password = ''.join(sys.stdin)
diff --git a/actions/deluge b/actions/deluge
index 9b7885d57..b282dc425 100755
--- a/actions/deluge
+++ b/actions/deluge
@@ -52,25 +52,13 @@ def parse_arguments():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
- subparsers.add_parser('enable', help='Enable deluge-web site')
- subparsers.add_parser('disable', help='Disable deluge-web site')
+ subparsers.add_parser('setup', help='Setup deluge')
subparsers.required = True
return parser.parse_args()
-def subcommand_enable(_):
- """Enable deluge-web site and start deluge-web."""
- setup()
- action_utils.service_enable('deluge-web')
-
-
-def subcommand_disable(_):
- """Disable deluge-web site and stop deluge-web."""
- action_utils.service_disable('deluge-web')
-
-
-def setup():
+def subcommand_setup(_):
"""Perform initial setup for deluge-web."""
if not os.path.isfile(SYSTEMD_SERVICE_PATH):
with open(SYSTEMD_SERVICE_PATH, 'w') as file_handle:
diff --git a/actions/diaspora b/actions/diaspora
index 79321735a..4a4795bae 100755
--- a/actions/diaspora
+++ b/actions/diaspora
@@ -38,8 +38,6 @@ def parse_arguments():
'pre-install',
help='Preseed debconf values before packages are installed.')
- subparsers.add_parser('enable', help='Enable diaspora* web server')
- subparsers.add_parser('disable', help='Disable diaspora* web server')
subparsers.add_parser('enable-user-registrations', help='Allow users to' \
'sign up to this diaspora* pod without an invitation.')
subparsers.add_parser('disable-user-registrations', help='Allow only, ' \
@@ -148,16 +146,6 @@ def subcommand_pre_install(_):
subprocess.check_output(['debconf-set-selections'], input=preset)
-def subcommand_enable(_):
- """Enable web configuration and reload."""
- action_utils.service_enable('diaspora')
-
-
-def subcommand_disable(_):
- """Disable web configuration and reload."""
- action_utils.service_disable('diaspora')
-
-
def main():
"""Parse arguments and perform all duties."""
arguments = parse_arguments()
diff --git a/actions/ejabberd b/actions/ejabberd
index e44e2f031..7700206d5 100755
--- a/actions/ejabberd
+++ b/actions/ejabberd
@@ -58,9 +58,6 @@ def parse_arguments():
# Setup ejabberd configuration
subparsers.add_parser('setup', help='Setup ejabberd configuration')
- subparsers.add_parser('enable', help='Enable XMPP service')
- subparsers.add_parser('disable', help='Disable XMPP service')
-
# Prepare ejabberd for hostname change
pre_hostname_change = subparsers.add_parser(
'pre-change-hostname', help='Prepare ejabberd for nodename change')
@@ -162,16 +159,6 @@ def upgrade_config():
ruamel.yaml.round_trip_dump(conf, file_handle)
-def subcommand_enable(_):
- """Enable XMPP service"""
- action_utils.service_enable('ejabberd')
-
-
-def subcommand_disable(_):
- """Disable XMPP service"""
- action_utils.service_disable('ejabberd')
-
-
def subcommand_pre_change_hostname(arguments):
"""Prepare ejabberd for hostname change"""
if not shutil.which('ejabberdctl'):
diff --git a/actions/i2p b/actions/i2p
index f53e87c38..ed5296970 100755
--- a/actions/i2p
+++ b/actions/i2p
@@ -22,7 +22,7 @@ Wrapper to list and handle system services
import argparse
import os
-from plinth import action_utils, cfg
+from plinth import cfg
from plinth.modules.i2p.helpers import RouterEditor, TunnelEditor
cfg.read()
@@ -36,9 +36,6 @@ def parse_arguments():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
- subparsers.add_parser('enable', help='enable i2p service')
- subparsers.add_parser('disable', help='disable i2p service')
-
subparser = subparsers.add_parser(
'add-favorite', help='Add an eepsite to the list of favorites')
subparser.add_argument('--name', help='Name of the entry', required=True)
@@ -58,16 +55,6 @@ def parse_arguments():
return parser.parse_args()
-def subcommand_enable(_):
- """Enable I2P service."""
- action_utils.service_enable('i2p')
-
-
-def subcommand_disable(_):
- """Disable I2P service."""
- action_utils.service_disable('i2p')
-
-
def subcommand_set_tunnel_property(arguments):
"""Modify the configuration file for a certain tunnel."""
editor = TunnelEditor()
diff --git a/actions/ikiwiki b/actions/ikiwiki
index 7fed468da..e753a684f 100755
--- a/actions/ikiwiki
+++ b/actions/ikiwiki
@@ -25,8 +25,6 @@ import shutil
import subprocess
import sys
-from plinth import action_utils
-
SETUP_WIKI = '/etc/ikiwiki/plinth-wiki.setup'
SETUP_BLOG = '/etc/ikiwiki/plinth-blog.setup'
SITE_PATH = '/var/www/ikiwiki'
diff --git a/actions/matrixsynapse b/actions/matrixsynapse
index 3c153cefd..7a689bd61 100755
--- a/actions/matrixsynapse
+++ b/actions/matrixsynapse
@@ -39,8 +39,6 @@ def parse_arguments():
subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
subparsers.add_parser('post-install', help='Perform post install steps')
- subparsers.add_parser('enable', help='Enable matrix-synapse service')
- subparsers.add_parser('disable', help='Disable matrix-synapse service')
help_pubreg = 'Enable/Disable/Status public user registration.'
pubreg = subparsers.add_parser('public-registration', help=help_pubreg)
pubreg.add_argument('command', choices=('enable', 'disable', 'status'),
@@ -166,17 +164,6 @@ def subcommand_setup(arguments):
action_utils.dpkg_reconfigure('matrix-synapse',
{'server-name': domain_name})
_update_tls_certificate()
- subcommand_enable(arguments)
-
-
-def subcommand_enable(_):
- """Enable service."""
- action_utils.service_enable('matrix-synapse')
-
-
-def subcommand_disable(_):
- """Disable service."""
- action_utils.service_disable('matrix-synapse')
def subcommand_public_registration(argument):
diff --git a/actions/mediawiki b/actions/mediawiki
index f4d76f40d..fe2306bf1 100755
--- a/actions/mediawiki
+++ b/actions/mediawiki
@@ -25,7 +25,6 @@ import subprocess
import sys
import tempfile
-from plinth import action_utils
from plinth.utils import generate_password, grep
MAINTENANCE_SCRIPTS_DIR = "/usr/share/mediawiki/maintenance"
@@ -38,8 +37,6 @@ def parse_arguments():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
- subparsers.add_parser('enable', help='Enable MediaWiki')
- subparsers.add_parser('disable', help='Disable MediaWiki')
subparsers.add_parser('setup', help='Setup MediaWiki')
subparsers.add_parser('update', help='Run MediaWiki update script')
@@ -116,16 +113,6 @@ def subcommand_update(_):
subprocess.check_call(['php', update_script])
-def subcommand_enable(_):
- """Enable web configuration and reload."""
- action_utils.service_enable('mediawiki-jobrunner')
-
-
-def subcommand_disable(_):
- """Disable web configuration and reload."""
- action_utils.service_disable('mediawiki-jobrunner')
-
-
def subcommand_public_registrations(arguments):
"""Enable or Disable public registrations for MediaWiki."""
diff --git a/actions/mldonkey b/actions/mldonkey
index 502e8ffb4..942dadeb1 100755
--- a/actions/mldonkey
+++ b/actions/mldonkey
@@ -23,8 +23,6 @@ Configuration helper for mldonkey.
import argparse
import subprocess
-from plinth import action_utils
-
def parse_arguments():
"""Return parsed command line arguments as dictionary."""
@@ -32,8 +30,6 @@ def parse_arguments():
subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
subparsers.add_parser('pre-install', help='Perform pre-install operations')
- subparsers.add_parser('enable', help='Enable mldonkey')
- subparsers.add_parser('disable', help='Disable mldonkey')
subparsers.required = True
return parser.parse_args()
@@ -46,16 +42,6 @@ def subcommand_pre_install(_):
], input=b'mldonkey-server mldonkey-server/launch_at_startup boolean true')
-def subcommand_enable(_):
- """Enable web configuration and reload."""
- action_utils.service_enable('mldonkey-server')
-
-
-def subcommand_disable(_):
- """Disable web configuration and reload."""
- action_utils.service_disable('mldonkey-server')
-
-
def main():
"""Parse arguments and perform all duties."""
arguments = parse_arguments()
diff --git a/actions/radicale b/actions/radicale
index 0fc97e689..f92c6f5fc 100755
--- a/actions/radicale
+++ b/actions/radicale
@@ -44,8 +44,8 @@ def parse_arguments():
subparsers.add_parser('setup', help='Setup Radicale configuration')
subparsers.add_parser('migrate', help='Migrate config to radicale 2.x')
- subparsers.add_parser('enable', help='Enable Radicale service')
- subparsers.add_parser('disable', help='Disable Radicale service')
+ subparsers.add_parser('fix-collections',
+ help='Ensure collections path exists')
configure = subparsers.add_parser('configure',
help='Configure various options')
configure.add_argument('--rights_type',
@@ -77,8 +77,6 @@ def subcommand_setup(_):
aug.save()
- subcommand_enable(None)
-
def subcommand_migrate(_):
"""Migrate from radicale 1.x to 2.x."""
@@ -121,23 +119,11 @@ def subcommand_configure(arguments):
action_utils.service_try_restart('radicale')
-def subcommand_enable(_):
- """Start service."""
- if radicale.get_package_version() >= radicale.VERSION_2:
- # Workaround for bug in radicale's uwsgi script (#919339)
- if not os.path.exists(COLLECTIONS_PATH):
- os.makedirs(COLLECTIONS_PATH)
- action_utils.service_disable('radicale')
- else:
- action_utils.service_enable('radicale')
- action_utils.service_restart('radicale')
-
-
-def subcommand_disable(_):
- """Stop service."""
- package_version = radicale.get_package_version()
- if package_version and package_version < radicale.VERSION_2:
- action_utils.service_disable('radicale')
+def subcommand_fix_collections(_):
+ """Fix collections path to work around a bug."""
+ # Workaround for bug in radicale's uwsgi script (#919339)
+ if not os.path.exists(COLLECTIONS_PATH):
+ os.makedirs(COLLECTIONS_PATH)
def load_augeas():
diff --git a/actions/syncthing b/actions/syncthing
index f113e6e8a..6fcfdbd24 100755
--- a/actions/syncthing
+++ b/actions/syncthing
@@ -26,22 +26,19 @@ import pwd
import shutil
import subprocess
-from plinth import action_utils
-
def parse_arguments():
"""Return parsed command line arguments as dictionary."""
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
- subparsers.add_parser('enable', help='Enable Syncthing')
- subparsers.add_parser('disable', help='Disable Syncthing')
+ subparsers.add_parser('setup', help='Setup Syncthing')
subparsers.required = True
return parser.parse_args()
-def setup():
+def subcommand_setup(_):
"""Actions to be performed before installing Syncthing"""
data_dir = '/var/lib/syncthing'
@@ -66,17 +63,6 @@ def setup():
shutil.chown(data_dir, user='syncthing', group='syncthing')
-def subcommand_enable(_):
- """Enable web configuration and reload."""
- setup()
- action_utils.service_enable('syncthing@syncthing')
-
-
-def subcommand_disable(_):
- """Disable web configuration and reload."""
- action_utils.service_disable('syncthing@syncthing')
-
-
def main():
"""Parse arguments and perform all duties."""
arguments = parse_arguments()
diff --git a/actions/tahoe-lafs b/actions/tahoe-lafs
index 829072eeb..5630d05a0 100755
--- a/actions/tahoe-lafs
+++ b/actions/tahoe-lafs
@@ -30,7 +30,6 @@ import subprocess
import augeas
import ruamel.yaml
-from plinth import action_utils
from plinth.modules.tahoe import (introducer_furl_file, introducer_name,
introducers_file, storage_node_name,
tahoe_home)
@@ -47,8 +46,6 @@ def parse_arguments():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
- subparsers.add_parser('enable', help='Enable Tahoe-LAFS')
- subparsers.add_parser('disable', help='Disable Tahoe-LAFS')
setup = subparsers.add_parser('setup',
help='Set domain name for Tahoe-LAFS')
setup.add_argument('--domain-name',
@@ -224,16 +221,6 @@ def subcommand_get_local_introducer(_):
print(json.dumps((introducer_name, furl)))
-def subcommand_enable(_):
- """Enable web configuration and reload."""
- action_utils.service_enable('tahoe-lafs')
-
-
-def subcommand_disable(_):
- """Disable web configuration and reload."""
- action_utils.service_disable('tahoe-lafs')
-
-
def restart_storage_node():
"""Called after exiting context of editing introducers file."""
try:
diff --git a/actions/tor b/actions/tor
index b03b71b62..96ec812a0 100755
--- a/actions/tor
+++ b/actions/tor
@@ -20,19 +20,19 @@ Configuration helper for the Tor service
"""
import argparse
-import augeas
import codecs
import json
import os
import re
import socket
-import time
import subprocess
+import time
+
+import augeas
from plinth import action_utils
-from plinth.modules.tor.utils import get_real_apt_uri_path, iter_apt_uris, \
- get_augeas, is_running, is_enabled, \
- APT_TOR_PREFIX
+from plinth.modules.tor.utils import (APT_TOR_PREFIX, get_augeas,
+ get_real_apt_uri_path, iter_apt_uris)
SERVICE_FILE = '/etc/firewalld/services/tor-{0}.xml'
TOR_CONFIG = '/files/etc/tor/instances/plinth/torrc'
@@ -212,7 +212,8 @@ def subcommand_configure(arguments):
def subcommand_restart(_):
"""Restart Tor."""
- if is_enabled() and is_running():
+ if (action_utils.service_is_enabled('tor@plinth', strict_check=True)
+ and action_utils.service_is_running('tor@plinth')):
action_utils.service_restart('tor@plinth')
aug = augeas_load()
@@ -527,8 +528,8 @@ def _update_ports():
def augeas_load():
"""Initialize Augeas."""
- aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
- augeas.Augeas.NO_MODL_AUTOLOAD)
+ aug = augeas.Augeas(
+ flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD)
aug.set('/augeas/load/Tor/lens', 'Tor.lns')
aug.set('/augeas/load/Tor/incl[last() + 1]',
'/etc/tor/instances/plinth/torrc')
diff --git a/actions/transmission b/actions/transmission
index 6445aa036..fa6418d68 100755
--- a/actions/transmission
+++ b/actions/transmission
@@ -15,7 +15,6 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
Configuration helper for Transmission daemon.
"""
@@ -26,7 +25,6 @@ import sys
from plinth import action_utils
-
TRANSMISSION_CONFIG = '/etc/transmission-daemon/settings.json'
@@ -35,10 +33,8 @@ def parse_arguments():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
- subparsers.add_parser('enable', help='Enable Transmission service')
- subparsers.add_parser('disable', help='Disable Transmission service')
- subparsers.add_parser(
- 'get-configuration', help='Return the current configuration')
+ subparsers.add_parser('get-configuration',
+ help='Return the current configuration')
subparsers.add_parser(
'merge-configuration',
help='Merge JSON configuration from stdin with existing')
@@ -47,16 +43,6 @@ def parse_arguments():
return parser.parse_args()
-def subcommand_enable(_):
- """Start Transmission service."""
- action_utils.service_enable('transmission-daemon')
-
-
-def subcommand_disable(_):
- """Stop Transmission service."""
- action_utils.service_disable('transmission-daemon')
-
-
def subcommand_get_configuration(_):
"""Return the current configuration in JSON format."""
configuration = open(TRANSMISSION_CONFIG, 'r').read()
diff --git a/actions/ttrss b/actions/ttrss
index d519f565a..012f662e6 100755
--- a/actions/ttrss
+++ b/actions/ttrss
@@ -40,8 +40,7 @@ def parse_arguments():
subparsers.add_parser('pre-setup', help='Perform pre-setup operations')
subparsers.add_parser('setup', help='Setup Tiny Tiny RSS configuration')
- subparsers.add_parser('enable', help='Enable Tiny Tiny RSS site')
- subparsers.add_parser('disable', help='Disable Tiny Tiny RSS site')
+ subparsers.add_parser('enable-api-access', help='Enable Tiny Tiny RSS API')
subparsers.add_parser('dump-database', help='Dump database to file')
subparsers.add_parser('restore-database',
help='Restore database from file')
@@ -84,7 +83,7 @@ def subcommand_setup(_):
action_utils.service_restart('tt-rss')
-def enable_api_access():
+def subcommand_enable_api_access(_):
"""Enable API access so that tt-rss can be accessed through mobile app."""
import psycopg2 # Only available post installation
@@ -111,17 +110,6 @@ def enable_api_access():
connection.close()
-def subcommand_enable(_):
- """Enable web configuration and reload."""
- action_utils.service_enable('tt-rss')
- enable_api_access()
-
-
-def subcommand_disable(_):
- """Disable web configuration and reload."""
- action_utils.service_disable('tt-rss')
-
-
def subcommand_dump_database(_):
"""Dump database to file."""
os.makedirs(os.path.dirname(DB_BACKUP_FILE), exist_ok=True)
diff --git a/actions/udiskie b/actions/udiskie
deleted file mode 100755
index 2b249a163..000000000
--- a/actions/udiskie
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/usr/bin/python3
-# -*- mode: python -*-
-#
-# This file is part of FreedomBox.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-"""
-Configuration helper for udiskie.
-"""
-
-import argparse
-
-from plinth import action_utils
-
-
-def parse_arguments():
- """Return parsed command line arguments as dictionary."""
- parser = argparse.ArgumentParser()
- subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
-
- subparsers.add_parser('enable', help='Enable udiskie')
- subparsers.add_parser('disable', help='Disable udiskie')
-
- subparsers.required = True
- return parser.parse_args()
-
-
-def subcommand_enable(_):
- """Enable web configuration and reload."""
- action_utils.service_enable('freedombox-udiskie')
-
-
-def subcommand_disable(_):
- """Disable web configuration and reload."""
- action_utils.service_disable('freedombox-udiskie')
-
-
-def main():
- """Parse arguments and perform all duties."""
- arguments = parse_arguments()
-
- subcommand = arguments.subcommand.replace('-', '_')
- subcommand_method = globals()['subcommand_' + subcommand]
- subcommand_method(arguments)
-
-
-if __name__ == '__main__':
- main()
diff --git a/plinth/__main__.py b/plinth/__main__.py
index bd65554ff..39392fcb5 100644
--- a/plinth/__main__.py
+++ b/plinth/__main__.py
@@ -24,7 +24,7 @@ import sys
import axes
from . import (__version__, cfg, dbus, frontpage, log, menu, module_loader,
- service, setup, web_framework, web_server)
+ setup, web_framework, web_server)
axes.default_app_config = "plinth.axes_app_config.AppConfig"
precedence_commandline_arguments = ["server_dir", "develop"]
diff --git a/plinth/app.py b/plinth/app.py
index e17a65d2e..60411a980 100644
--- a/plinth/app.py
+++ b/plinth/app.py
@@ -64,6 +64,12 @@ class App:
"""Return a component given the component's ID."""
return self.components[component_id]
+ def get_components_of_type(self, component_type):
+ """Return all components of a given type."""
+ for component in self.components.values():
+ if isinstance(component, component_type):
+ yield component
+
def enable(self):
"""Enable all the components of the app."""
for component in self.components.values():
@@ -75,7 +81,10 @@ class App:
component.disable()
def is_enabled(self):
- """Return whether all the leader components are enabled."""
+ """Return whether all the leader components are enabled.
+
+ Return True when there are no leader components.
+ """
return all((component.is_enabled()
for component in self.components.values()
if component.is_leader))
diff --git a/plinth/daemon.py b/plinth/daemon.py
new file mode 100644
index 000000000..604502d64
--- /dev/null
+++ b/plinth/daemon.py
@@ -0,0 +1,65 @@
+#
+# This file is part of FreedomBox.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+"""
+Component for managing a background daemon or any systemd unit.
+"""
+
+from plinth import action_utils, actions, app
+
+
+class Daemon(app.LeaderComponent):
+ """Component to manage a background daemon or any systemd unit."""
+
+ def __init__(self, component_id, unit, strict_check=False):
+ """Initialize a new daemon component.
+
+ 'component_id' must be a unique string across all apps and components
+ of a app. Conventionally starts with 'daemon-'.
+
+ 'unit' must the name of systemd unit that this component should manage.
+
+ """
+ super().__init__(component_id)
+
+ self.unit = unit
+ self.strict_check = strict_check
+
+ def is_enabled(self):
+ """Return if the daemon/unit is enabled."""
+ return action_utils.service_is_enabled(self.unit,
+ strict_check=self.strict_check)
+
+ def enable(self):
+ """Run operations to enable the daemon/unit."""
+ actions.superuser_run('service', ['enable', self.unit])
+
+ def disable(self):
+ """Run operations to disable the daemon/unit."""
+ actions.superuser_run('service', ['disable', self.unit])
+
+ def is_running(self):
+ """Return whether the daemon/unit is running."""
+ return action_utils.service_is_running(self.unit)
+
+
+def app_is_running(app_):
+ """Return whether all the daemons in the app are running."""
+ for component in app_.components.values():
+ if hasattr(component, 'is_running') and not component.is_running():
+ return False
+
+ return True
diff --git a/plinth/forms.py b/plinth/forms.py
index a315b331f..af56214ea 100644
--- a/plinth/forms.py
+++ b/plinth/forms.py
@@ -26,15 +26,15 @@ from django.conf import settings
from django.forms import CheckboxInput
from django.utils import translation
from django.utils.safestring import mark_safe
-from django.utils.translation import ugettext_lazy as _
from django.utils.translation import get_language_info
+from django.utils.translation import ugettext_lazy as _
import plinth
from plinth import utils
-class ServiceForm(forms.Form):
- """Generic configuration form for a service."""
+class AppForm(forms.Form):
+ """Generic configuration form for an app."""
is_enabled = forms.BooleanField(
label=_('Enable application'), required=False)
diff --git a/plinth/modules/avahi/__init__.py b/plinth/modules/avahi/__init__.py
index e20177a96..d01bc6a2f 100644
--- a/plinth/modules/avahi/__init__.py
+++ b/plinth/modules/avahi/__init__.py
@@ -23,10 +23,10 @@ from django.utils.translation import ugettext_lazy as _
from plinth import actions
from plinth import app as app_module
from plinth import cfg, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.firewall.components import Firewall
from plinth.utils import format_lazy
-from plinth.views import ServiceView
+from plinth.views import AppView
from .manifest import backup
@@ -53,8 +53,6 @@ description = [
'hostile local network.'), box_name=_(cfg.box_name))
]
-service = None
-
manual_page = 'ServiceDiscovery'
app = None
@@ -76,6 +74,9 @@ class AvahiApp(app_module.App):
is_external=False)
self.add(firewall)
+ daemon = Daemon('daemon-avahi', managed_services[0])
+ self.add(daemon)
+
def init():
"""Intialize the service discovery module."""
@@ -83,9 +84,6 @@ def init():
app = AvahiApp()
app.set_enabled(True)
- global service # pylint: disable=W0603
- service = service_module.Service(managed_services[0], name)
-
def setup(helper, old_version=None):
"""Install and configure the module."""
@@ -97,7 +95,8 @@ def setup(helper, old_version=None):
['reload', 'avahi-daemon'])
-class AvahiServiceView(ServiceView):
- service_id = managed_services[0]
+class AvahiAppView(AppView):
+ app_id = 'avahi'
+ name = name
description = description
manual_page = manual_page
diff --git a/plinth/modules/avahi/urls.py b/plinth/modules/avahi/urls.py
index 4f35c7574..685d49446 100644
--- a/plinth/modules/avahi/urls.py
+++ b/plinth/modules/avahi/urls.py
@@ -14,17 +14,14 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
URLs for the service discovery module.
"""
from django.conf.urls import url
-from plinth.modules.avahi import AvahiServiceView
-
+from plinth.modules.avahi import AvahiAppView
urlpatterns = [
- url(r'^sys/avahi/$', AvahiServiceView.as_view(),
- name='index'),
+ url(r'^sys/avahi/$', AvahiAppView.as_view(), name='index'),
]
diff --git a/plinth/modules/backups/__init__.py b/plinth/modules/backups/__init__.py
index 2d32de583..fb10323a0 100644
--- a/plinth/modules/backups/__init__.py
+++ b/plinth/modules/backups/__init__.py
@@ -41,8 +41,6 @@ description = [
_('Backups allows creating and managing backup archives.'),
]
-service = None
-
manual_page = 'Backups'
MANIFESTS_FOLDER = '/var/lib/plinth/backups-manifests/'
@@ -74,9 +72,8 @@ def init():
global app
app = BackupsApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
app.set_enabled(True)
diff --git a/plinth/modules/backups/templates/backups.html b/plinth/modules/backups/templates/backups.html
index 0472214e0..27cfc1233 100644
--- a/plinth/modules/backups/templates/backups.html
+++ b/plinth/modules/backups/templates/backups.html
@@ -1,4 +1,4 @@
-{% extends "service-subsubmenu.html" %}
+{% extends "app-subsubmenu.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/backups/templates/backups_form.html b/plinth/modules/backups/templates/backups_form.html
index 386d69534..9d466d606 100644
--- a/plinth/modules/backups/templates/backups_form.html
+++ b/plinth/modules/backups/templates/backups_form.html
@@ -1,4 +1,4 @@
-{% extends "service-subsubmenu.html" %}
+{% extends "app-subsubmenu.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/backups/templates/backups_upload.html b/plinth/modules/backups/templates/backups_upload.html
index 0623caf99..319bdd964 100644
--- a/plinth/modules/backups/templates/backups_upload.html
+++ b/plinth/modules/backups/templates/backups_upload.html
@@ -1,4 +1,4 @@
-{% extends "service-subsubmenu.html" %}
+{% extends "app-subsubmenu.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/bind/__init__.py b/plinth/modules/bind/__init__.py
index 02bc421cd..8b76ccb98 100644
--- a/plinth/modules/bind/__init__.py
+++ b/plinth/modules/bind/__init__.py
@@ -25,7 +25,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import cfg, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.firewall.components import Firewall
from plinth.utils import format_lazy
@@ -37,8 +37,6 @@ name = _('BIND')
short_description = _('Domain Name Server')
-service = None
-
managed_services = ['bind9']
managed_packages = ['bind9']
@@ -104,26 +102,23 @@ class BindApp(app_module.App):
is_external=False)
self.add(firewall)
+ daemon = Daemon('daemon-bind', managed_services[0])
+ self.add(daemon)
+
def init():
"""Intialize the BIND module."""
global app
app = BindApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(managed_services[0], name)
- app.set_enabled(True) # XXX: Perform better check
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.install(managed_packages)
- global service
- if service is None:
- service = service_module.Service(managed_services[0], name,
- enable=enable, disable=disable)
helper.call('post', actions.superuser_run, 'bind', ['setup'])
helper.call('post', app.enable)
@@ -133,18 +128,6 @@ def force_upgrade(helper, _packages):
helper.install(managed_packages, force_configuration='old')
-def enable():
- """Enable the module."""
- actions.superuser_run('service', ['enable', managed_services[0]])
- app.enable()
-
-
-def disable():
- """Disable the module."""
- actions.superuser_run('service', ['disable', managed_services[0]])
- app.disable()
-
-
def diagnose():
"""Run diagnostics and return the results."""
results = []
diff --git a/plinth/modules/bind/forms.py b/plinth/modules/bind/forms.py
index e6924cd39..955ed4db3 100644
--- a/plinth/modules/bind/forms.py
+++ b/plinth/modules/bind/forms.py
@@ -22,7 +22,7 @@ from django import forms
from django.core.validators import validate_ipv46_address
from django.utils.translation import ugettext_lazy as _
-from plinth.forms import ServiceForm
+from plinth.forms import AppForm
def validate_ips(ips):
@@ -31,7 +31,7 @@ def validate_ips(ips):
validate_ipv46_address(ip_addr)
-class BindForm(ServiceForm):
+class BindForm(AppForm):
"""BIND configuration form"""
forwarders = forms.CharField(
label=_('Forwarders'), required=False, validators=[validate_ips],
diff --git a/plinth/modules/bind/urls.py b/plinth/modules/bind/urls.py
index 14489b6f8..b679873ac 100644
--- a/plinth/modules/bind/urls.py
+++ b/plinth/modules/bind/urls.py
@@ -20,6 +20,8 @@ URLs for the BIND module.
from django.conf.urls import url
-from plinth.modules.bind.views import BindServiceView
+from plinth.modules.bind.views import BindAppView
-urlpatterns = [url(r'^sys/bind/$', BindServiceView.as_view(), name='index'), ]
+urlpatterns = [
+ url(r'^sys/bind/$', BindAppView.as_view(), name='index'),
+]
diff --git a/plinth/modules/bind/views.py b/plinth/modules/bind/views.py
index 5dfbeafcd..e394b396a 100644
--- a/plinth/modules/bind/views.py
+++ b/plinth/modules/bind/views.py
@@ -22,16 +22,17 @@ from django.contrib import messages
from django.utils.translation import ugettext_lazy as _
from plinth import actions
-from plinth.views import ServiceView
+from plinth.views import AppView
-from . import description, get_config, managed_services, port_forwarding_info
+from . import description, get_config, name, port_forwarding_info
from .forms import BindForm
-class BindServiceView(ServiceView): # pylint: disable=too-many-ancestors
+class BindAppView(AppView): # pylint: disable=too-many-ancestors
"""A specialized view for configuring Bind."""
- service_id = managed_services[0]
- diagnostics_module_name = "bind"
+ app_id = 'bind'
+ diagnostics_module_name = 'bind'
+ name = name
description = description
show_status_block = True
form_class = BindForm
diff --git a/plinth/modules/cockpit/__init__.py b/plinth/modules/cockpit/__init__.py
index e99e801a9..7bd47a4a4 100644
--- a/plinth/modules/cockpit/__init__.py
+++ b/plinth/modules/cockpit/__init__.py
@@ -24,7 +24,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import cfg, frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules import names
from plinth.modules.apache.components import Webserver
from plinth.modules.firewall.components import Firewall
@@ -58,8 +58,6 @@ description = [
users_url=reverse_lazy('users:index')),
]
-service = None
-
manual_page = 'Cockpit'
app = None
@@ -91,21 +89,18 @@ class CockpitApp(app_module.App):
webserver = Webserver('webserver-cockpit', 'cockpit-freedombox')
self.add(webserver)
+ daemon = Daemon('daemon-cockpit', managed_services[0])
+ self.add(daemon)
+
def init():
"""Intialize the module."""
global app
app = CockpitApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(managed_services[0], name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
-
- if is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
domain_added.connect(on_domain_added)
domain_removed.connect(on_domain_removed)
@@ -120,32 +115,9 @@ def setup(helper, old_version=None):
for domain in domains_of_a_type
]
helper.call('post', actions.superuser_run, 'cockpit', ['setup'] + domains)
- global service
- if service is None:
- service = service_module.Service(managed_services[0], name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
helper.call('post', app.enable)
-def is_enabled():
- """Return whether the module is enabled."""
- return (app.is_enabled()
- and action_utils.service_is_running('cockpit.socket'))
-
-
-def enable():
- """Enable the module."""
- actions.superuser_run('cockpit', ['enable'])
- app.enable()
-
-
-def disable():
- """Disable the module."""
- actions.superuser_run('cockpit', ['disable'])
- app.disable()
-
-
def diagnose():
"""Run diagnostics and return the results."""
results = []
diff --git a/plinth/modules/cockpit/urls.py b/plinth/modules/cockpit/urls.py
index 0cdea5e49..2abb14456 100644
--- a/plinth/modules/cockpit/urls.py
+++ b/plinth/modules/cockpit/urls.py
@@ -20,17 +20,15 @@ URLs for Cockpit module.
from django.conf.urls import url
-from plinth.views import ServiceView
from plinth.modules import cockpit
+from plinth.views import AppView
urlpatterns = [
- url(r'^sys/cockpit/$',
- ServiceView.as_view(
- service_id=cockpit.managed_services[0],
- diagnostics_module_name='cockpit',
- description=cockpit.description,
- show_status_block=True,
- clients=cockpit.clients,
- manual_page=cockpit.manual_page),
- name='index'),
+ url(
+ r'^sys/cockpit/$',
+ AppView.as_view(app_id='cockpit', name=cockpit.name,
+ diagnostics_module_name='cockpit',
+ description=cockpit.description,
+ show_status_block=True, clients=cockpit.clients,
+ manual_page=cockpit.manual_page), name='index'),
]
diff --git a/plinth/modules/coquelicot/__init__.py b/plinth/modules/coquelicot/__init__.py
index d3d3eb9ce..1db51146d 100644
--- a/plinth/modules/coquelicot/__init__.py
+++ b/plinth/modules/coquelicot/__init__.py
@@ -23,7 +23,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.apache.components import Webserver
from plinth.modules.firewall.components import Firewall
@@ -51,8 +51,6 @@ description = [
'The default upload password is "test".')
]
-service = None
-
manual_page = 'Coquelicot'
app = None
@@ -84,58 +82,27 @@ class CoquelicotApp(app_module.App):
webserver = Webserver('webserver-coquelicot', 'coquelicot-freedombox')
self.add(webserver)
+ daemon = Daemon('daemon-coquelicot', managed_services[0])
+ self.add(daemon)
+
def init():
"""Intialize the module."""
global app
app = CoquelicotApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(
- managed_services[0], name, is_enabled=is_enabled, enable=enable,
- disable=disable, is_running=is_running)
-
- if is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.install(managed_packages)
helper.call('post', actions.superuser_run, 'coquelicot', ['setup'])
- helper.call('post', actions.superuser_run, 'coquelicot', ['enable'])
- global service
- if service is None:
- service = service_module.Service(
- managed_services[0], name, is_enabled=is_enabled, enable=enable,
- disable=disable, is_running=is_running)
helper.call('post', app.enable)
-def is_running():
- """Return whether the service is running."""
- return action_utils.service_is_running('coquelicot')
-
-
-def is_enabled():
- """Return whether the module is enabled."""
- return (action_utils.service_is_enabled('coquelicot') and app.is_enabled())
-
-
-def enable():
- """Enable the module."""
- actions.superuser_run('coquelicot', ['enable'])
- app.enable()
-
-
-def disable():
- """Disable the module."""
- actions.superuser_run('coquelicot', ['disable'])
- app.disable()
-
-
def get_current_max_file_size():
"""Get the current value of maximum file size."""
size = actions.superuser_run('coquelicot', ['get-max-file-size'])
diff --git a/plinth/modules/coquelicot/forms.py b/plinth/modules/coquelicot/forms.py
index f1b610e0c..5a0db44ca 100644
--- a/plinth/modules/coquelicot/forms.py
+++ b/plinth/modules/coquelicot/forms.py
@@ -21,10 +21,10 @@ Plinth form for configuring Coquelicot.
from django import forms
from django.utils.translation import ugettext_lazy as _
-from plinth.forms import ServiceForm
+from plinth.forms import AppForm
-class CoquelicotForm(ServiceForm): # pylint: disable=W0232
+class CoquelicotForm(AppForm): # pylint: disable=W0232
"""Coquelicot configuration form."""
upload_password = forms.CharField(
label=_('Upload Password'),
diff --git a/plinth/modules/coquelicot/urls.py b/plinth/modules/coquelicot/urls.py
index 020d092cb..fbb78b8eb 100644
--- a/plinth/modules/coquelicot/urls.py
+++ b/plinth/modules/coquelicot/urls.py
@@ -20,8 +20,8 @@ URLs for the coquelicot module.
from django.conf.urls import url
-from .views import CoquelicotServiceView
+from .views import CoquelicotAppView
urlpatterns = [
- url(r'^apps/coquelicot/$', CoquelicotServiceView.as_view(), name='index'),
+ url(r'^apps/coquelicot/$', CoquelicotAppView.as_view(), name='index'),
]
diff --git a/plinth/modules/coquelicot/views.py b/plinth/modules/coquelicot/views.py
index 9fdb9e737..4eaa91e6b 100644
--- a/plinth/modules/coquelicot/views.py
+++ b/plinth/modules/coquelicot/views.py
@@ -24,17 +24,19 @@ from django.utils.translation import ugettext as _
from plinth import actions, views
from plinth.errors import ActionError
from plinth.modules.coquelicot import (clients, description,
- get_current_max_file_size, manual_page)
+ get_current_max_file_size, manual_page,
+ name)
from .forms import CoquelicotForm
-class CoquelicotServiceView(views.ServiceView):
+class CoquelicotAppView(views.AppView):
"""Serve configuration page."""
clients = clients
+ name = name
description = description
diagnostics_module_name = 'coquelicot'
- service_id = 'coquelicot'
+ app_id = 'coquelicot'
form_class = CoquelicotForm
show_status_block = True
manual_page = manual_page
diff --git a/plinth/modules/datetime/__init__.py b/plinth/modules/datetime/__init__.py
index 6b8c6f208..a6f5974e4 100644
--- a/plinth/modules/datetime/__init__.py
+++ b/plinth/modules/datetime/__init__.py
@@ -24,7 +24,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import app as app_module
from plinth import menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from .manifest import backup
@@ -45,8 +45,6 @@ description = [
manual_page = 'DateTime'
-service = None
-
app = None
@@ -62,6 +60,9 @@ class DateTimeApp(app_module.App):
'datetime:index', parent_url_name='system')
self.add(menu_item)
+ daemon = Daemon('daemon-datetime', managed_services[0])
+ self.add(daemon)
+
def init():
"""Intialize the date/time module."""
@@ -69,18 +70,9 @@ def init():
app = DateTimeApp()
app.set_enabled(True)
- global service
- setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(managed_services[0], name)
-
def setup(helper, old_version=None):
"""Install and configure the module."""
- global service
- if service is None:
- service = service_module.Service(managed_services[0], name)
- service.enable()
helper.call('post', app.enable)
diff --git a/plinth/modules/datetime/forms.py b/plinth/modules/datetime/forms.py
index 365b6cc94..654f2a4c5 100644
--- a/plinth/modules/datetime/forms.py
+++ b/plinth/modules/datetime/forms.py
@@ -14,23 +14,22 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
Forms for configuring date and time
"""
-from django import forms
-from django.utils.translation import ugettext_lazy as _
import logging
import subprocess
-from plinth.forms import ServiceForm
+from django import forms
+from django.utils.translation import ugettext_lazy as _
+from plinth.forms import AppForm
logger = logging.getLogger(__name__)
-class DateTimeForm(ServiceForm):
+class DateTimeForm(AppForm):
"""Date/time configuration form."""
time_zone = forms.ChoiceField(
label=_('Time Zone'),
@@ -41,8 +40,7 @@ class DateTimeForm(ServiceForm):
"""Initialize the date/time form."""
forms.Form.__init__(self, *args, **kwargs)
- time_zone_options = [(zone, zone)
- for zone in self.get_time_zones()]
+ time_zone_options = [(zone, zone) for zone in self.get_time_zones()]
# Show not-set option only when time zone is not set
current_time_zone = self.initial.get('time_zone')
if current_time_zone == 'none':
diff --git a/plinth/modules/datetime/urls.py b/plinth/modules/datetime/urls.py
index d0f732580..2ca059443 100644
--- a/plinth/modules/datetime/urls.py
+++ b/plinth/modules/datetime/urls.py
@@ -14,16 +14,14 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
URLs for the date and time module
"""
from django.conf.urls import url
-from .views import DateTimeServiceView
-
+from .views import DateTimeAppView
urlpatterns = [
- url(r'^sys/datetime/$', DateTimeServiceView.as_view(), name='index'),
+ url(r'^sys/datetime/$', DateTimeAppView.as_view(), name='index'),
]
diff --git a/plinth/modules/datetime/views.py b/plinth/modules/datetime/views.py
index e00093d43..a51906bed 100644
--- a/plinth/modules/datetime/views.py
+++ b/plinth/modules/datetime/views.py
@@ -25,26 +25,25 @@ from django.utils.translation import ugettext as _
from plinth import actions
from plinth.modules import datetime
-from plinth.views import ServiceView
+from plinth.views import AppView
from .forms import DateTimeForm
logger = logging.getLogger(__name__)
-class DateTimeServiceView(ServiceView):
+class DateTimeAppView(AppView):
+ name = datetime.name
description = datetime.description
form_class = DateTimeForm
- service_id = datetime.managed_services[0]
- diagnostics_module_name = "datetime"
+ app_id = 'datetime'
+ diagnostics_module_name = 'datetime'
manual_page = datetime.manual_page
def get_initial(self):
- return {
- 'is_enabled': self.service.is_enabled(),
- 'is_running': self.service.is_running(),
- 'time_zone': self.get_current_time_zone()
- }
+ status = super().get_initial()
+ status['time_zone'] = self.get_current_time_zone()
+ return status
def get_current_time_zone(self):
"""Get current time zone."""
@@ -61,9 +60,10 @@ class DateTimeServiceView(ServiceView):
actions.superuser_run('timezone-change',
[new_status['time_zone']])
except Exception as exception:
- messages.error(self.request,
- _('Error setting time zone: {exception}')
- .format(exception=exception))
+ messages.error(
+ self.request,
+ _('Error setting time zone: {exception}').format(
+ exception=exception))
else:
messages.success(self.request, _('Time zone set'))
diff --git a/plinth/modules/deluge/__init__.py b/plinth/modules/deluge/__init__.py
index c31bec212..708bf12d9 100644
--- a/plinth/modules/deluge/__init__.py
+++ b/plinth/modules/deluge/__init__.py
@@ -23,7 +23,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.apache.components import Webserver
from plinth.modules.firewall.components import Firewall
from plinth.modules.users import register_group
@@ -32,8 +32,6 @@ from .manifest import backup, clients
version = 2
-service = None
-
managed_services = ['deluge-web']
managed_packages = ['deluged', 'deluge-web']
@@ -86,6 +84,9 @@ class DelugeApp(app_module.App):
webserver = Webserver('webserver-deluge', 'deluge-plinth')
self.add(webserver)
+ daemon = Daemon('daemon-deluge', managed_services[0])
+ self.add(daemon)
+
def init():
"""Initialize the Deluge module."""
@@ -93,45 +94,18 @@ def init():
app = DelugeApp()
register_group(group)
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(managed_services[0], name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
- if is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.install(managed_packages)
- helper.call('post', actions.superuser_run, 'deluge', ['enable'])
- global service
- if service is None:
- service = service_module.Service(managed_services[0], name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
+ helper.call('post', actions.superuser_run, 'deluge', ['setup'])
helper.call('post', app.enable)
-def is_enabled():
- """Return whether the module is enabled."""
- return (app.is_enabled() and action_utils.service_is_enabled('deluge-web'))
-
-
-def enable():
- """Enable the module."""
- actions.superuser_run('deluge', ['enable'])
- app.enable()
-
-
-def disable():
- """Disable the module."""
- actions.superuser_run('deluge', ['disable'])
- app.disable()
-
-
def diagnose():
"""Run diagnostics and return the results."""
results = []
diff --git a/plinth/modules/deluge/urls.py b/plinth/modules/deluge/urls.py
index e5b8b3123..67cbb9c26 100644
--- a/plinth/modules/deluge/urls.py
+++ b/plinth/modules/deluge/urls.py
@@ -21,12 +21,13 @@ URLs for the Deluge module.
from django.conf.urls import url
from plinth.modules import deluge
-from plinth.views import ServiceView
+from plinth.views import AppView
urlpatterns = [
- url(r'^apps/deluge/$',
- ServiceView.as_view(
- description=deluge.description, diagnostics_module_name="deluge",
- clients=deluge.clients, service_id=deluge.managed_services[0],
- manual_page=deluge.manual_page), name='index'),
+ url(
+ r'^apps/deluge/$',
+ AppView.as_view(name=deluge.name, description=deluge.description,
+ diagnostics_module_name='deluge',
+ clients=deluge.clients, app_id='deluge',
+ manual_page=deluge.manual_page), name='index'),
]
diff --git a/plinth/modules/diagnostics/templates/diagnostics.html b/plinth/modules/diagnostics/templates/diagnostics.html
index 324dbf26c..a923b0e1f 100644
--- a/plinth/modules/diagnostics/templates/diagnostics.html
+++ b/plinth/modules/diagnostics/templates/diagnostics.html
@@ -1,4 +1,4 @@
-{% extends 'simple_service.html' %}
+{% extends 'simple_app.html' %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/diaspora/__init__.py b/plinth/modules/diaspora/__init__.py
index 2e5e4f128..f8854399e 100644
--- a/plinth/modules/diaspora/__init__.py
+++ b/plinth/modules/diaspora/__init__.py
@@ -22,7 +22,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.errors import DomainNotRegisteredError
from plinth.modules.apache.components import Webserver
from plinth.modules.firewall.components import Firewall
@@ -55,8 +55,6 @@ name = _('diaspora*')
short_description = _('Federated Social Network')
-service = None
-
managed_services = ['diaspora']
managed_packages = ['diaspora']
@@ -103,6 +101,9 @@ class DiasporaApp(app_module.App):
webserver = Webserver('webserver-diaspora', 'diaspora-plinth')
self.add(webserver)
+ daemon = Daemon('daemon-diaspora', managed_services[0])
+ self.add(daemon)
+
class Shortcut(frontpage.Shortcut):
"""Frontpage shortcut to use configured domain name for URL."""
@@ -118,15 +119,9 @@ def init():
global app
app = DiasporaApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(managed_services[0], name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
-
- if is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
def setup(helper, old_version=None):
@@ -139,31 +134,9 @@ def setup(helper, old_version=None):
def setup_domain_name(domain_name):
actions.superuser_run('diaspora', ['setup', '--domain-name', domain_name])
- global service
- if service is None:
- service = service_module.Service(managed_services[0], name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
app.enable()
-def is_enabled():
- """Return whether the module is enabled."""
- return app.is_enabled()
-
-
-def enable():
- """Enable the module."""
- actions.superuser_run('diaspora', ['enable'])
- app.enable()
-
-
-def disable():
- """Disable the module."""
- actions.superuser_run('diaspora', ['disable'])
- app.disable()
-
-
def is_user_registrations_enabled():
"""Return whether user registrations are enabled"""
with open('/etc/diaspora/diaspora.yml') as f:
diff --git a/plinth/modules/diaspora/forms.py b/plinth/modules/diaspora/forms.py
index 3adb0e261..2e97ae7e6 100644
--- a/plinth/modules/diaspora/forms.py
+++ b/plinth/modules/diaspora/forms.py
@@ -21,12 +21,10 @@ Forms for configuring diaspora*
from django import forms
from django.utils.translation import ugettext_lazy as _
-from plinth.forms import ServiceForm
+from plinth.forms import AppForm
-class DiasporaServiceForm(ServiceForm):
+class DiasporaAppForm(AppForm):
"""Service Form with additional fields for diaspora*"""
is_user_registrations_enabled = forms.BooleanField(
- label=_('Enable new user registrations'),
- required=False
- )
+ label=_('Enable new user registrations'), required=False)
diff --git a/plinth/modules/diaspora/templates/diaspora-post-setup.html b/plinth/modules/diaspora/templates/diaspora-post-setup.html
index cea3442e8..cc0b8c79d 100644
--- a/plinth/modules/diaspora/templates/diaspora-post-setup.html
+++ b/plinth/modules/diaspora/templates/diaspora-post-setup.html
@@ -1,4 +1,4 @@
-{% extends "service.html" %}
+{% extends "app.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/diaspora/urls.py b/plinth/modules/diaspora/urls.py
index 302707d0f..201234727 100644
--- a/plinth/modules/diaspora/urls.py
+++ b/plinth/modules/diaspora/urls.py
@@ -14,18 +14,15 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
URLs for the diaspora module
"""
from django.conf.urls import url
-from .views import DiasporaSetupView, DiasporaServiceView
+from .views import DiasporaAppView, DiasporaSetupView
urlpatterns = [
- url(r'^apps/diaspora/setup$', DiasporaSetupView.as_view(),
- name='setup'),
- url(r'^apps/diaspora/$', DiasporaServiceView.as_view(),
- name='index')
+ url(r'^apps/diaspora/setup$', DiasporaSetupView.as_view(), name='setup'),
+ url(r'^apps/diaspora/$', DiasporaAppView.as_view(), name='index')
]
diff --git a/plinth/modules/diaspora/views.py b/plinth/modules/diaspora/views.py
index b7b5f3e12..b8fcfac6c 100644
--- a/plinth/modules/diaspora/views.py
+++ b/plinth/modules/diaspora/views.py
@@ -27,9 +27,9 @@ from django.views.generic import FormView
from plinth.forms import DomainSelectionForm
from plinth.modules import diaspora
from plinth.utils import get_domain_names
-from plinth.views import ServiceView
+from plinth.views import AppView
-from .forms import DiasporaServiceForm
+from .forms import DiasporaAppForm
class DiasporaSetupView(FormView):
@@ -55,12 +55,13 @@ class DiasporaSetupView(FormView):
return context
-class DiasporaServiceView(ServiceView):
+class DiasporaAppView(AppView):
"""Show diaspora service page."""
- form_class = DiasporaServiceForm
- service_id = diaspora.managed_services[0]
+ form_class = DiasporaAppForm
+ app_id = 'diaspora'
template_name = 'diaspora-post-setup.html'
diagnostics_module_name = 'diaspora'
+ name = diaspora.name
def dispatch(self, request, *args, **kwargs):
if not diaspora.is_setup():
@@ -75,14 +76,10 @@ class DiasporaServiceView(ServiceView):
def get_initial(self):
"""Return the status of the service to fill in the form."""
- return {
- 'is_enabled':
- self.service.is_enabled(),
- 'is_user_registrations_enabled':
- diaspora.is_user_registrations_enabled(),
- 'is_running':
- self.service.is_running()
- }
+ status = super().get_initial()
+ status['is_user_registrations_enabled'] = \
+ diaspora.is_user_registrations_enabled()
+ return status
def form_valid(self, form):
"""Enable/disable user registrations"""
diff --git a/plinth/modules/dynamicdns/templates/dynamicdns.html b/plinth/modules/dynamicdns/templates/dynamicdns.html
index e15861018..1e8ba3a41 100644
--- a/plinth/modules/dynamicdns/templates/dynamicdns.html
+++ b/plinth/modules/dynamicdns/templates/dynamicdns.html
@@ -1,4 +1,4 @@
-{% extends "service-subsubmenu.html" %}
+{% extends "app-subsubmenu.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/dynamicdns/templates/dynamicdns_configure.html b/plinth/modules/dynamicdns/templates/dynamicdns_configure.html
index 2a8115658..1ac338efb 100644
--- a/plinth/modules/dynamicdns/templates/dynamicdns_configure.html
+++ b/plinth/modules/dynamicdns/templates/dynamicdns_configure.html
@@ -1,4 +1,4 @@
-{% extends "service-subsubmenu.html" %}
+{% extends "app-subsubmenu.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/dynamicdns/templates/dynamicdns_status.html b/plinth/modules/dynamicdns/templates/dynamicdns_status.html
index 69a25321c..de96582e1 100644
--- a/plinth/modules/dynamicdns/templates/dynamicdns_status.html
+++ b/plinth/modules/dynamicdns/templates/dynamicdns_status.html
@@ -1,4 +1,4 @@
-{% extends "service-subsubmenu.html" %}
+{% extends "app-subsubmenu.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/dynamicdns/views.py b/plinth/modules/dynamicdns/views.py
index 737650549..625db4884 100644
--- a/plinth/modules/dynamicdns/views.py
+++ b/plinth/modules/dynamicdns/views.py
@@ -39,13 +39,15 @@ EMPTYSTRING = 'none'
subsubmenu = [{
'url': reverse_lazy('dynamicdns:index'),
'text': ugettext_lazy('About')
-}, {
- 'url': reverse_lazy('dynamicdns:configure'),
- 'text': ugettext_lazy('Configure')
-}, {
- 'url': reverse_lazy('dynamicdns:statuspage'),
- 'text': ugettext_lazy('Status')
-}]
+},
+ {
+ 'url': reverse_lazy('dynamicdns:configure'),
+ 'text': ugettext_lazy('Configure')
+ },
+ {
+ 'url': reverse_lazy('dynamicdns:statuspage'),
+ 'text': ugettext_lazy('Status')
+ }]
def index(request):
diff --git a/plinth/modules/ejabberd/__init__.py b/plinth/modules/ejabberd/__init__.py
index 4a556a979..1852e9b89 100644
--- a/plinth/modules/ejabberd/__init__.py
+++ b/plinth/modules/ejabberd/__init__.py
@@ -26,7 +26,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import cfg, frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules import config
from plinth.modules.apache.components import Webserver
from plinth.modules.firewall.components import Firewall
@@ -63,8 +63,6 @@ clients = clients
reserved_usernames = ['ejabberd']
-service = None
-
manual_page = 'ejabberd'
port_forwarding_info = [
@@ -106,20 +104,18 @@ class EjabberdApp(app_module.App):
webserver = Webserver('webserver-ejabberd', 'jwchat-plinth')
self.add(webserver)
+ daemon = Daemon('daemon-ejabberd', managed_services[0])
+ self.add(daemon)
+
def init():
"""Initialize the ejabberd module"""
global app
app = EjabberdApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service('ejabberd', name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
- if is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
pre_hostname_change.connect(on_pre_hostname_change)
post_hostname_change.connect(on_post_hostname_change)
@@ -135,31 +131,9 @@ def setup(helper, old_version=None):
['pre-install', '--domainname', domainname])
helper.install(managed_packages)
helper.call('post', actions.superuser_run, 'ejabberd', ['setup'])
- global service
- if service is None:
- service = service_module.Service('ejabberd', name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
helper.call('post', app.enable)
-def is_enabled():
- """Return whether the module is enabled."""
- return action_utils.service_is_enabled('ejabberd')
-
-
-def enable():
- """Enable the module."""
- actions.superuser_run('ejabberd', ['enable'])
- app.enable()
-
-
-def disable():
- """Enable the module."""
- actions.superuser_run('ejabberd', ['disable'])
- app.disable()
-
-
def on_pre_hostname_change(sender, old_hostname, new_hostname, **kwargs):
"""
Backup ejabberd database before hostname is changed.
diff --git a/plinth/modules/ejabberd/forms.py b/plinth/modules/ejabberd/forms.py
index ea788c2b0..b20c930b4 100644
--- a/plinth/modules/ejabberd/forms.py
+++ b/plinth/modules/ejabberd/forms.py
@@ -14,27 +14,25 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
Forms for configuring Ejabberd.
"""
-from plinth import forms as plinthForms
-from django import forms as djangoForms
+from django import forms
from django.utils.translation import ugettext_lazy as _
from plinth import cfg
+from plinth.forms import AppForm
from plinth.utils import format_lazy
-class EjabberdForm(plinthForms.ServiceForm):
+class EjabberdForm(AppForm):
"""Ejabberd configuration form."""
- MAM_enabled = djangoForms.BooleanField(
- label=_('Enable Message Archive Management'),
- required=False,
- help_text=format_lazy(_(
- 'If enabled, your {box_name} will store chat message histories. '
- 'This allows synchronization of conversations between multiple '
- 'clients, and reading the history of a multi-user chat room. '
- 'It depends on the client settings whether the histories are '
- 'stored as plain text or encrypted.'), box_name=_(cfg.box_name)))
+ MAM_enabled = forms.BooleanField(
+ label=_('Enable Message Archive Management'), required=False,
+ help_text=format_lazy(
+ _('If enabled, your {box_name} will store chat message histories. '
+ 'This allows synchronization of conversations between multiple '
+ 'clients, and reading the history of a multi-user chat room. '
+ 'It depends on the client settings whether the histories are '
+ 'stored as plain text or encrypted.'), box_name=_(cfg.box_name)))
diff --git a/plinth/modules/ejabberd/templates/ejabberd.html b/plinth/modules/ejabberd/templates/ejabberd.html
index 0938c0a01..c6b69389c 100644
--- a/plinth/modules/ejabberd/templates/ejabberd.html
+++ b/plinth/modules/ejabberd/templates/ejabberd.html
@@ -1,4 +1,4 @@
-{% extends "service.html" %}
+{% extends "app.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/ejabberd/urls.py b/plinth/modules/ejabberd/urls.py
index ded518137..dbb8ddd7e 100644
--- a/plinth/modules/ejabberd/urls.py
+++ b/plinth/modules/ejabberd/urls.py
@@ -14,16 +14,14 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
URL for the Ejabberd module
"""
from django.conf.urls import url
-from .views import EjabberdServiceView
-
+from .views import EjabberdAppView
urlpatterns = [
- url(r'^apps/ejabberd/$', EjabberdServiceView.as_view(), name='index')
+ url(r'^apps/ejabberd/$', EjabberdAppView.as_view(), name='index')
]
diff --git a/plinth/modules/ejabberd/views.py b/plinth/modules/ejabberd/views.py
index 896014829..bb5d033d6 100644
--- a/plinth/modules/ejabberd/views.py
+++ b/plinth/modules/ejabberd/views.py
@@ -23,15 +23,16 @@ from django.utils.translation import ugettext as _
from plinth import actions
from plinth.modules import config, ejabberd
-from plinth.views import ServiceView
+from plinth.views import AppView
from .forms import EjabberdForm
-class EjabberdServiceView(ServiceView):
+class EjabberdAppView(AppView):
"""Show ejabberd as a service."""
- service_id = ejabberd.managed_services[0]
+ app_id = 'ejabberd'
template_name = 'ejabberd.html'
+ name = ejabberd.name
description = ejabberd.description
diagnostics_module_name = 'ejabberd'
form_class = EjabberdForm
@@ -64,11 +65,9 @@ class EjabberdServiceView(ServiceView):
messages.info(self.request, _('Setting unchanged'))
elif not app_same:
if new_status['is_enabled']:
- self.service.enable()
- messages.success(self.request, _('Application enabled'))
+ self.app.enable()
else:
- self.service.disable()
- messages.success(self.request, _('Application disabled'))
+ self.app.disable()
if not mam_same:
# note ejabberd action "enable" or "disable" restarts, if running
@@ -81,7 +80,7 @@ class EjabberdServiceView(ServiceView):
messages.success(self.request,
_('Message Archive Management disabled'))
- return super(ServiceView, self).form_valid(form)
+ return super().form_valid(form)
def is_MAM_enabled(self):
"""Return whether Message Archive Management (MAM) is enabled."""
diff --git a/plinth/modules/firewall/components.py b/plinth/modules/firewall/components.py
index 525a3f1d0..8d0a7040c 100644
--- a/plinth/modules/firewall/components.py
+++ b/plinth/modules/firewall/components.py
@@ -104,3 +104,8 @@ class Firewall(app.FollowerComponent):
]
if not any(enabled_components_on_port):
firewall.remove_service(port, zone='external')
+
+ @staticmethod
+ def get_internal_interfaces():
+ """Returns a list of interfaces in a firewall zone."""
+ return firewall.get_interfaces('internal')
diff --git a/plinth/modules/firewall/templates/firewall.html b/plinth/modules/firewall/templates/firewall.html
index b5ee99a8e..86a9b94e3 100644
--- a/plinth/modules/firewall/templates/firewall.html
+++ b/plinth/modules/firewall/templates/firewall.html
@@ -1,4 +1,4 @@
-{% extends "simple_service.html" %}
+{% extends "simple_app.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/firewall/views.py b/plinth/modules/firewall/views.py
index 2e85e1f08..a8890e3a5 100644
--- a/plinth/modules/firewall/views.py
+++ b/plinth/modules/firewall/views.py
@@ -20,7 +20,6 @@ FreedomBox app to configure a firewall.
from django.template.response import TemplateResponse
-import plinth.service as service_module
from plinth.modules import firewall
from . import components
diff --git a/plinth/modules/i2p/__init__.py b/plinth/modules/i2p/__init__.py
index 005f3bae6..b6f25eab3 100644
--- a/plinth/modules/i2p/__init__.py
+++ b/plinth/modules/i2p/__init__.py
@@ -23,7 +23,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.apache.components import Webserver
from plinth.modules.firewall.components import Firewall
from plinth.modules.i2p.resources import FAVORITES
@@ -58,8 +58,6 @@ clients = clients
group = ('i2p', _('Manage I2P application'))
-service = None
-
manual_page = 'I2P'
port_forwarding_info = [
@@ -107,6 +105,9 @@ class I2PApp(app_module.App):
webserver = Webserver('webserver-i2p', 'i2p-freedombox')
self.add(webserver)
+ daemon = Daemon('daemon-i2p', managed_services[0])
+ self.add(daemon)
+
def init():
"""Intialize the module."""
@@ -114,21 +115,16 @@ def init():
app = I2PApp()
register_group(group)
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(
- managed_services[0], name, is_enabled=is_enabled, enable=enable,
- disable=disable, is_running=is_running)
- if is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.install(managed_packages)
- helper.call('post', disable)
+ helper.call('post', app.disable)
# Add favorites to the configuration
for fav in FAVORITES:
args = [
@@ -152,38 +148,9 @@ def setup(helper, old_version=None):
'set-tunnel-property', '--name', tunnel, '--property', 'interface',
'--value', '0.0.0.0'
])
- helper.call('post', enable)
- global service
- if service is None:
- service = service_module.Service(
- managed_services[0], name, is_enabled=is_enabled, enable=enable,
- disable=disable, is_running=is_running)
-
helper.call('post', app.enable)
-def is_running():
- """Return whether the service is running."""
- return action_utils.service_is_running('i2p')
-
-
-def is_enabled():
- """Return whether the module is enabled."""
- return action_utils.service_is_enabled('i2p') and app.is_enabled()
-
-
-def enable():
- """Enable the module."""
- actions.superuser_run('i2p', ['enable'])
- app.enable()
-
-
-def disable():
- """Enable the module."""
- actions.superuser_run('i2p', ['disable'])
- app.disable()
-
-
def diagnose():
"""Run diagnostics and return the results."""
results = []
diff --git a/plinth/modules/i2p/templates/i2p.html b/plinth/modules/i2p/templates/i2p.html
index adf5b2f2e..4eda093dc 100644
--- a/plinth/modules/i2p/templates/i2p.html
+++ b/plinth/modules/i2p/templates/i2p.html
@@ -1,4 +1,4 @@
-{% extends "service-subsubmenu.html" %}
+{% extends "app-subsubmenu.html" %}
{% comment %}
#
# This file is part of FreedomBox.
@@ -26,8 +26,8 @@
{% if show_status_block %}
{% trans "Status" %}
- {% with service_name=service.name %}
- {% if service.is_running %}
+ {% with service_name=name %}
+ {% if is_running %}
{% blocktrans trimmed %}
Service {{ service_name }} is running.
@@ -45,7 +45,7 @@
{% block diagnostics %}
{% if diagnostics_module_name %}
- {% include "diagnostics_button.html" with module=diagnostics_module_name enabled=service.is_enabled %}
+ {% include "diagnostics_button.html" with module=diagnostics_module_name enabled=is_enabled %}
{% endif %}
{% endblock %}
diff --git a/plinth/modules/i2p/templates/i2p_service.html b/plinth/modules/i2p/templates/i2p_service.html
index 364ba0f38..7ddb303c7 100644
--- a/plinth/modules/i2p/templates/i2p_service.html
+++ b/plinth/modules/i2p/templates/i2p_service.html
@@ -1,4 +1,22 @@
-{% extends "service-subsubmenu.html" %}
+{% extends "app-subsubmenu.html" %}
+{% comment %}
+#
+# This file is part of FreedomBox.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+{% endcomment %}
{% load i18n %}
diff --git a/plinth/modules/i2p/urls.py b/plinth/modules/i2p/urls.py
index 8a62a9f76..3229d89df 100644
--- a/plinth/modules/i2p/urls.py
+++ b/plinth/modules/i2p/urls.py
@@ -23,7 +23,8 @@ from django.conf.urls import url
from plinth.modules.i2p import views
urlpatterns = [
- url(r'^apps/i2p/$', views.I2PServiceView.as_view(), name='index'),
+ url(r'^apps/i2p/$', views.I2PAppView.as_view(), name='index'),
url(r'^apps/i2p/tunnels/?$', views.TunnelsView.as_view(), name='tunnels'),
- url(r'^apps/i2p/torrents/?$', views.TorrentsView.as_view(), name='torrents'),
+ url(r'^apps/i2p/torrents/?$', views.TorrentsView.as_view(),
+ name='torrents'),
]
diff --git a/plinth/modules/i2p/views.py b/plinth/modules/i2p/views.py
index b7e2013c9..68ec2d517 100644
--- a/plinth/modules/i2p/views.py
+++ b/plinth/modules/i2p/views.py
@@ -24,7 +24,7 @@ from django.utils.translation import ugettext_lazy
from django.views.generic import TemplateView
import plinth.modules.i2p as i2p
-from plinth.views import ServiceView
+from plinth.views import AppView
subsubmenu = [{
'url': reverse_lazy('i2p:index'),
@@ -39,10 +39,11 @@ subsubmenu = [{
}]
-class I2PServiceView(ServiceView):
+class I2PAppView(AppView):
"""Serve configuration page."""
- service_id = i2p.service_name
+ app_id = 'i2p'
clients = i2p.clients
+ name = i2p.name
description = i2p.description
diagnostics_module_name = i2p.service_name
show_status_block = True
@@ -74,6 +75,7 @@ class ServiceBaseView(TemplateView):
context['clients'] = i2p.clients
context['manual_page'] = i2p.manual_page
context['subsubmenu'] = subsubmenu
+ context['is_enabled'] = i2p.app.is_enabled()
context['service_title'] = self.service_title
context['service_path'] = self.service_path
context['service_description'] = self.service_description
diff --git a/plinth/modules/ikiwiki/__init__.py b/plinth/modules/ikiwiki/__init__.py
index 51bf9c667..18c25c815 100644
--- a/plinth/modules/ikiwiki/__init__.py
+++ b/plinth/modules/ikiwiki/__init__.py
@@ -24,7 +24,6 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import cfg, frontpage, menu
-from plinth import service as service_module
from plinth.modules.apache.components import Webserver
from plinth.modules.firewall.components import Firewall
from plinth.modules.users import register_group
@@ -39,8 +38,6 @@ managed_packages = [
'libsearch-xapian-perl', 'libimage-magick-perl'
]
-service = None
-
name = _('ikiwiki')
short_description = _('Wiki and Blog')
@@ -114,43 +111,18 @@ def init():
app = IkiwikiApp()
register_group(group)
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service('ikiwiki', name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
- if is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.install(managed_packages)
helper.call('post', actions.superuser_run, 'ikiwiki', ['setup'])
- global service
- if service is None:
- service = service_module.Service('ikiwiki', name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
helper.call('post', app.enable)
-def is_enabled():
- """Return whether the module is enabled."""
- return app.is_enabled()
-
-
-def enable():
- """Enable the module."""
- app.enable()
-
-
-def disable():
- """Enable the module."""
- app.disable()
-
-
def diagnose():
"""Run diagnostics and return the results."""
results = []
diff --git a/plinth/modules/ikiwiki/templates/ikiwiki_configure.html b/plinth/modules/ikiwiki/templates/ikiwiki_configure.html
index 8b085396e..56ce04cff 100644
--- a/plinth/modules/ikiwiki/templates/ikiwiki_configure.html
+++ b/plinth/modules/ikiwiki/templates/ikiwiki_configure.html
@@ -1,4 +1,4 @@
-{% extends "service-subsubmenu.html" %}
+{% extends "app-subsubmenu.html" %}
{% comment %}
#
# This file is part of FreedomBox.
@@ -26,7 +26,7 @@
{% block diagnostics %}
{% if diagnostics_module_name %}
- {% include "diagnostics_button.html" with module=diagnostics_module_name enabled=service.is_enabled %}
+ {% include "diagnostics_button.html" with module=diagnostics_module_name enabled=is_enabled %}
{% endif %}
{% endblock %}
diff --git a/plinth/modules/ikiwiki/templates/ikiwiki_create.html b/plinth/modules/ikiwiki/templates/ikiwiki_create.html
index 64eb28ba4..35d1839c0 100644
--- a/plinth/modules/ikiwiki/templates/ikiwiki_create.html
+++ b/plinth/modules/ikiwiki/templates/ikiwiki_create.html
@@ -1,4 +1,4 @@
-{% extends "service-subsubmenu.html" %}
+{% extends "app-subsubmenu.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/ikiwiki/templates/ikiwiki_manage.html b/plinth/modules/ikiwiki/templates/ikiwiki_manage.html
index 8850d435b..00c3881e1 100644
--- a/plinth/modules/ikiwiki/templates/ikiwiki_manage.html
+++ b/plinth/modules/ikiwiki/templates/ikiwiki_manage.html
@@ -1,4 +1,4 @@
-{% extends "service-subsubmenu.html" %}
+{% extends "app-subsubmenu.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/ikiwiki/urls.py b/plinth/modules/ikiwiki/urls.py
index 195e5f198..57bed0f7f 100644
--- a/plinth/modules/ikiwiki/urls.py
+++ b/plinth/modules/ikiwiki/urls.py
@@ -14,7 +14,6 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
URLs for the ikiwiki module
"""
@@ -23,10 +22,8 @@ from django.conf.urls import url
from . import views
-
urlpatterns = [
- url(r'^apps/ikiwiki/$',
- views.IkiwikiServiceView.as_view(), name='index'),
+ url(r'^apps/ikiwiki/$', views.IkiwikiAppView.as_view(), name='index'),
url(r'^apps/ikiwiki/manage/$', views.manage, name='manage'),
url(r'^apps/ikiwiki/(?P[\w.@+-]+)/delete/$', views.delete,
name='delete'),
diff --git a/plinth/modules/ikiwiki/views.py b/plinth/modules/ikiwiki/views.py
index 2a4ee0399..e230aae4c 100644
--- a/plinth/modules/ikiwiki/views.py
+++ b/plinth/modules/ikiwiki/views.py
@@ -42,13 +42,14 @@ subsubmenu = [{
}]
-class IkiwikiServiceView(views.ServiceView):
+class IkiwikiAppView(views.AppView):
"""Serve configuration page."""
- service_id = "ikiwiki"
+ app_id = 'ikiwiki'
+ name = ikiwiki.name
description = ikiwiki.description
- diagnostics_module_name = "ikiwiki"
+ diagnostics_module_name = 'ikiwiki'
show_status_block = False
- template_name = "ikiwiki_configure.html"
+ template_name = 'ikiwiki_configure.html'
def get_context_data(self, **kwargs):
"""Return the context data for rendering the template view."""
@@ -72,7 +73,8 @@ def manage(request):
'description': ikiwiki.description,
'manual_page': ikiwiki.manual_page,
'subsubmenu': subsubmenu,
- 'sites': sites
+ 'sites': sites,
+ 'is_enabled': ikiwiki.app.is_enabled(),
})
@@ -108,6 +110,7 @@ def create(request):
'form': form,
'manual_page': ikiwiki.manual_page,
'subsubmenu': subsubmenu,
+ 'is_enabled': ikiwiki.app.is_enabled(),
})
diff --git a/plinth/modules/infinoted/__init__.py b/plinth/modules/infinoted/__init__.py
index 39014c3d1..329c961af 100644
--- a/plinth/modules/infinoted/__init__.py
+++ b/plinth/modules/infinoted/__init__.py
@@ -24,17 +24,15 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import cfg, frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.firewall.components import Firewall
from plinth.utils import format_lazy
-from plinth.views import ServiceView
+from plinth.views import AppView
from .manifest import backup, clients
version = 1
-service = None
-
managed_services = ['infinoted']
managed_packages = ['infinoted']
@@ -83,24 +81,24 @@ class InfinotedApp(app_module.App):
ports=['infinoted-plinth'], is_external=True)
self.add(firewall)
+ daemon = Daemon('daemon-infinoted', managed_services[0])
+ self.add(daemon)
+
def init():
"""Initialize the infinoted module."""
global app
app = InfinotedApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(managed_services[0], name,
- enable=enable, disable=disable)
- if service.is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
-class InfinotedServiceView(ServiceView):
- service_id = managed_services[0]
- diagnostics_module_name = "infinoted"
+class InfinotedAppView(AppView):
+ app_id = 'infinoted'
+ diagnostics_module_name = 'infinoted'
+ name = name
description = description
clients = clients
port_forwarding_info = port_forwarding_info
@@ -110,26 +108,9 @@ def setup(helper, old_version=None):
"""Install and configure the module."""
helper.install(managed_packages)
helper.call('post', actions.superuser_run, 'infinoted', ['setup'])
- global service
- if service is None:
- service = service_module.Service(managed_services[0], name,
- enable=enable, disable=disable)
-
helper.call('post', app.enable)
-def enable():
- """Enable the module."""
- actions.superuser_run('service', ['enable', managed_services[0]])
- app.enable()
-
-
-def disable():
- """Disable the module."""
- actions.superuser_run('service', ['disable', managed_services[0]])
- app.disable()
-
-
def diagnose():
"""Run diagnostics and return the results."""
results = []
diff --git a/plinth/modules/infinoted/urls.py b/plinth/modules/infinoted/urls.py
index e35be81e2..64a6e2188 100644
--- a/plinth/modules/infinoted/urls.py
+++ b/plinth/modules/infinoted/urls.py
@@ -14,16 +14,14 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
URLs for the infinoted module.
"""
from django.conf.urls import url
-from plinth.modules.infinoted import InfinotedServiceView
-
+from plinth.modules.infinoted import InfinotedAppView
urlpatterns = [
- url(r'^apps/infinoted/$', InfinotedServiceView.as_view(), name='index'),
+ url(r'^apps/infinoted/$', InfinotedAppView.as_view(), name='index'),
]
diff --git a/plinth/modules/jsxc/__init__.py b/plinth/modules/jsxc/__init__.py
index 4891b4c1c..cd1036e7b 100644
--- a/plinth/modules/jsxc/__init__.py
+++ b/plinth/modules/jsxc/__init__.py
@@ -25,7 +25,6 @@ from django.utils.translation import ugettext_lazy as _
from plinth import app as app_module
from plinth import frontpage, menu
-from plinth import service as service_module
from plinth.modules.firewall.components import Firewall
from .manifest import backup, clients
@@ -45,8 +44,6 @@ description = [
clients = clients
-service = None
-
logger = logging.getLogger(__name__)
app = None
@@ -79,36 +76,12 @@ def init():
global app
app = JSXCApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service('jsxc', name, is_enabled=is_enabled,
- enable=enable, disable=disable)
- if is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.install(managed_packages)
-
- global service
- if not service:
- service = service_module.Service('jsxc', name, is_enabled=is_enabled,
- enable=enable, disable=disable)
-
helper.call('post', app.enable)
-
-
-def is_enabled():
- """Return whether the module is enabled."""
- setup_helper = globals()['setup_helper']
- return setup_helper.get_state() != 'needs-setup'
-
-
-def enable():
- app.enable()
-
-
-def disable():
- app.disable()
diff --git a/plinth/modules/jsxc/templates/jsxc.html b/plinth/modules/jsxc/templates/jsxc.html
index 6f0da05a0..2cb34f379 100644
--- a/plinth/modules/jsxc/templates/jsxc.html
+++ b/plinth/modules/jsxc/templates/jsxc.html
@@ -1,4 +1,4 @@
-{% extends "service.html" %}
+{% extends "app.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/jsxc/urls.py b/plinth/modules/jsxc/urls.py
index 0c53d14ff..19ff648d0 100644
--- a/plinth/modules/jsxc/urls.py
+++ b/plinth/modules/jsxc/urls.py
@@ -20,9 +20,9 @@ URLs for the JSXC module
from django.conf.urls import url
-from .views import JSXCServiceView, JsxcView
+from .views import JSXCAppView, JsxcView
urlpatterns = [
- url(r'^apps/jsxc/$', JSXCServiceView.as_view(), name='index'),
+ url(r'^apps/jsxc/$', JSXCAppView.as_view(), name='index'),
url(r'^apps/jsxc/jsxc/$', JsxcView.as_view(), name='jsxc')
]
diff --git a/plinth/modules/jsxc/views.py b/plinth/modules/jsxc/views.py
index bc006410f..5dc674424 100644
--- a/plinth/modules/jsxc/views.py
+++ b/plinth/modules/jsxc/views.py
@@ -18,18 +18,19 @@
Views for the JSXC module
"""
-from django.views.generic import TemplateView
from django.utils.decorators import method_decorator
+from django.views.generic import TemplateView
from stronghold.decorators import public
from plinth.modules import config, jsxc
-from plinth.views import ServiceView
+from plinth.views import AppView
-class JSXCServiceView(ServiceView):
- """Show ejabberd as a service."""
- service_id = 'jsxc'
+class JSXCAppView(AppView):
+ """Show ejabberd as an app."""
+ app_id = 'jsxc'
template_name = 'jsxc.html'
+ name = jsxc.name
description = jsxc.description
show_status_block = False
clients = jsxc.clients
diff --git a/plinth/modules/letsencrypt/__init__.py b/plinth/modules/letsencrypt/__init__.py
index a19d79608..207136dbe 100644
--- a/plinth/modules/letsencrypt/__init__.py
+++ b/plinth/modules/letsencrypt/__init__.py
@@ -60,8 +60,6 @@ description = [
'Subscriber Agreement before using this service.')
]
-service = None
-
manual_page = 'LetsEncrypt'
MODULES_WITH_HOOKS = ['ejabberd', 'matrixsynapse']
diff --git a/plinth/modules/letsencrypt/templates/letsencrypt.html b/plinth/modules/letsencrypt/templates/letsencrypt.html
index 3ea9e6958..b9c160cba 100644
--- a/plinth/modules/letsencrypt/templates/letsencrypt.html
+++ b/plinth/modules/letsencrypt/templates/letsencrypt.html
@@ -1,4 +1,4 @@
-{% extends "simple_service.html" %}
+{% extends "simple_app.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/matrixsynapse/__init__.py b/plinth/modules/matrixsynapse/__init__.py
index b7974a227..0db44e08a 100644
--- a/plinth/modules/matrixsynapse/__init__.py
+++ b/plinth/modules/matrixsynapse/__init__.py
@@ -28,7 +28,7 @@ from ruamel.yaml.util import load_yaml_guess_indent
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.apache.components import Webserver
from plinth.modules.firewall.components import Firewall
@@ -60,8 +60,6 @@ description = [
clients = clients
-service = None
-
manual_page = 'MatrixSynapse'
port_forwarding_info = [('TCP', 8448)]
@@ -103,31 +101,23 @@ class MatrixSynapseApp(app_module.App):
'matrix-synapse-plinth')
self.add(webserver)
+ daemon = Daemon('daemon-matrixsynapse', managed_services[0])
+ self.add(daemon)
+
def init():
"""Initialize the matrix-synapse module."""
global app
app = MatrixSynapseApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service('matrix-synapse', name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
- if is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.install(managed_packages)
- global service
- if service is None:
- service = service_module.Service('matrix-synapse', name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
-
helper.call('post', actions.superuser_run, 'matrixsynapse',
['post-install'])
helper.call('post', app.enable)
@@ -138,24 +128,6 @@ def is_setup():
return os.path.exists(SERVER_NAME_PATH)
-def is_enabled():
- """Return whether the module is enabled."""
- return (action_utils.service_is_enabled('matrix-synapse')
- and app.is_enabled())
-
-
-def enable():
- """Enable the module."""
- actions.superuser_run('matrixsynapse', ['enable'])
- app.enable()
-
-
-def disable():
- """Enable the module."""
- actions.superuser_run('matrixsynapse', ['disable'])
- app.disable()
-
-
def diagnose():
"""Run diagnostics and return the results."""
results = []
diff --git a/plinth/modules/matrixsynapse/forms.py b/plinth/modules/matrixsynapse/forms.py
index 7c30f3914..6c180f8f2 100644
--- a/plinth/modules/matrixsynapse/forms.py
+++ b/plinth/modules/matrixsynapse/forms.py
@@ -14,21 +14,19 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
Forms for the Matrix Synapse module.
"""
from django import forms
from django.utils.translation import ugettext_lazy as _
-from plinth.forms import ServiceForm
+
+from plinth.forms import AppForm
-class MatrixSynapseForm(ServiceForm):
+class MatrixSynapseForm(AppForm):
enable_public_registration = forms.BooleanField(
- label=_('Enable Public Registration'),
- required=False,
- help_text=_(
+ label=_('Enable Public Registration'), required=False, help_text=_(
'Enabling public registration means that anyone on the Internet '
'can register a new account on your Matrix server. Disable this '
'if you only want existing users to be able to use it.'))
diff --git a/plinth/modules/matrixsynapse/templates/matrix-synapse.html b/plinth/modules/matrixsynapse/templates/matrix-synapse.html
index 9a4b832ae..70674c193 100644
--- a/plinth/modules/matrixsynapse/templates/matrix-synapse.html
+++ b/plinth/modules/matrixsynapse/templates/matrix-synapse.html
@@ -1,4 +1,4 @@
-{% extends "service.html" %}
+{% extends "app.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/matrixsynapse/urls.py b/plinth/modules/matrixsynapse/urls.py
index 7b175e009..788854856 100644
--- a/plinth/modules/matrixsynapse/urls.py
+++ b/plinth/modules/matrixsynapse/urls.py
@@ -14,17 +14,16 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
URLs for the matrix-synapse module.
"""
from django.conf.urls import url
-from .views import SetupView, MatrixSynapseServiceView
+from .views import MatrixSynapseAppView, SetupView
urlpatterns = [
url(r'^apps/matrixsynapse/setup/$', SetupView.as_view(), name='setup'),
- url(r'^apps/matrixsynapse/$', MatrixSynapseServiceView.as_view(),
+ url(r'^apps/matrixsynapse/$', MatrixSynapseAppView.as_view(),
name='index'),
]
diff --git a/plinth/modules/matrixsynapse/views.py b/plinth/modules/matrixsynapse/views.py
index 1e2751586..8d73f20ae 100644
--- a/plinth/modules/matrixsynapse/views.py
+++ b/plinth/modules/matrixsynapse/views.py
@@ -28,7 +28,7 @@ from plinth import actions
from plinth.forms import DomainSelectionForm
from plinth.modules import matrixsynapse
from plinth.utils import get_domain_names
-from plinth.views import ServiceView
+from plinth.views import AppView
from . import get_public_registration_status, has_valid_certificate
from .forms import MatrixSynapseForm
@@ -59,10 +59,11 @@ class SetupView(FormView):
return context
-class MatrixSynapseServiceView(ServiceView):
+class MatrixSynapseAppView(AppView):
"""Show matrix-synapse service page."""
- service_id = matrixsynapse.managed_services[0]
+ app_id = 'matrixsynapse'
template_name = 'matrix-synapse.html'
+ name = matrixsynapse.name
description = matrixsynapse.description
diagnostics_module_name = 'matrixsynapse'
form_class = MatrixSynapseForm
@@ -107,11 +108,9 @@ class MatrixSynapseServiceView(ServiceView):
messages.info(self.request, _('Setting unchanged'))
elif not app_same:
if new_config['is_enabled']:
- self.service.enable()
- messages.success(self.request, _('Application enabled'))
+ self.app.enable()
else:
- self.service.disable()
- messages.success(self.request, _('Application disabled'))
+ self.app.disable()
if not pubreg_same:
# note action public-registration restarts, if running now
@@ -126,4 +125,4 @@ class MatrixSynapseServiceView(ServiceView):
messages.success(self.request,
_('Public registration disabled'))
- return super(ServiceView, self).form_valid(form)
+ return super().form_valid(form)
diff --git a/plinth/modules/mediawiki/__init__.py b/plinth/modules/mediawiki/__init__.py
index 9eb220af1..5e60a58c2 100644
--- a/plinth/modules/mediawiki/__init__.py
+++ b/plinth/modules/mediawiki/__init__.py
@@ -23,7 +23,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.apache.components import Webserver
from plinth.modules.firewall.components import Firewall
@@ -33,6 +33,8 @@ version = 6
managed_packages = ['mediawiki', 'imagemagick', 'php-sqlite3']
+managed_services = ['mediawiki-jobrunner']
+
name = _('MediaWiki')
short_description = _('Wiki')
@@ -52,8 +54,6 @@ description = [
'logged in can make changes to the content.')
]
-service = None
-
manual_page = 'MediaWiki'
clients = clients
@@ -93,6 +93,9 @@ class MediaWikiApp(app_module.App):
'mediawiki-freedombox')
self.add(webserver)
+ daemon = Daemon('daemon-mediawiki', managed_services[0])
+ self.add(daemon)
+
class Shortcut(frontpage.Shortcut):
"""Frontpage shortcut for only logged users when in private mode."""
@@ -108,14 +111,9 @@ def init():
global app
app = MediaWikiApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service('mediawiki', name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
- if is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
def setup(helper, old_version=None):
@@ -123,32 +121,9 @@ def setup(helper, old_version=None):
helper.install(managed_packages)
helper.call('setup', actions.superuser_run, 'mediawiki', ['setup'])
helper.call('update', actions.superuser_run, 'mediawiki', ['update'])
- helper.call('enable', actions.superuser_run, 'mediawiki', ['enable'])
- global service
- if service is None:
- service = service_module.Service('mediawiki', name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
helper.call('post', app.enable)
-def is_enabled():
- """Return whether the module is enabled."""
- return app.is_enabled()
-
-
-def enable():
- """Enable the module."""
- actions.superuser_run('mediawiki', ['enable'])
- app.enable()
-
-
-def disable():
- """Enable the module."""
- actions.superuser_run('mediawiki', ['disable'])
- app.disable()
-
-
def diagnose():
"""Run diagnostics and return the results."""
results = []
diff --git a/plinth/modules/mediawiki/forms.py b/plinth/modules/mediawiki/forms.py
index d4a5343c6..671e4340e 100644
--- a/plinth/modules/mediawiki/forms.py
+++ b/plinth/modules/mediawiki/forms.py
@@ -21,10 +21,10 @@ FreedomBox app for configuring MediaWiki.
from django import forms
from django.utils.translation import ugettext_lazy as _
-from plinth.forms import ServiceForm
+from plinth.forms import AppForm
-class MediaWikiForm(ServiceForm): # pylint: disable=W0232
+class MediaWikiForm(AppForm): # pylint: disable=W0232
"""MediaWiki configuration form."""
password = forms.CharField(
label=_('Administrator Password'), help_text=_(
diff --git a/plinth/modules/mediawiki/templates/mediawiki.html b/plinth/modules/mediawiki/templates/mediawiki.html
index 66c041a61..4dbdc6776 100644
--- a/plinth/modules/mediawiki/templates/mediawiki.html
+++ b/plinth/modules/mediawiki/templates/mediawiki.html
@@ -1,4 +1,4 @@
-{% extends "service.html" %}
+{% extends "app.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/mediawiki/urls.py b/plinth/modules/mediawiki/urls.py
index b7b2ac33c..64dd1556a 100644
--- a/plinth/modules/mediawiki/urls.py
+++ b/plinth/modules/mediawiki/urls.py
@@ -20,8 +20,8 @@ URLs for the mediawiki module.
from django.conf.urls import url
-from .views import MediaWikiServiceView
+from .views import MediaWikiAppView
urlpatterns = [
- url(r'^apps/mediawiki/$', MediaWikiServiceView.as_view(), name='index'),
+ url(r'^apps/mediawiki/$', MediaWikiAppView.as_view(), name='index'),
]
diff --git a/plinth/modules/mediawiki/views.py b/plinth/modules/mediawiki/views.py
index 9a927dd54..07f7615e0 100644
--- a/plinth/modules/mediawiki/views.py
+++ b/plinth/modules/mediawiki/views.py
@@ -26,19 +26,19 @@ from django.utils.translation import ugettext as _
from plinth import actions, views
from plinth.modules import mediawiki
-from . import (is_enabled, is_private_mode_enabled,
- is_public_registration_enabled)
+from . import is_private_mode_enabled, is_public_registration_enabled
from .forms import MediaWikiForm
logger = logging.getLogger(__name__)
-class MediaWikiServiceView(views.ServiceView):
- """Serve configuration page."""
+class MediaWikiAppView(views.AppView):
+ """App configuration page."""
clients = mediawiki.clients
+ name = mediawiki.name
description = mediawiki.description
diagnostics_module_name = 'mediawiki'
- service_id = 'mediawiki'
+ app_id = 'mediawiki'
form_class = MediaWikiForm
manual_page = mediawiki.manual_page
show_status_block = False
@@ -75,11 +75,9 @@ class MediaWikiServiceView(views.ServiceView):
messages.info(self.request, _('Setting unchanged'))
elif not app_same:
if new_config['is_enabled']:
- self.service.enable()
- messages.success(self.request, _('Application enabled'))
+ self.app.enable()
else:
- self.service.disable()
- messages.success(self.request, _('Application disabled'))
+ self.app.disable()
if not pub_reg_same:
# note action public-registration restarts, if running now
diff --git a/plinth/modules/minetest/__init__.py b/plinth/modules/minetest/__init__.py
index ccce4a7bd..1252ce3df 100644
--- a/plinth/modules/minetest/__init__.py
+++ b/plinth/modules/minetest/__init__.py
@@ -22,10 +22,10 @@ import augeas
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _
-from plinth import action_utils, actions
+from plinth import action_utils
from plinth import app as app_module
from plinth import cfg, frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.firewall.components import Firewall
from plinth.utils import format_lazy
@@ -33,8 +33,6 @@ from .manifest import backup, clients
version = 2
-service = None
-
managed_services = ['minetest-server']
mods = [
@@ -102,43 +100,26 @@ class MinetestApp(app_module.App):
ports=['minetest-plinth'], is_external=True)
self.add(firewall)
+ daemon = Daemon('daemon-minetest', managed_services[0])
+ self.add(daemon)
+
def init():
"""Initialize the module."""
global app
app = MinetestApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(managed_services[0], name,
- enable=enable, disable=disable)
- if service.is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.install(managed_packages)
- global service
- if service is None:
- service = service_module.Service(managed_services[0], name,
- enable=enable, disable=disable)
helper.call('post', app.enable)
-def enable():
- """Enable the module."""
- actions.superuser_run('service', ['enable', managed_services[0]])
- app.enable()
-
-
-def disable():
- """Disable the module."""
- actions.superuser_run('service', ['disable', managed_services[0]])
- app.disable()
-
-
def diagnose():
"""Run diagnostics and return the results."""
results = []
diff --git a/plinth/modules/minetest/forms.py b/plinth/modules/minetest/forms.py
index b6467e86c..31afa21a7 100644
--- a/plinth/modules/minetest/forms.py
+++ b/plinth/modules/minetest/forms.py
@@ -14,7 +14,6 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
Forms for minetest module.
"""
@@ -22,34 +21,29 @@ Forms for minetest module.
from django import forms
from django.utils.translation import ugettext_lazy as _
-from plinth.forms import ServiceForm
+from plinth.forms import AppForm
-class MinetestForm(ServiceForm):
+class MinetestForm(AppForm):
"""Minetest configuration form"""
max_players = forms.IntegerField(
- label=_('Maximum number of players'),
- required=True,
- min_value=1,
- max_value=100,
- help_text=_('You can change the maximum number of players playing '
- 'minetest at a single instance of time.'))
+ label=_('Maximum number of players'), required=True, min_value=1,
+ max_value=100, help_text=_(
+ 'You can change the maximum number of players playing '
+ 'minetest at a single instance of time.'))
creative_mode = forms.BooleanField(
- label=_('Enable creative mode'),
- required=False,
+ label=_('Enable creative mode'), required=False,
help_text=_('Creative mode changes the rules of the game to make it '
'more suitable for creative gameplay, rather than '
'challenging "survival" gameplay.'))
enable_pvp = forms.BooleanField(
- label=_('Enable PVP'),
- required=False,
+ label=_('Enable PVP'), required=False,
help_text=_('Enabling Player Vs Player will allow players to damage '
'other players.'))
enable_damage = forms.BooleanField(
- label=_('Enable damage'),
- required=False,
+ label=_('Enable damage'), required=False,
help_text=_('When disabled, players cannot die or receive damage of '
'any kind.'))
diff --git a/plinth/modules/minetest/templates/minetest.html b/plinth/modules/minetest/templates/minetest.html
index 1e54a88e1..4a0fc1acc 100644
--- a/plinth/modules/minetest/templates/minetest.html
+++ b/plinth/modules/minetest/templates/minetest.html
@@ -1,4 +1,4 @@
-{% extends "service.html" %}
+{% extends "app.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/minetest/urls.py b/plinth/modules/minetest/urls.py
index b5327e670..91d2b8f42 100644
--- a/plinth/modules/minetest/urls.py
+++ b/plinth/modules/minetest/urls.py
@@ -14,16 +14,14 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
URLs for the minetest module.
"""
from django.conf.urls import url
-from plinth.modules.minetest.views import MinetestServiceView
-
+from plinth.modules.minetest.views import MinetestAppView
urlpatterns = [
- url(r'^apps/minetest/$', MinetestServiceView.as_view(), name='index'),
+ url(r'^apps/minetest/$', MinetestAppView.as_view(), name='index'),
]
diff --git a/plinth/modules/minetest/views.py b/plinth/modules/minetest/views.py
index 11efe629b..0414d6250 100644
--- a/plinth/modules/minetest/views.py
+++ b/plinth/modules/minetest/views.py
@@ -23,16 +23,17 @@ from django.utils.translation import ugettext_lazy as _
from plinth import actions
from plinth.modules import minetest, names
-from plinth.views import ServiceView
+from plinth.views import AppView
-from . import description, get_configuration, managed_services
+from . import description, get_configuration
from .forms import MinetestForm
-class MinetestServiceView(ServiceView): # pylint: disable=too-many-ancestors
+class MinetestAppView(AppView): # pylint: disable=too-many-ancestors
"""A specialized view for configuring minetest."""
- service_id = managed_services[0]
- diagnostics_module_name = "minetest"
+ app_id = 'minetest'
+ diagnostics_module_name = 'minetest'
+ name = minetest.name
description = description
show_status_block = True
template_name = 'minetest.html'
diff --git a/plinth/modules/mldonkey/__init__.py b/plinth/modules/mldonkey/__init__.py
index aa54901e0..99b82be0f 100644
--- a/plinth/modules/mldonkey/__init__.py
+++ b/plinth/modules/mldonkey/__init__.py
@@ -23,7 +23,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import cfg, frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.apache.components import Webserver
from plinth.modules.firewall.components import Firewall
from plinth.modules.users import register_group
@@ -60,8 +60,6 @@ reserved_usernames = ['mldonkey']
group = ('ed2k', _('Download files using eDonkey applications'))
-service = None
-
manual_page = 'MLDonkey'
app = None
@@ -93,6 +91,9 @@ class MLDonkeyApp(app_module.App):
webserver = Webserver('webserver-mldonkey', 'mldonkey-freedombox')
self.add(webserver)
+ daemon = Daemon('daemon-mldonkey', managed_services[0])
+ self.add(daemon)
+
def init():
"""Initialize the MLDonkey module."""
@@ -100,53 +101,18 @@ def init():
app = MLDonkeyApp()
register_group(group)
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(
- managed_services[0], name, is_enabled=is_enabled, enable=enable,
- disable=disable, is_running=is_running)
-
- if is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.call('pre', actions.superuser_run, 'mldonkey', ['pre-install'])
helper.install(managed_packages)
- helper.call('post', actions.superuser_run, 'mldonkey', ['enable'])
- global service
- if service is None:
- service = service_module.Service(
- managed_services[0], name, is_enabled=is_enabled, enable=enable,
- disable=disable, is_running=is_running)
helper.call('post', app.enable)
-def is_running():
- """Return whether the service is running."""
- return action_utils.service_is_running('mldonkey-server')
-
-
-def is_enabled():
- """Return whether the module is enabled."""
- return (action_utils.service_is_enabled('mldonkey-server')
- and app.is_enabled())
-
-
-def enable():
- """Enable the module."""
- actions.superuser_run('mldonkey', ['enable'])
- app.enable()
-
-
-def disable():
- """Disable the module."""
- actions.superuser_run('mldonkey', ['disable'])
- app.disable()
-
-
def diagnose():
"""Run diagnostics and return the results."""
results = []
diff --git a/plinth/modules/mldonkey/urls.py b/plinth/modules/mldonkey/urls.py
index f39d53cce..5b5e18483 100644
--- a/plinth/modules/mldonkey/urls.py
+++ b/plinth/modules/mldonkey/urls.py
@@ -21,16 +21,15 @@ URLs for the mldonkey module.
from django.conf.urls import url
from plinth.modules import mldonkey
-from plinth.views import ServiceView
+from plinth.views import AppView
urlpatterns = [
url(
r'^apps/mldonkey/$',
- ServiceView.as_view(service_id=mldonkey.managed_services[0],
- diagnostics_module_name='mldonkey',
- description=mldonkey.description,
- clients=mldonkey.clients,
- manual_page=mldonkey.manual_page,
- show_status_block=True),
+ AppView.as_view(
+ app_id='mldonkey', name=mldonkey.name,
+ diagnostics_module_name='mldonkey',
+ description=mldonkey.description, clients=mldonkey.clients,
+ manual_page=mldonkey.manual_page, show_status_block=True),
name='index'),
]
diff --git a/plinth/modules/monkeysphere/templates/monkeysphere.html b/plinth/modules/monkeysphere/templates/monkeysphere.html
index 9e593c8e2..3f56b7ed0 100644
--- a/plinth/modules/monkeysphere/templates/monkeysphere.html
+++ b/plinth/modules/monkeysphere/templates/monkeysphere.html
@@ -1,4 +1,4 @@
-{% extends "simple_service.html" %}
+{% extends "simple_app.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/mumble/__init__.py b/plinth/modules/mumble/__init__.py
index 64f409ea4..aa61f6001 100644
--- a/plinth/modules/mumble/__init__.py
+++ b/plinth/modules/mumble/__init__.py
@@ -21,12 +21,12 @@ FreedomBox app to configure Mumble server.
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _
-from plinth import action_utils, actions
+from plinth import action_utils
from plinth import app as app_module
from plinth import frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.firewall.components import Firewall
-from plinth.views import ServiceView
+from plinth.views import AppView
from .manifest import backup, clients
@@ -36,8 +36,6 @@ name = _('Mumble')
short_description = _('Voice Chat')
-service = None
-
managed_services = ['mumble-server']
managed_packages = ['mumble-server']
@@ -86,25 +84,24 @@ class MumbleApp(app_module.App):
is_external=True)
self.add(firewall)
+ daemon = Daemon('daemon-mumble', managed_services[0])
+ self.add(daemon)
+
def init():
"""Intialize the Mumble module."""
global app
app = MumbleApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(managed_services[0], name,
- enable=enable, disable=disable)
-
- if service.is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
-class MumbleServiceView(ServiceView):
- service_id = managed_services[0]
- diagnostics_module_name = "mumble"
+class MumbleAppView(AppView):
+ app_id = 'mumble'
+ diagnostics_module_name = 'mumble'
+ name = name
description = description
clients = clients
manual_page = manual_page
@@ -114,25 +111,9 @@ class MumbleServiceView(ServiceView):
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.install(managed_packages)
- global service
- if service is None:
- service = service_module.Service(managed_services[0], name,
- enable=enable, disable=disable)
helper.call('post', app.enable)
-def enable():
- """Enable the module."""
- actions.superuser_run('service', ['enable', managed_services[0]])
- app.enable()
-
-
-def disable():
- """Disable the module."""
- actions.superuser_run('service', ['disable', managed_services[0]])
- app.disable()
-
-
def diagnose():
"""Run diagnostics and return the results."""
results = []
diff --git a/plinth/modules/mumble/urls.py b/plinth/modules/mumble/urls.py
index 398e87b19..78580d0b7 100644
--- a/plinth/modules/mumble/urls.py
+++ b/plinth/modules/mumble/urls.py
@@ -14,16 +14,14 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
URLs for the Mumble module
"""
from django.conf.urls import url
-from plinth.modules.mumble import MumbleServiceView
-
+from plinth.modules.mumble import MumbleAppView
urlpatterns = [
- url(r'^apps/mumble/$', MumbleServiceView.as_view(), name='index'),
+ url(r'^apps/mumble/$', MumbleAppView.as_view(), name='index'),
]
diff --git a/plinth/modules/names/templates/names.html b/plinth/modules/names/templates/names.html
index 638d3a471..df791e519 100644
--- a/plinth/modules/names/templates/names.html
+++ b/plinth/modules/names/templates/names.html
@@ -1,4 +1,4 @@
-{% extends "simple_service.html" %}
+{% extends "simple_app.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/openvpn/__init__.py b/plinth/modules/openvpn/__init__.py
index f51f6a7dd..97e11217e 100644
--- a/plinth/modules/openvpn/__init__.py
+++ b/plinth/modules/openvpn/__init__.py
@@ -24,7 +24,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import cfg, frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.firewall.components import Firewall
from plinth.utils import format_lazy
@@ -32,8 +32,6 @@ from .manifest import backup
version = 3
-service = None
-
managed_services = ['openvpn-server@freedombox']
managed_packages = ['openvpn', 'easy-rsa']
@@ -87,31 +85,26 @@ class OpenVPNApp(app_module.App):
is_external=True)
self.add(firewall)
+ daemon = Daemon('daemon-openvpn', managed_services[0])
+ self.add(daemon)
+
def init():
"""Initialize the OpenVPN module."""
global app
app = OpenVPNApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(managed_services[0], name)
-
- if service.is_enabled() and is_setup():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled() \
+ and is_setup():
+ app.set_enabled(True)
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.install(managed_packages)
helper.call('post', actions.superuser_run, 'openvpn', ['upgrade'])
- global service
- if service is None:
- service = service_module.Service(managed_services[0], name,
- enable=enable, disable=disable)
-
- if service.is_enabled() and is_setup():
+ if app.is_enabled() and is_setup():
helper.call('post', app.enable)
@@ -120,18 +113,6 @@ def is_setup():
return actions.superuser_run('openvpn', ['is-setup']).strip() == 'true'
-def enable():
- """Enable the module."""
- actions.superuser_run('service', ['enable', managed_services[0]])
- app.enable()
-
-
-def disable():
- """Enable the module."""
- actions.superuser_run('service', ['disable', managed_services[0]])
- app.disable()
-
-
def diagnose():
"""Run diagnostics and return the results."""
return [action_utils.diagnose_port_listening(1194, 'udp4')]
diff --git a/plinth/modules/openvpn/templates/openvpn.html b/plinth/modules/openvpn/templates/openvpn.html
index a5f02e122..b4e15a755 100644
--- a/plinth/modules/openvpn/templates/openvpn.html
+++ b/plinth/modules/openvpn/templates/openvpn.html
@@ -1,4 +1,4 @@
-{% extends "simple_service.html" %}
+{% extends "simple_app.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/openvpn/views.py b/plinth/modules/openvpn/views.py
index f44ddd491..fd2b36f5b 100644
--- a/plinth/modules/openvpn/views.py
+++ b/plinth/modules/openvpn/views.py
@@ -27,7 +27,7 @@ from django.template.response import TemplateResponse
from django.utils.translation import ugettext as _
from django.views.decorators.http import require_POST
-from plinth import actions
+from plinth import actions, daemon
from plinth.modules import config, openvpn
from .forms import OpenVpnForm
@@ -75,7 +75,7 @@ def setup(request):
setup_process = actions.superuser_run('openvpn', ['setup'],
run_in_background=True)
- openvpn.enable()
+ openvpn.app.enable()
return redirect('openvpn:index')
@@ -105,8 +105,8 @@ def get_status():
return {
'is_setup': openvpn.is_setup(),
'setup_running': bool(setup_process),
- 'enabled': openvpn.service.is_enabled(),
- 'is_running': openvpn.service.is_running()
+ 'enabled': openvpn.app.is_enabled(),
+ 'is_running': daemon.app_is_running(openvpn.app)
}
@@ -136,9 +136,9 @@ def _apply_changes(request, old_status, new_status):
if old_status['enabled'] != new_status['enabled']:
if new_status['enabled']:
- openvpn.enable()
+ openvpn.app.enable()
else:
- openvpn.disable()
+ openvpn.app.disable()
modified = True
diff --git a/plinth/modules/pagekite/__init__.py b/plinth/modules/pagekite/__init__.py
index eb78b329e..10c2cdf9c 100644
--- a/plinth/modules/pagekite/__init__.py
+++ b/plinth/modules/pagekite/__init__.py
@@ -92,16 +92,17 @@ class PagekiteApp(app_module.App):
parent_url_name='system')
self.add(menu_item)
+ # XXX: Add pagekite daemon component and simplify action script
+
def init():
"""Intialize the PageKite module"""
global app
app = PagekiteApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- app.set_enabled(True) # XXX: Perform more proper check
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
# Register kite name with Name Services module.
utils.update_names_module(initial_registration=True)
diff --git a/plinth/modules/pagekite/templates/pagekite_base.html b/plinth/modules/pagekite/templates/pagekite_base.html
index 0215e7fb3..ad517a9cd 100644
--- a/plinth/modules/pagekite/templates/pagekite_base.html
+++ b/plinth/modules/pagekite/templates/pagekite_base.html
@@ -1,4 +1,4 @@
-{% extends "service-subsubmenu.html" %}
+{% extends "app-subsubmenu.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/pagekite/utils.py b/plinth/modules/pagekite/utils.py
index 4b1facd46..b85ba2db3 100644
--- a/plinth/modules/pagekite/utils.py
+++ b/plinth/modules/pagekite/utils.py
@@ -15,13 +15,13 @@
# along with this program. If not, see .
#
-from django.utils.translation import ugettext_lazy as _
import json
import logging
import os
-from plinth import actions
-from plinth import action_utils
+from django.utils.translation import ugettext_lazy as _
+
+from plinth import action_utils, actions
from plinth.signals import domain_added, domain_removed
LOGGER = logging.getLogger(__name__)
@@ -36,8 +36,9 @@ KITE_SECRET = '@kitesecret'
CONF_PATH = '/files/etc/pagekite.d'
# Parameters that get stored in configuration service_on entries
-SERVICE_PARAMS = ['protocol', 'kitename', 'backend_host', 'backend_port',
- 'secret']
+SERVICE_PARAMS = [
+ 'protocol', 'kitename', 'backend_host', 'backend_port', 'secret'
+]
# Predefined services are used to build the PredefinedServiceForm
#
@@ -45,35 +46,47 @@ SERVICE_PARAMS = ['protocol', 'kitename', 'backend_host', 'backend_port',
# still recognizes when you try to add a service equal to a predefined one
PREDEFINED_SERVICES = {
'http': {
- 'params': {'protocol': 'http',
- 'kitename': KITE_NAME,
- 'backend_port': '80',
- 'backend_host': BACKEND_HOST,
- 'secret': KITE_SECRET},
- 'label': _('Web Server (HTTP)'),
- 'help_text': _('Site will be available at '
- 'http://{0}'),
+ 'params': {
+ 'protocol': 'http',
+ 'kitename': KITE_NAME,
+ 'backend_port': '80',
+ 'backend_host': BACKEND_HOST,
+ 'secret': KITE_SECRET
+ },
+ 'label':
+ _('Web Server (HTTP)'),
+ 'help_text':
+ _('Site will be available at '
+ 'http://{0}'),
},
'https': {
- 'params': {'protocol': 'https',
- 'kitename': KITE_NAME,
- 'backend_port': '443',
- 'backend_host': BACKEND_HOST,
- 'secret': KITE_SECRET},
- 'label': _('Web Server (HTTPS)'),
- 'help_text': _('Site will be available at '
- 'https://{0}'),
+ 'params': {
+ 'protocol': 'https',
+ 'kitename': KITE_NAME,
+ 'backend_port': '443',
+ 'backend_host': BACKEND_HOST,
+ 'secret': KITE_SECRET
+ },
+ 'label':
+ _('Web Server (HTTPS)'),
+ 'help_text':
+ _('Site will be available at '
+ 'https://{0}'),
},
'ssh': {
- 'params': {'protocol': 'raw/22',
- 'kitename': KITE_NAME,
- 'backend_port': '22',
- 'backend_host': BACKEND_HOST,
- 'secret': KITE_SECRET},
- 'label': _('Secure Shell (SSH)'),
- 'help_text': _('See SSH client setup '
- 'instructions')
+ 'params': {
+ 'protocol': 'raw/22',
+ 'kitename': KITE_NAME,
+ 'backend_port': '22',
+ 'backend_host': BACKEND_HOST,
+ 'secret': KITE_SECRET
+ },
+ 'label':
+ _('Secure Shell (SSH)'),
+ 'help_text':
+ _('See SSH client setup '
+ 'instructions')
},
}
@@ -81,8 +94,7 @@ PREDEFINED_SERVICES = {
def get_kite_details():
output = run(['get-kite'])
kite_details = output.split()
- return {'kite_name': kite_details[0],
- 'kite_secret': kite_details[1]}
+ return {'kite_name': kite_details[0], 'kite_secret': kite_details[1]}
def get_pagekite_config():
@@ -259,8 +271,9 @@ def update_names_module(initial_registration=False, enabled=None,
if enabled:
# Get enabled services and kite name
services = get_pagekite_services()[0]
- enabled_services = [service for service in services if
- services[service]]
+ enabled_services = [
+ service for service in services if services[service]
+ ]
if kite_name is None:
try:
kite_name = get_kite_details()['kite_name']
@@ -271,9 +284,9 @@ def update_names_module(initial_registration=False, enabled=None,
kite_name = None
if initial_registration or (enabled and kite_name):
- domain_added.send_robust(
- sender='pagekite', domain_type='pagekite', name=kite_name,
- description=_('Pagekite'), services=enabled_services)
+ domain_added.send_robust(sender='pagekite', domain_type='pagekite',
+ name=kite_name, description=_('Pagekite'),
+ services=enabled_services)
if __name__ == "__main__":
diff --git a/plinth/modules/pagekite/views.py b/plinth/modules/pagekite/views.py
index d4f16f01f..342c146be 100644
--- a/plinth/modules/pagekite/views.py
+++ b/plinth/modules/pagekite/views.py
@@ -34,13 +34,15 @@ from .forms import (AddCustomServiceForm, ConfigurationForm,
subsubmenu = [{
'url': reverse_lazy('pagekite:index'),
'text': _('Configure')
-}, {
- 'url': reverse_lazy('pagekite:standard-services'),
- 'text': _('Standard Services')
-}, {
- 'url': reverse_lazy('pagekite:custom-services'),
- 'text': _('Custom Services')
-}]
+},
+ {
+ 'url': reverse_lazy('pagekite:standard-services'),
+ 'text': _('Standard Services')
+ },
+ {
+ 'url': reverse_lazy('pagekite:custom-services'),
+ 'text': _('Custom Services')
+ }]
class ContextMixin(object):
diff --git a/plinth/modules/power/templates/power.html b/plinth/modules/power/templates/power.html
index 981983c2f..49e963907 100644
--- a/plinth/modules/power/templates/power.html
+++ b/plinth/modules/power/templates/power.html
@@ -1,4 +1,4 @@
-{% extends "simple_service.html" %}
+{% extends "simple_app.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/privoxy/__init__.py b/plinth/modules/privoxy/__init__.py
index a18d1b08c..5b4ca64d9 100644
--- a/plinth/modules/privoxy/__init__.py
+++ b/plinth/modules/privoxy/__init__.py
@@ -24,10 +24,10 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import cfg, frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.firewall.components import Firewall
from plinth.utils import format_lazy
-from plinth.views import ServiceView
+from plinth.views import AppView
from .manifest import backup
@@ -60,8 +60,6 @@ description = [
reserved_usernames = ['privoxy']
-service = None
-
manual_page = 'Privoxy'
app = None
@@ -90,48 +88,31 @@ class PrivoxyApp(app_module.App):
is_external=False)
self.add(firewall)
+ daemon = Daemon('daemon-privoxy', managed_services[0])
+ self.add(daemon)
+
def init():
"""Intialize the module."""
global app
app = PrivoxyApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(managed_services[0], name,
- enable=enable, disable=disable)
-
- if service.is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.call('pre', actions.superuser_run, 'privoxy', ['pre-install'])
helper.install(managed_packages)
- global service
- if service is None:
- service = service_module.Service(managed_services[0], name,
- enable=enable, disable=disable)
helper.call('post', app.enable)
-def enable():
- """Enable the module."""
- actions.superuser_run('service', ['enable', managed_services[0]])
- app.enable()
-
-
-def disable():
- """Disable the module."""
- actions.superuser_run('service', ['disable', managed_services[0]])
- app.disable()
-
-
-class PrivoxyServiceView(ServiceView):
- service_id = managed_services[0]
+class PrivoxyAppView(AppView):
+ app_id = 'privoxy'
diagnostics_module_name = 'privoxy'
+ name = name
description = description
manual_page = manual_page
diff --git a/plinth/modules/privoxy/urls.py b/plinth/modules/privoxy/urls.py
index 2f7b81fc7..6887b281e 100644
--- a/plinth/modules/privoxy/urls.py
+++ b/plinth/modules/privoxy/urls.py
@@ -14,16 +14,14 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
URLs for the Privoxy module.
"""
from django.conf.urls import url
-from plinth.modules.privoxy import PrivoxyServiceView
-
+from plinth.modules.privoxy import PrivoxyAppView
urlpatterns = [
- url(r'^apps/privoxy/$', PrivoxyServiceView.as_view(), name='index'),
+ url(r'^apps/privoxy/$', PrivoxyAppView.as_view(), name='index'),
]
diff --git a/plinth/modules/quassel/__init__.py b/plinth/modules/quassel/__init__.py
index 4fcad5621..782ceb196 100644
--- a/plinth/modules/quassel/__init__.py
+++ b/plinth/modules/quassel/__init__.py
@@ -21,20 +21,18 @@ FreedomBox app for Quassel.
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _
-from plinth import action_utils, actions
+from plinth import action_utils
from plinth import app as app_module
from plinth import cfg, frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.firewall.components import Firewall
from plinth.utils import format_lazy
-from plinth.views import ServiceView
+from plinth.views import AppView
from .manifest import backup, clients
version = 1
-service = None
-
managed_services = ['quasselcore']
managed_packages = ['quassel-core']
@@ -94,25 +92,24 @@ class QuasselApp(app_module.App):
is_external=True)
self.add(firewall)
+ daemon = Daemon('daemon-quassel', managed_services[0])
+ self.add(daemon)
+
def init():
"""Initialize the quassel module."""
global app
app = QuasselApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(managed_services[0], name,
- enable=enable, disable=disable)
-
- if service.is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
-class QuasselServiceView(ServiceView):
- service_id = managed_services[0]
- diagnostics_module_name = "quassel"
+class QuasselAppView(AppView):
+ app_id = 'quassel'
+ diagnostics_module_name = 'quassel'
+ name = name
description = description
clients = clients
manual_page = manual_page
@@ -122,25 +119,9 @@ class QuasselServiceView(ServiceView):
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.install(managed_packages)
- global service
- if service is None:
- service = service_module.Service(managed_services[0], name,
- enable=enable, disable=disable)
helper.call('post', app.enable)
-def enable():
- """Enable the module."""
- actions.superuser_run('service', ['enable', managed_services[0]])
- app.enable()
-
-
-def disable():
- """Disable the module."""
- actions.superuser_run('service', ['disable', managed_services[0]])
- app.disable()
-
-
def diagnose():
"""Run diagnostics and return the results."""
results = []
diff --git a/plinth/modules/quassel/urls.py b/plinth/modules/quassel/urls.py
index 98b1b67bf..a2dc6f9c0 100644
--- a/plinth/modules/quassel/urls.py
+++ b/plinth/modules/quassel/urls.py
@@ -14,16 +14,14 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
URLs for the quassel module.
"""
from django.conf.urls import url
-from plinth.modules.quassel import QuasselServiceView
-
+from plinth.modules.quassel import QuasselAppView
urlpatterns = [
- url(r'^apps/quassel/$', QuasselServiceView.as_view(), name='index'),
+ url(r'^apps/quassel/$', QuasselAppView.as_view(), name='index'),
]
diff --git a/plinth/modules/radicale/__init__.py b/plinth/modules/radicale/__init__.py
index dfe208a92..52807e79c 100644
--- a/plinth/modules/radicale/__init__.py
+++ b/plinth/modules/radicale/__init__.py
@@ -29,7 +29,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import cfg, frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.apache.components import Uwsgi, Webserver
from plinth.modules.firewall.components import Firewall
from plinth.utils import format_lazy
@@ -38,8 +38,6 @@ from .manifest import backup, clients
version = 2
-service = None
-
managed_services = ['radicale']
managed_packages = ['radicale', 'uwsgi', 'uwsgi-plugin-python3']
@@ -104,6 +102,9 @@ class RadicaleApp(app_module.App):
uwsgi = RadicaleUwsgi('uwsgi-radicale', 'radicale')
self.add(uwsgi)
+ daemon = RadicaleDaemon('daemon-radicale', managed_services[0])
+ self.add(daemon)
+
class RadicaleWebserver(Webserver):
"""Webserver enable/disable behavior specific for radicale."""
@@ -137,6 +138,7 @@ class RadicaleUwsgi(Uwsgi):
"""Enable the uWSGI configuration if version >=2."""
package_version = get_package_version()
if package_version and package_version >= VERSION_2:
+ actions.superuser_run('radicale', ['fix-collections'])
super().enable()
def disable(self):
@@ -146,20 +148,50 @@ class RadicaleUwsgi(Uwsgi):
super().disable()
+class RadicaleDaemon(Daemon):
+ """Daemon enable/disable behavior specific for radicale."""
+
+ @staticmethod
+ def _is_old_radicale():
+ """Return whether radicale is less than version 2."""
+ package_version = get_package_version()
+ return package_version and package_version < VERSION_2
+
+ def is_enabled(self):
+ """Return whether daemon is enabled if version < 2."""
+ if self._is_old_radicale():
+ return super().is_enabled()
+
+ return True
+
+ def enable(self):
+ """Enable the daemon if version < 2."""
+ if self._is_old_radicale():
+ super().enable()
+ else:
+ super().disable()
+
+ def disable(self):
+ """Disable the daemon if version < 2."""
+ if self._is_old_radicale():
+ super().disable()
+
+ def is_running(self):
+ """Return whether daemon is enabled if version < 2."""
+ if self._is_old_radicale():
+ return super().is_running()
+
+ return True
+
+
def init():
"""Initialize the radicale module."""
global app
app = RadicaleApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(
- managed_services[0], name, is_enabled=is_enabled, enable=enable,
- disable=disable, is_running=is_running)
-
- if is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
def setup(helper, old_version=None):
@@ -188,11 +220,6 @@ def setup(helper, old_version=None):
helper.install(managed_packages)
helper.call('post', actions.superuser_run, 'radicale', ['setup'])
- global service
- if service is None:
- service = service_module.Service(
- managed_services[0], name, is_enabled=is_enabled, enable=enable,
- disable=disable, is_running=is_running)
helper.call('post', app.enable)
@@ -208,24 +235,6 @@ def get_package_version():
return LV(package_version)
-def is_running():
- """Return whether the service is running."""
- if get_package_version() < VERSION_2:
- return action_utils.service_is_running('radicale')
-
- return app.is_enabled()
-
-
-def is_enabled():
- """Return whether the module is enabled."""
- package_version = get_package_version()
- daemon_enabled = True
- if package_version and package_version < VERSION_2:
- daemon_enabled = action_utils.service_is_enabled('radicale')
-
- return app.is_enabled() and daemon_enabled
-
-
def enable():
"""Enable the module."""
actions.superuser_run('radicale', ['enable'])
diff --git a/plinth/modules/radicale/forms.py b/plinth/modules/radicale/forms.py
index 8d3178e9f..029fc6663 100644
--- a/plinth/modules/radicale/forms.py
+++ b/plinth/modules/radicale/forms.py
@@ -14,7 +14,6 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
Forms for radicale module.
"""
@@ -23,22 +22,26 @@ from django import forms
from django.utils.translation import ugettext_lazy as _
from plinth import cfg
-from plinth.forms import ServiceForm
+from plinth.forms import AppForm
from plinth.utils import format_lazy
CHOICES = [
- ('owner_only', _('Only the owner of a calendar/addressbook can view or '
- 'make changes.')),
- ('owner_write', format_lazy(
- _('Any user with a {box_name} login can view any calendar/addressbook'
- ', but only the owner can make changes.'), box_name=_(cfg.box_name))),
- ('authenticated', format_lazy(
- _('Any user with a {box_name} login can view or make changes'
- ' to any calendar/addressbook.'), box_name=_(cfg.box_name))),
+ ('owner_only',
+ _('Only the owner of a calendar/addressbook can view or '
+ 'make changes.')),
+ ('owner_write',
+ format_lazy(
+ _('Any user with a {box_name} login can view any calendar/addressbook'
+ ', but only the owner can make changes.'),
+ box_name=_(cfg.box_name))),
+ ('authenticated',
+ format_lazy(
+ _('Any user with a {box_name} login can view or make changes'
+ ' to any calendar/addressbook.'), box_name=_(cfg.box_name))),
]
-class RadicaleForm(ServiceForm):
+class RadicaleForm(AppForm):
"""Specialized configuration form for radicale service."""
access_rights = forms.ChoiceField(choices=CHOICES, required=True,
widget=forms.RadioSelect())
diff --git a/plinth/modules/radicale/urls.py b/plinth/modules/radicale/urls.py
index e3d3068d6..0601736fc 100644
--- a/plinth/modules/radicale/urls.py
+++ b/plinth/modules/radicale/urls.py
@@ -14,16 +14,14 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
URLs for the radicale module.
"""
from django.conf.urls import url
-from .views import RadicaleServiceView
-
+from .views import RadicaleAppView
urlpatterns = [
- url(r'^apps/radicale/$', RadicaleServiceView.as_view(), name='index'),
+ url(r'^apps/radicale/$', RadicaleAppView.as_view(), name='index'),
]
diff --git a/plinth/modules/radicale/views.py b/plinth/modules/radicale/views.py
index 62ab7b2d4..70f174c84 100644
--- a/plinth/modules/radicale/views.py
+++ b/plinth/modules/radicale/views.py
@@ -23,19 +23,20 @@ from django.utils.translation import ugettext_lazy as _
from plinth import actions
from plinth.modules import radicale
-from plinth.views import ServiceView
+from plinth.views import AppView
-from . import description, get_rights_value, managed_services
+from . import description, get_rights_value
from .forms import RadicaleForm
-class RadicaleServiceView(ServiceView):
+class RadicaleAppView(AppView):
"""A specialized view for configuring radicale service."""
clients = radicale.clients
+ name = radicale.name
description = description
diagnostics_module_name = 'radicale'
form_class = RadicaleForm
- service_id = managed_services[0]
+ app_id = 'radicale'
manual_page = radicale.manual_page
def get_initial(self):
diff --git a/plinth/modules/repro/__init__.py b/plinth/modules/repro/__init__.py
index ec64b4d8f..1ba7b4477 100644
--- a/plinth/modules/repro/__init__.py
+++ b/plinth/modules/repro/__init__.py
@@ -24,10 +24,10 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.apache.components import Webserver
from plinth.modules.firewall.components import Firewall
-from plinth.views import ServiceView
+from plinth.views import AppView
from .manifest import backup, clients
@@ -64,8 +64,6 @@ clients = clients
reserved_usernames = ['repro']
-service = None
-
manual_page = 'Repro'
port_forwarding_info = [('UDP', '1024-65535')]
@@ -100,27 +98,26 @@ class ReproApp(app_module.App):
webserver = Webserver('webserver-repro', 'repro-plinth')
self.add(webserver)
+ daemon = Daemon('daemon-repro', managed_services[0])
+ self.add(daemon)
+
def init():
"""Initialize the repro module."""
global app
app = ReproApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(managed_services[0], name,
- enable=enable, disable=disable)
-
- if service.is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
-class ReproServiceView(ServiceView):
+class ReproAppView(AppView):
clients = clients
+ name = name
description = description
- diagnostics_module_name = "repro"
- service_id = managed_services[0]
+ diagnostics_module_name = 'repro'
+ app_id = 'repro'
manual_page = manual_page
port_forwarding_info = port_forwarding_info
@@ -129,25 +126,9 @@ def setup(helper, old_version=None):
"""Install and configure the module."""
helper.install(managed_packages)
helper.call('post', actions.superuser_run, 'repro', ['setup'])
- global service
- if service is None:
- service = service_module.Service(managed_services[0], name,
- enable=enable, disable=disable)
helper.call('post', app.enable)
-def enable():
- """Enable the module."""
- actions.superuser_run('service', ['enable', managed_services[0]])
- app.enable()
-
-
-def disable():
- """Disable the module."""
- actions.superuser_run('service', ['disable', managed_services[0]])
- app.disable()
-
-
def diagnose():
"""Run diagnostics and return the results."""
results = []
diff --git a/plinth/modules/repro/urls.py b/plinth/modules/repro/urls.py
index 5072790ab..9433098ff 100644
--- a/plinth/modules/repro/urls.py
+++ b/plinth/modules/repro/urls.py
@@ -14,16 +14,14 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
URLs for the repro module.
"""
from django.conf.urls import url
-from plinth.modules.repro import ReproServiceView
-
+from plinth.modules.repro import ReproAppView
urlpatterns = [
- url(r'^apps/repro/$', ReproServiceView.as_view(), name='index'),
+ url(r'^apps/repro/$', ReproAppView.as_view(), name='index'),
]
diff --git a/plinth/modules/restore/__init__.py b/plinth/modules/restore/__init__.py
index dab62552d..2f6dfd4bc 100644
--- a/plinth/modules/restore/__init__.py
+++ b/plinth/modules/restore/__init__.py
@@ -22,7 +22,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import app as app_module
from plinth import cfg, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.firewall.components import Firewall
from plinth.utils import format_lazy
@@ -54,8 +54,6 @@ clients = clients
reserved_usernames = ['node-restore']
-service = None
-
app = None
@@ -76,21 +74,21 @@ class RestoreApp(app_module.App):
is_external=True)
self.add(firewall)
+ daemon = Daemon('daemon-restore', managed_services[0])
+ self.add(daemon)
+
def init():
"""Initialize the reStore module."""
global app
app = RestoreApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(managed_services[0], name)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.enable()
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.install(managed_packages)
- global service
- if service is None:
- service = service_module.Service(managed_services[0], name)
+ helper.call('post', app.enable)
diff --git a/plinth/modules/restore/urls.py b/plinth/modules/restore/urls.py
index 78547f0a9..1d8288de7 100644
--- a/plinth/modules/restore/urls.py
+++ b/plinth/modules/restore/urls.py
@@ -20,14 +20,13 @@ URLs for the reStore module.
from django.conf.urls import url
-from plinth.views import ServiceView
from plinth.modules import restore
+from plinth.views import AppView
urlpatterns = [
- url(r'^apps/restore/$',
- ServiceView.as_view(
- service_id=restore.managed_services[0],
- description=restore.description,
- clients=restore.clients),
- name='index'),
+ url(
+ r'^apps/restore/$',
+ AppView.as_view(app_id='restore', name=restore.name,
+ description=restore.description,
+ clients=restore.clients), name='index'),
]
diff --git a/plinth/modules/roundcube/__init__.py b/plinth/modules/roundcube/__init__.py
index dc49478ce..45f646fe4 100644
--- a/plinth/modules/roundcube/__init__.py
+++ b/plinth/modules/roundcube/__init__.py
@@ -23,7 +23,6 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import frontpage, menu
-from plinth import service as service_module
from plinth.modules.apache.components import Webserver
from plinth.modules.firewall.components import Firewall
@@ -59,8 +58,6 @@ description = [
clients = clients
-service = None
-
manual_page = 'Roundcube'
app = None
@@ -98,15 +95,9 @@ def init():
global app
app = RoundcubeApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service('roundcube', name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
-
- if is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
def setup(helper, old_version=None):
@@ -114,29 +105,9 @@ def setup(helper, old_version=None):
helper.call('pre', actions.superuser_run, 'roundcube', ['pre-install'])
helper.install(managed_packages)
helper.call('post', actions.superuser_run, 'roundcube', ['setup'])
- global service
- if service is None:
- service = service_module.Service('roundcube', name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
helper.call('post', app.enable)
-def is_enabled():
- """Return whether the module is enabled."""
- return app.is_enabled()
-
-
-def enable():
- """Enable the module."""
- app.enable()
-
-
-def disable():
- """Enable the module."""
- app.disable()
-
-
def diagnose():
"""Run diagnostics and return the results."""
results = []
diff --git a/plinth/modules/roundcube/urls.py b/plinth/modules/roundcube/urls.py
index ebc730e76..a9c29fda5 100644
--- a/plinth/modules/roundcube/urls.py
+++ b/plinth/modules/roundcube/urls.py
@@ -21,15 +21,14 @@ URLs for the Roundcube module.
from django.conf.urls import url
from plinth.modules import roundcube
-from plinth.views import ServiceView
+from plinth.views import AppView
urlpatterns = [
- url(r'^apps/roundcube/$',
- ServiceView.as_view(
- service_id="roundcube",
- diagnostics_module_name="roundcube",
- description=roundcube.description,
- show_status_block=False,
- manual_page=roundcube.manual_page,
- ), name='index'),
+ url(
+ r'^apps/roundcube/$',
+ AppView.as_view(app_id='roundcube', name=roundcube.name,
+ diagnostics_module_name='roundcube',
+ description=roundcube.description,
+ show_status_block=False,
+ manual_page=roundcube.manual_page), name='index'),
]
diff --git a/plinth/modules/searx/__init__.py b/plinth/modules/searx/__init__.py
index 9b8d6a1c0..3fd554568 100644
--- a/plinth/modules/searx/__init__.py
+++ b/plinth/modules/searx/__init__.py
@@ -25,7 +25,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.apache.components import Uwsgi, Webserver
from plinth.modules.firewall.components import Firewall
from plinth.modules.users import register_group
@@ -36,8 +36,6 @@ clients = clients
version = 3
-managed_services = ['searx']
-
managed_packages = ['searx', 'uwsgi', 'uwsgi-plugin-python3']
name = _('Searx')
@@ -53,8 +51,6 @@ description = [
group = ('web-search', _('Search the web'))
-service = None
-
manual_page = 'Searx'
app = None
@@ -119,15 +115,9 @@ def init():
app = SearxApp()
register_group(group)
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(managed_services[0], name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
-
- if is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
def setup(helper, old_version=None):
@@ -135,18 +125,10 @@ def setup(helper, old_version=None):
helper.install(managed_packages)
helper.call('post', actions.superuser_run, 'searx', ['setup'])
if not old_version or old_version < 3:
- helper.call('post', actions.superuser_run, 'searx', ['enable'])
helper.call('post', actions.superuser_run, 'searx',
['disable-public-access'])
+ helper.call('post', app.enable)
app.set_shortcut_login_required(True)
- app.enable()
-
- global service
- if service is None:
- service = service_module.Service(managed_services[0], name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
- helper.call('post', app.enable)
def get_safe_search_setting():
@@ -160,21 +142,6 @@ def is_public_access_enabled():
return os.path.exists(PUBLIC_ACCESS_SETTING_FILE)
-def is_enabled():
- """Return whether the module is enabled."""
- return app.is_enabled()
-
-
-def enable():
- """Enable the module."""
- app.enable()
-
-
-def disable():
- """Disable the module."""
- app.disable()
-
-
def diagnose():
"""Run diagnostics and return the results."""
results = []
diff --git a/plinth/modules/searx/forms.py b/plinth/modules/searx/forms.py
index 68c66177c..60821f3b3 100644
--- a/plinth/modules/searx/forms.py
+++ b/plinth/modules/searx/forms.py
@@ -21,10 +21,10 @@ Django form for configuring Searx.
from django import forms
from django.utils.translation import ugettext_lazy as _
-from plinth.forms import ServiceForm
+from plinth.forms import AppForm
-class SearxForm(ServiceForm):
+class SearxForm(AppForm):
"""Searx configuration form."""
safe_search = forms.ChoiceField(
label=_('Safe Search'), help_text=_(
diff --git a/plinth/modules/searx/urls.py b/plinth/modules/searx/urls.py
index 66307c8e9..c837e8142 100644
--- a/plinth/modules/searx/urls.py
+++ b/plinth/modules/searx/urls.py
@@ -20,8 +20,8 @@ URLs for the Searx module.
from django.conf.urls import url
-from .views import SearxServiceView
+from .views import SearxAppView
urlpatterns = [
- url(r'^apps/searx/$', SearxServiceView.as_view(), name='index'),
+ url(r'^apps/searx/$', SearxAppView.as_view(), name='index'),
]
diff --git a/plinth/modules/searx/views.py b/plinth/modules/searx/views.py
index aacf1f9a0..d4b5b48f3 100644
--- a/plinth/modules/searx/views.py
+++ b/plinth/modules/searx/views.py
@@ -23,29 +23,28 @@ from django.utils.translation import ugettext as _
from plinth import actions, views
from plinth.errors import ActionError
-from plinth.modules.searx import (clients, description, disable_public_access,
- enable_public_access,
- get_safe_search_setting, is_enabled,
- is_public_access_enabled, manual_page)
+from plinth.modules import searx
from .forms import SearxForm
-class SearxServiceView(views.ServiceView):
+class SearxAppView(views.AppView):
"""Serve configuration page."""
- clients = clients
- description = description
+ clients = searx.clients
+ name = searx.name
+ description = searx.description
diagnostics_module_name = 'searx'
- service_id = 'searx'
+ app_id = 'searx'
form_class = SearxForm
show_status_block = False
- manual_page = manual_page
+ manual_page = searx.manual_page
def get_initial(self):
"""Return the status of the service to fill in the form."""
initial = super().get_initial()
- initial['safe_search'] = get_safe_search_setting()
- initial['public_access'] = is_public_access_enabled() and is_enabled()
+ initial['safe_search'] = searx.get_safe_search_setting()
+ initial['public_access'] = searx.is_public_access_enabled() and \
+ searx.app.is_enabled()
return initial
def form_valid(self, form):
@@ -65,9 +64,9 @@ class SearxServiceView(views.ServiceView):
if old_data['public_access'] != form_data['public_access']:
try:
if form_data['public_access']:
- enable_public_access()
+ searx.enable_public_access()
else:
- disable_public_access()
+ searx.disable_public_access()
messages.success(self.request, _('Configuration updated.'))
except ActionError:
messages.error(self.request,
diff --git a/plinth/modules/security/templates/security.html b/plinth/modules/security/templates/security.html
index f3b84f011..3e4a999c0 100644
--- a/plinth/modules/security/templates/security.html
+++ b/plinth/modules/security/templates/security.html
@@ -1,4 +1,4 @@
-{% extends "simple_service.html" %}
+{% extends "simple_app.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/shaarli/__init__.py b/plinth/modules/shaarli/__init__.py
index 4c0069dfd..e7871af5a 100644
--- a/plinth/modules/shaarli/__init__.py
+++ b/plinth/modules/shaarli/__init__.py
@@ -22,7 +22,6 @@ from django.utils.translation import ugettext_lazy as _
from plinth import app as app_module
from plinth import frontpage, menu
-from plinth import service as service_module
from plinth.modules.apache.components import Webserver
from plinth.modules.firewall.components import Firewall
@@ -46,8 +45,6 @@ description = [
clients = clients
-service = None
-
manual_page = 'Shaarli'
app = None
@@ -85,38 +82,12 @@ def init():
global app
app = ShaarliApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service('shaarli', name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
-
- if is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.install(managed_packages)
- global service
- if service is None:
- service = service_module.Service('shaarli', name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
helper.call('post', app.enable)
-
-
-def is_enabled():
- """Return whether the module is enabled."""
- return app.is_enabled()
-
-
-def enable():
- """Enable the module."""
- app.enable()
-
-
-def disable():
- """Enable the module."""
- app.disable()
diff --git a/plinth/modules/shaarli/urls.py b/plinth/modules/shaarli/urls.py
index 09478b1d5..5bfaa73a5 100644
--- a/plinth/modules/shaarli/urls.py
+++ b/plinth/modules/shaarli/urls.py
@@ -21,12 +21,13 @@ URLs for the Shaarli module.
from django.conf.urls import url
from plinth.modules import shaarli
-from plinth.views import ServiceView
+from plinth.views import AppView
urlpatterns = [
- url(r'^apps/shaarli/$',
- ServiceView.as_view(
- service_id="shaarli", description=shaarli.description,
- show_status_block=False, manual_page=shaarli.manual_page),
- name='index'),
+ url(
+ r'^apps/shaarli/$',
+ AppView.as_view(app_id='shaarli', name=shaarli.name,
+ description=shaarli.description,
+ show_status_block=False,
+ manual_page=shaarli.manual_page), name='index'),
]
diff --git a/plinth/modules/shadowsocks/__init__.py b/plinth/modules/shadowsocks/__init__.py
index ecdab7d9a..aa41082db 100644
--- a/plinth/modules/shadowsocks/__init__.py
+++ b/plinth/modules/shadowsocks/__init__.py
@@ -24,7 +24,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import cfg, frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.firewall.components import Firewall
from plinth.utils import format_lazy
@@ -36,8 +36,6 @@ name = _('Shadowsocks')
short_description = _('Socks5 Proxy')
-service = None
-
managed_services = ['shadowsocks-libev-local@freedombox']
managed_packages = ['shadowsocks-libev']
@@ -86,58 +84,27 @@ class ShadowsocksApp(app_module.App):
is_external=False)
self.add(firewall)
+ daemon = Daemon('daemon-shadowsocks', managed_services[0])
+ self.add(daemon)
+
def init():
"""Intialize the module."""
global app
app = ShadowsocksApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(
- 'shadowsocks', name, is_enabled=is_enabled, is_running=is_running,
- enable=enable, disable=disable)
-
- if service.is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.install(managed_packages)
helper.call('post', actions.superuser_run, 'shadowsocks', ['setup'])
- global service
- if service is None:
- service = service_module.Service(
- 'shadowsocks', name, is_enabled=is_enabled, is_running=is_running,
- enable=enable, disable=disable)
-
helper.call('post', app.enable)
-def is_enabled():
- """Return whether service is enabled."""
- return action_utils.service_is_enabled(managed_services[0])
-
-
-def is_running():
- """Return whether service is running."""
- return action_utils.service_is_running(managed_services[0])
-
-
-def enable():
- """Enable service."""
- actions.superuser_run('service', ['enable', managed_services[0]])
- app.enable()
-
-
-def disable():
- """Disable service."""
- actions.superuser_run('service', ['disable', managed_services[0]])
- app.disable()
-
-
def diagnose():
"""Run diagnostics and return the results."""
results = []
diff --git a/plinth/modules/shadowsocks/forms.py b/plinth/modules/shadowsocks/forms.py
index b06f6e08b..761a56cc2 100644
--- a/plinth/modules/shadowsocks/forms.py
+++ b/plinth/modules/shadowsocks/forms.py
@@ -21,26 +21,20 @@ FreedomBox app for configuring Shadowsocks.
from django import forms
from django.utils.translation import ugettext_lazy as _
-from plinth.forms import ServiceForm
+from plinth.forms import AppForm
from plinth.utils import format_lazy
-METHODS = [
- ('chacha20-ietf-poly1305',
- format_lazy('chacha20-ietf-poly1305 ({})', _('Recommended'))),
- ('aes-256-gcm', format_lazy('aes-256-gcm ({})', _('Recommended'))),
- ('aes-192-gcm', 'aes-192-gcm'),
- ('aes-128-gcm', 'aes-128-gcm'),
- ('aes-128-ctr', 'aes-128-ctr'),
- ('aes-192-ctr', 'aes-192-ctr'),
- ('aes-256-ctr', 'aes-256-ctr'),
- ('aes-128-cfb', 'aes-128-cfb'),
- ('aes-192-cfb', 'aes-192-cfb'),
- ('aes-256-cfb', 'aes-256-cfb'),
- ('camellia-128-cfb', 'camellia-128-cfb'),
- ('camellia-192-cfb', 'camellia-192-cfb'),
- ('camellia-256-cfb', 'camellia-256-cfb'),
- ('chacha20-ietf', 'chacha20-ietf')
-]
+METHODS = [('chacha20-ietf-poly1305',
+ format_lazy('chacha20-ietf-poly1305 ({})', _('Recommended'))),
+ ('aes-256-gcm', format_lazy('aes-256-gcm ({})', _('Recommended'))),
+ ('aes-192-gcm', 'aes-192-gcm'), ('aes-128-gcm', 'aes-128-gcm'),
+ ('aes-128-ctr', 'aes-128-ctr'), ('aes-192-ctr', 'aes-192-ctr'),
+ ('aes-256-ctr', 'aes-256-ctr'), ('aes-128-cfb', 'aes-128-cfb'),
+ ('aes-192-cfb', 'aes-192-cfb'), ('aes-256-cfb', 'aes-256-cfb'),
+ ('camellia-128-cfb', 'camellia-128-cfb'),
+ ('camellia-192-cfb', 'camellia-192-cfb'),
+ ('camellia-256-cfb', 'camellia-256-cfb'),
+ ('chacha20-ietf', 'chacha20-ietf')]
class TrimmedCharField(forms.CharField):
@@ -54,24 +48,19 @@ class TrimmedCharField(forms.CharField):
return super(TrimmedCharField, self).clean(value)
-class ShadowsocksForm(ServiceForm):
+class ShadowsocksForm(AppForm):
"""Shadowsocks configuration form"""
server = TrimmedCharField(
- label=_('Server'),
- help_text=_('Server hostname or IP address'))
+ label=_('Server'), help_text=_('Server hostname or IP address'))
server_port = forms.IntegerField(
- label=_('Server port'),
- min_value=0,
- max_value=65535,
+ label=_('Server port'), min_value=0, max_value=65535,
help_text=_('Server port number'))
password = forms.CharField(
- label=_('Password'),
- help_text=_('Password used to encrypt data. '
- 'Must match server password.'))
+ label=_('Password'), help_text=_('Password used to encrypt data. '
+ 'Must match server password.'))
method = forms.ChoiceField(
- label=_('Method'),
- choices=METHODS,
+ label=_('Method'), choices=METHODS,
help_text=_('Encryption method. Must match setting on server.'))
diff --git a/plinth/modules/shadowsocks/urls.py b/plinth/modules/shadowsocks/urls.py
index bad1efa80..7551edad2 100644
--- a/plinth/modules/shadowsocks/urls.py
+++ b/plinth/modules/shadowsocks/urls.py
@@ -14,16 +14,14 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
URLs for the Shadowsocks module.
"""
from django.conf.urls import url
-from .views import ShadowsocksServiceView
+from .views import ShadowsocksAppView
urlpatterns = [
- url(r'^apps/shadowsocks/$', ShadowsocksServiceView.as_view(),
- name='index'),
+ url(r'^apps/shadowsocks/$', ShadowsocksAppView.as_view(), name='index'),
]
diff --git a/plinth/modules/shadowsocks/views.py b/plinth/modules/shadowsocks/views.py
index 282b81d8a..d9e13928d 100644
--- a/plinth/modules/shadowsocks/views.py
+++ b/plinth/modules/shadowsocks/views.py
@@ -30,30 +30,29 @@ from plinth.modules import shadowsocks
from .forms import ShadowsocksForm
-class ShadowsocksServiceView(views.ServiceView):
+class ShadowsocksAppView(views.AppView):
"""Configuration view for Shadowsocks local socks5 proxy."""
- service_id = 'shadowsocks'
+ app_id = 'shadowsocks'
diagnostics_module_name = 'shadowsocks'
form_class = ShadowsocksForm
+ name = shadowsocks.name
description = shadowsocks.description
manual_page = shadowsocks.manual_page
def get_initial(self, *args, **kwargs):
"""Get initial values for form."""
+ status = super().get_initial()
try:
configuration = actions.superuser_run('shadowsocks',
['get-config'])
- status = json.loads(configuration)
+ status.update(json.loads(configuration))
except ActionError:
- status = {
+ status.update({
'server': '',
'server_port': 8388,
'password': '',
'method': 'chacha20-ietf-poly1305',
- }
-
- status['is_enabled'] = self.service.is_enabled()
- status['is_running'] = self.service.is_running()
+ })
return status
diff --git a/plinth/modules/snapshot/__init__.py b/plinth/modules/snapshot/__init__.py
index 66f982c6c..2c1c81e0b 100644
--- a/plinth/modules/snapshot/__init__.py
+++ b/plinth/modules/snapshot/__init__.py
@@ -50,8 +50,6 @@ description = [
'they can only be stored on the same partition. ')
]
-service = None
-
manual_page = 'Snapshots'
DEFAULT_FILE = '/etc/default/snapper'
@@ -79,10 +77,9 @@ def init():
global app
app = SnapshotApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- app.set_enabled(True) # XXX: Perform better checks
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
def is_supported():
diff --git a/plinth/modules/snapshot/templates/snapshot.html b/plinth/modules/snapshot/templates/snapshot.html
index 79e55a02f..e1543326c 100644
--- a/plinth/modules/snapshot/templates/snapshot.html
+++ b/plinth/modules/snapshot/templates/snapshot.html
@@ -1,4 +1,4 @@
-{% extends "service-subsubmenu.html" %}
+{% extends "app-subsubmenu.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/snapshot/templates/snapshot_manage.html b/plinth/modules/snapshot/templates/snapshot_manage.html
index a8a24d0ba..4af1e3ae2 100644
--- a/plinth/modules/snapshot/templates/snapshot_manage.html
+++ b/plinth/modules/snapshot/templates/snapshot_manage.html
@@ -1,4 +1,4 @@
-{% extends "service-subsubmenu.html" %}
+{% extends "app-subsubmenu.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/snapshot/templates/snapshot_not_supported.html b/plinth/modules/snapshot/templates/snapshot_not_supported.html
index f555a0d08..5d97732ff 100644
--- a/plinth/modules/snapshot/templates/snapshot_not_supported.html
+++ b/plinth/modules/snapshot/templates/snapshot_not_supported.html
@@ -1,4 +1,4 @@
-{% extends "service-subsubmenu.html" %}
+{% extends "app-subsubmenu.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/ssh/__init__.py b/plinth/modules/ssh/__init__.py
index dabf47083..56019ad1a 100644
--- a/plinth/modules/ssh/__init__.py
+++ b/plinth/modules/ssh/__init__.py
@@ -23,9 +23,9 @@ from django.utils.translation import ugettext_lazy as _
from plinth import actions
from plinth import app as app_module
from plinth import menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.firewall.components import Firewall
-from plinth.views import ServiceView
+from plinth.views import AppView
from .manifest import backup
@@ -46,8 +46,6 @@ description = [
'using such connections.')
]
-service = None
-
port_forwarding_info = [('TCP', 22)]
app = None
@@ -69,6 +67,9 @@ class SSHApp(app_module.App):
is_external=True)
self.add(firewall)
+ daemon = Daemon('daemon-ssh', managed_services[0])
+ self.add(daemon)
+
def init():
"""Intialize the ssh module."""
@@ -76,16 +77,14 @@ def init():
app = SSHApp()
app.set_enabled(True)
- global service
- service = service_module.Service(managed_services[0], name)
-
def setup(helper, old_version=None):
"""Configure the module."""
actions.superuser_run('ssh', ['setup'])
-class SshServiceView(ServiceView):
- service_id = managed_services[0]
+class SshAppView(AppView):
+ app_id = 'ssh'
+ name = name
description = description
port_forwarding_info = port_forwarding_info
diff --git a/plinth/modules/ssh/urls.py b/plinth/modules/ssh/urls.py
index 19fd8c144..e8b1264d3 100644
--- a/plinth/modules/ssh/urls.py
+++ b/plinth/modules/ssh/urls.py
@@ -14,16 +14,14 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
URLs for the Secure Shell Server module.
"""
from django.conf.urls import url
-from plinth.modules.ssh import SshServiceView
-
+from plinth.modules.ssh import SshAppView
urlpatterns = [
- url(r'^sys/ssh/$', SshServiceView.as_view(), name='index'),
+ url(r'^sys/ssh/$', SshAppView.as_view(), name='index'),
]
diff --git a/plinth/modules/storage/__init__.py b/plinth/modules/storage/__init__.py
index 4330fca7c..03e4664c3 100644
--- a/plinth/modules/storage/__init__.py
+++ b/plinth/modules/storage/__init__.py
@@ -25,9 +25,8 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
-from plinth import cfg, menu
-from plinth import service as service_module
-from plinth import utils
+from plinth import cfg, menu, utils
+from plinth.daemon import Daemon
from plinth.errors import PlinthError
from plinth.utils import format_lazy, import_from_gi
@@ -47,8 +46,6 @@ description = [
box_name=_(cfg.box_name))
]
-service = None
-
logger = logging.getLogger(__name__)
manual_page = 'Storage'
@@ -70,6 +67,9 @@ class StorageApp(app_module.App):
'storage:index', parent_url_name='system')
self.add(menu_item)
+ daemon = Daemon('daemon-udiskie', managed_services[0])
+ self.add(daemon)
+
def init():
"""Intialize the module."""
@@ -271,37 +271,10 @@ def get_error_message(error):
return message
-def is_running():
- """Return whether the service is running."""
- return action_utils.service_is_running('freedombox-udiskie')
-
-
-def is_enabled():
- """Return whether the module is enabled."""
- return action_utils.service_is_enabled('freedombox-udiskie')
-
-
-def enable():
- """Enable the module."""
- actions.superuser_run('udiskie', ['enable'])
- app.enable()
-
-
-def disable():
- """Disable the module."""
- actions.superuser_run('udiskie', ['disable'])
- app.disable()
-
-
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.install(managed_packages, skip_recommends=True)
- helper.call('post', actions.superuser_run, 'udiskie', ['enable'])
- global service
- if service is None:
- service = service_module.Service(
- managed_services[0], name, is_enabled=is_enabled, enable=enable,
- disable=disable, is_running=is_running)
+ helper.call('post', app.enable)
disks = get_disks()
root_device = get_root_device(disks)
if is_expandable(root_device):
diff --git a/plinth/modules/syncthing/__init__.py b/plinth/modules/syncthing/__init__.py
index 94eb60639..da5d3609e 100644
--- a/plinth/modules/syncthing/__init__.py
+++ b/plinth/modules/syncthing/__init__.py
@@ -23,7 +23,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import cfg, frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.apache.components import Webserver
from plinth.modules.firewall.components import Firewall
from plinth.modules.users import register_group
@@ -63,8 +63,6 @@ clients = clients
group = ('syncthing', _('Administer Syncthing application'))
-service = None
-
manual_page = 'Syncthing'
app = None
@@ -96,6 +94,9 @@ class SyncthingApp(app_module.App):
webserver = Webserver('webserver-syncthing', 'syncthing-plinth')
self.add(webserver)
+ daemon = Daemon('daemon-syncthing', managed_services[0])
+ self.add(daemon)
+
def init():
"""Intialize the module."""
@@ -103,52 +104,18 @@ def init():
app = SyncthingApp()
register_group(group)
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(
- managed_services[0], name, is_enabled=is_enabled, enable=enable,
- disable=disable, is_running=is_running)
-
- if is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.install(managed_packages)
- helper.call('post', actions.superuser_run, 'syncthing', ['enable'])
- global service
- if service is None:
- service = service_module.Service(
- managed_services[0], name, is_enabled=is_enabled, enable=enable,
- disable=disable, is_running=is_running)
+ helper.call('post', actions.superuser_run, 'syncthing', ['setup'])
helper.call('post', app.enable)
-def is_running():
- """Return whether the service is running."""
- return action_utils.service_is_running('syncthing@syncthing')
-
-
-def is_enabled():
- """Return whether the module is enabled."""
- return (action_utils.service_is_enabled('syncthing@syncthing')
- and app.is_enabled())
-
-
-def enable():
- """Enable the module."""
- actions.superuser_run('syncthing', ['enable'])
- app.enable()
-
-
-def disable():
- """Enable the module."""
- actions.superuser_run('syncthing', ['disable'])
- app.disable()
-
-
def diagnose():
"""Run diagnostics and return the results."""
results = []
diff --git a/plinth/modules/syncthing/urls.py b/plinth/modules/syncthing/urls.py
index 71154f50e..63a7bee1e 100644
--- a/plinth/modules/syncthing/urls.py
+++ b/plinth/modules/syncthing/urls.py
@@ -21,12 +21,13 @@ URLs for the Syncthing module.
from django.conf.urls import url
from plinth.modules import syncthing
-from plinth.views import ServiceView
+from plinth.views import AppView
urlpatterns = [
- url(r'^apps/syncthing/$',
- ServiceView.as_view(
- service_id=syncthing.managed_services[0],
+ url(
+ r'^apps/syncthing/$',
+ AppView.as_view(
+ app_id='syncthing', name=syncthing.name,
diagnostics_module_name='syncthing',
description=syncthing.description, clients=syncthing.clients,
manual_page=syncthing.manual_page, show_status_block=True),
diff --git a/plinth/modules/tahoe/__init__.py b/plinth/modules/tahoe/__init__.py
index 8f5cf34c2..5dac44462 100644
--- a/plinth/modules/tahoe/__init__.py
+++ b/plinth/modules/tahoe/__init__.py
@@ -26,7 +26,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import cfg, frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.apache.components import Webserver
from plinth.modules.firewall.components import Firewall
from plinth.utils import format_lazy
@@ -44,8 +44,6 @@ name = _('Tahoe-LAFS')
short_description = _('Distributed File Storage')
-service = None
-
port_forwarding_info = [
('TCP', 3456),
('TCP', 5678),
@@ -88,6 +86,9 @@ class TahoeApp(app_module.App):
webserver = Webserver('webserver-tahoe', 'tahoe-plinth')
self.add(webserver)
+ daemon = Daemon('daemon-tahoe', managed_services[0])
+ self.add(daemon)
+
class Shortcut(frontpage.Shortcut):
"""Frontpage shortcut to use configured domain name for URL."""
@@ -131,15 +132,10 @@ def init():
global app
app = TahoeApp()
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup' and is_setup():
- service = service_module.Service(
- managed_services[0], name, is_enabled=is_enabled, enable=enable,
- disable=disable, is_running=is_running)
-
- if is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and is_setup() \
+ and app.is_enabled():
+ app.set_enabled(True)
def setup(helper, old_version=None):
@@ -151,44 +147,14 @@ def post_setup(configured_domain_name):
"""Actions to be performed after installing tahoe-lafs package."""
actions.superuser_run('tahoe-lafs',
['setup', '--domain-name', configured_domain_name])
- actions.superuser_run('tahoe-lafs', ['enable'])
actions.run_as_user('tahoe-lafs', ['create-introducer'],
become_user='tahoe-lafs')
actions.run_as_user('tahoe-lafs', ['create-storage-node'],
become_user='tahoe-lafs')
actions.superuser_run('tahoe-lafs', ['autostart'])
-
- global service
- if service is None:
- service = service_module.Service(
- managed_services[0], name, is_enabled=is_enabled, enable=enable,
- disable=disable, is_running=is_running)
app.enable()
-def is_running():
- """Return whether the service is running."""
- return action_utils.service_is_running(managed_services[0])
-
-
-def is_enabled():
- """Return whether the module is enabled."""
- return (action_utils.service_is_enabled(managed_services[0])
- and app.is_enabled())
-
-
-def enable():
- """Enable the module."""
- actions.superuser_run('tahoe-lafs', ['enable'])
- app.enable()
-
-
-def disable():
- """Enable the module."""
- actions.superuser_run('tahoe-lafs', ['disable'])
- app.disable()
-
-
def diagnose():
"""Run diagnostics and return the results."""
return [
diff --git a/plinth/modules/tahoe/templates/tahoe-post-setup.html b/plinth/modules/tahoe/templates/tahoe-post-setup.html
index 1cf79dae4..bd3a511a8 100644
--- a/plinth/modules/tahoe/templates/tahoe-post-setup.html
+++ b/plinth/modules/tahoe/templates/tahoe-post-setup.html
@@ -1,4 +1,4 @@
-{% extends "service.html" %}
+{% extends "app.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/tahoe/urls.py b/plinth/modules/tahoe/urls.py
index a74c0b23c..784068e27 100644
--- a/plinth/modules/tahoe/urls.py
+++ b/plinth/modules/tahoe/urls.py
@@ -21,7 +21,7 @@ URLs for the Tahoe-LAFS module.
from django.conf.urls import url
from . import views
-from .views import TahoeServiceView, TahoeSetupView
+from .views import TahoeAppView, TahoeSetupView
urlpatterns = [
url(r'^apps/tahoe/setup/$', TahoeSetupView.as_view(), name='setup'),
@@ -29,5 +29,5 @@ urlpatterns = [
name='add-introducer'),
url(r'^apps/tahoe/remove_introducer/(?P[0-9a-zA-Z_]+)/$',
views.remove_introducer, name='remove-introducer'),
- url(r'^apps/tahoe/$', TahoeServiceView.as_view(), name='index')
+ url(r'^apps/tahoe/$', TahoeAppView.as_view(), name='index')
]
diff --git a/plinth/modules/tahoe/views.py b/plinth/modules/tahoe/views.py
index af042a0ba..e9612f1b5 100644
--- a/plinth/modules/tahoe/views.py
+++ b/plinth/modules/tahoe/views.py
@@ -24,7 +24,7 @@ from django.views.generic import FormView
from plinth.forms import DomainSelectionForm
from plinth.modules import tahoe
from plinth.utils import get_domain_names
-from plinth.views import ServiceView
+from plinth.views import AppView
class TahoeSetupView(FormView):
@@ -49,10 +49,11 @@ class TahoeSetupView(FormView):
return context
-class TahoeServiceView(ServiceView):
+class TahoeAppView(AppView):
"""Show tahoe-lafs service page."""
- service_id = tahoe.managed_services[0]
+ app_id = 'tahoe'
template_name = 'tahoe-post-setup.html'
+ name = tahoe.name
description = tahoe.description
diagnostics_module_name = 'tahoe'
port_forwarding_info = tahoe.port_forwarding_info
diff --git a/plinth/modules/tor/__init__.py b/plinth/modules/tor/__init__.py
index 0b80074ca..823051cb2 100644
--- a/plinth/modules/tor/__init__.py
+++ b/plinth/modules/tor/__init__.py
@@ -25,7 +25,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.firewall.components import Firewall
from plinth.modules.names import SERVICES
from plinth.signals import domain_added, domain_removed
@@ -41,6 +41,8 @@ managed_packages = [
'tor', 'tor-geoipdb', 'torsocks', 'obfs4proxy', 'apt-transport-tor'
]
+managed_services = ['tor@plinth']
+
name = _('Tor')
short_description = _('Anonymity Network')
@@ -58,9 +60,6 @@ clients = clients
reserved_usernames = ['debian-tor']
-socks_service = None
-bridge_service = None
-
manual_page = 'Tor'
app = None
@@ -87,6 +86,9 @@ class TorApp(app_module.App):
'tor-obfs4'], is_external=True)
self.add(firewall)
+ daemon = Daemon('daemon-tor', managed_services[0], strict_check=True)
+ self.add(daemon)
+
def init():
"""Initialize the module."""
@@ -97,20 +99,9 @@ def init():
needs_setup = setup_helper.get_state() == 'needs-setup'
if not needs_setup:
- if utils.is_enabled():
+ if app.is_enabled():
app.set_enabled(True)
- global socks_service
- socks_service = service_module.Service(
- 'tor-socks', _('Tor Socks Proxy'), is_enabled=utils.is_enabled,
- is_running=utils.is_running)
-
- global bridge_service
- bridge_service = service_module.Service('tor-bridge',
- _('Tor Bridge Relay'),
- is_enabled=utils.is_enabled,
- is_running=utils.is_running)
-
# Register hidden service name with Name Services module.
status = utils.get_status()
hostname = status['hs_hostname']
@@ -141,44 +132,10 @@ def setup(helper, old_version=None):
helper.call('post', actions.superuser_run, 'tor',
['configure', '--apt-transport-tor', 'enable'])
- global socks_service
- if socks_service is None:
- socks_service = service_module.Service('tor-socks',
- _('Tor Anonymity Network'),
- is_enabled=utils.is_enabled,
- is_running=utils.is_running)
-
- global bridge_service
- if bridge_service is None:
- bridge_service = service_module.Service('tor-bridge',
- _('Tor Bridge Relay'),
- is_enabled=utils.is_enabled,
- is_running=utils.is_running)
-
helper.call('post', update_hidden_service_domain)
helper.call('post', app.enable)
-def enable():
- """Enable the app.
-
- XXX: Currently performs only partial activities while the rest happens
- elsewhere.
-
- """
- app.enable()
-
-
-def disable():
- """Enable the app.
-
- XXX: Currently performs only partial activities while the rest happens
- elsewhere.
-
- """
- app.disable()
-
-
def update_hidden_service_domain(status=None):
"""Update HS domain with Name Services module."""
if not status:
diff --git a/plinth/modules/tor/templates/tor.html b/plinth/modules/tor/templates/tor.html
index 8d7250011..3f369c7aa 100644
--- a/plinth/modules/tor/templates/tor.html
+++ b/plinth/modules/tor/templates/tor.html
@@ -1,4 +1,4 @@
-{% extends "simple_service.html" %}
+{% extends "simple_app.html" %}
{% comment %}
#
# This file is part of FreedomBox.
@@ -83,7 +83,7 @@
{% endif %}
- {% include "internal-zone.html" with service=socks_service %}
+ {% include "internal-zone.html" %}
{% trans "Configuration" %}
diff --git a/plinth/modules/tor/utils.py b/plinth/modules/tor/utils.py
index a87ffad4d..dc93d42b5 100644
--- a/plinth/modules/tor/utils.py
+++ b/plinth/modules/tor/utils.py
@@ -14,36 +14,26 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
Tor utility functions
"""
-import augeas
import glob
import itertools
import json
-from plinth import actions
-from plinth import action_utils
-from plinth.modules.names import SERVICES
+import augeas
+from plinth import actions
+from plinth.daemon import app_is_running
+from plinth.modules import tor
+from plinth.modules.names import SERVICES
APT_SOURCES_URI_PATHS = ('/files/etc/apt/sources.list/*/uri',
'/files/etc/apt/sources.list.d/*/*/uri')
APT_TOR_PREFIX = 'tor+'
-def is_enabled():
- """Return whether the module is enabled."""
- return action_utils.service_is_enabled('tor@plinth', strict_check=True)
-
-
-def is_running():
- """Return whether the service is running."""
- return action_utils.service_is_running('tor@plinth')
-
-
def get_status():
"""Return current Tor status."""
output = actions.superuser_run('tor', ['get-status'])
@@ -57,32 +47,34 @@ def get_status():
hs_services.append(service_type[0])
# Filter out obfs3/4 ports when bridge relay is disabled
- ports = {service_type: port
- for service_type, port in status['ports'].items()
- if service_type not in ['obfs4', 'obfs3'] or
- status['bridge_relay_enabled']}
+ ports = {
+ service_type: port
+ for service_type, port in status['ports'].items()
+ if service_type not in ['obfs4', 'obfs3']
+ or status['bridge_relay_enabled']
+ }
- return {'enabled': is_enabled(),
- 'is_running': is_running(),
- 'use_upstream_bridges': status['use_upstream_bridges'],
- 'upstream_bridges': status['upstream_bridges'],
- 'relay_enabled': status['relay_enabled'],
- 'bridge_relay_enabled': status['bridge_relay_enabled'],
- 'ports': ports,
- 'hs_enabled': hs_info['enabled'],
- 'hs_status': hs_info['status'],
- 'hs_hostname': hs_info['hostname'],
- 'hs_ports': hs_info['ports'],
- 'hs_services': hs_services,
- 'apt_transport_tor_enabled':
- is_apt_transport_tor_enabled()
- }
+ return {
+ 'enabled': tor.app.is_enabled(),
+ 'is_running': app_is_running(tor.app),
+ 'use_upstream_bridges': status['use_upstream_bridges'],
+ 'upstream_bridges': status['upstream_bridges'],
+ 'relay_enabled': status['relay_enabled'],
+ 'bridge_relay_enabled': status['bridge_relay_enabled'],
+ 'ports': ports,
+ 'hs_enabled': hs_info['enabled'],
+ 'hs_status': hs_info['status'],
+ 'hs_hostname': hs_info['hostname'],
+ 'hs_ports': hs_info['ports'],
+ 'hs_services': hs_services,
+ 'apt_transport_tor_enabled': is_apt_transport_tor_enabled()
+ }
def iter_apt_uris(aug):
"""Iterate over all the APT source URIs."""
- return itertools.chain.from_iterable([aug.match(path)
- for path in APT_SOURCES_URI_PATHS])
+ return itertools.chain.from_iterable(
+ [aug.match(path) for path in APT_SOURCES_URI_PATHS])
def get_real_apt_uri_path(aug, path):
@@ -109,8 +101,8 @@ def get_real_apt_uri_path(aug, path):
def get_augeas():
"""Return an instance of Augeaus for processing APT configuration."""
- aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
- augeas.Augeas.NO_MODL_AUTOLOAD)
+ aug = augeas.Augeas(
+ flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD)
aug.set('/augeas/load/Aptsources/lens', 'Aptsources.lns')
aug.set('/augeas/load/Aptsources/incl[last() + 1]',
'/etc/apt/sources.list')
diff --git a/plinth/modules/tor/views.py b/plinth/modules/tor/views.py
index a6a3da4a0..be1ecc4e4 100644
--- a/plinth/modules/tor/views.py
+++ b/plinth/modules/tor/views.py
@@ -19,11 +19,12 @@ FreedomBox app for configuring Tor.
"""
from django.contrib import messages
from django.template.response import TemplateResponse
-from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import ugettext as _
from plinth import actions
from plinth.errors import ActionError
from plinth.modules import tor
+from plinth.modules.firewall.components import Firewall
from . import utils as tor_utils
from .forms import TorForm
@@ -58,7 +59,7 @@ def index(request):
'status': status,
'config_running': bool(config_process),
'form': form,
- 'socks_service': tor.socks_service
+ 'firewall': tor.app.get_components_of_type(Firewall)
})
@@ -124,10 +125,11 @@ def __apply_changes(request, old_status, new_status):
if old_status['enabled'] != new_status['enabled']:
arg_value = 'enable' if new_status['enabled'] else 'disable'
arguments.extend(['--service', arg_value])
+ # XXX: Perform app enable/disable within the background process
if new_status['enabled']:
- tor.enable()
+ tor.app.enable()
else:
- tor.disable()
+ tor.app.disable()
config_process = actions.superuser_run(
'tor', ['configure'] + arguments, run_in_background=True)
diff --git a/plinth/modules/transmission/__init__.py b/plinth/modules/transmission/__init__.py
index 689a0152e..be5c47b55 100644
--- a/plinth/modules/transmission/__init__.py
+++ b/plinth/modules/transmission/__init__.py
@@ -25,7 +25,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.apache.components import Webserver
from plinth.modules.firewall.components import Firewall
from plinth.modules.users import register_group
@@ -55,8 +55,6 @@ reserved_usernames = ['debian-transmission']
group = ('bit-torrent', _('Download files using BitTorrent applications'))
-service = None
-
manual_page = 'Transmission'
app = None
@@ -88,6 +86,9 @@ class TransmissionApp(app_module.App):
webserver = Webserver('webserver-transmission', 'transmission-plinth')
self.add(webserver)
+ daemon = Daemon('daemon-transmission', managed_services[0])
+ self.add(daemon)
+
def init():
"""Initialize the Transmission module."""
@@ -95,15 +96,9 @@ def init():
app = TransmissionApp()
register_group(group)
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(managed_services[0], name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
-
- if is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
def setup(helper, old_version=None):
@@ -118,33 +113,9 @@ def setup(helper, old_version=None):
['merge-configuration'],
input=json.dumps(new_configuration).encode())
- helper.call('post', actions.superuser_run, 'transmission', ['enable'])
- global service
- if service is None:
- service = service_module.Service(managed_services[0], name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
helper.call('post', app.enable)
-def is_enabled():
- """Return whether the module is enabled."""
- return (action_utils.service_is_enabled('transmission-daemon')
- and app.is_enabled())
-
-
-def enable():
- """Enable the module."""
- actions.superuser_run('transmission', ['enable'])
- app.enable()
-
-
-def disable():
- """Enable the module."""
- actions.superuser_run('transmission', ['disable'])
- app.disable()
-
-
def diagnose():
"""Run diagnostics and return the results."""
results = []
diff --git a/plinth/modules/transmission/forms.py b/plinth/modules/transmission/forms.py
index 590bc6f65..da8f8bcf8 100644
--- a/plinth/modules/transmission/forms.py
+++ b/plinth/modules/transmission/forms.py
@@ -21,10 +21,10 @@ FreedomBox app for configuring Transmission.
from django import forms
from django.utils.translation import ugettext_lazy as _
-from plinth.forms import ServiceForm
+from plinth.forms import AppForm
-class TransmissionForm(ServiceForm): # pylint: disable=W0232
+class TransmissionForm(AppForm): # pylint: disable=W0232
"""Transmission configuration form"""
download_dir = forms.CharField(
label=_('Download directory'),
diff --git a/plinth/modules/transmission/urls.py b/plinth/modules/transmission/urls.py
index 2aec2935b..94d4d38ad 100644
--- a/plinth/modules/transmission/urls.py
+++ b/plinth/modules/transmission/urls.py
@@ -14,17 +14,14 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
URLs for the Transmission module.
"""
from django.conf.urls import url
-from .views import TransmissionServiceView
-
+from .views import TransmissionAppView
urlpatterns = [
- url(r'^apps/transmission/$',
- TransmissionServiceView.as_view(), name='index'),
+ url(r'^apps/transmission/$', TransmissionAppView.as_view(), name='index'),
]
diff --git a/plinth/modules/transmission/views.py b/plinth/modules/transmission/views.py
index b3e1443a7..4a7a73edb 100644
--- a/plinth/modules/transmission/views.py
+++ b/plinth/modules/transmission/views.py
@@ -33,28 +33,28 @@ from .forms import TransmissionForm
logger = logging.getLogger(__name__)
-class TransmissionServiceView(views.ServiceView):
+class TransmissionAppView(views.AppView):
"""Serve configuration page."""
clients = transmission.clients
+ name = transmission.name
description = transmission.description
diagnostics_module_name = 'transmission'
form_class = TransmissionForm
- service_id = transmission.managed_services[0]
+ app_id = 'transmission'
manual_page = transmission.manual_page
def get_initial(self):
"""Get the current settings from Transmission server."""
+ status = super().get_initial()
configuration = actions.superuser_run('transmission',
['get-configuration'])
- status = json.loads(configuration)
- status = {
+ configuration = json.loads(configuration)
+ status.update({
key.translate(str.maketrans({
'-': '_'
})): value
- for key, value in status.items()
- }
- status['is_enabled'] = self.service.is_enabled()
- status['is_running'] = self.service.is_running()
+ for key, value in configuration.items()
+ })
status['hostname'] = socket.gethostname()
return status
diff --git a/plinth/modules/ttrss/__init__.py b/plinth/modules/ttrss/__init__.py
index b51f21f77..7e25e0a1e 100644
--- a/plinth/modules/ttrss/__init__.py
+++ b/plinth/modules/ttrss/__init__.py
@@ -24,7 +24,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth import cfg, frontpage, menu
-from plinth import service as service_module
+from plinth.daemon import Daemon
from plinth.modules.apache.components import Webserver
from plinth.modules.firewall.components import Firewall
from plinth.modules.users import register_group
@@ -62,8 +62,6 @@ clients = clients
group = ('feed-reader', _('Read and subscribe to news feeds'))
-service = None
-
manual_page = 'TinyTinyRSS'
app = None
@@ -94,6 +92,14 @@ class TTRSSApp(app_module.App):
webserver = Webserver('webserver-ttrss', 'tt-rss-plinth')
self.add(webserver)
+ daemon = Daemon('daemon-ttrss', managed_services[0])
+ self.add(daemon)
+
+ def enable(self):
+ """Enable components and API access."""
+ super().enable()
+ actions.superuser_run('ttrss', ['enable-api-access'])
+
def init():
"""Intialize the module."""
@@ -101,15 +107,9 @@ def init():
app = TTRSSApp()
register_group(group)
- global service
setup_helper = globals()['setup_helper']
- if setup_helper.get_state() != 'needs-setup':
- service = service_module.Service(managed_services[0], name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
-
- if is_enabled():
- app.set_enabled(True)
+ if setup_helper.get_state() != 'needs-setup' and app.is_enabled():
+ app.set_enabled(True)
def setup(helper, old_version=None):
@@ -117,12 +117,6 @@ def setup(helper, old_version=None):
helper.call('pre', actions.superuser_run, 'ttrss', ['pre-setup'])
helper.install(managed_packages)
helper.call('post', actions.superuser_run, 'ttrss', ['setup'])
- helper.call('post', actions.superuser_run, 'ttrss', ['enable'])
- global service
- if service is None:
- service = service_module.Service(managed_services[0], name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
helper.call('post', app.enable)
@@ -141,23 +135,6 @@ def force_upgrade(helper, packages):
actions.superuser_run('ttrss', ['setup'])
-def is_enabled():
- """Return whether the module is enabled."""
- return (action_utils.service_is_enabled('tt-rss') and app.is_enabled())
-
-
-def enable():
- """Enable the module."""
- actions.superuser_run('ttrss', ['enable'])
- app.enable()
-
-
-def disable():
- """Enable the module."""
- actions.superuser_run('ttrss', ['disable'])
- app.disable()
-
-
def diagnose():
"""Run diagnostics and return the results."""
results = []
diff --git a/plinth/modules/ttrss/urls.py b/plinth/modules/ttrss/urls.py
index e85d8163d..7321e3216 100644
--- a/plinth/modules/ttrss/urls.py
+++ b/plinth/modules/ttrss/urls.py
@@ -21,13 +21,14 @@ URLs for the Tiny Tiny RSS module.
from django.conf.urls import url
from plinth.modules import ttrss
-from plinth.views import ServiceView
+from plinth.views import AppView
urlpatterns = [
- url(r'^apps/ttrss/$',
- ServiceView.as_view(
- service_id=ttrss.managed_services[0],
- diagnostics_module_name="ttrss", description=ttrss.description,
- clients=ttrss.clients, manual_page=ttrss.manual_page,
- show_status_block=True), name='index'),
+ url(
+ r'^apps/ttrss/$',
+ AppView.as_view(app_id='ttrss', name=ttrss.name,
+ diagnostics_module_name='ttrss',
+ description=ttrss.description, clients=ttrss.clients,
+ manual_page=ttrss.manual_page, show_status_block=True),
+ name='index'),
]
diff --git a/plinth/modules/upgrades/__init__.py b/plinth/modules/upgrades/__init__.py
index 27d3c16ab..8270c382e 100644
--- a/plinth/modules/upgrades/__init__.py
+++ b/plinth/modules/upgrades/__init__.py
@@ -23,7 +23,6 @@ from django.utils.translation import ugettext_lazy as _
from plinth import actions
from plinth import app as app_module
from plinth import menu
-from plinth import service as service_module
from .manifest import backup
@@ -39,8 +38,6 @@ description = [
_('Check for and apply the latest software and security updates.')
]
-service = None
-
manual_page = 'Upgrades'
app = None
@@ -65,11 +62,6 @@ def init():
app = UpgradesApp()
app.set_enabled(True)
- global service
- service = service_module.Service('auto-upgrades', name,
- is_enabled=is_enabled, enable=enable,
- disable=disable)
-
def setup(helper, old_version=None):
"""Install and configure the module."""
diff --git a/plinth/modules/upgrades/templates/upgrades.html b/plinth/modules/upgrades/templates/upgrades.html
index a08381c9a..86aea4f3d 100644
--- a/plinth/modules/upgrades/templates/upgrades.html
+++ b/plinth/modules/upgrades/templates/upgrades.html
@@ -1,4 +1,4 @@
-{% extends 'service-subsubmenu.html' %}
+{% extends 'app-subsubmenu.html' %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/upgrades/templates/upgrades_configure.html b/plinth/modules/upgrades/templates/upgrades_configure.html
index 6d162c2e8..bbe32f5fb 100644
--- a/plinth/modules/upgrades/templates/upgrades_configure.html
+++ b/plinth/modules/upgrades/templates/upgrades_configure.html
@@ -1,4 +1,4 @@
-{% extends "service-subsubmenu.html" %}
+{% extends "app-subsubmenu.html" %}
{% comment %}
#
# This file is part of FreedomBox.
diff --git a/plinth/modules/upgrades/views.py b/plinth/modules/upgrades/views.py
index 2c8a3f2f2..45761df7a 100644
--- a/plinth/modules/upgrades/views.py
+++ b/plinth/modules/upgrades/views.py
@@ -34,10 +34,11 @@ from .forms import ConfigureForm
subsubmenu = [{
'url': reverse_lazy('upgrades:index'),
'text': ugettext_lazy('Auto-update')
-}, {
- 'url': reverse_lazy('upgrades:upgrade'),
- 'text': ugettext_lazy('Manual update')
-}]
+},
+ {
+ 'url': reverse_lazy('upgrades:upgrade'),
+ 'text': ugettext_lazy('Manual update')
+ }]
class UpgradesConfigurationView(FormView):
@@ -56,7 +57,7 @@ class UpgradesConfigurationView(FormView):
return context
def get_initial(self):
- return {'auto_upgrades_enabled': upgrades.service.is_enabled()}
+ return {'auto_upgrades_enabled': upgrades.is_enabled()}
def form_valid(self, form):
"""Apply the form changes."""
@@ -68,15 +69,15 @@ class UpgradesConfigurationView(FormView):
try:
if new_status['auto_upgrades_enabled']:
- upgrades.service.enable()
+ upgrades.enable()
else:
- upgrades.service.disable()
+ upgrades.disable()
except ActionError as exception:
error = exception.args[2]
messages.error(
self.request,
- _('Error when configuring unattended-upgrades: {error}')
- .format(error=error))
+ _('Error when configuring unattended-upgrades: {error}').
+ format(error=error))
if new_status['auto_upgrades_enabled']:
messages.success(self.request, _('Automatic upgrades enabled'))
diff --git a/plinth/service.py b/plinth/service.py
deleted file mode 100644
index 38b35e176..000000000
--- a/plinth/service.py
+++ /dev/null
@@ -1,103 +0,0 @@
-#
-# This file is part of FreedomBox.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-"""
-Framework for working with servers and their services.
-"""
-
-import collections
-
-from plinth import action_utils, actions
-
-services = {}
-
-
-class Service():
- """
- Representation of an application service provided by the machine
- containing information such as current status.
-
- - service_id: unique service name. If possible this should be the name of
- the service's systemd unit file (without the extension).
- - name: service name as to be displayed in the GUI
- - is_enabled (optional): Boolean or a method returning Boolean
- - enable (optional): method
- - disable (optional): method
- - is_running (optional): Boolean or a method returning Boolean
- """
-
- def __init__(self, service_id, name, is_enabled=None, enable=None,
- disable=None, is_running=None):
- if is_enabled is None:
- is_enabled = self._default_is_enabled
-
- self.service_id = service_id
- self.name = name
- self._is_enabled = is_enabled
- self._enable = enable
- self._disable = disable
- self._is_running = is_running
-
- # Maintain a complete list of services
- assert service_id not in services
- services[service_id] = self
-
- def enable(self):
- if self._enable is None:
- actions.superuser_run('service', ['enable', self.service_id])
- else:
- self._call_or_return(self._enable)
-
- def disable(self):
- if self._disable is None:
- actions.superuser_run('service', ['disable', self.service_id])
- else:
- self._call_or_return(self._disable)
-
- def is_enabled(self):
- """Return whether the service is enabled."""
- # TODO: we could cache the service state if we only use this service
- # interface to change service status.
- return self._call_or_return(self._is_enabled)
-
- def is_running(self):
- """Return whether the service is running."""
- if self._is_running is None:
- return action_utils.service_is_running(self.service_id)
-
- return self._call_or_return(self._is_running)
-
- @staticmethod
- def _call_or_return(obj):
- """Calls obj if it's callable, returns it if it's Boolean."""
- if isinstance(obj, collections.abc.Callable):
- return obj()
-
- if isinstance(obj, bool):
- return obj
-
- message = 'obj is expected to be callable or a boolean.'
- raise ValueError(message)
-
- def _default_is_enabled(self):
- """Returns is_enabled relying on a correct service_id"""
- return action_utils.service_is_enabled(self.service_id)
-
- @staticmethod
- def get_internal_interfaces():
- """Returns a list of interfaces in a firewall zone."""
- from plinth.modules import firewall
- return firewall.get_interfaces('internal')
diff --git a/plinth/templates/service-subsubmenu.html b/plinth/templates/app-subsubmenu.html
similarity index 95%
rename from plinth/templates/service-subsubmenu.html
rename to plinth/templates/app-subsubmenu.html
index 778d32ae3..0757a5a1a 100644
--- a/plinth/templates/service-subsubmenu.html
+++ b/plinth/templates/app-subsubmenu.html
@@ -49,7 +49,7 @@
{% endif %}
- {% include "clients.html" with clients=clients enabled=service.is_enabled %}
+ {% include "clients.html" with clients=clients enabled=is_enabled %}
{% block subsubmenu %}
{% if subsubmenu %}
diff --git a/plinth/templates/service.html b/plinth/templates/app.html
similarity index 85%
rename from plinth/templates/service.html
rename to plinth/templates/app.html
index 72431dc3d..d8b8e8122 100644
--- a/plinth/templates/service.html
+++ b/plinth/templates/app.html
@@ -18,7 +18,7 @@
#
{% endcomment %}
-{# Template to display/configure a Service, used by views.ServiceView #}
+{# Template to display/configure an App, used by views.AppView #}
{% load bootstrap %}
{% load i18n %}
@@ -27,7 +27,7 @@
{% block content %}
{% block pagetitle %}
- {{ service.name }}
+ {{ name }}
{% endblock %}
{% block description %}
@@ -44,14 +44,14 @@
{% endif %}
- {% include "clients.html" with clients=clients enabled=service.is_enabled %}
+ {% include "clients.html" with clients=clients enabled=is_enabled %}
{% block status %}
{% if show_status_block %}
{% trans "Status" %}
- {% with service_name=service.name %}
- {% if service.is_running %}
+ {% with service_name=name %}
+ {% if is_running %}
{% blocktrans trimmed %}
Service {{ service_name }} is running.
@@ -69,13 +69,13 @@
{% block diagnostics %}
{% if diagnostics_module_name %}
- {% include "diagnostics_button.html" with module=diagnostics_module_name enabled=service.is_enabled %}
+ {% include "diagnostics_button.html" with module=diagnostics_module_name enabled=is_enabled %}
{% endif %}
{% endblock %}
{% include "internal-zone.html" %}
- {% include "port-forwarding-info.html" with service_name=service.name %}
+ {% include "port-forwarding-info.html" with service_name=name %}
{% block configuration %}
{% trans "Configuration" %}
diff --git a/plinth/templates/index.html b/plinth/templates/index.html
index dcad14631..35e7073c6 100644
--- a/plinth/templates/index.html
+++ b/plinth/templates/index.html
@@ -52,7 +52,7 @@
{% endfor %}
{% endblock %}
- {% include "clients.html" with clients=clients enabled=service.is_enabled %}
+ {% include "clients.html" with clients=selected_shortcut.clients enabled=True %}
{% if user.is_authenticated and user_is_admin and selected_shortcut.configure_url %}
diff --git a/plinth/templates/internal-zone.html b/plinth/templates/internal-zone.html
index 0d8ecaa57..a5931264c 100644
--- a/plinth/templates/internal-zone.html
+++ b/plinth/templates/internal-zone.html
@@ -20,22 +20,24 @@
{% load i18n %}
{% block internal_zone_warning %}
- {% if not service.is_external %}
-
- {% blocktrans trimmed with service_name=service.name %}
-
{{ service_name }} is available only on internal networks.
- {% endblocktrans %}
-
- {% with interfaces=service.get_internal_interfaces %}
- {% if not interfaces %}
- {% trans "Currently there are no network interfaces configured as internal." %}
- {% else %}
- {% blocktrans trimmed with interface_list=interfaces|join:", " %}
- Currently the following network interfaces are configured as internal: {{ interface_list }}
- {% endblocktrans %}
- {% endif %}
- {% endwith %}
-
-
- {% endif %}
+ {% for component in firewall %}
+ {% if not component.is_external %}
+
+ {% blocktrans trimmed with service_name=component.name %}
+
{{ service_name }} is available only on internal networks.
+ {% endblocktrans %}
+
+ {% with interfaces=component.get_internal_interfaces %}
+ {% if not interfaces %}
+ {% trans "Currently there are no network interfaces configured as internal." %}
+ {% else %}
+ {% blocktrans trimmed with interface_list=interfaces|join:", " %}
+ Currently the following network interfaces are configured as internal: {{ interface_list }}
+ {% endblocktrans %}
+ {% endif %}
+ {% endwith %}
+
+
+ {% endif %}
+ {% endfor %}
{% endblock %}
diff --git a/plinth/templates/simple_service.html b/plinth/templates/simple_app.html
similarity index 100%
rename from plinth/templates/simple_service.html
rename to plinth/templates/simple_app.html
diff --git a/plinth/tests/test_app.py b/plinth/tests/test_app.py
index 815b3d482..3afd40caa 100644
--- a/plinth/tests/test_app.py
+++ b/plinth/tests/test_app.py
@@ -95,6 +95,25 @@ def test_get_component(app_with_components):
app.get_component('x-invalid-component')
+def test_get_components_of_type(app_with_components):
+ """Test retrieving list of components of a given type."""
+ app = app_with_components
+ components = app.get_components_of_type(FollowerComponent)
+ follower_components = [
+ app.components['test-follower-1'],
+ app.components['test-follower-2'],
+ app.components['test-leader-1'],
+ app.components['test-leader-2'],
+ ]
+ assert list(components) == follower_components
+ components = app.get_components_of_type(LeaderTest)
+ leader_components = [
+ app.components['test-leader-1'],
+ app.components['test-leader-2'],
+ ]
+ assert list(components) == leader_components
+
+
def test_app_enable(app_with_components):
"""Test that enabling an app enables components."""
app_with_components.disable()
@@ -136,6 +155,12 @@ def test_app_is_enabled(app_with_components):
assert app.is_enabled()
+def test_app_is_enabled_with_no_leader_components():
+ """When there are not leader components, app.is_enabled() returns True."""
+ app = TestApp()
+ assert app.is_enabled()
+
+
def test_app_set_enabled(app_with_components):
"""Test that setting enabled effects only followers."""
app = app_with_components
diff --git a/plinth/tests/test_daemon.py b/plinth/tests/test_daemon.py
new file mode 100644
index 000000000..4e448348a
--- /dev/null
+++ b/plinth/tests/test_daemon.py
@@ -0,0 +1,119 @@
+#
+# This file is part of FreedomBox.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+"""
+Test module for component managing system daemons and other systemd units.
+"""
+
+from unittest.mock import Mock, call, patch
+
+import pytest
+
+from plinth.app import App, FollowerComponent
+from plinth.daemon import Daemon, app_is_running
+
+
+@pytest.fixture(name='daemon')
+def fixture_daemon():
+ """Create a test daemon object."""
+ return Daemon('test-daemon', 'test-unit')
+
+
+def test_initialization():
+ """Test that component is initialized properly."""
+ with pytest.raises(ValueError):
+ Daemon(None, None)
+
+ daemon = Daemon('test-daemon', 'test-unit')
+ assert daemon.component_id == 'test-daemon'
+ assert daemon.unit == 'test-unit'
+ assert not daemon.strict_check
+
+ daemon = Daemon('test-daemon', 'test-unit', strict_check=True)
+ assert daemon.strict_check
+
+
+@patch('plinth.action_utils.service_is_enabled')
+def test_is_enabled(service_is_enabled, daemon):
+ """Test that daemon enabled check works."""
+ service_is_enabled.return_value = True
+ assert daemon.is_enabled()
+ service_is_enabled.assert_has_calls(
+ [call('test-unit', strict_check=False)])
+
+ service_is_enabled.return_value = False
+ assert not daemon.is_enabled()
+
+ service_is_enabled.reset_mock()
+ daemon.strict_check = True
+ daemon.is_enabled()
+ service_is_enabled.assert_has_calls([call('test-unit', strict_check=True)])
+
+
+@patch('plinth.actions.superuser_run')
+def test_enable(superuser_run, daemon):
+ """Test that enabling the daemon works."""
+ daemon.enable()
+ superuser_run.assert_has_calls([call('service', ['enable', 'test-unit'])])
+
+
+@patch('plinth.actions.superuser_run')
+def test_disable(superuser_run, daemon):
+ """Test that disabling the daemon works."""
+ daemon.disable()
+ superuser_run.assert_has_calls([call('service', ['disable', 'test-unit'])])
+
+
+@patch('plinth.action_utils.service_is_running')
+def test_is_running(service_is_running, daemon):
+ """Test that checking that the daemon is running works."""
+ service_is_running.return_value = True
+ assert daemon.is_running()
+ service_is_running.assert_has_calls([call('test-unit')])
+
+ service_is_running.return_value = False
+ assert not daemon.is_running()
+
+
+@patch('plinth.action_utils.service_is_running')
+def test_app_is_running(service_is_running):
+ """Test that checking whether app is running works."""
+ daemon1 = Daemon('test-daemon-1', 'test-unit-1')
+ daemon2 = FollowerComponent('test-daemon-2', 'test-unit-2')
+ daemon2.is_running = Mock()
+
+ follower1 = FollowerComponent('test-follower-1')
+
+ class TestApp(App):
+ """Test app"""
+ app_id = 'test-app'
+
+ app = TestApp()
+ app.add(daemon1)
+ app.add(daemon2)
+ app.add(follower1)
+
+ service_is_running.return_value = True
+ daemon2.is_running.return_value = False
+ assert not app_is_running(app)
+
+ service_is_running.return_value = False
+ daemon2.is_running.return_value = False
+ assert not app_is_running(app)
+
+ service_is_running.return_value = True
+ daemon2.is_running.return_value = True
+ assert app_is_running(app)
diff --git a/plinth/views.py b/plinth/views.py
index 97bcb0e46..b1ddf259e 100644
--- a/plinth/views.py
+++ b/plinth/views.py
@@ -30,8 +30,9 @@ from django.views.generic import TemplateView
from django.views.generic.edit import FormView
from stronghold.decorators import public
-import plinth
from plinth import package
+from plinth.app import App
+from plinth.daemon import app_is_running
from plinth.modules.config import get_advanced_mode
from plinth.modules.storage import views as disk_views
from plinth.translation import get_language_from_request, set_language
@@ -106,47 +107,60 @@ class LanguageSelectionView(FormView):
return reverse('index')
-class ServiceView(FormView):
- """A generic view for configuring simple services."""
+class AppView(FormView):
+ """A generic view for configuring simple apps."""
clients = []
# Set diagnostics_module_name to the module name to show diagnostics button
diagnostics_module_name = ""
+ name = None
# List of paragraphs describing the service
description = ""
- form_class = forms.ServiceForm
- # Display the 'status' block of the service.html template
+ form_class = forms.AppForm
+ # Display the 'status' block of the app.html template
# This block uses information from service.is_running. This method is
# optional, so allow not showing this block here.
show_status_block = True
- service_id = None
- template_name = 'service.html'
- manual_page = ""
+ app_id = None
+ template_name = 'app.html'
+ manual_page = ''
port_forwarding_info = None
+ def __init__(self, *args, **kwargs):
+ """Intialize the view."""
+ super().__init__(*args, **kwargs)
+ self._common_status = None
+
+ if not self.name:
+ raise ImproperlyConfigured('Missing name attribute')
+
@property
def success_url(self):
return self.request.path
@property
- def service(self):
- if hasattr(self, '_service'):
- return self._service
+ def app(self):
+ """Return the app for which this view is configured."""
+ if not self.app_id:
+ raise ImproperlyConfigured('Missing attribute: app_id')
- if not self.service_id:
- raise ImproperlyConfigured("missing attribute: 'service_id'")
- service = plinth.service.services.get(self.service_id, None)
- if service is None:
- message = "Could not find service %s" % self.service_id
- raise ImproperlyConfigured(message)
- self._service = service
- return service
+ return App.get(self.app_id)
+
+ def _get_common_status(self):
+ """Return the status needed for form and template.
+
+ Avoid multiple queries to expensive operations such as
+ app.is_enabled().
+
+ """
+ if self._common_status:
+ return self._common_status
+
+ self._common_status = {'is_enabled': self.app.is_enabled()}
+ return self._common_status
def get_initial(self):
- """Return the status of the service to fill in the form."""
- return {
- 'is_enabled': self.service.is_enabled(),
- 'is_running': self.service.is_running()
- }
+ """Return the status of the app to fill in the form."""
+ return self._get_common_status()
def form_valid(self, form):
"""Enable/disable a service and set messages."""
@@ -160,10 +174,10 @@ class ServiceView(FormView):
messages.info(self.request, _('Setting unchanged'))
else:
if new_status['is_enabled']:
- self.service.enable()
+ self.app.enable()
messages.success(self.request, _('Application enabled'))
else:
- self.service.disable()
+ self.app.disable()
messages.success(self.request, _('Application disabled'))
return super().form_valid(form)
@@ -171,13 +185,20 @@ class ServiceView(FormView):
def get_context_data(self, *args, **kwargs):
"""Add service to the context data."""
context = super().get_context_data(*args, **kwargs)
- context['service'] = self.service
+ context.update(self._get_common_status())
+ context['app'] = self.app
+ context['is_running'] = app_is_running(self.app)
context['clients'] = self.clients
context['diagnostics_module_name'] = self.diagnostics_module_name
+ context['name'] = self.name
context['description'] = self.description
context['show_status_block'] = self.show_status_block
context['manual_page'] = self.manual_page
context['port_forwarding_info'] = self.port_forwarding_info
+
+ from plinth.modules.firewall.components import Firewall
+ context['firewall'] = self.app.get_components_of_type(Firewall)
+
return context