mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
[enh] Add 'output_directory' and 'no_compress' arguments to backup_create
This commit is contained in:
parent
42b1189cd1
commit
f7b591840c
4 changed files with 107 additions and 44 deletions
|
@ -574,6 +574,13 @@ backup:
|
||||||
-d:
|
-d:
|
||||||
full: --description
|
full: --description
|
||||||
help: Short description of the backup
|
help: Short description of the backup
|
||||||
|
-o:
|
||||||
|
full: --output-directory
|
||||||
|
help: Output directory for the backup
|
||||||
|
-r:
|
||||||
|
full: --no-compress
|
||||||
|
help: Do not create an archive file
|
||||||
|
action: store_true
|
||||||
--ignore-apps:
|
--ignore-apps:
|
||||||
help: Do not backup apps
|
help: Do not backup apps
|
||||||
action: store_true
|
action: store_true
|
||||||
|
|
84
backup.py
84
backup.py
|
@ -24,6 +24,7 @@
|
||||||
Manage backups
|
Manage backups
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import errno
|
import errno
|
||||||
|
@ -40,36 +41,70 @@ archives_path = '%s/archives' % backup_path
|
||||||
logger = getActionLogger('yunohost.backup')
|
logger = getActionLogger('yunohost.backup')
|
||||||
|
|
||||||
|
|
||||||
def backup_create(name=None, description=None, ignore_apps=False):
|
def backup_create(name=None, description=None, output_directory=None,
|
||||||
|
no_compress=False, ignore_apps=False):
|
||||||
"""
|
"""
|
||||||
Create a backup local archive
|
Create a backup local archive
|
||||||
|
|
||||||
Keyword arguments:
|
Keyword arguments:
|
||||||
name -- Name of the backup archive
|
name -- Name of the backup archive
|
||||||
description -- Short description of the backup
|
description -- Short description of the backup
|
||||||
|
output_directory -- Output directory for the backup
|
||||||
|
no_compress -- Do not create an archive file
|
||||||
ignore_apps -- Do not backup apps
|
ignore_apps -- Do not backup apps
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
# TODO: Add a 'clean' argument to clean output directory
|
||||||
from yunohost.hook import hook_add
|
from yunohost.hook import hook_add
|
||||||
from yunohost.hook import hook_callback
|
from yunohost.hook import hook_callback
|
||||||
|
|
||||||
|
tmp_dir = None
|
||||||
|
|
||||||
|
# Validate and define backup name
|
||||||
timestamp = int(time.time())
|
timestamp = int(time.time())
|
||||||
if not name:
|
if not name:
|
||||||
name = str(timestamp)
|
name = str(timestamp)
|
||||||
if name in backup_list()['archives']:
|
if name in backup_list()['archives']:
|
||||||
raise MoulinetteError(errno.EINVAL, m18n.n('backup_archive_name_exists'))
|
raise MoulinetteError(errno.EINVAL,
|
||||||
tmp_dir = "%s/tmp/%s" % (backup_path, name)
|
m18n.n('backup_archive_name_exists'))
|
||||||
|
|
||||||
# Initialize backup info
|
# Validate additional arguments
|
||||||
info = {
|
if no_compress and not output_directory:
|
||||||
'description': description or '',
|
raise MoulinetteError(errno.EINVAL,
|
||||||
'created_at': timestamp,
|
m18n.n('backup_output_directory_required'))
|
||||||
'apps': {},
|
if output_directory:
|
||||||
}
|
output_directory = os.path.abspath(output_directory)
|
||||||
|
|
||||||
|
# Check for forbidden folders
|
||||||
|
if output_directory.startswith(archives_path) or \
|
||||||
|
re.match(r'^/(|(bin|boot|dev|etc|lib|root|run|sbin|sys|usr|var)(|/.*))$',
|
||||||
|
output_directory):
|
||||||
|
logger.error("forbidden output directory '%'", output_directory)
|
||||||
|
raise MoulinetteError(errno.EINVAL,
|
||||||
|
m18n.n('backup_output_directory_forbidden'))
|
||||||
|
|
||||||
|
# Create the output directory
|
||||||
|
if not os.path.isdir(output_directory):
|
||||||
|
logger.info("creating output directory '%s'", output_directory)
|
||||||
|
os.makedirs(output_directory, 0750)
|
||||||
|
# Check that output directory is empty
|
||||||
|
elif no_compress and os.listdir(output_directory):
|
||||||
|
logger.error("not empty output directory '%'", output_directory)
|
||||||
|
raise MoulinetteError(errno.EIO,
|
||||||
|
m18n.n('backup_output_directory_not_empty'))
|
||||||
|
|
||||||
|
# Define temporary directory
|
||||||
|
if no_compress:
|
||||||
|
tmp_dir = output_directory
|
||||||
|
else:
|
||||||
|
output_directory = archives_path
|
||||||
|
|
||||||
# Create temporary directory
|
# Create temporary directory
|
||||||
|
if not tmp_dir:
|
||||||
|
tmp_dir = "%s/tmp/%s" % (backup_path, name)
|
||||||
if os.path.isdir(tmp_dir):
|
if os.path.isdir(tmp_dir):
|
||||||
logger.warning("temporary directory for backup '%s' already exists", tmp_dir)
|
logger.warning("temporary directory for backup '%s' already exists",
|
||||||
|
tmp_dir)
|
||||||
os.system('rm -rf %s' % tmp_dir)
|
os.system('rm -rf %s' % tmp_dir)
|
||||||
try:
|
try:
|
||||||
os.mkdir(tmp_dir, 0750)
|
os.mkdir(tmp_dir, 0750)
|
||||||
|
@ -80,12 +115,19 @@ def backup_create(name=None, description=None, ignore_apps=False):
|
||||||
else:
|
else:
|
||||||
os.system('chown -hR admin: %s' % tmp_dir)
|
os.system('chown -hR admin: %s' % tmp_dir)
|
||||||
|
|
||||||
|
# Initialize backup info
|
||||||
|
info = {
|
||||||
|
'description': description or '',
|
||||||
|
'created_at': timestamp,
|
||||||
|
'apps': {},
|
||||||
|
}
|
||||||
|
|
||||||
# Add apps backup hook
|
# Add apps backup hook
|
||||||
if not ignore_apps:
|
if not ignore_apps:
|
||||||
from yunohost.app import app_info
|
from yunohost.app import app_info
|
||||||
try:
|
try:
|
||||||
for app_id in os.listdir('/etc/yunohost/apps'):
|
for app_id in os.listdir('/etc/yunohost/apps'):
|
||||||
hook = '/etc/yunohost/apps/'+ app_id +'/scripts/backup'
|
hook = '/etc/yunohost/apps/%s/scripts/backup' % app_id
|
||||||
if os.path.isfile(hook):
|
if os.path.isfile(hook):
|
||||||
hook_add(app_id, hook)
|
hook_add(app_id, hook)
|
||||||
|
|
||||||
|
@ -95,7 +137,8 @@ def backup_create(name=None, description=None, ignore_apps=False):
|
||||||
'version': i['version'],
|
'version': i['version'],
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
logger.warning("unable to find app's backup hook '%s'", hook)
|
logger.warning("unable to find app's backup hook '%s'",
|
||||||
|
hook)
|
||||||
msignals.display(m18n.n('unbackup_app', app_id),
|
msignals.display(m18n.n('unbackup_app', app_id),
|
||||||
'warning')
|
'warning')
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
|
@ -110,8 +153,9 @@ def backup_create(name=None, description=None, ignore_apps=False):
|
||||||
f.write(json.dumps(info))
|
f.write(json.dumps(info))
|
||||||
|
|
||||||
# Create the archive
|
# Create the archive
|
||||||
|
if not no_compress:
|
||||||
msignals.display(m18n.n('backup_creating_archive'))
|
msignals.display(m18n.n('backup_creating_archive'))
|
||||||
archive_file = "%s/%s.tar.gz" % (archives_path, name)
|
archive_file = "%s/%s.tar.gz" % (output_directory, name)
|
||||||
try:
|
try:
|
||||||
tar = tarfile.open(archive_file, "w:gz")
|
tar = tarfile.open(archive_file, "w:gz")
|
||||||
except:
|
except:
|
||||||
|
@ -123,7 +167,7 @@ def backup_create(name=None, description=None, ignore_apps=False):
|
||||||
try:
|
try:
|
||||||
tar = tarfile.open(archive_file, "w:gz")
|
tar = tarfile.open(archive_file, "w:gz")
|
||||||
except:
|
except:
|
||||||
logger.exception("unable to open the archive '%s' for writing " \
|
logger.exception("unable to open the archive '%s' for writing "
|
||||||
"after creating directory '%s'",
|
"after creating directory '%s'",
|
||||||
archive_file, archives_path)
|
archive_file, archives_path)
|
||||||
tar = None
|
tar = None
|
||||||
|
@ -131,12 +175,17 @@ def backup_create(name=None, description=None, ignore_apps=False):
|
||||||
logger.exception("unable to open the archive '%s' for writing",
|
logger.exception("unable to open the archive '%s' for writing",
|
||||||
archive_file)
|
archive_file)
|
||||||
if tar is None:
|
if tar is None:
|
||||||
raise MoulinetteError(errno.EIO, m18n.n('backup_archive_open_failed'))
|
raise MoulinetteError(errno.EIO,
|
||||||
|
m18n.n('backup_archive_open_failed'))
|
||||||
tar.add(tmp_dir, arcname='')
|
tar.add(tmp_dir, arcname='')
|
||||||
tar.close()
|
tar.close()
|
||||||
|
|
||||||
# Copy info file and remove temporary directory
|
# Copy info file
|
||||||
os.system('mv %s/info.json %s/%s.info.json' % (tmp_dir, archives_path, name))
|
os.system('mv %s/info.json %s/%s.info.json' %
|
||||||
|
(tmp_dir, archives_path, name))
|
||||||
|
|
||||||
|
# Clean temporary directory
|
||||||
|
if tmp_dir != output_directory:
|
||||||
os.system('rm -rf %s' % tmp_dir)
|
os.system('rm -rf %s' % tmp_dir)
|
||||||
|
|
||||||
msignals.display(m18n.n('backup_complete'), 'success')
|
msignals.display(m18n.n('backup_complete'), 'success')
|
||||||
|
@ -260,6 +309,7 @@ def backup_list():
|
||||||
|
|
||||||
return { 'archives': result }
|
return { 'archives': result }
|
||||||
|
|
||||||
|
|
||||||
def backup_info(name):
|
def backup_info(name):
|
||||||
"""
|
"""
|
||||||
Get info about a local backup archive
|
Get info about a local backup archive
|
||||||
|
|
|
@ -128,6 +128,9 @@
|
||||||
"packages_upgrade_failed" : "Unable to upgrade all packages",
|
"packages_upgrade_failed" : "Unable to upgrade all packages",
|
||||||
"system_upgraded" : "System successfully upgraded",
|
"system_upgraded" : "System successfully upgraded",
|
||||||
|
|
||||||
|
"backup_output_directory_required" : "You must provide an output directory for the backup",
|
||||||
|
"backup_output_directory_forbidden" : "Forbidden output directory",
|
||||||
|
"backup_output_directory_not_empty" : "Output directory is not empty",
|
||||||
"backup_running_hooks" : "Running backup hooks...",
|
"backup_running_hooks" : "Running backup hooks...",
|
||||||
"backup_creating_archive" : "Creating the backup archive...",
|
"backup_creating_archive" : "Creating the backup archive...",
|
||||||
"backup_extracting_archive" : "Extracting the backup archive...",
|
"backup_extracting_archive" : "Extracting the backup archive...",
|
||||||
|
|
|
@ -128,6 +128,9 @@
|
||||||
"packages_upgrade_failed" : "Impossible de mettre à jour tous les paquets",
|
"packages_upgrade_failed" : "Impossible de mettre à jour tous les paquets",
|
||||||
"system_upgraded" : "Système mis à jour avec succès",
|
"system_upgraded" : "Système mis à jour avec succès",
|
||||||
|
|
||||||
|
"backup_output_directory_required" : "Vous devez spécifier un dossier de sortie pour la sauvegarde",
|
||||||
|
"backup_output_directory_forbidden" : "Dossier de sortie interdit",
|
||||||
|
"backup_output_directory_not_empty" : "Le dossier de sortie n'est pas vide",
|
||||||
"backup_running_hooks" : "Exécution des scripts de sauvegarde...",
|
"backup_running_hooks" : "Exécution des scripts de sauvegarde...",
|
||||||
"backup_creating_archive" : "Création de l'archive de sauvegarde...",
|
"backup_creating_archive" : "Création de l'archive de sauvegarde...",
|
||||||
"backup_extracting_archive" : "Extraction de l'archive de sauvegarde...",
|
"backup_extracting_archive" : "Extraction de l'archive de sauvegarde...",
|
||||||
|
|
Loading…
Add table
Reference in a new issue