You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by jo...@apache.org on 2013/02/06 22:29:51 UTC
git commit: [#5701] Added task manager to list and view MonQ tasks
Updated Branches:
refs/heads/cj/5701 [created] eb27f013c
[#5701] Added task manager to list and view MonQ tasks
Signed-off-by: Cory Johns <jo...@geek.net>
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/eb27f013
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/eb27f013
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/eb27f013
Branch: refs/heads/cj/5701
Commit: eb27f013c9e2024a864b992bbea9a34258520044
Parents: 59a9c26
Author: Cory Johns <jo...@geek.net>
Authored: Wed Feb 6 21:29:28 2013 +0000
Committer: Cory Johns <jo...@geek.net>
Committed: Wed Feb 6 21:29:28 2013 +0000
----------------------------------------------------------------------
Allura/allura/controllers/site_admin.py | 72 +++++++-
Allura/allura/lib/app_globals.py | 10 +-
Allura/allura/templates/site_admin.html | 13 +-
Allura/allura/templates/site_admin_task_list.html | 91 +++++++++
Allura/allura/templates/site_admin_task_view.html | 153 ++++++++++++++++
5 files changed, 329 insertions(+), 10 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/eb27f013/Allura/allura/controllers/site_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/site_admin.py b/Allura/allura/controllers/site_admin.py
index 8bb4f0d..b0d0cd5 100644
--- a/Allura/allura/controllers/site_admin.py
+++ b/Allura/allura/controllers/site_admin.py
@@ -1,3 +1,4 @@
+import re
import logging
from datetime import datetime, timedelta
from collections import defaultdict
@@ -6,7 +7,9 @@ from tg import expose, validate, flash, config, request
from tg.decorators import with_trailing_slash, without_trailing_slash
from ming.orm import session
import pymongo
-from pylons import c, g
+import bson
+import tg
+from pylons import c, g, request
from formencode import validators
from allura.lib import helpers as h
@@ -27,6 +30,9 @@ class W:
class SiteAdminController(object):
+ def __init__(self):
+ self.task_manager = TaskManagerController()
+
def _check_security(self):
with h.push_context(config.get('site_admin_project', 'allura'),
neighborhood=config.get('site_admin_project_nbhd', 'Projects')):
@@ -68,6 +74,7 @@ class SiteAdminController(object):
stats=stats[:int(limit)])
@expose('jinja:allura:templates/site_admin_api_tickets.html')
+ @without_trailing_slash
def api_tickets(self, **data):
import json
import dateutil.parser
@@ -151,6 +158,7 @@ class SiteAdminController(object):
return False
@expose('jinja:allura:templates/site_admin_add_subscribers.html')
+ @without_trailing_slash
def add_subscribers(self, **data):
if request.method == 'POST':
url = data['artifact_url']
@@ -174,6 +182,7 @@ class SiteAdminController(object):
return data
@expose('jinja:allura:templates/site_admin_new_projects.html')
+ @without_trailing_slash
@validate(dict(page=validators.Int(if_empty=0),
limit=validators.Int(if_empty=100)))
def new_projects(self, page=0, limit=100, **kwargs):
@@ -194,6 +203,7 @@ class SiteAdminController(object):
}
@expose('jinja:allura:templates/site_admin_reclone_repo.html')
+ @without_trailing_slash
@validate(dict(prefix=validators.NotEmpty(),
shortname=validators.NotEmpty(),
mount_point=validators.NotEmpty()))
@@ -230,3 +240,63 @@ class SiteAdminController(object):
shortname = ''
mount_point = ''
return dict(prefix=prefix, shortname=shortname, mount_point=mount_point)
+
+class TaskManagerController(object):
+
+ def _check_security(self):
+ with h.push_context(config.get('site_admin_project', 'allura'),
+ neighborhood=config.get('site_admin_project_nbhd', 'Projects')):
+ require_access(c.project, 'admin')
+
+ @expose('jinja:allura:templates/site_admin_task_list.html')
+ @without_trailing_slash
+ def index(self, page_num=1, hours=1, state=None, task_name=None, host=None):
+ now = datetime.utcnow()
+ try:
+ page_num = int(page_num)
+ except ValueError as e:
+ page_num = 1
+ try:
+ hours = int(hours)
+ except ValueError as e:
+ hours = 1
+ start_dt = now - timedelta(hours=(page_num-1)*hours)
+ end_dt = now - timedelta(hours=page_num*hours)
+ start = bson.ObjectId.from_datetime(start_dt)
+ end = bson.ObjectId.from_datetime(end_dt)
+ query = {'_id': {'$lt': start, '$gt': end}}
+ if state:
+ query['state'] = state
+ if task_name:
+ query['task_name'] = re.compile(re.escape(task_name))
+ if host:
+ query['process'] = re.compile(re.escape(host))
+
+ tasks = list(M.monq_model.MonQTask.query.find(query).sort('_id', -1))
+ for task in tasks:
+ task.project = M.Project.query.get(_id=task.context.project_id)
+ task.user = M.User.query.get(_id=task.context.user_id)
+ newer_url = tg.url(params=dict(request.params, page_num=page_num - 1)).lstrip('/')
+ older_url = tg.url(params=dict(request.params, page_num=page_num + 1)).lstrip('/')
+ return dict(
+ tasks=tasks,
+ page_num=page_num,
+ hours=hours,
+ newer_url=newer_url,
+ older_url=older_url,
+ window_start=start_dt,
+ window_end=end_dt,
+ )
+
+ @expose('jinja:allura:templates/site_admin_task_view.html')
+ @without_trailing_slash
+ def view(self, task_id):
+ try:
+ task = M.monq_model.MonQTask.query.get(_id=bson.ObjectId(task_id))
+ except bson.InvalidId as e:
+ task = None
+ if task:
+ task.project = M.Project.query.get(_id=task.context.project_id)
+ task.app_config = M.AppConfig.query.get(_id=task.context.app_config_id)
+ task.user = M.User.query.get(_id=task.context.user_id)
+ return dict(task=task)
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/eb27f013/Allura/allura/lib/app_globals.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/app_globals.py b/Allura/allura/lib/app_globals.py
index 736c297..14522aa 100644
--- a/Allura/allura/lib/app_globals.py
+++ b/Allura/allura/lib/app_globals.py
@@ -272,6 +272,12 @@ class Globals(object):
return Credentials.get()
def handle_paging(self, limit, page, default=50):
+ limit = self.manage_paging_preference(limit, default)
+ page = max(int(page), 0)
+ start = page * int(limit)
+ return (limit, page, start)
+
+ def manage_paging_preference(self, limit, default=50):
if limit:
if c.user in (None, M.User.anonymous()):
session['results_per_page'] = int(limit)
@@ -283,9 +289,7 @@ class Globals(object):
limit = 'results_per_page' in session and session['results_per_page'] or default
else:
limit = c.user.get_pref('results_per_page') or default
- page = max(int(page), 0)
- start = page * int(limit)
- return (limit, page, start)
+ return limit
def document_class(self, neighborhood):
classes = ''
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/eb27f013/Allura/allura/templates/site_admin.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin.html b/Allura/allura/templates/site_admin.html
index 25ccc18..d15daf1 100644
--- a/Allura/allura/templates/site_admin.html
+++ b/Allura/allura/templates/site_admin.html
@@ -15,12 +15,13 @@
<div id="sidebar">
<div> </div>
<ul>
- <li class="{{page=='index' and 'active' or ''}}"><a href="."><b data-icon="{{g.icons['admin'].char}}" class="ico {{g.icons['admin'].css}}"></b>Home</a></li>
- <li class="{{page=='stats' and 'active' or ''}}"><a href="stats"><b data-icon="{{g.icons['stats'].char}}" class="ico {{g.icons['stats'].css}}"></b>Stats</a></li>
- <li class="{{page=='api_tickets' and 'active' or ''}}"><a href="api_tickets"><b data-icon="{{g.icons['admin'].char}}" class="ico {{g.icons['admin'].css}}"></b>API Tickets</a></li>
- <li class="{{page=='add_subscribers' and 'active' or ''}}"><a href="add_subscribers"><b data-icon="{{g.icons['admin'].char}}" class="ico {{g.icons['admin'].css}}"></b>Add Subscribers</a></li>
- <li class="{{page=='new_projects' and 'active' or ''}}"><a href="new_projects"><b data-icon="{{g.icons['admin'].char}}" class="ico {{g.icons['admin'].css}}"></b>New Projects</a></li>
- <li class="{{page=='reclone_repo' and 'active' or ''}}"><a href="reclone_repo"><b data-icon="{{g.icons['admin'].char}}" class="ico {{g.icons['admin'].css}}"></b>Reclone repo</a></li>
+ <li class="{{page=='index' and 'active' or ''}}"><a href="{{sidebar_rel}}."><b data-icon="{{g.icons['admin'].char}}" class="ico {{g.icons['admin'].css}}"></b>Home</a></li>
+ <li class="{{page=='stats' and 'active' or ''}}"><a href="{{sidebar_rel}}stats"><b data-icon="{{g.icons['stats'].char}}" class="ico {{g.icons['stats'].css}}"></b>Stats</a></li>
+ <li class="{{page=='api_tickets' and 'active' or ''}}"><a href="{{sidebar_rel}}api_tickets"><b data-icon="{{g.icons['admin'].char}}" class="ico {{g.icons['admin'].css}}"></b>API Tickets</a></li>
+ <li class="{{page=='add_subscribers' and 'active' or ''}}"><a href="{{sidebar_rel}}add_subscribers"><b data-icon="{{g.icons['admin'].char}}" class="ico {{g.icons['admin'].css}}"></b>Add Subscribers</a></li>
+ <li class="{{page=='new_projects' and 'active' or ''}}"><a href="{{sidebar_rel}}new_projects"><b data-icon="{{g.icons['admin'].char}}" class="ico {{g.icons['admin'].css}}"></b>New Projects</a></li>
+ <li class="{{page=='reclone_repo' and 'active' or ''}}"><a href="{{sidebar_rel}}reclone_repo"><b data-icon="{{g.icons['admin'].char}}" class="ico {{g.icons['admin'].css}}"></b>Reclone Repo</a></li>
+ <li class="{{page=='task_manager' and 'active' or ''}}"><a href="{{sidebar_rel}}task_manager"><b data-icon="{{g.icons['stats'].char}}" class="ico {{g.icons['stats'].css}}"></b>Task Manager</a></li>
</ul>
</div>
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/eb27f013/Allura/allura/templates/site_admin_task_list.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin_task_list.html b/Allura/allura/templates/site_admin_task_list.html
new file mode 100644
index 0000000..20dc2d7
--- /dev/null
+++ b/Allura/allura/templates/site_admin_task_list.html
@@ -0,0 +1,91 @@
+{% set page="task_manager" %}
+{% extends 'allura:templates/site_admin.html' %}
+
+{% block extra_css %}
+<style type="text/css">
+ .paging {
+ float: right;
+ margin: 1em;
+ }
+ .paging-window {
+ margin: 1em;
+ }
+ .empty {
+ text-align: center;
+ font-style: italic;
+ }
+ #task_search_form {
+ margin-left: 1em;
+ }
+ #task_search_form label {
+ display: inline-block;
+ width: 6em;
+ }
+ #task_search_form input[type="submit"] {
+ float: none;
+ }
+ #task_list {
+ overflow: auto;
+ clear: both;
+ }
+</style>
+{% endblock %}
+
+{% macro _paging() %}
+<div class="paging">
+ {% if page_num > 3 -%}
+ <a class="newest" title="Newest" href="{{ newest_url }}"><<</a>
+ {%- endif -%}
+ {%- if page_num > 1 -%}
+ <a class="newer" title="Newer" href="{{ newer_url }}"><</a> …
+ {%- endif -%}
+ <a class="newer" title="Older" href="{{ older_url }}">></a>
+</div>
+{% endmacro %}
+
+{% block content %}
+<h2>Task Manager</h2>
+<form method="GET" id="task_search_form">
+ <label>State:</label> <input name="state" value="{{ request.params.state }}" /><br/>
+ <label>Task Name:</label> <input name="task_name" value="{{ request.params.task_name }}" /><br/>
+ <label>Host:</label> <input name="host" value="{{ request.params.host }}" />
+ <input type="submit" />
+ <input type="hidden" name="page_num" value="{{ page_num }}" />
+ <input type="hidden" name="hours" value="{{ hours }}" />
+</form>
+{{ _paging() }}
+<div class="paging-window">
+ Showing tasks from {{ window_start.strftime('%Y/%m/%d %H:%M:%S') }} to {{ window_end.strftime('%Y/%m/%d %H:%M:%S') }}...
+</div>
+<div id="task_list">
+ <table>
+ <thead>
+ <tr>
+ <th>Task Name</th>
+ <th>State</th>
+ <th>Project</th>
+ <th>User</th>
+ <th>Time Queued</th>
+ <th>Time Started</th>
+ <th>Process</th>
+ </tr>
+ </thead>
+ {% for task in tasks %}
+ <tr>
+ <td><a href="task_manager/view/{{task._id}}">{{task.task_name}}</a></td>
+ <td>{{task.state}}</td>
+ <td>{{task.project.shortname if task.project}}</td>
+ <td>{{task.user.username if task.user}}</td>
+ <td>{{task.time_queue.strftime('%Y/%m/%d %H:%M:%S') if task.time_queue}}</td>
+ <td>{{task.time_start.strftime('%Y/%m/%d %H:%M:%S') if task.time_start}}</td>
+ <td>{{task.process if task.process}}</td>
+ </tr>
+ {% else %}
+ <tr>
+ <td class="empty" colspan="7" >No tasks found</td>
+ </tr>
+ {% endfor %}
+ </table>
+</div>
+{{ _paging() }}
+{% endblock %}
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/eb27f013/Allura/allura/templates/site_admin_task_view.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin_task_view.html b/Allura/allura/templates/site_admin_task_view.html
new file mode 100644
index 0000000..2b1abee
--- /dev/null
+++ b/Allura/allura/templates/site_admin_task_view.html
@@ -0,0 +1,153 @@
+{% set page = 'task_manager' %}
+{% set sidebar_rel = '../../' %}
+{% extends 'allura:templates/site_admin.html' %}
+
+{% block extra_css %}
+<style type="text/css">
+ #task_details {
+ table-layout: fixed;
+ word-wrap: break-word;
+ border-collapse: separate;
+ border-spacing: 4px;
+ }
+ #task_details th,
+ #task_details td {
+ border: 0;
+ }
+ #task_details .first-column-headers {
+ width: 50px;
+ }
+ #task_details .first-column {
+ width: 225px;
+ }
+ #task_details .spacer {
+ width: 1px;
+ }
+ #task_details .second-column-headers {
+ width: 100px;
+ }
+ #task_details th {
+ background: #e5e5e5;
+ background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(100%, #e5e5e5));
+ background-image: -webkit-linear-gradient(#ffffff, #e5e5e5);
+ background-image: -moz-linear-gradient(#ffffff, #e5e5e5);
+ background-image: -o-linear-gradient(#ffffff, #e5e5e5);
+ background-image: -ms-linear-gradient(#ffffff, #e5e5e5);
+ background-image: linear-gradient(#ffffff, #e5e5e5);
+ text-shadow: #fff 0 1px 0;
+ border: 1px solid #aaa;
+ border-radius: 3px;
+ }
+ #task_details th.side-header {
+ text-align: right;
+ vertical-align: top;
+ padding: 4px 10px;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ }
+ #task_details td.second-column {
+ border: 0;
+ }
+</style>
+{% endblock %}
+
+{% block content %}
+{% if not task %}
+ Task not found
+{% else %}
+ <h2>Task Details</h2>
+ <table id="task_details">
+ <tr>
+ <td class="first-column-headers"></td>
+ <th class="first-column">Name</th>
+ <td class="spacer"></td>
+ <td class="second-column-headers"></td>
+ <th class="second-column">State</th>
+ </tr>
+ <tr>
+ <td class="first-column-headers"></td>
+ <td>{{ task.task_name }}</td>
+ <td class="spacer"></td>
+ <td class="second-column-headers"></td>
+ <td>{{ task.state }}</td>
+ </tr>
+ <tr>
+ <td class="first-column-headers"></td>
+ <th class="first-column">ID</th>
+ <td class="spacer"></td>
+ <td class="second-column-headers"></td>
+ <th class="second-column">Process</th>
+ </tr>
+ <tr>
+ <td class="first-column-headers"></td>
+ <td>{{ task._id }}</td>
+ <td class="spacer"></td>
+ <td class="second-column-headers"></td>
+ <td>{{ task.process if task.process }}</td>
+ </tr>
+ <tr>
+ <td class="first-column-headers"></td>
+ <th>Context</th>
+ <td class="spacer"></td>
+ <td class="second-column-headers"></td>
+ <th>Time</th>
+ </tr>
+ <tr>
+ <th class="side-header">Project</th>
+ <td>{{ task.project.shortname if task.project }}</td>
+ <td class="spacer"></td>
+ <th class="second-column-headers side-header">Queued</th>
+ <td>{{ task.time_queue.strftime('%Y/%m/%d %H:%M:%S') if task.time_queue }}</td>
+ </tr>
+ <tr>
+ <th class="side-header">Mount</th>
+ <td>{{ task.app_config.options.mount_point if task.app_config }}</td>
+ <td class="spacer"></td>
+ <th class="second-column-headers side-header">Started</th>
+ <td>{{ task.time_start.strftime('%Y/%m/%d %H:%M:%S') if task.time_start }}</td>
+ </tr>
+ <tr>
+ <th class="side-header">User</th>
+ <td>{{ task.user.username if task.user }}</td>
+ <td class="spacer"></td>
+ <th class="second-column-headers side-header">Stopped</th>
+ <td>{{ task.time_stop.strftime('%Y/%m/%d %H:%M:%S') if task.time_stop }}</td>
+ </tr>
+ <tr>
+ <td class="first-column-headers"></td>
+ <th>Args</th>
+ <td class="spacer"></td>
+ <td class="second-column-headers"></td>
+ <th>Keyword Args</th>
+ </tr>
+ {% if task.args|length > task.kwargs|length %}
+ {% set indexes = range(task.args|length) %}
+ {% else %}
+ {% set indexes = range(task.kwargs|length) %}
+ {% endif %}
+ {% set kwargs = task.kwargs.items() %}
+ {% for i in indexes %}
+ <tr>
+ <td class="first-column-headers"></td>
+ <td>{{ (task.args[i] or '')|truncate }}</td>
+ <td class="spacer"></td>
+ {% if kwargs[i] %}
+ <th class="second-column-headers side-header">{{ kwargs[i][0] }}</th>
+ <td>{{ (kwargs[i][1] or '')|truncate }}</td>
+ {% else %}
+ <td class="second-column-headers"></td>
+ <td></td>
+ {% endif %}
+ </tr>
+ {% endfor %}
+ <tr>
+ <td class="first-column-headers"></td>
+ <th colspan="4">Result</th>
+ </tr>
+ <tr>
+ <td class="first-column-headers"></td>
+ <td colspan="4"><pre>{{ task.result }}</pre></td>
+ </tr>
+ </table>
+{% endif %}
+{% endblock %}