Continuously deploying your Flask/Python code to your Linux production server with GitHub webhooks

In this article I will describe how you can deploy your Flask or python code in your GitHub Repository to your Linux production server as soon as you have committed a change.

What is a GitHub Webhook?
GitHub Webhooks allow you to set triggers for specific events like a PUSH to your GitHub repository. When an event occurs GitHub will send a HTTP POST payload which contains data regarding your commit to the URL you have configured in your webhook settings.

To Continuously Deploy your Flask/Python code to your Linux production server you need to:

  1. Write a Flask GitHub Webhook handler script that will pull changes to your production server when it receives the payload from GitHub.
  2. Add a GitHub Webhook which will notify your script that an event such as PUSH has occurred on your GitHub repository.

Step 1: Creating and deploying the Flask GitHub WebHook handler script

#Compare the HMAC hash signature
def verify_hmac_hash(data, signature):
    GitHub_secret = bytes('some secret', 'UTF-8')
    mac = hmac.new(GitHub_secret, msg=data, digestmod=hashlib.sha1)
    return hmac.compare_digest('sha1=' + mac.hexdigest(), signature)

#Flask route that will process the payload
@app.route("/payload", methods=['POST'])
def GitHub_payload():
    signature = request.headers.get('X-Hub-Signature')
    data = request.data
    if verify_hmac_hash(data, signature):
        if request.headers.get('X-GitHub-Event') == "ping":
            return jsonify({'msg': 'Ok'})
        if request.headers.get('X-GitHub-Event') == "push":
            payload = request.get_json()
            if payload['commits'][0]['distinct'] == True:
                try:
                    cmd_output = subprocess.check_output(
                        ['git', 'pull', 'origin', 'master'],)
                    return jsonify({'msg': str(cmd_output)})
                except subprocess.CalledProcessError as error:
                    return jsonify({'msg': str(error.output)})

    else:
        return jsonify({'msg': 'invalid hash'})

The complete code is available at https://GitHub.com/Leo-g/Flask-GitHub-Webhooks/blob/master/GitHub-webhook.py .

The first function in our GitHub Webhook Handler is a hash compare. While configuring a webhook you will need to set a  secret  which will be used to generate a hash signature. GitHub will send this hash signature along with each request in the headers as “X-Hub-Signature”. Comparing the hash signature is the recommended way to secure your repository and ensure that the request came from your GitHub repository. GitHub uses a HMAC hexdigest to compute a hash signature, hence I have used the hmac module to generate and compare hashes, you can read more about the module and its methods in the docs at the end of the article.

Next I defined an endpoint for the URL where I want to receive the GitHub payload via Flask routes
“@app.route(“/payload”, methods=['POST'])” . A POST request to this URL will call the function GitHub_payload(). The function GitHub_payload() will first verify the hash signature and then return a response accordingly for the PING and PUSH events. In case of a PUSH event it will also run the “git pull “ command. The output of the command will be returned in the response. This will allow you to check if the pull was a success or not.

Deploying the script on your Linux production server

First Clone the script

   [leo@linux-production]$ git clone git@GitHub.com:Leo-g/Flask-GitHub-Webhooks-Handler.git

Next install flask

[leo@linux-production]$ cd    Flask-GitHub-Webhooks-Handler
[leo@linux-production Flask-GitHub-Webhooks]$ pip install -r requirements.txt         

Set your secret in an environment variable named GitHub_SECRET

[leo@linux-production Flask-GitHub-Webhooks]$ export GitHub_SECRET="some secret"

Add your IP address

[leo@linux-production Flask-GitHub-Webhooks]$ vim GitHub-webhook.py

app.run(host="YourIP")

Run the script

[leo@linux-production Flask-GitHub-Webhooks]$ python3.4 GitHub-webhook.py 
 * Running on http://YourIP:5000/ (Press CTRL+C to quit)
 * Restarting with stat

Step 2: Adding a GitHub webhook to your repository

To add a GitHub WebHook to your repository you need to go to
https://GitHub.com/Leo-g/Flask-GitHub-Webhooks-Handler/settings/hooks (Replace Flask-GitHub-Webhooks-Handler  with the name of your repository)


flask github webhook handler

Here you need to fill out the following fields:
Payload URL : Add “yourdomain.com/payload”
Content type : Select json
Secret : Add the same secret you used in your script to generate the HMAC hash.
Which events you like to trigger this webhook? : Select the push event for this tutorial.

Select the Active checkbox and click on Add webhook to start receiving notifications.

You should immediately receive a ping event.

If you received a “200 ok” response then you should be able to continuous deploy your GitHub code to your Linux production server in the event of a PUSH..( Make sure to add this script in the directory which contains your git repo information)

flask github webhook handler

Here is video of the whole process.

Video

References:

https://developer.GitHub.com/webhooks/securing/

http://githooks.com/

https://developer.GitHub.com/webhooks/

https://docs.python.org/3/library/hmac.html

Many to Many Relationships with Flask-SQLALchemy

Many to Many Relationships with Flask-SQLALchemyIn my earlier post I described how to create  a One to Many relationship with Flask-SQLAlchemy . In this post I will describe how to create a Many to Many relationship with Flask-SQLAlcehmy . Defining a Many to Many relationship. A  Many to Many Relationship between two entities can be defined as one in which a... Read More »

One to Many Relationships with Flask-SQLAlchemy

One to Many Relationships with Flask-SQLAlchemyWhile building database applications with Flask-SQLAlchemy, you will come across a situation where you need to define a relationship between two database tables. While creating blogging application I came across such a situation where I had to define a One to Many Relationship between a blog post (Post Table) and post comments(Comments Table). In order... Read More »

Python PostgreSQL example

Python PostgreSQL exampleIn this post I will describe how you can connect to a  PostgreSQL database  with Psycop2 , SQLAlchemy and Flask. Software versions Python 3.4 PostgreSQL 9.3 Flask 0.10.1 Flask-SQLAlchemy 2.0 psycopg2 2.6 SQLAlchemy 0.9.9 Ubuntu Linux 14.4 Install PostgreSQL 9 on Ubuntu Linux Psycop2 Psycop2 is  a PostgreSQL adapter for python. You don’t need Flask or SQLAlchemy to... Read More »

Launching your Flask web application on Linux with Gunicorn and Nginx

Launching your Flask web application on Linux  with Gunicorn and NginxFlask is a web framework for python, Flask tackles Routing, HTML template rendering, Sessions etc. If you are building web applications on Linux then I highly recommend using Flask, here’s how quickly you can build an app with it on Linux. The inbuilt server with Flask is good for development, but sooner or later you... Read More »

How to install Selenium on Linux and automate your web tests

How to  install Selenium on Linux and automate your web testsSelenium is a web testing toolkit that allows you to test a web application in any browser of your choice. It does this with the help of a software called WebDriver which allows you to emulate a web browser and test your web application in it. In this post I am going to show you... Read More »

How to start building websites on Linux with Django

How to start building websites on Linux with DjangoDjango is a web framework for python. It provides you with the basic components that are required to build your website like HTML templates, User Authentication, Web Server etc. In this tutorial I will describe how you can install Django 1.7 on Linux with the latest version of Python and PostgreSQl. Software Versions Linux(CentOS 6.5)... Read More »

How to build CRUD app with Python, Flask, SQLAlchemy and MySQL

In this post I will briefly describe, how you can you build a database driven CRUD (Create, Read, Update, Delete) app on Linux with Python, Flask, SQLAlchemy and MySQL. I used this process to create a blog and hence the examples below will describe how to store and modify posts in a MySQL database. You... Read More »

Managing Linux server configs with the SaltStack

Managing Linux server configs with the SaltStackI came across Salt while searching for an alternative to Puppet. I like puppet, but I am falling in love with Salt :). This maybe a personal opinion but I found Salt easier to configure and get started with as compared to Puppet. Another reason I like Salt is that it let’s you manage your... Read More »

Creating your first Linux App with Python 3 and Flask

Creating your first  Linux  App with  Python 3 and FlaskWhether playing on Linux or working on Linux there is a good chance you have come across a program written in python. Back in college I wish they thought us Python instead of Java, it’s fun to learn and useful in building practical applications like the yum package manager. In this tutorial I will take... Read More »