mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-01-28 08:03:36 +00:00
backups: Use the backup component in all apps
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: Veiko Aasa <veiko17@disroot.org>
This commit is contained in:
parent
f630fb6059
commit
fb1898befc
@ -9,13 +9,14 @@ from plinth import actions
|
||||
from plinth import app as app_module
|
||||
from plinth import cfg, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.config import get_hostname
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.names.components import DomainType
|
||||
from plinth.signals import domain_added, domain_removed, post_hostname_change
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
from .manifest import backup # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
# pylint: disable=C0103
|
||||
|
||||
@ -76,6 +77,10 @@ class AvahiApp(app_module.App):
|
||||
daemon = Daemon('daemon-avahi', managed_services[0])
|
||||
self.add(daemon)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-avahi',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
if self.is_enabled():
|
||||
domain_added.send_robust(sender='avahi',
|
||||
domain_type='domain-type-local',
|
||||
|
||||
@ -3,10 +3,8 @@
|
||||
Application manifest for avahi.
|
||||
"""
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
# Services that intend to make themselves discoverable will drop files into
|
||||
# /etc/avahi/services. Currently, we don't intend to make that customizable.
|
||||
# There is no necessity for backup and restore. This manifest will ensure that
|
||||
# avahi enable/disable setting is preserved.
|
||||
backup = validate_backup({})
|
||||
backup = {}
|
||||
|
||||
@ -75,10 +75,10 @@ def _backup_handler(packet, encryption_passphrase=None):
|
||||
get_valid_filename(packet.path) + '.json')
|
||||
manifests = {
|
||||
'apps': [{
|
||||
'name': app.name,
|
||||
'version': app.app.app.info.version,
|
||||
'backup': app.manifest
|
||||
} for app in packet.apps]
|
||||
'name': component.app.app_id,
|
||||
'version': component.app.info.version,
|
||||
'backup': component.manifest
|
||||
} for component in packet.components]
|
||||
}
|
||||
with open(manifest_path, 'w') as manifest_file:
|
||||
json.dump(manifests, manifest_file)
|
||||
@ -124,9 +124,9 @@ def restore_archive_handler(packet, encryption_passphrase=None):
|
||||
actions.superuser_run('backups', arguments, input=locations_data.encode())
|
||||
|
||||
|
||||
def restore_from_upload(path, apps=None):
|
||||
def restore_from_upload(path, app_ids=None):
|
||||
"""Restore files from an uploaded .tar.gz backup file"""
|
||||
api.restore_apps(_restore_exported_archive_handler, app_names=apps,
|
||||
api.restore_apps(_restore_exported_archive_handler, app_ids=app_ids,
|
||||
create_subvolume=False, backup_file=path)
|
||||
|
||||
|
||||
|
||||
@ -10,79 +10,38 @@ TODO:
|
||||
- Implement unit tests.
|
||||
"""
|
||||
|
||||
import importlib
|
||||
import logging
|
||||
|
||||
from plinth import actions, action_utils, module_loader, setup
|
||||
from plinth import action_utils, actions
|
||||
from plinth import app as app_module
|
||||
from plinth import setup
|
||||
|
||||
from .components import BackupRestore
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def validate(backup):
|
||||
"""Validate the backup' information schema."""
|
||||
assert isinstance(backup, dict)
|
||||
|
||||
if 'config' in backup:
|
||||
assert isinstance(backup['config'], dict)
|
||||
_validate_directories_and_files(backup['config'])
|
||||
|
||||
if 'data' in backup:
|
||||
assert isinstance(backup['data'], dict)
|
||||
_validate_directories_and_files(backup['data'])
|
||||
|
||||
if 'secrets' in backup:
|
||||
assert isinstance(backup['secrets'], dict)
|
||||
_validate_directories_and_files(backup['secrets'])
|
||||
|
||||
if 'services' in backup:
|
||||
assert isinstance(backup['services'], list)
|
||||
for service in backup['services']:
|
||||
assert isinstance(service, (str, dict))
|
||||
if isinstance(service, dict):
|
||||
_validate_service(service)
|
||||
|
||||
return backup
|
||||
|
||||
|
||||
def _validate_directories_and_files(section):
|
||||
"""Validate directories and files keys in a section."""
|
||||
if 'directories' in section:
|
||||
assert isinstance(section['directories'], list)
|
||||
for directory in section['directories']:
|
||||
assert isinstance(directory, str)
|
||||
|
||||
if 'files' in section:
|
||||
assert isinstance(section['files'], list)
|
||||
for file_path in section['files']:
|
||||
assert isinstance(file_path, str)
|
||||
|
||||
|
||||
def _validate_service(service):
|
||||
"""Validate a service manifest provided as a dictionary."""
|
||||
assert isinstance(service['name'], str)
|
||||
assert isinstance(service['type'], str)
|
||||
assert service['type'] in ('apache', 'uwsgi', 'system')
|
||||
if service['type'] == 'apache':
|
||||
assert service['kind'] in ('config', 'site', 'module')
|
||||
|
||||
|
||||
class BackupError:
|
||||
"""Represent an backup/restore operation error."""
|
||||
def __init__(self, error_type, app, hook=None):
|
||||
|
||||
def __init__(self, error_type, component, hook=None):
|
||||
"""Initialize the error object."""
|
||||
self.error_type = error_type
|
||||
self.app = app
|
||||
self.component = component
|
||||
self.hook = hook
|
||||
|
||||
def __eq__(self, other_error):
|
||||
"""Compare to error objects."""
|
||||
return (self.error_type == other_error.error_type
|
||||
and self.app == other_error.app
|
||||
and self.component == other_error.component
|
||||
and self.hook == other_error.hook)
|
||||
|
||||
|
||||
class Packet:
|
||||
"""Information passed to a handlers for backup/restore operations."""
|
||||
def __init__(self, operation, scope, root, apps=None, path=None):
|
||||
|
||||
def __init__(self, operation, scope, root, components=None, path=None):
|
||||
"""Initialize the packet.
|
||||
|
||||
operation is either 'backup' or 'restore.
|
||||
@ -101,7 +60,7 @@ class Packet:
|
||||
self.operation = operation
|
||||
self.scope = scope
|
||||
self.root = root
|
||||
self.apps = apps
|
||||
self.components = components
|
||||
self.path = path
|
||||
self.errors = []
|
||||
|
||||
@ -112,11 +71,11 @@ class Packet:
|
||||
|
||||
def _process_manifests(self):
|
||||
"""Look at manifests and fill up the list of directories/files."""
|
||||
for app in self.apps:
|
||||
for component in self.components:
|
||||
for section in ['config', 'data', 'secrets']:
|
||||
self.directories += app.manifest.get(section, {}).get(
|
||||
'directories', [])
|
||||
self.files += app.manifest.get(section, {}).get('files', [])
|
||||
section = getattr(component, section)
|
||||
self.directories += section.get('directories', [])
|
||||
self.files += section.get('files', [])
|
||||
|
||||
|
||||
def backup_full(backup_handler, path=None):
|
||||
@ -146,25 +105,25 @@ def restore_full(restore_handler):
|
||||
_switch_to_subvolume(subvolume)
|
||||
|
||||
|
||||
def backup_apps(backup_handler, path, app_names=None,
|
||||
def backup_apps(backup_handler, path, app_ids=None,
|
||||
encryption_passphrase=None):
|
||||
"""Backup data belonging to a set of applications."""
|
||||
if not app_names:
|
||||
apps = get_all_apps_for_backup()
|
||||
if not app_ids:
|
||||
components = get_all_components_for_backup()
|
||||
else:
|
||||
apps = get_apps_in_order(app_names)
|
||||
components = get_components_in_order(app_ids)
|
||||
|
||||
if _is_snapshot_available():
|
||||
snapshot = _take_snapshot()
|
||||
backup_root = snapshot['mount_path']
|
||||
snapshotted = True
|
||||
else:
|
||||
_lockdown_apps(apps, lockdown=True)
|
||||
original_state = _shutdown_services(apps)
|
||||
_lockdown_apps(components, lockdown=True)
|
||||
original_state = _shutdown_services(components)
|
||||
backup_root = '/'
|
||||
snapshotted = False
|
||||
|
||||
packet = Packet('backup', 'apps', backup_root, apps, path)
|
||||
packet = Packet('backup', 'apps', backup_root, components, path)
|
||||
_run_operation(backup_handler, packet,
|
||||
encryption_passphrase=encryption_passphrase)
|
||||
|
||||
@ -172,29 +131,29 @@ def backup_apps(backup_handler, path, app_names=None,
|
||||
_delete_snapshot(snapshot)
|
||||
else:
|
||||
_restore_services(original_state)
|
||||
_lockdown_apps(apps, lockdown=False)
|
||||
_lockdown_apps(components, lockdown=False)
|
||||
|
||||
|
||||
def restore_apps(restore_handler, app_names=None, create_subvolume=True,
|
||||
def restore_apps(restore_handler, app_ids=None, create_subvolume=True,
|
||||
backup_file=None, encryption_passphrase=None):
|
||||
"""Restore data belonging to a set of applications."""
|
||||
if not app_names:
|
||||
apps = get_all_apps_for_backup()
|
||||
if not app_ids:
|
||||
components = get_all_components_for_backup()
|
||||
else:
|
||||
apps = get_apps_in_order(app_names)
|
||||
components = get_components_in_order(app_ids)
|
||||
|
||||
_install_apps_before_restore(apps)
|
||||
_install_apps_before_restore(components)
|
||||
|
||||
if _is_snapshot_available() and create_subvolume:
|
||||
subvolume = _create_subvolume(empty=False)
|
||||
restore_root = subvolume['mount_path']
|
||||
else:
|
||||
_lockdown_apps(apps, lockdown=True)
|
||||
original_state = _shutdown_services(apps)
|
||||
_lockdown_apps(components, lockdown=True)
|
||||
original_state = _shutdown_services(components)
|
||||
restore_root = '/'
|
||||
subvolume = False
|
||||
|
||||
packet = Packet('restore', 'apps', restore_root, apps, backup_file)
|
||||
packet = Packet('restore', 'apps', restore_root, components, backup_file)
|
||||
_run_operation(restore_handler, packet,
|
||||
encryption_passphrase=encryption_passphrase)
|
||||
|
||||
@ -202,10 +161,10 @@ def restore_apps(restore_handler, app_names=None, create_subvolume=True,
|
||||
_switch_to_subvolume(subvolume)
|
||||
else:
|
||||
_restore_services(original_state)
|
||||
_lockdown_apps(apps, lockdown=False)
|
||||
_lockdown_apps(components, lockdown=False)
|
||||
|
||||
|
||||
def _install_apps_before_restore(apps):
|
||||
def _install_apps_before_restore(components):
|
||||
"""Install/upgrade apps needed before restoring a backup.
|
||||
|
||||
Upgrading apps to latest version before backups reduces the chance of newer
|
||||
@ -213,92 +172,57 @@ def _install_apps_before_restore(apps):
|
||||
|
||||
"""
|
||||
modules_to_setup = []
|
||||
for backup_app in apps:
|
||||
if backup_app.app.setup_helper.get_state() in ('needs-setup',
|
||||
'needs-update'):
|
||||
modules_to_setup.append(backup_app.name)
|
||||
for component in components:
|
||||
module = importlib.import_module(component.app.__class__.__module__)
|
||||
if module.setup_helper.get_state() in ('needs-setup', 'needs-update'):
|
||||
modules_to_setup.append(component.app.app_id)
|
||||
|
||||
setup.run_setup_on_modules(modules_to_setup)
|
||||
|
||||
|
||||
class BackupApp:
|
||||
"""A application that can be backed up and its manifest."""
|
||||
def __init__(self, name, app):
|
||||
"""Initialize object and load manfiest."""
|
||||
self.name = name
|
||||
self.app = app
|
||||
def _get_backup_restore_component(app):
|
||||
"""Return the backup/restore component of the app."""
|
||||
for component in app.components.values():
|
||||
if isinstance(component, BackupRestore):
|
||||
return component
|
||||
|
||||
# Has no backup related meta data
|
||||
raise TypeError
|
||||
|
||||
|
||||
def get_all_components_for_backup():
|
||||
"""Return a list of all components that can be backed up."""
|
||||
components = []
|
||||
|
||||
for app_ in app_module.App.list():
|
||||
try:
|
||||
self.manifest = app.backup
|
||||
except AttributeError:
|
||||
raise TypeError
|
||||
|
||||
self.has_data = bool(app.backup)
|
||||
|
||||
def __eq__(self, other_app):
|
||||
"""Check if this app is same as another."""
|
||||
return self.name == other_app.name and \
|
||||
self.app == other_app.app and \
|
||||
self.manifest == other_app.manifest and \
|
||||
self.has_data == other_app.has_data
|
||||
|
||||
def is_installed(self):
|
||||
"""Return whether app is installed.
|
||||
|
||||
Return true even if the app needs update.
|
||||
"""
|
||||
return self.app.setup_helper.get_state() != 'needs-setup'
|
||||
|
||||
def run_hook(self, hook, packet):
|
||||
"""Run a hook inside an application."""
|
||||
if not hasattr(self.app, hook):
|
||||
return
|
||||
|
||||
try:
|
||||
getattr(self.app, hook)(packet)
|
||||
except Exception as exception:
|
||||
logger.exception(
|
||||
'Error running backup/restore hook for app %s: %s', self.name,
|
||||
exception)
|
||||
packet.errors.append(BackupError('hook', self.app, hook=hook))
|
||||
|
||||
|
||||
def get_all_apps_for_backup():
|
||||
"""Return a list of all applications that can be backed up."""
|
||||
apps = []
|
||||
for module_name, module in module_loader.loaded_modules.items():
|
||||
try:
|
||||
backup_app = BackupApp(module_name, module)
|
||||
if backup_app.is_installed():
|
||||
apps.append(backup_app)
|
||||
module = importlib.import_module(app_.__class__.__module__)
|
||||
if module.setup_helper.get_state() != 'needs-setup':
|
||||
components.append(_get_backup_restore_component(app_))
|
||||
except TypeError: # Application not available for backup/restore
|
||||
pass
|
||||
|
||||
return apps
|
||||
return components
|
||||
|
||||
|
||||
def get_apps_in_order(app_names):
|
||||
"""Return a list of app modules in order of dependency."""
|
||||
apps = []
|
||||
for module_name, module in module_loader.loaded_modules.items():
|
||||
if module_name in app_names:
|
||||
apps.append(BackupApp(module_name, module))
|
||||
def get_components_in_order(app_ids):
|
||||
"""Return a list of backup components in order of app dependencies."""
|
||||
components = []
|
||||
for app_ in app_module.App.list():
|
||||
if app_.app_id in app_ids:
|
||||
components.append(_get_backup_restore_component(app_))
|
||||
|
||||
return apps
|
||||
return components
|
||||
|
||||
|
||||
def _lockdown_apps(apps, lockdown):
|
||||
def _lockdown_apps(components, lockdown):
|
||||
"""Mark apps as in/out of lockdown mode and disable all user interaction.
|
||||
|
||||
This is a flag in the app module. It will enforced by a middleware that
|
||||
will intercept all interaction and show a lockdown message.
|
||||
|
||||
"""
|
||||
for app in apps:
|
||||
app.app.locked = lockdown
|
||||
|
||||
# XXX: Lockdown the application UI by implementing a middleware
|
||||
for component in components:
|
||||
component.app.locked = lockdown
|
||||
|
||||
|
||||
def _is_snapshot_available():
|
||||
@ -347,6 +271,7 @@ def _switch_to_subvolume(subvolume):
|
||||
|
||||
class ServiceHandler:
|
||||
"""Abstraction to help with service shutdown/restart."""
|
||||
|
||||
@staticmethod
|
||||
def create(backup_app, service):
|
||||
service_type = 'system'
|
||||
@ -381,6 +306,7 @@ class ServiceHandler:
|
||||
|
||||
class SystemServiceHandler(ServiceHandler):
|
||||
"""Handle starting and stopping of system services for backup."""
|
||||
|
||||
def __init__(self, backup_app, service):
|
||||
"""Initialize the object."""
|
||||
super().__init__(backup_app, service)
|
||||
@ -400,6 +326,7 @@ class SystemServiceHandler(ServiceHandler):
|
||||
|
||||
class ApacheServiceHandler(ServiceHandler):
|
||||
"""Handle starting and stopping of Apache services for backup."""
|
||||
|
||||
def __init__(self, backup_app, service):
|
||||
"""Initialize the object."""
|
||||
super().__init__(backup_app, service)
|
||||
@ -424,18 +351,19 @@ class ApacheServiceHandler(ServiceHandler):
|
||||
['enable', '--name', self.web_name, '--kind', self.kind])
|
||||
|
||||
|
||||
def _shutdown_services(apps):
|
||||
"""Shutdown all services specified by manifests.
|
||||
def _shutdown_services(components):
|
||||
"""Shutdown all services specified by backup manifests.
|
||||
|
||||
- Services are shutdown in the reverse order of the apps listing.
|
||||
- Services are shutdown in the reverse order of the components listing.
|
||||
|
||||
Return the current state of the services so they can be restored
|
||||
accurately.
|
||||
|
||||
"""
|
||||
state = []
|
||||
for app in apps:
|
||||
for service in app.manifest.get('services', []):
|
||||
state.append(ServiceHandler.create(app, service))
|
||||
for component in components:
|
||||
for service in component.services:
|
||||
state.append(ServiceHandler.create(component, service))
|
||||
|
||||
for service in reversed(state):
|
||||
service.stop()
|
||||
@ -480,8 +408,14 @@ def _run_hooks(hook, packet):
|
||||
|
||||
"""
|
||||
logger.info('Running %s hooks', hook)
|
||||
for app in packet.apps:
|
||||
app.run_hook(hook, packet)
|
||||
for component in packet.components:
|
||||
try:
|
||||
getattr(component, hook)(packet)
|
||||
except Exception as exception:
|
||||
logger.exception(
|
||||
'Error running backup/restore hook for app %s: %s',
|
||||
component.app.app_id, exception)
|
||||
packet.errors.append(BackupError('hook', component, hook=hook))
|
||||
|
||||
|
||||
def _run_operation(handler, packet, encryption_passphrase=None):
|
||||
|
||||
@ -24,16 +24,16 @@ from .repository import get_repositories
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _get_app_choices(apps):
|
||||
"""Return a list of check box multiple choices from list of apps."""
|
||||
def _get_app_choices(components):
|
||||
"""Return a list of check box multiple choices from list of components."""
|
||||
choices = []
|
||||
for app in apps:
|
||||
name = app.app.app.info.name
|
||||
if not app.has_data:
|
||||
for component in components:
|
||||
name = component.app.info.name
|
||||
if not component.has_data:
|
||||
name = ugettext('{app} (No data to backup)').format(
|
||||
app=app.app.app.info.name)
|
||||
app=component.app.info.name)
|
||||
|
||||
choices.append((app.name, name))
|
||||
choices.append((component.app_id, name))
|
||||
|
||||
return choices
|
||||
|
||||
@ -59,9 +59,12 @@ class CreateArchiveForm(forms.Form):
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Initialize the form with selectable apps."""
|
||||
super().__init__(*args, **kwargs)
|
||||
apps = api.get_all_apps_for_backup()
|
||||
self.fields['selected_apps'].choices = _get_app_choices(apps)
|
||||
self.fields['selected_apps'].initial = [app.name for app in apps]
|
||||
components = api.get_all_components_for_backup()
|
||||
choices = _get_app_choices(components)
|
||||
self.fields['selected_apps'].choices = choices
|
||||
self.fields['selected_apps'].initial = [
|
||||
choice[0] for choice in choices
|
||||
]
|
||||
self.fields['repository'].choices = _get_repository_choices()
|
||||
|
||||
|
||||
@ -72,10 +75,13 @@ class RestoreForm(forms.Form):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Initialize the form with selectable apps."""
|
||||
apps = kwargs.pop('apps')
|
||||
components = kwargs.pop('components')
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['selected_apps'].choices = _get_app_choices(apps)
|
||||
self.fields['selected_apps'].initial = [app.name for app in apps]
|
||||
choices = _get_app_choices(components)
|
||||
self.fields['selected_apps'].choices = choices
|
||||
self.fields['selected_apps'].initial = [
|
||||
choice[0] for choice in choices
|
||||
]
|
||||
|
||||
|
||||
class UploadForm(forms.Form):
|
||||
|
||||
@ -3,9 +3,7 @@
|
||||
Application manifest for backups.
|
||||
"""
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
# Currently, backup application does not have any settings. However, settings
|
||||
# such as scheduler settings, backup location, secrets to connect to remove
|
||||
# servers need to be backed up.
|
||||
backup = validate_backup({})
|
||||
backup = {}
|
||||
|
||||
@ -158,6 +158,7 @@ class BaseBorgRepository(abc.ABC):
|
||||
|
||||
def remove(self):
|
||||
"""Remove a borg repository"""
|
||||
|
||||
def list_archives(self):
|
||||
"""Return list of archives in this repository."""
|
||||
output = self.run(['list-repo', '--path', self.borg_path])
|
||||
@ -165,12 +166,12 @@ class BaseBorgRepository(abc.ABC):
|
||||
return sorted(archives, key=lambda archive: archive['start'],
|
||||
reverse=True)
|
||||
|
||||
def create_archive(self, archive_name, app_names):
|
||||
def create_archive(self, archive_name, app_ids):
|
||||
"""Create a new archive in this repository with given name."""
|
||||
archive_path = self._get_archive_path(archive_name)
|
||||
passphrase = self.credentials.get('encryption_passphrase', None)
|
||||
api.backup_apps(_backup_handler, path=archive_path,
|
||||
app_names=app_names, encryption_passphrase=passphrase)
|
||||
api.backup_apps(_backup_handler, path=archive_path, app_ids=app_ids,
|
||||
encryption_passphrase=passphrase)
|
||||
|
||||
def delete_archive(self, archive_name):
|
||||
"""Delete an archive with given name from this repository."""
|
||||
@ -222,6 +223,7 @@ class BaseBorgRepository(abc.ABC):
|
||||
|
||||
def get_download_stream(self, archive_name):
|
||||
"""Return an stream of .tar.gz binary data for a backup archive."""
|
||||
|
||||
class BufferedReader(io.BufferedReader):
|
||||
"""Improve performance of buffered binary streaming.
|
||||
|
||||
@ -235,6 +237,7 @@ class BaseBorgRepository(abc.ABC):
|
||||
binary data.
|
||||
|
||||
"""
|
||||
|
||||
def __next__(self):
|
||||
"""Override to call read() instead of readline()."""
|
||||
chunk = self.read(io.DEFAULT_BUFFER_SIZE)
|
||||
@ -279,11 +282,11 @@ class BaseBorgRepository(abc.ABC):
|
||||
output = self.run(['get-archive-apps', '--path', archive_path])
|
||||
return output.splitlines()
|
||||
|
||||
def restore_archive(self, archive_name, apps=None):
|
||||
def restore_archive(self, archive_name, app_ids=None):
|
||||
"""Restore an archive from this repository to the system."""
|
||||
archive_path = self._get_archive_path(archive_name)
|
||||
passphrase = self.credentials.get('encryption_passphrase', None)
|
||||
api.restore_apps(restore_archive_handler, app_names=apps,
|
||||
api.restore_apps(restore_archive_handler, app_ids=app_ids,
|
||||
create_subvolume=False, backup_file=archive_path,
|
||||
encryption_passphrase=passphrase)
|
||||
|
||||
|
||||
@ -8,13 +8,18 @@ from unittest.mock import MagicMock, call, patch
|
||||
import pytest
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
|
||||
from plinth.app import App
|
||||
|
||||
from .. import api, forms, repository
|
||||
from ..components import BackupRestore
|
||||
|
||||
# pylint: disable=protected-access
|
||||
|
||||
setup_helper = MagicMock()
|
||||
|
||||
|
||||
def _get_test_manifest(name):
|
||||
return api.validate({
|
||||
return {
|
||||
'config': {
|
||||
'directories': ['/etc/' + name + '/config.d/'],
|
||||
'files': ['/etc/' + name + '/config'],
|
||||
@ -32,50 +37,42 @@ def _get_test_manifest(name):
|
||||
'name': name,
|
||||
'kind': 'site'
|
||||
}]
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
def _get_backup_app(name):
|
||||
"""Return a dummy BackupApp object."""
|
||||
return api.BackupApp(name, MagicMock(backup=_get_test_manifest(name)))
|
||||
def _get_backup_component(name):
|
||||
"""Return a BackupRestore component."""
|
||||
return BackupRestore(name, **_get_test_manifest(name))
|
||||
|
||||
|
||||
class TestBackupApp:
|
||||
"""Test the BackupApp class."""
|
||||
@staticmethod
|
||||
def test_run_hook():
|
||||
"""Test running a hook on an application."""
|
||||
packet = api.Packet('backup', 'apps', '/', [])
|
||||
hook = 'testhook_pre'
|
||||
app = MagicMock()
|
||||
backup_app = api.BackupApp('app_name', app)
|
||||
backup_app.run_hook(hook, packet)
|
||||
class AppTest(App):
|
||||
"""Sample App for testing."""
|
||||
app_id = 'test-app'
|
||||
|
||||
app.testhook_pre.assert_has_calls([call(packet)])
|
||||
assert not packet.errors
|
||||
|
||||
app.testhook_pre.reset_mock()
|
||||
app.testhook_pre.side_effect = Exception()
|
||||
backup_app.run_hook(hook, packet)
|
||||
assert packet.errors == [api.BackupError('hook', app, hook=hook)]
|
||||
|
||||
del app.testhook_pre
|
||||
backup_app.run_hook(hook, packet)
|
||||
def _get_test_app(name):
|
||||
"""Return an App."""
|
||||
app = AppTest()
|
||||
app.app_id = name
|
||||
app._all_apps[name] = app
|
||||
app.add(_get_backup_component(name + '-component'))
|
||||
return app
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('load_cfg')
|
||||
class TestBackupProcesses:
|
||||
"""Test cases for backup processes"""
|
||||
|
||||
@staticmethod
|
||||
def test_packet_process_manifests():
|
||||
def test_packet_collected_files_directories():
|
||||
"""Test that directories/files are collected from manifests."""
|
||||
apps = [_get_backup_app('a'), _get_backup_app('b')]
|
||||
packet = api.Packet('backup', 'apps', '/', apps)
|
||||
for app in apps:
|
||||
components = [_get_backup_component('a'), _get_backup_component('b')]
|
||||
packet = api.Packet('backup', 'apps', '/', components)
|
||||
for component in components:
|
||||
for section in ['config', 'data', 'secrets']:
|
||||
for directory in app.manifest[section]['directories']:
|
||||
for directory in getattr(component, section)['directories']:
|
||||
assert directory in packet.directories
|
||||
for file_path in app.manifest[section]['files']:
|
||||
for file_path in getattr(component, section)['files']:
|
||||
assert file_path in packet.files
|
||||
|
||||
@staticmethod
|
||||
@ -97,50 +94,56 @@ class TestBackupProcesses:
|
||||
restore_handler.assert_called_once()
|
||||
|
||||
@staticmethod
|
||||
@patch('plinth.module_loader.loaded_modules.items')
|
||||
def test_get_all_apps_for_backup(modules):
|
||||
"""Test listing apps supporting backup and needing backup."""
|
||||
apps = [
|
||||
('a', MagicMock(backup=_get_test_manifest('a'))),
|
||||
('b', MagicMock(backup=_get_test_manifest('b'))),
|
||||
('c', MagicMock(backup=None)),
|
||||
('d', MagicMock()),
|
||||
]
|
||||
del apps[3][1].backup
|
||||
modules.return_value = apps
|
||||
@patch('importlib.import_module')
|
||||
@patch('plinth.app.App.list')
|
||||
def test_get_all_components_for_backup(apps_list, import_module):
|
||||
"""Test listing components supporting backup and needing backup."""
|
||||
modules = [MagicMock(), MagicMock(), MagicMock()]
|
||||
import_module.side_effect = modules
|
||||
apps = [_get_test_app('a'), _get_test_app('b'), _get_test_app('c')]
|
||||
modules[1].setup_helper.get_state.side_effect = ['needs-setup']
|
||||
apps_list.return_value = apps
|
||||
|
||||
returned_apps = api.get_all_apps_for_backup()
|
||||
expected_apps = [
|
||||
api.BackupApp('a', apps[0][1]),
|
||||
api.BackupApp('b', apps[1][1]),
|
||||
api.BackupApp('c', apps[2][1])
|
||||
returned_components = api.get_all_components_for_backup()
|
||||
expected_components = [
|
||||
apps[0].components['a-component'],
|
||||
apps[2].components['c-component']
|
||||
]
|
||||
assert returned_apps == expected_apps
|
||||
assert returned_components == expected_components
|
||||
|
||||
@staticmethod
|
||||
@patch('plinth.module_loader.loaded_modules.items')
|
||||
def test_get_apps_in_order(modules):
|
||||
"""Test that apps are listed in correct dependency order."""
|
||||
@patch('plinth.app.App.list')
|
||||
def test_get_components_in_order(apps_list):
|
||||
"""Test that components are listed in correct dependency order."""
|
||||
apps = [
|
||||
('names', MagicMock(backup=_get_test_manifest('names'))),
|
||||
('config', MagicMock(backup=_get_test_manifest('config'))),
|
||||
_get_test_app('names'),
|
||||
_get_test_app('other'),
|
||||
_get_test_app('config')
|
||||
]
|
||||
modules.return_value = apps
|
||||
apps_list.return_value = apps
|
||||
|
||||
app_names = ['config', 'names']
|
||||
apps = api.get_apps_in_order(app_names)
|
||||
assert apps[0].name == 'names'
|
||||
assert apps[1].name == 'config'
|
||||
app_ids = ['config', 'names']
|
||||
components = api.get_components_in_order(app_ids)
|
||||
assert len(components) == 2
|
||||
assert components[0].app_id == 'names'
|
||||
assert components[1].app_id == 'config'
|
||||
|
||||
@staticmethod
|
||||
def test__lockdown_apps():
|
||||
"""Test that locked flag is set for each app."""
|
||||
app_a = MagicMock(locked=False)
|
||||
app_b = MagicMock(locked=None)
|
||||
apps = [MagicMock(app=app_a), MagicMock(app=app_b)]
|
||||
api._lockdown_apps(apps, True)
|
||||
assert app_a.locked is True
|
||||
assert app_b.locked is True
|
||||
apps = [_get_test_app('test-app-1'), _get_test_app('test-app-2')]
|
||||
components = [
|
||||
apps[0].components['test-app-1-component'],
|
||||
apps[1].components['test-app-2-component']
|
||||
]
|
||||
|
||||
api._lockdown_apps(components, True)
|
||||
assert apps[0].locked
|
||||
assert apps[1].locked
|
||||
|
||||
api._lockdown_apps(components, False)
|
||||
assert not apps[0].locked
|
||||
assert not apps[1].locked
|
||||
|
||||
@staticmethod
|
||||
@patch('plinth.action_utils.webserver_is_enabled')
|
||||
@ -148,19 +151,20 @@ class TestBackupProcesses:
|
||||
@patch('plinth.actions.superuser_run')
|
||||
def test__shutdown_services(run, service_is_running, webserver_is_enabled):
|
||||
"""Test that services are stopped in correct order."""
|
||||
apps = [_get_backup_app('a'), _get_backup_app('b')]
|
||||
components = [_get_backup_component('a'), _get_backup_component('b')]
|
||||
service_is_running.return_value = True
|
||||
webserver_is_enabled.return_value = True
|
||||
state = api._shutdown_services(apps)
|
||||
state = api._shutdown_services(components)
|
||||
|
||||
expected_state = [
|
||||
api.ServiceHandler.create(apps[0],
|
||||
apps[0].manifest['services'][0]),
|
||||
api.ServiceHandler.create(apps[0],
|
||||
apps[0].manifest['services'][1]),
|
||||
api.ServiceHandler.create(apps[1],
|
||||
apps[1].manifest['services'][0]),
|
||||
api.ServiceHandler.create(apps[1], apps[1].manifest['services'][1])
|
||||
api.ServiceHandler.create(components[0],
|
||||
components[0].services[0]),
|
||||
api.ServiceHandler.create(components[0],
|
||||
components[0].services[1]),
|
||||
api.ServiceHandler.create(components[1],
|
||||
components[1].services[0]),
|
||||
api.ServiceHandler.create(components[1],
|
||||
components[1].services[1]),
|
||||
]
|
||||
assert state == expected_state
|
||||
|
||||
@ -207,21 +211,26 @@ class TestBackupProcesses:
|
||||
@staticmethod
|
||||
def test__run_operation():
|
||||
"""Test that operation runs handler and app hooks."""
|
||||
apps = [_get_backup_app('a'), _get_backup_app('b')]
|
||||
packet = api.Packet('backup', 'apps', '/', apps)
|
||||
packet.apps[0].run_hook = MagicMock()
|
||||
packet.apps[1].run_hook = MagicMock()
|
||||
components = [_get_backup_component('a'), _get_backup_component('b')]
|
||||
packet = api.Packet('backup', 'apps', '/', components)
|
||||
packet.components[0].backup_pre = MagicMock()
|
||||
packet.components[0].backup_post = MagicMock()
|
||||
packet.components[1].backup_pre = MagicMock()
|
||||
packet.components[1].backup_post = MagicMock()
|
||||
handler = MagicMock()
|
||||
api._run_operation(handler, packet)
|
||||
handler.assert_has_calls([call(packet, encryption_passphrase=None)])
|
||||
|
||||
calls = [call('backup_pre', packet), call('backup_post', packet)]
|
||||
packet.apps[0].run_hook.assert_has_calls(calls)
|
||||
packet.apps[1].run_hook.assert_has_calls(calls)
|
||||
calls = [call(packet)]
|
||||
packet.components[0].backup_pre.assert_has_calls(calls)
|
||||
packet.components[0].backup_post.assert_has_calls(calls)
|
||||
packet.components[1].backup_pre.assert_has_calls(calls)
|
||||
packet.components[1].backup_post.assert_has_calls(calls)
|
||||
|
||||
|
||||
class TestBackupModule:
|
||||
"""Tests of the backups django module, like views or forms."""
|
||||
|
||||
@staticmethod
|
||||
def test_file_upload():
|
||||
# posting a video should fail
|
||||
|
||||
@ -147,7 +147,7 @@ class BaseRestoreView(SuccessMessageMixin, FormView):
|
||||
"""Pass additional keyword args for instantiating the form."""
|
||||
kwargs = super().get_form_kwargs()
|
||||
included_apps = self._get_included_apps()
|
||||
kwargs['apps'] = api.get_apps_in_order(included_apps)
|
||||
kwargs['components'] = api.get_components_in_order(included_apps)
|
||||
return kwargs
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
||||
@ -11,9 +11,10 @@ from plinth import actions
|
||||
from plinth import app as app_module
|
||||
from plinth import frontpage, menu
|
||||
from plinth.modules.apache.components import Uwsgi, Webserver
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
|
||||
from .manifest import backup, clients # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 2
|
||||
|
||||
@ -64,7 +65,7 @@ class BepastyApp(app_module.App):
|
||||
icon_filename='bepasty',
|
||||
short_description=_('File & Snippet Sharing'),
|
||||
description=_description, manual_page='bepasty',
|
||||
clients=clients)
|
||||
clients=manifest.clients)
|
||||
self.add(info)
|
||||
|
||||
menu_item = menu.Menu('menu-bepasty', info.name,
|
||||
@ -75,7 +76,7 @@ class BepastyApp(app_module.App):
|
||||
shortcut = frontpage.Shortcut('shortcut-bepasty', info.name,
|
||||
info.short_description,
|
||||
info.icon_filename, '/bepasty',
|
||||
clients=clients)
|
||||
clients=manifest.clients)
|
||||
self.add(shortcut)
|
||||
|
||||
firewall = Firewall('firewall-bepasty', info.name,
|
||||
@ -89,6 +90,10 @@ class BepastyApp(app_module.App):
|
||||
urls=['https://{host}/bepasty/'])
|
||||
self.add(webserver)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-bepasty',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
"""Install and configure the module."""
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.clients import validate
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
clients = validate([{
|
||||
'name': _('bepasty'),
|
||||
@ -13,7 +12,7 @@ clients = validate([{
|
||||
}]
|
||||
}])
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'config': {
|
||||
'files': ['/etc/bepasty-freedombox.conf']
|
||||
},
|
||||
@ -21,4 +20,4 @@ backup = validate_backup({
|
||||
'directories': ['/var/lib/bepasty']
|
||||
},
|
||||
'services': ['uwsgi'],
|
||||
})
|
||||
}
|
||||
|
||||
@ -14,10 +14,11 @@ from plinth import actions
|
||||
from plinth import app as app_module
|
||||
from plinth import cfg, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
from .manifest import backup # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 2
|
||||
|
||||
@ -96,6 +97,10 @@ class BindApp(app_module.App):
|
||||
alias=managed_services[1])
|
||||
self.add(daemon)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-bind',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
"""Install and configure the module."""
|
||||
|
||||
@ -3,11 +3,9 @@
|
||||
Application manifest for bind.
|
||||
"""
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'config': {
|
||||
'files': ['/etc/bind/named.conf.options']
|
||||
},
|
||||
'services': ['bind9']
|
||||
})
|
||||
}
|
||||
|
||||
@ -13,11 +13,12 @@ from plinth import app as app_module
|
||||
from plinth import cfg, frontpage, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules.apache.components import Webserver
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
from .manifest import backup, clients # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 1
|
||||
|
||||
@ -60,7 +61,7 @@ class CalibreApp(app_module.App):
|
||||
name=_('calibre'), icon_filename='calibre',
|
||||
short_description=_('E-book Library'),
|
||||
description=_description, manual_page='Calibre',
|
||||
clients=clients,
|
||||
clients=manifest.clients,
|
||||
donation_url='https://calibre-ebook.com/donate')
|
||||
self.add(info)
|
||||
|
||||
@ -94,6 +95,10 @@ class CalibreApp(app_module.App):
|
||||
groups=groups)
|
||||
self.add(users_and_groups)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-calibre',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
"""Install and configure the module."""
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.clients import validate
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
clients = validate([{
|
||||
'name': _('calibre'),
|
||||
@ -13,9 +12,9 @@ clients = validate([{
|
||||
}]
|
||||
}])
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'data': {
|
||||
'directories': ['/var/lib/private/calibre-server-freedombox/']
|
||||
},
|
||||
'services': ['calibre-server-freedombox']
|
||||
})
|
||||
}
|
||||
|
||||
@ -12,12 +12,12 @@ from plinth import cfg, frontpage, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules import names
|
||||
from plinth.modules.apache.components import Webserver
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.signals import domain_added, domain_removed
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
from . import utils
|
||||
from .manifest import backup, clients # noqa, pylint: disable=unused-import
|
||||
from . import manifest, utils
|
||||
|
||||
version = 1
|
||||
|
||||
@ -65,7 +65,7 @@ class CockpitApp(app_module.App):
|
||||
icon='fa-wrench', icon_filename='cockpit',
|
||||
short_description=_('Server Administration'),
|
||||
description=_description, manual_page='Cockpit',
|
||||
clients=clients)
|
||||
clients=manifest.clients)
|
||||
self.add(info)
|
||||
|
||||
menu_item = menu.Menu('menu-cockpit', info.name,
|
||||
@ -92,6 +92,10 @@ class CockpitApp(app_module.App):
|
||||
daemon = Daemon('daemon-cockpit', managed_services[0])
|
||||
self.add(daemon)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-cockpit',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
domain_added.connect(on_domain_added)
|
||||
domain_removed.connect(on_domain_removed)
|
||||
|
||||
|
||||
@ -5,7 +5,6 @@ Application manifest for cockpit.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
from plinth.clients import validate
|
||||
|
||||
clients = validate([{
|
||||
@ -20,4 +19,4 @@ clients = validate([{
|
||||
# triggered on every Plinth domain change (and cockpit application install) and
|
||||
# will set the value of allowed domains correctly. This is the only key the is
|
||||
# customized in cockpit.conf.
|
||||
backup = validate_backup({})
|
||||
backup = {}
|
||||
|
||||
@ -13,11 +13,12 @@ from plinth import app as app_module
|
||||
from plinth import menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules import names
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.letsencrypt.components import LetsEncrypt
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
|
||||
from .manifest import backup # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 1
|
||||
|
||||
@ -86,6 +87,10 @@ class CoturnApp(app_module.App):
|
||||
reserved_usernames=['turnserver'])
|
||||
self.add(users_and_groups)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-coturn',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
"""Install and configure the module."""
|
||||
|
||||
@ -1,10 +1,3 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
backup = validate_backup({
|
||||
'secrets': {
|
||||
'directories': ['/etc/coturn']
|
||||
},
|
||||
'services': ['coturn']
|
||||
})
|
||||
backup = {'secrets': {'directories': ['/etc/coturn']}, 'services': ['coturn']}
|
||||
|
||||
@ -10,8 +10,9 @@ from django.utils.translation import ugettext_lazy as _
|
||||
from plinth import app as app_module
|
||||
from plinth import menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
|
||||
from .manifest import backup # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 2
|
||||
|
||||
@ -79,6 +80,10 @@ class DateTimeApp(app_module.App):
|
||||
daemon = Daemon('daemon-datetime', managed_services[0])
|
||||
self.add(daemon)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-datetime',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
def diagnose(self):
|
||||
"""Run diagnostics and return the results."""
|
||||
results = super().diagnose()
|
||||
|
||||
@ -3,6 +3,4 @@
|
||||
Application manifest for datetime.
|
||||
"""
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
backup = validate_backup({'data': {'files': ['/etc/timezone']}})
|
||||
backup = {'data': {'files': ['/etc/timezone']}}
|
||||
|
||||
@ -10,11 +10,12 @@ from plinth import app as app_module
|
||||
from plinth import frontpage, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules.apache.components import Webserver
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.users import add_user_to_share_group
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
|
||||
from .manifest import backup, clients # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 6
|
||||
|
||||
@ -50,7 +51,8 @@ class DelugeApp(app_module.App):
|
||||
app_id=self.app_id, version=version, name=_('Deluge'),
|
||||
icon_filename='deluge',
|
||||
short_description=_('BitTorrent Web Client'),
|
||||
description=_description, manual_page='Deluge', clients=clients,
|
||||
description=_description, manual_page='Deluge',
|
||||
clients=manifest.clients,
|
||||
donation_url='https://www.patreon.com/deluge_cas')
|
||||
self.add(info)
|
||||
|
||||
@ -88,6 +90,10 @@ class DelugeApp(app_module.App):
|
||||
groups=groups)
|
||||
self.add(users_and_groups)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-deluge',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
"""Install and configure the module."""
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.clients import validate
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
clients = validate([{
|
||||
'name': _('Deluge'),
|
||||
@ -14,9 +13,9 @@ clients = validate([{
|
||||
}]
|
||||
}])
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'config': {
|
||||
'directories': ['/var/lib/deluged/.config']
|
||||
},
|
||||
'services': ['deluged', 'deluge-web']
|
||||
})
|
||||
}
|
||||
|
||||
@ -16,8 +16,9 @@ from django.utils.translation import ugettext_noop
|
||||
from plinth import app as app_module
|
||||
from plinth import cfg, daemon, glib, menu
|
||||
from plinth.modules.apache.components import diagnose_url_on_all
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
|
||||
from .manifest import backup # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 1
|
||||
|
||||
@ -57,6 +58,10 @@ class DiagnosticsApp(app_module.App):
|
||||
'diagnostics:index', parent_url_name='system')
|
||||
self.add(menu_item)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-diagnostics',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
# Check periodically for low RAM space
|
||||
interval = 180 if cfg.develop else 3600
|
||||
glib.schedule(interval, _warn_about_low_ram_space)
|
||||
|
||||
@ -3,6 +3,4 @@
|
||||
Application manifest for diagnostics.
|
||||
"""
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
backup = validate_backup({})
|
||||
backup = {}
|
||||
|
||||
@ -52,8 +52,6 @@ _description = [
|
||||
' federate with other diaspora* pods.')
|
||||
]
|
||||
|
||||
from .manifest import clients # noqa pylint:disable=E402 isort:skip
|
||||
|
||||
app = None
|
||||
|
||||
|
||||
@ -65,10 +63,12 @@ class DiasporaApp(app_module.App):
|
||||
def __init__(self):
|
||||
"""Create components for the app."""
|
||||
super().__init__()
|
||||
from . import manifest
|
||||
info = app_module.Info(app_id=self.app_id, version=version,
|
||||
name=_('diaspora*'), icon_filename='diaspora',
|
||||
short_description=_('Federated Social Network'),
|
||||
description=_description, clients=clients)
|
||||
description=_description,
|
||||
clients=manifest.clients)
|
||||
self.add(info)
|
||||
|
||||
menu_item = menu.Menu('menu-diaspora', info.name,
|
||||
|
||||
@ -8,12 +8,13 @@ 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.modules.backups.components import BackupRestore
|
||||
from plinth.modules.names.components import DomainType
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
from plinth.signals import domain_added
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
from .manifest import backup # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 1
|
||||
|
||||
@ -70,6 +71,10 @@ class DynamicDNSApp(app_module.App):
|
||||
reserved_usernames=['ez-ipupd'])
|
||||
self.add(users_and_groups)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-dynamicdns',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
current_status = get_status()
|
||||
if current_status['enabled']:
|
||||
domain_added.send_robust(sender='dynamicdns',
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
backup = validate_backup({'config': {'directories': ['/etc/ez-ipupdate/']}})
|
||||
backup = {'config': {'directories': ['/etc/ez-ipupdate/']}}
|
||||
|
||||
@ -16,6 +16,7 @@ from plinth import cfg, frontpage, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules import config
|
||||
from plinth.modules.apache.components import Webserver
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.letsencrypt.components import LetsEncrypt
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
@ -23,7 +24,7 @@ from plinth.signals import (domain_added, post_hostname_change,
|
||||
pre_hostname_change)
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
from .manifest import backup, clients # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 3
|
||||
|
||||
@ -63,7 +64,8 @@ class EjabberdApp(app_module.App):
|
||||
name=_('ejabberd'), icon_filename='ejabberd',
|
||||
short_description=_('Chat Server'),
|
||||
description=_description,
|
||||
manual_page='ejabberd', clients=clients)
|
||||
manual_page='ejabberd',
|
||||
clients=manifest.clients)
|
||||
self.add(info)
|
||||
|
||||
menu_item = menu.Menu('menu-ejabberd', info.name,
|
||||
@ -107,6 +109,10 @@ class EjabberdApp(app_module.App):
|
||||
reserved_usernames=['ejabberd'])
|
||||
self.add(users_and_groups)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-ejabberd',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
pre_hostname_change.connect(on_pre_hostname_change)
|
||||
post_hostname_change.connect(on_post_hostname_change)
|
||||
domain_added.connect(on_domain_added)
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.clients import store_url, validate
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
from plinth.modules.jsxc import manifest as jsxc_manifest
|
||||
|
||||
_clients = validate([{
|
||||
@ -106,7 +105,7 @@ _clients.extend(jsxc_manifest.clients)
|
||||
|
||||
clients = _clients
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'config': {
|
||||
'files': ['/etc/ejabberd/ejabberd.yml']
|
||||
},
|
||||
@ -118,4 +117,4 @@ backup = validate_backup({
|
||||
'directories': ['/etc/ejabberd/letsencrypt/']
|
||||
},
|
||||
'services': ['ejabberd']
|
||||
})
|
||||
}
|
||||
|
||||
@ -12,9 +12,10 @@ from plinth import actions
|
||||
from plinth import app as app_module
|
||||
from plinth import cfg, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.utils import Version, format_lazy, import_from_gi
|
||||
|
||||
from .manifest import backup # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
gio = import_from_gi('Gio', '2.0')
|
||||
glib = import_from_gi('GLib', '2.0')
|
||||
@ -74,6 +75,10 @@ class FirewallApp(app_module.App):
|
||||
daemon = Daemon('daemon-firewall', managed_services[0])
|
||||
self.add(daemon)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-firewall',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
def _run_setup():
|
||||
"""Run firewalld setup."""
|
||||
|
||||
@ -3,6 +3,4 @@
|
||||
Application manifest for firewall.
|
||||
"""
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
backup = validate_backup({})
|
||||
backup = {}
|
||||
|
||||
@ -13,12 +13,13 @@ from plinth import app as app_module
|
||||
from plinth import frontpage, menu
|
||||
from plinth.errors import ActionError
|
||||
from plinth.modules.apache.components import Webserver
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
|
||||
from . import manifest
|
||||
from .forms import is_repo_url
|
||||
from .manifest import ( # noqa, pylint: disable=unused-import
|
||||
GIT_REPO_PATH, backup, clients)
|
||||
from .manifest import GIT_REPO_PATH
|
||||
|
||||
version = 1
|
||||
|
||||
@ -56,7 +57,7 @@ class GitwebApp(app_module.App):
|
||||
name=_('Gitweb'), icon_filename='gitweb',
|
||||
short_description=_('Simple Git Hosting'),
|
||||
description=_description, manual_page='GitWeb',
|
||||
clients=clients)
|
||||
clients=manifest.clients)
|
||||
self.add(info)
|
||||
|
||||
menu_item = menu.Menu('menu-gitweb', info.name, info.short_description,
|
||||
@ -88,6 +89,10 @@ class GitwebApp(app_module.App):
|
||||
groups=groups)
|
||||
self.add(users_and_groups)
|
||||
|
||||
backup_restore = GitwebBackupRestore('backup-restore-gitweb',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
setup_helper = globals()['setup_helper']
|
||||
if setup_helper.get_state() != 'needs-setup':
|
||||
self.update_service_access()
|
||||
@ -140,6 +145,14 @@ class GitwebWebserverAuth(Webserver):
|
||||
super().enable()
|
||||
|
||||
|
||||
class GitwebBackupRestore(BackupRestore):
|
||||
"""Component to handle backup/restore for Gitweb."""
|
||||
|
||||
def restore_post(self, packet):
|
||||
"""Update access after restoration of backups."""
|
||||
app.update_service_access()
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
"""Install and configure the module."""
|
||||
helper.install(managed_packages)
|
||||
@ -147,11 +160,6 @@ def setup(helper, old_version=None):
|
||||
helper.call('post', app.enable)
|
||||
|
||||
|
||||
def restore_post(packet):
|
||||
"""Update access after restoration of backups."""
|
||||
app.update_service_access()
|
||||
|
||||
|
||||
def repo_exists(name):
|
||||
"""Check whether a remote repository exists."""
|
||||
try:
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.clients import validate
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
CONFIG_FILE = '/etc/gitweb-freedombox.conf'
|
||||
GIT_REPO_PATH = '/var/lib/git'
|
||||
@ -35,11 +34,11 @@ clients = validate([
|
||||
},
|
||||
])
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'config': {
|
||||
'files': [CONFIG_FILE]
|
||||
},
|
||||
'data': {
|
||||
'directories': [GIT_REPO_PATH]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -10,11 +10,12 @@ from plinth import app as app_module
|
||||
from plinth import frontpage, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules.apache.components import Webserver
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.i2p.resources import FAVORITES
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
|
||||
from .manifest import backup, clients # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 1
|
||||
|
||||
@ -58,7 +59,8 @@ class I2PApp(app_module.App):
|
||||
info = app_module.Info(
|
||||
app_id=self.app_id, version=version, name=_('I2P'),
|
||||
icon_filename='i2p', short_description=_('Anonymity Network'),
|
||||
description=_description, manual_page='I2P', clients=clients,
|
||||
description=_description, manual_page='I2P',
|
||||
clients=manifest.clients,
|
||||
donation_url='https://geti2p.net/en/get-involved/donate')
|
||||
self.add(info)
|
||||
|
||||
@ -96,6 +98,9 @@ class I2PApp(app_module.App):
|
||||
groups=groups)
|
||||
self.add(users_and_groups)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-i2p', **manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
"""Install and configure the module."""
|
||||
|
||||
@ -6,7 +6,6 @@ Application manifest for I2P.
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.clients import validate
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
_package_id = 'net.geti2p.i2p'
|
||||
_download_url = 'https://geti2p.net/download'
|
||||
@ -36,9 +35,9 @@ clients = validate([{
|
||||
}]
|
||||
}])
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'secrets': {
|
||||
'directories': ['/var/lib/i2p/i2p-config']
|
||||
},
|
||||
'services': ['i2p']
|
||||
})
|
||||
}
|
||||
|
||||
@ -10,11 +10,12 @@ from plinth import actions
|
||||
from plinth import app as app_module
|
||||
from plinth import cfg, frontpage, menu
|
||||
from plinth.modules.apache.components import Webserver
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
from .manifest import backup, clients # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 1
|
||||
|
||||
@ -52,7 +53,7 @@ class IkiwikiApp(app_module.App):
|
||||
name=_('ikiwiki'), icon_filename='ikiwiki',
|
||||
short_description=_('Wiki and Blog'),
|
||||
description=_description, manual_page='Ikiwiki',
|
||||
clients=clients,
|
||||
clients=manifest.clients,
|
||||
donation_url='https://ikiwiki.info/tipjar/')
|
||||
self.add(info)
|
||||
|
||||
@ -76,6 +77,10 @@ class IkiwikiApp(app_module.App):
|
||||
groups=groups)
|
||||
self.add(users_and_groups)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-ikiwiki',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
def add_shortcut(self, site, title):
|
||||
"""Add an ikiwiki shortcut to frontpage."""
|
||||
shortcut = frontpage.Shortcut('shortcut-ikiwiki-' + site, title,
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
from plinth.clients import validate
|
||||
|
||||
clients = validate([{
|
||||
@ -13,7 +12,4 @@ clients = validate([{
|
||||
}]
|
||||
}])
|
||||
|
||||
backup = validate_backup(
|
||||
{'data': {
|
||||
'directories': ['/var/lib/ikiwiki/', '/var/www/ikiwiki/']
|
||||
}})
|
||||
backup = {'data': {'directories': ['/var/lib/ikiwiki/', '/var/www/ikiwiki/']}}
|
||||
|
||||
@ -10,10 +10,11 @@ from plinth import actions
|
||||
from plinth import app as app_module
|
||||
from plinth import cfg, frontpage, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
from .manifest import backup, clients # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 3
|
||||
|
||||
@ -45,7 +46,8 @@ class InfinotedApp(app_module.App):
|
||||
name=_('infinoted'), icon_filename='infinoted',
|
||||
short_description=_('Gobby Server'),
|
||||
description=_description,
|
||||
manual_page='Infinoted', clients=clients)
|
||||
manual_page='Infinoted',
|
||||
clients=manifest.clients)
|
||||
self.add(info)
|
||||
|
||||
menu_item = menu.Menu('menu-infinoted', info.name,
|
||||
@ -69,6 +71,10 @@ class InfinotedApp(app_module.App):
|
||||
listen_ports=[(6523, 'tcp4'), (6523, 'tcp6')])
|
||||
self.add(daemon)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-infinoted',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
"""Install and configure the module."""
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth import cfg
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
from plinth.clients import validate
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
@ -32,7 +31,7 @@ clients = validate([{
|
||||
}]
|
||||
}])
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'data': {
|
||||
'directories': ['/var/lib/infinoted/']
|
||||
},
|
||||
@ -43,4 +42,4 @@ backup = validate_backup({
|
||||
],
|
||||
},
|
||||
'services': ['infinoted']
|
||||
})
|
||||
}
|
||||
|
||||
@ -10,10 +10,11 @@ from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth import app as app_module
|
||||
from plinth import frontpage, menu
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.web_server import StaticFiles
|
||||
|
||||
from .manifest import backup, clients # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 1
|
||||
|
||||
@ -43,7 +44,7 @@ class JSXCApp(app_module.App):
|
||||
name=_('JSXC'), icon_filename='jsxc',
|
||||
short_description=_('Chat Client'),
|
||||
description=_description, manual_page='JSXC',
|
||||
clients=clients)
|
||||
clients=manifest.clients)
|
||||
self.add(info)
|
||||
|
||||
menu_item = menu.Menu('menu-jsxc', info.name, info.short_description,
|
||||
@ -72,6 +73,10 @@ class JSXCApp(app_module.App):
|
||||
directory_map=directory_map)
|
||||
self.add(static_files)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-jsxc',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
"""Install and configure the module."""
|
||||
|
||||
@ -4,7 +4,6 @@ from django.urls import reverse_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.clients import validate
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
clients = validate([{
|
||||
'name': _('JSXC'),
|
||||
@ -14,4 +13,4 @@ clients = validate([{
|
||||
}]
|
||||
}])
|
||||
|
||||
backup = validate_backup({})
|
||||
backup = {}
|
||||
|
||||
@ -15,12 +15,12 @@ from plinth import cfg, menu
|
||||
from plinth.errors import ActionError
|
||||
from plinth.modules import names
|
||||
from plinth.modules.apache.components import diagnose_url
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.names.components import DomainType
|
||||
from plinth.signals import domain_added, domain_removed, post_module_loading
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
from . import components
|
||||
from .manifest import backup # noqa, pylint: disable=unused-import
|
||||
from . import components, manifest
|
||||
|
||||
version = 3
|
||||
|
||||
@ -74,6 +74,10 @@ class LetsEncryptApp(app_module.App):
|
||||
'letsencrypt:index', parent_url_name='system')
|
||||
self.add(menu_item)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-letsencrypt',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
domain_added.connect(on_domain_added)
|
||||
domain_removed.connect(on_domain_removed)
|
||||
|
||||
|
||||
@ -3,7 +3,5 @@
|
||||
Application manfiest for letsencrypt.
|
||||
"""
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
# XXX: Backup and restore the Apache site configuration.
|
||||
backup = validate_backup({'secrets': {'directories': ['/etc/letsencrypt/']}})
|
||||
backup = {'secrets': {'directories': ['/etc/letsencrypt/']}}
|
||||
|
||||
@ -16,10 +16,11 @@ from plinth import app as app_module
|
||||
from plinth import frontpage, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules.apache.components import Webserver
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.letsencrypt.components import LetsEncrypt
|
||||
|
||||
from .manifest import backup, clients # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 6
|
||||
|
||||
@ -63,12 +64,11 @@ class MatrixSynapseApp(app_module.App):
|
||||
def __init__(self):
|
||||
"""Create components for the app."""
|
||||
super().__init__()
|
||||
info = app_module.Info(app_id=self.app_id, version=version,
|
||||
name=_('Matrix Synapse'),
|
||||
icon_filename='matrixsynapse',
|
||||
short_description=_('Chat Server'),
|
||||
description=_description,
|
||||
manual_page='MatrixSynapse', clients=clients)
|
||||
info = app_module.Info(
|
||||
app_id=self.app_id, version=version, name=_('Matrix Synapse'),
|
||||
icon_filename='matrixsynapse', short_description=_('Chat Server'),
|
||||
description=_description, manual_page='MatrixSynapse',
|
||||
clients=manifest.clients)
|
||||
self.add(info)
|
||||
|
||||
menu_item = menu.Menu('menu-matrixsynapse', info.name,
|
||||
@ -106,6 +106,10 @@ class MatrixSynapseApp(app_module.App):
|
||||
listen_ports=[(8008, 'tcp4'), (8448, 'tcp4')])
|
||||
self.add(daemon)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-matrixsynapse',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
"""Install and configure the module."""
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.clients import store_url, validate
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
_android_package_id = 'im.vector.app'
|
||||
_element_desktop_download_url = 'https://element.io/get-started'
|
||||
@ -44,7 +43,7 @@ clients = validate([{
|
||||
}]
|
||||
}])
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'config': {
|
||||
'directories': ['/etc/matrix-synapse/conf.d/'],
|
||||
'files': [
|
||||
@ -68,4 +67,4 @@ backup = validate_backup({
|
||||
]
|
||||
},
|
||||
'services': ['matrix-synapse']
|
||||
})
|
||||
}
|
||||
|
||||
@ -13,9 +13,10 @@ from plinth import app as app_module
|
||||
from plinth import frontpage, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules.apache.components import Webserver
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
|
||||
from .manifest import backup, clients # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 9
|
||||
|
||||
@ -58,7 +59,8 @@ class MediaWikiApp(app_module.App):
|
||||
name=_('MediaWiki'), icon_filename='mediawiki',
|
||||
short_description=_('Wiki'),
|
||||
description=_description,
|
||||
manual_page='MediaWiki', clients=clients)
|
||||
manual_page='MediaWiki',
|
||||
clients=manifest.clients)
|
||||
self.add(info)
|
||||
|
||||
menu_item = menu.Menu('menu-mediawiki', info.name,
|
||||
@ -87,6 +89,10 @@ class MediaWikiApp(app_module.App):
|
||||
daemon = Daemon('daemon-mediawiki', managed_services[0])
|
||||
self.add(daemon)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-mediawiki',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
class Shortcut(frontpage.Shortcut):
|
||||
"""Frontpage shortcut for only logged users when in private mode."""
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.clients import validate
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
clients = validate([{
|
||||
'name': _('MediaWiki'),
|
||||
@ -13,7 +12,7 @@ clients = validate([{
|
||||
}]
|
||||
}])
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'config': {
|
||||
'files': ['/etc/mediawiki/FreedomBoxSettings.php']
|
||||
},
|
||||
@ -21,4 +20,4 @@ backup = validate_backup({
|
||||
'directories': ['/var/lib/mediawiki-db/']
|
||||
},
|
||||
'services': ['mediawiki-jobrunner']
|
||||
})
|
||||
}
|
||||
|
||||
@ -10,11 +10,12 @@ from django.utils.translation import ugettext_lazy as _
|
||||
from plinth import app as app_module
|
||||
from plinth import cfg, frontpage, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
from .manifest import backup, clients # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 2
|
||||
|
||||
@ -59,7 +60,8 @@ class MinetestApp(app_module.App):
|
||||
info = app_module.Info(
|
||||
app_id=self.app_id, version=version, name=_('Minetest'),
|
||||
icon_filename='minetest', short_description=_('Block Sandbox'),
|
||||
description=_description, manual_page='Minetest', clients=clients,
|
||||
description=_description, manual_page='Minetest',
|
||||
clients=manifest.clients,
|
||||
donation_url='https://www.minetest.net/get-involved/#donate')
|
||||
self.add(info)
|
||||
|
||||
@ -89,6 +91,10 @@ class MinetestApp(app_module.App):
|
||||
reserved_usernames=['Debian-minetest'])
|
||||
self.add(users_and_groups)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-minetest',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
"""Install and configure the module."""
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
from plinth.clients import store_url, validate
|
||||
|
||||
clients = validate([{
|
||||
@ -37,7 +36,7 @@ clients = validate([{
|
||||
}]
|
||||
}])
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'config': {
|
||||
'files': ['/etc/minetest/minetest.conf']
|
||||
},
|
||||
@ -45,4 +44,4 @@ backup = validate_backup({
|
||||
'directories': ['/var/games/minetest-server/']
|
||||
},
|
||||
'services': ['minetest-server']
|
||||
})
|
||||
}
|
||||
|
||||
@ -8,10 +8,11 @@ import plinth.app as app_module
|
||||
from plinth import actions, frontpage, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules.apache.components import Webserver
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
|
||||
from .manifest import backup, clients # noqa
|
||||
from . import manifest
|
||||
|
||||
version = 2
|
||||
|
||||
@ -47,7 +48,8 @@ class MiniDLNAApp(app_module.App):
|
||||
name=_('MiniDLNA'), icon_filename='minidlna',
|
||||
short_description=_('Simple Media Server'),
|
||||
description=_description,
|
||||
manual_page='MiniDLNA', clients=clients)
|
||||
manual_page='MiniDLNA',
|
||||
clients=manifest.clients)
|
||||
self.add(info)
|
||||
|
||||
menu_item = menu.Menu(
|
||||
@ -70,6 +72,10 @@ class MiniDLNAApp(app_module.App):
|
||||
allowed_groups=list(groups))
|
||||
daemon = Daemon('daemon-minidlna', managed_services[0])
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-minidlna',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
self.add(menu_item)
|
||||
self.add(webserver)
|
||||
self.add(firewall)
|
||||
|
||||
@ -2,124 +2,108 @@
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
from plinth.clients import validate, store_url
|
||||
from plinth.clients import store_url, validate
|
||||
|
||||
clients = validate([
|
||||
{
|
||||
'name': _('vlc'),
|
||||
'platforms': [
|
||||
{
|
||||
'type': 'package',
|
||||
'os': 'gnu-linux',
|
||||
'format': 'deb',
|
||||
'name': 'vlc',
|
||||
},
|
||||
{
|
||||
'type': 'package',
|
||||
'os': 'gnu-linux',
|
||||
'format': 'rpm',
|
||||
'name': 'vlc',
|
||||
},
|
||||
{
|
||||
'type': 'download',
|
||||
'os': 'windows',
|
||||
'url': 'https://www.videolan.org/vlc/download-windows.html',
|
||||
},
|
||||
{
|
||||
'type': 'download',
|
||||
'os': 'macos',
|
||||
'url': 'https://www.videolan.org/vlc/download-macosx.html',
|
||||
},
|
||||
{
|
||||
'type': 'store',
|
||||
'os': 'android',
|
||||
'store_name': 'google-play',
|
||||
'url': store_url('google-play', 'org.videolan.vlc')
|
||||
},
|
||||
{
|
||||
'type': 'store',
|
||||
'os': 'android',
|
||||
'store_name': 'f-droid',
|
||||
'url': store_url('f-droid', 'org.videolan.vlc')
|
||||
},
|
||||
]
|
||||
'name':
|
||||
_('vlc'),
|
||||
'platforms': [{
|
||||
'type': 'package',
|
||||
'os': 'gnu-linux',
|
||||
'format': 'deb',
|
||||
'name': 'vlc',
|
||||
}, {
|
||||
'type': 'package',
|
||||
'os': 'gnu-linux',
|
||||
'format': 'rpm',
|
||||
'name': 'vlc',
|
||||
}, {
|
||||
'type': 'download',
|
||||
'os': 'windows',
|
||||
'url': 'https://www.videolan.org/vlc/download-windows.html',
|
||||
}, {
|
||||
'type': 'download',
|
||||
'os': 'macos',
|
||||
'url': 'https://www.videolan.org/vlc/download-macosx.html',
|
||||
}, {
|
||||
'type': 'store',
|
||||
'os': 'android',
|
||||
'store_name': 'google-play',
|
||||
'url': store_url('google-play', 'org.videolan.vlc')
|
||||
}, {
|
||||
'type': 'store',
|
||||
'os': 'android',
|
||||
'store_name': 'f-droid',
|
||||
'url': store_url('f-droid', 'org.videolan.vlc')
|
||||
}]
|
||||
},
|
||||
{
|
||||
'name': _('kodi'),
|
||||
'platforms': [
|
||||
{
|
||||
'type': 'package',
|
||||
'os': 'gnu-linux',
|
||||
'format': 'deb',
|
||||
'name': 'kodi',
|
||||
},
|
||||
{
|
||||
'type': 'package',
|
||||
'os': 'gnu-linux',
|
||||
'format': 'rpm',
|
||||
'name': 'kodi',
|
||||
},
|
||||
{
|
||||
'type': 'download',
|
||||
'os': 'windows',
|
||||
'url': 'http://kodi.tv/download/',
|
||||
},
|
||||
{
|
||||
'type': 'download',
|
||||
'os': 'macos',
|
||||
'url': 'http://kodi.tv/download/',
|
||||
},
|
||||
{
|
||||
'type': 'store',
|
||||
'os': 'android',
|
||||
'store_name': 'google-play',
|
||||
'url': store_url('google-play', 'org.xbmc.kodi')
|
||||
},
|
||||
{
|
||||
'type': 'store',
|
||||
'os': 'android',
|
||||
'store_name': 'f-droid',
|
||||
'url': store_url('f-droid', 'org.xbmc.kodi')
|
||||
},
|
||||
]
|
||||
'name':
|
||||
_('kodi'),
|
||||
'platforms': [{
|
||||
'type': 'package',
|
||||
'os': 'gnu-linux',
|
||||
'format': 'deb',
|
||||
'name': 'kodi',
|
||||
}, {
|
||||
'type': 'package',
|
||||
'os': 'gnu-linux',
|
||||
'format': 'rpm',
|
||||
'name': 'kodi',
|
||||
}, {
|
||||
'type': 'download',
|
||||
'os': 'windows',
|
||||
'url': 'http://kodi.tv/download/',
|
||||
}, {
|
||||
'type': 'download',
|
||||
'os': 'macos',
|
||||
'url': 'http://kodi.tv/download/',
|
||||
}, {
|
||||
'type': 'store',
|
||||
'os': 'android',
|
||||
'store_name': 'google-play',
|
||||
'url': store_url('google-play', 'org.xbmc.kodi')
|
||||
}, {
|
||||
'type': 'store',
|
||||
'os': 'android',
|
||||
'store_name': 'f-droid',
|
||||
'url': store_url('f-droid', 'org.xbmc.kodi')
|
||||
}]
|
||||
},
|
||||
{
|
||||
'name': _('yaacc'),
|
||||
'platforms': [
|
||||
{
|
||||
'type': 'store',
|
||||
'os': 'android',
|
||||
'store_name': 'f-droid',
|
||||
'url': store_url('f-droid', 'de.yaacc')
|
||||
},
|
||||
]
|
||||
'name':
|
||||
_('yaacc'),
|
||||
'platforms': [{
|
||||
'type': 'store',
|
||||
'os': 'android',
|
||||
'store_name': 'f-droid',
|
||||
'url': store_url('f-droid', 'de.yaacc')
|
||||
}]
|
||||
},
|
||||
{
|
||||
'name': _('totem'),
|
||||
'platforms': [
|
||||
{
|
||||
'type': 'package',
|
||||
'os': 'gnu-linux',
|
||||
'format': 'deb',
|
||||
'name': 'totem',
|
||||
},
|
||||
{
|
||||
'type': 'package',
|
||||
'os': 'gnu-linux',
|
||||
'format': 'rpm',
|
||||
'name': 'totem',
|
||||
},
|
||||
]
|
||||
'name':
|
||||
_('totem'),
|
||||
'platforms': [{
|
||||
'type': 'package',
|
||||
'os': 'gnu-linux',
|
||||
'format': 'deb',
|
||||
'name': 'totem',
|
||||
}, {
|
||||
'type': 'package',
|
||||
'os': 'gnu-linux',
|
||||
'format': 'rpm',
|
||||
'name': 'totem',
|
||||
}]
|
||||
},
|
||||
])
|
||||
|
||||
# TODO: get all media directories from config file
|
||||
# for now hard code default media folder.
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'data': {
|
||||
'files': ['/etc/minidlna.conf'],
|
||||
'directories': ['/var/lib/minidlna']
|
||||
},
|
||||
'services': ['minidlna']
|
||||
})
|
||||
}
|
||||
|
||||
@ -10,12 +10,13 @@ from plinth import app as app_module
|
||||
from plinth import cfg, frontpage, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules.apache.components import Webserver
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.users import add_user_to_share_group
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
from .manifest import backup, clients # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 2
|
||||
|
||||
@ -56,7 +57,8 @@ class MLDonkeyApp(app_module.App):
|
||||
app_id=self.app_id, version=version, name=_('MLDonkey'),
|
||||
icon_filename='mldonkey',
|
||||
short_description=_('Peer-to-peer File Sharing'),
|
||||
description=_description, manual_page='MLDonkey', clients=clients)
|
||||
description=_description, manual_page='MLDonkey',
|
||||
clients=manifest.clients)
|
||||
self.add(info)
|
||||
|
||||
menu_item = menu.Menu('menu-mldonkey', info.name,
|
||||
@ -88,6 +90,10 @@ class MLDonkeyApp(app_module.App):
|
||||
groups=groups)
|
||||
self.add(users_and_groups)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-mldonkey',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
"""Install and configure the module."""
|
||||
|
||||
@ -6,7 +6,6 @@ Application manifest for mldonkey.
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.clients import store_url, validate
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
clients = validate([{
|
||||
'name': _('MLDonkey'),
|
||||
@ -37,7 +36,7 @@ clients = validate([{
|
||||
}]
|
||||
}])
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'config': {
|
||||
'files': [
|
||||
'/var/lib/mldonkey/bittorrent.ini', '/var/lib/mldonkey/bt_dht.ini',
|
||||
@ -55,4 +54,4 @@ backup = validate_backup({
|
||||
]
|
||||
},
|
||||
'services': ['mldonkey-server']
|
||||
})
|
||||
}
|
||||
|
||||
@ -7,9 +7,10 @@ from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth import app as app_module
|
||||
from plinth import menu
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
|
||||
from .manifest import backup # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 1
|
||||
|
||||
@ -60,6 +61,10 @@ class MonkeysphereApp(app_module.App):
|
||||
reserved_usernames=['monkeysphere'])
|
||||
self.add(users_and_groups)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-monkeysphere',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
"""Install and configure the module."""
|
||||
|
||||
@ -3,13 +3,11 @@
|
||||
Application manfiest for monkeysphere.
|
||||
"""
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'config': {
|
||||
'directories': ['/etc/monkeysphere/']
|
||||
},
|
||||
'secrets': {
|
||||
'directories': ['/var/lib/monkeysphere/']
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -13,12 +13,13 @@ from plinth import app as app_module
|
||||
from plinth import frontpage, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules import names
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.letsencrypt.components import LetsEncrypt
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
from plinth.utils import Version
|
||||
|
||||
from .manifest import backup, clients # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 2
|
||||
|
||||
@ -50,7 +51,8 @@ class MumbleApp(app_module.App):
|
||||
info = app_module.Info(
|
||||
app_id=self.app_id, version=version, name=_('Mumble'),
|
||||
icon_filename='mumble', short_description=_('Voice Chat'),
|
||||
description=_description, manual_page='Mumble', clients=clients,
|
||||
description=_description, manual_page='Mumble',
|
||||
clients=manifest.clients,
|
||||
donation_url='https://wiki.mumble.info/wiki/Donate')
|
||||
self.add(info)
|
||||
|
||||
@ -88,6 +90,10 @@ class MumbleApp(app_module.App):
|
||||
reserved_usernames=['mumble-server'])
|
||||
self.add(users_and_groups)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-mumble',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
"""Install and configure the module."""
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.clients import store_url, validate
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
clients = validate([{
|
||||
'name':
|
||||
@ -55,9 +54,9 @@ clients = validate([{
|
||||
}]
|
||||
}])
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'data': {
|
||||
'directories': ['/var/lib/mumble-server']
|
||||
},
|
||||
'services': ['mumble-server']
|
||||
})
|
||||
}
|
||||
|
||||
@ -9,11 +9,11 @@ from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth import app as app_module
|
||||
from plinth import cfg, menu
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.signals import domain_added, domain_removed
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
from . import components
|
||||
from .manifest import backup # noqa, pylint: disable=unused-import
|
||||
from . import components, manifest
|
||||
|
||||
version = 1
|
||||
|
||||
@ -52,6 +52,10 @@ class NamesApp(app_module.App):
|
||||
'names:index', parent_url_name='system')
|
||||
self.add(menu_item)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-names',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
domain_added.connect(on_domain_added)
|
||||
domain_removed.connect(on_domain_removed)
|
||||
|
||||
|
||||
@ -3,6 +3,4 @@
|
||||
Application manifest for names.
|
||||
"""
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
backup = validate_backup({})
|
||||
backup = {}
|
||||
|
||||
@ -12,11 +12,12 @@ from plinth import actions
|
||||
from plinth import app as app_module
|
||||
from plinth import cfg, frontpage, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
from .manifest import backup, clients # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 4
|
||||
|
||||
@ -60,7 +61,7 @@ class OpenVPNApp(app_module.App):
|
||||
name=_('OpenVPN'), icon_filename='openvpn',
|
||||
short_description=_('Virtual Private Network'),
|
||||
description=_description, manual_page='OpenVPN',
|
||||
clients=clients)
|
||||
clients=manifest.clients)
|
||||
self.add(info)
|
||||
|
||||
menu_item = menu.Menu('menu-openvpn', info.name,
|
||||
@ -92,6 +93,10 @@ class OpenVPNApp(app_module.App):
|
||||
groups=self.groups)
|
||||
self.add(users_and_groups)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-openvpn',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
def is_enabled(self):
|
||||
"""Return whether all the leader components are enabled.
|
||||
|
||||
|
||||
@ -6,12 +6,11 @@ Application manifest for OpenVPN.
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.clients import store_url, validate
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
_package_id = 'de.blinkt.openvpn'
|
||||
_download_url = 'https://openvpn.net/community-downloads'
|
||||
|
||||
backup = validate_backup({'secrets': {'directories': ['/etc/openvpn/']}})
|
||||
backup = {'secrets': {'directories': ['/etc/openvpn/']}}
|
||||
|
||||
clients = validate([{
|
||||
'name':
|
||||
|
||||
@ -9,11 +9,11 @@ from plinth import actions
|
||||
from plinth import app as app_module
|
||||
from plinth import cfg, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.names.components import DomainType
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
from . import utils
|
||||
from .manifest import backup # noqa, pylint: disable=unused-import
|
||||
from . import manifest, utils
|
||||
|
||||
version = 2
|
||||
|
||||
@ -80,6 +80,10 @@ class PagekiteApp(app_module.App):
|
||||
daemon = Daemon('daemon-pagekite', managed_services[0])
|
||||
self.add(daemon)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-pagekite',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
# Register kite name with Name Services module.
|
||||
setup_helper = globals()['setup_helper']
|
||||
if setup_helper.get_state() != 'needs-setup' and self.is_enabled():
|
||||
|
||||
@ -3,11 +3,9 @@
|
||||
Application manifest for pagekite.
|
||||
"""
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'config': {
|
||||
'directories': ['/etc/pagekite.d/']
|
||||
},
|
||||
'services': ['pagekite']
|
||||
})
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ from plinth import app as app_module
|
||||
from plinth import menu
|
||||
from plinth.daemon import Daemon
|
||||
|
||||
from .manifest import clients
|
||||
from . import manifest
|
||||
|
||||
version = 1
|
||||
|
||||
@ -45,7 +45,8 @@ class PerformanceApp(app_module.App):
|
||||
name=_('Performance'), icon='fa-bar-chart',
|
||||
short_description=_('System Monitoring'),
|
||||
description=_description,
|
||||
manual_page='Performance', clients=clients)
|
||||
manual_page='Performance',
|
||||
clients=manifest.clients)
|
||||
self.add(info)
|
||||
|
||||
menu_item = menu.Menu('menu-performance', info.name,
|
||||
|
||||
@ -6,8 +6,9 @@ FreedomBox app for power controls.
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth import app as app_module
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
|
||||
from .manifest import backup # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 1
|
||||
|
||||
@ -32,4 +33,8 @@ class PowerApp(app_module.App):
|
||||
description=_description, manual_page='Power')
|
||||
self.add(info)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-power',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
# not in menu, see issue #834
|
||||
|
||||
@ -3,6 +3,4 @@
|
||||
Application manifest for power.
|
||||
"""
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
backup = validate_backup({})
|
||||
backup = {}
|
||||
|
||||
@ -11,11 +11,12 @@ from plinth import app as app_module
|
||||
from plinth import cfg, frontpage, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules.apache.components import diagnose_url
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.utils import format_lazy
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
from .manifest import backup # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 1
|
||||
|
||||
@ -82,6 +83,10 @@ class PrivoxyApp(app_module.App):
|
||||
reserved_usernames=['privoxy'])
|
||||
self.add(users_and_groups)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-privoxy',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
def diagnose(self):
|
||||
"""Run diagnostics and return the results."""
|
||||
results = super().diagnose()
|
||||
|
||||
@ -3,6 +3,4 @@
|
||||
Application manifest for privoxy.
|
||||
"""
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
backup = validate_backup({})
|
||||
backup = {}
|
||||
|
||||
@ -13,12 +13,13 @@ from plinth import app as app_module
|
||||
from plinth import cfg, frontpage, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules import names
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.letsencrypt.components import LetsEncrypt
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
from .manifest import backup, clients # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 1
|
||||
|
||||
@ -59,7 +60,7 @@ class QuasselApp(app_module.App):
|
||||
name=_('Quassel'), icon_filename='quassel',
|
||||
short_description=_('IRC Client'),
|
||||
description=_description, manual_page='Quassel',
|
||||
clients=clients)
|
||||
clients=manifest.clients)
|
||||
self.add(info)
|
||||
|
||||
menu_item = menu.Menu('menu-quassel', info.name,
|
||||
@ -96,6 +97,10 @@ class QuasselApp(app_module.App):
|
||||
reserved_usernames=['quasselcore'])
|
||||
self.add(users_and_groups)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-quassel',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
"""Install and configure the module."""
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.clients import store_url, validate
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
clients = validate([{
|
||||
'name':
|
||||
@ -45,9 +44,9 @@ clients = validate([{
|
||||
}]
|
||||
}])
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'secrets': {
|
||||
'directories': ['/var/lib/quassel/']
|
||||
},
|
||||
'services': ['quasselcore'],
|
||||
})
|
||||
}
|
||||
|
||||
@ -12,11 +12,12 @@ from plinth import actions
|
||||
from plinth import app as app_module
|
||||
from plinth import cfg, frontpage, menu
|
||||
from plinth.modules.apache.components import Uwsgi, Webserver
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
from plinth.utils import Version, format_lazy
|
||||
|
||||
from .manifest import backup, clients # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 2
|
||||
|
||||
@ -54,7 +55,8 @@ class RadicaleApp(app_module.App):
|
||||
name=_('Radicale'), icon_filename='radicale',
|
||||
short_description=_('Calendar and Addressbook'),
|
||||
description=_description,
|
||||
manual_page='Radicale', clients=clients)
|
||||
manual_page='Radicale',
|
||||
clients=manifest.clients)
|
||||
self.add(info)
|
||||
|
||||
menu_item = menu.Menu('menu-radicale', info.name,
|
||||
@ -84,6 +86,10 @@ class RadicaleApp(app_module.App):
|
||||
reserved_usernames=['radicale'])
|
||||
self.add(users_and_groups)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-radicale',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
def enable(self):
|
||||
"""Fix missing directories before enabling radicale."""
|
||||
actions.superuser_run('radicale', ['fix-paths'])
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.clients import store_url, validate
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
clients = validate([{
|
||||
'name':
|
||||
@ -79,9 +78,9 @@ clients = validate([{
|
||||
}]
|
||||
}])
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'data': {
|
||||
'directories': ['/var/lib/radicale/']
|
||||
},
|
||||
'services': ['uwsgi']
|
||||
})
|
||||
}
|
||||
|
||||
@ -9,9 +9,10 @@ from plinth import actions
|
||||
from plinth import app as app_module
|
||||
from plinth import frontpage, menu
|
||||
from plinth.modules.apache.components import Webserver
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
|
||||
from .manifest import backup, clients # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 1
|
||||
|
||||
@ -53,7 +54,8 @@ class RoundcubeApp(app_module.App):
|
||||
name=_('Roundcube'), icon_filename='roundcube',
|
||||
short_description=_('Email Client'),
|
||||
description=_description,
|
||||
manual_page='Roundcube', clients=clients)
|
||||
manual_page='Roundcube',
|
||||
clients=manifest.clients)
|
||||
self.add(info)
|
||||
|
||||
menu_item = menu.Menu('menu-roundcube', info.name,
|
||||
@ -76,6 +78,10 @@ class RoundcubeApp(app_module.App):
|
||||
urls=['https://{host}/roundcube'])
|
||||
self.add(webserver)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-roundcube',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
"""Install and configure the module."""
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.clients import validate
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
clients = validate([{
|
||||
'name': _('Roundcube'),
|
||||
@ -13,4 +12,4 @@ clients = validate([{
|
||||
}]
|
||||
}])
|
||||
|
||||
backup = validate_backup({})
|
||||
backup = {}
|
||||
|
||||
@ -15,11 +15,12 @@ from plinth import actions
|
||||
from plinth import app as app_module
|
||||
from plinth import frontpage, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
from .manifest import backup, clients # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 2
|
||||
|
||||
@ -60,7 +61,8 @@ class SambaApp(app_module.App):
|
||||
info = app_module.Info(
|
||||
app_id=self.app_id, version=version, name=_('Samba'),
|
||||
icon_filename='samba', short_description=_('Network File Storage'),
|
||||
manual_page='Samba', description=_description, clients=clients,
|
||||
manual_page='Samba', description=_description,
|
||||
clients=manifest.clients,
|
||||
donation_url='https://www.samba.org/samba/donations.html')
|
||||
self.add(info)
|
||||
|
||||
@ -96,6 +98,23 @@ class SambaApp(app_module.App):
|
||||
groups=groups)
|
||||
self.add(users_and_groups)
|
||||
|
||||
backup_restore = SambaBackupRestore('backup-restore-samba',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
class SambaBackupRestore(BackupRestore):
|
||||
"""Component to backup/restore Samba."""
|
||||
|
||||
def backup_pre(self, packet):
|
||||
"""Save registry share configuration."""
|
||||
actions.superuser_run('samba', ['dump-shares'])
|
||||
|
||||
def restore_post(self, packet):
|
||||
"""Restore configuration."""
|
||||
actions.superuser_run('samba', ['setup'])
|
||||
actions.superuser_run('samba', ['restore-shares'])
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
"""Install and configure the module."""
|
||||
@ -148,14 +167,3 @@ def get_shares():
|
||||
output = actions.superuser_run('samba', ['get-shares'])
|
||||
|
||||
return json.loads(output)
|
||||
|
||||
|
||||
def backup_pre(packet):
|
||||
"""Save registry share configuration."""
|
||||
actions.superuser_run('samba', ['dump-shares'])
|
||||
|
||||
|
||||
def restore_post(packet):
|
||||
"""Restore configuration."""
|
||||
actions.superuser_run('samba', ['setup'])
|
||||
actions.superuser_run('samba', ['restore-shares'])
|
||||
|
||||
@ -6,7 +6,6 @@ Application manifest for Samba.
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.clients import store_url, validate
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
SHARES_CONF_BACKUP_FILE = '/var/lib/plinth/backups-data/samba-shares-dump.conf'
|
||||
|
||||
@ -77,9 +76,9 @@ clients = validate([{
|
||||
}]
|
||||
}])
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'data': {
|
||||
'files': [SHARES_CONF_BACKUP_FILE]
|
||||
},
|
||||
'services': ['smbd', 'nmbd']
|
||||
})
|
||||
}
|
||||
|
||||
@ -11,11 +11,11 @@ from plinth import actions
|
||||
from plinth import app as app_module
|
||||
from plinth import frontpage, menu
|
||||
from plinth.modules.apache.components import Uwsgi, Webserver
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
|
||||
from .manifest import backup # noqa, pylint: disable=unused-import
|
||||
from .manifest import (PUBLIC_ACCESS_SETTING_FILE, clients)
|
||||
from . import manifest
|
||||
|
||||
version = 4
|
||||
|
||||
@ -47,7 +47,8 @@ class SearxApp(app_module.App):
|
||||
info = app_module.Info(
|
||||
app_id=self.app_id, version=version, name=_('Searx'),
|
||||
icon_filename='searx', short_description=_('Web Search'),
|
||||
description=_description, manual_page='Searx', clients=clients,
|
||||
description=_description, manual_page='Searx',
|
||||
clients=manifest.clients,
|
||||
donation_url='https://searx.me/static/donate.html')
|
||||
self.add(info)
|
||||
|
||||
@ -83,6 +84,10 @@ class SearxApp(app_module.App):
|
||||
groups=groups)
|
||||
self.add(users_and_groups)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-searx',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
def set_shortcut_login_required(self, login_required):
|
||||
"""Change the login_required property of shortcut."""
|
||||
shortcut = self.remove('shortcut-searx')
|
||||
@ -122,7 +127,7 @@ def get_safe_search_setting():
|
||||
|
||||
def is_public_access_enabled():
|
||||
"""Check whether public access is enabled for Searx."""
|
||||
return os.path.exists(PUBLIC_ACCESS_SETTING_FILE)
|
||||
return os.path.exists(manifest.PUBLIC_ACCESS_SETTING_FILE)
|
||||
|
||||
|
||||
def enable_public_access():
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.clients import validate
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
clients = validate([{
|
||||
'name': _('Searx'),
|
||||
@ -15,4 +14,4 @@ clients = validate([{
|
||||
|
||||
PUBLIC_ACCESS_SETTING_FILE = '/etc/searx/allow_public_access'
|
||||
|
||||
backup = validate_backup({'config': {'files': [PUBLIC_ACCESS_SETTING_FILE]}})
|
||||
backup = {'config': {'files': [PUBLIC_ACCESS_SETTING_FILE]}}
|
||||
|
||||
@ -13,8 +13,9 @@ from django.utils.translation import ugettext_lazy as _
|
||||
from plinth import actions
|
||||
from plinth import app as app_module
|
||||
from plinth import menu, module_loader
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
|
||||
from .manifest import backup # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 6
|
||||
|
||||
@ -50,6 +51,10 @@ class SecurityApp(app_module.App):
|
||||
'security:index', parent_url_name='system')
|
||||
self.add(menu_item)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-security',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
"""Install the required packages"""
|
||||
|
||||
@ -3,9 +3,4 @@
|
||||
Application manifest for security.
|
||||
"""
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
backup = validate_backup(
|
||||
{'config': {
|
||||
'files': ['/etc/security/access.d/50freedombox.conf']
|
||||
}})
|
||||
backup = {'config': {'files': ['/etc/security/access.d/50freedombox.conf']}}
|
||||
|
||||
@ -10,7 +10,7 @@ from plinth import frontpage, menu
|
||||
from plinth.modules.apache.components import Webserver
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
|
||||
from .manifest import clients
|
||||
from . import manifest
|
||||
|
||||
version = 1
|
||||
|
||||
@ -37,7 +37,7 @@ class ShaarliApp(app_module.App):
|
||||
name=_('Shaarli'), icon_filename='shaarli',
|
||||
short_description=_('Bookmarks'),
|
||||
description=_description, manual_page='Shaarli',
|
||||
clients=clients)
|
||||
clients=manifest.clients)
|
||||
self.add(info)
|
||||
|
||||
menu_item = menu.Menu('menu-shaarli', info.name,
|
||||
|
||||
@ -10,10 +10,11 @@ from plinth import actions
|
||||
from plinth import app as app_module
|
||||
from plinth import cfg, frontpage, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
from .manifest import backup # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 3
|
||||
|
||||
@ -76,6 +77,10 @@ class ShadowsocksApp(app_module.App):
|
||||
listen_ports=[(1080, 'tcp4'), (1080, 'tcp6')])
|
||||
self.add(daemon)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-shadowsocks',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
"""Install and configure the module."""
|
||||
|
||||
@ -3,13 +3,11 @@
|
||||
Application manifest for shadowsocks.
|
||||
"""
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'secrets': {
|
||||
'files': [
|
||||
'/var/lib/private/shadowsocks-libev/freedombox/freedombox.json'
|
||||
]
|
||||
},
|
||||
'services': ['shadowsocks-libev-local@freedombox']
|
||||
})
|
||||
}
|
||||
|
||||
@ -10,9 +10,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.modules.backups.components import BackupRestore
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
from .manifest import backup # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 1
|
||||
|
||||
@ -44,6 +45,10 @@ class SharingApp(app_module.App):
|
||||
parent_url_name='apps')
|
||||
self.add(menu_item)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-sharing',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
def list_shares():
|
||||
"""Return a list of shares."""
|
||||
|
||||
@ -3,9 +3,7 @@
|
||||
Application manifest for sharing.
|
||||
"""
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'config': {
|
||||
'files': ['/etc/apache2/conf-available/sharing-freedombox.conf']
|
||||
},
|
||||
@ -14,4 +12,4 @@ backup = validate_backup({
|
||||
'kind': 'config',
|
||||
'name': 'sharing-freedombox'
|
||||
}]
|
||||
})
|
||||
}
|
||||
|
||||
@ -13,8 +13,9 @@ from plinth import actions
|
||||
from plinth import app as app_module
|
||||
from plinth import menu
|
||||
from plinth.modules import storage
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
|
||||
from .manifest import backup # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 4
|
||||
|
||||
@ -61,6 +62,18 @@ class SnapshotApp(app_module.App):
|
||||
'snapshot:index', parent_url_name='system')
|
||||
self.add(menu_item)
|
||||
|
||||
backup_restore = SnapshotBackupRestore('backup-restore-snapshot',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
class SnapshotBackupRestore(BackupRestore):
|
||||
"""Component to backup/restore snapshot module."""
|
||||
|
||||
def restore_post(self, packet):
|
||||
"""Run after restore."""
|
||||
actions.superuser_run('snapshot', ['kill-daemon'])
|
||||
|
||||
|
||||
def is_supported():
|
||||
"""Return whether snapshots are support on current setup."""
|
||||
@ -129,8 +142,3 @@ def get_configuration():
|
||||
'free_space':
|
||||
output['FREE_LIMIT'],
|
||||
}
|
||||
|
||||
|
||||
def restore_post(packet):
|
||||
"""Run after restore."""
|
||||
actions.superuser_run('snapshot', ['kill-daemon'])
|
||||
|
||||
@ -3,10 +3,8 @@
|
||||
Application manifest for snapshot.
|
||||
"""
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'config': {
|
||||
'files': ['/etc/snapper/configs/root', '/etc/default/snapper']
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -13,9 +13,10 @@ from plinth import actions
|
||||
from plinth import app as app_module
|
||||
from plinth import menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
|
||||
from .manifest import backup # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 1
|
||||
|
||||
@ -60,6 +61,9 @@ class SSHApp(app_module.App):
|
||||
daemon = Daemon('daemon-ssh', managed_services[0])
|
||||
self.add(daemon)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-ssh', **manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
"""Configure the module."""
|
||||
|
||||
@ -3,9 +3,7 @@
|
||||
Application manifest for ssh.
|
||||
"""
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'secrets': {
|
||||
'files': [
|
||||
'/etc/ssh/ssh_host_ecdsa_key', '/etc/ssh/ssh_host_ecdsa_key.pub',
|
||||
@ -14,4 +12,4 @@ backup = validate_backup({
|
||||
'/etc/ssh/ssh_host_rsa_key.pub'
|
||||
]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -15,10 +15,10 @@ from plinth import actions
|
||||
from plinth import app as app_module
|
||||
from plinth import cfg, glib, menu
|
||||
from plinth.errors import ActionError, PlinthError
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
from . import udisks2
|
||||
from .manifest import backup # noqa, pylint: disable=unused-import
|
||||
from . import manifest, udisks2
|
||||
|
||||
version = 4
|
||||
|
||||
@ -59,6 +59,10 @@ class StorageApp(app_module.App):
|
||||
'storage:index', parent_url_name='system')
|
||||
self.add(menu_item)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-storage',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
# Check every hour for low disk space, every 3 minutes in debug mode
|
||||
interval = 180 if cfg.develop else 3600
|
||||
glib.schedule(interval, warn_about_low_disk_space)
|
||||
|
||||
@ -3,6 +3,4 @@
|
||||
Application manifest for storage.
|
||||
"""
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
backup = validate_backup({})
|
||||
backup = {}
|
||||
|
||||
@ -10,12 +10,13 @@ from plinth import app as app_module
|
||||
from plinth import cfg, frontpage, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules.apache.components import Webserver
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
from plinth.modules.users import add_user_to_share_group
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
from .manifest import backup, clients # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 3
|
||||
|
||||
@ -59,7 +60,8 @@ class SyncthingApp(app_module.App):
|
||||
name=_('Syncthing'), icon_filename='syncthing',
|
||||
short_description=_('File Synchronization'),
|
||||
description=_description,
|
||||
manual_page='Syncthing', clients=clients,
|
||||
manual_page='Syncthing',
|
||||
clients=manifest.clients,
|
||||
donation_url='https://syncthing.net/donations/')
|
||||
self.add(info)
|
||||
|
||||
@ -95,6 +97,10 @@ class SyncthingApp(app_module.App):
|
||||
[SYSTEM_USER], self.groups)
|
||||
self.add(users_and_groups)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-syncthing',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
"""Install and configure the module."""
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.clients import store_url, validate
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
_package_id = 'com.nutomic.syncthingandroid'
|
||||
_download_url = 'https://syncthing.net/'
|
||||
@ -47,9 +46,9 @@ clients = validate([{
|
||||
}]
|
||||
}])
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'secrets': {
|
||||
'directories': ['/var/lib/syncthing/.config']
|
||||
},
|
||||
'services': ['syncthing@syncthing']
|
||||
})
|
||||
}
|
||||
|
||||
@ -14,11 +14,12 @@ from plinth import app as app_module
|
||||
from plinth import cfg, frontpage, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules.apache.components import Webserver, diagnose_url
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.utils import format_lazy
|
||||
|
||||
from . import manifest
|
||||
from .errors import TahoeConfigurationError
|
||||
from .manifest import backup # noqa, pylint: disable=unused-import
|
||||
|
||||
version = 1
|
||||
|
||||
@ -87,6 +88,10 @@ class TahoeApp(app_module.App):
|
||||
daemon = Daemon('daemon-tahoe', managed_services[0])
|
||||
self.add(daemon)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-tahoe',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
def is_enabled(self):
|
||||
"""Return whether all the leader components are enabled.
|
||||
|
||||
|
||||
@ -3,11 +3,9 @@
|
||||
Application manfiest for tahoe-lafs.
|
||||
"""
|
||||
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'secrets': {
|
||||
'directories': ['/var/lib/tahoe-lafs/']
|
||||
},
|
||||
'services': ['tahoe-lafs']
|
||||
})
|
||||
}
|
||||
|
||||
@ -13,13 +13,13 @@ from plinth import menu
|
||||
from plinth.daemon import (Daemon, app_is_running, diagnose_netcat,
|
||||
diagnose_port_listening)
|
||||
from plinth.modules.apache.components import diagnose_url
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.names.components import DomainType
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
from plinth.signals import domain_added, domain_removed
|
||||
|
||||
from . import utils
|
||||
from .manifest import backup, clients # noqa, pylint: disable=unused-import
|
||||
from . import manifest, utils
|
||||
|
||||
version = 5
|
||||
|
||||
@ -55,7 +55,7 @@ class TorApp(app_module.App):
|
||||
name=_('Tor'), icon_filename='tor',
|
||||
short_description=_('Anonymity Network'),
|
||||
description=_description, manual_page='Tor',
|
||||
clients=clients,
|
||||
clients=manifest.clients,
|
||||
donation_url='https://donate.torproject.org/')
|
||||
self.add(info)
|
||||
|
||||
@ -87,6 +87,9 @@ class TorApp(app_module.App):
|
||||
reserved_usernames=['debian-tor'])
|
||||
self.add(users_and_groups)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-tor', **manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
# Register hidden service name with Name Services module.
|
||||
setup_helper = globals()['setup_helper']
|
||||
if setup_helper.get_state() != 'needs-setup' and \
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.clients import store_url, validate
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
_orbot_package_id = 'org.torproject.android'
|
||||
_tor_browser_download_url = \
|
||||
@ -41,7 +40,7 @@ clients = validate([{
|
||||
}]
|
||||
}])
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'config': {
|
||||
'directories': ['/etc/tor/']
|
||||
},
|
||||
@ -49,4 +48,4 @@ backup = validate_backup({
|
||||
'directories': ['/var/lib/tor/', '/var/lib/tor-instances/']
|
||||
},
|
||||
'services': ['tor@plinth']
|
||||
})
|
||||
}
|
||||
|
||||
@ -12,11 +12,12 @@ from plinth import app as app_module
|
||||
from plinth import frontpage, menu
|
||||
from plinth.daemon import Daemon
|
||||
from plinth.modules.apache.components import Webserver
|
||||
from plinth.modules.backups.components import BackupRestore
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.users import add_user_to_share_group
|
||||
from plinth.modules.users.components import UsersAndGroups
|
||||
|
||||
from .manifest import backup, clients # noqa, pylint: disable=unused-import
|
||||
from . import manifest
|
||||
|
||||
version = 3
|
||||
|
||||
@ -52,7 +53,8 @@ class TransmissionApp(app_module.App):
|
||||
icon_filename='transmission',
|
||||
short_description=_('BitTorrent Web Client'),
|
||||
description=_description, manual_page='Transmission',
|
||||
clients=clients, donation_url='https://transmissionbt.com/donate/')
|
||||
clients=manifest.clients,
|
||||
donation_url='https://transmissionbt.com/donate/')
|
||||
self.add(info)
|
||||
|
||||
menu_item = menu.Menu('menu-transmission', info.name,
|
||||
@ -84,6 +86,10 @@ class TransmissionApp(app_module.App):
|
||||
groups=groups)
|
||||
self.add(users_and_groups)
|
||||
|
||||
backup_restore = BackupRestore('backup-restore-transmission',
|
||||
**manifest.backup)
|
||||
self.add(backup_restore)
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
"""Install and configure the module."""
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from plinth.clients import validate
|
||||
from plinth.modules.backups.api import validate as validate_backup
|
||||
|
||||
clients = validate([{
|
||||
'name': _('Transmission'),
|
||||
@ -13,7 +12,7 @@ clients = validate([{
|
||||
}]
|
||||
}])
|
||||
|
||||
backup = validate_backup({
|
||||
backup = {
|
||||
'data': {
|
||||
'directories': ['/var/lib/transmission-daemon/.config']
|
||||
},
|
||||
@ -21,4 +20,4 @@ backup = validate_backup({
|
||||
'files': ['/etc/transmission-daemon/settings.json']
|
||||
},
|
||||
'services': ['transmission-daemon']
|
||||
})
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user