[PYTHON] Template for Bottle when deploying with Github and Bitbucket

A template for your own Bottle.

The API for Hook on Bitbucket and Github is an API server (gunicorn registered in Upstart after pulling. )) Is restarting.

I have included GitPython for working with the Git repository.

Arrow is also included in the processing around the time.

server.py


# -*- coding: utf-8 -*-

import commands
import os.path
import traceback
from decorator import decorator
import logging
import subprocess
import getpass

from bottle import get, post, put, delete, run, default_app, request, response, HTTPError, redirect, local, abort 
from bottle import static_file, route

import arrow

from git import Repo


# Decorator

@decorator
def check_db_connection(func, *args, **kwargs):
    """
For Peewee. db is an instance of Peewee's database.
    """

    try:
        db.get_conn().ping(True)
    except:
        logging.error(traceback.format_exc())
    
    return func(*args, **kwargs)

@decorator
def check_login(func, *args, **kwargs):
    """
Write the authentication process and localize the logged-in user instance.Put it in me or something.
    """

    response_json = func(*args, **kwargs)
    return response_json

@decorator
def error_handling(func, *args, **kwargs):
    """
Returns the error in JSON format. For debugging. At the time of this release, error_class or error_Delete trace.
    """

    try:
        return func(*args, **kwargs)
    except Exception as exception:
        if issubclass(exception.__class__, HTTPError):
            raise exception
        else:
            logging.error(traceback.format_exc())

            return {
                "error_class": type(exception).__name__,
                "error_trace": traceback.format_exc(),
            }

@decorator
def measurement(func, *args, **kwargs):
    """
Measure the processing time of the API.
    """

    start_time = arrow.now()

    result = func(*args, **kwargs)

    print "Transaction time: {0} secs".format(arrow.now().float_timestamp - start_time.float_timestamp)

    return result


# API


# Static files

@route('/')
@route('/<filepath:path>')
def server_static(filepath = None):
    if filepath is None:
        filepath = 'index.html'

    root_path = u"Web root path"

    response = static_file(filepath, root = root_path)
    return response


# Pull from Bitbucket

@post('/__pull_from_bitbucket')
@error_handling
def pull_from_bitbucket():
    """
For Bitbucket integration.
With IP, limit access to this API only from Bitbucket.
    """

    repository_path = "{0}/../../..".format(os.path.dirname(__file__))
    repository = Repo(repository_path)

    payload = request.json

    logging.info("payload: {0}".format(payload))
    branch = payload['push']['changes'][0]['new']['name']

    logging.info("Pull from Bitbucket: {0}: {1}".format(
        branch, repository.active_branch.path))

    if repository.active_branch.path.endswith(branch):
        repository.remotes[0].pull()

        reboot_gunicorn_command = ["/usr/bin/sudo", "/sbin/restart", "api-server"]
        output = subprocess.check_output(reboot_gunicorn_command)
        logging.info("Reboot API server: {0}: {1}".format(
            reboot_gunicorn_command, output))

    return {
    }


# Pull from GitHub

GITHUB_HOOK_SECRET = os.environ.get('GITHUB_HOOK_SECRET')

@post('/__pull_from_github')
@error_handling
def pull_from_github():
    """
For GitHub integration.
Put the secret key of GitHub Hook in the environment variable.
    """

    sent_signature = request.headers.get('X-Hub-Signature')[5:]
    raw_payload = request.body.read()
    generated_signature = hmac.new(GITHUB_HOOK_SECRET, raw_payload, hashlib.sha1).hexdigest()

    if sent_signature == generated_signature:

        repository_path = "{0}/../../..".format(os.path.dirname(__file__))
        repository = Repo(repository_path)
    
        payload = request.json
    
        if payload['ref'] == repository.active_branch.path:
            logging.info("Pull from GitHub: {0}: {1}".format(payload['ref'], payload['head_commit']['id']))
            repository.remotes[0].pull()
    
            reboot_gunicorn_command = ["/bin/sudo", "/usr/bin/systemctl", "restart", "api_server"]
    
            logging.info("Reboot API server: {0}".format(reboot_gunicorn_command))
            return_code = subprocess.call(reboot_gunicorn_command)

    return {
    }




application = default_app()
if __name__ == '__main__':
    run(host = 'localhost', port = 8000, debug = True)

Recommended Posts

Template for Bottle when deploying with Github and Bitbucket
Display serial number columns and variables with Bottle template
How to deal with errors when installing whitenoise and deploying to Heroku
Impressions and memorandums when working with VS code for the first time
selenium: wait for element with AND / OR
Solution for errors when deploying to Heroku
Connect Scratch X and Digispark with a bottle
Recommended environment and usage when developing with Python
Causal reasoning and causal search with Python (for beginners)
This and that useful when used with nohup
Template network config generation with Python and Jinja2