Skip to content

Instantly share code, notes, and snippets.

@tutuca
Last active November 15, 2016 13:26
Show Gist options
  • Save tutuca/430151 to your computer and use it in GitHub Desktop.
Save tutuca/430151 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
# -- coding: utf-8 --
"""Deployment script.
This script is coded so it can make the deployments automagically in the
designed servers, it also works as a documentation of where are the programs
installed.
USE: fab <hosts>:<username> <action>
EX: fab staging:admin release
"""
import os
import datetime
from contextlib import contextmanager
from fabric.api import env, run, local, require, put, lcd, prefix
from fabric.contrib.files import exists
env.project_name = 'sma'
env.tar = '%s-%s.tar.gz' % (
env.project_name,
datetime.datetime.now().strftime('%Y%m%d%H%M%S'),
)
env.bundle = '%s-static.tar.gz' % (
env.project_name,
)
env.use_ssh_config = True
@contextmanager
def virtualenv():
with prefix('. %(venv_dir)s/bin/activate' % env):
yield
def production(username, host):
"""Production environment."""
env.hosts = host
env.user = username
base_dir = '/home/%s' % username
name = env.project_name
env.static_dir = os.path.join(base_dir, 'sites', '%s_web' % name)
env.deploy_dir = os.path.join(base_dir, 'sites', '%s_service' % name)
env.venv_dir = os.path.join(base_dir, 'venvs', name)
env.server_command = os.path.join(env.deploy_dir, 'apache2/bin/restart')
def setup_env():
"""
Creates required directories for deployment.
It also attempts to install pip requirements on remote host.
While not intended you might run it for local setup.
"""
dirs = (env[x] for x in env if x.endswith('_dir'))
for directory in dirs:
if not exists(directory):
run('mkdir -p %s' % directory)
if not exists('%(venv_dir)s/bin/activate' % env):
run('virtualenv -q -ppython3 %(venv_dir)s' % env)
put('service/requirements.txt', 'requirements.txt')
with virtualenv():
run('pip -q install -U pip')
run('pip -q install -Ur requirements.txt')
def upload_service(rev='HEAD'):
"""
Create a tarball honoring git's ignored and non-tracked files,
uploads it and decompresses it in the rigth path.
"""
require('host', provided_by=[production])
require('deploy_dir', provided_by=[production])
require('venv_dir', provided_by=[production])
tar = env.tar
with lcd('service'):
local('git archive %s -o %s' % (rev, tar))
put(tar, tar)
run('tar xfz %s -C %s' % (tar, env.deploy_dir))
run('rm %s' % tar)
local('rm %s' % tar)
def build_static_bundle():
"""
Create a tarball of the static files
to be uploaded later.
It invokes django's collectstatic method and
runs a regular grunt build.
Requires your local development environment to be activated and the
`manage` management command to be available.
"""
require('project_name', provided_by=[production])
require('static_dir')
require('bundle')
local('manage collectstatic --noinput')
with lcd('web'):
local('grunt build')
local('tar cf %s -C ./build/ .' % env.bundle)
local('mv %s ../' % env.bundle)
def upload_static(force=False):
"""
Uploads `env.bundle` and decompresses it in the right path
This will attempt to create and delete local gzips.
Cleanup is not always what it should...
"""
require('project_name', provided_by=[production])
require('static_dir', provided_by=[production])
bundle_path = os.path.join(os.path.dirname(__file__), env.bundle)
if force or not os.path.exists(bundle_path):
build_static_bundle()
put(bundle_path, env.bundle)
run('tar xf %s -C %s' % (env.bundle, env.static_dir))
run('rm %s' % env.bundle)
local('rm %s' % bundle_path)
def release(rev='HEAD', force=False):
"""
End-to-end release.
It's a wrapper for the other functions.
"""
require('host', provided_by=[production])
setup_env()
upload_service(rev=rev)
upload_static(force=force)
def apache_restart():
"""Restart the program in the servers."""
require('server_command', provided_by=[production])
run(env.server_command)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment