Saturday, September 3, 2011

Live PHP demo: The OpenShfit Babygame is available in the Cloud!

I wanted to run through how to push a simple PHP application that used a MySQL database into the new OpenShift Express environment. Follow along as we show you how to do it.

You can jump right to the OpenShift Babygame if you can't wait to see it live at: http://babygame-ishereon.rhcloud.com/babygame.php.

 We will assume you have registered a user at http://www.openshift.com.


Get Babygame code
First step is to pull a copy of the BabyGame from github.

Next you will want to setup your client tools for OpenShift access as outlined in their Quick Start. I am running Fedora 15 so just had to add the yum repo and install rhc. This brings us to the point of actually getting into setup of our applications new home.

Create your domain
# We need to create the domain for Express to start setting up
# our URL with the client tooling using 
# rhc-create-domain -n domainname -l rhlogin
#
$ rhc-create-domain --help

Usage: /usr/bin/rhc-create-domain
Bind a registered rhcloud user to a domain in rhcloud.

  NOTE: to change ssh key, please alter your ~/.ssh/libra_id_rsa and
        ~/.ssh/libra_id_rsa.pub key, then re-run with --alter

  -n|--namespace   namespace   Namespace for your application(s) (alphanumeric - max 16 chars) (required)
  -l|--rhlogin     rhlogin     Red Hat login (RHN or OpenShift login with OpenShift Express access) (required)
  -p|--password    password    RHLogin password (optional, will prompt)
  -a|--alter                   Alter namespace (will change urls) and/or ssh key
  -d|--debug                   Print Debug info
  -h|--help                    Show Usage info

# So we setup one for the Babygame. Note that I already have setup my ssh keys for OpenShift,
# if you have not yet done that, then it will walk you through it.
#
$ rhc-create-domain -n ishereon -l [registered-user] -p [your-password]

OpenShift Express key found at /home/[homedir]/.ssh/libra_id_rsa.  Reusing...
Contacting https://openshift.redhat.com
Creation successful

You may now create an application.  Please make note of your local config file
in /home/[homedir]/.openshift/express.conf which has been created and populated for you.


Create your application
Next we want to create our application, which means we want to tell the OpenShift Express which stack we need. This is done with the rhc-create-app client tool.

# Let's take a look at the options available before we setup a php stack for
# our babygame app.
#
$ rhc-create-app --help
Contacting https://openshift.redhat.com to obtain list of cartridges...
 (please excuse the delay)

Usage: /usr/bin/rhc-create-app
Create an OpenShift Express app.

  -a|--app   application     Application name  (alphanumeric - max 16 chars) (required)
  -t|--type  type            Type of app to create (perl-5.10, jbossas-7.0, wsgi-3.2, rack-1.1, php-5.3) (required)
  -l|--rhlogin  rhlogin      Red Hat login (RHN or OpenShift login with OpenShift Express access) (Default: xxxxxxxxx)
  -p|--password  password    RHLogin password  (optional, will prompt)
  -r|--repo  path            Git Repo path (defaults to ./$app_name)
  -n|--nogit                 Only create remote space, don't pull it locally
  -d|--debug                 Print Debug info
  -h|--help                  Show Usage info

# It seems we can choose between several but we want the php-5.3 
# stack (called a cartridge). I provide a user, password and location 
# for the git repo to be created called 'babygame-express', see the 
# documentation for the defaults. Let's watch the magic happen!
#
$ rhc-create-app -a babygame -t php-5.3 -l [registered-user] -p [password] -r /home/[homedir]/git-projects/babygame-express

Found a bug? Post to the forum and we'll get right on it.
    IRC: #openshift on freenode
    Forums: https://www.redhat.com/openshift/forums

Attempting to create remote application space: babygame
Contacting https://openshift.redhat.com
API version:    1.1.1
Broker version: 1.1.1

RESULT:
Successfully created application: babygame

Checking ~/.ssh/config
Contacting https://openshift.redhat.com
Found rhcloud.com in ~/.ssh/config... No need to adjust
Now your new domain name is being propagated worldwide (this might take a minute)...
  retry # 1 - Waiting for DNS: babygame-ishereon.rhcloud.com
  retry # 2 - Waiting for DNS: babygame-ishereon.rhcloud.com
  retry # 3 - Waiting for DNS: babygame-ishereon.rhcloud.com
  retry # 4 - Waiting for DNS: babygame-ishereon.rhcloud.com
Pulling new repo down
Warning: Permanently added 'babygame-ishereon.rhcloud.com,174.129.64.40' (RSA) to the list of known hosts.
Confirming application babygame is available
  Attempt # 1

Success!  Your application is now published here:

      http://babygame-ishereon.rhcloud.com/

The remote repository is located here:

    ssh://14b02b5262ce41daba2a70ad4b01657b@babygame-ishereon.rhcloud.com/~/git/babygame.git/

To make changes to your application, commit to /home/[homedir]/git-projects/babygame-express/.
Then run 'git push' to update your OpenShift Express space

If we take a look at my given path to the repo we find a git-projects/babygame-express git repository! Note that if you decide to alter your domain name you will have to adjust the git repository config file to reflect where the remote repository is, see above the line with 'ssh:.....'. Also the page is already live at http://babygame-ishereon.rhcloud.com/, how about that!

It is just a splash screen to get you started, so now we move on to getting the babygame running.

First lets look at the provided README in our babygame-express project which gives some insight to the repository layout.

Repo layout
===========
php/ - Externally exposed php code goes here
libs/ - Additional libraries
misc/ - For not-externally exposed php code
../data - For persistent data (full path in environment 
             var: OPENSHIFT_DATA_DIR)
deplist.txt - list of pears to install
.openshift/action_hooks/build - Script that gets run 
               every push, just prior to starting your app

The babygame app also comes with a README file that states we need to just add the babygame.php, const.inc.php, introtext.php, and *.jpg files to a webserver, so we will place these in the git repository that was created into the php directory.

# placing our application into our express git repo.
#
$ cp babygame/babygame.php git-projects/babygame-express/php/
$ cp babygame/const.inc.php git-projects/babygame-express/php/
$ cp babygame/introtext.php git-projects/babygame-express/php/
$ cp *.jpg git-projects/babygame-express/php/

# lets see what is going on in our project, for git commands please refer to git online help.
#
$ git st

# On branch master
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
#	php/babyblue.jpg
#	php/babygame.php
#	php/babypink.jpg
nothing added to commit but untracked files present (use "git add" to track)

# now we need to add, commit and push them to the master repo.
#
$ git add php/*.jpg php/*.php
$ git st

# On branch master
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
#	new file:   php/babyblue.jpg
#	new file:   php/babygame.php
#	new file:   php/babypink.jpg
#	new file:   php/introtext.php
#	new file:   php/const.inc.php
#

$ git commit -m "Added babygame and images."

[master 8b73d1a] Added babygame and images.
 3 files changed, 364 insertions(+), 0 deletions(-)
 create mode 100644 php/babyblue.jpg
 create mode 100644 php/babygame.php
 create mode 100644 php/babypink.jpg

$ git push origin
Counting objects: 8, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 10.48 KiB, done.
Total 6 (delta 1), reused 0 (delta 0)
remote: Stopping application...
remote: Waiting for stop to finish
remote: Done
remote: Running .openshift/action_hooks/build
remote: Starting application...
To ssh://14b02b5262ce41daba2a70ad4b01657b@babygame-ishereon.rhcloud.com/~/git/babygame.git/
   ff8218d..8b73d1a  master -> master

Now we should be able to find our application online at http://babygame-ishereon.rhcloud.com/babygame.php.


Some cleanup
# clean out the default files.
#
$ git rm php/index.php

rm 'php/index.php'

$ git rm php/health_check.php

rm 'php/health_check.php'

$ git st

# On branch master
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
#	deleted:    php/health_check.php
#	deleted:    php/index.php
#

$ git commit -m "Removed default files."

[master 820db4f] Removed default files.
 0 files changed, 0 insertions(+), 2 deletions(-)
 delete mode 100644 php/health_check.php
 delete mode 100644 php/index.php  (100%)

$ git push origin
Counting objects: 5, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 384 bytes, done.
Total 2 (delta 1), reused 0 (delta 0)
remote: Stopping application...
remote: Waiting for stop to finish
remote: Done
remote: Running .openshift/action_hooks/build
remote: Starting application...
To ssh://14b02b5262ce41daba2a70ad4b01657b@babygame-ishereon.rhcloud.com/~/git/babygame.git/
   8b73d1a..820db4f  master -> master
Babygame without a database

Setup mySQL database on OpenShift
So for now we have our project on line, but the MySQL database needs to be setup. The babygame without a database is just a bunch of garbled layout and empty tables. We can't have that now can we?

Let's get our mySQL database setup on OpenShift.

# First we need to add the mysql database instance to our Express instance,
# by making use of the rhc-ctl-app client tool.
#
$ rhc-ctl-app --help

Usage: /usr/bin/rhc-ctl-app
Control an OpenShift express app

  -a|--app   application   Application name  (alphanumeric) (required)
  -l|--rhlogin rhlogin     Red Hat login (RHN or OpenShift login with OpenShift Express access) (Default: xxxxxx)
  -p|--password password   RHLogin password  (optional, will prompt)
  -c|--command command     (start|stop|restart|reload|status|destroy)
  -L|--embedded-list       List supported embedded cartridges
  -e|--embed               (add-$cartridge|remove-$cartridge) eg: add-mysql-5.1
  -b|--bypass              Bypass warnings
  -d|--debug               Print Debug info
  -h|--help                Show Usage info

# now lets add the mysql-5.1 embedded cartridge.
#
$ rhc-ctl-app -a babygame -l [registered-user] -p [password] -e add-mysql-5.1

Contacting https://openshift.redhat.com
Contacting https://openshift.redhat.com
API version:    1.1.1
Broker version: 1.1.1

RESULT:

Mysql 5.1 database added.  Please make note of these credentials:

   Root User: admin
   Root Password: XXXXXXXXX
   Database Name: babygame

Connection URL: mysql://XXX.X.X.X:3306/

Now we need to add the const.inc.php file and adjust to reflect the proper db variables. So we adjust this and push the file to our repo.

# edit our const.inc.php file to add mysql database info and set the initial birth dates.
#
$ cat const.inc.php

[skip boring parts]
// Database settings.
//
define( "DB_SERVER",    $_ENV['OPENSHIFT_DB_HOST'] );
define( "DB_USER",      $_ENV['OPENSHIFT_DB_USERNAME'] );	
define( "DB_PASSWORD",  $_ENV['OPENSHIFT_DB_PASSWORD'] );	
define( "DB_DATABASE",  "babygame" );	


# Add the config file, push to repo.
#
$ git add php/const.inc.php; git commit -m "Added mysql config file."; git push origin

[master b7f9973] Added mysql config file.
 1 files changed, 31 insertions(+), 0 deletions(-)
 create mode 100644 php/const.inc.php
Counting objects: 6, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 778 bytes, done.
Total 4 (delta 2), reused 0 (delta 0)
remote: Stopping application...
remote: Waiting for stop to finish
remote: Done
remote: Running .openshift/action_hooks/build
remote: Starting application...
To ssh://14b02b5262ce41daba2a70ad4b01657b@babygame-ishereon.rhcloud.com/~/git/babygame.git/
   820db4f..b7f9973  master -> master


Managing your mySQL database
One problem I had was that the database was created, but not the table 'guesses' that I needed. To achieve this I had to put some configuration changes into the build script that runs on each push to the repo (causing a fresh deploy of your application).

# addded this to my .openshift/action_hooks/build file in 
# the babygame project.
#
set -e

if [ -z $OPENSHIFT_DB_HOST ]
then
    echo 1>&2
    echo "Could not find mysql database.  Please run:" 1>&2
    echo "rhc-ctl-app -a $OPENSHIFT_APP_NAME -e add-mysql-5.1" 1>&2
    echo "then make a sample commit (add whitespace somewhere) and re-push" 1>&2
    echo 1>&2
    exit 5
fi

# check for database.
if ! /usr/bin/mysql -u "$OPENSHIFT_DB_USERNAME" --password="$OPENSHIFT_DB_PASSWORD" -h "$OPENSHIFT_DB_HOST" -e "show tables;" $OPENSHIFT_APP_NAME > /dev/null
then
    echo 1>&2
    echo "Could not find mysql database. " 1>&2
    echo "Creating database for application named: $OPENSHIFT_APP_NAME." 1 >&2
    /usr/bin/mysqladmin -u "$OPENSHIFT_DB_USERNAME" --password="$OPENSHIFT_DB_PASSWORD" -h "$OPENSHIFT_DB_HOST" create "$OPENSHIFT_APP_NAME"
fi

# Confirm database exists, if not create it
if ! /usr/bin/mysql -u "$OPENSHIFT_DB_USERNAME" --password="$OPENSHIFT_DB_PASSWORD" -h "$OPENSHIFT_DB_HOST" -e "select * from guesses;;" "$OPENSHIFT_APP_NAME" > /dev/null
then
    echo
    echo "Schema not found!  Importing schema from .openshift/action_hooks/baby.sql"
    echo
    /usr/bin/mysql -u "$OPENSHIFT_DB_USERNAME" --password="$OPENSHIFT_DB_PASSWORD" -h "$OPENSHIFT_DB_HOST" "$OPENSHIFT_APP_NAME" < "$OPENSHIFT_REPO_DIR/.openshift/action_hooks/baby.sql"
    echo
    echo "done."
else
    echo "Database found, skipping import."
fi

Fully configured babygame!
If you look closely you will see that I also added the baby.sql file in the same directory so that the 'guesses' table is created if needed. Now we fire up the application and add a guess!

This completes the migration of the original PHP Babygame application from a local installation to the cloud with OpenShift Express!

I will be pushing this project soon to github at https://github.com/eschabell.

Happy guessing! :-)