Add fabric bundle for 'theo-server'

This commit is contained in:
Lance Edgar 2020-09-19 18:55:17 -05:00
parent 9e275a35f8
commit a26e3088c5
23 changed files with 1032 additions and 0 deletions

4
.gitignore vendored
View file

@ -1 +1,5 @@
tailbone_theo.egg-info/ tailbone_theo.egg-info/
machines/theo-server/.vagrant/
machines/theo-server/fabenv.py
machines/theo-server/fabric.yaml
machines/theo-server/Vagrantfile

View file

@ -0,0 +1,42 @@
<!-- -*- mode: markdown; -*- -->
# theo-server
This is for a server which runs Theo, the order system.
## Updating Live Server
Note that this assumes you have defined `server` within your SSH config,
e.g. at `~/.ssh/config`. Also you should configure the root password within
`./fabric.yaml`.
Install everything with:
fab2 -e -H server bootstrap-all
## Testing with Vagrant
You should be able to get a VM going with a simple:
vagrant up
You can then SSH directly into the VM with:
vagrant ssh
You can confirm SSH credentials needed for connecting to it, with:
vagrant ssh-config
Now you can "bootstrap" the machine with Fabric. Please double-check your
`fabenv.py` file and make sure it contains:
env.machine_is_live = False
After all this machine is *not* live, it's just for testing. Finally, here is
the bootstrap command. Note that it's possible you may need to modify some
parameters based on the output of `vagrant ssh-config` above.
fab2 -e -H vagrant@localhost:2222 -i .vagrant/machines/default/virtualbox/private_key bootstrap-all

View file

@ -0,0 +1,27 @@
# -*- mode: ruby; -*-
Vagrant.configure("2") do |config|
# live machine runs Debian 10 Buster
config.vm.box = "debian/buster64"
# live machine runs Ubuntu 20.04 Focal Fossa
#config.vm.box = "ubuntu/focal64"
# this may be necessary for big data import tasks. you can raise or lower
# it, or comment out if you find that you don't need it
config.vm.provider "virtualbox" do |v|
v.memory = 4096
end
# Theo app
config.vm.network "forwarded_port", guest: 7000, host: 7000
# Theo (stage) app
config.vm.network "forwarded_port", guest: 7010, host: 7010
# # apache
# config.vm.network "forwarded_port", guest: 80, host: 7080
# config.vm.network "forwarded_port", guest: 443, host: 7443
end

View file

@ -0,0 +1,13 @@
## -*- mode: conf; -*-
[catapult-default]
host = ${env.catapult_host}
port = 2638
tds version = 5.0
# this is to allow for product images up to 8MB
text size = 8388608
# [catapult-tj-default]
# host = ${env.catapult_host}
# port = 2641
# tds version = 5.0

View file

@ -0,0 +1,12 @@
[catapult-default]
Description = ECRS Catapult
Driver = /usr/local/lib/libtdsodbc.so
ServerName = catapult-default
ServerDSN = prototype
# [catapult-tj-default]
# Description = ECRS Catapult Transaction Journal
# Driver = /usr/local/lib/libtdsodbc.so
# ServerName = catapult-tj-default
# ServerDSN = tj

View file

@ -0,0 +1,103 @@
## -*- mode: conf; -*-
######################################################################
#
# machine-wide rattail config
#
######################################################################
##############################
# rattail
##############################
[rattail]
timezone.default = ${env.timezone}
[rattail.config]
configure_logging = true
[rattail.mail]
smtp.server = localhost
templates = rattail:templates/mail
default.from = ${env.email_default_sender}
default.to = ${', '.join(env.email_default_recipients)}
[rattail.pod]
pictures.gtin.root_url = https://rattailproject.org/pod/pictures/gtin
##############################
# logging
##############################
[loggers]
keys = root, exc_logger, beaker, txn, sqlalchemy, django_db, flufl_bounce, requests
[handlers]
keys = file, console, email
[formatters]
keys = generic, console
[logger_root]
handlers = file, console
level = DEBUG
[logger_exc_logger]
qualname = exc_logger
handlers = email
level = ERROR
[logger_beaker]
qualname = beaker
handlers =
level = INFO
[logger_txn]
qualname = txn
handlers =
level = INFO
[logger_sqlalchemy]
qualname = sqlalchemy.engine
handlers =
# level = INFO
[logger_django_db]
qualname = django.db.backends
handlers =
level = INFO
[logger_flufl_bounce]
qualname = flufl.bounce
handlers =
level = WARNING
[logger_requests]
qualname = requests
handlers =
# level = WARNING
[handler_file]
class = handlers.WatchedFileHandler
args = ('rattail.log', 'a', 'utf_8')
formatter = generic
[handler_console]
class = StreamHandler
args = (sys.stderr,)
formatter = console
[handler_email]
class = handlers.SMTPHandler
args = ('localhost', '${env.email_default_sender}', ${env.email_default_recipients}, "[Rattail] Logging")
formatter = generic
level = ERROR
[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(funcName)s: %(message)s
datefmt = %Y-%m-%d %H:%M:%S
[formatter_console]
format = %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s

View file

@ -0,0 +1,26 @@
## -*- mode: conf; -*-
<%text>############################################################</%text>
#
# cron config for Theo
#
<%text>############################################################</%text>
<%text>####################</%text>
# rattail
<%text>####################</%text>
[rattail.config]
include = %(here)s/rattail.conf
<%text>####################</%text>
# logging
<%text>####################</%text>
[handler_console]
level = WARNING
[handler_file]
args = ('${envroot}/app/log/cron.log', 'a', 'utf_8')

View file

@ -0,0 +1,11 @@
## -*- mode: conf; -*-
<%text>############################################################</%text>
#
# cron schedule for ${envname}
#
<%text>############################################################</%text>
# overnight automation starts at ${pretty_time}
${'' if env.machine_is_live else '# '}${cron_time} * * * rattail ${envroot}/app/overnight.sh

View file

@ -0,0 +1,17 @@
#!/bin/sh -e
# sanity check
if [ "$USER" != 'rattail' ]; then
echo ''
echo "Please run this script as 'rattail' user:"
echo ''
echo " sudo -u rattail $0"
exit 1
fi
cd ${envroot}
RATTAIL='bin/rattail -c app/quiet.conf -P'
$RATTAIL import-catapult --no-versioning --warnings
$RATTAIL import-versions --runas catapult --warnings -m "initial data from Catapult"

View file

@ -0,0 +1,17 @@
#!/bin/sh -e
# sanity check
if [ "$USER" != 'rattail' ]; then
echo ''
echo "Please run this script as 'rattail' user:"
echo ''
echo " sudo -u rattail $0"
exit 1
fi
cd ${envroot}
RATTAIL='bin/rattail -c app/quiet.conf -P'
$RATTAIL import-corepos-api --no-versioning --warnings
$RATTAIL import-versions --runas corepos --warnings -m "initial data from CORE-POS"

View file

@ -0,0 +1,21 @@
## -*- mode: conf; -*-
${envroot}/pip.log {
compress
create 600 rattail rattail
delaycompress
missingok
notifempty
rotate 10
size 10M
}
${envroot}/app/log/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 600 rattail rattail
}

View file

@ -0,0 +1,34 @@
#!/bin/sh -e
<%text>############################################################</%text>
#
# overnight automation for Theo
#
<%text>############################################################</%text>
if [ "$1" = "--verbose" ]; then
VERBOSE='--verbose'
PROGRESS='--progress'
else
VERBOSE=
PROGRESS=
fi
cd ${envroot}
RATTAIL="bin/rattail --config=app/cron.conf $PROGRESS"
<%text>##############################</%text>
# sync data
<%text>##############################</%text>
% if env.theo_integrates_with == 'corepos':
# CORE-POS -> Theo
$RATTAIL --runas corepos import-corepos-api --delete
% elif env.theo_integrates_with == 'catapult':
# Catapult -> Theo
$RATTAIL --runas catapult import-catapult --delete
% endif
# make sure version data is correct
$RATTAIL --runas theo import-versions --delete --dry-run --warnings

View file

@ -0,0 +1,10 @@
## -*- mode: conf; -*-
[global]
extra-index-url =
https://pypi.rattailproject.org/simple/
% if env.theo_integrates_with == 'catapult':
https://${env.restricted_pypi_username}:${env.restricted_pypi_password}@pypi-restricted.rattailproject.org/catapult/
% endif
log-file = ${envroot}/pip.log
exists-action = i

View file

@ -0,0 +1,106 @@
## -*- mode: conf; -*-
<%text>############################################################</%text>
#
# core config for Theo
#
<%text>############################################################</%text>
[theo]
% if env.theo_integrates_with == 'corepos':
integrate_corepos = true
% elif env.theo_integrates_with == 'catapult':
integrate_catapult = true
% endif
## begin corepos
% if env.theo_integrates_with == 'corepos':
<%text>##############################</%text>
# CORE-POS
<%text>##############################</%text>
[corepos]
office.url = ${env.corepos_office_url}
[corepos.api]
url = ${env.corepos_api_url}
[corepos.db.office_op]
default.url = mysql+mysqlconnector://${env.corepos_db_username}:${env.corepos_db_password}@${env.corepos_db_host}/${env.corepos_db_name_office_op}
default.pool_recycle = 3600
## end corepos
% endif
## begin catapult
% if env.theo_integrates_with == 'catapult':
<%text>##############################</%text>
# Catapult
<%text>##############################</%text>
[catapult.db]
default.url = catapult://${env.catapult_odbc_username}:${env.catapult_odbc_password}@catapult-default
## end catapult
% endif
<%text>##############################</%text>
# rattail
<%text>##############################</%text>
[rattail]
production = ${'true' if production else 'false'}
appdir = ${envroot}/app
datadir = ${envroot}/app/data
batch.files = ${envroot}/app/batch
workdir = ${envroot}/app/work
runas.default = theo
[rattail.config]
include = /etc/rattail/rattail.conf
usedb = true
preferdb = true
[rattail.db]
default.url = postgresql://rattail:${env.password_postgresql_rattail}@localhost/${dbname}
versioning.enabled = true
[rattail.mail]
send_emails = true
default.prefix = [Theo]
[rattail.upgrades]
command = sudo ${envroot}/app/upgrade-wrapper.sh --verbose
files = ${envroot}/app/data/upgrades
<%text>##############################</%text>
# alembic
<%text>##############################</%text>
[alembic]
script_location = rattail.db:alembic
% if env.theo_integrates_with == 'corepos':
version_locations = rattail_corepos.db:alembic/versions rattail.db:alembic/versions
% elif env.theo_integrates_with == 'catapult':
version_locations = rattail_onager.db:alembic/versions rattail.db:alembic/versions
% else:
version_locations = rattail.db:alembic/versions
% endif
<%text>##############################</%text>
# logging
<%text>##############################</%text>
[handler_file]
args = ('${envroot}/app/log/rattail.log', 'a', 'utf_8')
[handler_email]
args = ('localhost', '${env.email_default_sender}', ${env.email_default_recipients}, "[Theo${'' if production else ' (stage)'}] Logging")

View file

@ -0,0 +1,4 @@
## -*- mode: conf; -*-
# let rattail upgrade ${envname} app
rattail ALL = NOPASSWD: ${envroot}/app/upgrade-wrapper.sh --verbose

View file

@ -0,0 +1,9 @@
## -*- mode: conf; -*-
[group:${safename}]
programs=${safename}_webmain
[program:${safename}_webmain]
command=${envroot}/bin/pserve pastedeploy+ini:${envroot}/app/web.conf
directory=${envroot}/app/work
user=rattail

View file

@ -0,0 +1,9 @@
## -*- coding: utf-8; mode: python; -*-
# -*- coding: utf-8; -*-
from invoke import task
@task
def upgrade(ctx):
ctx.run('${envroot}/app/upgrade.sh --verbose')

View file

@ -0,0 +1,19 @@
#!/bin/sh -e
if [ "$1" = "--verbose" ]; then
VERBOSE='--verbose'
INVOKE_ARGS='--echo'
else
VERBOSE=
INVOKE_ARGS=
fi
cd ${envroot}
INVOKE="sudo -H -u rattail bin/invoke --collection=app/tasks $INVOKE_ARGS"
# run upgrade task, as rattail user
$INVOKE upgrade
# restart web app
sh -c 'sleep 10; supervisorctl restart ${safename}:${safename}_webmain' &

View file

@ -0,0 +1,105 @@
#!/bin/sh -e
# NOTE: this script is meant to be ran by the 'rattail' user!
if [ "$1" = "--verbose" ]; then
VERBOSE='--verbose'
QUIET=
else
VERBOSE=
QUIET='--quiet'
fi
% if not production:
SRC=${envroot}/src
% endif
PIP=${envroot}/bin/pip
export PIP_CONFIG_FILE=${envroot}/pip.conf
# upgrade pip
$PIP install $QUIET --disable-pip-version-check --upgrade pip wheel
% if not production:
# now we fetch latest source code and install any "new" dependencies...
# rattail
cd $SRC/rattail
git pull $QUIET
find . -name '*.pyc' -delete
$PIP install $QUIET --editable .
# tailbone
cd $SRC/tailbone
git pull $QUIET
find . -name '*.pyc' -delete
$PIP install $QUIET --editable .
## begin corepos
% if env.theo_integrates_with == 'corepos':
# pycorepos
cd $SRC/pycorepos
git pull $QUIET
find . -name '*.pyc' -delete
$PIP install $QUIET --editable .
# rattail-corepos
cd $SRC/rattail-corepos
git pull $QUIET
find . -name '*.pyc' -delete
$PIP install $QUIET --editable .
# tailbone-corepos
cd $SRC/tailbone-corepos
git pull $QUIET
find . -name '*.pyc' -delete
$PIP install $QUIET --editable .
## end corepos
% endif
## begin catapult
% if env.theo_integrates_with == 'catapult':
# onager
cd $SRC/onager
git pull $QUIET
find . -name '*.pyc' -delete
$PIP install $QUIET --editable .
# rattail-onager
cd $SRC/rattail-onager
git pull $QUIET
find . -name '*.pyc' -delete
$PIP install $QUIET --editable .
# tailbone-onager
cd $SRC/tailbone-onager
git pull $QUIET
find . -name '*.pyc' -delete
$PIP install $QUIET --editable .
## end catapult
% endif
# theo
cd $SRC/theo
git pull $QUIET
find . -name '*.pyc' -delete
$PIP install $QUIET --editable .
## end !production
% endif
# now upgrade *all* dependencies
% if env.theo_integrates_with == 'corepos':
$PIP install $QUIET --upgrade --upgrade-strategy eager tailbone-theo[app,corepos]
% elif env.theo_integrates_with == 'catapult':
$PIP install $QUIET --upgrade --upgrade-strategy eager tailbone-theo[app,catapult]
% else:
$PIP install $QUIET --upgrade --upgrade-strategy eager tailbone-theo[app]
% endif
# migrate database schema
cd ${envroot}
bin/alembic --config app/rattail.conf upgrade heads

View file

@ -0,0 +1,66 @@
## -*- mode: conf; -*-
<%text>############################################################</%text>
#
# config for Theo web app
#
<%text>############################################################</%text>
<%text>###############################</%text>
# rattail
<%text>###############################</%text>
[rattail.config]
include = %(here)s/rattail.conf
<%text>###############################</%text>
# pyramid
<%text>###############################</%text>
[app:main]
use = egg:Tailbone_Theo
pyramid.reload_templates = false
pyramid.debug_all = false
pyramid.default_locale_name = en
pyramid.includes = pyramid_exclog
beaker.session.type = file
beaker.session.data_dir = %(here)s/sessions/data
beaker.session.lock_dir = %(here)s/sessions/lock
beaker.session.secret = ${env.theo_beaker_secret}
beaker.session.key = ${dbname}
exclog.extra_info = true
# required for tailbone
rattail.config = %(__file__)s
[server:main]
use = egg:waitress#main
host = 0.0.0.0
port = ${port}
# NOTE: this is needed for local reverse proxy stuff to work with HTTPS
# https://docs.pylonsproject.org/projects/waitress/en/latest/reverse-proxy.html
# https://docs.pylonsproject.org/projects/waitress/en/latest/arguments.html
trusted_proxy = 127.0.0.1
# TODO: leave this empty if proxy serves as root site, e.g. http://rattail.example.com/
url_prefix =
# TODO: or, if proxy serves as subpath of root site, e.g. http://rattail.example.com/backend/
# url_prefix = /backend
<%text>###############################</%text>
# logging
<%text>###############################</%text>
[handler_console]
level = INFO
[handler_file]
args = ('${envroot}/app/log/web.log', 'a', 'utf_8')

View file

@ -0,0 +1,93 @@
# -*- coding: utf-8; mode: python; -*-
"""
Fabric environment tweaks
"""
from fabfile import env
##############################
# volatile
##############################
# this should be True only when targeting the truly *live* machine, but False
# otherwise, e.g. while building a new "live" machine, or using Vagrant. it
# determines whether certain features are enabled, which only make sense for a
# truly live machine, e.g. overnight cron jobs, or writing to the POS.
env.machine_is_live = False
##############################
# stable
##############################
# for a list of possible time zone values, see
# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List
env.timezone = 'America/Chicago'
# set this to the POS system you wish to integrate with, if any
env.theo_integrates_with = None
#env.theo_integrates_with = 'corepos'
#env.theo_integrates_with = 'catapult'
# default admin user credentials for Theo web app
env.theo_admin_username = 'username'
env.theo_admin_password = 'password'
# default sender and recipients for all emails
env.email_default_sender = 'rattail@localhost'
env.email_default_recipients = ['root@localhost']
# this is for the 'rattail' user within PostgreSQL
env.password_postgresql_rattail = 'password'
# this is used to secure the user session and/or cookie for the web app
env.theo_beaker_secret = 'ABCDEFGHIJKLMNOPQRST'
##############################
# restricted software
##############################
# these credentials are used to access the "restricted" Rattail Project PyPI
# (https://pypi-restricted.rattailproject.org/). they are only needed if you
# are integrating with a proprietary POS system, and installing released
# packages instead of running from source; i.e. a typical production setup.
env.restricted_pypi_username = 'username'
env.restricted_pypi_password = 'password'
# these credentials are used to access the Rattail Project source code on
# Kallithea (https://kallithea.rattailproject.org/). they are only needed if
# you are integrating with a proprietary POS system, and running from source
# instead of released packages; i.e. a typical stage setup.
env.kallithea_username = 'username'
env.kallithea_password = 'password'
##############################
# CORE-POS
##############################
# URL of CORE Office (Fannie) website
env.corepos_office_url = 'http://localhost/'
# URL of CORE Office API
env.corepos_api_url = 'http://localhost/ws/'
# MySQL info for CORE operational DB
env.corepos_db_host = 'localhost'
env.corepos_db_username = 'username'
env.corepos_db_password = 'password'
env.corepos_db_name_office_op = 'core_op'
##############################
# ECRS Catapult
##############################
# this is the hostname for your Catapult WebOffice
env.catapult_host = 'INSTANCE.catapultweboffice.com'
# these credentials are used to access the ODBC DSN for ECRS Catapult
env.catapult_odbc_username = 'username'
env.catapult_odbc_password = 'password'

281
machines/theo-server/fabfile.py vendored Normal file
View file

@ -0,0 +1,281 @@
# -*- coding: utf-8; -*-
"""
Fabric script for a server running Theo, the order system
Please see the accompanying README for full instructions.
"""
import datetime
from fabric2 import task
from rattail.core import Object
from rattail_fabric2 import make_deploy, apt, postfix, postgresql, exists, make_system_user, mkdir
env = Object()
deploy = make_deploy(__file__)
##############################
# bootstrap
##############################
@task
def bootstrap_all(c):
"""
Bootstrap all aspects of the machine
"""
bootstrap_base(c)
bootstrap_theo(c)
bootstrap_theo_stage(c)
@task
def bootstrap_base(c):
"""
Bootstrap the base system
"""
# we do `apt update && apt dist-upgrade` every time this task runs
apt.dist_upgrade(c)
# we assume postfix is installed, but the configuration thereof is not
# dealt with here; you may need to configure further on your own
postfix.install(c)
# rattail user + common config
make_system_user(c, 'rattail', home='/var/lib/rattail', shell='/bin/bash')
postfix.alias(c, 'rattail', 'root')
mkdir(c, '/etc/rattail', use_sudo=True)
deploy(c, 'rattail/rattail.conf.mako', '/etc/rattail/rattail.conf',
use_sudo=True, context={'env': env})
# postgresql
postgresql.install(c)
postgresql.create_user(c, 'rattail', password=env.password_postgresql_rattail)
# python
mkdir(c, '/srv/envs', use_sudo=True, owner='rattail:')
apt.install(
c,
'build-essential',
'git',
'libpq-dev',
'python3-dev',
'python3-venv',
'supervisor',
)
# catapult extras
if env.theo_integrates_with == 'catapult':
# freetds / odbc
apt.install(c, 'unixodbc', 'unixodbc-dev')
# we must install FreeTDS from source, b/c the version APT makes available
# is too old. however the *latest* source seems to have some issue(s)
# which cause it to use too much memory, so we use a more stable branch
from rattail_fabric2 import freetds
freetds.install_from_source(c, user='rattail', branch='Branch-1_2')
deploy(c, 'rattail/freetds.conf.mako', '/usr/local/etc/freetds.conf',
use_sudo=True, context={'env': env})
deploy(c, 'rattail/odbc.ini', '/etc/odbc.ini', use_sudo=True)
@task
def bootstrap_theo(c):
"""
Bootstrap Theo, the order system
"""
install_theo_app(c, 'theo', True, 7000,
# overnight runs at 1:00am
run_overnight_at=datetime.time(1))
@task
def bootstrap_theo_stage(c):
"""
Bootstrap "stage" for Theo, the order system
"""
install_theo_app(c, 'theo-stage', False, 7010, from_source=True,
# overnight runs at 12:30am
run_overnight_at=datetime.time(0, 30))
##############################
# support functions
##############################
def install_theo_app(c, envname, production, port, from_source=False,
run_overnight_at=None):
"""
Install a Theo app, per the given parameters
"""
dbname = envname
safename = envname.replace('-', '_')
envroot = '/srv/envs/{}'.format(envname)
c.sudo('supervisorctl stop {}:'.format(safename), warn=True)
# virtualenv
if not exists(c, envroot):
c.sudo('python3 -m venv {}'.format(envroot), user='rattail')
c.sudo('{}/bin/pip install --upgrade pip wheel'.format(envroot), user='rattail')
deploy(c, 'theo-common/pip.conf.mako', '{}/pip.conf'.format(envroot),
use_sudo=True, owner='rattail:', mode='0600',
context={'env': env, 'envroot': envroot})
c.sudo('touch {}/pip.log'.format(envroot), user='rattail')
c.sudo('chmod 0600 {}/pip.log'.format(envroot))
# theo
if from_source:
install_theo_source(c, envroot)
# always install theo package by name, even if running from source
if env.theo_integrates_with == 'corepos':
pkgname = 'tailbone-theo[app,corepos]'
elif env.theo_integrates_with == 'catapult':
pkgname = 'tailbone-theo[app,catapult]'
else:
pkgname = 'tailbone-theo[app]'
c.sudo("bash -c 'PIP_CONFIG_FILE={0}/pip.conf cd {0} && bin/pip install {1}'".format(envroot, pkgname),
user='rattail')
# app dir
if not exists(c, '{}/app'.format(envroot)):
c.sudo("bash -c 'cd {} && bin/rattail make-appdir'".format(envroot),
user='rattail')
c.sudo('chmod 0750 {}/app/log'.format(envroot))
# config
deploy(c, 'theo-common/rattail.conf.mako', '{}/app/rattail.conf'.format(envroot),
use_sudo=True, owner='rattail:', mode='0600',
context={'env': env, 'envroot': envroot, 'dbname': dbname, 'production': production})
if not exists(c, '{}/app/quiet.conf'.format(envroot)):
c.sudo("bash -c 'cd {} && bin/rattail make-config -T quiet -O app/'".format(envroot),
user='rattail')
deploy(c, 'theo-common/web.conf.mako', '{}/app/web.conf'.format(envroot),
use_sudo=True, owner='rattail:', mode='0600',
context={'env': env, 'envroot': envroot, 'dbname': dbname, 'port': port})
deploy(c, 'theo-common/cron.conf.mako', '{}/app/cron.conf'.format(envroot),
use_sudo=True, owner='rattail:',
context={'envroot': envroot})
# scripts
deploy(c, 'theo-common/upgrade.sh.mako', '{}/app/upgrade.sh'.format(envroot),
use_sudo=True, owner='rattail:', mode='0755',
context={'env': env, 'envroot': envroot, 'production': production})
deploy(c, 'theo-common/tasks.py.mako', '{}/app/tasks.py'.format(envroot),
use_sudo=True, owner='rattail:',
context={'envroot': envroot})
deploy(c, 'theo-common/upgrade-wrapper.sh.mako', '{}/app/upgrade-wrapper.sh'.format(envroot),
use_sudo=True, owner='rattail:', mode='0755',
context={'envroot': envroot, 'safename': safename})
deploy(c, 'theo-common/overnight.sh.mako', '{}/app/overnight.sh'.format(envroot),
use_sudo=True, owner='rattail:', mode='0755',
context={'env': env, 'envroot': envroot})
if env.theo_integrates_with == 'corepos':
deploy(c, 'theo-common/import-corepos-first.sh.mako', '{}/app/import-corepos-first.sh'.format(envroot),
use_sudo=True, owner='rattail:', mode='0755',
context={'envroot': envroot})
elif env.theo_integrates_with == 'catapult':
deploy(c, 'theo-common/import-catapult-first.sh.mako', '{}/app/import-catapult-first.sh'.format(envroot),
use_sudo=True, owner='rattail:', mode='0755',
context={'envroot': envroot})
# theo db
if not postgresql.db_exists(c, dbname):
postgresql.create_db(c, dbname, owner='rattail', checkfirst=False)
c.sudo("bash -c 'cd {} && bin/alembic -c app/rattail.conf upgrade heads'".format(envroot),
user='rattail')
# misc. default settings
postgresql.sql(c, "insert into setting values ('tailbone.theme', 'falafel')",
database=dbname)
postgresql.sql(c, "insert into setting values ('tailbone.themes.expose_picker', 'false')",
database=dbname)
postgresql.sql(c, "insert into setting values ('tailbone.global_help_url', 'https://rattailproject.org/moin/Documentation')",
database=dbname)
# theo user
c.sudo("bash -c 'cd {} && bin/rattail -c app/quiet.conf --no-versioning make-user theo --no-password'".format(envroot),
user='rattail')
c.sudo("bash -c 'cd {} && bin/rattail -c app/quiet.conf --runas theo import-versions User'".format(envroot),
user='rattail')
# admin user
c.sudo("bash -c 'cd {} && bin/rattail -c app/quiet.conf --runas theo make-user --admin {} --password {}'".format(
envroot, env.theo_admin_username, env.theo_admin_password),
user='rattail', echo=False)
# integration users
if env.theo_integrates_with == 'corepos':
c.sudo("bash -c 'cd {} && bin/rattail -c app/quiet.conf --runas theo make-user --no-password corepos'".format(envroot),
user='rattail')
elif env.theo_integrates_with == 'catapult':
c.sudo("bash -c 'cd {} && bin/rattail -c app/quiet.conf --runas theo make-user --no-password catapult'".format(envroot),
user='rattail')
# supervisor
deploy(c, 'theo-common/supervisor.conf.mako', '/etc/supervisor/conf.d/{}.conf'.format(safename),
use_sudo=True, context={'envroot': envroot, 'safename': safename})
c.sudo('supervisorctl update')
c.sudo('supervisorctl start {}:'.format(safename))
# sudoers, crontab, logrotate
deploy.sudoers(c, 'theo-common/sudoers.mako', '/etc/sudoers.d/{}'.format(safename),
context={'envname': envname, 'envroot': envroot})
deploy(c, 'theo-common/crontab.mako', '/etc/cron.d/{}'.format(safename),
use_sudo=True,
context={'env': env, 'envname': envname, 'envroot': envroot,
'pretty_time': run_overnight_at.strftime('%I:%M %p'),
'cron_time': run_overnight_at.strftime('%M %H')})
deploy(c, 'theo-common/logrotate.conf.mako', '/etc/logrotate.d/{}'.format(safename),
use_sudo=True, context={'envroot': envroot})
def install_theo_source(c, envroot):
"""
Install source code for Theo
"""
# rattail
install_source_package(c, envroot, 'rattail')
install_source_package(c, envroot, 'tailbone')
# corepos
if env.theo_integrates_with == 'corepos':
install_source_package(c, envroot, 'pycorepos')
install_source_package(c, envroot, 'rattail-corepos')
install_source_package(c, envroot, 'tailbone-corepos')
# catapult
if env.theo_integrates_with == 'catapult':
install_source_package(c, envroot, 'onager', restricted=True)
install_source_package(c, envroot, 'rattail-onager', restricted=True)
install_source_package(c, envroot, 'tailbone-onager', restricted=True)
# theo
install_source_package(c, envroot, 'theo')
def install_source_package(c, envroot, name, restricted=False):
if not exists(c, '{}/src/{}'.format(envroot, name)):
if restricted:
c.sudo('git clone https://{0}:{1}@kallithea.rattailproject.org/rattail-restricted/{2} {3}/src/{2}'.format(
env.kallithea_username, env.kallithea_password, name, envroot),
user='rattail', echo=False)
else:
c.sudo('git clone https://kallithea.rattailproject.org/rattail-project/{0} {1}/src/{0}'.format(name, envroot),
user='rattail')
c.sudo("bash -c 'PIP_CONFIG_FILE={0}/pip.conf cd {0} && bin/pip install -e src/{1}'".format(envroot, name),
user='rattail')
##############################
# fabenv
##############################
try:
import fabenv
except ImportError as error:
print("\ncouldn't import fabenv: {}".format(error))
env.setdefault('machine_is_live', False)

View file

@ -0,0 +1,3 @@
# -*- mode: yaml; -*-
sudo:
password: "XXXXXXXX"