27 August 2012

OpenShift My Python Django Project

Red Hat's OpenShift platform-as-a-service is easy to set up and start using if you have a Python Django project (I haven't tried the other platforms supported, e.g. Java).  It's just 9 (longish) steps!

The django-example they offer gives a good idea of what the completed Django on OpenShift project should look like, but I thought I'd jot some notes down on how to get there from an existing Django project on Ubuntu Linux.

There are two main parts to this process, (A) OpenShift Tools Set-up, and (B) Set-up Python Django Project for OpenShift.


(A) OpenShift Tools Set-up
 
(0) Go to OpenShift and sign up for an account.

(1) Install the rhc client tool on your local computer.
 There's some instructions provided, but it boils down to running on your command line:

$ sudo apt-get install ruby-full rubygems git-core
$ sudo gem install rhc
$ rhc  #this should now run without errors

(2)  Setup your computer to connect to the OpenShift servers.
This should be easy. Just do on the command line: rhc setup and follow the on-screen instructions.

That should really be all it takes, but note that that will upload your default public encryption key for your computer to OpenShift, namely: ~/.ssh/id_rsa.pub so you should know the password to that key pair or else you won't be able to connect to OpenShift.

If you don't want to use your default key, or some other reason, you can always create a new public/private encryption key pair and upload that (just delete the default one from OpenShift, which you can do through their web interface or on the command line).  I'll describe that next.

(3 optional) Setup new encryption keys for your computer to talk to OpenShift servers.
 IF you want to create a new public/private encryption key pair, then do the following.  I assume you have SSH installed, and I assume you have a trusted folder to fold the encryption keys in, e.g. ~/.ssh.  Then try the following on the command line:

$ cd ~/.ssh
$ ssh-keygen

This should enter you into an interactive program that will ask you for a file name and to enter a new password.  Let's name our keys' file exampleKey.  After the interactive program is done, then continue on the command line:

$ rhc sshkey add -i exampleKey -k exampleKey.pub

It should ask you to log in with you OpenShift account info. Follow the onscreen instructions and that should save your public key onto your OpenShift account

(4) Create your Python web app on OpenShift
On the command line, e.g. do rhc app create -a appName -t python-2.6 and follow the on-screen instructions.

If you missed it, you can go on the OpenShift web site to find the git repository URL for your newly created app.  It should look something like this:

ssh://123jh3hjksfd78921jk@appName-yourAccountName.rhcloud.com/~/git/appName.git/

If you were starting a new Python web app from scratch, you can git clone that repository and start there.  Otherwise you'll want to set up your existing Python web app with git instead, which I'll describe now.


(B) Set-up Python Django Project for OpenShift

(5) Set up Git for existing Python Django web project
Let's assuming you have a Python Django web app project folder called pyAppProj and it's already a git repository that's tracking a Github repository.  This means that git push origin master will push the branch master to Github.

Making it run on OpenShift will take some work: Set up Git, Set up directory structure, Set up settings files, then Set up deployment scripts.  Git is the easy part, and it's described in detail between two different sources (here, and here), but below is my condensed notes:

In terminal, cd into your pyAppProj directory.  Next, with the git repository URL on OpenShift in hand, do:

git remote add openshift ssh://123jh3hjksfd78921jk@appName-yourAccountName.rhcloud.com/~/git/appName.git/

That will add a remote called openshift that points to your OpenShift appName repository, in addition to your existing remote origin (which points to Github).

Now you have to merge the openshift/master branch with your local repository. This is potentially dangerous to your code, so be careful!  Then, still in terminal in your pyAppProj directory on your master (or whatever correct branch):

git fetch openshift
git checkout -b osmaster openshift/master
git merge master

Note that we're on the osmaster now, which tracks the openshift/master brach, and merged the origin/master branch into the local osmaster.

(6) Set up directory structure.
If you have a typical Django project, you can pretty well just follow the django-example to structure your project files.

Essentially, in terminal, cd into the directory containing your pyAppProj directory, then you have to:
  1. mv pyAppProj pyAppOpenShift # rename the existing folder
  2. mkdir pyAppOpenShift/wsgi/pyAppProj
  3. Now move everything from your pyAppOpenShift folder that you initially had (so exclude the new stuff given to you by the openshift/master branch) into the pyAppProj folder.
The reason for this musical chairs routine is to keep your git repository intact. If you know how to move the hidden git repository folder, you could probably do this more efficiently.

Your pyAppOpenShift folder should contain only the following now: data, libs, README, setup.py, and wsgi.
(7) Set up settings files.
pyAppOpenShift/setup.py:
Self explanatory. Note the install_requires array holds the kind of things pip freeze shows on the terminal.  For example:

install_requires=['Django==1.3.1', 'django-userena==1.1.2', 'django-widget-tweaks==1.1.2', 'PIL==1.1.7'],

pyAppOpenShift/wsgi/application:
Add these lines near the top of the file (after the import code):

import sys

os.environ['DJANGO_SETTINGS_MODULE'] = 'pyAppProj.settings'
sys.path.append(os.path.join(os.environ['OPENSHIFT_REPO_DIR'], 'wsgi', 'pyAppProj'))

Next, delete the entire function defined by:

def application(environ, start_response):

In the same place as the deleted function, add:

import django.core.handlers.wsgi

application = django.core.handlers.wsgi.WSGIHandler()

pyAppOpenShift/wsgi/pyAppProj/settings.py:
Finally, the hard part.  Add import os if it's not there already.  You will want your settings to change depending on if it's running on OpenShift or not.  This will help:

ON_OPENSHIFT = False
if os.environ.has_key('OPENSHIFT_REPO_DIR'):
    ON_OPENSHIFT = True

It helps because where your database is stored will need to change, if you are using SQLite3 as the database backend.  It has to be placed in the persistent data directory pointed to by OPENSHIFT_DATA_DIR, so e.g.:

DATABASE_PATH = os.path.join('path','to','local','theDatabase.db')
if ON_OPENSHIFT:
    DATABASE_PATH = os.path.join(os.environ['OPENSHIFT_DATA_DIR'], 'theDatabase.db')

Then use DATABASE_PATH in setting the DATABASES settings.

Similarly for the "media" directory (assuming you had PROJECT_ROOT set to the absolute directory of pyAppProjnot pyAppOpenShift):

MEDIA_ROOT = os.path.join(PROJECT_ROOT, 'media')
if ON_OPENSHIFT:
    MEDIA_ROOT = os.path.join(os.environ['OPENSHIFT_DATA_DIR'], 'media')

Similarly for STATIC_ROOT, which should now point to pyAppOpenShift/wsgi/static (again, assuming you had PROJECT_ROOT set to the absolute directory of pyAppProjnot pyAppOpenShift):

STATIC_ROOT = os.path.join(PROJECT_ROOT, '..', 'static')

(8) Set up deployment scripts
OpenShift uses bash scripts to let you control how the web app is deployed when pushed onto the server.  The scripts are located in pyAppOpenShift/.openshift/action_hooks.  You should look through the examples in django-example.

Depending on whether you are using SQLite3 or MySQL database backends, you'll do things differently.  If SQLite3, the examples in django-example shows you how to copy a working "starter" database (that must be checked into your git repository) into the persistent OPENSHIFT_DATA_DIR directory.

Regardless, the examples in django-example shows you how to run syncdb each time you deploy to OpenShift.

(9) Deploy the thing!

In terminal, cd into your pyAppOpenShift directory.  If you followed the above instructions, you should be on git branch osmaster.  Assuming you have checked in and committed all the above changes into the git repository on branch osmaster, then:

git push openshift osmaster:master

Enter your OpenShift account info if it asks for it, and it should otherwise just work — it will printed out all kinds of diagnostic info on your terminal, so you should scan through it to make sure no errors occurred.

And that's it.

Visit your Python Django web app on  appName-yourAccountName.rhcloud.com

No comments: