latest PDF - Read the Docs

Kuma Documentation
Release latest
Mozilla
January 08, 2015
Contents
1
Development
2
Getting Started
2.1 Installation . . . . . . . . . . .
2.2 Vendor Library . . . . . . . . .
2.3 Kuma via Vagrant . . . . . . .
2.4 Celery and Rabbit . . . . . . .
2.5 Running Kuma with mod_wsgi
2.6 Email from Kuma . . . . . . .
2.7 Search . . . . . . . . . . . . .
2.8 Development . . . . . . . . . .
2.9 Localization . . . . . . . . . .
2.10 The Kuma Test Suite . . . . . .
3
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5
5
8
10
13
15
18
19
20
22
27
i
ii
Kuma Documentation, Release latest
Kuma is the platform that powers MDN (developer.mozilla.org)
Contents
1
Kuma Documentation, Release latest
2
Contents
CHAPTER 1
Development
Code https://github.com/mozilla/kuma
Issues http://mzl.la/mdn_backlog (Product)
https://github.com/mozilla/kuma/issues?state=open (Engineering)
https://prs.paas.allizom.org/mozilla:kuma,kuma-lib,kumascript,mozhacks (PR Queue)
Dev Docs https://kuma.readthedocs.org/en/latest/installation-vagrant.html
CI Server https://travis-ci.org/mozilla/kuma
Mailing list https://lists.mozilla.org/listinfo/dev-mdn
IRC irc://irc.mozilla.org/mdndev
http://logs.glob.uno/?c=mozilla%23mdndev (logs)
Servers http://mzl.la/deployed-mdn (What’s Deployed)
https://developer-dev.allizom.org/ (dev)
https://developer.allizom.org/ (stage)
https://developer.mozilla.org/ (prod)
3
Kuma Documentation, Release latest
4
Chapter 1. Development
CHAPTER 2
Getting Started
Want to help make MDN great? Here are some options:
1. Contribute to our selenium test suite
2. Contribute to the platform itself. Our contribution guide lists some good first projects and offers direction on
submitting code.
Contents:
2.1 Installation
This page describes the manual installation procedure. If you can, you should set up the vagrant-managed virtual
machine instead.
2.1.1 Requirements
To run everything and make all the tests pass locally, you’ll need the following things (in addition to Git, of course).
• Python 2.6.
• setuptools or pip.
• MySQL Server and client headers.
• Memcached Server and libmemcached.
• Elasticsearch 0.90.9.
• RabbitMQ.
• libxml and headers.
• libxslt and headers.
• libjpeg and headers.
• zlib and headers.
• libmagic and headers.
• libtidy and headers
• Several Python packages. See Installing the Packages.
Installation for these is very system dependent. Using a package manager, like yum, aptitude, or brew, is encouraged.
5
Kuma Documentation, Release latest
Additional Requirements
If you want to use Apache, instead of the dev server (not strictly required but it’s more like our production environment)
you’ll also need:
• Apache HTTPD Server.
• mod_wsgi
See the documentation on WSGI for more information and instructions.
2.1.2 Getting the Source
First, to follow the instructions from Webdev Bootcamp, fork the project into your own account. Then get the source
using:
mkdir mdn # you probably want to do this, since you’ll have to create
cd mdn
# product_details_json/ as a sibling of kuma/ later.
git clone git@github.com:<your_username>/kuma.git
cd kuma
git submodule update --init --recursive
2.1.3 Installing the Packages
Compiled Packages
There are a small number of compiled packages, including the MySQL Python client. You can install these using pip
(if you don’t have pip, you can get it with easy_install pip) or via a package manager. To use pip, you only
need to do this:
sudo pip install -r requirements/compiled.txt
Python Packages
All of the pure-Python requirements are available in a git repository, known as a vendor library. This allows them to
be available on the Python path without needing to be installed in the system, allowing multiple versions for multiple
projects simultaneously.
2.1.4 Configuration
Start by creating a file named settings_local.py, and putting this line in it:
from settings import *
Now you can copy and modify any settings from settings.py into settings_local.py and the value will
override the default.
Database
At a minimum, you will need to define a database connection. An example configuration is:
6
Chapter 2. Getting Started
Kuma Documentation, Release latest
DATABASES = {
’default’: {
’NAME’: ’kuma’,
’ENGINE’: ’django.db.backends.mysql’,
’HOST’: ’localhost’,
’USER’: ’kuma’,
’PASSWORD’: ’’,
’OPTIONS’: {’init_command’: ’SET storage_engine=InnoDB’},
’TEST_CHARSET’: ’utf8’,
’TEST_COLLATION’: ’utf8_unicode_ci’,
},
}
Note the two settings TEST_CHARSET and TEST_COLLATION. Without these, the test suite will use MySQL’s
(moronic) defaults when creating the test database (see below) and lots of tests will fail. Hundreds.
Once you’ve set up the database, you can generate the schema with Django’s syncdb command:
mkdir ../product_details_json
./manage.py syncdb
./manage.py migrate
This will generate an empty database, which will get you started!
Initializing Mozilla Product Details
One of the packages Kuma uses, Django Mozilla Product Details, needs to fetch JSON files containing historical
Firefox version data and write them within its package directory. To set this up, just run:
./manage.py update_product_details
...to do the initial fetch.
Media
If you want to see images and have the pages formatted with CSS you need to set your settings_local.py with
the following:
DEBUG = True
TEMPLATE_DEBUG = DEBUG
SERVE_MEDIA = True
Setting DEBUG = False will put the installation in production mode and ask for minified assets. In that case, you
will need to generate CSS from stylus and compress resource:
./scripts/compile-stylesheets
./manage.py compress_assets
Configure Persona
Add the following to settings_local.py so that Persona works with the development instance:
SITE_URL = ’http://localhost:8000’
PROTOCOL = ’http://’
DOMAIN = ’localhost’
PORT = 8000
2.1. Installation
7
Kuma Documentation, Release latest
SESSION_COOKIE_SECURE = False # needed if the server is running on http://
SESSION_EXPIRE_AT_BROWSER_CLOSE = False
The SESSION_EXPIRE_AT_BROWSER_CLOSE setting is not strictly necessary, but it’s convenient for development.
Secure Cookies
To prevent error messages like Forbidden (CSRF cookie not set.):, you need to set your
settings_local.py with the following:
CSRF_COOKIE_SECURE = False
2.1.5 Testing it Out
To start the dev server, run ./manage.py runserver, then open up http://localhost:8000. If everything’s working, you should see the MDN home page!
You might need to first set LC_CTYPE if you’re on Mac OS X until bug 754728 is fixed:
export LC_CTYPE=en_US
2.1.6 What’s next?
See development for further instructions.
Some site funcationaly require waffle flags. Waffle flags include:
• kumaediting: Allows creation, editing, and translating of documents
• page_move: Allows moving of documents
• revision-dashboard-newusers: Allows searching of new users through the revision dashboard
• events_map: Allows display of map on the events page
• elasticsearch: Enables elastic search for site search
To create or modify waffle flags, visit “/admin/” and click the “Waffle” link.
2.1.7 Last Steps
Setting Up Search
See the search documentation for steps to get Elasticsearch search working.
2.2 Vendor Library
The vendor directory contains the source code for Kuma libraries.
8
Chapter 2. Getting Started
Kuma Documentation, Release latest
2.2.1 Getting the Vendor Libraries
To get the vendor libraries in your Kuma clone,
$ git submodule update --init
Git will fetch all the vendor submodules.
2.2.2 Updating the Vendor Library
Danger: We are moving all libraries from vendor to pip. Any pull requests with vendor updates will be rejected
unless it is an emergency situation.
From time to time we need to update libraries, either for new versions of libraries or to add a new library. There are
two ways to do that.
Updating a Library with Git Submodules
If the library is in vendor/src, it was pulled directly from version control, and if that version control was git, update
the submodule like so:
$
$
$
$
$
$
cd vendor/src/$LIBRARY
git fetch origin
git checkout <REFSPEC>
cd ../..
git add src/$LIBRARY
git ci -m "Updating $LIBRARY"
Just like updating any other git submodule.
Adding a New Library with Git Submodules
Technically this can be done with pip install --no-install but we do this:
$
$
$
$
$
$
$
cd vendor/src
git clone git://<repo>
cd ../..
./addsubmodules.sh
vim kuma.pth # Add the new library’s path
git add kuma.pth
git ci -m "Adding $LIBRARY"
Using PyPI
Follow the playdoh instructions for non-git based repos, replacing vendor-local with vendor.
2.2.3 Requirements Files
We are in the process of moving all our libraries to pip requirements.
2.2. Vendor Library
9
Kuma Documentation, Release latest
We still maintain requirements files in requirements/. Sometimes people will use these to install the requirements
in a virtual environment. When you update the vendor repo, you should make sure to update version numbers (if
necessary) in the requirements files.
2.3 Kuma via Vagrant
Core developers run Kuma in a Vagrant-managed virtual machine so we can run the entire MDN stack. (Django,
KumaScript, Search, Celery, etc.) If you’re on Mac OS X or Linux and looking for a quick way to get started, you
should try these instructions.
At the end, you’ll earn the badge:
Note: If you have problems using vagrant, check Troubleshooting and Getting More Help below.
2.3.1 Install and run everything
1. Install VirtualBox 4.x from http://www.virtualbox.org/
Note:
(Windows) After installing
Files\Oracle\VirtualBox\VBoxManage.exe;
VirtualBox
you
need
to
set
PATH=C:\Program
2. Install vagrant >= 1.6 using the installer from vagrantup.com
3. Install the vagrant-vbguest plugin.
4. Fork the project. (See GitHub and Webdev Bootcamp)
5. Clone your fork of Kuma and update submodules:
git clone git@github.com:<your_username>/kuma.git
cd kuma
git submodule update --init --recursive
6. Copy a vagrantconfig_local.yaml file for your VM:
cp vagrantconfig_local.yaml-dist vagrantconfig_local.yaml
7. Start the VM and install everything. (approx. 30 min on a fast net connection).:
vagrant up
Note: VirtualBox creates VMs in your system drive. Kuma’s VM is 3GB. If it won’t fit on your system drive,
you will need to change that directory to another drive.
At the end, you should see:
=> default: notice: Finished catalog run in .... seconds
If the above process fails with an error, check Troubleshooting.
8. Add the hostnames to the end of your hosts file with this shell command:
echo ’192.168.10.55 developer-local.allizom.org mdn-local.mozillademos.org’ | sudo tee -a /etc/h
9. Log into the VM with ssh:
10
Chapter 2. Getting Started
Kuma Documentation, Release latest
vagrant ssh
10. Use foreman inside the VM to start all site services:
foreman start
You should see output like:
20:32:59
20:32:59
20:32:59
20:32:59
...
web.1
celery.1
kumascript.1
stylus.1
|
|
|
|
started
started
started
started
with
with
with
with
pid
pid
pid
pid
2244
2245
2246
2247
11. Visit https://mdn-local.mozillademos.org and add an exception for the security certificate if prompted
12. Visit the homepage at https://developer-local.allizom.org
13. You’ve installed Kuma! If you want the badge, email a screenshot of your browser to mdn-dev at mozilla dot
com.
2.3.2 Create an admin user
You will want to make yourself an admin user to enable important site features.
1. Sign up/in with Persona
2. After you sign in, SSH into the vm and make yourself an admin:
vagrant ssh
mysql -uroot kuma
UPDATE auth_user set is_staff = 1, is_active=1, is_superuser = 1 WHERE username = ’YOUR_USERNAME
You should see:
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
2.3.3 Enable Important Site Features
Some site features are controlled using django-waffle. You control these features in the waffle admin.
Some site features are controlled using constance. You control these features in the constance config admin panel.
GitHub Auth
To enable GitHub authentication ...
Register your own OAuth application on GitHub:
• Application name: MDN (<username>)
• Homepage url: https://developer-local.allizom.org/docs/MDN/Contribute/Howto/Create_an_MDN_account
• Application description: My own GitHub app for MDN!
• Authorization callback URL: https://developer-local.allizom.org/users/github/login/callback/
Add a django-allauth social app for GitHub:
2.3. Kuma via Vagrant
11
Kuma Documentation, Release latest
• Provider: GitHub
• Name: developer-local.allizom.org
• Client id: <your GitHub App Client ID>
• Secret key: <your GitHub App Client Secret>
• Sites: example.com -> Chosen sites
GitHub auth is also (temporarily) behind a waffle flag. So, add a waffle flag called github_login and set “Everyone” to “Yes”.
Now you can sign in with GitHub at https://developer-local.allizom.org
Wiki Editing
The central feature of MDN is wiki editing. We use a waffle flag called kumaediting to control edits to the wiki.
So we can effectively put the site into “read-only” and/or “write-by-staff-only” modes.
To enable wiki editing on your MDN vm, add a waffle flag called kumaediting and set “Everyone” to “Yes”.
KumaScript
To enable KumaScript (Kuma’s template system):
1. Sign in
2. Visit the constance config admin panel
3. Change KUMASCRIPT_TIMEOUT to 600
4. Click “Save” at the bottom
2.3.4 Create pages
You can visit https://developer-local.allizom.org/docs/new to create new wiki pages as needed.
Many core MDN contributors create a personal User:<username> page as a testing sandbox.
2.3.5 Developing with Vagrant
Edit files as usual on your host machine; the current directory is mounted via NFS at /home/vagrant/src within
the VM. Updates should be reflected without any action on your part.
• See development for tips not specific to vagrant.
• Useful vagrant sub-commands:
vagrant
vagrant
vagrant
vagrant
vagrant
12
ssh
suspend
halt
up
destroy
#
#
#
#
#
Connect to the VM via ssh
Sleep the VM, saving state
Shutdown the VM
Boot up the VM
Destroy the VM
Chapter 2. Getting Started
Kuma Documentation, Release latest
2.3.6 Troubleshooting
Errors during vagrant up
vagrant up starts the virtual machine. The first time you run vagrant up it also provisions the vm - i.e., it
automatically installs and configures Kuma software on the vm. We provision the vm with puppet manifests in the
puppet/manifests directory.
Sometimes we put puppet declarations in the wrong order. Which means some errors can be fixed by simply provisioning the vm again:
vagrant provision
In some rare occasions you might need to run this multiple times. If you see the same error over and over, please ask
for more help.
On Ubuntu, vagrant up might fail after being unable to mount NFS shared folders. First, make sure you have
the nfs-common and nfs-server packages installed and also note that you can’t export anything via NFS inside an
encrypted volume or home dir.
If that doesn’t help you can disable nfs by setting the nfs flag in the vagrantconfig_local.yaml file you just created.
nfs: false
Note: If you decide to run nfs: false, the system will be a lot slower. There is also the potential of running into
weird issues with puppet, since the current puppet configurations do not currently support nfs: false.
If you have other problems during vagrant up, please ask for more help.
Errors after switching branches
• You should occasionally re-run the Puppet setup, especially after updating code with major changes. This
will ensure that the VM environment stays up to date with configuration changes and installation of additional
services.
– On the Host:
vagrant provision
– Inside the VM:
sudo puppet apply /home/vagrant/src/puppet/manifests/dev-vagrant.pp
Getting more help
If you have more problems using vagrant, please:
1. Paste errors to pastebin
2. email dev-mdn@lists.mozilla.org.
3. After you email dev-mdn, you can also ask in IRC
2.4 Celery and Rabbit
Kuma uses Celery to enable offline task processing for long-running jobs like sending email notifications and rerendering the Knowledge Base.
2.4. Celery and Rabbit
13
Kuma Documentation, Release latest
Though Celery supports multiple message backends, we use, and recommend that you use, RabbitMQ. RabbitMQ is
an AMQP message broker written in Erlang.
2.4.1 When is Celery Appropriate
You can use Celery to do any processing that doesn’t need to happen in the current request-response cycle. Examples
are generating thumbnails, sending out notification emails, updating content that isn’t about to be displayed to the user,
and others.
Ask yourself the question: “Is the user going to need this data on the page I’m about to send them?” If not, using a
Celery task may be a good choice.
2.4.2 RabbitMQ
Installing
RabbitMQ should be installed via your favorite package manager. It can be installed from source but has a number of
Erlang dependencies.
Configuring
RabbitMQ takes very little configuration.
# Start the server.
sudo rabbitmq-server -detached
# Set up the permissions.
rabbitmqctl add_user kuma kuma
rabbitmqctl add_vhost kuma
rabbitmqctl set_permissions -p kuma kuma ".*" ".*" ".*"
That should do it. You may need to use sudo for rabbitmqctl. It depends on the OS and how Rabbit was installed.
2.4.3 Celery
Installing
Celery (and Django-Celery) is part of our vendor library. You shouldn’t need to do any manual installation.
Configuring and Running
We set some reasonable defaults for Celery in settings.py.
These can be overriden either in
settings_local.py or via the command line when running manage.py celeryd.
In settings_local.py you should set at least this, if you want to use Celery:
CELERY_ALWAYS_EAGER = False
This defaults to True, which causes all task processing to be done online. This lets you run Kuma even if you don’t
have Rabbit or want to deal with running workers all the time.
You can also configure the log level or concurrency. Here are the defaults:
14
Chapter 2. Getting Started
Kuma Documentation, Release latest
CELERYD_LOG_LEVEL = logging.INFO
CELERYD_CONCURRENCY = 4
Then to start the Celery workers, you just need to run:
./manage.py celeryd
This will start Celery with the default number of worker threads and the default logging level. You can change those
with:
./manage.py celeryd --log-level=DEBUG -c 10
This would start Celery with 10 worker threads and a log level of DEBUG.
2.5 Running Kuma with mod_wsgi
2.5.1 Requirements
• See the installation docs.
• Apache HTTP server
• mod_rewrite
• mod_headers
• mod_expires
• mod_wsgi
• Not mod_python! It is incompatible with mod_wsgi.
2.5.2 Overview
Setting up Kuma to run as a WSGI application is fairly straightforward. You will need to install the requirements and
clone the vendor repo as described in the installation docs.
There are 3 steps once Kuma is installed:
• Set the document root.
• Set up aliases.
• Some file permissions.
• Set up WSGI itself.
Apache Modules
Most of the Apache modules are part of a default Apache install, but may need to be activated. If they aren’t installed,
all of them, including mod_wsgi should be installable via your favorite package manager.
2.5. Running Kuma with mod_wsgi
15
Kuma Documentation, Release latest
WSGI Configuration
In the Apache config (or <VirtualHost>) you will need the following:
Note that values may be slightly different.
DocumentRoot /path/to/kuma/webroot/
<Directory "/path/to/kuma/webroot/">
Options +FollowSymLinks
</Directory>
Alias /media/ "/path/to/kuma/media/"
Alias /admin-media/ \
"/path/to/kuma/vendor/src/django/django/contrib/admin/media/"
WSGISocketPrefix /var/run/wsgi
WSGIDaemonProcess kuma processes=8 threads=1 \
maximum-requests=4000
WSGIProcessGroup kuma
WSGIScriptAlias /k "/path/to/kuma/wsgi/kuma.wsgi"
WSGISocketPrefix: May or may not be necessary. It was for me.
WSGIDaemonProcess: processes should be set to the number of cores. threads should probably be left at
1. maximum-requests is good at between 4000 and 10000.
WSGIScriptAlias: Will make Kuma accessible from http://domain/k, and we use rewrites in
webroot/.htaccess to hide the /k. This will change soon, and the .htaccess file won’t be necessary.
The Alias directives let Kuma access its CSS, JS, and images through Apache, reducing the load on Django.
Configuration
Most of our settings.py is under version control, but can be overridden in a file called settings_local.py
in the base of the app (the same place as settings.py).
You can see example settings in
docs/settings/settings_local.prod.py:
from settings import *
DEBUG = False
TEMPLATE_DEBUG = False
# The default database should point to the master.
DATABASES = {
’default’: {
’NAME’: ’kitsune’,
’ENGINE’: ’django.db.backends.mysql’,
’HOST’: ’’,
’USER’: ’’,
’PASSWORD’: ’’,
’OPTIONS’: {’init_command’: ’SET storage_engine=InnoDB’},
},
}
# This is used to hash some things in Django.
16
Chapter 2. Getting Started
Kuma Documentation, Release latest
SECRET_KEY = ’replace me with something long and random’
DEBUG_PROPAGATE_EXCEPTIONS = DEBUG
2.5.3 File Permissions
To upload files, the webserver needs write access to media/uploads and all its subdirectories. The directories we
currently use are:
media/uploads
media/uploads/avatars
media/uploads/images
media/uploads/images/thumbnails
media/uploads/gallery/images
media/uploads/gallery/images/thumbnails
media/uploads/gallery/videos
media/uploads/gallery/videos/thumbnails
media/uploads and its subdirectories should never be added to version control, as they are installation-/contentspecific.
Product Details JSON
Some people have issues with django-mozilla-product-details and file permissions. The management
command manage.py update_product_details writes a number of JSON files to disk, and the webserver
then needs to read them.
If you get file system errors from product_details, make sure the files are readable by the webserver (should be
by default) and the directory is readable and executable.
By default, product_details stores the JSON files in:
vendor/src/django-mozilla-product-details/product_details/json
This is configurable. If you have multiple web servers, they should share this data. You can set the
PROD_DETAILS_DIR variable in settings_local.py to a different path, for example on NFS.
2.5.4 Debugging
Debugging via WSGI is a little more interesting than via the dev server. One key difference is that you cannot use
pdb. Writing to stdout is not allowed within the WSGI process, and will result in a Internal Server Error.
There are three relevant cases for debugging via WSGI (by which I mean, where to find stack traces):
Apache Error Page
So you’ve got a really bad error and you aren’t even seeing the Kuma error page! This is usually caused by an
uncaught exception during the WSGI application start-up. Our WSGI script tries to run all the initial validation that
the dev server runs, to catch these errors early.
So where is the stack trace? You’ll need to look in your Apache error logs. Where these are is OS-dependent, but
a good place to look is /var/log/httpd. If you are using SSL, also check the SSL VirtualHost‘s logs, for
example /var/log/httpd/ssl_error_log.
2.5. Running Kuma with mod_wsgi
17
Kuma Documentation, Release latest
With DEBUG=True
With DEBUG = True in your settings_local.py, you will see a stack trace in the browser on error. Problem
solved!
With DEBUG=False
With DEBUG = False in your settings_local.py, you’ll see our Server Error message. You can still get
stack traces, though, by setting the ADMINS variable in settings_local.py:
ADMINS = (
(’me’, ’my@email.address’),
)
Django will email you the stack trace. Provided you’ve set up email.
2.5.5 Reloading WSGI
WSGI keeps Python and Kuma running in an isolated process. That means code changes aren’t automatically reflected
on the server. In most default configurations of mod_wsgi, you can simply do this:
touch wsgi/kuma.wsgi
That will cause the WSGI process to reload.
2.6 Email from Kuma
The default settings for Kuma do not send email. If you want to get email, you should double check one thing first:
are there any rows in the tidings_watch table? If there are, you may be sending email to real users. The script in
scripts/anonymize.sql will truncate this table. Simply run it against your Kuma database:
mysql -ukuma -p kuma < scripts/anonymize.sql
2.6.1 Sending Email
So now you know you aren’t emailing real users, but you’d still like to email yourself and test email in general. There
are a few settings you’ll need to use.
First, set the EMAIL_BACKEND. This document assumes you’re using the SMTP mail backend.
EMAIL_BACKEND = ’django.core.mail.backends.smtp.EmailBackend’
If you have sendmail installed and working, that should do it. However, you might get caught in spam filters. An
easy workaround for spam filters or not having sendmail working is to send email via a Gmail account.
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST = ’smtp.gmail.com’
EMAIL_HOST_USER = ’<your gmail address>@gmail.com’
EMAIL_HOST_PASSWORD = ’<your gmail password>’
Yeah, you need to put your Gmail password in a plain text file on your computer. It’s not for everyone. Be very careful
copying and pasting settings from settings_local.py if you go this route.
18
Chapter 2. Getting Started
Kuma Documentation, Release latest
2.7 Search
Kuma uses Elasticsearch to power its on-site search facility.
Elasticsearch search gives us a number of advantages over MySQL’s full-text search or Google’s site search.
• Much faster than MySQL. * And reduces load on MySQL.
• We have total control over what results look like.
• We can adjust searches with non-visible content.
• We don’t rely on Google reindexing the site.
• We can fine-tune the algorithm ourselves.
2.7.1 Installing Elasticsearch Search
We currently require Elasticsearch 0.90.9. You may be able to install this from a package manager like yum, aptitude,
or brew.
If not, you can easily download the source and compile it. Generally all you’ll need to do is:
$ cd elasticsearch-0.90.9
$ bin/elasticsearch -f
Then run the Kuma search tests:
$ ./manage.py test -s --noinput --logging-clear-handlers search
If the tests pass, everything is set up correctly!
2.7.2 Using Elasticsearch
Having Elasticsearch installed will allow the search tests to run, which may be enough. But you want to work on or
test the search app, you will probably need to actually see search results!
The Easy, Sort of Wrong Way
The easiest way to start Elasticsearch for testing is:
$ cd path/to/elasticsearch-0.90.9
$ bin/elasticsearch -f
Then from the Kuma source code path:
$ ./manage.py reindex
If you need to update the search indexes:
$ ./manage.py reindex
While this method is very easy, you will need to reindex after any time you run the search tests, as they will overwrite
the data files Elasticsearch uses.
2.7. Search
19
Kuma Documentation, Release latest
The Ellaborate, Kinda Proper Way
Assuming you’re running the full stack with foreman start (or any other way that makes sure the Celery workers
run) there is a better way:
• Open the Django admin UI under http://127.0.0.1:8000/admin/search/index/ or https://developerlocal.allizom.org/admin/search/index/ if you’re using Vagrant.
• Add a search index by clicking on the “Add index” button in the top right corner, safe it by clicking on the same
button in the lower right corner to safe it to the database.
• On the search index list view again, select the just created index (the top most) and select “Populate search index
with Celery task” from the actions dropdown below.
• Once the population is ready the “populated” field with show up as a green checkbox image. You’ll also get an
email (probably via the console if you’re developing kuma locally) notifying you of the completion.
• To actually enable that newly created search index you have to promote it now. On the search index list view
again, select the just created index (the top most) and select “Promote search index” from the actions dropwdown
below.
• Once the search index is promoted the “promoted” and the “is current index” field will show up as a green
checkbox image. The index is now live.
Similarly you can also demote a search index and it will automatically fall back to the previously created index (by
created date). That helps to figure out issues in production and should allow for a smooth deployment of search index
changes. It’s recommmended to keep a few search indexes around just in case.
If no index is created in the admin UI the fallback “main_index” index will be used instead.
Warning: If you delete any of the search indexes in the admin interface they will be deleted on Elasticsearch as
well.
2.8 Development
We strongly suggest using a Vagrant-managed VM if you can. Or, you can use the manual installation steps.
2.8.1 Running Kuma in Vagrant VM
If you are using a Vagrant-managed VM, you can start all Kuma servers and services with:
vagrant ssh
foreman start
2.8.2 Running Kuma manually
If you are using manual installation, you can run the django server with:
./manage.py runserver
and the kumascript service with:
node kumascript/run.js
Note: Before running kumascript, you need to install the node.js fibers module by running npm install
fibers.
20
Chapter 2. Getting Started
Kuma Documentation, Release latest
2.8.3 Log in
You can log into MDN using Persona or GitHub. For GitHub, you must first enable GitHub Auth as described in the
installation instructions.
2.8.4 Set up permissions
Some features are only available to privileged users. To manage permissions use the Auth -> Users section of the
django admin interface.
2.8.5 Compiling Stylus Files
If you’re updating the Stylus CSS files, you’ll need to compile them before you can see your updates within the
browser. To compile stylus files, run the following from the command line:
./scripts/compile-stylesheets
The relevant CSS files will be generated and placed within the media/redesign/css directory. You can add a -w flag to
that call to compile stylesheets upon save.
2.8.6 Hacking on bleeding edge features
To hack on the features not yet ready for production you have to enable them first.
Enable Kumascript
Kuma uses a separate nodejs-based service to process templates in wiki pages. Its use is disabled by default, to
enable: open the django admin interface and in the Constance section change the value of KUMASCRIPT_TIMEOUT
parameter to a positive value (such as 2.0 seconds).
2.8.7 Running the Tests
A great way to check that everything really is working is to run the test suite.
Django tests
If you’re not using the vagrant VM, you’ll need to add an extra grant in MySQL for your database user:
GRANT ALL ON test_NAME.* TO USER@localhost;
Where NAME and USER are the same as the values in your database configuration.
The test suite will create and use this database, to keep any data in your development database safe from tests.
Running the test suite is easy:
./manage.py test -s --noinput --logging-clear-handlers
Note that this will try (and fail) to run tests that depend on apps disabled via INSTALLED_APPS. You should run a
subset of tests:
2.8. Development
21
Kuma Documentation, Release latest
./manage.py test actioncounters authkeys contentflagging devmo landing kpi kuma
For more information, see the test documentation.
Kumascript tests
If you’re changing Kumascript, be sure to run its tests too. See https://github.com/mozilla/kumascript
2.8.8 Coding Conventions
Tests
• Avoid naming test files test_utils.py, since we use a library with the same name.
test__utils.py instead.
Use
• If you’re expecting reverse to return locales in the URL, use LocalizingClient instead of the default
client for the TestCase class.
2.9 Localization
Kuma is localized with gettext. User-facing strings in the code or templates need to be marked for gettext localization.
We use Verbatim to provide an easy interface to localizing these files. Localizers are also free to download the PO files
and use whatever tool they are comfortable with.
2.9.1 Making Strings Localizable
Making strings in templates localizable is exceptionally easy. Making strings in Python localizable is a little more
complicated. The short answer, though, is just wrap the string in _().
Interpolation
A string is often a combination of a fixed string and something changing, for example, Welcome, James is a
combination of the fixed part Welcome,, and the changing part James. The naive solution is to localize the first part
and the follow it with the name:
_(’Welcome, ’) + username
This is wrong!
In some locales, the word order may be different. Use Python string formatting to interpolate the changing part into
the string:
_(’Welcome, {name}’).format(name=username)
Python gives you a lot of ways to interpolate strings. The best way is to use Py3k formatting and kwargs. That’s the
clearest for localizers.
The worst way is to use %(label)s, as localizers seem to have all manner of trouble with it. Options like %s and
{0} are somewhere in the middle, and generally OK if it’s clear from context what they will be.
22
Chapter 2. Getting Started
Kuma Documentation, Release latest
Localization Comments
Sometimes, it can help localizers to describe where a string comes from, particularly if it can be difficult to find in the
interface, or is not very self-descriptive (e.g. very short strings). If you immediately precede the string with a comment
that starts L10n:, the comment will be added to the PO file, and visible to localizers.
Adding Context with msgctxt
Strings may be the same in English, but different in other languages. English, for example, has no grammatical gender,
and sometimes the noun and verb forms of a word are identical.
To make it possible to localize these correctly, we can add “context” (known in gettext as “msgctxt”) to differentiate
two otherwise identical strings.
For example, the string “Search” may be a noun or a verb in English. In a heading, it may be considered a noun, but
on a button, it may be a verb. It’s appropriate to add a context (like “button”) to one of them.
Generally, we should only add context if we are sure the strings aren’t used in the same way, or if localizers ask us to.
Plurals
“You have 1 new messages” grates on discerning ears. Fortunately, gettext gives us a way to fix that in English and
other locales, the ngettext function:
ngettext(’singular’, ’plural’, count)
A more realistic example might be:
ngettext(’Found {count} result.’,
’Found {count} results’,
len(results)).format(count=len(results))
This method takes three arguments because English only needs three, i.e., zero is considered “plural” for English.
Other locales may have different plural rules, and require different phrases for, say 0, 1, 2-3, 4-10, >10. That’s
absolutely fine, and gettext makes it possible.
Strings in Templates
When putting new text into a template, all you need to do is wrap it in a _() call:
<h1>{{ _(’Heading’) }}</h1>
Adding context is easy, too:
<h1>{{ _(’Heading’, ’context’) }}</h1>
L10n comments need to be Jinja2 comments:
{# L10n: Describes this heading #}
<h1>{{ _(’Heading’) }}</h1>
Note that Jinja2 escapes all content output through {{ }} by default. To put HTML in a string, you’ll need to add
the |safe filter:
<h1>{{ _(’Firefox <span>Help</span>’)|safe }}</h1>
2.9. Localization
23
Kuma Documentation, Release latest
To interpolate, you should use one of two Jinja2 filters: |f() or, in some cases, |fe(). |f() has exactly the same
arguments as u’’.format():
{{ _(’Welcome, {name}!’)|f(name=request.user.username) }}
The |fe() is exactly like the |f() filter, but escapes its arguments before interpolating, then returns a “safe” object.
Use it when the localized string contains HTML:
{{ _(’Found <strong>{0}</strong> results.’)|fe(num_results) }}
Note that you do not need to use |safe with |fe(). Also note that while it may look similar, the following is not
safe:
{{ _(’Found <strong>{0}</strong> results.’)|f(num_results)|safe }}
The ngettext function is also available:
{{ ngettext(’Found {0} result.’,
’Found {0} results.’,
num_results)|f(num_results) }}
Using {% trans %} Blocks for Long Strings
When a string is very long, i.e. long enough to make Github scroll sideways, it should be line-broken and put in a {%
trans %} block. {% trans %} blocks work like other block-level tags in Jinja2, except they cannot have other
tags, except strings, inside them.
The only thing that should be inside a {% trans %} block is printing a string with {{ string }}. These are
defined in the opening {% trans %} tag:
{% trans user=request.user.username %}
Thanks for registering, {{ user }}! We’re so...
hope that you’ll...
{% trans %}
Strings in Python
NB: Whenever you are adding a string in Python, ask yourself if it really needs to be there, or if it should be in the
template. Keep logic and presentation separate!
Strings in Python are more complex for two reasons:
1. We need to make sure we’re always using Unicode strings and the Unicode-friendly versions of the functions.
2. If you use the ugettext function in the wrong place, the string may end up in the wrong locale!
Here’s how you might localize a string in a view:
from tower import ugettext as _
def my_view(request):
if request.user.is_superuser:
msg = _(u’Oh hi, staff!’)
else:
msg = _(u’You are not staff!’)
Interpolation is done through normal Python string formatting:
24
Chapter 2. Getting Started
Kuma Documentation, Release latest
msg = _(u’Oh, hi, {user}’).format(user=request.user.username)
ugettext supports context, too:
msg = _(’Search’, ’context’)
L10n comments are normal one-line Python comments:
# L10n: A message to users.
msg = _(u’Oh, hi there!’)
If you need to use plurals, import the function ungettext from Tower:
from tower import ungettext, ugettext as _
n = len(results)
msg = ungettext(’Found {0} result’, ’Found {0} results’, n).format(n)
Lazily Translated Strings
You can use ugettext or ungettext only in views or functions called from views. If the function will be evaluated
when the module is loaded, then the string may end up in English or the locale of the last request! (We’re tracking
down that issue.)
Examples include strings in module-level code, arguments to functions in class definitions, strings in functions called
from outside the context of a view. To localize these strings, you need to use the _lazy versions of the above
methods, ugettext_lazy and ungettext_lazy. The result doesn’t get translated until it is evaluated as a
string, for example by being output or passed to unicode():
from tower import ugettext_lazy as _lazy
PAGE_TITLE = _lazy(u’Page Title’)
ugettext_lazy also supports context.
It is very important to pass Unicode objects to the _lazy versions of these functions. Failure to do so results in
significant issues when they are evaluated as strings.
If you need to work with a lazily-translated string, you’ll first need to convert it to a unicode object:
from tower import ugettext_lazy as _lazy
WELCOME = _lazy(u’Welcome, %s’)
def my_view(request):
# Fails:
WELCOME % request.user.username
# Works:
unicode(WELCOME) % request.user.username
2.9.2 Getting the Localizations
Localizations are not stored in this repository, but are in Mozilla’s SVN:
http://svn.mozilla.org/projects/mdn/trunk/locale
2.9. Localization
25
Kuma Documentation, Release latest
You don’t need the localization files for general development. However, if you need them for something, they’re pretty
easy to get:
$ cd kuma
$ svn checkout https://svn.mozilla.org/projects/mdn/trunk/locale
(Alternatively, you can do yourself a favor and use:
$ git svn clone -r HEAD https://svn.mozilla.org/projects/mdn/trunk/locale
if you’re a git fan.)
2.9.3 Updating the Localizations
Updating strings is easy. But when we add or update strings, we need to update Verbatim templates and PO files for
localizers. If you commit changes to SVN without updating Verbatim, localizers will have merge head-aches.
1. Check out the localizations (See get-localizations)
2. Run the following in the virtual machine (see installation-vagrant):
$ python manage.py extract
3. Commit the POT file.
If you used svn checkout above:
$ cd locale
$ svn up
$ svn ci -m "MDN string update YYYY-MM-DD"
If you used git svn clone above:
$
$
$
$
$
cd locale
git svn fetch
git add -A
git commit -m "MDN string update YYYY-MM-DD"
git svn dcommit
Note: You need verbatim permissions for the following. If you don’t have permissions, email groovecoder or mathjazz
to do the following ...
4. Go to the MDN templates on Verbatim
5. Click ‘Update all from VCS’
6. ssh to sm-verbatim01 (See L10n:Verbtim on wiki.mozilla.org)
7. Update all locales against templates:
sudo su verbatim
cd /data/www/localize.mozilla.org/verbatim/pootle_env/Pootle
POOTLE_SETTINGS=localsettings.py python2.6 manage.py
update_against_templates --project=mdn -v 2
2.9.4 Adding a new Locale
Adding a new locale is also easy.
26
Chapter 2. Getting Started
Kuma Documentation, Release latest
1. Check out the localizations (See get-localizations)
2. Follow the “Add locale” instructions on wiki.mozilla.org.
3. Update your locale repo to get the new locale:
$ cd locale
$ svn up
4. Add the locale to MDN_LANGUAGES in settings.py
5. Verify django loads new locale without errors by visiting the locale’s home page. E.g., https://developerlocal.allizom.org/ml/
6. BONUS: Use podebug to test a fake translation of the locale:
$ cd locale
$ podebug --rewrite=bracket templates/LC_MESSAGES/messages.pot
ml/LC_MESSAGES/messages.po
$ ./compile-mo.sh .
Restart the django server and re-visit the new locale to verify it shows “translated” strings in the locale.
2.10 The Kuma Test Suite
Kuma has a fairly comprehensive Python test suite. Changes should not break tests–only change a test if there is a
good reason to change the expected behavior–and new code should come with tests.
2.10.1 Running the Test Suite
If you followed the steps in the installation docs, then all you should need to do to run the test suite is:
./manage.py test
However, that doesn’t provide the most sensible defaults. Here is a good command to alias to something short:
./manage.py test -s --noinput --logging-clear-handlers
The -s flag is important if you want to be able to drop into PDB from within tests.
Some tests will fail. See Running a Subset below for running the subset that is expected to pass.
Some other helpful flags are:
-x: Fast fail. Exit immediately on failure. No need to run the whole test suite if you already know something is
broken.
--pdb: Drop into PDB on an uncaught exception. (These show up as E or errors in the test results, not F or failures.)
--pdb-fail: Drop into PDB on a test failure. This usually drops you right at the assertion.
Running a Subset
You can run part of the test suite by specifying the apps you want to run, like:
./manage.py test kuma
You can also exclude tests that match a regular expression with -e:
2.10. The Kuma Test Suite
27
Kuma Documentation, Release latest
./manage.py test -e "search"
To run the subset of tests that should pass:
./manage.py test actioncounters contentflagging devmo landing kuma
See the output of ./manage.py test --help for more arguments.
The Test Database
The test suite will create a new database named test_%s where %s is whatever value you have for
settings.DATABASES[’default’][’NAME’]. Make sure the user has ALL on the test database as well.
When the schema changes, you may need to drop the test database. You can also run the test suite with FORCE_DB
once to cause Django to drop and recreate it:
FORCE_DB=1 ./manage.py test -s --noinput --logging-clear-handlers
2.10.2 Adding Tests
Code should be written so it can be tested, and then there should be tests for it.
When adding code to an app, tests should be added in that app that cover the new functionality. All apps have a tests
module where tests should go. They will be discovered automatically by the test runner as long as the look like a test.
2.10.3 Changing Tests
Unless the current behavior, and thus the test that verifies that behavior is correct, is demonstrably wrong, don’t change
tests. Tests may be refactored as long as its clear that the result is the same.
2.10.4 Removing Tests
On those rare, wonderful occasions when we get to remove code, we should remove the tests for it, as well.
If we liberate some functionality into a new package, the tests for that functionality should move to that package, too.
28
Chapter 2. Getting Started