# HG changeset patch # User Peter Sanchez # Date 1318032317 25200 # Fri Oct 07 17:05:17 2011 -0700 # Node ID 7f135ee84956a9990851944ac952a7cbba7200b2 # Parent 581c08339638e28673adb593106cf4f91eccf015 Updated fabfile to a much more modern version diff --git a/README.txt b/README.txt --- a/README.txt +++ b/README.txt @@ -19,7 +19,7 @@ If you use a Python version less than 2.6 then please refer to this URL: -http://docs.fabfile.org/0.9.2/#documentation +http://docs.fabfile.org/en/1.2.2/index.html#documentation You will need to add the following to your fabfile.py: @@ -117,11 +117,15 @@ Here is a basic deploy to the LOCAL machine: -$ fab local setup +$ fab space:local deploy:full Or say to the production environment: -$ fab prod setup +$ fab space:prod deploy:full + +Or say you just want to update the code and touch the WSGI handler: + +$ fab space:prod deploy:update TODO diff --git a/fabfile.py b/fabfile.py --- a/fabfile.py +++ b/fabfile.py @@ -1,31 +1,28 @@ ''' -Original idea from: - -http://gist.github.com/571155 - -Hacked it to basically be completely original. - + Base fabric deploy. See README.txt ''' import os +from fabric.colors import red as _red from fabric.api import * # globals -env.project_name = 'PROJECT_NAME' +env.project_name = 'yourproject' env.run_south_migrate = True env.copy_base_settings_local = False env.num_releases = 7 +env.shell = '/bin/sh -c' # Environments def _is_local(): - require('run_type', provided_by=[local, staging, prod]) + require('run_type', provided_by=[space]) return env.run_type == 'local' def _get_callable(default=run): 'Return local or default (run) based on hosts variable' - require('run_type', provided_by=[local, staging, prod]) + require('run_type', provided_by=[space]) is_local = _is_local() if default == cd: return lcd if is_local else default @@ -44,41 +41,57 @@ ) -def localdev(): +def _localdev(): 'Use the local machine' env.hosts = ['localhost'] - env.env_path = '/path/to/environments/PROJECT_NAME' - env.user = 'username' + env.env_path = '/Users/pjs/envs/yourproject' + env.user = 'pjs' + env.virtualhost_path = '/' env.run_type = 'local' - env.repo_path = '/path/to/local/repository' + env.repo_path = '/Users/pjs/development/yourproject' env.repo_rev = 'tip' env.copy_base_settings_local = True -def staging(): +def _staging(): 'Use the staging environment' pass -def prod(): +def _prod(): 'Use the production environment' - env.hosts = ['yourproject.yourdomain.com'] - env.env_path = '/path/to/environments/PROJECT_NAME' - env.user = 'username' + env.hosts = ['your_production_host.com'] + env.env_path = '/home/pjs/envs/yourproject' + env.user = 'pjs' + env.virtualhost_path = '/' env.run_type = 'prod' - env.repo_path = 'http://bitbucket.org/someuser/yourproject' + env.repo_path = 'http://bitbucket.org/youraccount/yourrepo' env.repo_rev = 'tip' +# Tasks +def space(envname='None'): + 'Which environment? local, staging, or prod' + if envname == 'staging': + _staging() + elif envname == 'prod': + _prod() + elif envname == 'local': + _localdev() + else: + abort(_red('\n*** Invalid space variable passed: %s' % envname)) + + def set_repo_revision(rev='tip'): + 'Set repository revision to pull. Default: tip' env.repo_rev = rev def set_num_releases(amount=7): - env.num_releases = amount + 'Set number of releases to save. Default: 7' + env.num_releases = int(amount) -# Tasks def test(): 'Run the test suite and bail out if it fails' _run, _sudo, _cd = _get_cmds() @@ -87,51 +100,14 @@ _run('python manage.py test') -def setup(): - ''' - Setup a fresh virtualenv as well as a few useful directories, then run - a full deployment - ''' - require('hosts', provided_by=[localdev, staging, prod]) - require('env_path') - _run, _sudo, _cd = _get_cmds() - - import time - env.release = time.strftime('%Y%m%d%H%M%S') - - lpath = '%(env_path)s/releases/%(release)s' % env - _run('mkdir -p %s' % lpath) - with _cd(lpath): - _run('virtualenv --no-site-packages .') - _run('mkdir -p shared packages') - deploy() - - -def soft_update(): - 'Just update codebase. Do not do a full deploy' - require('hosts', provided_by=[localdev, staging, prod]) - require('env_path') - - checkout_code_repo(update=True) - touch_wsgi_handler() - - -def deploy(): - ''' - Deploy the latest version of the site to the servers, install any - required third party modules, install the virtual host and - then restart the webserver - ''' - require('hosts', provided_by=[localdev, staging, prod]) - require('env_path') - - checkout_code_repo() - install_requirements() - migrate() - install_site() - symlink_current_release() - restart_webserver() - remove_oldest_release() +def deploy(dtype='None'): + 'Deploy type? Options are: update, full' + if dtype == 'full': + _setup() + elif dtype == 'update': + _soft_update() + else: + abort(_red('\n*** Invalid deploy type given: %s' % dtype)) def show_versions(): @@ -145,26 +121,26 @@ def rollback_version(version): 'Specify a specific version to be made live' - require('hosts', provided_by=[localdev, staging, prod]) + require('hosts', provided_by=[space]) require('env_path') _run, _sudo, _cd = _get_cmds() env.version = version with _cd('%(env_path)s' % env): _run('ln -nfs releases/%(version)s current' % env) - restart_webserver() + _restart_webserver() def rollback(): 'Simple GENERIC rollback. Symlink to the second most recent release' - require('hosts', provided_by=[localdev, staging, prod]) + require('hosts', provided_by=[space]) require('env_path') _run, _sudo, _cd = _get_cmds() releases = _get_releases_list() release = releases[-2] _run('ln -nfs releases/%s current' % release) - restart_webserver() + _restart_webserver() def fail_cleanup(): @@ -173,7 +149,7 @@ mess left behind. It will only remove the most recent release directory. BE CAREFUL USING THIS. ''' - require('hosts', provided_by=[localdev, staging, prod]) + require('hosts', provided_by=[space]) require('env_path') _run, _sudo, _cd = _get_cmds() @@ -186,7 +162,7 @@ # Helpers. These are called by other functions rather than directly def _get_releases_list(): 'Returns sorted list of all current releases' - require('hosts', provided_by=[localdev, staging, prod]) + require('hosts', provided_by=[space]) require('env_path') _run, _sudo, _cd = _get_cmds() @@ -196,10 +172,44 @@ return sorted(releases) -def checkout_code_repo(update=False): +def _setup(): + ''' + Setup a fresh virtualenv as well as a few useful directories, then run + a full deployment + ''' + require('hosts', provided_by=[space]) + require('env_path', provided_by=[space]) + _run, _sudo, _cd = _get_cmds() + + import time + env.release = time.strftime('%Y%m%d%H%M%S') + + lpath = '%(env_path)s/releases/%(release)s' % env + _run('mkdir -p %s' % lpath) + + _checkout_code_repo() + _make_virtual_environment() + _install_requirements() + _migrate() + _install_site() + _symlink_current_release() + _restart_webserver() + _remove_oldest_release() + + +def _soft_update(): + 'Just update codebase. Do not do a full deploy' + require('hosts', provided_by=[space]) + require('env_path') + + _checkout_code_repo(update=True) + _touch_wsgi_handler() + + +def _checkout_code_repo(update=False): 'Create an archive from the current Git master branch and upload it' - require('repo_path', provided_by=[localdev, staging, prod]) - require('repo_rev', provided_by=[localdev, staging, prod]) + require('repo_path', provided_by=[space]) + require('repo_rev', provided_by=[space]) _run, _sudo, _cd = _get_cmds() if update: @@ -207,7 +217,7 @@ with _cd(lpath): _run('hg pull -r %(repo_rev)s -u' % env) else: - require('release', provided_by=[deploy, setup]) + require('release', provided_by=[deploy]) lpath = '%(env_path)s/releases/%(release)s' % env with _cd(lpath): cmd = 'hg clone -r ' @@ -221,77 +231,87 @@ _run('cp base_settings_local.py settings_local.py') -def install_site(): +def _make_virtual_environment(): + ' Create the virtualenv in the code repo ' + require('release', provided_by=[deploy]) + _run, _sudo, _cd = _get_cmds() + + lpath = '%(env_path)s/releases/%(release)s/%(project_name)s' % env + with _cd(lpath): + _run('virtualenv --no-site-packages .') + _run('mkdir -p shared packages') + + +def _install_site(): 'Add the virtualhost file to apache' - require('release', provided_by=[deploy, setup]) + require('release', provided_by=[deploy]) _run, _sudo, _cd = _get_cmds() if not _is_local(): with _cd('%(env_path)s/releases/%(release)s' % env): cmd = 'cp %(project_name)s/apache/%(project_name)s.conf ' % env + \ - '/etc/apache2/conf.d/' + '/usr/local/etc/apache22/Includes/' _sudo(cmd) -def install_requirements(): +def _install_requirements(): 'Install the required packages from the requirements file using pip' - require('release', provided_by=[deploy, setup]) + require('release', provided_by=[deploy]) _run, _sudo, _cd = _get_cmds() - with _cd('%(env_path)s/releases/%(release)s' % env): - cmd = './bin/pip install -E . ' - cmd += '-r ./%(project_name)s/requirements.txt ' % env - cmd += '--download-cache=~/.pipcache' + with _cd('%(env_path)s/releases/%(release)s/%(project_name)s' % env): + cmd = './bin/pip --timeout=1 install -E . ' + cmd += '-r ./requirements.txt --download-cache=~/.pipcache' _run(cmd) -def symlink_current_release(): +def _symlink_current_release(): 'Symlink our current release' - require('release', provided_by=[deploy, setup]) + require('release', provided_by=[deploy]) _run, _sudo, _cd = _get_cmds() with _cd('%(env_path)s' % env): _run('ln -nfs releases/%(release)s current' % env) -def migrate(): +def _migrate(): 'Update the database' require('project_name') - require('release', provided_by=[deploy, setup]) + require('release', provided_by=[deploy]) _run, _sudo, _cd = _get_cmds() p = '%(env_path)s/releases/%(release)s/%(project_name)s/%(project_name)s' % env with _cd(p): - _run('../../bin/python manage.py syncdb --noinput') + _run('../bin/python manage.py syncdb --noinput') if env.run_south_migrate: - _run('../../bin/python manage.py migrate') + _run('../bin/python manage.py migrate') -def restart_webserver(): +def _restart_webserver(): 'Restart the web server' _run, _sudo, _cd = _get_cmds() if not _is_local(): - _sudo('apache2ctl configtest') - _sudo('service apache2 restart') + _sudo('/usr/local/etc/rc.d/apache22 configtest', pty=False) + _sudo('/usr/local/etc/rc.d/apache22 restart', pty=False) -def touch_wsgi_handler(): +def _touch_wsgi_handler(): 'Touch the mod_wsgi wsgi_handler.py file' require('project_name') - require('hosts', provided_by=[localdev, staging, prod]) + require('hosts', provided_by=[space]) _run, _sudo, _cd = _get_cmds() with _cd('%(env_path)s/current/%(project_name)s/apache' % env): _run('touch wsgi_handler.py') -def remove_oldest_release(): +def _remove_oldest_release(): ''' Remove oldest releases past the ammount passed in with the "allow" variable. Default 7. ''' - require('hosts', provided_by=[localdev, staging, prod]) + require('hosts', provided_by=[space]) require('num_releases') require('env_path') _run, _sudo, _cd = _get_cmds()