# HG changeset patch # User Louis Opter # Date 1270149529 0 # Node ID b4d371b24a5e9e0dc46fbe1fd819350e03bad248 Initial Import diff -r 000000000000 -r b4d371b24a5e backup-lapp-app --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/backup-lapp-app Thu Apr 01 19:18:49 2010 +0000 @@ -0,0 +1,118 @@ +#!/usr/bin/env python + +# The MIT License +# +# Copyright (c) 2010 Louis Opter +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +import errno +import os +import shutil +import subprocess +import sys +import tarfile +import tempfile + +class TempDir(object): + """Wrap tempfile.mkdtemp to use the with statement""" + + def __init__(self): + pass + + def __enter__(self): + self.__path = tempfile.mkdtemp() + return self.__path + + def __exit__(self, exc_type, exc_value, traceback): + shutil.rmtree(self.__path) + +def status(message): + print '%s: %s.' % (os.path.basename(sys.argv[0]), message) + +def die(message): + status(message) + status('a log has been recorded in %s' % log_path) + sys.exit(1) + +def dump_db(): + """Use pg_dump to backup the databse into `root'""" + + dump_path = os.path.join(root, db_name + '.sql') + with open(dump_path, 'w') as dump: + status('Dumping database to %s' % dump_path) + if subprocess.call(['sudo', '-u', 'postgres', 'pg_dump', db_name], + stdout=dump, stderr=log) != 0: + die('error while dumping database %s to a temporary directory' % db_name) + + status('Database %s dumped' % db_name) + +def archive(): + """Create a tar bzipped archive of the db dump and the www-dir""" + + try: + archive = tarfile.open(os.path.join(root, archive_name), 'w:bz2') + archive.add(os.path.join(root, db_name + '.sql'), db_name + '.sql') + archive.add(www_dir, os.path.basename(www_dir)) + archive.close() + except tarfile.TarError, ex: + die('Can\'t create the tar archive %s: %s' % (archive_name, str(ex))) + + status('Archive %s created' % archive_name) + +def send_archive(): + """Send the tarball using scp or s3cmd""" + + archive = os.path.join(root, archive_name) + if dest[0:5] == 's3://': + ret = subprocess.call(['s3cmd', '--acl-private', 'put', archive, dest], stdout=log, stderr=log) + else: + ret = subprocess.call(['scp', archive, dest], stdout=log, stderr=log) + + if ret != 0: + die('error while cpying %s to %s' % (archive_name, dest)) + + status('Archive %s copied to "%s"' % (archive_name, dest)) + +if __name__ == '__main__': + if len(sys.argv) != 4 or sys.argv[1] == '--help': + print 'Usage: %s db-name www-dir [[user@]host:]path|s3://bucket/[path]' % os.path.basename(sys.argv[0]) + sys.exit(0) + + # globals + db_name = sys.argv[1] + # python basename return '' for a path with an ending slash... + www_dir = sys.argv[2] != '/' and os.path.join('/var/www', sys.argv[2]) or '/var/www' + dest = sys.argv[3] + archive_name = 'backup-lapp-app-%s.tar.bz2' % db_name + log_path = os.path.join(os.getenv('TMP') or '/tmp/', db_name + '.log') + + if not os.path.exists(www_dir): + status('%s: %s' % (www_dir, os.strerror(errno.ENOENT))) + sys.exit(1) + + with open(log_path, 'w') as log: + with TempDir() as root: + status('root=%s' % root) + dump_db() + archive() + send_archive() + os.remove(log_path) + + sys.exit(0)