Skip to content
Permalink
 
 
Cannot retrieve contributors at this time
from fabric.api import *
from fabric.colors import green, red, yellow
from fabric.contrib.files import append, comment, contains, sed, uncomment
import os, sys, time
env.user = 'drupaldeploy'
env.sudouser = None
env.shell = '/bin/bash -c'
env.web_root = '/var/www'
env.release_archive = None
env.release_time = time.strftime('%Y.%m.%d-%H.%M')
env.local_tmp = '/tmp'
env.remote_tmp = '/tmp'
env.deploy_tasks = [
'build_release',
'upload_release',
'extract_release',
'create_release_files_symlink',
'create_release_settings_symlink',
'drush_site_offline',
'drush_backup_database',
'symlink_current_release',
'drush_update_database',
#'drush_feature_revert',
'drush_cache_clear_all',
'drush_site_online',
]
@task
def list_deploy_tasks():
"""List your deployment tasks
Run load_config task first to see what tasks your site would run
"""
print(yellow("\n".join(env.deploy_tasks)))
@task
def deploy(tag):
"""Deploy your site
Calls load_config(), then proceeds to run through the defined deployment tasks.
"""
load_config()
if (env.apptype == 'piwik'):
env.deploy_tasks = [
'build_release',
'upload_release',
'extract_release',
'piwik_create_release_config_symlink',
'piwik_create_release_tmp_symlink',
'piwik_site_offline',
'symlink_current_release',
'piwik_run_updates',
'piwik_site_online',
]
env.scm_build_dir = '%(local_tmp)s/%(apptype)s-site-%(site)s' % env
set_sitetag(env.site, tag)
print(green("=> Beginning deploy"))
list_deploy_tasks()
for task in env.deploy_tasks:
if ('feature_revert' in task or 'update_database' in task):
execute(task, prompt=False)
else:
execute(task)
@task
def load_config():
"""Load site config.
Assume config file is called siteconfig.py and resides in the current directory.
Can be overridden by setting the siteconfig_dir env variable, eg.: --set siteconfig_dir=/path/to/your/siteconfig
"""
print(green("===> Loading site recipe..."))
try:
env.siteconfig_dir
except AttributeError:
env.siteconfig_dir = None
if (env.siteconfig_dir == None):
directory = os.getcwd()
else:
directory = env.siteconfig_dir
sys.path.append(directory)
import siteconfig
def set_sitetag(site=None, tag=None):
if (not site is None):
env.site = site
if (not tag is None):
env.tag = tag
@task
def tag_release(site, tag, commit, message=''):
print(green("===> Building the release..."))
tag = 'site-%(release_time)s-' % env
# Ensure code directory exists
with settings(warn_only=True):
if local('test -d %(scm_build_dir)s' % env).failed:
local('git clone %(repository)s %(scm_build_dir)s' % env)
with lcd(env.scm_build_dir):
# TODO: put git status check here
if (local("git pull", capture=True)).succeeded:
if (message == ''):
local('git tag %s %s' % (tag, commit))
else:
local('git tag -m "%s" %s %s' % (message, tag, commit))
return tag
@task
@runs_once
def build_release(tag=None, site=None):
"""Build your release tarball
Keyword arguments: tag, site
Standalone Usage: load_config build_release:tag='mytag'
Required environment variables: apptype, local_tmp, repository, tag, site
- tag, site can be set during build_release call
"""
set_sitetag(site, tag)
print(green("===> Building the release..."))
env.release_archive = '%(apptype)s-site-%(site)s_%(tag)s.tar.gz' % env
env.scm_build_dir = '%(local_tmp)s/%(apptype)s-site-%(site)s' % env
# Ensure code directory exists
with settings(warn_only=True):
if local('test -d %(scm_build_dir)s' % env).failed:
local('git clone %(repository)s %(scm_build_dir)s' % env)
with lcd(env.scm_build_dir):
# put git status check here
if (local("git pull", capture=True)).succeeded:
env.release_tree = local('git show-ref --tags -s "%(tag)s"' % env, True)
local('git archive --format tar %(release_tree)s | gzip > %(local_tmp)s/%(release_archive)s' % env)
@task
@serial
@roles('web')
def upload_release(site=None, tag=None):
set_sitetag(site, tag)
print(green("===> Uploading the release archive..."))
env.release_archive = '%(apptype)s-site-%(site)s_%(tag)s.tar.gz' % env
with settings(warn_only=True):
if run("test -f %(remote_tmp)s/%(release_archive)s" % env).failed:
put('%(local_tmp)s/%(release_archive)s' % env, '/tmp/')
@task
@serial
@roles('web')
def extract_release(site=None, tag=None):
set_sitetag(site, tag)
print(green("===> Extracting the release..."))
env.release_archive = '%(apptype)s-site-%(site)s_%(tag)s.tar.gz' % env
with settings(warn_only=True):
if run("test -f %(remote_tmp)s/%(release_archive)s" % env).failed:
abort(red("Release archive doesn't exist, please run build_release again"))
if run('test -d /var/www/%(apptype)s/%(site)s/releases/%(tag)s' % env).succeeded:
abort(red("Release directory already exists"))
if run('test -d /var/www/%(apptype)s/%(site)s/releases' % env).succeeded:
with cd('/var/www/%(apptype)s/%(site)s/releases' % env):
run('mkdir -p /var/www/%(apptype)s/%(site)s/releases/%(tag)s' % env)
env.extraction_flags = 'zxf'
run('tar -%(extraction_flags)s %(remote_tmp)s/%(release_archive)s -C /var/www/%(apptype)s/%(site)s/releases/%(tag)s' % env)
@task
@serial
@roles('web')
def create_release_files_symlink(site=None, tag=None):
set_sitetag(site, tag)
print(green("===> Symlink shared files to current release..."))
run('ln -nfs /var/lib/sitedata/%(apptype)s/%(site)s/files /var/www/%(apptype)s/%(site)s/releases/%(tag)s/sites/default/files' % env)
@task
@serial
@roles('web')
def create_release_settings_symlink(site=None, tag=None):
set_sitetag(site, tag)
print(green("===> Symlink settings.php to current release..."))
run('ln -nfs /var/www/%(apptype)s/%(site)s/settings.php /var/www/%(apptype)s/%(site)s/releases/%(tag)s/sites/default/settings.php' % env)
@task
@serial
@roles('web')
def piwik_create_release_config_symlink(site=None, tag=None):
set_sitetag(site, tag)
print green("===> Symlink shared files to current release...")
run('ln -nfs /var/lib/sitedata/%(apptype)s/%(site)s/config /var/www/%(apptype)s/%(site)s/releases/%(tag)s/config' % env)
@task
@serial
@roles('web')
def piwik_create_release_tmp_symlink(site=None, tag=None):
set_sitetag(site, tag)
print green("===> Symlink settings.php to current release...")
run('ln -nfs /var/lib/sitedata/%(apptype)s/%(site)s/tmp /var/www/%(apptype)s/%(site)s/releases/%(tag)s/tmp' % env)
@task
@serial
@roles('web')
def symlink_current_release(site=None, tag=None):
set_sitetag(site, tag)
print(green("===> Symlinking current release..."))
env.site_symlink = '/var/www/%(apptype)s/%(site)s/current' % env
env.previous_site_symlink = '/var/www/%(apptype)s/%(site)s/previous' % env
env.new_previous = ''
with settings(warn_only=True):
env.new_previous = run('readlink %(site_symlink)s' % env)
env.new_current = '/var/www/%(apptype)s/%(site)s/releases/%(tag)s' % env
# If targets are different, set target of current -> previous, and new release -> current
if (env.new_previous != env.new_current):
if run("test -d %(new_current)s" % env).succeeded:
run('ln -fns %(new_current)s %(site_symlink)s' % env)
with settings(warn_only=True):
if run("test -d %(new_previous)s" % env).succeeded:
run('ln -fns %(new_previous)s %(previous_site_symlink)s' % env)
@task
@serial
@roles('web')
def rollback_symlink(site=None, tag=None):
set_sitetag(site, tag)
print(green("===> Settings current release symlink to the value of previous symlink..."))
env.site_symlink = '/var/www/%(apptype)s/%(site)s/current' % env
env.previous_site_symlink = '/var/www/%(apptype)s/%(site)s/previous' % env
env.previous = run('readlink %(previous_site_symlink)s' % env)
run('ln -fns %(previous)s %(site_symlink)s' % env)
run("rm %(previous_site_symlink)s" % env)
@task
@runs_once
@roles('web')
def drush_backup_database(site=None, tag=None):
"""
Backup database to deploy user's home directory with drush
"""
set_sitetag(site, tag)
print(green("===> Quick and dirty database backup..."))
env.backup_time = time.strftime('%Y.%m.%d-%H.%M')
run('drush -u 1 -r /var/www/%(apptype)s/%(site)s/current sql-dump --result-file=~/%(site)s_%(stage)s_%(backup_time)s.sql --gzip' % env)
@task
@runs_once
@roles('web')
def drush_site_offline(site=None, tag=None, version=7):
"""
Put drupal in maintenance mode
"""
set_sitetag(site, tag)
print(green("===> Set site offline..."))
if (env.version == 7):
run("drush -u 1 -r /var/www/%(apptype)s/%(site)s/current -y vset maintenance_mode 1" % env)
elif (env.version == 6):
run("drush -u 1 -r /var/www/%(apptype)s/%(site)s/current -y vset site_offline 1" % env)
@task
@runs_once
@roles('web')
def drush_site_online(site=None, tag=None, version=7):
"""
Take drupal out of maintenance mode
"""
set_sitetag(site, tag)
print(green("===> Set site online..."))
if (env.version == 7):
run("drush -u 1 -r /var/www/%(apptype)s/%(site)s/current -y vset maintenance_mode 0" % env)
elif (env.version == 6):
run("drush -u 1 -r /var/www/%(apptype)s/%(site)s/current -y vset site_offline 0" % env)
@task
@runs_once
@roles('web')
def drush_features(site=None):
"""
List the available site features, and their state
"""
set_sitetag(site)
run("drush -u 1 -r /var/www/%(apptype)s/%(site)s/current features" % env)
@task
@runs_once
@roles('web')
def drush_feature_diff(feature, site=None):
"""Show drupal feature differences
Keyword arguments: feature, site, prompt, force
- feature: The feature to check (required)
"""
set_sitetag(site)
print(green("===> Running feature-diff..."))
env.drupal_feature = feature
run("drush -u 1 -r /var/www/%(apptype)s/%(site)s/current fd %(drupal_feature)s" % env)
@task
@runs_once
@roles('web')
def drush_feature_revert(feature=None, site=None, prompt=True, force=False):
"""Revert drupal feature via drush
Keyword arguments: feature, site, prompt, force
- feature: None; If set, revert that feature. Otherwise, loop through env.revertable_features (if it exists)
- prompt: True; Set to false to use -y for drush
- force: False; See drush help feature-revert
"""
set_sitetag(site)
env.force_revert_string = ''
if (force == True or force == 'True'):
env.force_revert_string = '--force'
env.prompt_string = ''
if (prompt == False or prompt == 'False'):
env.prompt_string = '-y'
print(green("===> Reverting site feature(s)..."))
if (not feature == None):
env.drupal_feature = feature
run("drush -u 1 -r /var/www/%(apptype)s/%(site)s/current %(prompt_string)s fr %(force_revert_string)s %(drupal_feature)s" % env)
else:
try:
env.revertable_features
except AttributeError:
env.revertable_features = None
if (not env.revertable_features == None):
for feature in env.revertable_features:
env.drupal_feature = feature
run("drush -u 1 -r /var/www/%(apptype)s/%(site)s/current %(prompt_string)s fr %(force_revert_string)s %(drupal_feature)s" % env)
else:
print(yellow('[warning]: ') + 'Nothing to revert, no argument, and env.revertable_features was empty.')
@task
@runs_once
@roles('web')
def drush_feature_revert_all(site=None, prompt=True, force=False):
"""
Revert ALL drupal feature via drush
"""
# TODO: Add the ability to exclude features (per: drush help fra)
set_sitetag(site)
env.force_revert_string = ''
if (force == True or force == 'True'):
env.force_revert_string = '--force'
env.prompt_string = ''
if (prompt == False or prompt == 'False'):
env.prompt_string = '-y'
print(green("===> Reverting site feature(s)..."))
if (prompt == True or prompt == 'True'):
"""
Show list of changed features prior to revert
"""
run("drush -u 1 -r /var/www/%(apptype)s/%(site)s/current features" % env)
run("drush -u 1 -r /var/www/%(apptype)s/%(site)s/current %(prompt_string)s fra %(force_revert_string)s" % env)
@task
@runs_once
@roles('web')
def drush_cron(site=None, tag=None, prompt=True):
"""
Use drush to enable cron
"""
set_sitetag(site, tag)
print(green("===> Running cron via drush..."))
run("drush -u 1 -r /var/www/%(apptype)s/%(site)s/current cron" % env)
@task
@runs_once
@roles('web')
def drush_enable_module(drupal_module, site=None, tag=None, prompt=True):
"""
Enable drupal module via drush
"""
set_sitetag(site, tag)
env.drupal_module = drupal_module
print(green("===> Enabling drupal module..."))
if (prompt == True or prompt == 'True'):
"""
Show list of changed features, and then have drush ask whether to continue.
"""
run("drush -u 1 -r /var/www/%(apptype)s/%(site)s/current en %(drupal_module)s" % env)
else:
run("drush -u 1 -r /var/www/%(apptype)s/%(site)s/current -y en %(drupal_module)s" % env)
@task
@runs_once
@roles('web')
def drush_disable_module(drupal_module, site=None, tag=None, prompt=True):
"""
Enable drupal module via drush
"""
set_sitetag(site, tag)
env.drupal_module = drupal_module
print(green("===> Enabling drupal module..."))
if (prompt == True or prompt == 'True'):
"""
Show list of changed features, and then have drush ask whether to continue.
"""
run("drush -u 1 -r /var/www/%(apptype)s/%(site)s/current dis %(drupal_module)s" % env)
else:
run("drush -u 1 -r /var/www/%(apptype)s/%(site)s/current -y dis %(drupal_module)s" % env)
@task
@runs_once
@roles('web')
def drush_update_database(site=None, tag=None, prompt=True):
"""
Run drupal database updates via: drush updb
"""
set_sitetag(site, tag)
print(green("===> Running database updates..."))
command = 'drush -u 1 -r /var/www/%(apptype)s/%(site)s/current updb' % env
if (prompt != True):
command += ' -y'
run(command)
@task
@runs_once
@roles('web')
def drush_cache_clear_all(site=None, tag=None):
"""
Run drupal cache clear via: drush cc all
"""
set_sitetag(site, tag)
print(green("===> Running drush cache clear all..."))
run("drush -u 1 -r /var/www/%(apptype)s/%(site)s/current cc all" % env)
@task
@runs_once
@roles('web')
def piwik_run_updates(site=None, tag=None, prompt=True):
"""
Run piwik updates via
"""
set_sitetag(site, tag)
print green("===> Running piwik updates...")
command = 'php /var/www/%(apptype)s/%(site)s/current/index.php -- "module=CoreUpdater"' % env
run(command)
@task
@runs_once
@roles('web')
def piwik_site_offline():
''' Disable piwik tracking and user interface
'''
config_file = '/var/www/%(apptype)s/%(site)s/current/config/config.ini.php' % env
patterns = {
'maintenance_mode': '[[:space:]]*maintenance_mode[[:space:]]*=[[:space:]]*',
'record_statistics': '[[:space:]]*record_statistics[[:space:]]*=[[:space:]]*',
}
# Turn on maintenance mode
if (not contains(config_file, '[General]', exact=True)):
append(config_file, '[General]\nmaintenance_mode = 1')
if (not contains(config_file, '[General]', exact=True)):
abort(red('Unable to put site into maintenance mode'))
else:
if (contains(config_file, '^%(maintenance_mode)s0' % patterns, escape=False)):
comment(config_file, '^%(maintenance_mode)s0' % patterns, char=';')
if (contains(config_file, '^[[:space:]]*;{1}%(maintenance_mode)s1' % patterns, escape=False)):
uncomment(config_file, '^[[:space:]]*;{1}%(maintenance_mode)s1' % patterns, char=';')
else:
if (not contains(config_file, '^%(maintenance_mode)s1' % patterns, escape=False)):
sed(config_file, '\[General\]', '[General]\\nmaintenance_mode = 1')
# Stop recording statistics
if (not contains(config_file, '[Tracker]', exact=True)):
append(config_file, '[Tracker]\nrecord_statistics = 0')
if (not contains(config_file, '[Tracker]', exact=True)):
abort(red('Unable to put site into maintenance mode'))
else:
if (contains(config_file, '^%(record_statistics)s1' % patterns, escape=False)):
comment(config_file, '^%(record_statistics)s1' % patterns, char=';')
if (contains(config_file, '^[[:space:]]*;{1}%(record_statistics)s0' % patterns, escape=False)):
uncomment(config_file, '^[[:space:]]*;{1}%(record_statistics)s0' % patterns, char=';')
else:
if (not contains(config_file, '^%(record_statistics)s0' % patterns, escape=False)):
sed(config_file, '\[Tracker\]', '[Tracker]\\nrecord_statistics = 0')
@task
@runs_once
@roles('web')
def piwik_site_online():
''' Enable piwik tracking and user interface
'''
config_file = '/var/www/%(apptype)s/%(site)s/current/config/config.ini.php' % env
patterns = {
'maintenance_mode': '[[:space:]]*maintenance_mode[[:space:]]*=[[:space:]]*',
'record_statistics': '[[:space:]]*record_statistics[[:space:]]*=[[:space:]]*',
}
# Turn off maintenance mode
if (contains(config_file, '^%(maintenance_mode)s1' % patterns, escape=False)):
comment(config_file, '^%(maintenance_mode)s1' % patterns, char=';')
# Resume recording statistics
if (contains(config_file, '^%(record_statistics)s0' % patterns, escape=False)):
comment(config_file, '^%(record_statistics)s0' % patterns, char=';')
def mkdir(dir, use_sudo=False):
"""
Helper function to create directories
"""
command = 'if [ ! -d %s ]; then mkdir -p %s; fi;' % (dir, dir)
if (use_sudo == True):
sudo(command)
else:
run(command)
# fabric sudo doc: http://docs.fabfile.org/en/1.4.2/api/core/operations.html#fabric.operations.sudo
# env.sudouser == the dude who you want to sudo as
def run_or_sudo(*args, **kwargs):
"""run command as 'env.sudouser' if defined and env.usesudo
Passes all arguments on to run() or sudo() except 'user'."""
if env.usesudo == False or sudouser not in env:
run(*args, **kwargs)
else:
## obviously this clobbers any passed-in 'user' arg
kwargs['user'] = env.sudouser
sudo(*args, **kwargs)