diff --git a/roles/pagure/files/backup-database b/roles/pagure/files/backup-database new file mode 100644 index 0000000000..3f6e7d8fb1 --- /dev/null +++ b/roles/pagure/files/backup-database @@ -0,0 +1,10 @@ +#!/bin/bash +# Backup a database *locally* to /backups/. + +DB=$1 + +# Make our latest backup +/usr/bin/pg_dump -C $DB | /usr/bin/xz > /backups/$DB-$(date +%F).dump.xz + +# Also, delete the backup from a few days ago. +rm -f /backups/$DB-$(date --date="3 days ago" +%F).dump.xz diff --git a/roles/pagure/files/pg_hba.conf b/roles/pagure/files/pg_hba.conf new file mode 100644 index 0000000000..83aca29868 --- /dev/null +++ b/roles/pagure/files/pg_hba.conf @@ -0,0 +1,78 @@ +# PostgreSQL Client Authentication Configuration File +# =================================================== +# +# Refer to the PostgreSQL Administrator's Guide, chapter "Client +# Authentication" for a complete description. A short synopsis +# follows. +# +# This file controls: which hosts are allowed to connect, how clients +# are authenticated, which PostgreSQL user names they can use, which +# databases they can access. Records take one of these forms: +# +# local DATABASE USER METHOD [OPTION] +# host DATABASE USER CIDR-ADDRESS METHOD [OPTION] +# hostssl DATABASE USER CIDR-ADDRESS METHOD [OPTION] +# hostnossl DATABASE USER CIDR-ADDRESS METHOD [OPTION] +# +# (The uppercase items must be replaced by actual values.) +# +# The first field is the connection type: "local" is a Unix-domain socket, +# "host" is either a plain or SSL-encrypted TCP/IP socket, "hostssl" is an +# SSL-encrypted TCP/IP socket, and "hostnossl" is a plain TCP/IP socket. +# +# DATABASE can be "all", "sameuser", "samerole", a database name, or +# a comma-separated list thereof. +# +# USER can be "all", a user name, a group name prefixed with "+", or +# a comma-separated list thereof. In both the DATABASE and USER fields +# you can also write a file name prefixed with "@" to include names from +# a separate file. +# +# CIDR-ADDRESS specifies the set of hosts the record matches. +# It is made up of an IP address and a CIDR mask that is an integer +# (between 0 and 32 (IPv4) or 128 (IPv6) inclusive) that specifies +# the number of significant bits in the mask. Alternatively, you can write +# an IP address and netmask in separate columns to specify the set of hosts. +# +# METHOD can be "trust", "reject", "md5", "crypt", "password", +# "krb5", "ident", or "pam". Note that "password" sends passwords +# in clear text; "md5" is preferred since it sends encrypted passwords. +# +# OPTION is the ident map or the name of the PAM service, depending on METHOD. +# +# Database and user names containing spaces, commas, quotes and other special +# characters must be quoted. Quoting one of the keywords "all", "sameuser" or +# "samerole" makes the name lose its special character, and just match a +# database or username with that name. +# +# This file is read on server startup and when the postmaster receives +# a SIGHUP signal. If you edit the file on a running system, you have +# to SIGHUP the postmaster for the changes to take effect. You can use +# "pg_ctl reload" to do that. + +# Put your actual configuration here +# ---------------------------------- +# +# If you want to allow non-local connections, you need to add more +# "host" records. In that case you will also need to make PostgreSQL listen +# on a non-local interface via the listen_addresses configuration parameter, +# or via the -i or -h command line switches. +# + +#@authcomment@ + +# TYPE DATABASE USER CIDR-ADDRESS METHOD + +#@remove-line-for-nolocal@# "local" is for Unix domain socket connections only +#@remove-line-for-nolocal@local all all @authmethod@ +# IPv4 local connections: +#host all all 127.0.0.1/32 @authmethod@ +# IPv6 local connections: +#host all all ::1/128 @authmethod@ + +local all all ident +host koji koji 10.5.126.61 255.255.255.255 md5 +host all all 0.0.0.0 0.0.0.0 md5 +# Note, I can't think of a reason to make this more restrictive than ipv4 but +# only fakefas needs it so far +host all all ::1/128 md5 diff --git a/roles/pagure/tasks/main.yml b/roles/pagure/tasks/main.yml new file mode 100644 index 0000000000..87e2a16bef --- /dev/null +++ b/roles/pagure/tasks/main.yml @@ -0,0 +1,217 @@ +--- +# Configuration for the pagure webapp + +- name: install needed packages + yum: pkg={{ item }} state=present + with_items: + - pagure + - python-psycopg2 + - libsemanage-python + -postgresql-server + tags: + - pagure + - packages + + +# Set-up gitolite + +- name: create the folder where we store the git repositories + action: file state=directory + path=/srv/git + owner=root group=root mode=0755 + tags: + - gitolite + - pagure + +- name: Rename the user gitolite into git + command: usermod --move-home --login git --home /srv/git/ gitolite + tags: + - gitolite + - pagure + +- name: Rename the group gitolite into git + command: groupmod --new-name git gitolite + tags: + - gitolite + - pagure + +- name: create the /etc/gitolite/conf folder + action: file state=directory + path=/etc/gitolite/conf + owner=git group=git mode=0775 + tags: + - gitolite + - pagure + +- name: Adjust owner of /srv/git + command: chown git:git -R /srv/git/ + tags: + - gitolite + - pagure + +- name: Adjust permissions of /etc/gitolite + command: chown git:git -R /etc/gitolite + tags: + - gitolite + - pagure + +- name: set-up gitolite + command: gl-setup + sudo: yes + sudo_user: git + creates: /srv/git/.gitolite.rc + tags: + - gitolite + - pagure + +- name: install our own gitolite configuration + template: src=gitolite.rc + dest=/srv/git/.gitolite.rc + owner=git group=git mode=0755 + tags: + - gitolite + - pagure + +- name: create all the directories where we store the git repos + action: file state=directory + path={{ item }} + owner=git group=git mode=0775 + with_items: + - /srv/git/repositories/ + - /srv/git/repositories/forks + - /srv/git/repositories/docs + - /srv/git/repositories/tickets + - /srv/git/repositories/requests + tags: + - gitolite + - pagure + + +# Set-up PostgresQL + +- name: Initialize postgres if necessary + command: /usr/bin/postgresql-setup initdb + creates=/var/lib/pgsql/data + notify: + - restart postgresql + tags: + - postgresql + - pagure + +- name: Set postgresql-server to run on boot + service: name=postgresql enabled=yes + ignore_errors: true + notify: + - restart postgresql + tags: + - service + - postgresql + - pagure + +- name: Ensure postgres has a place to backup to + file: dest=/backups state=directory owner=postgres + tags: + - postgresql + - pagure + +- name: Copy over backup scriplet + copy: src=backup-database dest=/usr/local/bin/backup-database mode=0755 + tags: + - postgresql + - pagure + +- name: Set up some cronjobs to backup databases as configured + template: > + src=cron-backup-database + dest=/etc/cron.d/cron-backup-database-{{ item }} + with_items: + - anitya + tags: + - cron + - postgresql + - pagure + +- name: Add our postgres config file. + copy: > + src={{ item }} + dest=/var/lib/pgsql/data/{{ item }} + owner=postgres + with_items: + - pg_hba.conf + notify: + - restart postgresql + tags: + - config + - postgresql + - pagure + +- name: Set up some cronjobs to backup databases as configured + template: > + src=cron-backup-database + dest=/etc/cron.d/cron-backup-database-{{ item }} + with_items: + - "{{ dbs_to_backup }}" + when: dbs_to_backup != [] + tags: + - cron + - pagure + + +# Set-up Pagure + +- name: copy sundry pagure configuration + template: src={{ item.file }} + dest={{ item.location }}/{{ item.dest }} + owner=apache group=apache mode=0600 + with_items: + - { file: pagure_admin.cfg, location: /etc/pagure, dest: pagure.cfg } +# - { file: alembic.ini, location: /etc/pagure, dest: alembic.ini } + changed_when: "1 != 1" + tags: + - config + - web + - pagure + notify: + - restart apache + +- name: create the database scheme + command: /usr/bin/python2 /usr/share/pagure/pagure_createdb.py + changed_when: "1 != 1" + environment: + PAGURE_CONFIG: /etc/pagure/pagure.cfg + tags: + - web + - pagure + +- name: Install all the configuration files of pagure + template: src={{ item.file }} + dest={{ item.location }}/{{ item.file }} + owner=apache group=apache mode=0600 + with_items: + - { file: pagure.cfg, location: /etc/pagure } + - { file: pagure.conf, location: /etc/httpd/conf.d } + - { file: pagure.wsgi, location: /var/www/, dest: pagure.wsgi } + tags: + - config + - web + - pagure + notify: + - restart apache + +- name: set sebooleans so pkgdb2 can talk to the db + action: seboolean name=httpd_can_network_connect_db + state=true + persistent=true + tags: + - selinux + - web + - pagure + +- name: set sebooleans so apache can send emails + action: seboolean name=httpd_can_sendmail + state=true + persistent=true + tags: + - selinux + - web + - pagure diff --git a/roles/pagure/templates/alembic.ini b/roles/pagure/templates/alembic.ini new file mode 100644 index 0000000000..06f2464252 --- /dev/null +++ b/roles/pagure/templates/alembic.ini @@ -0,0 +1,51 @@ +# A generic, single database configuration. + +[alembic] +# path to migration scripts +script_location = /usr/share/pagure/alembic + +# template used to generate migration files +# file_template = %%(rev)s_%%(slug)s + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + +#sqlalchemy.url = postgresql://<%= pkgdb_app %>:<%= pkgdb_appPassword %>@db-pkgdb/pkgdb +sqlalchemy.url = postgresql://{{ pagure_db_admin_user }}:{{ pagure_db_admin_pass }}@{{ pagure_db_host }}/{{ pagure_db_name }} + + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/roles/pagure/templates/gitolite.rc b/roles/pagure/templates/gitolite.rc new file mode 100644 index 0000000000..24816009f6 --- /dev/null +++ b/roles/pagure/templates/gitolite.rc @@ -0,0 +1,233 @@ +# paths and configuration variables for gitolite + +# please read comments before editing + +# this file is meant to be pulled into a perl program using "do" or "require". + +# You do NOT need to know perl to edit the paths; it should be fairly +# self-explanatory and easy to maintain perl syntax :-) + +# -------------------------------------- +# Do not uncomment these values unless you know what you're doing +# $GL_PACKAGE_CONF = ""; +# $GL_PACKAGE_HOOKS = ""; + +# -------------------------------------- + +# -------------------------------------- + +# this is where the repos go. If you provide a relative path (not starting +# with "/"), it's relative to your $HOME. You may want to put in something +# like "/bigdisk" or whatever if your $HOME is too small for the repos, for +# example + +$REPO_BASE="/srv/git/repositories/"; + +# the default umask for repositories is 0077; change this if you run stuff +# like gitweb and find it can't read the repos. Please note the syntax; the +# leading 0 is required + +$REPO_UMASK = 0002; +# $REPO_UMASK = 0027; # gets you 'rwxr-x---' +# $REPO_UMASK = 0022; # gets you 'rwxr-xr-x' + +# part of the setup of gitweb is a variable called $projects_list (please see +# gitweb documentation for more on this). Set this to the same value: + +$PROJECTS_LIST = $ENV{HOME} . "/projects.list"; + +# -------------------------------------- + +# I see no reason anyone may want to change the gitolite admin directory, but +# feel free to do so. However, please note that it *must* be an *absolute* +# path (i.e., starting with a "/" character) + +# gitolite admin directory, files, etc + +$GL_ADMINDIR="/etc/gitolite"; + +# -------------------------------------- + +# templates for location of the log files and format of their names + +# I prefer this template (note the %y and %m placeholders) +# it produces files like `~/.gitolite/logs/gitolite-2009-09.log` + +$GL_LOGT="/var/log/gitolite/gitolite-%y-%m.log"; + +# other choices are below, or you can make your own -- but PLEASE MAKE SURE +# the directory exists and is writable; gitolite won't do that for you (unless +# it is the default, which is "$GL_ADMINDIR/logs") + +# $GL_LOGT="$GL_ADMINDIR/logs/gitolite-%y-%m-%d.log"; +# $GL_LOGT="$GL_ADMINDIR/logs/gitolite-%y.log"; + +# -------------------------------------- + +# Please DO NOT change these three paths + +$GL_CONF="$GL_ADMINDIR/conf/gitolite.conf"; +$GL_KEYDIR="$GL_ADMINDIR/keydir"; +$GL_CONF_COMPILED="$GL_ADMINDIR/conf/gitolite.conf-compiled.pm"; + +# -------------------------------------- + +# if git on your server is on a standard path (that is +# ssh git@server git --version +# works), leave this setting as is. Otherwise, choose one of the +# alternatives, or write your own + +$GIT_PATH=""; +# $GIT_PATH="/opt/bin/"; + +# -------------------------------------- + +# ---------------------------------------------------------------------- +# BIG CONFIG SETTINGS + +# Please read doc/big-config.mkd for details + +$GL_BIG_CONFIG = 1; +$GL_NO_DAEMON_NO_GITWEB = 1; +$GL_NO_CREATE_REPOS = 1; +$GL_NO_SETUP_AUTHKEYS = 1; + + +# ---------------------------------------------------------------------- +# SECURITY SENSITIVE SETTINGS +# +# Settings below this point may have security implications. That +# usually means that I have not thought hard enough about all the +# possible ways to crack security if these settings are enabled. + +# Please see details on each setting for specifics, if any. +# ---------------------------------------------------------------------- + + + +# -------------------------------------- +# ALLOW REPO ADMIN TO SET GITCONFIG KEYS +# +# Gitolite allows you to set git repo options using the "config" keyword; see +# conf/example.conf for details and syntax. +# +# However, if you are in an installation where the repo admin does not (and +# should not) have shell access to the server, then allowing him to set +# arbitrary repo config options *may* be a security risk -- some config +# settings may allow executing arbitrary commands. +# +# You have 3 choices. By default $GL_GITCONFIG_KEYS is left empty, which +# completely disables this feature (meaning you cannot set git configs from +# the repo config). + +$GL_GITCONFIG_KEYS = ""; + +# The second choice is to give it a space separated list of settings you +# consider safe. (These are actually treated as a set of regular expression +# patterns, and any one of them must match). For example: +# $GL_GITCONFIG_KEYS = "core\.logAllRefUpdates core\..*compression"; +# allows repo admins to set one of those 3 config keys (yes, that second +# pattern matches two settings from "man git-config", if you look) +# +# The third choice (which you may have guessed already if you're familiar with +# regular expressions) is to allow anything and everything: +# $GL_GITCONFIG_KEYS = ".*"; + +# -------------------------------------- +# EXTERNAL COMMAND HELPER -- HTPASSWD + +# security note: runs an external command (htpasswd) with specific arguments, +# including a user-chosen "password". + +# if you want to enable the "htpasswd" command, give this the absolute path to +# whatever file apache (etc) expect to find the passwords in. + +$HTPASSWD_FILE = ""; + +# Look in doc/3 ("easier to link gitweb authorisation with gitolite" section) +# for more details on using this feature. + +# -------------------------------------- +# EXTERNAL COMMAND HELPER -- RSYNC + +# security note: runs an external command (rsync) with specific arguments, all +# presumably filled in correctly by the client-side rsync. + +# base path of all the files that are accessible via rsync. Must be an +# absolute path. Leave it undefined or set to the empty string to disable the +# rsync helper. + +$RSYNC_BASE = ""; + +# $RSYNC_BASE = "/home/git/up-down"; +# $RSYNC_BASE = "/tmp/up-down"; + +# -------------------------------------- +# EXTERNAL COMMAND HELPER -- SVNSERVE + +# security note: runs an external command (svnserve) with specific arguments, +# as specified below. %u is substituted with the username. + +# This setting allows launching svnserve when requested by the ssh client. +# This allows using the same SSH setup (hostname/username/public key) for both +# SVN and git access. Leave it undefined or set to the empty string to disable +# svnserve access. + +$SVNSERVE = ""; +# $SVNSERVE = "/usr/bin/svnserve -r /var/svn/ -t --tunnel-user=%u"; + +# -------------------------------------- +# ALLOW REPO CONFIG TO USE WILDCARDS + +# security note: this used to in a separate "wildrepos" branch. You can +# create repositories based on wild cards, give "ownership" to the specific +# user who created it, allow him/her to hand out R and RW permissions to other +# users to collaborate, etc. This is powerful stuff, and I've made it as +# secure as I can, but it hasn't had the kind of rigorous line-by-line +# analysis that the old "master" branch had. + +# This has now been rolled into master, with all the functionality gated by +# this variable. Set this to 1 if you want to enable the wildrepos features. +# Please see doc/4-wildcard-repositories.mkd for details. + +$GL_WILDREPOS = 0; + +# -------------------------------------- +# DEFAULT WILDCARD PERMISSIONS + +# If set, this value will be used as the default user-level permission rule of +# new wildcard repositories. The user can change this value with the setperms command +# as desired after repository creation; it is only a default. Note that @all can be +# used here but is special; no other groups can be used in user-level permissions. + +# $GL_WILDREPOS_DEFPERMS = 'R = @all'; + +# -------------------------------------- +# HOOK CHAINING + +# by default, the update hook in every repo chains to "update.secondary". +# Similarly, the post-update hook in the admin repo chains to +# "post-update.secondary". If you're fine with the defaults, there's no need +# to do anything here. However, if you want to use different names or paths, +# change these variables + +# $UPDATE_CHAINS_TO = "hooks/update.secondary"; +# $ADMIN_POST_UPDATE_CHAINS_TO = "hooks/post-update.secondary"; + +# -------------------------------------- +# ADMIN DEFINED COMMANDS + +# WARNING: Use this feature only if (a) you really really know what you're +# doing or (b) you really don't care too much about security. Please read +# doc/admin-defined-commands.mkd for details. + +# $GL_ADC_PATH = ""; + +# -------------------------------------- +# per perl rules, this should be the last line in such a file: +1; + +# Local variables: +# mode: perl +# End: +# vim: set syn=perl: diff --git a/roles/pagure/templates/pagure.cfg b/roles/pagure/templates/pagure.cfg new file mode 100644 index 0000000000..5ce7c3f7d5 --- /dev/null +++ b/roles/pagure/templates/pagure.cfg @@ -0,0 +1,120 @@ + +### Set the time after which the admin session expires +# There are two sessions on pagure, login that holds for 31 days and +# the session defined here after which an user has to re-login. +# This session is used when accessing all administrative parts of pagure +# (ie: changing a project's or a user's settings) +ADMIN_SESSION_LIFETIME = timedelta(minutes=20) + +### Secret key for the Flask application +SECRET_KEY='{{ pagure_secret_key }}' + +### url to the database server: +#DB_URL=mysql://user:pass@host/db_name +#DB_URL=postgres://user:pass@host/db_name +DB_URL = 'postgresql://{{ pagure_db_user }}:{{ pagure_db_pass }}@{{ pagure_db_host }}/{{ pagure_db_name }}' + +### The FAS group in which the admin of pagure are +ADMIN_GROUP = ['sysadmin-main'] + +### The email address to which the flask.log will send the errors (tracebacks) +EMAIL_ERROR = 'pingou@pingoured.fr' + +### Default SMTP server to use for sending emails +SMTP_SERVER = 'localhost' + +### Email used to sent emails +{% if env == 'staging' %} +APP_URL = 'https://dev.pagure.io/' +{% else %} +FROM_EMAIL = 'pagure@dev.pagure.io' +{% endif %} + +### The URL at which the project is available. +{% if env == 'staging' %} +APP_URL = 'https://dev.pagure.io/' +{% else %} +APP_URL = 'https://pagure.io/' +{% endif %} + +### The URL to use to clone git repositories. +GIT_URL_SSH = 'git@pagure.io' +GIT_URL_GIT = 'git://pagure.io' + +### Folder containing to the git repos +GIT_FOLDER = '/srv/git/repositories' + +### Folder containing the forks repos +FORK_FOLDER = '/srv/git/repositories/forks' + +### Folder containing the docs repos +DOCS_FOLDER = '/srv/git/repositories/docs' + +### Folder containing the pull-requests repos +REQUESTS_FOLDER = '/srv/git/repositories/requests' + + +### Configuration file for gitolite +GITOLITE_CONFIG = '/etc/gitolite/conf/gitolite.conf' + + +### Home folder of the gitolite user +### Folder where to run gl-compile-conf from +GITOLITE_HOME = '/srv/git/' + +### Folder containing all the public ssh keys for gitolite +GITOLITE_KEYDIR = '/etc/gitolite/keydir/' + +### Path to the gitolite.rc file +GL_RC = '/etc/gitolite/gitolite.rc' + +### Path to the /bin directory where the gitolite tools can be found +GL_BINDIR = '/usr/bin/' + + +# Optional configuration + +### Number of items displayed per page +# Used when listing items +ITEM_PER_PAGE = 50 + +### Maximum size of the uploaded content +# Used to limit the size of file attached to a ticket for example +MAX_CONTENT_LENGTH = 4 * 1024 * 1024 # 4 megabytes + +### Lenght for short commits ids or file hex +SHORT_LENGTH = 6 + +### List of blacklisted project names that can conflicts for pagure's URLs +### or other +BLACKLISTED_PROJECTS = ['static', 'pv'] + + +# Authentication related configuration option + +### Switch the authentication method +# Specify which authentication method to use, defaults to `fas` can be or +# `local` +# Default: ``fas``. +PAGURE_AUTH = 'fas' + +# When this is set to True, the session cookie will only be returned to the +# server via ssl (https). If you connect to the server via plain http, the +# cookie will not be sent. This prevents sniffing of the cookie contents. +# This may be set to False when testing your application but should always +# be set to True in production. +# Default: ``True``. +SESSION_COOKIE_SECURE = False + +# The name of the cookie used to store the session id. +# Default: ``.pagure``. +SESSION_COOKIE_NAME = 'pagure' + +# Boolean specifying wether to check the user's IP address when retrieving +# its session. This make things more secure (thus is on by default) but +# under certain setup it might not work (for example is there are proxies +# in front of the application). +CHECK_SESSION_IP = True + +# Used by SESSION_COOKIE_PATH +APPLICATION_ROOT = '/' diff --git a/roles/pagure/templates/pagure.conf b/roles/pagure/templates/pagure.conf new file mode 100644 index 0000000000..7193920f9c --- /dev/null +++ b/roles/pagure/templates/pagure.conf @@ -0,0 +1,23 @@ +Alias /static /usr/lib/python2.7/site-packages/pagure/static/ + +WSGIDaemonProcess pagure user=git group=git maximum-requests=1000 display-name=pagure processes=4 threads=4 inactivity-timeout=300 + +WSGISocketPrefix run/wsgi +WSGIRestrictStdout On +WSGIRestrictSignal Off +WSGIPythonOptimize 1 + +WSGIScriptAlias / /var/www/pagure.wsgi + + + WSGIProcessGroup pagure + + # Apache 2.4 + Require all granted + + + # Apache 2.2 + Order deny,allow + Allow from all + + diff --git a/roles/pagure/templates/pagure.wsgi b/roles/pagure/templates/pagure.wsgi new file mode 100644 index 0000000000..935345d53b --- /dev/null +++ b/roles/pagure/templates/pagure.wsgi @@ -0,0 +1,22 @@ +#-*- coding: utf-8 -*- + +# The three lines below are required to run on EL6 as EL6 has +# two possible version of python-sqlalchemy and python-jinja2 +# These lines make sure the application uses the correct version. +import __main__ +__main__.__requires__ = ['SQLAlchemy >= 0.8', 'jinja2 >= 2.4'] +import pkg_resources + +import os +## Set the environment variable pointing to the configuration file +os.environ['PAGURE_CONFIG'] = '/etc/pagure/pagure.cfg' + +## The following is only needed if you did not install pagure +## as a python module (for example if you run it from a git clone). +#import sys +#sys.path.insert(0, '/path/to/pagure/') + + +## The most import line to make the wsgi working +from pagure import APP as application +#application.debug = True