webfabric / webfabric.py

import os
import sys
import sqlite3
import datetime
from flask import Flask, request, session, g, redirect, url_for, \
     abort, render_template, flash, jsonify
import json
from fabric import main
import fabric
from multiprocessing import Process


# default configuration
FABFILE = 'fabfile.py'
LOG_DIR = os.path.join(os.path.dirname(__file__), 'static', 'logs')
DATABASE = os.path.join(os.path.dirname(__file__), 'logs.sqlite')

FABRIC_USER = None
FABRIC_KEY_FILENAME = None

app = Flask(__name__)
app.config.from_object(__name__)
app.config.from_pyfile('config.cfg', silent=True)


def connect_db():
    conn = sqlite3.connect(app.config['DATABASE'])
    conn.row_factory = sqlite3.Row
    return conn


def init_db():
    conn = connect_db()
    with app.open_resource('schema.sql') as f:
        conn.cursor().executescript(f.read())
    conn.commit()

@app.before_request
def before_request():
    g.db = connect_db()


@app.teardown_request
def teardown_request(exception):
    g.db.close()


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

    docstring, tasks, default = main.load_fabfile(app.config['FABFILE'])
    data = {
       'docstring': docstring,
       'tasks': tasks,
       'default': default,
       'fabfile': app.config['FABFILE'],
    }
    return render_template('index.html', **data)


@app.route("/logs")
def logs():

    SELECT_LOGS = """SELECT * FROM logs
    ORDER BY start DESC LIMIT 20"""
    cur = g.db.execute(SELECT_LOGS)

    logs = cur.fetchall()

    data = {
       'logs': logs,
    }
    return render_template('logs.html', **data)


def run_task(code, taskname):

    fabric.state.env['user'] = app.config['FABRIC_USER']
    fabric.state.env['key_filename'] = app.config['FABRIC_KEY_FILENAME']
    fabric.state.env['abort_on_prompts'] = True

    docstring, tasks, default = main.load_fabfile(app.config['FABFILE'])

    task = tasks[taskname]

    _stdout = sys.stdout
    _stderr = sys.stderr

    logfilename = os.path.join(app.config['LOG_DIR'], '%s.txt' % code)
    logfile = open(logfilename, 'w', 0)

    sys.stdout = logfile
    sys.stderr = logfile

    try:
        fabric.tasks.execute(
                task,
                hosts=[],
                roles=[],
                exclude_hosts=[],
            )
    except Exception, e:
        print "ERROR: ", e
    finally:
        # ignore task errors
        sys.stdout = _stdout
        sys.stderr = _stderr

        logfile.close()

        UPDATE = "UPDATE logs SET end=? WHERE id=?"
        db = connect_db()
        cursor = db.cursor()
        cursor.execute(UPDATE, (datetime.datetime.now(), code))
        db.commit()
    return


@app.route("/output")
def output():
    code = request.args['code']

    #SELECT_LOGS = """select id, taskname, user, start, end from logs
    #order by start desc limit 20"""

    logfilename = os.path.join(app.config['LOG_DIR'], '%s.txt' % code)
    output = open(logfilename).read()

    SELECT = "SELECT * FROM logs WHERE id=?"
    cursor = g.db.cursor()
    cursor.execute(SELECT, (code,))
    row = cursor.fetchone()
    g.db.commit()

    finished = row['end'] != None

    log = {
        'code': row['id'],
        'start': str(row['start']),
        'end': row['end'] and str(row['end']) or None,
        'user': row['user'],
        'taskname': row['taskname'],
    }

    return jsonify({'out': output, 'finished': finished, 'log': log})


@app.route("/run", methods=['POST'])
def run():
    taskname = request.form['task']

    start = datetime.datetime.now()
    user = ''
    if hasattr(request, 'remote_user') and request.remote_user:
        user = request.remote_user
    INSERT = """INSERT INTO logs
    (taskname, user, start) VALUES (?, ?, ?)"""

    cursor = g.db.cursor()
    cursor.execute(INSERT, (taskname, user, start))
    rowid = cursor.lastrowid
    g.db.commit()

    p = Process(target=run_task, args=(rowid, taskname))
    p.start()

    return jsonify({'task': taskname, 'code': rowid})


if __name__ == "__main__":
    app.run(host='0.0.0.0', debug=True)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.