diff --git a/nodepool/status.py b/nodepool/status.py index d9a3fa39b..1283d358f 100644 --- a/nodepool/status.py +++ b/nodepool/status.py @@ -14,6 +14,7 @@ # License for the specific language governing permissions and limitations # under the License. +import json import time from nodepool import nodedb @@ -61,6 +62,20 @@ def dib_image_list(zk): return str(t) +def dib_image_list_json(zk): + objs = [] + for image_name in zk.getImageNames(): + for build_no in zk.getBuildNumbers(image_name): + build = zk.getBuild(image_name, build_no) + objs.append({'id' : '-'.join([image_name, build_no]), + 'image': image_name, + 'builder': build.builder, + 'formats': build.formats, + 'state': build.state, + 'age': int(build.state_time) + }) + return json.dumps(objs) + def image_list(zk): t = PrettyTable(["Build ID", "Upload ID", "Provider", "Image", "Provider Image Name", "Provider Image ID", "State", diff --git a/nodepool/tests/test_webapp.py b/nodepool/tests/test_webapp.py index 9a2671385..3038547b6 100644 --- a/nodepool/tests/test_webapp.py +++ b/nodepool/tests/test_webapp.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import json import logging import urllib2 @@ -37,5 +38,32 @@ class TestWebApp(tests.DBTestCase): req = urllib2.Request( "http://localhost:%s/image-list" % port) f = urllib2.urlopen(req) + self.assertEqual(f.info().getheader('Content-Type'), + 'application/text') data = f.read() self.assertTrue('fake-image' in data) + + def test_dib_image_list_json(self): + configfile = self.setup_config('node.yaml') + pool = self.useNodepool(configfile, watermark_sleep=1) + self._useBuilder(configfile) + pool.start() + webapp = self.useWebApp(pool, port=0) + webapp.start() + port = webapp.server.socket.getsockname()[1] + + self.waitForImage('fake-provider', 'fake-image') + self.waitForNodes(pool) + + req = urllib2.Request( + "http://localhost:%s/dib-image-list.json" % port) + f = urllib2.urlopen(req) + self.assertEqual(f.info().getheader('Content-Type'), + 'application/json') + data = f.read() + objs = json.loads(data) + # make sure this is valid json and has some of the + # non-changing keys + self.assertDictContainsSubset({'id': 'fake-image-0000000001', + 'formats': ['qcow2'], + 'state': 'ready'}, objs[0]) diff --git a/nodepool/webapp.py b/nodepool/webapp.py index b827834cc..9da0cd5dc 100644 --- a/nodepool/webapp.py +++ b/nodepool/webapp.py @@ -75,21 +75,28 @@ class WebApp(threading.Thread): if result: return result if path == '/image-list': - table = status.image_list(self.nodepool.getZK()) + output = status.image_list(self.nodepool.getZK()) elif path == '/dib-image-list': - table = status.dib_image_list(self.nodepool.getZK()) + output = status.dib_image_list(self.nodepool.getZK()) + elif path == '/dib-image-list.json': + output = status.dib_image_list_json(self.nodepool.getZK()) else: return None - return self.cache.put(path, table) + return self.cache.put(path, output) def app(self, request): result = self.get_cache(request.path) if result is None: raise webob.exc.HTTPNotFound() - last_modified, table = result + last_modified, output = result - response = webob.Response(body=table, - content_type='text/plain') + if request.path.endswith('.json'): + content_type = 'application/json' + else: + content_type = 'application/text' + + response = webob.Response(body=output, + content_type=content_type) response.headers['Access-Control-Allow-Origin'] = '*' response.cache_control.public = True