Fixed restore mode

This commit is contained in:
Antoine Nguyen
2022-11-09 10:30:44 +01:00
parent d6f9a5b913
commit 37633008cb
12 changed files with 103 additions and 63 deletions

60
.github/workflows/installer.yml vendored Normal file
View File

@@ -0,0 +1,60 @@
name: Modoboa installer
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.7, 3.8, 3.9]
fail-fast: false
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
pip install -r test-requirements.txt
- name: Run tests
if: ${{ matrix.python-version != '3.9' }}
run: |
python tests.py
- name: Run tests and coverage
if: ${{ matrix.python-version == '3.9' }}
run: |
coverage run tests.py
- name: Upload coverage result
if: ${{ matrix.python-version == '3.9' }}
uses: actions/upload-artifact@v2
with:
name: coverage-results
path: .coverage
coverage:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install dependencies
run: |
pip install codecov
- name: Download coverage results
uses: actions/download-artifact@v2
with:
name: coverage-results
- name: Report coverage
run: |
coverage report
codecov

View File

@@ -1,15 +0,0 @@
sudo: false
language: python
cache: pip
python:
- "2.7"
- "3.4"
before_install:
- pip install -r test-requirements.txt
script:
- coverage run tests.py
after_success:
- codecov

View File

@@ -1,7 +1,7 @@
modoboa-installer
=================
|travis| |codecov|
|workflow| |codecov|
An installer which deploy a complete mail server based on Modoboa.
@@ -100,7 +100,7 @@ An experimental backup mode is available.
.. warning::
You must keep the original configuration file, i.e. the one used for
the installation. Otherwise, you will need to recreate it manually with the right information !
the installation. Otherwise, you will need to recreate it manually with the right information!
You can start the process as follows::
@@ -108,7 +108,7 @@ You can start the process as follows::
Then follow the step on the console.
There are also a non-interactive mode:
There is also a non-interactive mode:
1. Silent mode
@@ -116,21 +116,17 @@ Command::
$ sudo ./run.py --silent-backup <your domain>
This mode is the silent batch mode, when executed, it will create /modoboa_backup/ and each time you execute it, it will create a new backup directory with current date and time.
This mode will run silently. When executed, it will create
/modoboa_backup/ and each time you execute it, it will create a new
backup directory with current date and time.
You can supply a custom path.
Command::
You can supply a custom path if needed::
$ sudo ./run.py --silent-backup --backup-path /path/of/backup/directory <your domain>
This mode is the same as silent batch mode, but you provide the path to the backup directory you want.
If you want to disable emails backup, disable dovecot in the
configuration file (set enabled to False).
If you want to disable mail backup::
$ sudo ./run.py {--backup|--silent-backup} --no-mail-backup <your domain>
This can be useful for larger instance.
Restore mode
@@ -142,7 +138,7 @@ You can start the process as follows::
$ sudo ./run.py --restore /path/to/backup/directory/ <your domain>
Then wait for the process to finish
Then wait for the process to finish.
Change the generated hostname
-----------------------------
@@ -187,7 +183,6 @@ modify the following settings::
Change the ``email`` setting to a valid value since it will be used
for account recovery.
.. |travis| image:: https://travis-ci.org/modoboa/modoboa-installer.png?branch=master
:target: https://travis-ci.org/modoboa/modoboa-installer
.. |workflow| image:: https://github.com/modoboa/modoboa-installer/workflows/Modoboa%20installer/badge.svg
.. |codecov| image:: http://codecov.io/github/modoboa/modoboa-installer/coverage.svg?branch=master
:target: http://codecov.io/github/modoboa/modoboa-installer?branch=master

View File

@@ -17,7 +17,7 @@ def load_app_script(appname):
return script
def install(appname, config, upgrade, restore):
def install(appname: str, config, upgrade: bool, archive_path: str):
"""Install an application."""
if (config.has_option(appname, "enabled") and
not config.getboolean(appname, "enabled")):
@@ -26,9 +26,9 @@ def install(appname, config, upgrade, restore):
utils.printcolor("Installing {}".format(appname), utils.MAGENTA)
script = load_app_script(appname)
try:
getattr(script, appname.capitalize())(config, upgrade, restore).run()
getattr(script, appname.capitalize())(config, upgrade, archive_path).run()
except utils.FatalError as inst:
utils.printcolor(u"{}".format(inst), utils.RED)
utils.error("{}".format(inst))
sys.exit(1)
@@ -43,7 +43,7 @@ def backup(appname, config, path):
try:
getattr(script, appname.capitalize())(config, False, False).backup(path)
except utils.FatalError as inst:
utils.printcolor(u"{}".format(inst), utils.RED)
utils.error("{}".format(inst))
sys.exit(1)

View File

@@ -92,8 +92,8 @@ class Amavis(base.Installer):
def post_run(self):
"""Additional tasks."""
install("spamassassin", self.config, self.upgrade, self.restore)
install("clamav", self.config, self.upgrade, self.restore)
install("spamassassin", self.config, self.upgrade, self.archive_path)
install("clamav", self.config, self.upgrade, self.archive_path)
def custom_backup(self, path):
"""Backup custom configuration if any."""
@@ -109,7 +109,7 @@ class Amavis(base.Installer):
if package.backend.FORMAT != "deb":
return
amavis_custom_configuration = os.path.join(
self.restore, "custom/99-custom")
self.archive_path, "custom/99-custom")
if os.path.isfile(amavis_custom_configuration):
utils.copy_file(amavis_custom_configuration, os.path.join(
self.config_dir, "conf.d"))

View File

@@ -20,11 +20,11 @@ class Installer(object):
with_db = False
config_files = []
def __init__(self, config, upgrade, restore):
def __init__(self, config, upgrade: bool, archive_path: str):
"""Get configuration."""
self.config = config
self.upgrade = upgrade
self.restore = restore
self.archive_path = archive_path
if self.config.has_section(self.appname):
self.app_config = dict(self.config.items(self.appname))
self.dbengine = self.config.get("database", "engine")
@@ -61,7 +61,7 @@ class Installer(object):
utils.MAGENTA
)
database_backup_path = os.path.join(
self.restore, f"databases/{self.appname}.sql")
self.archive_path, f"databases/{self.appname}.sql")
if os.path.isfile(database_backup_path):
utils.success(f"SQL dump found in backup for {self.appname}!")
return database_backup_path
@@ -81,7 +81,7 @@ class Installer(object):
self.backend.create_user(self.dbuser, self.dbpasswd)
self.backend.create_database(self.dbname, self.dbuser)
schema = None
if self.restore:
if self.archive_path:
schema = self.get_sql_schema_from_backup()
if not schema:
schema = self.get_sql_schema_path()
@@ -188,9 +188,9 @@ class Installer(object):
if not self.upgrade:
self.setup_database()
self.install_config_files()
if self.restore:
self.restore()
self.post_run()
if self.archive_path:
self.restore()
self.restart_daemon()
def _dump_database(self, backup_path: str):

View File

@@ -153,7 +153,7 @@ class Dovecot(base.Installer):
def restore(self):
"""Restore emails."""
home_dir = self.config.get("dovecot", "home_dir")
mail_dir = os.path.join(self.restore, "mails/")
mail_dir = os.path.join(self.archive_path, "mails/")
if len(os.listdir(mail_dir)) > 0:
utils.success("Copying mail backup over dovecot directory.")
if os.path.exists(home_dir):

View File

@@ -47,19 +47,7 @@ class Opendkim(base.Installer):
stat.S_IROTH | stat.S_IXOTH,
target[1], target[2]
)
# Restore dkim keys from backup if restoring
if self.restore is not None:
dkim_keys_backup = os.path.join(
self.restore, "custom/dkim")
if os.path.isdir(dkim_keys_backup):
for file in os.listdir(dkim_keys_backup):
file_path = os.path.join(dkim_keys_backup, file)
if os.path.isfile(file_path):
utils.copy_file(file_path, self.config.get(
"opendkim", "keys_storage_dir", fallback="/var/lib/dkim"))
utils.printcolor(
"DKIM keys restored from backup", utils.GREEN)
super(Opendkim, self).install_config_files()
super().install_config_files()
def get_template_context(self):
"""Additional variables."""
@@ -123,6 +111,18 @@ class Opendkim(base.Installer):
utils.exec_cmd(
"perl -pi -e '{}' /lib/systemd/system/opendkim.service".format(pattern))
def restore(self):
"""Restore keys."""
dkim_keys_backup = os.path.join(
self.archive_path, "custom/dkim")
if os.path.isdir(dkim_keys_backup):
for file in os.listdir(dkim_keys_backup):
file_path = os.path.join(dkim_keys_backup, file)
if os.path.isfile(file_path):
utils.copy_file(file_path, self.config.get(
"opendkim", "keys_storage_dir", fallback="/var/lib/dkim"))
utils.success("DKIM keys restored from backup")
def custom_backup(self, path):
"""Backup DKIM keys."""
storage_dir = self.config.get(

View File

@@ -97,7 +97,7 @@ class Postfix(base.Installer):
utils.exec_cmd("postalias {}".format(aliases_file))
# Postwhite
install("postwhite", self.config, self.upgrade, self.restore)
install("postwhite", self.config, self.upgrade, self.archive_path)
def backup(self, path):
"""Launch postwhite backup."""

View File

@@ -61,7 +61,7 @@ class Postwhite(base.Installer):
def restore(self):
"""Restore config files."""
postwhite_backup_configuration = os.path.join(
self.restore, "custom/postwhite.conf")
self.archive_path, "custom/postwhite.conf")
if os.path.isfile(postwhite_backup_configuration):
utils.copy_file(postwhite_backup_configuration, self.config_dir)
utils.success("postwhite.conf restored from backup")

View File

@@ -26,7 +26,7 @@ class Radicale(base.Installer):
def __init__(self, *args, **kwargs):
"""Get configuration."""
super(Radicale, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.venv_path = self.config.get("radicale", "venv_path")
def _setup_venv(self):
@@ -76,7 +76,7 @@ class Radicale(base.Installer):
def restore(self):
"""Restore collections."""
radicale_backup = os.path.join(
self.restore, "custom/radicale")
self.archive_path, "custom/radicale")
if os.path.isdir(radicale_backup):
restore_target = os.path.join(self.home_dir, "collections")
if os.path.isdir(restore_target):

2
run.py
View File

@@ -72,7 +72,7 @@ def backup_disclaimer():
def restore_disclaimer():
"""Display restore disclamer. """
utils.printcolor(
"You are about to restore a previous installation of Modoboa."
"You are about to restore a previous installation of Modoboa.\n"
"If a new version has been released in between, please update your database!",
utils.BLUE)