Port logic for deploying a "backup" app

This commit is contained in:
Lance Edgar 2019-01-06 14:14:47 -06:00
parent c2fe7586da
commit bd4768839a
7 changed files with 196 additions and 0 deletions

View file

@ -36,5 +36,6 @@ from .core import (
make_system_user,
mkdir,
set_timezone,
UNSPECIFIED,
)
from .util import exists

103
rattail_fabric2/backup.py Normal file
View file

@ -0,0 +1,103 @@
# -*- coding: utf-8; -*-
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2018 Lance Edgar
#
# This file is part of Rattail.
#
# Rattail is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# Rattail. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Fabric library for Backup app
"""
from __future__ import unicode_literals, absolute_import
import os
import datetime
from rattail_fabric2 import python, exists, make_deploy, mkdir, UNSPECIFIED
deploy_generic = make_deploy(__file__)
def deploy_backup_everything(c, **context):
"""
Deploy the generic `backup-everything` script
"""
context.setdefault('envname', 'backup')
context.setdefault('user', 'rattail')
deploy_generic(c, 'backup/backup-everything.mako', '/usr/local/bin/backup-everything',
mode='0700', context=context, use_sudo=True)
def deploy_backup_app(c, deploy, envname, mkvirtualenv=True, user='rattail',
config=None, context={}, everything=None,
crontab=None, runat=UNSPECIFIED):
"""
Make an app which can run backups for the server.
"""
if not config:
path = '{}/rattail.conf'.format(envname)
if deploy.local_exists(path):
config = path
else:
raise ValueError("Must provide config path for backup app")
if runat is UNSPECIFIED:
runat = datetime.time(0) # defaults to midnight
# virtualenv
if mkvirtualenv:
python.mkvirtualenv(c, envname, python='/usr/bin/python3')
envpath = '/srv/envs/{}'.format(envname)
c.sudo('chown -R {}: {}'.format(user, envpath))
mkdir(c, os.path.join(envpath, 'src'), use_sudo=True, runas_user=user)
c.sudo("bash -l -c 'workon {} && pip install --upgrade pip'".format(envname), user=user)
# rattail
if not exists(c, os.path.join(envpath, 'src/rattail')):
c.sudo('git clone https://rattailproject.org/git/rattail.git {}/src/rattail'.format(envpath), user=user)
c.sudo("bash -l -c 'cd {}/src/rattail && git pull'".format(envpath), user=user)
deploy_generic(c, 'backup/git-exclude', os.path.join(envpath, 'src/rattail/.git/info/exclude'), use_sudo=True, owner=user)
c.sudo("bash -l -c 'workon {} && cdvirtualenv && bin/pip install --upgrade --upgrade-strategy eager src/rattail'".format(envname), user=user)
# config
c.sudo("bash -l -c 'workon {} && cdvirtualenv && rattail make-appdir'".format(envname), user=user)
deploy(c, config, os.path.join(envpath, 'app/rattail.conf'), owner=user, mode='0600', use_sudo=True)
c.sudo("bash -l -c 'workon {} && cdvirtualenv && bin/rattail -c app/rattail.conf make-config -T quiet -O app/'".format(envname), user=user)
c.sudo("bash -l -c 'workon {} && cdvirtualenv && bin/rattail -c app/rattail.conf make-config -T silent -O app/'".format(envname), user=user)
# backup-everything script
everything_context = dict(context)
everything_context['envname'] = envname
everything_context['user'] = user
if everything:
deploy(c, everything, '/usr/local/bin/backup-everything', mode='0700', context=everything_context, use_sudo=True)
else:
deploy_backup_everything(c, **everything_context)
# crontab
if runat:
crontab_context = dict(context)
crontab_context['envname'] = envname
crontab_context['pretty_time'] = runat.strftime('%I:%M %p')
crontab_context['cron_time'] = runat.strftime('%M %H')
if crontab:
deploy(c, crontab, '/etc/cron.d/backup', context=crontab_context, use_sudo=True)
else:
deploy_generic(c, 'backup/crontab.mako', '/etc/cron.d/backup', context=crontab_context, use_sudo=True)

43
rattail_fabric2/borg.py Normal file
View file

@ -0,0 +1,43 @@
# -*- coding: utf-8; -*-
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2018 Lance Edgar
#
# This file is part of Rattail.
#
# Rattail is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# Rattail. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Fabric library for Borg backups
https://www.borgbackup.org/
"""
from __future__ import unicode_literals, absolute_import
from rattail_fabric2 import apt
def install_dependencies(c):
"""
Install the dependencies for Borg
"""
apt.install(
c,
'libacl1-dev',
'libfuse-dev',
'pkg-config',
)

View file

@ -35,6 +35,9 @@ import six
from mako.template import Template
UNSPECIFIED = object()
def is_link(c, path, use_sudo=False):
"""
Return True if the given path is a symlink on the current remote host.
@ -186,6 +189,9 @@ class Deployer(object):
def full_path(self, local_path):
return '{}/{}'.format(self.deploy_path, local_path)
def local_exists(self, local_path):
return os.path.exists(self.full_path(local_path))
def deploy(self, c, local_path, remote_path, context={}, **kwargs):
local_path = self.full_path(local_path)
if local_path.endswith('.template'):
@ -204,6 +210,10 @@ class Deployer(object):
kwargs['use_sudo'] = True
deploy_site(c, self, local_path, name, **kwargs)
def backup_app(self, c, envname='backup', *args, **kwargs):
from rattail_fabric2.backup import deploy_backup_app
deploy_backup_app(c, self, envname, *args, **kwargs)
def make_deploy(deploy_path, last_segment='deploy'):
"""

View file

@ -0,0 +1,34 @@
#!/bin/sh -e
if [ "$1" = "-v" -o "$1" = "--verbose" ]; then
VERBOSE='--verbose'
QUIET=
PROGRESS='--progress'
CONFIG='/srv/envs/${envname}/app/rattail.conf'
else
VERBOSE=
QUIET='--quiet'
PROGRESS=
CONFIG='/srv/envs/${envname}/app/silent.conf'
fi
RATTAIL="/srv/envs/${envname}/bin/rattail --config=$CONFIG $PROGRESS $VERBOSE"
PIP="sudo -u ${user} PIP_CONFIG_FILE=/srv/envs/${envname}/pip.conf /srv/envs/${envname}/bin/pip"
# upgrade pip
$PIP install $QUIET --upgrade pip
# upgrade rattail
cd /srv/envs/${envname}/src/rattail
if [ "$(sudo -u ${user} git status --porcelain)" != '' ]; then
sudo -u ${user} git status
exit 1
fi
sudo -u ${user} git pull $QUIET
sudo -u ${user} find . -name '*.pyc' -delete
$PIP install $QUIET --upgrade --upgrade-strategy eager --editable .
# run backup
cd /srv/envs/${envname}
$RATTAIL backup

View file

@ -0,0 +1,4 @@
# -*- mode: conf; -*-
# backup everything of importance at ${pretty_time}
${'' if env.machine_is_live else '# '}${cron_time} * * * root /usr/local/bin/backup-everything

View file

@ -0,0 +1 @@
**/__pycache__/