Commits

Andriy Kornatskyy  committed 0f0d066

Added fabric deployment options with debian, nginx and uwsgi.

  • Participants
  • Parent commits c99b1f3

Comments (0)

Files changed (28)

File demos/quickstart-empty/MANIFEST.in

-include *.ini
 include Makefile
 include README.rst
+include content/maintenance.html
+include etc/config.ini
+include etc/nginx.conf
 include src/*.py
 recursive-include content/static/css *.css
 recursive-include content/static/img *.ico *.jpg *.gif *.png

File demos/quickstart-empty/Makefile

 
 env: virtualenv
 	$(EASY_INSTALL) -i $(PYPI) -O2 coverage nose pytest \
-	        pytest-pep8 pytest-cov
+	        pytest-pep8 pytest-cov lxml
 	if [ "$$(echo $(VERSION) | sed 's/\.//')" -eq 24 ]; then \
 		$(EASY_INSTALL) -i $(PYPI) -O2 wsgiref ; \
 	else \

File demos/quickstart-empty/development.ini

-
-[runtime]
-mode = mock
-unhandled = stderr
-
-[cache-profile]
-public-enabled = True
-static-enabled = True
-
-[crypto]
-encryption-key = r0sWsYR3dHUcrPWeTcB7
-ticket-max-age = 1200
-ticket-salt = WmMFjzVbSpWlCKb6cOC4
-validation-key = kTrdyg9ZwcNyE6YKoPJU
-
-[uwsgi]
-wsgi = app:main
-; uwsgi-socket = /tmp/uwsgi-mysite.sock
-http-socket = 0.0.0.0:8080
-uid = www-data
-gid = www-data
-chmod-socket = 700
-umask = 077
-harakiri = 10
-optimize = 2
-master = True
-processes = 1
-chdir = .
-virtualenv = env
-pythonpath = src
-disable-logging = True
-; logto = /dev/null
-no-default-app = False
-auto-procname = True
-procname-prefix = MySite-
-; Higher concurrency rates you are probably hitting your OS socket backlog
-; queue limit.
-; echo 1024 > /proc/sys/net/core/somaxconn
-; echo 1024 > /proc/sys/net/ipv4/tcp_max_syn_backlog
-listen = 100
-; Limit the address space usage of each uWSGI process using
-; POSIX/UNIX setrlimit()
-limit-as = 120
-; Set the internal buffer size for uwsgi packet parsing. Default is 4k.
-buffer-size = 4096
-; Enable http body buffering. uWSGI will save to disk all HTTP body
-; bigger than the limit specified.
-post-buffering = 1024
-; Limit the size of body in HTTP requests. It reads the CONTENT_LENGTH
-; uwsgi variable to know the size.
-limit-post = 1024
-thread-stacksize = 64
-idle = 300
-python-auto-reload = 5
-lazy = True
-static-map = /static=content/static
-static-map = /favicon.ico=content/static/img/favicon.ico

File demos/quickstart-empty/etc/config.ini

+
+[runtime]
+mode = mock
+unhandled = stderr
+
+[cache-profile]
+public-enabled = True
+static-enabled = True
+
+[crypto]
+encryption-key = 9CvH6TDvwjwKt443tNZS
+ticket-max-age = 1200
+ticket-salt = 9a84Nm9kuAyXF9vHS8dH
+validation-key = mU5ChwVKqgE7vHY7Hqp9
+
+[uwsgi]
+; uwsgi version 1.2.3
+wsgi = app:main
+plugins = python27
+uwsgi-socket = /var/tmp/uwsgi-mysite.sock
+uid = www-data
+gid = www-data
+chmod-socket = 700
+umask = 077
+harakiri = 10
+optimize = 2
+master = True
+processes = 1
+env = CONFIG=/usr/local/etc/mysite/config.ini
+chdir = /usr/local/lib/mysite/current
+virtualenv = env
+pythonpath = src
+disable-logging = True
+logto = /dev/null
+no-default-app = False
+auto-procname = True
+procname-prefix = MySite-
+; Higher concurrency rates you are probably hitting your OS socket backlog
+; queue limit.
+; echo 1024 > /proc/sys/net/core/somaxconn
+; echo 1024 > /proc/sys/net/ipv4/tcp_max_syn_backlog
+listen = 100
+; Limit the address space usage of each uWSGI process using
+; POSIX/UNIX setrlimit()
+limit-as = 120
+; Set the internal buffer size for uwsgi packet parsing. Default is 4k.
+buffer-size = 4096
+; Enable http body buffering. uWSGI will save to disk all HTTP body
+; bigger than the limit specified.
+post-buffering = 2048
+; Limit the size of body in HTTP requests. It reads the CONTENT_LENGTH
+; uwsgi variable to know the size.
+limit-post = 2048
+thread-stacksize = 64
+idle = 300
+; Try to remove all of the generated files/sockets (UNIX sockets and
+; pidfiles) upon exit.
+vacuum = True

File demos/quickstart-empty/etc/development.ini

+
+[runtime]
+mode = mock
+unhandled = stderr
+
+[cache-profile]
+public-enabled = True
+static-enabled = True
+
+[crypto]
+encryption-key = r0sWsYR3dHUcrPWeTcB7
+ticket-max-age = 1200
+ticket-salt = WmMFjzVbSpWlCKb6cOC4
+validation-key = kTrdyg9ZwcNyE6YKoPJU
+
+[uwsgi]
+wsgi = app:main
+; uwsgi-socket = /tmp/uwsgi-mysite.sock
+http-socket = 0.0.0.0:8080
+uid = www-data
+gid = www-data
+chmod-socket = 700
+umask = 077
+harakiri = 10
+optimize = 2
+master = True
+processes = 1
+chdir = .
+virtualenv = env
+pythonpath = src
+disable-logging = True
+; logto = /dev/null
+no-default-app = False
+auto-procname = True
+procname-prefix = MySite-
+; Higher concurrency rates you are probably hitting your OS socket backlog
+; queue limit.
+; echo 1024 > /proc/sys/net/core/somaxconn
+; echo 1024 > /proc/sys/net/ipv4/tcp_max_syn_backlog
+listen = 100
+; Limit the address space usage of each uWSGI process using
+; POSIX/UNIX setrlimit()
+limit-as = 120
+; Set the internal buffer size for uwsgi packet parsing. Default is 4k.
+buffer-size = 4096
+; Enable http body buffering. uWSGI will save to disk all HTTP body
+; bigger than the limit specified.
+post-buffering = 1024
+; Limit the size of body in HTTP requests. It reads the CONTENT_LENGTH
+; uwsgi variable to know the size.
+limit-post = 1024
+thread-stacksize = 64
+idle = 300
+python-auto-reload = 5
+lazy = True
+static-map = /static=content/static
+static-map = /favicon.ico=content/static/img/favicon.ico

File demos/quickstart-empty/etc/nginx.conf

+
+# nginx version 1.2.1
+
+upstream backend {
+    server unix:/var/tmp/uwsgi-mysite.sock;
+}
+
+server {
+    #server_name mysite.mydomain.com;
+
+    client_max_body_size 1k;
+    error_page 502 /maintenance.html;
+
+    location / {
+        uwsgi_pass backend;
+        include uwsgi_params;
+        uwsgi_param SCRIPT_NAME '';
+        #uwsgi_param Host $host;
+        #uwsgi_param X-Real-IP $remote_addr;
+        #uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for;
+        #uwsgi_param X-Forwarded-Proto $http_x_forwarded_proto;
+    }
+
+    location  /static/ {
+        alias  /usr/local/lib/mysite/current/content/static/;
+        access_log off;
+        expires 7d;
+    }
+
+    location /maintenance.html {
+        root /usr/share/nginx/www/;
+        internal;
+    }
+}

File demos/quickstart-empty/fabfile.py

+from fabric.api import cd
+from fabric.api import env
+from fabric.api import lcd
+from fabric.api import local
+from fabric.api import put
+from fabric.api import run
+from fabric.api import sudo
+
+
+# apt-get install sudo
+# #adduser <username> sudo
+# echo '<username> ALL=(ALL:ALL) NOPASSWD: ALL' >> /etc/sudoers
+# env/bin/fab -H <host> -u <username> <command>
+
+NAME = 'mysite'
+ETC_PATH = '/usr/local/etc/' + NAME
+LIB_PATH = '/usr/local/lib/' + NAME
+USER = env['user']
+
+
+def update():
+    name = get_name()
+    filename = name + '.tar.gz'
+    with lcd('dist'), cd(LIB_PATH):
+        put(filename, env.cwd)
+        run('rm -rf ' + name)
+        run('tar xzf ' + filename)
+        run('rm ' + filename)
+        run('rm -f current ')
+        run('ln -s %s current' % name)
+        with cd('current'):
+            run('make install')
+            sudo('cp content/maintenance.html /usr/share/nginx/www')
+
+
+def config():
+    with cd('%s/etc/' % CURRENT_PATH):
+        run('cp *.conf *.ini %s' % ETC_PATH)
+    with cd('/etc/nginx/sites-available'):
+        sudo('rm -f %s.conf' % NAME)
+        sudo('ln -s %s/nginx.conf %s.conf' % (ETC_PATH, NAME))
+    with cd('/etc/nginx/sites-enabled'):
+        sudo('rm -f %s.conf' % NAME)
+        sudo('ln -s /etc/nginx/sites-available/%s.conf' % NAME)
+    sudo('rm -f /etc/nginx/sites-enabled/default')
+    sudo('/etc/init.d/nginx restart')
+    with cd('/etc/uwsgi/apps-available'):
+        sudo('rm -f %s.ini' % NAME)
+        sudo('ln -s %s/config.ini %s.ini' % (ETC_PATH, NAME))
+    with cd('/etc/uwsgi/apps-enabled'):
+        sudo('rm -f %s.ini' % NAME)
+        sudo('ln -s /etc/uwsgi/apps-available/%s.ini' % NAME)
+
+
+def install():
+    sudo('mkdir -p %s %s' % (ETC_PATH, LIB_PATH))
+    sudo('chown -R %s %s %s' % (USER, ETC_PATH, LIB_PATH))
+    update()
+
+
+def uninstall():
+    sudo('rm -rf ' + LIB_PATH)
+
+
+def purge():
+    uninstall()
+    sudo('rm -rf ' + ETC_PATH)
+
+
+def debian():
+	sudo('apt-get update')
+	sudo('apt-get install --no-install-recommends -y build-essential '
+		 'python2.7 python2.7-dev python-setuptools '
+		 'python-virtualenv gettext libgmp3-dev '
+         'nginx-full uwsgi uwsgi-plugin-python')
+	sudo('apt-get clean')
+
+
+def start():
+    sudo('/etc/init.d/uwsgi start')
+
+
+def stop():
+    sudo('/etc/init.d/uwsgi stop')
+
+
+def restart():
+    sudo('/etc/init.d/uwsgi restart')
+
+
+# region: internal details
+#
+# Allow members of group sudo to execute any command without password
+# %sudo   ALL=(ALL:ALL) NOPASSWD: ALL
+
+def get_name():
+    revision = local("hg head --template '{rev}'", capture=True)
+    assert int(revision)
+    name = local('env/bin/python setup.py --fullname', capture=True)
+    return name + '.' + revision
+
+
+CURRENT_PATH = LIB_PATH + '/current'
+
+
+env.colorize_errors = True
+env.key_filename = '~/.ssh/id_rsa'
+env.ssh_config_path = '~/.ssh/config'
+env.use_ssh_config = True

File demos/quickstart-empty/setup.py

 install_optional = [
     #'pylibmc>=1.2.3',
     #'PIL>=1.1.7',
-    'lxml>=3.2.0',
     'pycrypto>=2.6',
 ]
 

File demos/quickstart-empty/src/config.py

 """
 
 import logging
+import os
 import sys
 
 try:  # pragma: nocover
 from tracing import error_report_extra_provider
 
 
-config.read('development.ini')
+config.read(os.getenv('CONFIG', 'etc/development.ini'))
 
 mode = config.get('runtime', 'mode')
 if mode == 'mock':

File demos/quickstart-i18n/MANIFEST.in

-include *.ini
 include Makefile
 include README.rst
+include content/maintenance.html
+include etc/config.ini
+include etc/nginx.conf
 include src/*.py
 recursive-include content/static/css *.css
 recursive-include content/static/img *.ico *.jpg *.gif *.png

File demos/quickstart-i18n/Makefile

 
 env: virtualenv
 	$(EASY_INSTALL) -i $(PYPI) -O2 coverage nose pytest \
-	        pytest-pep8 pytest-cov
+	        pytest-pep8 pytest-cov lxml
 	if [ "$$(echo $(VERSION) | sed 's/\.//')" -eq 24 ]; then \
 		$(EASY_INSTALL) -i $(PYPI) -O2 wsgiref ; \
 	else \

File demos/quickstart-i18n/development.ini

-
-[runtime]
-mode = mock
-unhandled = stderr
-
-[cache-profile]
-public-enabled = False
-static-enabled = True
-
-[crypto]
-encryption-key = r0sWsYR3dHUcrPWeTcB7
-ticket-max-age = 1200
-ticket-salt = WmMFjzVbSpWlCKb6cOC4
-validation-key = kTrdyg9ZwcNyE6YKoPJU
-
-[uwsgi]
-wsgi = app:main
-; uwsgi-socket = /tmp/uwsgi-mysite.sock
-http-socket = 0.0.0.0:8080
-uid = www-data
-gid = www-data
-chmod-socket = 700
-umask = 077
-harakiri = 10
-optimize = 2
-master = True
-processes = 1
-chdir = .
-virtualenv = env
-pythonpath = src
-disable-logging = True
-; logto = /dev/null
-no-default-app = False
-auto-procname = True
-procname-prefix = MySite-
-; Higher concurrency rates you are probably hitting your OS socket backlog
-; queue limit.
-; echo 1024 > /proc/sys/net/core/somaxconn
-; echo 1024 > /proc/sys/net/ipv4/tcp_max_syn_backlog
-listen = 100
-; Limit the address space usage of each uWSGI process using
-; POSIX/UNIX setrlimit()
-limit-as = 120
-; Set the internal buffer size for uwsgi packet parsing. Default is 4k.
-buffer-size = 4096
-; Enable http body buffering. uWSGI will save to disk all HTTP body
-; bigger than the limit specified.
-post-buffering = 1024
-; Limit the size of body in HTTP requests. It reads the CONTENT_LENGTH
-; uwsgi variable to know the size.
-limit-post = 1024
-thread-stacksize = 64
-idle = 300
-python-auto-reload = 5
-lazy = True
-static-map = /static=content/static
-static-map = /favicon.ico=content/static/img/favicon.ico

File demos/quickstart-i18n/etc/config.ini

+
+[runtime]
+mode = mock
+unhandled = stderr
+
+[cache-profile]
+public-enabled = True
+static-enabled = True
+
+[crypto]
+encryption-key = FZdXZR5PRpmwdfQLkCuj
+ticket-max-age = 1200
+ticket-salt = RPV3xBaNaFUffhWPgz9e
+validation-key = wvg5bCcQMn2s5TE8r7FV
+
+[uwsgi]
+; uwsgi version 1.2.3
+wsgi = app:main
+plugins = python27
+uwsgi-socket = /var/tmp/uwsgi-mysite.sock
+uid = www-data
+gid = www-data
+chmod-socket = 700
+umask = 077
+harakiri = 10
+optimize = 2
+master = True
+processes = 1
+env = CONFIG=/usr/local/etc/mysite/config.ini
+chdir = /usr/local/lib/mysite/current
+virtualenv = env
+pythonpath = src
+disable-logging = True
+logto = /dev/null
+no-default-app = False
+auto-procname = True
+procname-prefix = MySite-
+; Higher concurrency rates you are probably hitting your OS socket backlog
+; queue limit.
+; echo 1024 > /proc/sys/net/core/somaxconn
+; echo 1024 > /proc/sys/net/ipv4/tcp_max_syn_backlog
+listen = 100
+; Limit the address space usage of each uWSGI process using
+; POSIX/UNIX setrlimit()
+limit-as = 120
+; Set the internal buffer size for uwsgi packet parsing. Default is 4k.
+buffer-size = 4096
+; Enable http body buffering. uWSGI will save to disk all HTTP body
+; bigger than the limit specified.
+post-buffering = 2048
+; Limit the size of body in HTTP requests. It reads the CONTENT_LENGTH
+; uwsgi variable to know the size.
+limit-post = 2048
+thread-stacksize = 64
+idle = 300
+; Try to remove all of the generated files/sockets (UNIX sockets and
+; pidfiles) upon exit.
+vacuum = True

File demos/quickstart-i18n/etc/development.ini

+
+[runtime]
+mode = mock
+unhandled = stderr
+
+[cache-profile]
+public-enabled = False
+static-enabled = True
+
+[crypto]
+encryption-key = r0sWsYR3dHUcrPWeTcB7
+ticket-max-age = 1200
+ticket-salt = WmMFjzVbSpWlCKb6cOC4
+validation-key = kTrdyg9ZwcNyE6YKoPJU
+
+[uwsgi]
+wsgi = app:main
+; uwsgi-socket = /tmp/uwsgi-mysite.sock
+http-socket = 0.0.0.0:8080
+uid = www-data
+gid = www-data
+chmod-socket = 700
+umask = 077
+harakiri = 10
+optimize = 2
+master = True
+processes = 1
+chdir = .
+virtualenv = env
+pythonpath = src
+disable-logging = True
+; logto = /dev/null
+no-default-app = False
+auto-procname = True
+procname-prefix = MySite-
+; Higher concurrency rates you are probably hitting your OS socket backlog
+; queue limit.
+; echo 1024 > /proc/sys/net/core/somaxconn
+; echo 1024 > /proc/sys/net/ipv4/tcp_max_syn_backlog
+listen = 100
+; Limit the address space usage of each uWSGI process using
+; POSIX/UNIX setrlimit()
+limit-as = 120
+; Set the internal buffer size for uwsgi packet parsing. Default is 4k.
+buffer-size = 4096
+; Enable http body buffering. uWSGI will save to disk all HTTP body
+; bigger than the limit specified.
+post-buffering = 1024
+; Limit the size of body in HTTP requests. It reads the CONTENT_LENGTH
+; uwsgi variable to know the size.
+limit-post = 1024
+thread-stacksize = 64
+idle = 300
+python-auto-reload = 5
+lazy = True
+static-map = /static=content/static
+static-map = /favicon.ico=content/static/img/favicon.ico

File demos/quickstart-i18n/etc/nginx.conf

+
+# nginx version 1.2.1
+
+upstream backend {
+    server unix:/var/tmp/uwsgi-mysite.sock;
+}
+
+server {
+    #server_name mysite.mydomain.com;
+
+    client_max_body_size 1k;
+    error_page 502 /maintenance.html;
+
+    location / {
+        uwsgi_pass backend;
+        include uwsgi_params;
+        uwsgi_param SCRIPT_NAME '';
+        #uwsgi_param Host $host;
+        #uwsgi_param X-Real-IP $remote_addr;
+        #uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for;
+        #uwsgi_param X-Forwarded-Proto $http_x_forwarded_proto;
+    }
+
+    location  /static/ {
+        alias  /usr/local/lib/mysite/current/content/static/;
+        access_log off;
+        expires 7d;
+    }
+
+    location /maintenance.html {
+        root /usr/share/nginx/www/;
+        internal;
+    }
+}

File demos/quickstart-i18n/fabfile.py

+from fabric.api import cd
+from fabric.api import env
+from fabric.api import lcd
+from fabric.api import local
+from fabric.api import put
+from fabric.api import run
+from fabric.api import sudo
+
+
+# apt-get install sudo
+# #adduser <username> sudo
+# echo '<username> ALL=(ALL:ALL) NOPASSWD: ALL' >> /etc/sudoers
+# env/bin/fab -H <host> -u <username> <command>
+
+NAME = 'mysite'
+ETC_PATH = '/usr/local/etc/' + NAME
+LIB_PATH = '/usr/local/lib/' + NAME
+USER = env['user']
+
+
+def update():
+    name = get_name()
+    filename = name + '.tar.gz'
+    with lcd('dist'), cd(LIB_PATH):
+        put(filename, env.cwd)
+        run('rm -rf ' + name)
+        run('tar xzf ' + filename)
+        run('rm ' + filename)
+        run('rm -f current ')
+        run('ln -s %s current' % name)
+        with cd('current'):
+            run('make install po')
+            sudo('cp content/maintenance.html /usr/share/nginx/www')
+
+
+def config():
+    with cd('%s/etc/' % CURRENT_PATH):
+        run('cp *.conf *.ini %s' % ETC_PATH)
+    with cd('/etc/nginx/sites-available'):
+        sudo('rm -f %s.conf' % NAME)
+        sudo('ln -s %s/nginx.conf %s.conf' % (ETC_PATH, NAME))
+    with cd('/etc/nginx/sites-enabled'):
+        sudo('rm -f %s.conf' % NAME)
+        sudo('ln -s /etc/nginx/sites-available/%s.conf' % NAME)
+    sudo('rm -f /etc/nginx/sites-enabled/default')
+    sudo('/etc/init.d/nginx restart')
+    with cd('/etc/uwsgi/apps-available'):
+        sudo('rm -f %s.ini' % NAME)
+        sudo('ln -s %s/config.ini %s.ini' % (ETC_PATH, NAME))
+    with cd('/etc/uwsgi/apps-enabled'):
+        sudo('rm -f %s.ini' % NAME)
+        sudo('ln -s /etc/uwsgi/apps-available/%s.ini' % NAME)
+
+
+def install():
+    sudo('mkdir -p %s %s' % (ETC_PATH, LIB_PATH))
+    sudo('chown -R %s %s %s' % (USER, ETC_PATH, LIB_PATH))
+    update()
+
+
+def uninstall():
+    sudo('rm -rf ' + LIB_PATH)
+
+
+def purge():
+    uninstall()
+    sudo('rm -rf ' + ETC_PATH)
+
+
+def debian():
+	sudo('apt-get update')
+	sudo('apt-get install --no-install-recommends -y build-essential '
+		 'python2.7 python2.7-dev python-setuptools '
+		 'python-virtualenv gettext libgmp3-dev '
+         'nginx-full uwsgi uwsgi-plugin-python')
+	sudo('apt-get clean')
+
+
+def start():
+    sudo('/etc/init.d/uwsgi start')
+
+
+def stop():
+    sudo('/etc/init.d/uwsgi stop')
+
+
+def restart():
+    sudo('/etc/init.d/uwsgi restart')
+
+
+# region: internal details
+#
+# Allow members of group sudo to execute any command without password
+# %sudo   ALL=(ALL:ALL) NOPASSWD: ALL
+
+def get_name():
+    revision = local("hg head --template '{rev}'", capture=True)
+    assert int(revision)
+    name = local('env/bin/python setup.py --fullname', capture=True)
+    return name + '.' + revision
+
+
+CURRENT_PATH = LIB_PATH + '/current'
+
+
+env.colorize_errors = True
+env.key_filename = '~/.ssh/id_rsa'
+env.ssh_config_path = '~/.ssh/config'
+env.use_ssh_config = True

File demos/quickstart-i18n/setup.py

 install_optional = [
     #'pylibmc>=1.2.3',
     #'PIL>=1.1.7',
-    'lxml>=3.2.0',
     'pycrypto>=2.6',
 ]
 

File demos/quickstart-i18n/src/config.py

 """
 
 import logging
+import os
 import sys
 
 try:  # pragma: nocover
 from tracing import error_report_extra_provider
 
 
-config.read('development.ini')
+config.read(os.getenv('CONFIG', 'etc/development.ini'))
 
 mode = config.get('runtime', 'mode')
 if mode == 'mock':

File demos/template/MANIFEST.in

-include *.ini
 include Makefile
 include README.rst
+include content/maintenance.html
+include etc/config.ini
+include etc/nginx.conf
 include src/*.py
 recursive-include content/static/css *.css
 recursive-include content/static/img *.ico *.jpg *.gif *.png

File demos/template/Makefile

 
 env: virtualenv
 	$(EASY_INSTALL) -i $(PYPI) -O2 coverage nose pytest \
-	        pytest-pep8 pytest-cov mock mako tenjin jinja2 \
-			wheezy.template
+	        pytest-pep8 pytest-cov mock lxml \
+			mako tenjin jinja2 wheezy.template
 	if [ "$$(echo $(VERSION) | sed 's/\.//')" -eq 24 ]; then \
 		$(EASY_INSTALL) -i $(PYPI) -O2 wsgiref ; \
 	else \

File demos/template/content/maintenance.html

+<html>
+<head>
+    <title>Maintenance</title>
+    <meta http-equiv="refresh" content="120" url="/" />
+    <style>
+    html, body { height: 80%; }
+    html { display: table; margin: auto; }
+    body { display: table-cell; vertical-align: middle; font-family: monospace;}
+    #t { color: grey; }
+    </style>
+</head>
+<body>
+    <h1>
+        Scheduled Maintenance
+    </h1>
+    <p>
+        <span id="t"></span> Visit us later, please.
+    </p>
+    <script>
+    document.getElementById('t').innerHTML = new Date().toLocaleTimeString() + ':';
+    </script>
+</body>
+</html>

File demos/template/development.ini

-
-[runtime]
-mode = mock
-unhandled = stderr
-
-[cache-profile]
-membership-enabled = True
-public-enabled = True
-static-enabled = True
-
-[crypto]
-encryption-key = r0sWsYR3dHUcrPWeTcB7
-ticket-max-age = 1200
-ticket-salt = WmMFjzVbSpWlCKb6cOC4
-validation-key = kTrdyg9ZwcNyE6YKoPJU
-
-[mako]
-filesystem-checks = False
-module-directory = /tmp/mako_modules
-inline-preprocessor-fallback = False
-
-[jinja2]
-auto-reload = False
-inline-preprocessor-fallback = False
-
-[tenjin]
-inline-preprocessor-fallback = False
-
-[wheezy.template]
-auto-reload = False
-inline-preprocessor-fallback = False
-
-[uwsgi]
-wsgi = app:main
-; uwsgi-socket = /tmp/uwsgi-mysite.sock
-http-socket = 0.0.0.0:8080
-uid = www-data
-gid = www-data
-chmod-socket = 700
-umask = 077
-harakiri = 10
-optimize = 2
-master = True
-processes = 1
-chdir = .
-virtualenv = env
-pythonpath = src
-disable-logging = True
-; logto = /dev/null
-no-default-app = False
-auto-procname = True
-procname-prefix = MySite-
-; Higher concurrency rates you are probably hitting your OS socket backlog
-; queue limit.
-; echo 1024 > /proc/sys/net/core/somaxconn
-; echo 1024 > /proc/sys/net/ipv4/tcp_max_syn_backlog
-listen = 100
-; Limit the address space usage of each uWSGI process using
-; POSIX/UNIX setrlimit()
-limit-as = 120
-; Set the internal buffer size for uwsgi packet parsing. Default is 4k.
-buffer-size = 4096
-; Enable http body buffering. uWSGI will save to disk all HTTP body
-; bigger than the limit specified.
-post-buffering = 1024
-; Limit the size of body in HTTP requests. It reads the CONTENT_LENGTH
-; uwsgi variable to know the size.
-limit-post = 1024
-thread-stacksize = 64
-idle = 300
-python-auto-reload = 5
-lazy = True
-static-map = /static=content/static
-static-map = /favicon.ico=content/static/img/favicon.ico

File demos/template/etc/config.ini

+
+[runtime]
+mode = mock
+unhandled = stderr
+
+[cache-profile]
+membership-enabled = True
+public-enabled = True
+static-enabled = True
+
+[crypto]
+encryption-key = r0sWsYR3dHUcrPWeTcB7
+ticket-max-age = 1200
+ticket-salt = WmMFjzVbSpWlCKb6cOC4
+validation-key = kTrdyg9ZwcNyE6YKoPJU
+
+[mako]
+filesystem-checks = False
+module-directory = /tmp/mako_modules
+inline-preprocessor-fallback = False
+
+[jinja2]
+auto-reload = False
+inline-preprocessor-fallback = False
+
+[tenjin]
+inline-preprocessor-fallback = False
+
+[wheezy.template]
+auto-reload = False
+inline-preprocessor-fallback = False
+
+[uwsgi]
+; uwsgi version 1.2.3
+wsgi = app:main
+plugins = python27
+uwsgi-socket = /var/tmp/uwsgi-mysite.sock
+uid = www-data
+gid = www-data
+chmod-socket = 700
+umask = 077
+harakiri = 10
+optimize = 2
+master = True
+processes = 1
+env = CONFIG=/usr/local/etc/mysite/config.ini
+chdir = /usr/local/lib/mysite/current
+virtualenv = env
+pythonpath = src
+disable-logging = True
+logto = /dev/null
+no-default-app = False
+auto-procname = True
+procname-prefix = MySite-
+; Higher concurrency rates you are probably hitting your OS socket backlog
+; queue limit.
+; echo 1024 > /proc/sys/net/core/somaxconn
+; echo 1024 > /proc/sys/net/ipv4/tcp_max_syn_backlog
+listen = 100
+; Limit the address space usage of each uWSGI process using
+; POSIX/UNIX setrlimit()
+limit-as = 120
+; Set the internal buffer size for uwsgi packet parsing. Default is 4k.
+buffer-size = 4096
+; Enable http body buffering. uWSGI will save to disk all HTTP body
+; bigger than the limit specified.
+post-buffering = 2048
+; Limit the size of body in HTTP requests. It reads the CONTENT_LENGTH
+; uwsgi variable to know the size.
+limit-post = 2048
+thread-stacksize = 64
+idle = 300
+; Try to remove all of the generated files/sockets (UNIX sockets and
+; pidfiles) upon exit.
+vacuum = True

File demos/template/etc/development.ini

+
+[runtime]
+mode = mock
+unhandled = stderr
+
+[cache-profile]
+membership-enabled = True
+public-enabled = True
+static-enabled = True
+
+[crypto]
+encryption-key = r0sWsYR3dHUcrPWeTcB7
+ticket-max-age = 1200
+ticket-salt = WmMFjzVbSpWlCKb6cOC4
+validation-key = kTrdyg9ZwcNyE6YKoPJU
+
+[mako]
+filesystem-checks = False
+module-directory = /tmp/mako_modules
+inline-preprocessor-fallback = False
+
+[jinja2]
+auto-reload = False
+inline-preprocessor-fallback = False
+
+[tenjin]
+inline-preprocessor-fallback = False
+
+[wheezy.template]
+auto-reload = False
+inline-preprocessor-fallback = False
+
+[uwsgi]
+wsgi = app:main
+; uwsgi-socket = /tmp/uwsgi-mysite.sock
+http-socket = 0.0.0.0:8080
+uid = www-data
+gid = www-data
+chmod-socket = 700
+umask = 077
+harakiri = 10
+optimize = 2
+master = True
+processes = 1
+chdir = .
+virtualenv = env
+pythonpath = src
+disable-logging = True
+; logto = /dev/null
+no-default-app = False
+auto-procname = True
+procname-prefix = MySite-
+; Higher concurrency rates you are probably hitting your OS socket backlog
+; queue limit.
+; echo 1024 > /proc/sys/net/core/somaxconn
+; echo 1024 > /proc/sys/net/ipv4/tcp_max_syn_backlog
+listen = 100
+; Limit the address space usage of each uWSGI process using
+; POSIX/UNIX setrlimit()
+limit-as = 120
+; Set the internal buffer size for uwsgi packet parsing. Default is 4k.
+buffer-size = 4096
+; Enable http body buffering. uWSGI will save to disk all HTTP body
+; bigger than the limit specified.
+post-buffering = 1024
+; Limit the size of body in HTTP requests. It reads the CONTENT_LENGTH
+; uwsgi variable to know the size.
+limit-post = 1024
+thread-stacksize = 64
+idle = 300
+python-auto-reload = 5
+lazy = True
+static-map = /static=content/static
+static-map = /favicon.ico=content/static/img/favicon.ico

File demos/template/etc/nginx.conf

+
+# nginx version 1.2.1
+
+upstream backend {
+    server unix:/var/tmp/uwsgi-mysite.sock;
+}
+
+server {
+    #server_name mysite.mydomain.com;
+
+    client_max_body_size 1k;
+    error_page 502 /maintenance.html;
+
+    location / {
+        uwsgi_pass backend;
+        include uwsgi_params;
+        uwsgi_param SCRIPT_NAME '';
+        #uwsgi_param Host $host;
+        #uwsgi_param X-Real-IP $remote_addr;
+        #uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for;
+        #uwsgi_param X-Forwarded-Proto $http_x_forwarded_proto;
+    }
+
+    location  /static/ {
+        alias  /usr/local/lib/mysite/current/content/static/;
+        access_log off;
+        expires 7d;
+    }
+
+    location /maintenance.html {
+        root /usr/share/nginx/www/;
+        internal;
+    }
+}

File demos/template/fabfile.py

+from fabric.api import cd
+from fabric.api import env
+from fabric.api import lcd
+from fabric.api import local
+from fabric.api import put
+from fabric.api import run
+from fabric.api import sudo
+
+
+# apt-get install sudo
+# #adduser <username> sudo
+# echo '<username> ALL=(ALL:ALL) NOPASSWD: ALL' >> /etc/sudoers
+# env/bin/fab -H <host> -u <username> <command>
+
+NAME = 'mysite'
+ETC_PATH = '/usr/local/etc/' + NAME
+LIB_PATH = '/usr/local/lib/' + NAME
+USER = env['user']
+
+
+def update():
+    name = get_name()
+    filename = name + '.tar.gz'
+    with lcd('dist'), cd(LIB_PATH):
+        put(filename, env.cwd)
+        run('rm -rf ' + name)
+        run('tar xzf ' + filename)
+        run('rm ' + filename)
+        run('rm -f current ')
+        run('ln -s %s current' % name)
+        with cd('current'):
+            run('make install po')
+            sudo('cp content/maintenance.html /usr/share/nginx/www')
+
+
+def config():
+    with cd('%s/etc/' % CURRENT_PATH):
+        run('cp *.conf *.ini %s' % ETC_PATH)
+    with cd('/etc/nginx/sites-available'):
+        sudo('rm -f %s.conf' % NAME)
+        sudo('ln -s %s/nginx.conf %s.conf' % (ETC_PATH, NAME))
+    with cd('/etc/nginx/sites-enabled'):
+        sudo('rm -f %s.conf' % NAME)
+        sudo('ln -s /etc/nginx/sites-available/%s.conf' % NAME)
+    sudo('rm -f /etc/nginx/sites-enabled/default')
+    sudo('/etc/init.d/nginx restart')
+    with cd('/etc/uwsgi/apps-available'):
+        sudo('rm -f %s.ini' % NAME)
+        sudo('ln -s %s/config.ini %s.ini' % (ETC_PATH, NAME))
+    with cd('/etc/uwsgi/apps-enabled'):
+        sudo('rm -f %s.ini' % NAME)
+        sudo('ln -s /etc/uwsgi/apps-available/%s.ini' % NAME)
+
+
+def install():
+    sudo('mkdir -p %s %s' % (ETC_PATH, LIB_PATH))
+    sudo('chown -R %s %s %s' % (USER, ETC_PATH, LIB_PATH))
+    update()
+
+
+def uninstall():
+    sudo('rm -rf ' + LIB_PATH)
+
+
+def purge():
+    uninstall()
+    sudo('rm -rf ' + ETC_PATH)
+
+
+def debian():
+	sudo('apt-get update')
+	sudo('apt-get install --no-install-recommends -y build-essential '
+		 'python2.7 python2.7-dev python-setuptools '
+		 'python-virtualenv gettext libgmp3-dev '
+         'nginx-full uwsgi uwsgi-plugin-python')
+	sudo('apt-get clean')
+
+
+def start():
+    sudo('/etc/init.d/uwsgi start')
+
+
+def stop():
+    sudo('/etc/init.d/uwsgi stop')
+
+
+def restart():
+    sudo('/etc/init.d/uwsgi restart')
+
+
+# region: internal details
+#
+# Allow members of group sudo to execute any command without password
+# %sudo   ALL=(ALL:ALL) NOPASSWD: ALL
+
+def get_name():
+    revision = local("hg head --template '{rev}'", capture=True)
+    assert int(revision)
+    name = local('env/bin/python setup.py --fullname', capture=True)
+    return name + '.' + revision
+
+
+CURRENT_PATH = LIB_PATH + '/current'
+
+
+env.colorize_errors = True
+env.key_filename = '~/.ssh/id_rsa'
+env.ssh_config_path = '~/.ssh/config'
+env.use_ssh_config = True

File demos/template/setup.py

 install_optional = [
     #'pylibmc>=1.2.3',
     #'PIL>=1.1.7',
-    'lxml>=3.2.0',
     'pycrypto>=2.6',
 ]
 

File demos/template/src/config.py

 from tracing import error_report_extra_provider
 
 
-config.read('development.ini')
+config.read(os.getenv('CONFIG', 'etc/development.ini'))
 
 mode = config.get('runtime', 'mode')
 if mode == 'mock':