X-Git-Url: https://git.mdrn.pl/redakcja.git/blobdiff_plain/7100b7600042ac22687fb3036547841578b7e512..5505442331be28acb7e2919f21df7ec94fe938ea:/deployment.py diff --git a/deployment.py b/deployment.py index 3553aa18..b989fc7a 100644 --- a/deployment.py +++ b/deployment.py @@ -1,64 +1,155 @@ -#!/srv/library/redakcja/pythonenv/bin/python from __future__ import with_statement import shutil import os import sys +import logging + +logging.basicConfig(stream=sys.stderr, format="%(levelname)s:: %(message)s", level=logging.INFO) from string import Template -def render_template(source, dest, context={}): - print "Rendering template:", - with open(source, 'rb') as source_file: - t = Template(source_file.read()) - with open(dest, 'wb') as dest_file: - dest_file.write(t.safe_substitute(context)) - print "done." +class DeploySite(object): + + def __init__(self, **env): + self.env = env + + for arg in ('ROOT', 'PROJECT_NAME', 'PYTHON_VERSION'): + if arg not in self.env: + raise ValueError("Argument '%s' is required." % arg) + + if 'PYTHON_BASE' not in self.env: + self.env['PYTHON_BASE'] = os.path.join(self.env['ROOT'], 'pythonenv') + + if 'PYTHON_BIN' not in self.env: + self.env['PYTHON_BIN'] = os.path.join( + self.env['PYTHON_BASE'], 'bin', 'python') + self.env['PYTHON_VERSION'] + + if 'PIP_BIN' not in self.env: + self.env['PIP_BIN'] = os.path.join(self.env['PYTHON_BASE'], 'bin', 'pip') + + if 'PYTHON_SITE' not in self.env: + self.env['PYTHON_SITE'] = os.path.join( + self.env['PYTHON_BASE'], 'lib', + 'python' + self.env['PYTHON_VERSION'], 'site-packages') + + if 'APP_DIR' not in self.env: + self.env['APP_DIR'] = os.path.join(self.env['ROOT'], 'application') + + if 'CONFIG_DIR' not in self.env: + self.env['CONFIG_DIR'] = os.path.join(self.env['ROOT'], 'etc') + + if 'MEDIA_DIR' not in self.env: + self.env['MEDIA_DIR'] = os.path.join(self.env['ROOT'], 'www', 'media') + + self._logger = logging.getLogger("deployment") + + def info(self, *args, **kwargs): + self._logger.info(*args, **kwargs) + + def render_template(self, source, dest, extra_context={}): + self.info("Rendering template: %s", source) + + with open(source, 'rb') as source_file: + t = Template(source_file.read()) + + context = dict(self.env) + context.update(extra_context) + + with open(dest, 'wb') as dest_file: + dest_file.write(t.safe_substitute(context)) + + self.info("Done.") + + def restart_app(self): + pass + + def update_app(self): + pass + + def update_config(self): + pass + + def install_dependencies(self): + pass + + def deploy(self): + self.update_app() + self.install_dependencies() + self.update_config() + self.restart_app() + + def find_resource(self, path): + for dir in (self.env['CONFIG_DIR'], self.env['APP_DIR']): + full_path = os.path.join(dir, path) + if os.path.isfile(full_path): + return full_path + + raise ValueError("Resource '%s' not found" % path) + + @classmethod + def run_deploy(cls, *args, **kwargs): + site = cls(*args, **kwargs) + return site.deploy() + +class WSGISite(DeploySite): + + def __init__(self, **env): + super(WSGISite, self).__init__(**env) + + if 'WSGI_FILE' not in self.env: + self.env['WSGI_FILE'] = os.path.join(self.env['ROOT'], 'www', + 'wsgi', self.env['PROJECT_NAME']) + '.wsgi' + + self.env['WSGI_DIR'] = os.path.dirname(self.env['WSGI_FILE']) + + if 'WSGI_SOURCE_FILE' not in self.env: + self.env['WSGI_SOURCE_FILE'] = 'wsgi_app.template' + + if 'WSGI_USER' not in self.env: + self.env['WSGI_USER'] = 'www-data' + + def restart_app(self): + self.info("Restarting wsgi application: %s", self.env['WSGI_FILE']) + os.system("touch %s" % self.env['WSGI_FILE']) -def restart_wsgi(): - print "Restarting wsgi application:", - os.system("touch %s" % WSGI_TARGET) - print "done." + def update_config(self): + super(WSGISite, self).update_config() -def update_application(): - print "Updating repository.", - os.system("cd %s; git pull" % PROJECT_ROOT) - print "Installing requirements" - os.system("pip install -r %s" % os.path.join(PROJECT_ROOT, 'requirements.txt')) - print "Installing local requirements" - os.system("pip install -r %s" % os.path.join(ROOT, 'etc', 'requirements.txt')) - print "done." + source = self.find_resource(self.env['WSGI_SOURCE_FILE']) + self.render_template(source, self.env['WSGI_FILE']) +class PIPSite(DeploySite): -PYTHON = os.path.join(ROOT, 'pythonenv', 'bin', 'python') -PYTHON_SITE = os.path.join(ROOT, 'pythonenv', 'lib', 'python2.6', 'site-packages') + def install_dependencies(self): + self.info("Installing requirements") + os.system("%s install -r %s" % (self.env['PIP_BIN'], self.find_resource('requirements.txt'))) -PROJECT_NAME = 'redakcja' -PROJECT_ROOT = os.path.join(ROOT, 'application') + try: + self.info("Installing local requirements") + os.system("%s install -r %s" % (self.env['PIP_BIN'], self.find_resource('requirements_local.txt'))) + except ValueError: + pass -MEDIA_ROOT = os.path.join(ROOT, 'www', 'media') +class GitSite(DeploySite): -ADMIN_EMAIL = 'lrekucki@gmail.com' + def update_app(self): + self.info("Updating repository.") + os.system("cd %s; git pull" % self.env['APP_DIR']) -WSGI_TARGET = os.path.join(ROOT, 'www', 'wsgi', PROJECT_NAME + '.wsgi') -WSGI_DIR = os.path.dirname(WSGI_TARGET) +class ApacheSite(DeploySite): -WSGI_USER = PROJECT_NAME -WSGI_PROCESSES = 5 -WSGI_THREADS = 1 + def __init__(self, **env): + super(ApacheSite, self).__init__(**env) -DOMAIN = 'redakcja.wolnelektury.pl' -DOMAIN_ALIASES = 'redakcja.nowoczesnapolska.org.pl' + if 'VHOST_SOURCE_FILE' not in self.env: + self.env['VHOST_SOURCE_FILE'] = 'apache_vhost.template' -# -# Load local configuration -# -sys.path = [ os.path.join(ROOT, 'etc') ] + sys.path + if 'VHOST_FILE' not in self.env: + self.env['VHOST_FILE'] = os.path.join(self.env['CONFIG_DIR'], self.env['PROJECT_NAME'] + '.vhost') -from local_deployment import * + def update_config(self): + super(ApacheSite, self).update_config() -if __name__ == '__main__': - update_application() - render_template(os.path.join(PROJECT_ROOT, PROJECT_NAME + '.wsgi.template'), WSGI_TARGET, context=globals()) - render_template(os.path.join(PROJECT_ROOT, PROJECT_NAME + '.vhost.template'), os.path.join(ROOT, 'etc', PROJECT_NAME + '.vhost'), context=globals()) - restart_wsgi() + source = self.find_resource(self.env['VHOST_SOURCE_FILE']) + self.render_template(source, self.env['VHOST_FILE'])