web: add /{tenant}/jobs route
This change adds the 'job:list' job to the scheduler gearman worker to expose the tenant jobs list. This change also adds the /{tenant}/jobs.json endpoint to the zuul-web as well as a /{tenant}/jobs.html web interface and command line client: zuul show jobs $tenant Change-Id: I950cb6a809a360867b2daccded9a8a45ac46359c
This commit is contained in:
parent
2623731dc6
commit
be0441a839
|
@ -517,6 +517,7 @@ class JobParser(object):
|
|||
# "job.run.append(...)").
|
||||
|
||||
job = model.Job(name)
|
||||
job.description = conf.get('description')
|
||||
job.source_context = conf.get('_source_context')
|
||||
job.source_line = conf.get('_start_mark').line + 1
|
||||
|
||||
|
|
|
@ -858,6 +858,7 @@ class Job(object):
|
|||
source_line=None,
|
||||
inheritance_path=(),
|
||||
parent_data=None,
|
||||
description=None,
|
||||
)
|
||||
|
||||
self.inheritable_attributes = {}
|
||||
|
|
|
@ -58,6 +58,7 @@ class RPCListener(object):
|
|||
self.worker.registerFunction("zuul:get_job_log_stream_address")
|
||||
self.worker.registerFunction("zuul:tenant_list")
|
||||
self.worker.registerFunction("zuul:status_get")
|
||||
self.worker.registerFunction("zuul:job_list")
|
||||
|
||||
def getFunctions(self):
|
||||
functions = {}
|
||||
|
@ -283,3 +284,17 @@ class RPCListener(object):
|
|||
args = json.loads(job.arguments)
|
||||
output = self.sched.formatStatusJSON(args.get("tenant"))
|
||||
job.sendWorkComplete(output)
|
||||
|
||||
def handle_job_list(self, job):
|
||||
args = json.loads(job.arguments)
|
||||
tenant = self.sched.abide.tenants.get(args.get("tenant"))
|
||||
output = []
|
||||
for job_name in sorted(tenant.layout.jobs):
|
||||
desc = None
|
||||
for tenant_job in tenant.layout.jobs[job_name]:
|
||||
if tenant_job.description:
|
||||
desc = tenant_job.description.split('\n')[0]
|
||||
break
|
||||
output.append({"name": job_name,
|
||||
"description": desc})
|
||||
job.sendWorkComplete(json.dumps(output))
|
||||
|
|
|
@ -162,6 +162,7 @@ class GearmanHandler(object):
|
|||
self.controllers = {
|
||||
'tenant_list': self.tenant_list,
|
||||
'status_get': self.status_get,
|
||||
'job_list': self.job_list,
|
||||
}
|
||||
|
||||
def tenant_list(self, request):
|
||||
|
@ -182,6 +183,11 @@ class GearmanHandler(object):
|
|||
resp.last_modified = self.cache_time[tenant]
|
||||
return resp
|
||||
|
||||
def job_list(self, request):
|
||||
tenant = request.match_info["tenant"]
|
||||
job = self.rpc.submitJob('zuul:job_list', {'tenant': tenant})
|
||||
return web.json_response(json.loads(job.data[0]))
|
||||
|
||||
async def processRequest(self, request, action):
|
||||
try:
|
||||
resp = self.controllers[action](request)
|
||||
|
@ -224,12 +230,17 @@ class ZuulWeb(object):
|
|||
async def _handleStatusRequest(self, request):
|
||||
return await self.gearman_handler.processRequest(request, 'status_get')
|
||||
|
||||
async def _handleJobsRequest(self, request):
|
||||
return await self.gearman_handler.processRequest(request, 'job_list')
|
||||
|
||||
async def _handleStaticRequest(self, request):
|
||||
fp = None
|
||||
if request.path.endswith("tenants.html") or request.path.endswith("/"):
|
||||
fp = os.path.join(STATIC_DIR, "index.html")
|
||||
elif request.path.endswith("status.html"):
|
||||
fp = os.path.join(STATIC_DIR, "status.html")
|
||||
elif request.path.endswith("jobs.html"):
|
||||
fp = os.path.join(STATIC_DIR, "jobs.html")
|
||||
headers = {}
|
||||
if self.static_cache_expiry:
|
||||
headers['Cache-Control'] = "public, max-age=%d" % \
|
||||
|
@ -251,7 +262,9 @@ class ZuulWeb(object):
|
|||
('GET', '/console-stream', self._handleWebsocket),
|
||||
('GET', '/tenants.json', self._handleTenantsRequest),
|
||||
('GET', '/{tenant}/status.json', self._handleStatusRequest),
|
||||
('GET', '/{tenant}/jobs.json', self._handleJobsRequest),
|
||||
('GET', '/{tenant}/status.html', self._handleStaticRequest),
|
||||
('GET', '/{tenant}/jobs.html', self._handleStaticRequest),
|
||||
('GET', '/tenants.html', self._handleStaticRequest),
|
||||
('GET', '/', self._handleStaticRequest),
|
||||
]
|
||||
|
|
|
@ -30,3 +30,16 @@ angular.module('zuulTenants', []).controller(
|
|||
}
|
||||
$scope.tenants_fetch();
|
||||
});
|
||||
|
||||
angular.module('zuulJobs', []).controller(
|
||||
'mainController', function($scope, $http)
|
||||
{
|
||||
$scope.jobs = undefined;
|
||||
$scope.jobs_fetch = function() {
|
||||
$http.get("jobs.json")
|
||||
.then(function success(result) {
|
||||
$scope.jobs = result.data;
|
||||
});
|
||||
}
|
||||
$scope.jobs_fetch();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<!--
|
||||
Copyright 2017 Red Hat
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
not use this file except in compliance with the License. You may obtain
|
||||
a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Zuul Builds</title>
|
||||
<link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="../static/styles/zuul.css" />
|
||||
<script src="/static/js/jquery.min.js"></script>
|
||||
<script src="/static/js/angular.min.js"></script>
|
||||
<script src="../static/javascripts/zuul.angular.js"></script>
|
||||
</head>
|
||||
<body ng-app="zuulJobs" ng-controller="mainController"><div class="container-fluid">
|
||||
<nav class="navbar navbar-default">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand" href="../" target="_self">Zuul Dashboard</a>
|
||||
</div>
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="status.html" target="_self">Status</a></li>
|
||||
<li class="active"><a href="jobs.html" target="_self">Jobs</a></li>
|
||||
<li><a href="builds.html" target="_self">Builds</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<table class="table table-hover table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Last builds</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="job in jobs">
|
||||
<td>{{ job.name }}</td>
|
||||
<td>{{ job.description }}</td>
|
||||
<td><a href="builds.html?job_name={{ job.name }}">builds</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></body></html>
|
Loading…
Reference in New Issue