Background and Requirements

This build has been tested on Ubuntu.

$  lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 14.04.4 LTS
Release:    14.04
Codename:   trusty

Throughout this guide, some words will be surrounded by asterisks (*), this will denote a variable you will need to fill in.

Before installation, make sure python3.6 and postgres9.4.2 are already installed and running. If the installation will be serving C exercises, gcc 4.9 is required, and Java exercises require a Java developer kit (JDK 1.7) installation (for javac). For R exercises, R is required. If you use a python virtual environment, the packages virtualenv and virtualenvwrapper are required.

$ psql --version
psql (PostgreSQL) 9.3.9
$ python3 --version
Python 3.6.1
$ gcc --version
gcc (Ubuntu 4.9.2-0ubuntu1~14.04) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ javac -version
javac 1.7.0_10
$ r --version
R version 3.4.0

You can either install PCRS onto an empty database or onto an image pre-loaded with videos and content. We have an image available for the C programming language, but this image is not distributed on the web, since it contains solutions to the exercises. To get access, mail us from your institution's email address. Please include a web link to your institutional web page, so we can verify that you are a course instructor or system administrator.

The remainder of this guide provides details on the individual steps required to install PCRS. However, the required steps have also been placed into a script. The interactive installer will guide you through the configuration for your specific use case:

$ python3 <(curl -L https://bitbucket.org/utmandrew/pcrs/raw/6e77826b08727727524156ada78582b65ed37d6b/admin_scripts/pcrsdevinstaller.py)

Webserver Configuration

For testing, you can turn off authentication and use django's "runserver" command to experiment with PCRS. For production, you need a webserver and a method to authenticate. For the former, we use apache with mod_wsgi. For the latter, we use shibboleth, but you'll need to create your own interface depending on your authentication preference. Here are the lines we placed in httpd.conf to set up an instance for C exercises:

Alias /*Your Prefix*/static *Path to webfolder*
<Directory *Path to webfolder*>
    Order deny,allow
    Allow from all
</Directory>

WSGIDaemonProcess pcrs_*Your Prefix* user=pcrsadmin group=pcrsadmin processes=5
WSGIScriptAlias /*Your Prefix* *Path to webfolder*/wsgi.py
<Directory *Path to webfolder*>
    <Files wsgi.py>
        Order deny,allow
        Allow from all
    </Files>
</Directory>

Here is the wsgi.py referenced above:

import os
import sys

# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks
# if running multiple sites in the same mod_wsgi process. To fix this, use
# mod_wsgi daemon mode with each site in its own daemon process, or use
# os.environ["DJANGO_SETTINGS_MODULE"] = "pcrs.settings"
sys.path.append("*Path to webfolder*")
os.environ["DJANGO_SETTINGS_MODULE"] = "pcrs.settings"


# This application object is used by any WSGI server configured to use this
# file. This includes Django's development server, if the WSGI_APPLICATION
# setting points here.
from django.core.wsgi import get_wsgi_application
_application = get_wsgi_application()

Virtualenv

PCRS is a django application that runs on python3.6. I recommend setting up a virtual environment for it, but you may skip this step if you'd prefer to install the dependencies in your system python libraries.

$ virtualenv -p /usr/local/bin/python3 ~/.virtualenvs/pcrsenv
$ workon pcrsenv

Pull down a fresh copy of PCRS. Using git will allow you to pull updates automatically.

$ git clone https://bitbucket.org/utmandrew/pcrs.git

There is a requirements file that you can use to set up the dependencies.

$ cd pcrs
$ pip3 install -r requirements.txt

Settings

Next, you'll need to edit pcrs/settings_local.py for your server. settings_local overrides options that are given default values in settings.py and settings_pcrs.py. At a minimum, you need to perform steps 1, 5, and 11 below, but you should review all of the settings, as several more could apply to your setup.

  1. Set INSTALLED_PROBLEM APPS to the languages you want supported. The example below is for instance serving C exercises and multiple choice questions. Any combination of apps is accepted as long as their dependencies are met.

    INSTALLED_PROBLEM_APPS = {
        # 'problems_python': 'Python',
        'problems_c': 'C',
        # 'problems_java': 'Java',
        # 'problems_rdb': '',
        # 'problems_sql': 'SQL',
        # 'problems_ra': 'Relational Algebra',
        'problems_multiple_choice': '',
        # 'problems_short_answer': '',
    }
    
    If you enable "problems_ra" or "problems_sql", you must also enable "problems_rdb", which provides support for both relational languages.
  2. An installation serving C exercises should use safeexec. To do so, set the SAFEEXEC_USERID and SAFEEXEC_GROUPID to the id of the user running the server and then install safeexec.

    $ id
    uid=1001(pcrsadmin) gid=1001(pcrsadmin) groups=1001(pcrsadmin)
    
  3. Production mode enables site caching and hides full error messages. Debug mode will show full stacktraces on the site when errors are encountered. Normally, you do not want both of these on at once.

    PRODUCTION = True
    DEBUG = not PRODUCTION
  4. Set admins if you want email on failures. An example of this field with the name "Test Admin" and the email example@test.com can be seen below.

    ADMINS = (
      ('Test Admin', 'example@test.com'),
    )
  5. Change the password of the database user, and if you wish, the the name of the database. If you are installing PCRS using a database dump, you will need to keep the user the same. Otherwise, if you are installing into an empty database, you may change the user as well.

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql_psycopg2',
            'NAME': 'pcrsadmin',
            'USER': 'pcrsadmin',
            'PASSWORD': 'adminpass',
            'HOST': 'localhost',                      # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
            'PORT': '',                               # Set to empty string for default.
        }
    }
  6. For instances serving SQL and relational algebra exercises, set the RDB_DATABASE. This database will be used to execute student submissions.

  7. Change the site location. This value will vary depending on how you've set up Apache, WSGI, etc. For example, our server runs the application on "https://*Server Address*/pcrs_dev", the site prefix is /pcrs_dev.

        SITE_PREFIX = '/pcrs_dev'
        FORCE_SCRIPT_NAME = SITE_PREFIX
        LOGIN_URL = SITE_PREFIX + '/login'
  8. Select how you'll authenticate. To start, you may want to use 'pass' (a password within the database) or 'none' (for a very brief time). Shibboleth and pwauth interfaces are provided (configured for U of T -- YMMV), but you may need to write your interface for your own central authentication service.

    AUTH_TYPE = 'pass'       # 'shibboleth', 'pwauth', 'pass', or 'none'
  9. If DEBUG is True, set allowed_hosts to the specific host (or domain of the hosts) running the application.

    ALLOWED_HOSTS = ['.*Server Address*']
  10. Set the project root if you'd prefer it were not set automagically. Set the static root to match your server settings.

    PROJECT_ROOT = '*Path to webfolder*/pcrs/'
    STATIC_ROOT = '*Path to webfolder*/static'
    STATIC_URL = 'https://*Server Address*/*Your Prefix*/static/'
  11. Change your secret key, this should be a set of random characters produced from a cryptography secure source.

    SECRET_KEY = '....'
    

Sandboxing

This step is for installations serving C and Java exercises.

For C, we use a judging system, safeexec, to make sure the student code can't access arbitrary files or to run for any length of time. To set up safeexec:

$ pushd *Path to webfolder*/languages/c/execution/safeexec_master/
$ gcc -o safeexec safeexec.c
$ chown root.root safeexec
$ chmod 4555 safeexec
$ popd

For Java, we use a customized version of JavaJail (originally written by David Pritchard). To set up JavaJail, start from the main PCRS directory:

$ git submodule init
$ git submodule update
$ cd languages/java/execution/JavaJail
$ ./setup.sh

Database

You can either set up an empty instance of PCRS or load a postgres dump into it. Either way, you'll need a user and database set up. The following example creates a user and database named pcrsadmin:

$ createuser -P pcrsadmin
Enter password for new role:
Enter it again:
$ createdb pcrsadmin -O pcrsadmin

To create an empty instance, use Django's migrations.

$ python3 manage.py migrate

While running migrate, you will get the following error if your postgres user does not have superuser privileges:

django.db.utils.ProgrammingError: permission denied to create extension "hstore"
HINT:  Must be superuser to create this extension.

To fix this, you must manually create the HStore extension in the database. Using a user with appropriate privileges, connect to your database and run the query:

CREATE EXTENSION IF NOT EXISTS hstore;

Otherwise, load a pg_dump'd database image. (See the top of the page if you need an image.)

$ psql -d pcrsadmin -f image.psql

If you need to create a superuser to access the admin interface for PCRS, you can create one with a command like the one below, which creates an admin instructor named peters43.

pcrsadmin=# insert into users_pcrsuser (last_login, username, section_id, code_style, is_student, is_ta, is_instructor, is_active, is_admin, is_staff, use_simpleui) values (CURRENT_TIMESTAMP, 'peters43', 'master', 'eclipse', False, False, True, True, True, True, False);

For installations serving SQL and relational algebra exercises, run the sql commands in admin_scripts/create_crs_data.sql after changing the name of the database being created to match the name assigned to RDB_DATABASE in the settings file. These commands create roles for instructors and students that allow them to create and copy schemas. When adding users to the system, they will need to be granted either the instructor or the student role to create or submit SQL or relational algebra exercises.

For installations using file uploads, files have a lifespan to reduce server occupation. When a file's lifespan has passed, a django-cron job has been set up to delete it. This django command itself must be run through it's own cron job. The following command must be scheduled by cron:

python manage.py runcrons

By default the django-cron job checks everyday. For more details, refer to the django-cron documentation here: Django-cron

Static Files

You should be using a static root -- unless you're just testing. Collect the static files and change permissions so they are visible.

$ python manage.py collectstatic
$ pushd ../static
$ find . -type d -exec chmod 775 {} \;
$ find . -type f -exec chmod 664 {} \;
$ popd

Done!

At this point, the software should be ready to view in a web browser.