Select Git revision

Benedikt von St. Vieth authored
run.py 6.36 KiB
import argparse
import logging
import os
import subprocess
import sys
import time
from datetime import datetime
from flask import Flask, render_template, request,\
send_from_directory as send_file
from flask_bootstrap import Bootstrap
from flask_sqlalchemy import SQLAlchemy
from pydoc import locate
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///logs.db'
Bootstrap(app)
db = SQLAlchemy(app)
command = ''
tokens = False
class WebhookCall(db.Model):
__tablename__ = 'webhookcall'
timestamp = db.Column(db.Integer, primary_key=True, unique=True)
repository = db.Column(db.String(20))
success = db.Column(db.Boolean)
results = db.relationship('WebhookCallResult',
backref=db.backref('webhookcall'))
def __init__(self, timestamp, repository, success):
self.timestamp = timestamp
self.repository = repository
self.success = success
def __repr__(self):
return '<WebhookCall %r>' % self.timestamp
def __gt__(self, other):
return True if int(self.timestamp) > int(other.timestamp) else False
def __lt__(self, other):
return True if int(self.timestamp) < int(other.timestamp) else False
class WebhookCallResult(db.Model):
__tablename__ = 'webhookcallresult'
id = db.Column(db.Integer, primary_key=True)
timestamp = db.Column(db.Integer, db.ForeignKey('webhookcall.timestamp'))
output = db.Column(db.String(1000))
def __init__(self, timestamp, output):
self.timestamp = timestamp
self.output = output
def __repr__(self):
return '<WebhookCallResult %r>' % self.id
def _restart():
global command
try:
output = subprocess.check_output(command.split())
except Exception as err:
output = 'Error {} while executing {}'.format(err, command)
return output
@app.route('/', methods=['POST'])
@app.route('/<hooking_repository>/', methods=['POST'])
def post_hook(hooking_repository=None):
global tokens
if tokens:
if not authenticate(tokens, request):
return 'Access forbidden', 403
for item in request.headers:
logging.debug(item)
if hooking_repository:
if len(hooking_repository) < 20:
repository = hooking_repository
else:
repository = hooking_repository[0:20]
else:
repository = 'unknown'
if assess_reload(request):
current_time = int(time.time())
output = _restart()
success = False if output.startswith('Error') else True
output = output.strip()
item = WebhookCall.query.filter_by(timestamp=current_time).first()
if not item:
db.session.add(WebhookCall(current_time, repository, success))
db.session.add(WebhookCallResult(timestamp=current_time,
output=output))
else:
db.session.add(WebhookCallResult(timestamp=current_time,
output=output))
db.session.commit()
response = 'Executed restart action at {} with output:\n{}'\
.format(format_datetime(current_time), output)
if success:
return response, 201
else:
return response, 500
else:
return 'OK', 200
@app.route('/', methods=['GET'])
@app.route('/logs/', methods=['GET'])
def get_logs():
return render_template('logs.html', content=WebhookCall.query.all())
@app.route('/<log_id>/', methods=['GET'])
@app.route('/logs/<log_id>', methods=['GET'])
def get_log(log_id):
logs = WebhookCallResult.query.filter(
WebhookCallResult.timestamp == log_id).all()
if logs:
return render_template('log.html', timestamp=log_id, logs=logs)
else:
return '', 404
@app.route('/favicon.ico')
def favicon():
return send_file(os.path.join(app.root_path, 'static'), 'favicon.ico')
@app.template_filter('datetime')
def format_datetime(value):
return datetime.fromtimestamp(int(value))\
.strftime("%Y-%m-%d_%H-%M-%S")
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("--command",
help="reload command that should be executed")
parser.add_argument("--debug",
help="get debug output",
action="store_true")
parser.add_argument("--logstash",
help="log everything (in addition) to logstash "
", give host:port")
parser.add_argument("--tokens",
help="use tokens for authenticating a remote service")
parser.add_argument("--port",
help="port to use for listening")
parser.add_argument("--hooker",
help="which service is hooking? github,gitlab,travis")
args = parser.parse_args()
if args.debug:
logging.basicConfig(format='%(message)s', level=logging.DEBUG)
debug = True
else:
logging.basicConfig(format='%(message)s', level=logging.INFO)
debug = False
logger = logging.getLogger()
logger.addHandler(logging.StreamHandler())
if args.logstash:
try:
import logstash
host, port = args.logstash.split(':')
logger.addHandler(logstash.TCPLogstashHandler(host=host,
port=int(port),
version=1))
except ImportError as err:
logging.error('Logstash module not available %s', err)
if args.hooker:
try:
global authenticate
authenticate = locate('hooker.{}.authenticate'.format(args.hooker))
global assess_reload
assess_reload = locate('hooker.{}.assess_reload'.format(args.hooker))
except ImportError as err:
logging.error('Logstash module not available %s', err)
else:
logging.error('--hooker is required, gitlab/github/travis')
exit(1)
if args.tokens:
global tokens
tokens = args.tokens
if args.command:
global command
command = args.command
else:
logging.error('--command <script> is required for this webhook')
exit(1)
if args.port:
port = int(args.port)
else:
port = 7010
db.create_all()
app.run(host='0.0.0.0', port=port, debug=debug, use_reloader=False)