From f31acf2593b65d4a54a32ef9f9c88959c84c0649 Mon Sep 17 00:00:00 2001 From: Brett Haydon Date: Mon, 16 Aug 2010 12:54:29 +1000 Subject: [PATCH] add startsites command. Changed deploy_webservers to deploy_webconf and webservices to webservers. Added a reload_webservers function. Fixed some issues relating to using the wrong settings file in production --- woven/api.py | 6 ++- woven/management/base.py | 4 +- woven/management/commands/patch.py | 8 ++- woven/management/commands/startsites.py | 63 ++++++++++++++++++++++++ woven/project.py | 15 ++++++ woven/templates/woven/nginx-template.txt | 4 +- woven/virtualenv.py | 10 ++-- woven/webservers.py | 59 ++++++++++++++++------ 8 files changed, 138 insertions(+), 31 deletions(-) create mode 100644 woven/management/commands/startsites.py diff --git a/woven/api.py b/woven/api.py index 68e9d2a..c764173 100644 --- a/woven/api.py +++ b/woven/api.py @@ -18,14 +18,14 @@ from woven.virtualenv import activate, active_version from woven.virtualenv import mkvirtualenv, rmvirtualenv, pip_install_requirements -from woven.webservers import deploy_wsgi, deploy_webservers, start_webservices, stop_webservices +from woven.webservers import deploy_wsgi, deploy_webconf, start_webservers, stop_webservers, reload_webservers def deploy(): """ deploy a versioned project on the host """ - deploy_funcs = [deploy_project,deploy_templates, deploy_static, deploy_public, deploy_webservers, deploy_wsgi] + deploy_funcs = [deploy_project,deploy_templates, deploy_static, deploy_public, deploy_webconf, deploy_wsgi] if not patch_project(): deploy_funcs = [deploy_db,mkvirtualenv,pip_install_requirements] + deploy_funcs for func in deploy_funcs: func() @@ -56,6 +56,8 @@ def setupnode(rollback=False, overwrite=False): install_packages(overwrite=overwrite) upload_etc() set_timezone() + stop_webservers() + start_webservers() else: diff --git a/woven/management/base.py b/woven/management/base.py index 24c11d9..2bbddaf 100644 --- a/woven/management/base.py +++ b/woven/management/base.py @@ -90,8 +90,8 @@ def handle(self, *args, **options): all_role_hosts+=role_host state.env['roles'] = state.env['roles'] + [r] if all_role_hosts: comma_hosts = ','.join(all_role_hosts) - state.env.hosts = comma_hosts - + if comma_hosts: + state.env.hosts = comma_hosts if 'hosts' in state.env and isinstance(state.env['hosts'], str): state.env['hosts'] = state.env['hosts'].split(',') elif hasattr(settings,'HOSTS') and settings.HOSTS: diff --git a/woven/management/commands/patch.py b/woven/management/commands/patch.py index 043829c..00859eb 100644 --- a/woven/management/commands/patch.py +++ b/woven/management/commands/patch.py @@ -5,12 +5,10 @@ from woven.api import deploy, activate from woven.api import deploy_project, deploy_templates, deploy_static, deploy_public -from woven.api import deploy_wsgi, deploy_webservers +from woven.api import deploy_wsgi, deploy_webconf from woven.management.base import WovenCommand - - class Command(WovenCommand): """ Patch the current version of your project on hosts and restart webservices @@ -29,7 +27,7 @@ class Command(WovenCommand): """ help = "Patch all parts of the current version of your project, or patch part of the project" - args = "[project|templates|static|public|wsgi|webservers] [user@hoststring ...]" + args = "[project|templates|static|public|wsgi|webconf] [user@hoststring ...]" requires_model_validation = False def parse_host_args(self, *args): @@ -40,7 +38,7 @@ def parse_host_args(self, *args): new_args = args try: sub = args[0] - if sub in ['project','templates','static','public','wsgi','webservers']: + if sub in ['project','templates','static','public','wsgi','webconf']: self.subcommand = args[0] new_args = args[1:] except IndexError: diff --git a/woven/management/commands/startsites.py b/woven/management/commands/startsites.py new file mode 100644 index 0000000..6c75003 --- /dev/null +++ b/woven/management/commands/startsites.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +from optparse import make_option +import os + +from fabric import state +from fabric.decorators import runs_once +from fabric.context_managers import settings +from fabric.operations import sudo +from fabric.contrib.files import exists + +from woven.management.base import WovenCommand +from woven.webservers import _get_django_sites, deploy_wsgi, deploy_webconf, domain_sites, reload_webservers +from woven.project import deploy_sitesettings + +class Command(WovenCommand): + """ + Create sitesetting files for new django.contrib.sites. + + In django site creation is through the production database. The startsite command + creates the sitesetting files for each of the new sites, and deploys them. + + Basic Usage: + ``python manage.py startsite [hoststring|role]`` + + """ + help = "Create a sitesetting file for new django sites" + requires_model_validation = False + + def handle_host(self,*args, **options): + if not hasattr(state.env,'sites_created'): + local_settings_dir = os.path.join(os.getcwd(),state.env.project_name,'sitesettings') + sites = _get_django_sites() + site_ids = sites.keys() + site_ids.sort() + for id in site_ids: + sitesetting_path = os.path.join(state.env.project_name,'sitesettings',''.join([sites[id].replace('.','_'),'.py'])) + if not os.path.exists(sitesetting_path): + f = open(sitesetting_path, "w+") + f.write("from %s.sitesettings.settings import *"% state.env.project_name) + f.write("\nSITE_ID=%s\n"% str(id)) + f.close() + state.env.sites_created = True + created = deploy_sitesettings() + with settings(patch=True): + deploy_wsgi() + deploy_webconf() + + #activate sites + activate_sites = [''.join([d.replace('.','_'),'-',state.env.project_version,'.conf']) for d in domain_sites()] + site_paths = ['/etc/apache2','/etc/nginx'] + + #activate new sites + for path in site_paths: + for site in activate_sites: + if not exists('/'.join([path,'sites-enabled',site])): + sudo("chmod 644 %s" % '/'.join([path,'sites-available',site])) + sudo("ln -s %s/sites-available/%s %s/sites-enabled/%s"% (path,site,path,site)) + if state.env.verbosity: + print " * enabled", "%s/sites-enabled/%s"% (path,site) + reload_webservers() + + + diff --git a/woven/project.py b/woven/project.py index b07deaf..21d4f3d 100644 --- a/woven/project.py +++ b/woven/project.py @@ -84,6 +84,21 @@ def deploy_project(): return created +def deploy_sitesettings(): + """ + Deploy to the project directory in the virtualenv + """ + + sitesettings = '/'.join([deployment_root(),'env',env.project_fullname,'project',env.project_name,'sitesettings']) + local_dir = os.path.join(os.getcwd(),env.project_name,'sitesettings') + + created = deploy_files(local_dir, sitesettings) + if env.verbosity and created: + print env.host,"DEPLOYING sitesettings" + for path in created: + tail = path.split('/')[-1] + print ' * uploaded',tail + @run_once_per_host_version def deploy_templates(): """ diff --git a/woven/templates/woven/nginx-template.txt b/woven/templates/woven/nginx-template.txt index afff835..a14912b 100644 --- a/woven/templates/woven/nginx-template.txt +++ b/woven/templates/woven/nginx-template.txt @@ -21,14 +21,14 @@ server { {% if media_url %} location {{ media_url }} { root {{ deployment_root }}/public/; - #expires 1d; + } {% endif %} {% if static_url %} location {{ static_url }} { root {{ deployment_root }}/env/{{ project_name }}/static/; - #expires 1d; + } {% endif %} diff --git a/woven/virtualenv.py b/woven/virtualenv.py index f38b1f5..fea0fea 100644 --- a/woven/virtualenv.py +++ b/woven/virtualenv.py @@ -15,7 +15,7 @@ from woven.deployment import mkdirs, run_once_per_host_version, deploy_files from woven.environment import deployment_root,set_server_state, server_state, State -from woven.webservers import _ls_sites, stop_webservices, start_webservices, domain_sites +from woven.webservers import _ls_sites, stop_webservers, start_webservers, domain_sites from fabric.contrib.files import append def active_version(): @@ -48,7 +48,7 @@ def activate(): active = active_version() if env.patch or active <> env.project_fullname: - stop_webservices() + stop_webservers() if not env.patch and active <> env.project_fullname: @@ -96,7 +96,7 @@ def activate(): print env.project_fullname,"is the active version" if env.patch or active <> env.project_fullname: - start_webservices() + start_webservers() print return @@ -105,7 +105,7 @@ def sync_db(): """ Runs the django syncdb command """ - with cd('/'.join([deployment_root(),'env',env.project_fullname,'project',env.project_name])): + with cd('/'.join([deployment_root(),'env',env.project_fullname,'project',env.project_name,'sitesettings'])): venv = '/'.join([deployment_root(),'env',env.project_fullname,'bin','activate']) if env.verbosity: print " * python manage.py syncdb --noinput" @@ -139,7 +139,7 @@ def migration(): """ #activate env - with cd('/'.join([deployment_root(),'env',env.project_fullname,'project',env.project_name])): + with cd('/'.join([deployment_root(),'env',env.project_fullname,'project',env.project_name,'sitesettings'])): #migrates all or specific env.migration venv = '/'.join([deployment_root(),'env',env.project_fullname,'bin','activate']) cmdpt1 = ' '.join(['source',venv,'&&']) diff --git a/woven/webservers.py b/woven/webservers.py index 7d9c015..481e811 100644 --- a/woven/webservers.py +++ b/woven/webservers.py @@ -25,16 +25,17 @@ def _activate_sites(path, filenames): if not exists('/etc/apache2/sites-enabled'+ filename): sudo("ln -s %s%s %s%s"% (self.deploy_root,filename,self.enabled_path,filename)) -def _deploy_webserver(remote_dir,template): +def _deploy_webconf(remote_dir,template): if not 'http:' in env.MEDIA_URL: media_url = env.MEDIA_URL else: media_url = '' if not 'http:' in env.STATIC_URL: static_url = env.STATIC_URL - else: static_url = '' + else: static_url = '' + if not static_url: static_url = env.ADMIN_MEDIA_PREFIX log_dir = '/'.join([deployment_root(),'log']) deployed = [] - - for d in domain_sites(): + domains = domain_sites() + for d in domains: u_domain = d.replace('.','_') @@ -74,7 +75,6 @@ def _ls_sites(path): dom_sites.append(s) return dom_sites -@runs_once def _get_django_sites(): """ Get a list of sites as dictionaries {site_id:'domain.name'} @@ -82,7 +82,7 @@ def _get_django_sites(): """ deployed = server_state('deploy_project') if not env.sites and 'django.contrib.sites' in env.INSTALLED_APPS and deployed: - with cd('/'.join([deployment_root(),'env',env.project_fullname,'project',env.project_name])): + with cd('/'.join([deployment_root(),'env',env.project_fullname,'project',env.project_name,'sitesettings'])): venv = '/'.join([deployment_root(),'env',env.project_fullname,'bin','activate']) output = run(' '.join(['source',venv,'&&',"./manage.py dumpdata sites"])) sites = json.loads(output) @@ -111,19 +111,19 @@ def domain_sites(): return env.domains @run_once_per_host_version -def deploy_webservers(): +def deploy_webconf(): """ Deploy apache & nginx site configurations to the host """ deployed = [] log_dir = '/'.join([deployment_root(),'log']) #TODO - incorrect - check for actual package to confirm installation if exists('/etc/apache2/sites-enabled/') and exists('/etc/nginx/sites-enabled'): if env.verbosity: - print env.host,"DEPLOYING webservers:" + print env.host,"DEPLOYING webconf:" if not exists(log_dir): run('ln -s /var/log log') - deployed += _deploy_webserver('/etc/apache2/sites-available','django-apache-template.txt') - deployed += _deploy_webserver('/etc/nginx/sites-available','nginx-template.txt') + deployed += _deploy_webconf('/etc/apache2/sites-available','django-apache-template.txt') + deployed += _deploy_webconf('/etc/nginx/sites-available','nginx-template.txt') upload_template('woven/maintenance.html','/var/www/nginx-default/maintenance.html',use_sudo=True) sudo('chmod ugo+r /var/www/nginx-default/maintenance.html') else: @@ -140,7 +140,8 @@ def deploy_wsgi(): deployed = [] if env.verbosity: print env.host,"DEPLOYING wsgi", remote_dir - for domain in domain_sites(): + domains = domain_sites() + for domain in domains: deployed += mkdirs(remote_dir) with cd(remote_dir): u_domain = domain.replace('.','_') @@ -163,7 +164,34 @@ def deploy_wsgi(): run("chmod ug+xr %s"% filename) return deployed -def stop_webservices(): +def reload_webservers(): + """ + Reload apache2 and nginx + """ + if env.verbosity: + print env.host, "RELOADING apache2" + with settings(warn_only=True): + a = sudo("/etc/init.d/apache2 reload") + if env.verbosity: + print '',a + if env.verbosity: + + #Reload used to fail on Ubuntu but at least in 10.04 it works + print env.host,"RELOADING nginx" + with settings(warn_only=True): + s = run("/etc/init.d/nginx status") + if 'running' in s: + n = sudo("/etc/init.d/nginx reload") + else: + n = sudo("/etc/init.d/nginx start") + if env.verbosity: + print ' *',n + return True + +def stop_webservers(): + """ + Stop apache2 + """ #TODO - distinguish between a warning and a error on apache with settings(warn_only=True): if env.verbosity: @@ -174,7 +202,10 @@ def stop_webservices(): return True -def start_webservices(): +def start_webservers(): + """ + Start apache2 and start/reload nginx + """ with settings(warn_only=True): if env.verbosity: print env.host,"STARTING apache2" @@ -188,8 +219,6 @@ def start_webservices(): sys.exit(1) if env.verbosity: #Reload used to fail on Ubuntu but at least in 10.04 it works - - #TODO - Check that it is already running print env.host,"RELOADING nginx" with settings(warn_only=True): s = run("/etc/init.d/nginx status")