Source code for modules.web

"""
Install/Configure Apache for your static (or other web) file serving needs.

Web Module Settings
-------------------
::

    WEB_HTTPD = "apache" #apache2 or nginx
    WEB_CONFIG_TEMPLATE_PATH = "templates/my_apache.conf"  #This is the path to the template on the LOCAL machine

    #Params that are provided to the template.
    #Note: The following env variables are also inserted
    #into this dictionary:
    #code_root
    #log_dir
    #project  (the project name)
    #virtualenv_root
    WEB_PARAM_DICT = {
        "HOST_PORT" : 80 #Primary port for hosting things
    }

"""
import posixpath
from fabric import utils
from fabric.context_managers import cd
from fabric.contrib.files import uncomment, upload_template
from fabric.operations import sudo, require, put
from fabric.state import env
from fabric.contrib import files
from fabric.colors import green, yellow
from modules.utils import what_os
from fabric.context_managers import settings as fab_settings
import settings


def setup_env(deploy_level="staging"):
    if deploy_level == "staging":
        _staging()
    elif deploy_level == "production":
        _production()
    else:
        raise Exception("Unrecognized Deploy Level: %s" % deploy_level)
    env.os = what_os()
#    env.user = settings.PROJECT_USER
#    env.sudo_user = settings.SUDO_USER
    env.project = settings.PROJECT_NAME
    env.project_root = settings.PROJECT_ROOT % env #remember to pass in the 'env' dict before using this field from settings, since it could contain keywords.
    env.httpd = settings.WEB_HTTPD
    env.httpd_local_template_path = settings.WEB_CONFIG_TEMPLATE_PATH
    httpd_dict = settings.WEB_PARAM_DICT
    _setup_path()

    #insert some additional useful pairs
    httpd_dict["code_root"] = env.code_root
    httpd_dict["log_dir"] = env.log_dir
    httpd_dict["project"] = env.project
    httpd_dict["virtualenv_root"] = env.virtualenv_root
    env.httpd_dict = httpd_dict

def _production():
    """ use production environment on remote host"""
    env.environment = 'production'
    env.server_name = 'project-production.dimagi.com'
    env.hosts = settings.PRODUCTION_HOST

def _staging():
    """ use staging environment on remote host"""
    env.environment = 'staging'
    env.server_name = 'project-staging.dimagi.com'
    env.hosts = settings.STAGING_HOST

def _setup_path():
    """
    Assigns all the various paths that will be needed (to the env object)
    in deploying code, populating config templates, etc.
    """
    env.sup_template_path = posixpath.join(posixpath.abspath(settings.__file__),settings.SUPERVISOR_TEMPLATE_PATH)
    env.project_root = settings.PROJECT_ROOT
    env.www_root = posixpath.join(env.project_root,'www',env.environment)
    env.log_dir = posixpath.join(env.www_root,'log')
    env.code_root = posixpath.join(env.www_root,'code_root')
    env.project_media = posixpath.join(env.code_root, 'media')
    env.project_static = posixpath.join(env.project_root, 'static')
    env.virtualenv_name = getattr(settings, 'PYTHON_ENV_NAME', 'python_env') #not a required setting and should be sufficient with default name
    env.virtualenv_root = posixpath.join(env.www_root, env.virtualenv_name)
    env.services_root = posixpath.join(env.project_root, 'services')
    env.httpd_services_root = posixpath.join(env.services_root, 'apache')
    env.httpd_services_template_name = '%(project)s.conf' % env
    env.httpd_remote_services_template_path = posixpath.join(env.httpd_services_root,env.httpd_services_template_name)
    env.supervisor_conf_root = posixpath.join(env.services_root, 'supervisor')
    env.supervisor_conf_path = posixpath.join(env.supervisor_conf_root, 'supervisor.conf')
    env.supervisor_init_template_path = settings.SUPERVISOR_INIT_TEMPLATE
    if env.os == 'ubuntu':
        env.httpd_remote_conf_root = '/etc/apache2/sites-enabled'
        env.httpd_user_group = 'www-data'
    elif env.os == 'redhat':
        env.httpd_remote_conf_root = '/etc/httpd/conf.d'
        env.httpd_user_group = 'apache'
    else:
        utils.abort('In Web module. Remote operating system ("%(os)s") not recognized. Aborting.' % env)



[docs]def setup_dirs(): """ create (if necessary) and make writable uploaded media, log, etc. directories """ if not files.exists(env.log_dir): print green('Log Directory (%s) does not exist on host, creating...' % env.log_dir) sudo('mkdir -p %(log_dir)s' % env) sudo('chmod a+w %(log_dir)s' % env) if not files.exists(env.httpd_services_root): print green('Services/apache Directory (%(httpd_services_root)s) does not exist on host, creating...' % env) sudo('mkdir -p %(httpd_services_root)s' % env) sudo('chmod a+w %(httpd_services_root)s' % env)
[docs]def bootstrap(deploy_level="staging"): """ Sets up log directories if they don't exist, uploads the apache conf and reloads apache. """ print green("In Web Module, bootstrap().") setup_env(deploy_level) setup_dirs() start_apache() #reload fails if we don't start apache for the first time upload_apache_conf() reload_apache() print green("Done bootstrapping web module")
[docs]def deploy(): """ Uploads the httpd conf (apache or nginx in future) to the correct place. """ upload_apache_conf() reload_apache()
[docs]def upload_apache_conf(): """ Upload and link Supervisor configuration from the template. """ require('environment', 'httpd_services_template_name', provided_by=('setup_env')) env.tmp_destination = posixpath.join('/', 'tmp', env.httpd_services_template_name) files.upload_template(env.httpd_local_template_path, env.tmp_destination, context=env.httpd_dict, use_sudo=True) env.httpd_sudo_user = settings.SUDO_USER sudo('chown -R %(httpd_sudo_user)s %(tmp_destination)s' % env) sudo('chgrp -R %(httpd_user_group)s %(tmp_destination)s' % env) sudo('chmod -R g+w %(tmp_destination)s' % env) sudo('mv -f %(tmp_destination)s %(httpd_remote_services_template_path)s' % env) if env.os == 'ubuntu': sudo('a2enmod proxy') sudo('a2enmod proxy_http') #should already be enabled for redhat elif env.os != 'redhat': utils.abort('OS Not recognized in Web Module') with(fab_settings(warn_only=True)): sudo('rm %(httpd_remote_conf_root)s/%(project)s' % env) sudo('ln -s %(httpd_remote_services_template_path)s %(httpd_remote_conf_root)s/%(project)s' % env) #symbolic link our apache conf to the 'sites-enabled' folder
[docs]def run_apache_command(command): """ Runs the given command on the apache service """ require('os', provided_by=('setup_env')) if env.os == 'ubuntu': httpd_service_name = 'apache2' elif env.os == 'redhat': httpd_service_name = 'httpd' else: utils.abort('OS Not recognized in Web Module') #execute the command sudo('/etc/init.d/%s %s' % (httpd_service_name, command)) #convenience functions:
def restart_apache(): require('os', provided_by=('setup_env')) run_apache_command('restart') def stop_apache(): require('os', provided_by=('setup_env')) run_apache_command('stop') def start_apache(): require('os', provided_by=('setup_env')) run_apache_command('start') def reload_apache(): require('os', provided_by=('setup_env')) run_apache_command('reload') def status_apache(): require('os', provided_by=('setup_env')) run_apache_command('status')