commit cf06a1987d2cb38112987941f53679abffdfc15c Author: Lance Edgar Date: Sun Nov 15 20:22:01 2015 -0600 Initial commit, with 'host' server example. Even that isn't quite complete, but I'm anxious to test other things.. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8162118 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +rattail_fabdemo.egg-info/ +servers/*/fabenv.py +servers/*/.vagrant/ diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..0d04efe --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,3 @@ +# -*- mode: conf -*- + +recursive-include servers * diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..daded88 --- /dev/null +++ b/README.rst @@ -0,0 +1,12 @@ +.. -*- coding: utf-8 -*- + +Rattail Fabric Demo +=================== + +This project serves as a working demo, to illustrate various concepts of the +Rattail server deployment framework. See the `Rattail Wiki`_ for more info. + +Note that it also aims to be usable as a starting point for your own deployment +project(s), should you need one. + +.. _`Rattail Wiki`: https://rattailproject.org/moin/Deployment diff --git a/fabdemo/__init__.py b/fabdemo/__init__.py new file mode 100644 index 0000000..3638bdf --- /dev/null +++ b/fabdemo/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +""" +Rattail Fabric Demo +""" + +from ._version import __version__ diff --git a/fabdemo/_version.py b/fabdemo/_version.py new file mode 100644 index 0000000..e727f3d --- /dev/null +++ b/fabdemo/_version.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +__version__ = u'0.1.0' diff --git a/servers/host/README.rst b/servers/host/README.rst new file mode 100644 index 0000000..d581ba2 --- /dev/null +++ b/servers/host/README.rst @@ -0,0 +1,10 @@ +.. -*- coding: utf-8 -*- + +Bundle for 'host' Server +======================== + +This is a fictitious "host" server, with no special requirements other than +general bundle prep (fabenv only, no secure files needed for this one). Please +see the `Rattail Wiki`_ for instructions. + +.. _`Rattail Wiki`: https://rattailproject.org/moin/Deployment/ServerBundlePrep diff --git a/servers/host/Vagrantfile b/servers/host/Vagrantfile new file mode 100644 index 0000000..3b14418 --- /dev/null +++ b/servers/host/Vagrantfile @@ -0,0 +1,7 @@ +# -*- mode: ruby -*- + +Vagrant.configure("2") do |config| + config.vm.box = "debian/jessie64" + config.vm.network "forwarded_port", guest: 80, host: 9080 + config.vm.network "forwarded_port", guest: 443, host: 9443 +end diff --git a/servers/host/deploy/apache/wsgi.conf b/servers/host/deploy/apache/wsgi.conf new file mode 100644 index 0000000..b8bac14 --- /dev/null +++ b/servers/host/deploy/apache/wsgi.conf @@ -0,0 +1,3 @@ +# -*- mode: apache -*- + +WSGIPythonHome /srv/envs/BASELINE diff --git a/servers/host/deploy/pod/pod.localhost.conf b/servers/host/deploy/pod/pod.localhost.conf new file mode 100644 index 0000000..f30a6e4 --- /dev/null +++ b/servers/host/deploy/pod/pod.localhost.conf @@ -0,0 +1,49 @@ +# -*- mode: apache -*- + + + ServerName pod.localhost + + DocumentRoot /srv/pod/ + + Options +Indexes + Require all granted + + + # Forbid directory browsing of POD images; there are just too many. + + Options -Indexes + + + ErrorLog ${APACHE_LOG_DIR}/error.log + LogLevel warn + CustomLog ${APACHE_LOG_DIR}/access.log combined + + + + + ServerName pod.localhost + + DocumentRoot /srv/pod/ + + Options +Indexes + Require all granted + + + # Forbid directory browsing of POD images; there are just too many. + + Options -Indexes + + + SSLEngine on + SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem + SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key + + ErrorLog ${APACHE_LOG_DIR}/error.log + LogLevel warn + CustomLog ${APACHE_LOG_DIR}/ssl_access.log combined + + BrowserMatch "MSIE [2-6]" \ + nokeepalive ssl-unclean-shutdown \ + downgrade-1.0 force-response-1.0 + BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown + diff --git a/servers/host/deploy/python/premkvirtualenv b/servers/host/deploy/python/premkvirtualenv new file mode 100755 index 0000000..dcd4ad5 --- /dev/null +++ b/servers/host/deploy/python/premkvirtualenv @@ -0,0 +1,17 @@ +#!/bin/bash +# This hook is run after a new virtualenv is created and before it is activated. + +cat >$1/pip.conf <$1/bin/postactivate <$1/bin/postdeactivate < + ServerName rattail.localhost + + WSGIScriptAlias / /srv/envs/rattail/app/rattail.wsgi + + WSGIProcessGroup rattail + Require all granted + + + ErrorLog ${APACHE_LOG_DIR}/error.log + LogLevel warn + CustomLog ${APACHE_LOG_DIR}/access.log combined + + + + ServerName rattail.localhost + + WSGIScriptAlias / /srv/envs/rattail/app/rattail.wsgi + + WSGIProcessGroup rattail + Require all granted + + + ErrorLog ${APACHE_LOG_DIR}/error.log + LogLevel warn + CustomLog ${APACHE_LOG_DIR}/ssl_access.log combined + + SSLEngine on + SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem + SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key + + BrowserMatch "MSIE [2-6]" \ + nokeepalive ssl-unclean-shutdown \ + downgrade-1.0 force-response-1.0 + BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown + diff --git a/servers/host/deploy/rattail/rattail.wsgi b/servers/host/deploy/rattail/rattail.wsgi new file mode 100644 index 0000000..238abab --- /dev/null +++ b/servers/host/deploy/rattail/rattail.wsgi @@ -0,0 +1,9 @@ +# -*- coding: utf-8; mode: python -*- + +from __future__ import unicode_literals + +import site +site.addsitedir('/srv/envs/rattail/lib/python2.7/site-packages') + +from pyramid.paster import get_app +application = get_app('/srv/envs/rattail/app/web.conf') diff --git a/servers/host/deploy/rattail/web.conf b/servers/host/deploy/rattail/web.conf new file mode 100644 index 0000000..e04df43 --- /dev/null +++ b/servers/host/deploy/rattail/web.conf @@ -0,0 +1,44 @@ + +###################################################################### +# +# Tailbone Website +# +###################################################################### + + +############################## +# Rattail +############################## + +[rattail.config] +include = %(here)s/rattail.conf + + +#################### +# Pyramid +#################### + +[app:main] +use = egg:Tailbone + +pyramid.reload_templates = true +pyramid.debug_all = true +pyramid.default_locale_name = en +pyramid.includes = pyramid_debugtoolbar + +beaker.session.type = file +beaker.session.data_dir = %(here)s/sessions/data +beaker.session.lock_dir = %(here)s/sessions/lock +beaker.session.secret = some-gobbledy-gook +beaker.session.key = rattail + +# Hack so rattail can find this file from within WSGI app. +edbob.config = %(here)s/web.conf + + +############################## +# Logging +############################## + +[handler_file] +args = ('/srv/envs/rattail/app/log/web.log', 'a', 1000000, 20, 'utf_8') diff --git a/servers/host/fabenv.py.dist b/servers/host/fabenv.py.dist new file mode 100644 index 0000000..68be47e --- /dev/null +++ b/servers/host/fabenv.py.dist @@ -0,0 +1,25 @@ +# -*- coding: utf-8; mode: python -*- +""" +Fabric environment tweaks. + +You must save this file as 'fabenv.py' within the current directory, then edit +the settings however you need/like to manage a particular target server. +""" + +from __future__ import unicode_literals + +from fabric.api import env + + +# Whether or not the target server should be considered "live". This may +# control various things, such as whether certain automated tasks are enabled. +env.server_is_live = False + +# Whether or not Product Open Data (POD) files should be downloaded. +env.rattail_download_pod = False + +# Alternate download URL for POD source file. +#env.setting_pod_download_url = 'https://rattailproject.org/downloads/POD/pod_pictures_gtin_2013.08.29_01.zip' + +# Password for 'rattail' PostgreSQL user; used to access the Rattail database. +env.password_postgresql_rattail = 'password' diff --git a/servers/host/fabfile.py b/servers/host/fabfile.py new file mode 100644 index 0000000..d7c0f62 --- /dev/null +++ b/servers/host/fabfile.py @@ -0,0 +1,144 @@ +# -*- coding: utf-8 -*- +""" +Fabric script for the 'host' server + +Please see the accompanying README for full instructions. +""" + +from __future__ import unicode_literals + +import os + +from fabric.api import * +from fabric.utils import warn, puts +from fabric.contrib.files import append, exists + +from rattail.fablib import make_deploy, mkdir, make_system_user, cdvirtualenv, workon +from rattail.fablib import apt, pod, postgresql, python + + +__all__ = ['bootstrap_all', 'bootstrap_system', 'bootstrap_rattail', 'bootstrap_pod'] + +# Set the 'live' role to the canonical hostname for this server. +#env.roledefs = {'live': ['host.example.com']} + +deploy = make_deploy(__file__) + +try: + import fabenv +except ImportError as error: + warn("Couldn't import fabenv: {0}".format(error)) + + +@task +def bootstrap_all(): + """ + Bootstrap all aspects of the server. + """ + bootstrap_system() + bootstrap_rattail() + bootstrap_pod() + + +@task +def bootstrap_system(): + """ + Bootstrap the base system. + """ + apt.dist_upgrade() + + # postgresql + apt.install('postgresql') + + # python + apt.install('libpython-dev', 'libpq-dev') + python.install_pip() + python.install_virtualenvwrapper() + deploy('python/premkvirtualenv', '/srv/envs/premkvirtualenv') + sudo('mkvirtualenv BASELINE') + + # apache + apt.install('apache2', 'libapache2-mod-wsgi') + deploy('apache/wsgi.conf', '/etc/apache2/conf-available/wsgi.conf') + sudo('a2enconf wsgi') + sudo('a2enmod ssl') + sudo('service apache2 restart') + + # misc + apt.install('git', 'emacs-nox') + + +@task +def bootstrap_rattail(): + """ + Bootstrap the Rattail software. + """ + from rattail.fablib.rattail import bootstrap_rattail + + # rattail user and core files + bootstrap_rattail() + + # virtual environment + python.mkvirtualenv('rattail') + with cdvirtualenv('rattail'): + mkdir('src') + with workon('rattail'): + python.pip('psycopg2') + + # rattail source + with cdvirtualenv('rattail', 'src'): + if not exists('rattail'): + sudo('git clone https://rattailproject.org/git/rattail.git') + with cdvirtualenv('rattail', 'src/rattail'): + sudo('git pull') + sudo('pip install --editable .') + with workon('rattail'): + sudo('pip install --upgrade rattail[db,auth]') + + # tailbone source + with cdvirtualenv('rattail', 'src'): + if not exists('tailbone'): + sudo('git clone https://rattailproject.org/git/tailbone.git') + with cdvirtualenv('rattail', 'src/tailbone'): + sudo('git pull') + sudo('pip install --upgrade --editable .') + + # config + with cdvirtualenv('rattail', 'app'): + deploy('rattail/rattail.conf.template', 'rattail.conf') + + # database + postgresql.create_user('rattail', password=env.password_postgresql_rattail) + postgresql.create_db('rattail', owner='rattail') + with cd('/srv/envs/rattail'): + sudo('bin/alembic --config=app/rattail.conf upgrade heads', user='rattail') + sudo('bin/rattail --config app/rattail.conf initdb --with-admin', user='rattail') + + # website + with cdvirtualenv('rattail', 'app'): + mkdir('sessions', owner='rattail:rattail') + deploy('rattail/web.conf', 'web.conf') + deploy('rattail/rattail.wsgi', 'rattail.wsgi') + append('/etc/hosts', '127.0.0.1 rattail.localhost', use_sudo=True) + deploy('rattail/rattail.localhost.conf', '/etc/apache2/sites-available/rattail.localhost.conf') + sudo('a2ensite rattail.localhost') + sudo('service apache2 restart') + + +@task +def bootstrap_pod(): + """ + Bootstrap the POD images website. + """ + # images + mkdir('/srv/pod') + if getattr(env, 'rattail_download_pod', False): + pod.install_pod() + else: + puts("Skipping POD download, per 'fabenv' settings.") + + # website + append('/etc/hosts', '127.0.0.1 pod.localhost', use_sudo=True) + deploy('pod/pod.localhost.conf', '/etc/apache2/sites-available/pod.localhost.conf') + sudo('a2ensite pod.localhost') + sudo('service apache2 restart') diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..2cb5839 --- /dev/null +++ b/setup.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +""" +Setup script for Rattail Fabric Demo +""" + +from __future__ import unicode_literals + +import os +from setuptools import setup, find_packages + + +here = os.path.abspath(os.path.dirname(__file__)) +execfile(os.path.join(here, 'fabdemo', '_version.py')) +README = open(os.path.join(here, 'README.rst')).read() + + +requires = [ + # + # Version numbers within comments below have specific meanings. + # Basically the 'low' value is a "soft low," and 'high' a "soft high." + # In other words: + # + # If either a 'low' or 'high' value exists, the primary point to be + # made about the value is that it represents the most current (stable) + # version available for the package (assuming typical public access + # methods) whenever this project was started and/or documented. + # Therefore: + # + # If a 'low' version is present, you should know that attempts to use + # versions of the package significantly older than the 'low' version + # may not yield happy results. (A "hard" high limit may or may not be + # indicated by a true version requirement.) + # + # Similarly, if a 'high' version is present, and especially if this + # project has laid dormant for a while, you may need to refactor a bit + # when attempting to support a more recent version of the package. (A + # "hard" low limit should be indicated by a true version requirement + # when a 'high' version is present.) + # + # In any case, developers and other users are encouraged to play + # outside the lines with regard to these soft limits. If bugs are + # encountered then they should be filed as such. + # + # package # low high + + 'Fabric', # 1.10.2 + 'rattail', # 0.5.9 + ] + + +setup( + name = "rattail-fabdemo", + version = __version__, + author = "Lance Edgar", + author_email = "lance@edbob.org", + url = "https://rattailproject.org/", + description = "Rattail Fabric Deployment Demo", + long_description = README, + + classifiers = [ + 'Private :: Do No Upload', + 'Development Status :: 3 - Alpha', + 'Environment :: Console', + 'Intended Audience :: Developers', + 'Natural Language :: English', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Topic :: Office/Business', + 'Topic :: Software Development :: Libraries :: Python Modules', + ], + + install_requires = requires, + packages = find_packages(), + )