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
diff --git a/doc/source/zuul.rst b/doc/source/zuul.rst
index 961c964..25c2087 100644
--- a/doc/source/zuul.rst
+++ b/doc/source/zuul.rst
@@ -166,6 +166,10 @@
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:
diff --git a/zuul/launcher/jenkins.py b/zuul/launcher/jenkins.py
index 8feea02..1841a92 100644
--- a/zuul/launcher/jenkins.py
+++ b/zuul/launcher/jenkins.py
@@ -49,9 +49,9 @@
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 @@
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):
diff --git a/zuul/model.py b/zuul/model.py
index 57810b9..aa55561 100644
--- a/zuul/model.py
+++ b/zuul/model.py
@@ -27,6 +27,7 @@
"""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 @@
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 @@
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
diff --git a/zuul/scheduler.py b/zuul/scheduler.py
index d7fd544..aa3f8ab 100644
--- a/zuul/scheduler.py
+++ b/zuul/scheduler.py
@@ -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 @@
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 @@
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")