[enh] Manage local backup archive and extend backup_restore

This commit is contained in:
Jérôme Lebleu 2014-11-05 00:17:18 +01:00
parent d1cb0b0d80
commit c594ce03a6
4 changed files with 101 additions and 45 deletions

View file

@ -559,7 +559,7 @@ backup:
### backup_create() ### backup_create()
create: create:
action_help: Backup and create a local archive action_help: Create a backup local archive
api: POST /backup api: POST /backup
configuration: configuration:
lock: false lock: false
@ -570,14 +570,19 @@ backup:
### backup_restore() ### backup_restore()
restore: restore:
action_help: Restore from an encrypted backup tarball action_help: Restore from a local backup archive
api: POST /restore api: POST /restore
configuration: configuration:
authenticate: false authenticate: false
lock: false
arguments: arguments:
path: name:
help: Path of the restauration package help: Name of the local backup archive
--ignore-apps:
help: Do not restore apps
action: store_true
--force:
help: Force restauration on an already installed system
action: store_true
### backup_list() ### backup_list()
list: list:

108
backup.py
View file

@ -42,7 +42,7 @@ logger = getActionLogger('yunohost.backup')
def backup_create(ignore_apps=False): def backup_create(ignore_apps=False):
""" """
Backup and create a local archive Create a backup local archive
Keyword arguments: Keyword arguments:
ignore_apps -- Do not backup apps ignore_apps -- Do not backup apps
@ -67,7 +67,7 @@ def backup_create(ignore_apps=False):
else: else:
os.system('chown -hR admin: %s' % tmp_dir) os.system('chown -hR admin: %s' % tmp_dir)
# Add app's backup hooks # Add apps backup hook
if not ignore_apps: if not ignore_apps:
try: try:
for app_id in os.listdir('/etc/yunohost/apps'): for app_id in os.listdir('/etc/yunohost/apps'):
@ -79,16 +79,16 @@ def backup_create(ignore_apps=False):
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:
logger.info("unable to add app's backup hooks: %s", str(e)) logger.info("unable to add apps backup hook: %s", str(e))
# Run hooks # Run hooks
m18n.display(m18n.n('backup_running_hooks')) msignals.display(m18n.n('backup_running_hooks'))
hook_callback('backup', [tmp_dir]) hook_callback('backup', [tmp_dir])
# TODO: Add a backup info file # TODO: Add a backup info file
# Create the archive # Create the archive
m18n.display(m18n.n('backup_creating_archive')) msignals.display(m18n.n('backup_creating_archive'))
archive_file = "%s/%s.tar.gz" % (archives_path, timestamp) archive_file = "%s/%s.tar.gz" % (archives_path, timestamp)
try: try:
tar = tarfile.open(archive_file, "w:gz") tar = tarfile.open(archive_file, "w:gz")
@ -119,51 +119,89 @@ def backup_create(ignore_apps=False):
msignals.display(m18n.n('backup_complete'), 'success') msignals.display(m18n.n('backup_complete'), 'success')
def backup_restore(path): def backup_restore(name, ignore_apps=False, force=False):
""" """
Restore from an encrypted backup tarball Restore from a local backup archive
Keyword argument: Keyword argument:
path -- Path to the restore directory name -- Name of the local backup archive
ignore_apps -- Do not restore apps
force -- Force restauration on an already installed system
""" """
from yunohost.tools import tools_postinstall
from yunohost.hook import hook_add from yunohost.hook import hook_add
from yunohost.hook import hook_callback from yunohost.hook import hook_callback
path = os.path.abspath(path) # Retrieve and open the archive
archive_file = backup_info(name)['path']
try: try:
with open("%s/yunohost/current_host" % path, 'r') as f: tar = tarfile.open(archive_file, "r:gz")
except:
logger.exception("unable to open the archive '%s' for reading",
archive_file)
raise MoulinetteError(errno.EIO, m18n.n('backup_archive_open_failed'))
# Check temporary directory
tmp_dir = "%s/tmp/%s" % (backup_path, name)
if os.path.isdir(tmp_dir):
logger.warning("temporary directory for restoration '%s' already exists",
tmp_dir)
os.system('rm -rf %s' % tmp_dir)
# Extract the tarball
msignals.display(m18n.n('backup_extracting_archive'))
tar.extractall(tmp_dir)
tar.close()
# Retrieve domain from the backup
try:
with open("%s/yunohost/current_host" % tmp_dir, 'r') as f:
domain = f.readline().rstrip() domain = f.readline().rstrip()
except IOError: except IOError:
raise MoulinetteError(errno.EINVAL, m18n.n('invalid_restore_package')) logger.error("unable to retrieve domain from '%s/yunohost/current_host'",
tmp_dir)
raise MoulinetteError(errno.EIO, m18n.n('backup_invalid_archive'))
#TODO Decrypt & extract tarball # Check if YunoHost is installed
if os.path.isfile('/etc/yunohost/installed'):
try: msignals.display(m18n.n('yunohost_already_installed'), 'warning')
with open('/etc/yunohost/installed') as f: if not force:
#raise MoulinetteError(errno.EINVAL, m18n.n('yunohost_already_installed')) try:
msignals.display(m18n.n('restoring_installed_system'), 'warning') # Ask confirmation for restoring
time.sleep(5) i = msignals.prompt(m18n.n('restore_confirm_yunohost_installed',
pass answers='y/N'))
except IOError: except NotImplemented:
pass
else:
if i == 'y' or i == 'Y':
force = True
if not force:
raise MoulinetteError(errno.EEXIST, m18n.n('restore_failed'))
else:
from yunohost.tools import tools_postinstall
logger.info("executing the post-install...")
tools_postinstall(domain, 'yunohost', True) tools_postinstall(domain, 'yunohost', True)
# Add app's restore hooks # Add apps restore hook
try: if not ignore_apps:
for app_id in os.listdir('/etc/yunohost/apps'): try:
hook = '/etc/yunohost/apps/'+ app_id +'/scripts/restore' # TODO: Check if the app_id is part of the backup archive
if os.path.isfile(hook): for app_id in os.listdir('/etc/yunohost/apps'):
hook_add(app_id, hook) hook = '/etc/yunohost/apps/'+ app_id +'/scripts/restore'
else: if os.path.isfile(hook):
msignals.display(m18n.n('unrestore_app', app_id), hook_add(app_id, hook)
'warning') else:
except IOError: msignals.display(m18n.n('unrestore_app', app_id),
pass 'warning')
except IOError as e:
logger.info("unable to add apps restore hook: %s", str(e))
# Run hook # Run hooks
hook_callback('restore', [path]) msignals.display(m18n.n('restore_running_hooks'))
hook_callback('restore', [tmp_dir])
# Remove temporary directory
os.system('rm -rf %s' % tmp_dir)
msignals.display(m18n.n('restore_complete'), 'success') msignals.display(m18n.n('restore_complete'), 'success')

View file

@ -130,14 +130,17 @@
"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_archive_open_failed" : "Unable to open the backup archive", "backup_archive_open_failed" : "Unable to open the backup archive",
"backup_archive_name_unknown" : "Unknown local backup archive name", "backup_archive_name_unknown" : "Unknown local backup archive name",
"backup_complete" : "Backup complete", "backup_complete" : "Backup complete",
"invalid_restore_package" : "Invalid restore package", "backup_invalid_archive" : "Invalid backup archive",
"restore_confirm_yunohost_installed" : "Do you really want to restore an already installed system? [{answers:s}]",
"restore_running_hooks" : "Running restoration hooks...",
"restore_failed" : "Unable to restore the system",
"restore_complete" : "Restore complete", "restore_complete" : "Restore complete",
"restoring_installed_system" : "You are trying to restore a backup on an already installed system, abort unless you know what you are doing!", "unbackup_app" : "App '{:s}' will not be saved",
"unbackup_app" : "'{:s}' will NOT be saved", "unrestore_app" : "App '{:s}' will not be restored",
"unrestore_app" : "'{:s}' will NOT be restored",
"field_invalid" : "Invalid field '{:s}'", "field_invalid" : "Invalid field '{:s}'",
"mail_domain_unknown" : "Unknown mail address domain '{:s}'", "mail_domain_unknown" : "Unknown mail address domain '{:s}'",

View file

@ -128,9 +128,19 @@
"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_running_hooks" : "Exécution des scripts de sauvegarde...",
"backup_creating_archive" : "Création de l'archive de sauvegarde...",
"backup_extracting_archive" : "Extraction de l'archive de sauvegarde...",
"backup_archive_open_failed" : "Impossible d'ouvrir l'archive de sauvegarde",
"backup_archive_name_unknown" : "Nom d'archive de sauvegarde locale inconnu",
"backup_complete" : "Sauvegarde terminée", "backup_complete" : "Sauvegarde terminée",
"invalid_restore_package" : "Dossier de restauration invalide", "backup_invalid_archive" : "Archive de sauvegarde incorrecte",
"restore_confirm_yunohost_installed" : "Voulez-vous vraiment restaurer un système déjà installé ? [{answers:s}]",
"restore_running_hooks" : "Exécution des scripts de restauration...",
"restore_failed" : "Impossible de restaurer le système",
"restore_complete" : "Restauration terminée", "restore_complete" : "Restauration terminée",
"unbackup_app" : "L'application '{:s}' ne sera pas sauvegardée",
"unrestore_app" : "L'application '{:s}' ne sera pas restaurée",
"field_invalid" : "Champ incorrect : {:s}", "field_invalid" : "Champ incorrect : {:s}",
"mail_domain_unknown" : "Domaine '{:s}' de l'adresse mail inconnu", "mail_domain_unknown" : "Domaine '{:s}' de l'adresse mail inconnu",