The homepage for NTNUI Telemark-Alpint.
Slingsby was also the first man to conquer Store Vengetind in Romsdalen, along with hundreds of summits in Jotunheimen. One of the hardest ski routes in Romsdalen, down the east side of Store Vengetind, is named after his ascent.
- Easily readable code (read: pythonic python and idiomatic javascript)
- Easy to get started for new developers
- Deployment handled automatically
- Well tested code
Our server is running on a Raspberry Pi 2 hosted by ITEM, with deployments handled automatically by
Travis CI. User uploaded media is stored on our studorg server at org.ntnu.no/telemark. We utilize
the studorg MySQL database at mysql.stud.ntnu.no
, which means that the RPi doesn't contain any
critical data and can thus easily be rebuilt if it crashes.
tl;dr: To setup a build environment and run the tests, check out .travis.yml
. For more
in-depth explanation, read on.
It's recommended to use virtualenvs when working on slingsby. First off, get pip and virtualenv if you haven't already:
$ easy_install pip
$ pip install virtualenv
Fetch the source code:
$ git clone https://github.com/TelemarkAlpint/slingsby
$ cd slingsby
Set up a virtualenv and install the python requirements:
$ virtualenv venv
$ . venv/bin/activate # windows: .\venv\Scripts\activate.bat
$ pip install -r dev-requirements.txt
Note: If you're having trouble installing PyCrypto on windows due to missing C compiler, you
can install the precompiled binaries from
the voidspace python modules. If you
install PyCrypto globally, you can copy it into your virtualenv manually by copying Crypto
and
pycrypto-2.6-py2.7.egg-info
from C:\Python2.7\Lib\site-packages
into venv\Lib\site-packages
and edit the salt\slingsby\requirements.txt
to use pycrypto==2.6.
You now have everything needed to run the tests:
$ python manage.py test
Code coverage reports are automatically generated by Travis, and can be seen on our GitHub pages site.
To run the server to test it in your browser, you need a little bit more work, because you need to build the project first.
Slingsby uses Grunt to run boring tasks that should be automated, like
compiling SASS stylesheet, minifying js and similar. To use grunt, you need NodeJS installed.
Follow the instructions over at NodeJS to install it for your system. The
node package manager npm is bundled with recent versions of node, we'll use that to install grunt
plugins we use. These are defined in the package.json
file.
Once you have node and npm installed, you should install the grunt-cli, bower and all the grunt plugins and frontend dependencies:
$ npm install -g grunt-cli
$ npm install
Great! Now you can compile all the static files:
$ grunt prep watch
Adding the watch
task makes sure grunt will stay awake and listen for changes to the project
files, and re-run whatever has to be done for those files and reload your browser when done.
Magic!
Add some dummy data to work with:
$ python manage.py migrate --noinput && python manage.py bootstrap
And now, you can start the devserver:
$ python manage.py runserver
This should start the devserver at port 8000, browse to http://localhost:8000
to see it!
Starting the devserver like this will create a SQLite database you can use locally. You can
log in as an admin by clicking "login" in the upper-right corner, and click "Developer login".
Hack away!
Social login will not work out of the box, since authenticating with Facebook requires you to know our Facebook app secret. If you need to test social login you can decrypt the secrets needed and start the devserver on port 80. You also need to add the following line to your hosts file:
127.0.0.1 ntnuita.local
Decrypt the secrets and start the devserver with them:
$ python tools/secure_data.py decrypt
$ python manage.py runserver 80
You'll find the secret needed for decryption in the styre-dropbox, in the file Kontoer.kdbx
.
You'll need KeePass to open it, the password for that file should be
given to you by the webmaster if you're deemed worthy.
To test that stuff works in the same environment (or rather, very similar) to the one in production, you can start two local machines with all the same software we're using in production by using VirtualBox and Vagrant. Once you have installed the two, simply execute the following to start your VMs and deploy the app to it:
$ grunt build
$ vagrant up
$ fab deploy_vagrant
Make sure you have the following entries in your hosts file:
127.0.0.1 ntnuita.local
127.0.0.1 media.ntnuita.local
You can now visit http://ntnuita.local
in your webbrowser to test how the app runs behind nginx
and gunicorn, with caching and the fileserver and all the bells and whistles.
Handled by three (!) different package managers for three different purposes:
pip
handles python libraries we use, defined insalt/slingsby/requirements.txt
.bower
handles frontend dependencies like jQuery and Handlebars, defined inbower.json
.npm
handles build dependencies like grunt and the grunt plugins for SASS transiling and js minification, defined inpackage.json
.
Relax, take a deep breath, check the logs. Relevant logs to check include:
gunicorn: /var/log/slingsby.log
nginx: /usr/share/nginx/logs/error.log
slingsby: /var/log/slingsby/log.log
Try restarting gunicorn and nginx, to see if it makes a difference:
$ sudo service slingsby restart
$ sudo service nginx restart
Try to see if you can import the settings without failure:
$ sudo /srv/ntnuita.no/venv/bin/python -c "import prod_settings"
Or, that you can import slingsby without failure:
$ /srv/ntnuita.no/venv/bin/python -c "import slingsby"
If you're truly dumbfounded and have no idea what's going on and just need to fix something quick, send Tarjei a mail at hello (at) thusoy.com. He built most of the mess and can probably help. And yes he's old and probably graduated, but he's (hopefully) still alive, and will happily give you a hand.
Q: Create a user for myself on the server?
A: 1) Encrypt your password hash by running
python tools/secure_data.py encrypt <YOURNAME>_PASSWORD=$(pcrypt -r 50000)
(will prompt for your password twice and encryption key once), 2) add your details to
pillar/users/init.sls
, optionally also an SSH key, and Travis will create your user once you
commit the changes.
Q: Add a new frontend library?
A: Install the library with bower: bower install <new-libary> --save
. This will save it into
bower_components
, now add it to an existing script or create a new one in the uglify task in
Gruntfile.js, to have it minified and concatenated.
Q: Add a new grunt plugin?
A: npm install --save-dev <name-of-grunt-plugin>
. --save-dev
makes sure the new library is
saved in package.json
and thus will be installed by everyone else as well.
Q: Add a secret value to the repo?
A: python tools/secure_data.py encrypt <your-new-value>=<your-secret>
. The name you choose
will be the name it will be added to pillar as.
Q: Generate good secrets?
A: Use openssl rand -base64 <number-of-bytes>
. For most keys, 30 random bytes is plenty.
Q: The server is fubar, how do I create a new one?
A: See the steps under salt/README.md
.
Q: How do I get the devserver back to untouched state?
A: Delete the sqlite database: rm db-dev.sqlite
, recreate an empty one: python manage.py syncdb --noinput
, and optionally fill it with some dummy data: python manage.py bootstrap
.
Some tests require a fileserver to dump files to, notably the music upload. You can run these tests
by starting the vagrant box with vagrant up
and run the tests like this:
$ RUN_SSH_TESTS=1 python manage.py test
(Windows user have to set the RUN_SSH_TESTS envvar separately, ie set RUN_SSH_TESTS=1
and then
run the tests as normal). If your fileserver is not reachable by vagrant@localhost:2222
, set
the FILESERVER
envvar to point to the one you want to use. Make sure that the user can log in
with the pubkey listed under pillar/vagrant.sls
.
Wipe the local database and bootstrap a new one:
$ rm db-dev.sqlite && python manage.py migrate --noinput && python manage.py bootstrap
Assuming you've logged in on vagrant, give a given used id admin access (like yourself):
$ echo "update auth_user set is_superuser=1, is_staff=1 where id=1;" | mysql -u root slingsby_rel
MySQL sucks and has a hard limit on 767 bytes for index keys, which in conjunction with
django-celery causes problems. To get it
working django-celery/models.py
was hand-patched to reduce the size of all indexed fields to
191 chars, to let migrations run. Once migrations have run, this shouldn't matter anymore, even
if the modifications are lost, but if the error Specified key was to long; max key length is 767 bytes
ever shows up again, this is probably the cause.
Note: This is now fixed automatically by our slingsby salt state, by running a replace on
djcelery/models.py
.