Add Travis-CI integration.

The only way to test travis is to deploy to master with a `.travis.yml` file and wait for travis-ci to pick up the change.  To do some pre-testing here, the `Vagrantfile` has been split into two distinct machines:

 * `default` is, as before, the full reddit build (we have an opportunity to rename this)
 * `travis` is a minimal install with only the packages and services required to run `nosetests` against the codebase.  It tries to mimic what will happen when we try to build this on travis-ci's workers.

As part of this addition, I've moved `install-reddit.sh` to `install/reddit.sh` and populated that `install` folder with common scripts used for both `default` and `travis` builds.
This commit is contained in:
Chris Slowe
2016-01-14 15:50:02 -08:00
parent 817c1c668a
commit 69698a9d12
15 changed files with 1441 additions and 1001 deletions

26
.travis.yml Normal file
View File

@@ -0,0 +1,26 @@
sudo: required
dist: trusty
language: python
python:
- "2.7"
virtualenv:
system_site_packages: true
services:
- postgres
- memcached
- rabbitmq
install:
- sudo install/travis.sh travis .
before_script:
- install/setup_rabbitmq.sh
- install/setup_postgres.sh
- install/setup_cassandra.sh
script:
- cd r2 && nosetests

140
Vagrantfile vendored
View File

@@ -25,6 +25,14 @@
# each plugin directory is that "reddit-plugin-NAME" should be in the directory
# {ROOTDIR}/NAME.
#
# This VagrantFile allows for the creation of two VMs:
# * default: the primary VM, with all services necessary to run reddit
# locally against the local codebase.
# * travis: Testing-only VM suitable for running `nosetests` and debugging
# issues encountered without having to wait for travis-ci to pick
# up the build. This will *not* be the same environment as
# travis, but it should be useful for repairing broken tests.
#
# To start your vagrant box simply enter `vagrant up` from {ROOTDIR}/reddit.
# You can then ssh into it with `vagrant ssh`.
#
@@ -49,7 +57,7 @@ overlay_mount = "/home/#{vagrant_user}/src"
overlay_lower = code_share_guest_path
overlay_upper = "/home/#{vagrant_user}/.overlay"
# vm config
# "default" vm config
guest_ip = "192.168.56.111"
guest_mem = "4096"
guest_swap = "4096"
@@ -62,11 +70,6 @@ Vagrant.configure(2) do |config|
config.vm.box_download_checksum = "0975e1a73226563ec7791c9b2fd114a57e918e401f82f4778a44e43040e39609"
config.vm.box_download_checksum_type = "sha256"
config.vm.hostname = hostname
# host-only network interface
config.vm.network "private_network", ip: guest_ip
# mount the host shared folder
config.vm.synced_folder code_share_host_path, code_share_guest_path, mount_options: ["ro"]
@@ -88,7 +91,7 @@ Vagrant.configure(2) do |config|
fi
SCRIPT
# setup the overlay filesystem
# set up the overlay filesystem
config.vm.provision "shell", inline: <<-SCRIPT
if [ ! -d #{overlay_mount} ]; then
echo "creating overlay mount directory #{overlay_mount}"
@@ -104,49 +107,90 @@ Vagrant.configure(2) do |config|
mount -t overlayfs overlayfs -o lowerdir=#{overlay_lower},upperdir=#{overlay_upper} #{overlay_mount}
SCRIPT
# run install script
plugin_string = plugins.join(" ")
config.vm.provision "shell", inline: <<-SCRIPT
if [ ! -f /var/local/reddit_installed ]; then
echo "running install script"
cd /home/#{vagrant_user}/src/reddit
REDDIT_PLUGINS="#{plugin_string}" REDDIT_DOMAIN="#{hostname}" ./install-reddit.sh
touch /var/local/reddit_installed
else
echo "install script already run"
fi
SCRIPT
# setup private code
if File.exist?("#{code_share_host_path}/private/vagrant_setup.sh")
config.vm.provision "shell",
path: "#{code_share_host_path}/private/vagrant_setup.sh",
args: [vagrant_user]
# NOTE: This VM exists solely to assist in writing tests. It does not actually
# install travis but rather builds a minimal vm with only the services
# available under a travis build to aid in test debugging (via `nosetests`)
# To use:
# $ vagrant up travis
# $ vagrant ssh travis
# vagrant@travis$ cd src/reddit/r2 && nosetests
config.vm.define "travis", autostart: false do |travis|
travis.vm.hostname = "travis"
# run install script
plugin_string = plugins.join(" ")
travis.vm.provision "shell", inline: <<-SCRIPT
if [ ! -f /var/local/reddit_installed ]; then
echo "running install script"
cd /home/#{vagrant_user}/src/reddit
./install/travis.sh vagrant
touch /var/local/reddit_installed
else
echo "install script already run"
fi
SCRIPT
end
# inject test data
config.vm.provision "shell", inline: <<-SCRIPT
if [ ! -f /var/local/test_data_injected ]; then
cd /home/#{vagrant_user}/src/reddit
sudo -u #{vagrant_user} reddit-run scripts/inject_test_data.py -c 'inject_test_data()'
touch /var/local/test_data_injected
else
echo "inject test data already run"
fi
# NB: this is the primary VM. To build run
# $ vagrant up
# [though 'vagrant up default' will also work, the 'default' is redudnant]
# Once built, avahi-daemon should guarantee the instance will be accessible
# from https://reddit.local/
config.vm.define "default", primary: true do |redditlocal|
redditlocal.vm.hostname = hostname
# host-only network interface
redditlocal.vm.network "private_network", ip: guest_ip
# HACK: stop and start everything (otherwise sometimes there's an issue with
# ports being in use?)
reddit-stop
reddit-start
SCRIPT
# run install script
plugin_string = plugins.join(" ")
redditlocal.vm.provision "shell", inline: <<-SCRIPT
if [ ! -f /var/local/reddit_installed ]; then
echo "running install script"
cd /home/#{vagrant_user}/src/reddit
REDDIT_PLUGINS="#{plugin_string}" REDDIT_DOMAIN="#{hostname}" ./install/reddit.sh
touch /var/local/reddit_installed
else
echo "install script already run"
fi
SCRIPT
# additional setup
config.vm.provision "shell", inline: <<-SCRIPT
if [ ! -f /var/local/additional_setup ]; then
apt-get install -y ipython avahi-daemon
touch /var/local/additional_setup
else
echo "additional setup already run"
fi
SCRIPT
# set up private code
if File.exist?("#{code_share_host_path}/private/vagrant_setup.sh")
redditlocal.vm.provision "shell",
path: "#{code_share_host_path}/private/vagrant_setup.sh",
args: [vagrant_user]
end
# inject test data
redditlocal.vm.provision "shell", inline: <<-SCRIPT
if [ ! -f /var/local/test_data_injected ]; then
cd /home/#{vagrant_user}/src/reddit
sudo -u #{vagrant_user} reddit-run scripts/inject_test_data.py -c 'inject_test_data()'
touch /var/local/test_data_injected
else
echo "inject test data already run"
fi
# HACK: stop and start everything (otherwise sometimes there's an issue with
# ports being in use?)
reddit-stop
reddit-start
SCRIPT
# additional setup
redditlocal.vm.provision "shell", inline: <<-SCRIPT
if [ ! -f /var/local/additional_setup ]; then
apt-get install -y ipython avahi-daemon
touch /var/local/additional_setup
else
echo "additional setup already run"
fi
SCRIPT
# DONE: let this run whenever provision is run so that the user can see
# how to proceed.
redditlocal.vm.provision "shell", inline: <<-SCRIPT
cd /home/#{vagrant_user}/src/reddit
REDDIT_DOMAIN="#{hostname}" ./install/done.sh
SCRIPT
end
end

View File

@@ -1,905 +0,0 @@
#!/bin/bash
# The contents of this file are subject to the Common Public Attribution
# License Version 1.0. (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
# License Version 1.1, but Sections 14 and 15 have been added to cover use of
# software over a computer network and provide for limited attribution for the
# Original Developer. In addition, Exhibit A has been modified to be consistent
# with Exhibit B.
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
# the specific language governing rights and limitations under the License.
#
# The Original Code is reddit.
#
# The Original Developer is the Initial Developer. The Initial Developer of
# the Original Code is reddit Inc.
#
# All portions of the code written by reddit are Copyright (c) 2006-2015 reddit
# Inc. All Rights Reserved.
###############################################################################
###############################################################################
# reddit dev environment installer
# --------------------------------
# This script installs a reddit stack suitable for development. DO NOT run this
# on a system that you use for other purposes as it might delete important
# files, truncate your databases, and otherwise do mean things to you.
#
# By default, this script will install the reddit code in the current user's
# home directory and all of its dependencies (including libraries and database
# servers) at the system level. The installed reddit will expect to be visited
# on the domain "reddit.local" unless specified otherwise. Configuring name
# resolution for the domain is expected to be done outside the installed
# environment (e.g. in your host machine's /etc/hosts file) and is not
# something this script handles.
#
# Several configuration options (listed in the "Configuration" section below)
# are overridable with environment variables. e.g.
#
# sudo REDDIT_DOMAIN=example.com ./install-reddit.sh
#
###############################################################################
set -e
###############################################################################
# Configuration
###############################################################################
# which user to install the code for; defaults to the user invoking this script
REDDIT_USER=${REDDIT_USER:-$SUDO_USER}
# the group to run reddit code as; must exist already
REDDIT_GROUP=${REDDIT_GROUP:-nogroup}
# the root directory to base the install in. must exist already
REDDIT_HOME=${REDDIT_HOME:-/home/$REDDIT_USER}
# the domain that you will connect to your reddit install with.
# MUST contain a . in it somewhere as browsers won't do cookies for dotless
# domains. an IP address will suffice if nothing else is available.
REDDIT_DOMAIN=${REDDIT_DOMAIN:-reddit.local}
#The plugins to clone and register in the ini file
REDDIT_PLUGINS=${REDDIT_PLUGINS:-meatspace about liveupdate}
###############################################################################
# Sanity Checks
###############################################################################
if [[ $EUID -ne 0 ]]; then
echo "ERROR: Must be run with root privileges."
exit 1
fi
if [[ -z "$REDDIT_USER" ]]; then
# in a production install, you'd want the code to be owned by root and run
# by a less privileged user. this script is intended to build a development
# install, so we expect the owner to run the app and not be root.
cat <<END
ERROR: You have not specified a user. This usually means you're running this
script directly as root. It is not recommended to run reddit as the root user.
Please create a user to run reddit and set the REDDIT_USER variable
appropriately.
END
exit 1
fi
if [[ "amd64" != $(dpkg --print-architecture) ]]; then
cat <<END
ERROR: This host is running the $(dpkg --print-architecture) architecture!
Because of the pre-built dependencies in our PPA, and some extra picky things
like ID generation in liveupdate, installing reddit is only supported on amd64
architectures.
END
exit 1
fi
# seriously! these checks are here for a reason. the packages from the
# reddit ppa aren't built for anything but trusty (14.04) right now, so
# if you try and use this install script on another release you're gonna
# have a bad time.
source /etc/lsb-release
if [ "$DISTRIB_ID" != "Ubuntu" -o "$DISTRIB_RELEASE" != "14.04" ]; then
echo "ERROR: Only Ubuntu 14.04 is supported."
exit 1
fi
if [[ "2000000" -gt $(awk '/MemTotal/{print $2}' /proc/meminfo) ]]; then
LOW_MEM_PROMPT="reddit requires at least 2GB of memory to work properly, continue anyway? [y/n] "
read -er -n1 -p "$LOW_MEM_PROMPT" response
if [[ "$response" != "y" ]]; then
echo "Quitting."
exit 1
fi
fi
###############################################################################
# Install prerequisites
###############################################################################
set -x
# aptitude configuration
APTITUDE_OPTIONS="-y"
export DEBIAN_FRONTEND=noninteractive
# run an aptitude update to make sure python-software-properties
# dependencies are found
apt-get update
# add the reddit ppa for some custom packages
apt-get install $APTITUDE_OPTIONS python-software-properties
apt-add-repository -y ppa:reddit/ppa
# pin the ppa -- packages present in the ppa will take precedence over
# ones in other repositories (unless further pinning is done)
cat <<HERE > /etc/apt/preferences.d/reddit
Package: *
Pin: release o=LP-PPA-reddit
Pin-Priority: 600
HERE
# add the datastax cassandra repos
echo deb http://debian.datastax.com/community stable main > /etc/apt/sources.list.d/cassandra.sources.list
wget -qO- -L https://debian.datastax.com/debian/repo_key | sudo apt-key add -
# grab the new ppas' package listings
apt-get update
# install prerequisites
cat <<PACKAGES | xargs apt-get install $APTITUDE_OPTIONS
netcat-openbsd
git-core
python-dev
python-setuptools
python-routes
python-pylons
python-boto
python-tz
python-crypto
python-babel
cython
python-sqlalchemy
python-beautifulsoup
python-chardet
python-psycopg2
python-pycassa
python-imaging
python-pycaptcha
python-amqplib
python-pylibmc=1.2.2-1~trusty5
python-bcrypt
python-snudown
python-l2cs
python-lxml
python-kazoo
python-stripe
python-tinycss2
python-unidecode
python-mock
python-yaml
python-baseplate
python-flask
geoip-bin
geoip-database
python-geoip
nodejs
node-less
node-uglify
gettext
make
optipng
jpegoptim
mcrouter
memcached
postgresql
postgresql-client
rabbitmq-server
cassandra=1.2.19
haproxy
nginx
gunicorn
sutro
libpcre3-dev
PACKAGES
# we don't want to upgrade to C* 2.0 yet, so we'll put it on hold
apt-mark hold cassandra
###############################################################################
# Wait for all the services to be up
###############################################################################
# cassandra doesn't auto-start after install
service cassandra start
# check each port for connectivity
echo "Waiting for services to be available, see source for port meanings..."
# 11211 - memcache
# 5432 - postgres
# 5672 - rabbitmq
# 9160 - cassandra
for port in 11211 5432 5672 9160; do
while ! nc -vz localhost $port; do
sleep 1
done
done
###############################################################################
# Install the reddit source repositories
###############################################################################
if [ ! -d $REDDIT_HOME/src ]; then
mkdir -p $REDDIT_HOME/src
chown $REDDIT_USER $REDDIT_HOME/src
fi
function clone_reddit_repo {
local destination=$REDDIT_HOME/src/${1}
local repository_url=https://github.com/${2}.git
if [ ! -d $destination ]; then
sudo -u $REDDIT_USER -H git clone $repository_url $destination
fi
if [ -d $destination/upstart ]; then
cp $destination/upstart/* /etc/init/
fi
}
function clone_reddit_plugin_repo {
clone_reddit_repo $1 reddit/reddit-plugin-$1
}
clone_reddit_repo reddit reddit/reddit
clone_reddit_repo i18n reddit/reddit-i18n
for plugin in $REDDIT_PLUGINS; do
clone_reddit_plugin_repo $plugin
done
###############################################################################
# Configure Cassandra
###############################################################################
python <<END
import pycassa
sys = pycassa.SystemManager("localhost:9160")
if "reddit" not in sys.list_keyspaces():
print "creating keyspace 'reddit'"
sys.create_keyspace("reddit", "SimpleStrategy", {"replication_factor": "1"})
print "done"
if "permacache" not in sys.get_keyspace_column_families("reddit"):
print "creating column family 'permacache'"
sys.create_column_family("reddit", "permacache")
print "done"
END
###############################################################################
# Configure PostgreSQL
###############################################################################
SQL="SELECT COUNT(1) FROM pg_catalog.pg_database WHERE datname = 'reddit';"
IS_DATABASE_CREATED=$(sudo -u postgres psql -t -c "$SQL")
if [ $IS_DATABASE_CREATED -ne 1 ]; then
cat <<PGSCRIPT | sudo -u postgres psql
CREATE DATABASE reddit WITH ENCODING = 'utf8' TEMPLATE template0 LC_COLLATE='en_US.utf8' LC_CTYPE='en_US.utf8';
CREATE USER reddit WITH PASSWORD 'password';
PGSCRIPT
fi
sudo -u postgres psql reddit < $REDDIT_HOME/src/reddit/sql/functions.sql
###############################################################################
# Configure mcrouter
###############################################################################
if [ ! -d /etc/mcrouter ]; then
mkdir -p /etc/mcrouter
fi
if [ ! -f /etc/mcrouter/global.conf ]; then
cat > /etc/mcrouter/global.conf <<MCROUTER
{
// route all valid prefixes to the local memcached
"pools": {
"local": {
"servers": [
"127.0.0.1:11211",
],
"protocol": "ascii",
"keep_routing_prefix": false,
},
},
"route": {
"type": "PrefixSelectorRoute",
"policies": {
"rend:": {
"type": "PoolRoute",
"pool": "local",
},
"page:": {
"type": "PoolRoute",
"pool": "local",
},
"pane:": {
"type": "PoolRoute",
"pool": "local",
},
},
"wildcard": {
"type": "NullRoute",
},
},
}
MCROUTER
fi
###############################################################################
# Configure RabbitMQ
###############################################################################
if ! rabbitmqctl list_vhosts | egrep "^/$"
then
rabbitmqctl add_vhost /
fi
if ! rabbitmqctl list_users | egrep "^reddit"
then
rabbitmqctl add_user reddit reddit
fi
rabbitmqctl set_permissions -p / reddit ".*" ".*" ".*"
###############################################################################
# Install and configure the reddit code
###############################################################################
function install_reddit_repo {
cd $REDDIT_HOME/src/$1
sudo -u $REDDIT_USER python setup.py build
python setup.py develop --no-deps
}
install_reddit_repo reddit/r2
install_reddit_repo i18n
for plugin in $REDDIT_PLUGINS; do
install_reddit_repo $plugin
done
# generate binary translation files from source
cd $REDDIT_HOME/src/i18n/
sudo -u $REDDIT_USER make clean all
# this builds static files and should be run *after* languages are installed
# so that the proper language-specific static files can be generated and after
# plugins are installed so all the static files are available.
cd $REDDIT_HOME/src/reddit/r2
sudo -u $REDDIT_USER make clean all
plugin_str=$(echo -n "$REDDIT_PLUGINS" | tr " " ,)
if [ ! -f development.update ]; then
cat > development.update <<DEVELOPMENT
# after editing this file, run "make ini" to
# generate a new development.ini
[DEFAULT]
# global debug flag -- displays pylons stacktrace rather than 500 page on error when true
# WARNING: a pylons stacktrace allows remote code execution. Make sure this is false
# if your server is publicly accessible.
debug = true
disable_ads = true
disable_captcha = true
disable_ratelimit = true
disable_require_admin_otp = true
page_cache_time = 0
domain = $REDDIT_DOMAIN
oauth_domain = $REDDIT_DOMAIN
plugins = $plugin_str
media_provider = filesystem
media_fs_root = /srv/www/media
media_fs_base_url_http = http://%(domain)s/media/
[server:main]
port = 8001
DEVELOPMENT
chown $REDDIT_USER development.update
else
sed -i "s/^plugins = .*$/plugins = $plugin_str/" $REDDIT_HOME/src/reddit/r2/development.update
sed -i "s/^domain = .*$/domain = $REDDIT_DOMAIN/" $REDDIT_HOME/src/reddit/r2/development.update
sed -i "s/^oauth_domain = .*$/oauth_domain = $REDDIT_DOMAIN/" $REDDIT_HOME/src/reddit/r2/development.update
fi
sudo -u $REDDIT_USER make ini
if [ ! -L run.ini ]; then
sudo -u $REDDIT_USER ln -nsf development.ini run.ini
fi
###############################################################################
# some useful helper scripts
###############################################################################
function helper-script() {
cat > $1
chmod 755 $1
}
helper-script /usr/local/bin/reddit-run <<REDDITRUN
#!/bin/bash
exec paster --plugin=r2 run $REDDIT_HOME/src/reddit/r2/run.ini "\$@"
REDDITRUN
helper-script /usr/local/bin/reddit-shell <<REDDITSHELL
#!/bin/bash
exec paster --plugin=r2 shell $REDDIT_HOME/src/reddit/r2/run.ini
REDDITSHELL
helper-script /usr/local/bin/reddit-start <<REDDITSTART
#!/bin/bash
initctl emit reddit-start
REDDITSTART
helper-script /usr/local/bin/reddit-stop <<REDDITSTOP
#!/bin/bash
initctl emit reddit-stop
REDDITSTOP
helper-script /usr/local/bin/reddit-restart <<REDDITRESTART
#!/bin/bash
initctl emit reddit-restart TARGET=${1:-all}
REDDITRESTART
helper-script /usr/local/bin/reddit-flush <<REDDITFLUSH
#!/bin/bash
echo flush_all | nc localhost 11211
REDDITFLUSH
###############################################################################
# pixel and click server
###############################################################################
mkdir -p /var/opt/reddit/
chown $REDDIT_USER:$REDDIT_GROUP /var/opt/reddit/
mkdir -p /srv/www/pixel
chown $REDDIT_USER:$REDDIT_GROUP /srv/www/pixel
cp $REDDIT_HOME/src/reddit/r2/r2/public/static/pixel.png /srv/www/pixel
if [ ! -f /etc/gunicorn.d/click.conf ]; then
cat > /etc/gunicorn.d/click.conf <<CLICK
CONFIG = {
"mode": "wsgi",
"working_dir": "$REDDIT_HOME/src/reddit/scripts",
"user": "$REDDIT_USER",
"group": "$REDDIT_USER",
"args": (
"--bind=unix:/var/opt/reddit/click.sock",
"--workers=1",
"tracker:application",
),
}
CLICK
fi
service gunicorn start
###############################################################################
# nginx
###############################################################################
mkdir -p /srv/www/media
chown $REDDIT_USER:$REDDIT_GROUP /srv/www/media
cat > /etc/nginx/sites-available/reddit-media <<MEDIA
server {
listen 9000;
expires max;
location /media/ {
alias /srv/www/media/;
}
}
MEDIA
cat > /etc/nginx/sites-available/reddit-pixel <<PIXEL
upstream click_server {
server unix:/var/opt/reddit/click.sock fail_timeout=0;
}
server {
listen 8082;
log_format directlog '\$remote_addr - \$remote_user [\$time_local] '
'"\$request_method \$request_uri \$server_protocol" \$status \$body_bytes_sent '
'"\$http_referer" "\$http_user_agent"';
access_log /var/log/nginx/traffic/traffic.log directlog;
location / {
rewrite ^/pixel/of_ /pixel.png;
add_header Last-Modified "";
add_header Pragma "no-cache";
expires -1;
root /srv/www/pixel/;
}
location /click {
proxy_pass http://click_server;
}
}
PIXEL
cat > /etc/nginx/sites-available/reddit-ssl <<SSL
map \$http_upgrade \$connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443;
ssl on;
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:1m;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host \$http_host;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For \$remote_addr;
proxy_pass_header Server;
# allow websockets through if desired
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection \$connection_upgrade;
}
}
SSL
# remove the default nginx site that may conflict with haproxy
rm -rf /etc/nginx/sites-enabled/default
# put our config in place
ln -nsf /etc/nginx/sites-available/reddit-media /etc/nginx/sites-enabled/
ln -nsf /etc/nginx/sites-available/reddit-pixel /etc/nginx/sites-enabled/
ln -nsf /etc/nginx/sites-available/reddit-ssl /etc/nginx/sites-enabled/
# make the pixel log directory
mkdir -p /var/log/nginx/traffic
# link the ini file for the Flask click tracker
ln -nsf $REDDIT_HOME/src/reddit/r2/development.ini $REDDIT_HOME/src/reddit/scripts/production.ini
service nginx restart
###############################################################################
# haproxy
###############################################################################
if [ -e /etc/haproxy/haproxy.cfg ]; then
BACKUP_HAPROXY=$(mktemp /etc/haproxy/haproxy.cfg.XXX)
echo "Backing up /etc/haproxy/haproxy.cfg to $BACKUP_HAPROXY"
cat /etc/haproxy/haproxy.cfg > $BACKUP_HAPROXY
fi
# make sure haproxy is enabled
cat > /etc/default/haproxy <<DEFAULT
ENABLED=1
DEFAULT
# configure haproxy
cat > /etc/haproxy/haproxy.cfg <<HAPROXY
global
maxconn 350
frontend frontend
mode http
bind 0.0.0.0:80
bind 127.0.0.1:8080
timeout client 24h
option forwardfor except 127.0.0.1
option httpclose
# make sure that requests have x-forwarded-proto: https iff tls
reqidel ^X-Forwarded-Proto:.*
acl is-ssl dst_port 8080
reqadd X-Forwarded-Proto:\ https if is-ssl
# send websockets to sutro
acl is-websocket hdr(Upgrade) -i WebSocket
use_backend sutro if is-websocket
# send media stuff to the local nginx
acl is-media path_beg /media/
use_backend media if is-media
# send pixel stuff to local nginx
acl is-pixel path_beg /pixel/
acl is-click path_beg /click
use_backend pixel if is-pixel || is-click
default_backend reddit
backend reddit
mode http
timeout connect 4000
timeout server 30000
timeout queue 60000
balance roundrobin
server app01-8001 localhost:8001 maxconn 30
backend sutro
mode http
timeout connect 4s
timeout server 24h
balance roundrobin
server sutro localhost:8002 maxconn 250
backend media
mode http
timeout connect 4000
timeout server 30000
timeout queue 60000
balance roundrobin
server nginx localhost:9000 maxconn 20
backend pixel
mode http
timeout connect 4000
timeout server 30000
timeout queue 60000
balance roundrobin
server nginx localhost:8082 maxconn 20
HAPROXY
# this will start it even if currently stopped
service haproxy restart
###############################################################################
# sutro (websocket server)
###############################################################################
if [ ! -f /etc/sutro.ini ]; then
cat > /etc/sutro.ini <<SUTRO
[app:main]
paste.app_factory = sutro.app:make_app
amqp.host = localhost
amqp.port = 5672
amqp.vhost = /
amqp.username = reddit
amqp.password = reddit
web.allowed_origins = $REDDIT_DOMAIN
web.mac_secret = YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5
web.ping_interval = 300
stats.host =
stats.port = 0
[server:main]
use = egg:gunicorn#main
worker_class = sutro.socketserver.SutroWorker
workers = 1
worker_connections = 250
host = 127.0.0.1
port = 8002
graceful_timeout = 5
forward_allow_ips = 127.0.0.1
[loggers]
keys = root
[handlers]
keys = syslog
[formatters]
keys = generic
[logger_root]
level = INFO
handlers = syslog
[handler_syslog]
class = handlers.SysLogHandler
args = ("/dev/log", "local7")
formatter = generic
level = NOTSET
[formatter_generic]
format = [%(name)s] %(message)s
SUTRO
fi
if [ ! -f /etc/init/sutro.conf ]; then
cat > /etc/init/sutro.conf << UPSTART_SUTRO
description "sutro websocket server"
stop on runlevel [!2345]
start on runlevel [2345]
respawn
respawn limit 10 5
kill timeout 15
limit nofile 65535 65535
exec gunicorn_paster /etc/sutro.ini
UPSTART_SUTRO
fi
service sutro restart
###############################################################################
# geoip service
###############################################################################
if [ ! -f /etc/gunicorn.d/geoip.conf ]; then
cat > /etc/gunicorn.d/geoip.conf <<GEOIP
CONFIG = {
"mode": "wsgi",
"working_dir": "$REDDIT_HOME/src/reddit/scripts",
"user": "$REDDIT_USER",
"group": "$REDDIT_USER",
"args": (
"--bind=127.0.0.1:5000",
"--workers=1",
"--limit-request-line=8190",
"geoip_service:application",
),
}
GEOIP
fi
service gunicorn start
###############################################################################
# Job Environment
###############################################################################
CONSUMER_CONFIG_ROOT=$REDDIT_HOME/consumer-count.d
if [ ! -f /etc/default/reddit ]; then
cat > /etc/default/reddit <<DEFAULT
export REDDIT_ROOT=$REDDIT_HOME/src/reddit/r2
export REDDIT_INI=$REDDIT_HOME/src/reddit/r2/run.ini
export REDDIT_USER=$REDDIT_USER
export REDDIT_GROUP=$REDDIT_GROUP
export REDDIT_CONSUMER_CONFIG=$CONSUMER_CONFIG_ROOT
alias wrap-job=$REDDIT_HOME/src/reddit/scripts/wrap-job
alias manage-consumers=$REDDIT_HOME/src/reddit/scripts/manage-consumers
DEFAULT
fi
###############################################################################
# Queue Processors
###############################################################################
mkdir -p $CONSUMER_CONFIG_ROOT
function set_consumer_count {
if [ ! -f $CONSUMER_CONFIG_ROOT/$1 ]; then
echo $2 > $CONSUMER_CONFIG_ROOT/$1
fi
}
set_consumer_count log_q 0
set_consumer_count search_q 0
set_consumer_count del_account_q 1
set_consumer_count scraper_q 1
set_consumer_count markread_q 1
set_consumer_count commentstree_q 1
set_consumer_count newcomments_q 1
set_consumer_count vote_link_q 1
set_consumer_count vote_comment_q 1
set_consumer_count automoderator_q 0
chown -R $REDDIT_USER:$REDDIT_GROUP $CONSUMER_CONFIG_ROOT/
###############################################################################
# Start everything up
###############################################################################
# the initial database setup should be done by one process rather than a bunch
# vying with eachother to get there first
reddit-run -c 'print "ok done"'
# ok, now start everything else up
initctl emit reddit-stop
initctl emit reddit-start
###############################################################################
# Cron Jobs
###############################################################################
if [ ! -f /etc/cron.d/reddit ]; then
cat > /etc/cron.d/reddit <<CRON
0 3 * * * root /sbin/start --quiet reddit-job-update_sr_names
30 16 * * * root /sbin/start --quiet reddit-job-update_reddits
0 * * * * root /sbin/start --quiet reddit-job-update_promos
*/5 * * * * root /sbin/start --quiet reddit-job-clean_up_hardcache
*/2 * * * * root /sbin/start --quiet reddit-job-broken_things
*/2 * * * * root /sbin/start --quiet reddit-job-rising
0 * * * * root /sbin/start --quiet reddit-job-trylater
# liveupdate
* * * * * root /sbin/start --quiet reddit-job-liveupdate_activity
# jobs that recalculate time-limited listings (e.g. top this year)
PGPASSWORD=password
*/15 * * * * $REDDIT_USER $REDDIT_HOME/src/reddit/scripts/compute_time_listings link year '("hour", "day", "week", "month", "year")'
*/15 * * * * $REDDIT_USER $REDDIT_HOME/src/reddit/scripts/compute_time_listings comment year '("hour", "day", "week", "month", "year")'
# disabled by default, uncomment if you need these jobs
#* * * * * root /sbin/start --quiet reddit-job-email
#0 0 * * * root /sbin/start --quiet reddit-job-update_gold_users
CRON
fi
###############################################################################
# All done!
###############################################################################
cd $REDDIT_HOME
cat <<CONCLUSION
Congratulations! reddit is now installed.
The reddit application code is managed with upstart, to see what's currently
running, run
sudo initctl list | grep reddit
Cron jobs start with "reddit-job-" and queue processors start with
"reddit-consumer-". The crons are managed by /etc/cron.d/reddit. You can
initiate a restart of all the consumers by running:
sudo reddit-restart
or target specific ones:
sudo reddit-restart scraper_q
See the GitHub wiki for more information on these jobs:
* https://github.com/reddit/reddit/wiki/Cron-jobs
* https://github.com/reddit/reddit/wiki/Services
The reddit code can be shut down or started up with
sudo reddit-stop
sudo reddit-start
And if you think caching might be hurting you, you can flush memcache with
reddit-flush
Now that the core of reddit is installed, you may want to do some additional
steps:
* Ensure that $REDDIT_DOMAIN resolves to this machine.
* To populate the database with test data, run:
cd $REDDIT_HOME/src/reddit
reddit-run scripts/inject_test_data.py -c 'inject_test_data()'
* Manually run reddit-job-update_reddits immediately after populating the db
or adding your own subreddits.
CONCLUSION

1
install-reddit.sh Symbolic link
View File

@@ -0,0 +1 @@
install/reddit.sh

76
install/done.sh Executable file
View File

@@ -0,0 +1,76 @@
#!/bin/bash
# The contents of this file are subject to the Common Public Attribution
# License Version 1.0. (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
# License Version 1.1, but Sections 14 and 15 have been added to cover use of
# software over a computer network and provide for limited attribution for the
# Original Developer. In addition, Exhibit A has been modified to be consistent
# with Exhibit B.
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
# the specific language governing rights and limitations under the License.
#
# The Original Code is reddit.
#
# The Original Developer is the Initial Developer. The Initial Developer of
# the Original Code is reddit Inc.
#
# All portions of the code written by reddit are Copyright (c) 2006-2015 reddit
# Inc. All Rights Reserved.
###############################################################################
# load configuration
RUNDIR=$(dirname $0)
source $RUNDIR/install.cfg
###############################################################################
# All done!
###############################################################################
cat <<CONCLUSION
Congratulations! reddit is now installed.
The reddit application code is managed with upstart, to see what's currently
running, run
sudo initctl list | grep reddit
Cron jobs start with "reddit-job-" and queue processors start with
"reddit-consumer-". The crons are managed by /etc/cron.d/reddit. You can
initiate a restart of all the consumers by running:
sudo reddit-restart
or target specific ones:
sudo reddit-restart scraper_q
See the GitHub wiki for more information on these jobs:
* https://github.com/reddit/reddit/wiki/Cron-jobs
* https://github.com/reddit/reddit/wiki/Services
The reddit code can be shut down or started up with
sudo reddit-stop
sudo reddit-start
And if you think caching might be hurting you, you can flush memcache with
reddit-flush
Now that the core of reddit is installed, you may want to do some additional
steps:
* Ensure that $REDDIT_DOMAIN resolves to this machine.
* To populate the database with test data, run:
cd $REDDIT_SRC/reddit
reddit-run scripts/inject_test_data.py -c 'inject_test_data()'
* Manually run reddit-job-update_reddits immediately after populating the db
or adding your own subreddits.
CONCLUSION

52
install/install.cfg Normal file
View File

@@ -0,0 +1,52 @@
#!/bin/bash
# The contents of this file are subject to the Common Public Attribution
# License Version 1.0. (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
# License Version 1.1, but Sections 14 and 15 have been added to cover use of
# software over a computer network and provide for limited attribution for the
# Original Developer. In addition, Exhibit A has been modified to be consistent
# with Exhibit B.
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
# the specific language governing rights and limitations under the License.
#
# The Original Code is reddit.
#
# The Original Developer is the Initial Developer. The Initial Developer of
# the Original Code is reddit Inc.
#
# All portions of the code written by reddit are Copyright (c) 2006-2015 reddit
# Inc. All Rights Reserved.
###############################################################################
set -e -x
###############################################################################
# Configuration
###############################################################################
# which user to install the code for; defaults to the user invoking this script
REDDIT_USER=${REDDIT_USER:-$SUDO_USER}
# the group to run reddit code as; must exist already
REDDIT_GROUP=${REDDIT_GROUP:-nogroup}
# the root directory to base the install in. must exist already
REDDIT_HOME=${REDDIT_HOME:-/home/$REDDIT_USER}
REDDIT_SRC=${REDDIT_SRC:-$REDDIT_HOME/src}
# the domain that you will connect to your reddit install with.
# MUST contain a . in it somewhere as browsers won't do cookies for dotless
# domains. an IP address will suffice if nothing else is available.
REDDIT_DOMAIN=${REDDIT_DOMAIN:-reddit.local}
#The plugins to clone and register in the ini file
REDDIT_PLUGINS=${REDDIT_PLUGINS:-meatspace about liveupdate}
# aptitude configuration
APTITUDE_OPTIONS=${APTITUDE_OPTIONS:-"-y"}
# Custom datastax repo
CASSANDRA_SOURCES_LIST=/etc/apt/sources.list.d/cassandra.sources.list
export DEBIAN_FRONTEND=noninteractive

112
install/install_apt.sh Executable file
View File

@@ -0,0 +1,112 @@
#!/bin/bash
# The contents of this file are subject to the Common Public Attribution
# License Version 1.0. (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
# License Version 1.1, but Sections 14 and 15 have been added to cover use of
# software over a computer network and provide for limited attribution for the
# Original Developer. In addition, Exhibit A has been modified to be consistent
# with Exhibit B.
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
# the specific language governing rights and limitations under the License.
#
# The Original Code is reddit.
#
# The Original Developer is the Initial Developer. The Initial Developer of
# the Original Code is reddit Inc.
#
# All portions of the code written by reddit are Copyright (c) 2006-2015 reddit
# Inc. All Rights Reserved.
###############################################################################
# load configuration
RUNDIR=$(dirname $0)
source $RUNDIR/install.cfg
# run an aptitude update to make sure python-software-properties
# dependencies are found
apt-get update
# add the datastax cassandra repos (NB: this is required for
# install_cassandra.sh to work correctly, and the non-existence of this
# file will trigger install_cassandra.sh to rerun this script)
echo deb http://debian.datastax.com/community stable main | \
sudo tee $CASSANDRA_SOURCES_LIST
wget -qO- -L https://debian.datastax.com/debian/repo_key | \
sudo apt-key add -
# add the reddit ppa for some custom packages
apt-get install $APTITUDE_OPTIONS python-software-properties
apt-add-repository -y ppa:reddit/ppa
# pin the ppa -- packages present in the ppa will take precedence over
# ones in other repositories (unless further pinning is done)
cat <<HERE > /etc/apt/preferences.d/reddit
Package: *
Pin: release o=LP-PPA-reddit
Pin-Priority: 600
HERE
# grab the new ppas' package listings
apt-get update
# travis gives us a stock libmemcached. We have to remove that
apt-get remove $APTITUDE_OPTIONS $(dpkg-query -W -f='${binary:Package}\n' | grep libmemcached | tr '\n' ' ')
apt-get autoremove $APTITUDE_OPTIONS
# install prerequisites
cat <<PACKAGES | xargs apt-get install $APTITUDE_OPTIONS
netcat-openbsd
git-core
python-dev
python-setuptools
python-routes
python-pylons
python-boto
python-tz
python-crypto
python-babel
python-numpy
python-dateutil
cython
python-sqlalchemy
python-beautifulsoup
python-chardet
python-psycopg2
python-pycassa
python-imaging
python-pycaptcha
python-pylibmc=1.2.2-1~trusty5
python-amqplib
python-bcrypt
python-snudown
python-l2cs
python-lxml
python-kazoo
python-stripe
python-tinycss2
python-unidecode
python-mock
python-yaml
python-baseplate
python-flask
geoip-bin
geoip-database
python-geoip
nodejs
node-less
node-uglify
gettext
make
optipng
jpegoptim
libpcre3-dev
PACKAGES

46
install/install_cassandra.sh Executable file
View File

@@ -0,0 +1,46 @@
#!/bin/bash
# The contents of this file are subject to the Common Public Attribution
# License Version 1.0. (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
# License Version 1.1, but Sections 14 and 15 have been added to cover use of
# software over a computer network and provide for limited attribution for the
# Original Developer. In addition, Exhibit A has been modified to be consistent
# with Exhibit B.
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
# the specific language governing rights and limitations under the License.
#
# The Original Code is reddit.
#
# The Original Developer is the Initial Developer. The Initial Developer of
# the Original Code is reddit Inc.
#
# All portions of the code written by reddit are Copyright (c) 2006-2015 reddit
# Inc. All Rights Reserved.
###############################################################################
# load configuration
RUNDIR=$(dirname $0)
source $RUNDIR/install.cfg
if [ ! -e $CASSANDRA_SOURCES_LIST ]; then
echo "Cassandra repo not added. Running `install_apt.sh`"
$RUNDIR/install_apt.sh
fi
# install cassandra
sudo apt-get install $APTITUDE_OPTIONS cassandra=1.2.19
# we don't want to upgrade to C* 2.0 yet, so we'll put it on hold
apt-mark hold cassandra || true
# cassandra doesn't auto-start after install
sudo service cassandra start
# check each port for connectivity
echo "Waiting for cassandra to be available..."
while ! nc -vz localhost 9160; do
sleep 1
done

57
install/install_services.sh Executable file
View File

@@ -0,0 +1,57 @@
#!/bin/bash
# The contents of this file are subject to the Common Public Attribution
# License Version 1.0. (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
# License Version 1.1, but Sections 14 and 15 have been added to cover use of
# software over a computer network and provide for limited attribution for the
# Original Developer. In addition, Exhibit A has been modified to be consistent
# with Exhibit B.
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
# the specific language governing rights and limitations under the License.
#
# The Original Code is reddit.
#
# The Original Developer is the Initial Developer. The Initial Developer of
# the Original Code is reddit Inc.
#
# All portions of the code written by reddit are Copyright (c) 2006-2015 reddit
# Inc. All Rights Reserved.
###############################################################################
###############################################################################
# Install services
###############################################################################
# load configuration
RUNDIR=$(dirname $0)
source $RUNDIR/install.cfg
# install prerequisites
cat <<PACKAGES | xargs apt-get install $APTITUDE_OPTIONS
mcrouter
memcached
postgresql
postgresql-client
rabbitmq-server
haproxy
nginx
gunicorn
sutro
PACKAGES
###############################################################################
# Wait for all the services to be up
###############################################################################
# check each port for connectivity
echo "Waiting for services to be available, see source for port meanings..."
# 11211 - memcache
# 5432 - postgres
# 5672 - rabbitmq
for port in 11211 5432 5672; do
while ! nc -vz localhost $port; do
sleep 1
done
done

639
install/reddit.sh Executable file
View File

@@ -0,0 +1,639 @@
###############################################################################
# reddit dev environment installer
# --------------------------------
# This script installs a reddit stack suitable for development. DO NOT run this
# on a system that you use for other purposes as it might delete important
# files, truncate your databases, and otherwise do mean things to you.
#
# By default, this script will install the reddit code in the current user's
# home directory and all of its dependencies (including libraries and database
# servers) at the system level. The installed reddit will expect to be visited
# on the domain "reddit.local" unless specified otherwise. Configuring name
# resolution for the domain is expected to be done outside the installed
# environment (e.g. in your host machine's /etc/hosts file) and is not
# something this script handles.
#
# Several configuration options (listed in the "Configuration" section below)
# are overridable with environment variables. e.g.
#
# sudo REDDIT_DOMAIN=example.com ./install/reddit.sh
#
###############################################################################
# load configuration
RUNDIR=$(dirname $0)
source $RUNDIR/install.cfg
###############################################################################
# Sanity Checks
###############################################################################
if [[ $EUID -ne 0 ]]; then
echo "ERROR: Must be run with root privileges."
exit 1
fi
if [[ -z "$REDDIT_USER" ]]; then
# in a production install, you'd want the code to be owned by root and run
# by a less privileged user. this script is intended to build a development
# install, so we expect the owner to run the app and not be root.
cat <<END
ERROR: You have not specified a user. This usually means you're running this
script directly as root. It is not recommended to run reddit as the root user.
Please create a user to run reddit and set the REDDIT_USER variable
appropriately.
END
exit 1
fi
if [[ "amd64" != $(dpkg --print-architecture) ]]; then
cat <<END
ERROR: This host is running the $(dpkg --print-architecture) architecture!
Because of the pre-built dependencies in our PPA, and some extra picky things
like ID generation in liveupdate, installing reddit is only supported on amd64
architectures.
END
exit 1
fi
# seriously! these checks are here for a reason. the packages from the
# reddit ppa aren't built for anything but trusty (14.04) right now, so
# if you try and use this install script on another release you're gonna
# have a bad time.
source /etc/lsb-release
if [ "$DISTRIB_ID" != "Ubuntu" -o "$DISTRIB_RELEASE" != "14.04" ]; then
echo "ERROR: Only Ubuntu 14.04 is supported."
exit 1
fi
if [[ "2000000" -gt $(awk '/MemTotal/{print $2}' /proc/meminfo) ]]; then
LOW_MEM_PROMPT="reddit requires at least 2GB of memory to work properly, continue anyway? [y/n] "
read -er -n1 -p "$LOW_MEM_PROMPT" response
if [[ "$response" != "y" ]]; then
echo "Quitting."
exit 1
fi
fi
###############################################################################
# Install prerequisites
###############################################################################
# install primary packages
$RUNDIR/install_apt.sh
# install cassandra from datastax
$RUNDIR/install_cassandra.sh
# install services (rabbitmq, postgres, memcached, etc.)
$RUNDIR/install_services.sh
###############################################################################
# Install the reddit source repositories
###############################################################################
if [ ! -d $REDDIT_SRC ]; then
mkdir -p $REDDIT_SRC
chown $REDDIT_USER $REDDIT_SRC
fi
function clone_reddit_repo {
local destination=$REDDIT_SRC/${1}
local repository_url=https://github.com/${2}.git
if [ ! -d $destination ]; then
sudo -u $REDDIT_USER -H git clone $repository_url $destination
fi
if [ -d $destination/upstart ]; then
cp $destination/upstart/* /etc/init/
fi
}
function clone_reddit_plugin_repo {
clone_reddit_repo $1 reddit/reddit-plugin-$1
}
clone_reddit_repo reddit reddit/reddit
clone_reddit_repo i18n reddit/reddit-i18n
for plugin in $REDDIT_PLUGINS; do
clone_reddit_plugin_repo $plugin
done
###############################################################################
# Configure Services
###############################################################################
# Configure Cassandra
$RUNDIR/setup_cassandra.sh
# Configure PostgreSQL
$RUNDIR/setup_postgres.sh
# Configure mcrouter
$RUNDIR/setup_mcrouter.sh
# Configure RabbitMQ
$RUNDIR/setup_rabbitmq.sh
###############################################################################
# Install and configure the reddit code
###############################################################################
function install_reddit_repo {
cd $REDDIT_SRC/$1
sudo -u $REDDIT_USER python setup.py build
python setup.py develop --no-deps
}
install_reddit_repo reddit/r2
install_reddit_repo i18n
for plugin in $REDDIT_PLUGINS; do
install_reddit_repo $plugin
done
# generate binary translation files from source
cd $REDDIT_SRC/i18n/
sudo -u $REDDIT_USER make clean all
# this builds static files and should be run *after* languages are installed
# so that the proper language-specific static files can be generated and after
# plugins are installed so all the static files are available.
cd $REDDIT_SRC/reddit/r2
sudo -u $REDDIT_USER make clean all
plugin_str=$(echo -n "$REDDIT_PLUGINS" | tr " " ,)
if [ ! -f development.update ]; then
cat > development.update <<DEVELOPMENT
# after editing this file, run "make ini" to
# generate a new development.ini
[DEFAULT]
# global debug flag -- displays pylons stacktrace rather than 500 page on error when true
# WARNING: a pylons stacktrace allows remote code execution. Make sure this is false
# if your server is publicly accessible.
debug = true
disable_ads = true
disable_captcha = true
disable_ratelimit = true
disable_require_admin_otp = true
page_cache_time = 0
domain = $REDDIT_DOMAIN
oauth_domain = $REDDIT_DOMAIN
plugins = $plugin_str
media_provider = filesystem
media_fs_root = /srv/www/media
media_fs_base_url_http = http://%(domain)s/media/
[server:main]
port = 8001
DEVELOPMENT
chown $REDDIT_USER development.update
else
sed -i "s/^plugins = .*$/plugins = $plugin_str/" $REDDIT_SRC/reddit/r2/development.update
sed -i "s/^domain = .*$/domain = $REDDIT_DOMAIN/" $REDDIT_SRC/reddit/r2/development.update
sed -i "s/^oauth_domain = .*$/oauth_domain = $REDDIT_DOMAIN/" $REDDIT_SRC/reddit/r2/development.update
fi
sudo -u $REDDIT_USER make ini
if [ ! -L run.ini ]; then
sudo -u $REDDIT_USER ln -nsf development.ini run.ini
fi
###############################################################################
# some useful helper scripts
###############################################################################
function helper-script() {
cat > $1
chmod 755 $1
}
helper-script /usr/local/bin/reddit-run <<REDDITRUN
#!/bin/bash
exec paster --plugin=r2 run $REDDIT_SRC/reddit/r2/run.ini "\$@"
REDDITRUN
helper-script /usr/local/bin/reddit-shell <<REDDITSHELL
#!/bin/bash
exec paster --plugin=r2 shell $REDDIT_SRC/reddit/r2/run.ini
REDDITSHELL
helper-script /usr/local/bin/reddit-start <<REDDITSTART
#!/bin/bash
initctl emit reddit-start
REDDITSTART
helper-script /usr/local/bin/reddit-stop <<REDDITSTOP
#!/bin/bash
initctl emit reddit-stop
REDDITSTOP
helper-script /usr/local/bin/reddit-restart <<REDDITRESTART
#!/bin/bash
initctl emit reddit-restart TARGET=${1:-all}
REDDITRESTART
helper-script /usr/local/bin/reddit-flush <<REDDITFLUSH
#!/bin/bash
echo flush_all | nc localhost 11211
REDDITFLUSH
###############################################################################
# pixel and click server
###############################################################################
mkdir -p /var/opt/reddit/
chown $REDDIT_USER:$REDDIT_GROUP /var/opt/reddit/
mkdir -p /srv/www/pixel
chown $REDDIT_USER:$REDDIT_GROUP /srv/www/pixel
cp $REDDIT_SRC/reddit/r2/r2/public/static/pixel.png /srv/www/pixel
if [ ! -f /etc/gunicorn.d/click.conf ]; then
cat > /etc/gunicorn.d/click.conf <<CLICK
CONFIG = {
"mode": "wsgi",
"working_dir": "$REDDIT_SRC/reddit/scripts",
"user": "$REDDIT_USER",
"group": "$REDDIT_USER",
"args": (
"--bind=unix:/var/opt/reddit/click.sock",
"--workers=1",
"tracker:application",
),
}
CLICK
fi
service gunicorn start
###############################################################################
# nginx
###############################################################################
mkdir -p /srv/www/media
chown $REDDIT_USER:$REDDIT_GROUP /srv/www/media
cat > /etc/nginx/sites-available/reddit-media <<MEDIA
server {
listen 9000;
expires max;
location /media/ {
alias /srv/www/media/;
}
}
MEDIA
cat > /etc/nginx/sites-available/reddit-pixel <<PIXEL
upstream click_server {
server unix:/var/opt/reddit/click.sock fail_timeout=0;
}
server {
listen 8082;
log_format directlog '\$remote_addr - \$remote_user [\$time_local] '
'"\$request_method \$request_uri \$server_protocol" \$status \$body_bytes_sent '
'"\$http_referer" "\$http_user_agent"';
access_log /var/log/nginx/traffic/traffic.log directlog;
location / {
rewrite ^/pixel/of_ /pixel.png;
add_header Last-Modified "";
add_header Pragma "no-cache";
expires -1;
root /srv/www/pixel/;
}
location /click {
proxy_pass http://click_server;
}
}
PIXEL
cat > /etc/nginx/sites-available/reddit-ssl <<SSL
map \$http_upgrade \$connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443;
ssl on;
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:1m;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host \$http_host;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For \$remote_addr;
proxy_pass_header Server;
# allow websockets through if desired
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection \$connection_upgrade;
}
}
SSL
# remove the default nginx site that may conflict with haproxy
rm -rf /etc/nginx/sites-enabled/default
# put our config in place
ln -nsf /etc/nginx/sites-available/reddit-media /etc/nginx/sites-enabled/
ln -nsf /etc/nginx/sites-available/reddit-pixel /etc/nginx/sites-enabled/
ln -nsf /etc/nginx/sites-available/reddit-ssl /etc/nginx/sites-enabled/
# make the pixel log directory
mkdir -p /var/log/nginx/traffic
# link the ini file for the Flask click tracker
ln -nsf $REDDIT_SRC/reddit/r2/development.ini $REDDIT_SRC/reddit/scripts/production.ini
service nginx restart
###############################################################################
# haproxy
###############################################################################
if [ -e /etc/haproxy/haproxy.cfg ]; then
BACKUP_HAPROXY=$(mktemp /etc/haproxy/haproxy.cfg.XXX)
echo "Backing up /etc/haproxy/haproxy.cfg to $BACKUP_HAPROXY"
cat /etc/haproxy/haproxy.cfg > $BACKUP_HAPROXY
fi
# make sure haproxy is enabled
cat > /etc/default/haproxy <<DEFAULT
ENABLED=1
DEFAULT
# configure haproxy
cat > /etc/haproxy/haproxy.cfg <<HAPROXY
global
maxconn 350
frontend frontend
mode http
bind 0.0.0.0:80
bind 127.0.0.1:8080
timeout client 24h
option forwardfor except 127.0.0.1
option httpclose
# make sure that requests have x-forwarded-proto: https iff tls
reqidel ^X-Forwarded-Proto:.*
acl is-ssl dst_port 8080
reqadd X-Forwarded-Proto:\ https if is-ssl
# send websockets to sutro
acl is-websocket hdr(Upgrade) -i WebSocket
use_backend sutro if is-websocket
# send media stuff to the local nginx
acl is-media path_beg /media/
use_backend media if is-media
# send pixel stuff to local nginx
acl is-pixel path_beg /pixel/
acl is-click path_beg /click
use_backend pixel if is-pixel || is-click
default_backend reddit
backend reddit
mode http
timeout connect 4000
timeout server 30000
timeout queue 60000
balance roundrobin
server app01-8001 localhost:8001 maxconn 30
backend sutro
mode http
timeout connect 4s
timeout server 24h
balance roundrobin
server sutro localhost:8002 maxconn 250
backend media
mode http
timeout connect 4000
timeout server 30000
timeout queue 60000
balance roundrobin
server nginx localhost:9000 maxconn 20
backend pixel
mode http
timeout connect 4000
timeout server 30000
timeout queue 60000
balance roundrobin
server nginx localhost:8082 maxconn 20
HAPROXY
# this will start it even if currently stopped
service haproxy restart
###############################################################################
# sutro (websocket server)
###############################################################################
if [ ! -f /etc/sutro.ini ]; then
cat > /etc/sutro.ini <<SUTRO
[app:main]
paste.app_factory = sutro.app:make_app
amqp.host = localhost
amqp.port = 5672
amqp.vhost = /
amqp.username = reddit
amqp.password = reddit
web.allowed_origins = $REDDIT_DOMAIN
web.mac_secret = YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5
web.ping_interval = 300
stats.host =
stats.port = 0
[server:main]
use = egg:gunicorn#main
worker_class = sutro.socketserver.SutroWorker
workers = 1
worker_connections = 250
host = 127.0.0.1
port = 8002
graceful_timeout = 5
forward_allow_ips = 127.0.0.1
[loggers]
keys = root
[handlers]
keys = syslog
[formatters]
keys = generic
[logger_root]
level = INFO
handlers = syslog
[handler_syslog]
class = handlers.SysLogHandler
args = ("/dev/log", "local7")
formatter = generic
level = NOTSET
[formatter_generic]
format = [%(name)s] %(message)s
SUTRO
fi
if [ ! -f /etc/init/sutro.conf ]; then
cat > /etc/init/sutro.conf << UPSTART_SUTRO
description "sutro websocket server"
stop on runlevel [!2345]
start on runlevel [2345]
respawn
respawn limit 10 5
kill timeout 15
limit nofile 65535 65535
exec gunicorn_paster /etc/sutro.ini
UPSTART_SUTRO
fi
service sutro restart
###############################################################################
# geoip service
###############################################################################
if [ ! -f /etc/gunicorn.d/geoip.conf ]; then
cat > /etc/gunicorn.d/geoip.conf <<GEOIP
CONFIG = {
"mode": "wsgi",
"working_dir": "$REDDIT_SRC/reddit/scripts",
"user": "$REDDIT_USER",
"group": "$REDDIT_USER",
"args": (
"--bind=127.0.0.1:5000",
"--workers=1",
"--limit-request-line=8190",
"geoip_service:application",
),
}
GEOIP
fi
service gunicorn start
###############################################################################
# Job Environment
###############################################################################
CONSUMER_CONFIG_ROOT=$REDDIT_HOME/consumer-count.d
if [ ! -f /etc/default/reddit ]; then
cat > /etc/default/reddit <<DEFAULT
export REDDIT_ROOT=$REDDIT_SRC/reddit/r2
export REDDIT_INI=$REDDIT_SRC/reddit/r2/run.ini
export REDDIT_USER=$REDDIT_USER
export REDDIT_GROUP=$REDDIT_GROUP
export REDDIT_CONSUMER_CONFIG=$CONSUMER_CONFIG_ROOT
alias wrap-job=$REDDIT_SRC/reddit/scripts/wrap-job
alias manage-consumers=$REDDIT_SRC/reddit/scripts/manage-consumers
DEFAULT
fi
###############################################################################
# Queue Processors
###############################################################################
mkdir -p $CONSUMER_CONFIG_ROOT
function set_consumer_count {
if [ ! -f $CONSUMER_CONFIG_ROOT/$1 ]; then
echo $2 > $CONSUMER_CONFIG_ROOT/$1
fi
}
set_consumer_count log_q 0
set_consumer_count search_q 0
set_consumer_count del_account_q 1
set_consumer_count scraper_q 1
set_consumer_count markread_q 1
set_consumer_count commentstree_q 1
set_consumer_count notifications_q 1
set_consumer_count newcomments_q 1
set_consumer_count vote_link_q 1
set_consumer_count vote_comment_q 1
set_consumer_count automoderator_q 0
set_consumer_count butler_q 1
chown -R $REDDIT_USER:$REDDIT_GROUP $CONSUMER_CONFIG_ROOT/
###############################################################################
# Start everything up
###############################################################################
# the initial database setup should be done by one process rather than a bunch
# vying with eachother to get there first
reddit-run -c 'print "ok done"'
# ok, now start everything else up
initctl emit reddit-stop
initctl emit reddit-start
###############################################################################
# Cron Jobs
###############################################################################
if [ ! -f /etc/cron.d/reddit ]; then
cat > /etc/cron.d/reddit <<CRON
0 3 * * * root /sbin/start --quiet reddit-job-update_sr_names
30 16 * * * root /sbin/start --quiet reddit-job-update_reddits
0 * * * * root /sbin/start --quiet reddit-job-update_promos
*/5 * * * * root /sbin/start --quiet reddit-job-clean_up_hardcache
*/2 * * * * root /sbin/start --quiet reddit-job-broken_things
*/2 * * * * root /sbin/start --quiet reddit-job-rising
0 * * * * root /sbin/start --quiet reddit-job-trylater
# liveupdate
* * * * * root /sbin/start --quiet reddit-job-liveupdate_activity
# jobs that recalculate time-limited listings (e.g. top this year)
PGPASSWORD=password
*/15 * * * * $REDDIT_USER $REDDIT_SRC/reddit/scripts/compute_time_listings link year '("hour", "day", "week", "month", "year")'
*/15 * * * * $REDDIT_USER $REDDIT_SRC/reddit/scripts/compute_time_listings comment year '("hour", "day", "week", "month", "year")'
# disabled by default, uncomment if you need these jobs
#* * * * * root /sbin/start --quiet reddit-job-email
#0 0 * * * root /sbin/start --quiet reddit-job-update_gold_users
CRON
fi

40
install/setup_cassandra.sh Executable file
View File

@@ -0,0 +1,40 @@
#!/bin/bash
# The contents of this file are subject to the Common Public Attribution
# License Version 1.0. (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
# License Version 1.1, but Sections 14 and 15 have been added to cover use of
# software over a computer network and provide for limited attribution for the
# Original Developer. In addition, Exhibit A has been modified to be consistent
# with Exhibit B.
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
# the specific language governing rights and limitations under the License.
#
# The Original Code is reddit.
#
# The Original Developer is the Initial Developer. The Initial Developer of
# the Original Code is reddit Inc.
#
# All portions of the code written by reddit are Copyright (c) 2006-2015 reddit
# Inc. All Rights Reserved.
###############################################################################
###############################################################################
# Configure Cassandra
###############################################################################
python <<END
import pycassa
sys = pycassa.SystemManager("localhost:9160")
if "reddit" not in sys.list_keyspaces():
print "creating keyspace 'reddit'"
sys.create_keyspace("reddit", "SimpleStrategy", {"replication_factor": "1"})
print "done"
if "permacache" not in sys.get_keyspace_column_families("reddit"):
print "creating column family 'permacache'"
sys.create_column_family("reddit", "permacache")
print "done"
END

66
install/setup_mcrouter.sh Executable file
View File

@@ -0,0 +1,66 @@
#!/bin/bash
# The contents of this file are subject to the Common Public Attribution
# License Version 1.0. (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
# License Version 1.1, but Sections 14 and 15 have been added to cover use of
# software over a computer network and provide for limited attribution for the
# Original Developer. In addition, Exhibit A has been modified to be consistent
# with Exhibit B.
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
# the specific language governing rights and limitations under the License.
#
# The Original Code is reddit.
#
# The Original Developer is the Initial Developer. The Initial Developer of
# the Original Code is reddit Inc.
#
# All portions of the code written by reddit are Copyright (c) 2006-2015 reddit
# Inc. All Rights Reserved.
###############################################################################
###############################################################################
# Configure mcrouter
###############################################################################
if [ ! -d /etc/mcrouter ]; then
mkdir -p /etc/mcrouter
fi
if [ ! -f /etc/mcrouter/global.conf ]; then
cat > /etc/mcrouter/global.conf <<MCROUTER
{
// route all valid prefixes to the local memcached
"pools": {
"local": {
"servers": [
"127.0.0.1:11211",
],
"protocol": "ascii",
"keep_routing_prefix": false,
},
},
"route": {
"type": "PrefixSelectorRoute",
"policies": {
"rend:": {
"type": "PoolRoute",
"pool": "local",
},
"page:": {
"type": "PoolRoute",
"pool": "local",
},
"pane:": {
"type": "PoolRoute",
"pool": "local",
},
},
"wildcard": {
"type": "NullRoute",
},
},
}
MCROUTER
fi

68
install/setup_postgres.sh Executable file
View File

@@ -0,0 +1,68 @@
#!/bin/bash
# The contents of this file are subject to the Common Public Attribution
# License Version 1.0. (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
# License Version 1.1, but Sections 14 and 15 have been added to cover use of
# software over a computer network and provide for limited attribution for the
# Original Developer. In addition, Exhibit A has been modified to be consistent
# with Exhibit B.
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
# the specific language governing rights and limitations under the License.
#
# The Original Code is reddit.
#
# The Original Developer is the Initial Developer. The Initial Developer of
# the Original Code is reddit Inc.
#
# All portions of the code written by reddit are Copyright (c) 2006-2015 reddit
# Inc. All Rights Reserved.
###############################################################################
# load configuration
RUNDIR=$(dirname $0)
source $RUNDIR/install.cfg
###############################################################################
# Configure PostgreSQL
###############################################################################
SQL="SELECT COUNT(1) FROM pg_catalog.pg_database WHERE datname = 'reddit';"
IS_DATABASE_CREATED=$(sudo -u postgres psql -t -c "$SQL")
if [ $IS_DATABASE_CREATED -ne 1 ]; then
cat <<PGSCRIPT | sudo -u postgres psql
CREATE DATABASE reddit WITH ENCODING = 'utf8' TEMPLATE template0 LC_COLLATE='en_US.utf8' LC_CTYPE='en_US.utf8';
CREATE USER reddit WITH PASSWORD 'password';
PGSCRIPT
fi
sudo -u postgres psql reddit <<FUNCTIONSQL
create or replace function hot(ups integer, downs integer, date timestamp with time zone) returns numeric as \$\$
select round(cast(log(greatest(abs(\$1 - \$2), 1)) * sign(\$1 - \$2) + (date_part('epoch', \$3) - 1134028003) / 45000.0 as numeric), 7)
\$\$ language sql immutable;
create or replace function score(ups integer, downs integer) returns integer as \$\$
select \$1 - \$2
\$\$ language sql immutable;
create or replace function controversy(ups integer, downs integer) returns float as \$\$
select CASE WHEN \$1 <= 0 or \$2 <= 0 THEN 0
WHEN \$1 > \$2 THEN power(\$1 + \$2, cast(\$2 as float) / \$1)
ELSE power(\$1 + \$2, cast(\$1 as float) / \$2)
END;
\$\$ language sql immutable;
create or replace function ip_network(ip text) returns text as \$\$
select substring(\$1 from E'[\\d]+\.[\\d]+\.[\\d]+')
\$\$ language sql immutable;
create or replace function base_url(url text) returns text as \$\$
select substring(\$1 from E'(?i)(?:.+?://)?(?:www[\\d]*\\.)?([^#]*[^#/])/?')
\$\$ language sql immutable;
create or replace function domain(url text) returns text as \$\$
select substring(\$1 from E'(?i)(?:.+?://)?(?:www[\\d]*\\.)?([^#/]*)/?')
\$\$ language sql immutable;
FUNCTIONSQL

41
install/setup_rabbitmq.sh Executable file
View File

@@ -0,0 +1,41 @@
#!/bin/bash
# The contents of this file are subject to the Common Public Attribution
# License Version 1.0. (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
# License Version 1.1, but Sections 14 and 15 have been added to cover use of
# software over a computer network and provide for limited attribution for the
# Original Developer. In addition, Exhibit A has been modified to be consistent
# with Exhibit B.
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
# the specific language governing rights and limitations under the License.
#
# The Original Code is reddit.
#
# The Original Developer is the Initial Developer. The Initial Developer of
# the Original Code is reddit Inc.
#
# All portions of the code written by reddit are Copyright (c) 2006-2015 reddit
# Inc. All Rights Reserved.
###############################################################################
# load configuration
RUNDIR=$(dirname $0)
source $RUNDIR/install.cfg
###############################################################################
# Configure RabbitMQ
###############################################################################
if ! sudo rabbitmqctl list_vhosts | egrep "^/$"
then
sudo rabbitmqctl add_vhost /
fi
if ! sudo rabbitmqctl list_users | egrep "^reddit"
then
sudo rabbitmqctl add_user reddit reddit
fi
sudo rabbitmqctl set_permissions -p / reddit ".*" ".*" ".*"

125
install/travis.sh Executable file
View File

@@ -0,0 +1,125 @@
#!/bin/bash
# The contents of this file are subject to the Common Public Attribution
# License Version 1.0. (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
# License Version 1.1, but Sections 14 and 15 have been added to cover use of
# software over a computer network and provide for limited attribution for the
# Original Developer. In addition, Exhibit A has been modified to be consistent
# with Exhibit B.
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
# the specific language governing rights and limitations under the License.
#
# The Original Code is reddit.
#
# The Original Developer is the Initial Developer. The Initial Developer of
# the Original Code is reddit Inc.
#
# All portions of the code written by reddit are Copyright (c) 2006-2015 reddit
# Inc. All Rights Reserved.
###############################################################################
###############################################################################
# reddit travis environment installer
# -----------------------------------
# This script installs a reddit stack suitable for running on travis-ci.
# As such, this is a minimal build to allow for running "nosetests"
# and not much more.
###############################################################################
# load configuration
RUNDIR=$(dirname $0)
source $RUNDIR/install.cfg
# who is running me (expects "travis" or "vagrant")
ENVIRONMENT=${1:-travis}
# the root directory to base the install in. must exist already
REDDIT_CODE=${2:-$REDDIT_SRC/reddit}
if [ ! -e $REDDIT_CODE ]; then
echo "Couldn't find source $REDDIT_CODE. Aborting"
exit 1
fi
###############################################################################
# Sanity Checks
###############################################################################
if [[ $EUID -ne 0 ]]; then
echo "ERROR: Must be run with root privileges."
exit 1
fi
if [[ "amd64" != $(dpkg --print-architecture) ]]; then
cat <<END
ERROR: This host is running the $(dpkg --print-architecture) architecture!
Because of the pre-built dependencies in our PPA, and some extra picky things
like ID generation in liveupdate, installing reddit is only supported on amd64
architectures.
END
exit 1
fi
# seriously! these checks are here for a reason. the packages from the
# reddit ppa aren't built for anything but trusty (14.04) right now, so
# if you try and use this install script on another release you're gonna
# have a bad time.
source /etc/lsb-release
if [ "$DISTRIB_ID" != "Ubuntu" -o "$DISTRIB_RELEASE" != "14.04" ]; then
echo "ERROR: Only Ubuntu 14.04 is supported."
exit 1
fi
###############################################################################
# Install prerequisites
###############################################################################
$RUNDIR/install_apt.sh
$RUNDIR/install_cassandra.sh
###############################################################################
# Install and configure the reddit code
###############################################################################
[ -x "$(which pip)" ] || easy_install pip
pip install -U pip wheel setuptools
pushd $REDDIT_CODE/r2
sudo python setup.py build
python setup.py develop
make
ln -sf example.ini test.ini
popd
###############################################################################
# Install services (for local testing only!)
# NB: this is otherwise handled in the .travis.yml in before_script
###############################################################################
if [ "$ENVIRONMENT" == "vagrant" ]; then
# install services (cassandra, postgres, etc.)
$RUNDIR/install_services.sh
# travis doesn't have mcrouter as a possible service, so we need to
# be able to test without that running
service mcrouter stop
# Configure PostgreSQL
$RUNDIR/setup_postgres.sh
# Configure Cassandra
$RUNDIR/setup_cassandra.sh
# Configure RabbitMQ
$RUNDIR/setup_rabbitmq.sh
fi
###############################################################################
# All done!
###############################################################################
cat <<CONCLUSION
Congratulations! A base version of reddit is now installed. To run the
unit tests:
cd src/reddit/r2
nosetests
CONCLUSION

View File

@@ -1,48 +0,0 @@
-- The contents of this file are subject to the Common Public Attribution
-- License Version 1.0. (the "License"); you may not use this file except in
-- compliance with the License. You may obtain a copy of the License at
-- http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
-- License Version 1.1, but Sections 14 and 15 have been added to cover use of
-- software over a computer network and provide for limited attribution for the
-- Original Developer. In addition, Exhibit A has been modified to be
-- consistent with Exhibit B.
--
-- Software distributed under the License is distributed on an "AS IS" basis,
-- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-- the specific language governing rights and limitations under the License.
--
-- The Original Code is reddit.
--
-- The Original Developer is the Initial Developer. The Initial Developer of
-- the Original Code is reddit Inc.
--
-- All portions of the code written by reddit are Copyright (c) 2006-2015
-- reddit Inc. All Rights Reserved.
-------------------------------------------------------------------------------
create or replace function hot(ups integer, downs integer, date timestamp with time zone) returns numeric as $$
select round(cast(log(greatest(abs($1 - $2), 1)) * sign($1 - $2) + (date_part('epoch', $3) - 1134028003) / 45000.0 as numeric), 7)
$$ language sql immutable;
create or replace function score(ups integer, downs integer) returns integer as $$
select $1 - $2
$$ language sql immutable;
create or replace function controversy(ups integer, downs integer) returns float as $$
select CASE WHEN $1 <= 0 or $2 <= 0 THEN 0
WHEN $1 > $2 THEN power($1 + $2, cast($2 as float) / $1)
ELSE power($1 + $2, cast($1 as float) / $2)
END;
$$ language sql immutable;
create or replace function ip_network(ip text) returns text as $$
select substring($1 from E'[\\d]+\.[\\d]+\.[\\d]+')
$$ language sql immutable;
create or replace function base_url(url text) returns text as $$
select substring($1 from E'(?i)(?:.+?://)?(?:www[\\d]*\\.)?([^#]*[^#/])/?')
$$ language sql immutable;
create or replace function domain(url text) returns text as $$
select substring($1 from E'(?i)(?:.+?://)?(?:www[\\d]*\\.)?([^#/]*)/?')
$$ language sql immutable;