Beginners Guide to Writing Flask Apps on OpenShift

January 8, 2013
By
Author: 

Beginners Guide to Writing Flask Apps on OpenShift

In my previous blog How-to Install and Configure a Python Flask Dev Environment & Deploy to OpenShift I demonstrated how to prepare your local development environment for developing python apps. I also showed you how to create a simple “hello world” app and deploy it on OpenShift. As I mentioned in my previous blog I hate “hello world” apps and in this blog I’ll happily show you how to wack out or delete the silly “hello world” app that we previously created. I’ll show you how to create a new app that we will continue to enhance in future blogs. We’ll also start hacking on a new flask app that will be much kooler than the previous “hello world” app and I’ll do my best to explain the key components of flask and how to use them.

In this tutorial I assume that you are familiar with the following:

Goodbye “hello world”

There are two ways to delete existing OpenShift applications. You can invoke the delete app command via the web interface console from the OpenShift site or you can use the rhc console tool. I randomly use both methods to delete apps so I will briefly walk through both.

Delete an app using the Web Interface

In this example I’m going to delete an app that I have named “flasktut”

  • Sign into the OpenShift site
  • After successfully signing in you should see a list of your existing apps if not click the “MY APPS” item on the top right of the browser.
  • Find the app you intend to delete in the list and click the “>” character displayed to the far right
  • You should now see the app details and on the far right, under the “Need Help” pane, click the “Delete this Application” button
  • Here you will be asked to confirm your “Delete” intentions. Be aware that this is permanent and your application and data will be lost forever. Click the red “Delete” button

And that’s how you delete an app using the Web Interface but my favorite way to kill these apps is to use the rhc tools in the console so lets move on to deleting an app with rhc tools.

Delete an app with rhc tools###delete

In this example open a terminal or console and type:

$ rhc app delete -a flasktut

$ Password: <Enter your OpenShift Password>

$  !!!! WARNING !!!! WARNING !!!! WARNING !!!! You are about to delete the flasktut application. This is NOT reversible, all remote data for this application will be removed.

Do you want to delete this application (y/n): <Type "y" here>

$ RESULT: Successfully deleted application: flasktut

And that’s how you wack out apps in OpenShift. Don’t be sad about all the digital carnage that you just unleashed because you are going to redeem yourself shortly by creating a new and improved app for the world to enjoy.

New and improved flask application

We’re going to create our new app that we’ll hack on in this blog. Since I already posted a thorough blog on how to prep your local dev environments for Flask & OpenShift we’re going to use super quick instructions on setting up our new app. If you need explanations for some of the commands I suggest you read my previous How-to Blog which has more detail.

In this tutorial my new app will be called “mynotes” which is an app that I can use to record some thoughts or ideas & that I can access online if I need to. You can name your app whatever you like just make sure you replace your app’s name in the command texts of this tutorial.

Let’s create our new app using rhc commands in a terminal:

$ rhc app create -a mynotes -t python-2.6

$ cd mynotes

$ git remote add upstream -m master git://github.com/openshift/flask-example.git

$ git pull -s recursive -X theirs upstream master

$ git push

$ cd wsgi/

$ virtualenv venv --python=python2.6

Activate the python virtual environment on your local box

$ source /venv/bin/activate

The (venv) text must be displayed in front of your bash $ prompt

$ pip install flask

Let’s tell git to ignore our “venv” folder. We don’t need to version control it.

$ echo "venv/" >> ../.gitignore

$ mkdir templates

Now we are going to remove a file that was installed by default.

$ git rm myflaskapp.py  

Here we’re going to configure our application to use a run.py file so fire up your text editor of choice and modify the last line in the application file to look like the text below & save it:

from run import app as application

Next we create the run.py file so in terminal type:

$ touch run.py

I will break the run.py source down for you later in this blog. Right now we need some content to ensure our environment is correctly configured.

Open run.py in an editor and add the following code:

import os
from flask import Flask
from flask import render_template
from flask import request

app = Flask(__name__)

#Create our index or root / route
@app.route("/")
@app.route("/index")
def index():
    return "This is the application mynote & I'm alive"

if __name__ == "__main__":
    app.run(debug = "True")

Now let’s test our local application before we commit and deploy it to OpenShift.

$ python run.py

In a web browser type: http://localhost:5000/ You should see the text “This is the application mynote & I’m alive & well” on the page. Now we can deploy this app to our OpenShift gear.

In the terminal type:

$ git add .

$ git commit -a -m "Initial staging & deployment of this app to OpenShift"

$ git push

After the git push processes are complete you should be able to see your simple application online at your app’s url.

We actually performed many tasks to get to this point but the nice thing is we won’t have to do the majority of them again as we move forward.

Now let’s learn about flask

I just want to start out by saying that if you don’t grasp a concept or get confused about something as we move forward don’t let it deter you from continuing. There are plenty of help and resources out there to assist in resolving your problems. I always hit up the OpenShift community with questions either on the OpenShift forums or the OpenShift IRC channel. I have also used the flask irc room from time to time. There are a ton of developers out there that are interested in helping others resolve their programming issues.

I started working with flask recently in order to create web applications using the python language. It took me a minute to understand what the flask framework actually was and what I needed to learn in order to use this framework. The flask project maintainers have some great documentation but they are written at higher levels with the assumption that all the readers have certain level of development experience. These assumptions suck for beginner or even experienced programmers that are crossing over to web app development. I will attempt to explain flask and it’s template system in a low level manner so that hopefully everyone get’s it.

Review the run.py file

We previously created a run.py file and this file is our application’s starting point. Let’s review this file line by line before we start changing it.

import os  
from flask import Flask  
from flask import render_template  
from flask import request

Here we’re just importing the functions from the modules that we want to use in our app. By importing only the functions we need to use our app will receive a performance boost.

app = Flask(__name__)  

Now we are setting the variable app equal to an instance of the Flask constructor.

@app.route("/")  
@app.route("/index")  

Here is some actual flask action. In this section we are creating “http” decorators and routes for any http requests made to our web app. HTTP requests occur when a browser makes a request to a website via url. The decorators allow you to specify where your requests are routed to. So if we had a url like http://mynote.com/index we would make a decorator like @app.route("/index") above a function that would then perform some action like serve up a web page.

def index():
    return "This is the application mynote & I'm alive & well"

The def index(): function specifies what the app should do when a request for http://mynote.com/index is received. In this case the index() function returns the string "This is the application mynote & I'm alive & well" I would like to point out that the @app.route("/") decorator would also perform the index() function if our application was called using this url http://mynote.com/. Note the “/” at the end of the url which signifies the root of a website. If you wanted other routes in your application to perform index() then you would declare more decorators above the function. If you would like more information on decorators and routes please visit the flask docs.

if __name__ == "__main__":
    app.run(debug = "True")

Finally we actually run our application using the app.run() function. Note that the debug = "True" values simply activate the internal flask debugger so that we can more easily debug our application via the browser. In the interest of security it’s important that you remove the “debug” values from your code prior to deploying your code online. If not you run the risk of exposing vulnerabilities in your application to malicious attackers.

Jinja2 Templates for Our app

For those of you new to the flask framework I’m going to briefly explain Jinja2 which is the default templating system that flask utilizes. Templates basically facilitate the seperation of presentation and processing of your data. Templates are web pages that have mostly static elements and integrate programming logic which produces dynamic content. I hope I haven’t lost you but I think with some examples you should get the point. I recommend that you read the docs on the Jinja2 template system checkout the docs here.

Lets Make a Template

In the /templates folder create a file named base.html

$ touch templates/base.html

Open a text editor and add the following html syntax to your base.html file and save the file:

<html>
 <head>
 </head>
 <body>
  {% block content %}{% endblock %}
 </body>
</html>

The base.html file will serve as our core template file. This file contains the {% block content %}{% endblock %} code blocks and basically serves as a place holder for the content that we will dynamically generate in our flask code. The base.html will house the general page structure elements that will be inherited by an index.html file that we’ll create shortly.

Next let’s create our index.html file that will serve up content

$ touch templates/index.html

Add the html syntax to the index.html file

<!--
The extend statement tells this file inherit the general html elements from the the base.html file
-->  
{% extends "base.html" %}  
{% block content %}  

  <h2>Welcome to MyNote</h2>  
  <hr>  
  <p>  
    <b>{{ notes.name }}</b> <br>  
    Author: {{ notes.author }} <br><br>  
    {{ notes.content }}  
  </p>  
  <hr>  

{% endblock %}

The {% extends "base.html" %} block basically tells Jinja that our index.html file is inheriting the general html elements from the base.html file. This inheritance enables us to only deal with the meat of our code within our index.html file. Again we have a {% block content %} and {% endblock %} that define the area where our html and code will live. We also added a <div> element with some text to display.

The {{ note.name }} and {{ note.content }} elements are Jinja2’s place holders for our dynamic content. We’ll be seeing a ton of these in the future.

In the next section we’re going to make quick use of our templates.

Using Templates

Now that we’ve created some templates for our app let’s put them to good use. Open your run.py file so that we can connect to our templates and display some data. The index() function is what we’re going to use to interface our python code with the index.html template that we previously created.

Modify your index() function so it looks like the example below:

@app.route("/")
@app.route("/index", methods=["GET","POST"])
def index():
    notes = { "name":"First Note Ever",
            "author":"Angel",
            "content":"This text is coming from the content field"
           }  
    return render_template("index.html",notes = notes)

Let’s save the data and see our app in action. Go to your terminal and start your app with the following command:

$ python run.py
    * Running on http://127.0.0.1:5000/
    * Restarting with reloader

Punch up http://localhost:5000 in your browser and you should see your MyNote site come to life with your first note entry.

This example shows the basics of how python, flask, Jinja templates and html integrate to generate dynamic websites. I’ll quickly cover the new code that we added to our index() function.

@app.route("/index", methods=["GET","POST"])

In the route decorator above we added a the method array and that enables this route to utilize GET and POST calls

    notes = { "name":"First Note Ever",
            "author":"Angel",
            "content":"This text is coming from the content field"
           }

Here we defined a dict variable and assigned it some data using key:value pairs. The variable will supply the data to the render_template() function that we’ll cover next.

return render_template("index.html", notes = notes)  

Finally our index() call returns the flask render_template() function that we used to specify the template to be presented which was index.html in this case. We also passed our notes dictionary in render_template() by assigning it to another notes variable that will be passed to our index.html template for use by our Jinja2 place holders {{ notes.name }} {{ notes.author }} {{ notes.content }}

Next we’ll use some of the Jinja2 control structures which add some useful functionality to your templates.

Jinja Template Control Structures

Before we begin changing templates let’s change the note variable in our index() function. We will be adding some more key:value pairs so that we can properly demo the Jinja control structures. Make the notes variable look like the example shown below:

    notes = [{ "name":"First Note Ever",
            "author":"Angel",
            "content":"This text is coming from the content field"
           },
       { "name":"Finish this Blog",
            "author":"Angel",
            "content":"Show the template control structures"

       },
       {"name":"Deploy this app to OpenShift",
            "author":"Angel",
            "content":"When finished coding this app deploy it to OpenShift"

       }]

Save the run.py file and now we can move on to outfitting our template with control structures that can handle the data elements. Open your index.html file and make it look like the example below:

<!--
The extend statement tells this file inherit the general html elements from the the base.html file
-->  
{% extends "base.html" %}  
{% block content %}  
  <h2>Welcome to MyNote</h2>  
  <hr>  
  {% for note in notes %}
  <p>  
    <b>{{ note.name }}</b> <br>  
    Author: {{ note.author }} <br><br>  
    {{ note.content }}  
  </p>  
  <hr>  
  {% endfor %}
{% endblock %}

I’m sure you noticed that we added the {% for note in notes %} ... {% endfor %} structures that basically iterate through our notes dictionary array that was passed from the index() function in our run.py file. Save the file and browse to http://localhost:5000 to witness the for loop in action.

If all went well you should see a list of new notes that reflect the information listed in our notes variable. We now have a functional flask app that we can push to OpenShift for the world to see.

The goal here was to demonstrate control structures in the Jinja template engine and their basic usage. I could go into more examples but I can’t do all the work for you so take a look at the Jinja2 Template Control Structure docs to further your knowledge on template control structures. You should also familiarize yourself with all of the Jinja2 documentation.

Deploy Your App to OpenShift

Now that we’ve tested our app locally it’s time for us to deploy it to OpenShift and believe it or not this is the easy part. OpenShift uses the GIT versioning tool in the application deployment process. During our app development we created some new files and before we deploy our app to OpenShift we need to add the new files and commit our changes in our GIT repository so cd into your mynote project folder and run the following commands in a terminal:

$ git add .  
$ git commit -a -m "Adding template folders and files"  
$ git push

The app has now been published to the web for the world to consume. Go to your applications url and see it in all of it’s glory on the web which should be similar to the following yourappname-yournamespace.rhcloud.com.

SSH and SCP into OpenShift Gears

If your code has no bugs your app should be alive and well on the web. I can almost guarantee you this won’t always be the case during your programming career. Occasionally you will develop an app and it will perform flawlessly in your dev environment and when you deploy it to OpenShift your app will not function for some mysterious reason. From my experience most of these issues are derived from restricted access or missing dependencies/functionality in your OpenShift gear. OpenShift operates on secure servers and by design restricts access to many things that you can control in your dev environment. So you’re probably asking yourself “How do I resolve these deployment issues on OpenShift?” Its a reasonable question with a simple answer; check the relative logs to trace the root of your problem.

Fortunately OpenShift allows SSH and SCP access to your gears so that you can actually login to your gear and administer your server. Again your access rights are more restricted than your dev environment but you should have the appropriate access you need to resolve most of your issues.

In order to gain SSH or SCP access to your system you’re going to need your apps UUID if you forgot your UUID you can always retrieve by using via the rhc client in a terminal like this

$ rhc domain show

This will show you most of the details regarding all of your existing applications. What you will need is the UUID for the app that you want to ssh into. Once we have the UUID you will be able to ssh into your OpenShift gear by using a form of the following command. You will need to replace the yourUUID, yourAPP, yourDOMAIN bits with your particular data:

$ ssh yourUUID@yourAPP-yourDOMAIN.rhcloud.com

Upon successful login you should see the following message:

Welcome to OpenShift shell

This shell will assist you in managing OpenShift applications.

!!! IMPORTANT !!! IMPORTANT !!! IMPORTANT !!!
Shell access is quite powerful and it is possible for you to
accidentally damage your application.  Proceed with care!
If worse comes to worst, delete your application with 'rhc app delete'
and recreate it
!!! IMPORTANT !!! IMPORTANT !!! IMPORTANT !!!

Type "help" for more info. 

Now your in the gear and can run commands within it.

I’m in my OpenShift Gear now what?

Now that you’re in you can access the data & logs in your gear. OpenShift makes use of environment variables and we’ll be using them when navigating your gear’s file system. So where do we find these variables? Run the following command while in your gear:

> env |grep OPENSHIFT_

After running this command you should see a list of all the OPENSHIFT variables and their assigned values. Below are some examples of common environment variables:

OPENSHIFT_LOG_DIR  
OPENSHIFT_TMP_DIR  
OPENSHIFT_HOMEDIR  
OPENSHIFT_INTERNAL_PORT  
OPENSHIFT_INTERNAL_IP  
OPENSHIFT_GEAR_TYPE  
OPENSHIFT_APP_NAME  
OPENSHIFT_DATA_DIR  
OPENSHIFT_APP_UUID  

Next we’re going to list the python log files by using the ls command and our newly found environment variables. When using environment variables in commands you need prefix the variable with a $. See the ls command example below:

> ls -l $OPENSHIFT_LOG_DIR

There should be a list of log files displayed on your screen now. The error logs are where the system writes errors encountered at runtime. These are useful in debugging apps on OpenShift. While logged into the gear you can view the logs by using a text editor like nano or vim but you can also download a copy of the logs via scp.

How do I download files with SCP?

Before you can download the log you must copy the log file into the folder specified in the $OPENSHIFT_DATA_DIR variable. While logged into the gear you can copy files using the following command just replace yourERRORLOGFILE with the name of the file you want to download.

> cp $OPENSHIFT_LOG_DIR/yourERRORLOGFILE $OPENSHIFT_DATA_DIR

Now in your terminal you can execute the scp command and download the log file we are interested in. Replace the youUUID and yourDOMAIN with respective values in the example below. Remember to exit your ssh session before proceeding.

$ scp youUUID@yourDOMAIN.rhcloud.com:~/app-root/data/error_log-20121215-000000-EST ~/

The scp example that you just executed is used when you want to download data from your OpenShift gear. On occasion you will need to upload data to your gear that doesn’t need to be versioned by git. A great example of why you would upload data via scp would be if you have data in a file like csv or json that you would like to import into the database in your gear.

The following example shows how to upload a csv to an OpenShift gear:

$ scp ~/test.csv youUUID@yourDOMAIN.rhcloud.com:~/app-root/data/test.csv

You will see a confirmation that the file was successfully uploaded to your gear. Now you have the basics of ssh and scp in OpenShift.

Summary

We’ve covered lots of ground and you should have a good understanding of app development with OpenShift. The exercises you’ve completed provide you a great starting point in your OpenShift endeavors.

What’s next?

In my next tutorial we’re going to learn about how to install, configure and use a MongoDB within OpenShift.

Read from Source

PaasMag

Paasmag Logo

Twitter

Paasmag Twitter

Tweets