Skip to content
Snippets Groups Projects
fabfile.py 5.84 KiB
Newer Older
from datetime import datetime

George Hickman's avatar
George Hickman committed
from fabric.api import env, get, lcd, local, prompt, roles, run, runs_once

env.roledefs = {
    'production': [],
    'pre-production': {
        'hosts': ['otfpreprod@staging-1-a.bmyrk.torchbox.net'],
        'config': {
            'env_name': 'pre-production',
            'remote_db_name': 'otfpreprod',
            'local_db_name': 'opentech',
            'remote_dump_path': '/var/www/otfpreprod/tmp/',
            'local_dump_path': '/tmp/',
        }
    },
    'staging': {
        'hosts': ['otfstaging@staging-1-a.bmyrk.torchbox.net'],
        'config': {
            'env_name': 'staging',
            'remote_db_name': 'otfstaging',
            'local_db_name': 'opentech',
            'remote_dump_path': '/var/www/otfstaging/tmp/',
            'local_dump_path': '/tmp/',
        },
    },
    'dev': {
        'hosts': ['otfdev@staging-1-a.bmyrk.torchbox.net'],
        'config': {
            'env_name': 'dev',
            'remote_db_name': 'otfdev',
            'local_db_name': 'opentech',
            'remote_dump_path': '/var/www/otfdev/tmp/',
            'local_dump_path': '/tmp/',
        },
    },
}


@roles('production')
def deploy_production():
    # Remove this line when you're happy that this task is correct
    raise RuntimeError("Please check the fabfile before using it")

    _deploy()


@runs_once
@roles('production')
def pull_production_data():
    # Remove this line when you're happy that this task is correct
    raise RuntimeError("Please check the fabfile before using it")

    _pull_data_wrapper()


@runs_once
@roles('production')
def pull_production_media():
    _pull_media()


@roles('staging')
def deploy_staging():
    _deploy()


@runs_once
@roles('staging')
def pull_staging_data():
    _pull_data_wrapper()


@runs_once
@roles('staging')
def pull_staging_media():
    _pull_media()
@roles('pre-production')
def deploy_pre_production():
    _deploy()


@runs_once
@roles('pre-production')
def pull_pre_production_data():
    _pull_data_wrapper()


@runs_once
@roles('pre-production')
def pull_pre_production_media():
    _pull_media()


@roles('dev')
def deploy_dev():
    _deploy('develop')


@runs_once
@roles('dev')
def pull_dev_data():
    _pull_data_wrapper()


@runs_once
@roles('dev')
def pull_dev_media():
    _pull_media()


def _deploy(branch='master'):
    """Generic deployment tasks. Inherits the active role"""

Dan Braghis's avatar
Dan Braghis committed
    _build_static(branch)
    _deploy_static()

    run('git pull')
    run('pip install -r requirements.txt')
    _run_migrate()
    run('django-admin collectstatic --noinput')

    # 'restart' should be an alias to a script that restarts the web server
    run('restart')

    _post_deploy()


def _pull_data_wrapper():
    role = env.effective_roles[0]
    config = env.roledefs[role]['config']

    _pull_data(
        env_name=config['env_name'],
        remote_db_name=config['remote_db_name'],
        local_db_name=config['local_db_name'],
        remote_dump_path=config['remote_dump_path'],
        local_dump_path=config['local_dump_path'],
    )


@runs_once
def _pull_media():
    local('rsync -avz %s:\'%s\' /vagrant/media/' % (env['host_string'], '$CFG_MEDIA_DIR'))


@runs_once
def _pull_data(env_name, remote_db_name, local_db_name, remote_dump_path, local_dump_path):
    timestamp = datetime.now().strftime('%Y%m%d-%I%M%S')

    filename = '.'.join([env_name, remote_db_name, timestamp, 'sql'])
    remote_filename = remote_dump_path + filename
    local_filename = local_dump_path + filename

    params = {
        'remote_db_name': remote_db_name,
        'remote_filename': remote_filename,
        'local_db_name': local_db_name,
        'local_filename': local_filename,
    }

    # Dump/download database from server
    run('pg_dump {remote_db_name} -xOf {remote_filename}'.format(**params))
    run('gzip {remote_filename}'.format(**params))
    get('{remote_filename}.gz'.format(**params), '{local_filename}.gz'.format(**params))
    run('rm {remote_filename}.gz'.format(**params))

    # Load database locally
    local('gunzip {local_filename}.gz'.format(**params))
    _restore_db(local_db_name, local_filename)


def _restore_db(local_db_name, local_dump_path):
    params = {
        'local_db_name': local_db_name,
        'local_dump_path': local_dump_path,
    }

    local('dropdb {local_db_name}'.format(**params))
    local('createdb {local_db_name}'.format(**params))
    local('psql {local_db_name} -f {local_dump_path}'.format(**params))
    local('rm {local_dump_path}'.format(**params))

    newsuperuser = prompt(
        'Any superuser accounts you previously created locally will'
        ' have been wiped. Do you wish to create a new superuser? (Y/n): ',
        default="Y"
    )
    if newsuperuser.strip().lower() == 'y':
        local('django-admin createsuperuser')


@runs_once
def _run_migrate():
    # Run migrations
    run('django-admin migrate --noinput')
    # Create a table for database cache backend
    run('django-admin createcachetable')


@runs_once
def _post_deploy():
    # clear frontend cache only on production
    if 'production' in env.effective_roles:
        run(
            'for host in $(echo $CFG_HOSTNAMES | tr \',\' \' \'); do echo "Purge cache for $host";'
            'ats-cache-purge $host; '
            'done'
        )

    # update search index
    run('django-admin update_index')
def _build_static(build_branch='master'):
    # Build a specific branch
    current_branch = local('git rev-parse --abbrev-ref HEAD', capture=True)
    if current_branch != build_branch:
        raise RuntimeError("Please switch to '{}' before deploying".format(build_branch))

    local('git pull')
    with lcd('/vagrant/opentech/static_src/'):
        local('yarn build:prod --silent')
def _deploy_static():
    # Copy the compiled static files to the server
    local("rsync -avz /vagrant/opentech/static_compiled %s:'../app/opentech/'" % (env['host_string']))