diff --git a/docs/backup.md b/docs/backup.md new file mode 100644 index 00000000..6e8d3b71 --- /dev/null +++ b/docs/backup.md @@ -0,0 +1,44 @@ +# Backups + +There are two important places where your data are located, +in your database and in your media folder. The following `umap` commands +might help you to backup these data: + +## `backup` + +The `backup` command requires a `path` as a parameter where two archives +will be generated: + +* `/database..tar.gz` contains a JSON dump of the database + ready to be passed to a `loaddata` command. +* `/media..tar.gz` contains the content of your media + folder as declared in your `MEDIA_ROOT` setting. + +### Examples + +``` +umap backup /tmp/test_backup +``` + +will generate (if run on May, 4th 2017!): + +``` +/tmp/test_backup/database.2017-05-04.tar.gz +/tmp/test_backup/media.2017-05-04.tar.gz +``` + +## `sync_backup` + +The `sync_backup` command requires a `path` as a parameter and +a `destination` to synchronize to. + +It will take both database and media archives files for the current day +and `rsync` these to the destination. + +### Examples + +``` +umap sync_backup /tmp/test_backup root@ip:/backups +``` + +will sync generated files from the `backup` command to your distant server. diff --git a/mkdocs.yml b/mkdocs.yml index ddfe693c..5af9b2ea 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -6,5 +6,6 @@ pages: - how-tos: - Ubuntu from scratch: ubuntu.md - Customize your uMap style: custom.md + - Backups and sync: backup.md - Changelog: changelog.md theme: readthedocs diff --git a/umap/management/commands/backup.py b/umap/management/commands/backup.py new file mode 100644 index 00000000..bfc9b197 --- /dev/null +++ b/umap/management/commands/backup.py @@ -0,0 +1,39 @@ +import os +import tarfile +from datetime import date +from pathlib import Path + +from django.conf import settings +from django.core.management import call_command +from django.core.management.base import BaseCommand + + +class Command(BaseCommand): + help = 'Backup database (postgresql) and geojsons.' + + def add_arguments(self, parser): + parser.add_argument('path', help='Location of the backups.') + + def archive(self, source, destination): + try: + archive = tarfile.open(str(destination), mode='w:gz') + archive.add(str(source), arcname='./', recursive=True, + exclude=os.path.islink) + except: # NOQA + raise + finally: + archive.close() + + def handle(self, *args, **options): + today = date.today().isoformat() + root = Path(options['path']) + if not root.exists(): + root.mkdir() + database_tmp = root.joinpath('database.{}.json'.format(today)) + with database_tmp.open('w') as out: + call_command('dumpdata', format='json', stdout=out) + self.archive(database_tmp, + root.joinpath('database.{}.tar.gz'.format(today))) + self.archive(settings.MEDIA_ROOT, + root.joinpath('media.{}.tar.gz'.format(today))) + os.unlink(str(database_tmp)) diff --git a/umap/management/commands/sync_backup.py b/umap/management/commands/sync_backup.py new file mode 100644 index 00000000..b5a19030 --- /dev/null +++ b/umap/management/commands/sync_backup.py @@ -0,0 +1,20 @@ +import subprocess +from datetime import date +from pathlib import Path + +from django.core.management.base import BaseCommand + + +class Command(BaseCommand): + help = "Synchronize today's backup with whatever rsync-able." + + def add_arguments(self, parser): + parser.add_argument('path', help='Location of the backups.') + parser.add_argument('destination', help='Destination of the backups.') + + def handle(self, *args, **options): + today = date.today().isoformat() + root = Path(options['path']) + subprocess.call( + ['rsync', '-rv', str(root), '--include', '*{}*'.format(today), + options['destination']])