Add JSON status endpoint.
Can be used for nifty ajax-style status pages. Add optional description field to pipeline. Change-Id: If5db3f6945f65f038833cbf9c783de5ffef63b49 Reviewed-on: https://review.openstack.org/18579 Reviewed-by: Jeremy Stanley <fungi@yuggoth.org> Approved: James E. Blair <corvus@inaugust.com> Tested-by: Jenkins
This commit is contained in:
parent
6aea36dd35
commit
8dbd56aff0
|
@ -166,6 +166,10 @@ explanation of each of the parameters::
|
|||
This is used later in the project definition to indicate what jobs
|
||||
should be run for events in the pipeline.
|
||||
|
||||
**description**
|
||||
This is an optional field that may be used to provide a textual
|
||||
description of the pipeline.
|
||||
|
||||
**manager**
|
||||
There are currently two schemes for managing pipelines:
|
||||
|
||||
|
|
|
@ -49,9 +49,9 @@ class JenkinsCallback(threading.Thread):
|
|||
|
||||
def app(self, environ, start_response):
|
||||
request = Request(environ)
|
||||
start_response('200 OK', [('content-type', 'text/html')])
|
||||
if request.path == '/jenkins_endpoint':
|
||||
self.jenkins_endpoint(request)
|
||||
start_response('200 OK', [('content-type', 'text/html')])
|
||||
return ['Zuul good.']
|
||||
elif request.path == '/status':
|
||||
try:
|
||||
|
@ -59,8 +59,19 @@ class JenkinsCallback(threading.Thread):
|
|||
except:
|
||||
self.log.exception("Exception formatting status:")
|
||||
raise
|
||||
start_response('200 OK', [('content-type', 'text/html')])
|
||||
return [ret]
|
||||
elif request.path == '/status.json':
|
||||
try:
|
||||
ret = self.jenkins.sched.formatStatusJSON()
|
||||
except:
|
||||
self.log.exception("Exception formatting status:")
|
||||
raise
|
||||
start_response('200 OK', [('content-type', 'application/json'),
|
||||
('Access-Control-Allow-Origin', '*')])
|
||||
return [ret]
|
||||
else:
|
||||
start_response('200 OK', [('content-type', 'text/html')])
|
||||
return ['Zuul good.']
|
||||
|
||||
def jenkins_endpoint(self, request):
|
||||
|
|
|
@ -27,6 +27,7 @@ class Pipeline(object):
|
|||
"""A top-level pipeline such as check, gate, post, etc."""
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.description = None
|
||||
self.job_trees = {} # project -> JobTree
|
||||
self.manager = None
|
||||
self.queues = []
|
||||
|
@ -186,6 +187,24 @@ class Pipeline(object):
|
|||
ret += self.formatStatus(head, html=True)
|
||||
return ret
|
||||
|
||||
def formatStatusJSON(self):
|
||||
j_pipeline = dict(name=self.name,
|
||||
description=self.description)
|
||||
j_queues = []
|
||||
j_pipeline['change_queues'] = j_queues
|
||||
for queue in self.queues:
|
||||
j_queue = dict(name=queue.name)
|
||||
j_queues.append(j_queue)
|
||||
j_queue['heads'] = []
|
||||
for head in queue.getHeads():
|
||||
j_changes = []
|
||||
c = head
|
||||
while c:
|
||||
j_changes.append(self.formatChangeJSON(c))
|
||||
c = c.change_behind
|
||||
j_queue['heads'].append(j_changes)
|
||||
return j_pipeline
|
||||
|
||||
def formatStatus(self, changeish, indent=0, html=False):
|
||||
indent_str = ' ' * indent
|
||||
ret = ''
|
||||
|
@ -224,6 +243,29 @@ class Pipeline(object):
|
|||
ret += self.formatStatus(changeish.change_behind, indent + 2, html)
|
||||
return ret
|
||||
|
||||
def formatChangeJSON(self, changeish):
|
||||
ret = {}
|
||||
if hasattr(changeish, 'url') and changeish.url is not None:
|
||||
ret['url'] = changeish.url
|
||||
ret['id'] = changeish._id()
|
||||
ret['project'] = changeish.project.name
|
||||
ret['jobs'] = []
|
||||
for job in self.getJobs(changeish):
|
||||
build = changeish.current_build_set.getBuild(job.name)
|
||||
if build:
|
||||
result = build.result
|
||||
url = build.url
|
||||
else:
|
||||
result = None
|
||||
url = None
|
||||
ret['jobs'].append(
|
||||
dict(
|
||||
name=job.name,
|
||||
url=url,
|
||||
result=result,
|
||||
voting=job.voting))
|
||||
return ret
|
||||
|
||||
|
||||
class ChangeQueue(object):
|
||||
"""DependentPipelines have multiple parallel queues shared by
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import pickle
|
||||
|
@ -82,6 +83,7 @@ class Scheduler(threading.Thread):
|
|||
|
||||
for conf_pipeline in data.get('pipelines', []):
|
||||
pipeline = Pipeline(conf_pipeline['name'])
|
||||
pipeline.description = conf_pipeline.get('description')
|
||||
manager = globals()[conf_pipeline['manager']](self, pipeline)
|
||||
pipeline.setManager(manager)
|
||||
|
||||
|
@ -407,6 +409,27 @@ class Scheduler(threading.Thread):
|
|||
ret += '</pre></html>'
|
||||
return ret
|
||||
|
||||
def formatStatusJSON(self):
|
||||
data = {}
|
||||
if self._pause:
|
||||
ret = '<p><b>Queue only mode:</b> preparing to '
|
||||
if self._reconfigure:
|
||||
ret += 'reconfigure'
|
||||
if self._exit:
|
||||
ret += 'exit'
|
||||
ret += ', queue length: %s' % self.trigger_event_queue.qsize()
|
||||
ret += '</p>'
|
||||
data['message'] = ret
|
||||
|
||||
pipelines = []
|
||||
data['pipelines'] = pipelines
|
||||
keys = self.pipelines.keys()
|
||||
keys.sort()
|
||||
for key in keys:
|
||||
pipeline = self.pipelines[key]
|
||||
pipelines.append(pipeline.formatStatusJSON())
|
||||
return json.dumps(data)
|
||||
|
||||
|
||||
class BasePipelineManager(object):
|
||||
log = logging.getLogger("zuul.BasePipelineManager")
|
||||
|
|
Loading…
Reference in New Issue